Merge branch 'master' of github.com:jcupitt/libvips
This commit is contained in:
commit
af6e00e10f
@ -18,6 +18,8 @@
|
||||
- jpeg strip option removes a little more, thanks Benjamin
|
||||
- added vips_image_new_from_memory_copy()
|
||||
- improve vips_sink_screen() stability under heavy load
|
||||
- added vips_arrayjoin()
|
||||
- Python x.bandjoin(y) is now x.ibandjoin(y), sorry
|
||||
|
||||
7/5/15 started 8.1.1
|
||||
- oop, vips-8.0 wrapper script should be vips-8.1, thanks Danilo
|
||||
|
1
TODO
1
TODO
@ -1,3 +1,4 @@
|
||||
|
||||
- get some brightly coloured spots with nohalo / vsqbs on wobble.ws ... very
|
||||
odd, the interpolation shouldn't change between bands
|
||||
|
||||
|
@ -497,7 +497,14 @@ if test x"$with_orc" != "xno"; then
|
||||
PKG_CHECK_MODULES(ORC, orc-0.4 >= 0.4.11,
|
||||
[AC_DEFINE(HAVE_ORC,1,[define if you have orc-0.4.11 or later installed.])
|
||||
with_orc=yes
|
||||
PACKAGES_USED="$PACKAGES_USED orc-0.4"],
|
||||
PACKAGES_USED="$PACKAGES_USED orc-0.4"
|
||||
save_LIBS=$LIBS
|
||||
LIBS="$LIBS $ORC_LIBS"
|
||||
AC_CHECK_FUNCS(orc_program_get_error,
|
||||
AC_DEFINE(HAVE_ORC_PROGRAM_GET_ERROR,1,
|
||||
[define if your orc has orc_program_get_error.]))
|
||||
LIBS=$save_LIBS
|
||||
],
|
||||
[AC_MSG_WARN([orc-0.4.11 or later not found; disabling orc support])
|
||||
with_orc=no
|
||||
])
|
||||
|
@ -318,6 +318,11 @@
|
||||
<entry>join a pair of images</entry>
|
||||
<entry>vips_join()</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>arrayjoin</entry>
|
||||
<entry>join an array of images</entry>
|
||||
<entry>vips_arrayjoin()</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>extract_area</entry>
|
||||
<entry>extract an area from an image</entry>
|
||||
@ -335,7 +340,7 @@
|
||||
</row>
|
||||
<row>
|
||||
<entry>bandjoin_const</entry>
|
||||
<entry>appendd a set of constants to an image</entry>
|
||||
<entry>append a constant band to an image</entry>
|
||||
<entry>vips_bandjoin_const(), vips_bandjoin_const1()</entry>
|
||||
</row>
|
||||
<row>
|
||||
@ -777,9 +782,9 @@
|
||||
<entry>vips_shrink()</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>quadratic</entry>
|
||||
<entry>resample an image with a quadratic transform</entry>
|
||||
<entry>vips_quadratic()</entry>
|
||||
<entry>mapim</entry>
|
||||
<entry>resample an image with an arbitrary warp</entry>
|
||||
<entry>vips_mapim()</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>affine</entry>
|
||||
|
@ -25,7 +25,6 @@ TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
|
||||
|
||||
SETUP_FILES = \
|
||||
$(content_files) \
|
||||
$(expand_content_files) \
|
||||
$(DOC_MAIN_SGML_FILE) \
|
||||
$(DOC_MODULE)-sections.txt \
|
||||
$(DOC_MODULE)-overrides.txt
|
||||
@ -87,7 +86,7 @@ GTK_DOC_V_SETUP_0=@echo " DOC Preparing build";
|
||||
|
||||
setup-build.stamp:
|
||||
-$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
|
||||
files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \
|
||||
files=`echo $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types`; \
|
||||
if test "x$$files" != "x" ; then \
|
||||
for file in $$files ; do \
|
||||
destdir=`dirname $(abs_builddir)/$$file`; \
|
||||
@ -119,7 +118,7 @@ scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB)
|
||||
$(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \
|
||||
scanobj_options=""; \
|
||||
gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \
|
||||
if test "$$?" = "0"; then \
|
||||
if test "$(?)" = "0"; then \
|
||||
if test "x$(V)" = "x1"; then \
|
||||
scanobj_options="--verbose"; \
|
||||
fi; \
|
||||
@ -163,17 +162,17 @@ GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_$(V))
|
||||
GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_$(AM_DEFAULT_VERBOSITY))
|
||||
GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references";
|
||||
|
||||
html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files)
|
||||
html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
|
||||
$(GTK_DOC_V_HTML)rm -rf html && mkdir html && \
|
||||
mkhtml_options=""; \
|
||||
gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \
|
||||
if test "$$?" = "0"; then \
|
||||
if test "$(?)" = "0"; then \
|
||||
if test "x$(V)" = "x1"; then \
|
||||
mkhtml_options="$$mkhtml_options --verbose"; \
|
||||
fi; \
|
||||
fi; \
|
||||
gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \
|
||||
if test "$$?" = "0"; then \
|
||||
if test "$(?)" = "0"; then \
|
||||
mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \
|
||||
fi; \
|
||||
cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
|
||||
@ -195,11 +194,11 @@ GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_$(V))
|
||||
GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_$(AM_DEFAULT_VERBOSITY))
|
||||
GTK_DOC_V_PDF_0=@echo " DOC Building PDF";
|
||||
|
||||
pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files)
|
||||
pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
|
||||
$(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \
|
||||
mkpdf_options=""; \
|
||||
gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \
|
||||
if test "$$?" = "0"; then \
|
||||
if test "$(?)" = "0"; then \
|
||||
if test "x$(V)" = "x1"; then \
|
||||
mkpdf_options="$$mkpdf_options --verbose"; \
|
||||
fi; \
|
||||
@ -224,15 +223,12 @@ clean-local:
|
||||
@if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \
|
||||
rm -f $(DOC_MODULE).types; \
|
||||
fi
|
||||
@if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-sections" ; then \
|
||||
rm -f $(DOC_MODULE)-sections.txt; \
|
||||
fi
|
||||
|
||||
distclean-local:
|
||||
@rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \
|
||||
$(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
|
||||
@if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
|
||||
rm -f $(SETUP_FILES) $(DOC_MODULE).types; \
|
||||
rm -f $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types; \
|
||||
fi
|
||||
|
||||
maintainer-clean-local:
|
||||
|
@ -461,21 +461,41 @@ result_image = condition_image.ifthenelse([0, 255, 0], [255, 0, 0])
|
||||
two or more images up bandwise. You can write:
|
||||
|
||||
<programlisting language="Python">
|
||||
rgba = rgb.bandjoin(255)
|
||||
rgba = rgb.ibandjoin(255)
|
||||
</programlisting>
|
||||
|
||||
to add a constant 255 band to an image, perhaps to add an alpha
|
||||
channel. Of course you can also write:
|
||||
|
||||
<programlisting language="Python">
|
||||
result_image = image1.bandjoin(image2)
|
||||
result_image = image1.bandjoin([image2, image3])
|
||||
result_image = image1.ibandjoin(image2)
|
||||
result_image = image1.ibandjoin([image2, image3])
|
||||
result_image = Vips.Image.bandjoin([image1, image2, image3])
|
||||
result_image = image1.bandjoin([image2, 255])
|
||||
result_image = image1.ibandjoin([image2, 255])
|
||||
</programlisting>
|
||||
|
||||
and so on.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There's one annoying wrinkle in <code>.bandjoin()</code>. The vips
|
||||
operation <code>vips_bandjoin()</code> takes an array of images to join,
|
||||
so you can't use it as an instance member, it appears in the API as
|
||||
|
||||
<programlisting language="Python">
|
||||
result_image = Vips.Image.bandjoin([image1, image2, image3])
|
||||
</programlisting>
|
||||
|
||||
For convenience, the wrapper has an extra instance function called
|
||||
<code>.ibandjoin()</code> which puts the <code>self</code> at the head
|
||||
of the image array. This means the previous line is the same as:
|
||||
|
||||
<programlisting language="Python">
|
||||
result_image = image1.ibandjoin([image2, image3])
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
</refsect3>
|
||||
|
||||
<refsect3 id="python-exceptions">
|
||||
|
@ -16,6 +16,7 @@ libconversion_la_SOURCES = \
|
||||
flip.c \
|
||||
insert.c \
|
||||
join.c \
|
||||
arrayjoin.c \
|
||||
extract.c \
|
||||
replicate.c \
|
||||
cast.c \
|
||||
|
437
libvips/conversion/arrayjoin.c
Normal file
437
libvips/conversion/arrayjoin.c
Normal file
@ -0,0 +1,437 @@
|
||||
/* join an array of images together
|
||||
*
|
||||
* 11/12/15
|
||||
* - from join.c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#include "pconversion.h"
|
||||
|
||||
/* Round N down to P boundary.
|
||||
*/
|
||||
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
|
||||
|
||||
/* Round N up to P boundary.
|
||||
*/
|
||||
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
|
||||
|
||||
typedef struct _VipsArrayjoin {
|
||||
VipsConversion parent_instance;
|
||||
|
||||
/* Params.
|
||||
*/
|
||||
VipsArrayImage *in;
|
||||
int across;
|
||||
int shim;
|
||||
VipsArea *background;
|
||||
VipsAlign halign;
|
||||
VipsAlign valign;
|
||||
int hspacing;
|
||||
int vspacing;
|
||||
|
||||
int down;
|
||||
VipsRect *rects;
|
||||
|
||||
} VipsArrayjoin;
|
||||
|
||||
typedef VipsConversionClass VipsArrayjoinClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsArrayjoin, vips_arrayjoin, VIPS_TYPE_CONVERSION );
|
||||
|
||||
static int
|
||||
vips_arrayjoin_gen( VipsRegion *or, void *seq,
|
||||
void *a, void *b, gboolean *stop )
|
||||
{
|
||||
VipsRegion **ir = (VipsRegion **) seq;
|
||||
VipsArrayjoin *join = (VipsArrayjoin *) b;
|
||||
VipsRect *r = &or->valid;
|
||||
int n = ((VipsArea *) join->in)->n;
|
||||
|
||||
int i;
|
||||
|
||||
/* Does this rect fit within one of our inputs? If it does, we
|
||||
* can pass just the request on.
|
||||
*/
|
||||
for( i = 0; i < n; i++ )
|
||||
if( vips_rect_includesrect( &join->rects[i], r ) )
|
||||
return( vips__insert_just_one( or, ir[i],
|
||||
join->rects[i].left, join->rects[i].top ) );
|
||||
|
||||
/* Output requires more than one input. Paste all touching inputs into
|
||||
* the output.
|
||||
*/
|
||||
for( i = 0; i < n; i++ )
|
||||
if( vips__insert_paste_region( or, ir[i], &join->rects[i] ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_arrayjoin_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsConversion *conversion = VIPS_CONVERSION( object );
|
||||
VipsArrayjoin *join = (VipsArrayjoin *) object;
|
||||
|
||||
VipsImage **in;
|
||||
int n;
|
||||
|
||||
VipsImage **format;
|
||||
VipsImage **band;
|
||||
VipsImage **size;
|
||||
|
||||
int hspacing;
|
||||
int vspacing;
|
||||
int output_width;
|
||||
int output_height;
|
||||
int i;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_arrayjoin_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
in = vips_array_image_get( join->in, &n );
|
||||
|
||||
/* Move all input images to a common format and number of bands.
|
||||
*/
|
||||
format = (VipsImage **) vips_object_local_array( object, n );
|
||||
if( vips__formatalike_vec( in, format, n ) )
|
||||
return( -1 );
|
||||
in = format;
|
||||
|
||||
/* We have to include the number of bands in @background in our
|
||||
* calculation.
|
||||
*/
|
||||
band = (VipsImage **) vips_object_local_array( object, n );
|
||||
if( vips__bandalike_vec( class->nickname,
|
||||
in, band, n, join->background->n ) )
|
||||
return( -1 );
|
||||
in = band;
|
||||
|
||||
/* Now sizealike: search for the largest image.
|
||||
*/
|
||||
hspacing = in[0]->Xsize;
|
||||
vspacing = in[0]->Ysize;
|
||||
for( i = 1; i < n; i++ ) {
|
||||
if( in[i]->Xsize > hspacing )
|
||||
hspacing = in[i]->Xsize;
|
||||
if( in[i]->Ysize > vspacing )
|
||||
vspacing = in[i]->Ysize;
|
||||
}
|
||||
|
||||
if( !vips_object_argument_isset( object, "hspacing" ) )
|
||||
g_object_set( object, "hspacing", hspacing, NULL );
|
||||
if( !vips_object_argument_isset( object, "vspacing" ) )
|
||||
g_object_set( object, "vspacing", vspacing, NULL );
|
||||
|
||||
hspacing = join->hspacing;
|
||||
vspacing = join->vspacing;
|
||||
|
||||
if( !vips_object_argument_isset( object, "across" ) )
|
||||
g_object_set( object, "across", n, NULL );
|
||||
|
||||
/* How many images down the grid?
|
||||
*/
|
||||
join->down = ROUND_UP( n, join->across ) / join->across;
|
||||
|
||||
/* The output size.
|
||||
*/
|
||||
output_width = hspacing * join->across +
|
||||
join->shim * (join->across - 1);
|
||||
output_height = vspacing * join->down +
|
||||
join->shim * (join->down - 1);
|
||||
|
||||
/* Make a rect for the position of each input.
|
||||
*/
|
||||
join->rects = VIPS_ARRAY( join, n, VipsRect );
|
||||
for( i = 0; i < n; i++ ) {
|
||||
int x = i % join->across;
|
||||
int y = i / join->across;
|
||||
|
||||
join->rects[i].left = x * (hspacing + join->shim);
|
||||
join->rects[i].top = y * (vspacing + join->shim);
|
||||
join->rects[i].width = hspacing;
|
||||
join->rects[i].height = vspacing;
|
||||
|
||||
/* In the centre of the array, we make width / height larger
|
||||
* by shim.
|
||||
*/
|
||||
if( x != join->across - 1 )
|
||||
join->rects[i].width += join->shim;
|
||||
if( y != join->down - 1 )
|
||||
join->rects[i].height += join->shim;
|
||||
|
||||
/* The right edge of the final image is stretched to the right
|
||||
* to fill the whole row.
|
||||
*/
|
||||
if( i == n - 1 )
|
||||
join->rects[i].width =
|
||||
output_width - join->rects[i].left;
|
||||
}
|
||||
|
||||
/* Each image must be cropped and aligned within an @hspacing by
|
||||
* @vspacing box.
|
||||
*/
|
||||
size = (VipsImage **) vips_object_local_array( object, n );
|
||||
for( i = 0; i < n; i++ ) {
|
||||
int left, top;
|
||||
int width, height;
|
||||
|
||||
switch( join->halign ) {
|
||||
case VIPS_ALIGN_LOW:
|
||||
left = 0;
|
||||
break;
|
||||
|
||||
case VIPS_ALIGN_CENTRE:
|
||||
left = (hspacing - in[i]->Xsize) / 2;
|
||||
break;
|
||||
|
||||
case VIPS_ALIGN_HIGH:
|
||||
left = hspacing - in[i]->Xsize;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
switch( join->valign ) {
|
||||
case VIPS_ALIGN_LOW:
|
||||
top = 0;
|
||||
break;
|
||||
|
||||
case VIPS_ALIGN_CENTRE:
|
||||
top = (vspacing - in[i]->Ysize) / 2;
|
||||
break;
|
||||
|
||||
case VIPS_ALIGN_HIGH:
|
||||
top = vspacing - in[i]->Ysize;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
width = join->rects[i].width;
|
||||
height = join->rects[i].height;
|
||||
|
||||
if( vips_embed( in[i], &size[i], left, top, width, height,
|
||||
"extend", VIPS_EXTEND_BACKGROUND,
|
||||
"background", join->background,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_image_pipeline_array( conversion->out,
|
||||
VIPS_DEMAND_STYLE_THINSTRIP, size ) )
|
||||
return( -1 );
|
||||
|
||||
conversion->out->Xsize = output_width;
|
||||
conversion->out->Ysize = output_height;
|
||||
|
||||
if( vips_image_generate( conversion->out,
|
||||
vips_start_many, vips_arrayjoin_gen, vips_stop_many,
|
||||
size, join ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_arrayjoin_class_init( VipsArrayjoinClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_arrayjoin_class_init\n" );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
vobject_class->nickname = "arrayjoin";
|
||||
vobject_class->description = _( "join an array of images" );
|
||||
vobject_class->build = vips_arrayjoin_build;
|
||||
|
||||
VIPS_ARG_BOXED( class, "in", -1,
|
||||
_( "Input" ),
|
||||
_( "Array of input images" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, in ),
|
||||
VIPS_TYPE_ARRAY_IMAGE );
|
||||
|
||||
VIPS_ARG_INT( class, "across", 4,
|
||||
_( "Across" ),
|
||||
_( "Number of images across grid" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, across ),
|
||||
1, 1000000, 1 );
|
||||
|
||||
VIPS_ARG_INT( class, "shim", 5,
|
||||
_( "Shim" ),
|
||||
_( "Pixels between images" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, shim ),
|
||||
0, 1000000, 0 );
|
||||
|
||||
VIPS_ARG_BOXED( class, "background", 6,
|
||||
_( "Background" ),
|
||||
_( "Colour for new pixels" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, background ),
|
||||
VIPS_TYPE_ARRAY_DOUBLE );
|
||||
|
||||
VIPS_ARG_ENUM( class, "halign", 7,
|
||||
_( "Horizontal align" ),
|
||||
_( "Align on the left, centre or right" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, halign ),
|
||||
VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW );
|
||||
|
||||
VIPS_ARG_ENUM( class, "valign", 8,
|
||||
_( "Vertical align" ),
|
||||
_( "Align on the top, centre or bottom" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, valign ),
|
||||
VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW );
|
||||
|
||||
VIPS_ARG_INT( class, "hspacing", 9,
|
||||
_( "Horizontal spacing" ),
|
||||
_( "Horizontal spacing between images" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, hspacing ),
|
||||
1, 1000000, 1 );
|
||||
|
||||
VIPS_ARG_INT( class, "vspacing", 10,
|
||||
_( "Vertical spacing" ),
|
||||
_( "Vertical spacing between images" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsArrayjoin, vspacing ),
|
||||
1, 1000000, 1 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_arrayjoin_init( VipsArrayjoin *join )
|
||||
{
|
||||
/* Init our instance fields.
|
||||
*/
|
||||
join->background =
|
||||
vips_area_new_array( G_TYPE_DOUBLE, sizeof( double ), 1 );
|
||||
((double *) (join->background->data))[0] = 0.0;
|
||||
}
|
||||
|
||||
static int
|
||||
vips_arrayjoinv( VipsImage **in, VipsImage **out, int n, va_list ap )
|
||||
{
|
||||
VipsArrayImage *array;
|
||||
int result;
|
||||
|
||||
array = vips_array_image_new( in, n );
|
||||
result = vips_call_split( "arrayjoin", ap, array, out );
|
||||
vips_area_unref( VIPS_AREA( array ) );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_arrayjoin:
|
||||
* @in: (array length=n) (transfer none): array of input images
|
||||
* @out: output image
|
||||
* @n: number of input images
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* @across: number of images per row
|
||||
* @shim: space between images, in pixels
|
||||
* @background: background ink colour
|
||||
* @halign: low, centre or high alignment
|
||||
* @valign: low, centre or high alignment
|
||||
* @hspacing: horizontal distance between images
|
||||
* @vspacing: vertical distance between images
|
||||
*
|
||||
* Lay out the images in @in in a grid. The grid is @across images across and
|
||||
* however high is necessary to use up all of @in. Images are set down
|
||||
* left-to-right and top-to-bottom. @across defaults to @n.
|
||||
*
|
||||
* Each input image is placed with a box of size @hspacing by @vspacing
|
||||
* pixels and cropped. These default to the largest width and largest height
|
||||
* of the input images.
|
||||
*
|
||||
* Space between images is filled with @background. This defaults to 0
|
||||
* (black).
|
||||
*
|
||||
* Images are positioned within their @hspacing by @vspacing box at low,
|
||||
* centre or high coordinate values, controlled by @halign and @valign. These
|
||||
* default to left-top.
|
||||
*
|
||||
* Boxes are joined and separated by @shim pixels. This defaults to 0.
|
||||
*
|
||||
* If the number of bands in the input images differs, all but one of the
|
||||
* images must have one band. In this case, an n-band image is formed from the
|
||||
* one-band image by joining n copies of the one-band image together, and then
|
||||
* the n-band images are operated upon.
|
||||
*
|
||||
* The input images are cast up to the smallest common type (see table
|
||||
* Smallest common format in
|
||||
* <link linkend="libvips-arithmetic">arithmetic</link>).
|
||||
*
|
||||
* See also: vips_join(), vips_insert().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_arrayjoin( VipsImage **in, VipsImage **out, int n, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, n );
|
||||
result = vips_arrayjoinv( in, out, n, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
@ -223,6 +223,7 @@ vips_conversion_operation_init( void )
|
||||
extern GType vips_flip_get_type( void );
|
||||
extern GType vips_insert_get_type( void );
|
||||
extern GType vips_join_get_type( void );
|
||||
extern GType vips_arrayjoin_get_type( void );
|
||||
extern GType vips_extract_area_get_type( void );
|
||||
extern GType vips_crop_get_type( void );
|
||||
extern GType vips_extract_band_get_type( void );
|
||||
@ -268,6 +269,7 @@ vips_conversion_operation_init( void )
|
||||
vips_flip_get_type();
|
||||
vips_insert_get_type();
|
||||
vips_join_get_type();
|
||||
vips_arrayjoin_get_type();
|
||||
vips_extract_area_get_type();
|
||||
vips_crop_get_type();
|
||||
vips_extract_band_get_type();
|
||||
|
@ -357,9 +357,6 @@ vips_embed_build( VipsObject *object )
|
||||
embed->height == embed->in->Ysize )
|
||||
return( vips_image_write( embed->in, conversion->out ) );
|
||||
|
||||
if( vips_image_pio_input( embed->in ) )
|
||||
return( -1 );
|
||||
|
||||
if( !(embed->ink = vips__vector_to_ink(
|
||||
class->nickname, embed->in,
|
||||
VIPS_AREA( embed->background )->data, NULL,
|
||||
|
@ -110,9 +110,11 @@ typedef VipsConversionClass VipsInsertClass;
|
||||
G_DEFINE_TYPE( VipsInsert, vips_insert, VIPS_TYPE_CONVERSION );
|
||||
|
||||
/* Trivial case: we just need pels from one of the inputs.
|
||||
*
|
||||
* Also used by vips_arrayjoin.
|
||||
*/
|
||||
static int
|
||||
vips_insert_just_one( VipsRegion *or, VipsRegion *ir, int x, int y )
|
||||
int
|
||||
vips__insert_just_one( VipsRegion *or, VipsRegion *ir, int x, int y )
|
||||
{
|
||||
VipsRect need;
|
||||
|
||||
@ -134,9 +136,11 @@ vips_insert_just_one( VipsRegion *or, VipsRegion *ir, int x, int y )
|
||||
|
||||
/* Paste in parts of ir that fall within or --- ir is an input REGION for an
|
||||
* image positioned at pos within or.
|
||||
*
|
||||
* Also used by vips_arrayjoin.
|
||||
*/
|
||||
static int
|
||||
vips_insert_paste_region( VipsRegion *or, VipsRegion *ir, VipsRect *pos )
|
||||
int
|
||||
vips__insert_paste_region( VipsRegion *or, VipsRegion *ir, VipsRect *pos )
|
||||
{
|
||||
VipsRect ovl;
|
||||
|
||||
@ -175,7 +179,7 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
* sub-image?
|
||||
*/
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) )
|
||||
return( vips_insert_just_one( or, ir[1],
|
||||
return( vips__insert_just_one( or, ir[1],
|
||||
insert->rsub.left, insert->rsub.top ) );
|
||||
|
||||
/* Does it fall entirely inside the main, and not at all inside the
|
||||
@ -184,7 +188,7 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
vips_rect_intersectrect( &or->valid, &insert->rsub, &ovl );
|
||||
if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
||||
vips_rect_isempty( &ovl ) )
|
||||
return( vips_insert_just_one( or, ir[0],
|
||||
return( vips__insert_just_one( or, ir[0],
|
||||
insert->rmain.left, insert->rmain.top ) );
|
||||
|
||||
/* Output requires both (or neither) input. If it is not entirely
|
||||
@ -197,12 +201,12 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( vips_insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips_insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
|
@ -193,14 +193,19 @@ vips_join_build( VipsObject *object )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( vips_extract_area( t, &t2,
|
||||
left, top, width, height, NULL ) ) {
|
||||
if( left != 0 ||
|
||||
top != 0 ||
|
||||
width != t->Xsize ||
|
||||
height != t->Ysize ) {
|
||||
if( vips_extract_area( t, &t2,
|
||||
left, top, width, height, NULL ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
t = t2;
|
||||
t = t2;
|
||||
}
|
||||
}
|
||||
|
||||
if( vips_image_write( t, conversion->out ) ) {
|
||||
@ -324,7 +329,10 @@ vips_join_init( VipsJoin *join )
|
||||
* Smallest common format in
|
||||
* <link linkend="libvips-arithmetic">arithmetic</link>).
|
||||
*
|
||||
* See also: vips_insert().
|
||||
* If you are going to be joining many thousands of images in a regular
|
||||
* grid, vips_arrayjoin() is a better choice.
|
||||
*
|
||||
* See also: vips_arrayjoin(), vips_insert().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -133,7 +133,7 @@
|
||||
/**
|
||||
* VipsForeignLoad:
|
||||
*
|
||||
* @header() must set at least the header fields of @out. @laod(), if defined,
|
||||
* @header() must set at least the header fields of @out. @load(), if defined,
|
||||
* must load the pixels to @real.
|
||||
*/
|
||||
|
||||
|
@ -1146,6 +1146,12 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
|
||||
out->Xsize = width;
|
||||
out->Ysize = height;
|
||||
|
||||
/* Even though we could end up serving tiled data, always hint
|
||||
* THINSTRIP, since we're quite happy doing that too, and it could need
|
||||
* a lot less memory.
|
||||
*/
|
||||
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "parse_header: samples_per_pixel = %d\n",
|
||||
rtiff->samples_per_pixel );
|
||||
@ -2042,7 +2048,7 @@ vips__tiff_read_buffer( const void *buf, size_t len,
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() );
|
||||
printf( "tiff2vips: libtiff starting for %s\n", filename );
|
||||
printf( "tiff2vips: libtiff starting for buffer %p\n", buf );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
vips__tiff_init();
|
||||
|
@ -857,11 +857,16 @@ write_new( VipsImage *im, const char *filename,
|
||||
write->xres = xres;
|
||||
write->yres = yres;
|
||||
|
||||
if( (write->tilew & 0xf) != 0 ||
|
||||
(write->tileh & 0xf) != 0 ) {
|
||||
vips_error( "vips2tiff",
|
||||
"%s", _( "tile size not a multiple of 16" ) );
|
||||
return( NULL );
|
||||
/* In strip mode we use tileh to set rowsperstrip, and that does not
|
||||
* have the multiple-of-16 restriction.
|
||||
*/
|
||||
if( tile ) {
|
||||
if( (write->tilew & 0xf) != 0 ||
|
||||
(write->tileh & 0xf) != 0 ) {
|
||||
vips_error( "vips2tiff",
|
||||
"%s", _( "tile size not a multiple of 16" ) );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* We can only pyramid LABQ and non-complex images.
|
||||
|
@ -105,6 +105,8 @@ int vips_insert( VipsImage *main, VipsImage *sub, VipsImage **out,
|
||||
int vips_join( VipsImage *in1, VipsImage *in2, VipsImage **out,
|
||||
VipsDirection direction, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_arrayjoin( VipsImage **in, VipsImage **out, int n, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_extract_area( VipsImage *in, VipsImage **out,
|
||||
int left, int top, int width, int height, ... )
|
||||
__attribute__((sentinel));
|
||||
|
@ -197,6 +197,9 @@ void vips__draw_line_direct( VipsImage *image, int x1, int y1, int x2, int y2,
|
||||
void vips__draw_circle_direct( VipsImage *image, int cx, int cy, int r,
|
||||
VipsDrawScanline draw_scanline, void *client );
|
||||
|
||||
int vips__insert_just_one( VipsRegion *out, VipsRegion *in, int x, int y );
|
||||
int vips__insert_paste_region( VipsRegion *out, VipsRegion *in, VipsRect *pos );
|
||||
|
||||
/* Register base vips interpolators, called during startup.
|
||||
*/
|
||||
void vips__interpolate_init( void );
|
||||
|
@ -52,8 +52,8 @@
|
||||
/*
|
||||
#define DEBUG_VERBOSE
|
||||
#define DEBUG_CREATE
|
||||
*/
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
@ -68,7 +68,7 @@
|
||||
#include <vips/thread.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Track all regions here for debugging.
|
||||
/* Track all buffers here for debugging.
|
||||
*/
|
||||
static GSList *vips__buffer_all = NULL;
|
||||
#endif /*DEBUG*/
|
||||
@ -608,6 +608,14 @@ vips__buffer_init( void )
|
||||
|
||||
if( buffer_cache_max_reserve < 1 )
|
||||
printf( "vips__buffer_init: buffer reserve disabled\n" );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__buffer_init: DEBUG enabled\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
#ifdef DEBUG_CREATE
|
||||
printf( "vips__buffer_init: DEBUG_CREATE enabled\n" );
|
||||
#endif /*DEBUG_CREATE*/
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,12 +60,24 @@
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/vector.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/thread.h>
|
||||
|
||||
/* Cleared by the command-line --vips-novector switch and the IM_NOVECTOR env
|
||||
* var.
|
||||
*/
|
||||
gboolean vips__vector_enabled = TRUE;
|
||||
|
||||
void
|
||||
vips_vector_error( VipsVector *vector )
|
||||
{
|
||||
#ifdef HAVE_ORC_PROGRAM_GET_ERROR
|
||||
if( vector->program )
|
||||
vips_warn( "VipsVector", "orc error: %s",
|
||||
orc_program_get_error( vector->program ) );
|
||||
#endif /*HAVE_ORC_PROGRAM_GET_ERROR*/
|
||||
}
|
||||
|
||||
void
|
||||
vips_vector_init( void )
|
||||
{
|
||||
@ -168,6 +180,10 @@ vips_vector_new( const char *name, int dsize )
|
||||
|
||||
/* We always make d1, our callers make either a single point source, or
|
||||
* for area ops, a set of scanlines.
|
||||
*
|
||||
* Don't check error return. orc uses 0 to mean error, but the first
|
||||
* var you create will have id 0 :-( The first var is unlikely to fail
|
||||
* anyway.
|
||||
*/
|
||||
vector->d1 = orc_program_add_destination( vector->program,
|
||||
dsize, "d1" );
|
||||
@ -250,7 +266,9 @@ vips_vector_constant( VipsVector *vector, char *name, int value, int size )
|
||||
printf( "orc_program_add_constant( %s, %d, %d, \"%s\" );\n",
|
||||
vector->unique_name, size, value, name );
|
||||
#endif /*DEBUG_TRACE*/
|
||||
orc_program_add_constant( vector->program, size, value, name );
|
||||
if( !orc_program_add_constant( vector->program,
|
||||
size, value, name ) )
|
||||
vips_vector_error( vector );
|
||||
vector->n_constant += 1;
|
||||
}
|
||||
#endif /*HAVE_ORC*/
|
||||
@ -264,8 +282,9 @@ vips_vector_source_name( VipsVector *vector, char *name, int size )
|
||||
#ifdef HAVE_ORC
|
||||
g_assert( orc_program_find_var_by_name( vector->program, name ) == -1 );
|
||||
|
||||
vector->s[vector->n_source] = var =
|
||||
orc_program_add_source( vector->program, size, name );
|
||||
if( !(var = orc_program_add_source( vector->program, size, name )) )
|
||||
vips_vector_error( vector );
|
||||
vector->s[vector->n_source] = var;
|
||||
#ifdef DEBUG_TRACE
|
||||
printf( "orc_program_add_source( %s, %d, \"%s\" );\n",
|
||||
vector->unique_name, size, name );
|
||||
@ -288,7 +307,9 @@ vips_vector_source_scanline( VipsVector *vector,
|
||||
if( orc_program_find_var_by_name( vector->program, name ) == -1 ) {
|
||||
int var;
|
||||
|
||||
var = orc_program_add_source( vector->program, size, name );
|
||||
if( !(var = orc_program_add_source( vector->program,
|
||||
size, name )) )
|
||||
vips_vector_error( vector );
|
||||
#ifdef DEBUG_TRACE
|
||||
printf( "orc_program_add_source( %s, %d, \"%s\" );\n",
|
||||
vector->unique_name, size, name );
|
||||
@ -306,7 +327,9 @@ vips_vector_temporary( VipsVector *vector, char *name, int size )
|
||||
#ifdef HAVE_ORC
|
||||
g_assert( orc_program_find_var_by_name( vector->program, name ) == -1 );
|
||||
|
||||
orc_program_add_temporary( vector->program, size, name );
|
||||
if( !orc_program_add_temporary( vector->program, size, name ) )
|
||||
vips_vector_error( vector );
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
printf( "orc_program_add_temporary( %s, %d, \"%s\" );\n",
|
||||
vector->unique_name, size, name );
|
||||
@ -318,10 +341,14 @@ vips_vector_temporary( VipsVector *vector, char *name, int size )
|
||||
gboolean
|
||||
vips_vector_full( VipsVector *vector )
|
||||
{
|
||||
/* Many orcs don't have ORC_MAX_CONST_VARS etc., stick to our own
|
||||
* constants for now.
|
||||
*/
|
||||
|
||||
/* We can need a max of 2 constants plus one source per
|
||||
* coefficient, so stop if we're sure we don't have enough.
|
||||
*/
|
||||
if( vector->n_constant > 16 - 2 )
|
||||
if( vector->n_constant + 2 > 8 )
|
||||
return( TRUE );
|
||||
|
||||
/* You can have 8 parameters, and d1 counts as one of them, so +1
|
||||
@ -330,11 +357,10 @@ vips_vector_full( VipsVector *vector )
|
||||
if( vector->n_source + vector->n_scanline + 1 > 7 )
|
||||
return( TRUE );
|
||||
|
||||
/* I seem to get segvs with I counts over about 50 :-( argh. After
|
||||
* signalling full, some operations will add up to 4 more instructions
|
||||
* as they finish up. Leave a margin.
|
||||
/* After signalling full, some operations will add up to 4 more
|
||||
* instructions as they finish up. Leave a margin.
|
||||
*/
|
||||
if( vector->n_instruction > 42 )
|
||||
if( vector->n_instruction + 10 > 50 )
|
||||
return( TRUE );
|
||||
|
||||
return( FALSE );
|
||||
@ -346,7 +372,12 @@ vips_vector_compile( VipsVector *vector )
|
||||
#ifdef HAVE_ORC
|
||||
OrcCompileResult result;
|
||||
|
||||
/* Some orcs seem to be unstable with many compilers active at once.
|
||||
*/
|
||||
g_mutex_lock( vips__global_lock );
|
||||
result = orc_program_compile( vector->program );
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
printf( "orc_program_compile( %s );\n", vector->unique_name );
|
||||
#endif /*DEBUG_TRACE*/
|
||||
|
@ -906,7 +906,9 @@ class Image(Vips.Image):
|
||||
"""Split an n-band image into n separate images."""
|
||||
return [x for x in self]
|
||||
|
||||
def bandjoin(self, other):
|
||||
# bandjoin as an instance method ... it needs a different name,
|
||||
# unfortunately
|
||||
def ibandjoin(self, other):
|
||||
"""Append a set of images or constants bandwise."""
|
||||
if not isinstance(other, list):
|
||||
other = [other]
|
||||
@ -1050,6 +1052,7 @@ class_methods = [
|
||||
"system",
|
||||
"sum",
|
||||
"bandjoin",
|
||||
"arrayjoin",
|
||||
"bandrank",
|
||||
"black",
|
||||
"gaussnoise",
|
||||
|
@ -173,18 +173,18 @@ class TestConversion(unittest.TestCase):
|
||||
def test_bandjoin(self):
|
||||
def bandjoin(x, y):
|
||||
if isinstance(x, Vips.Image) and isinstance(y, Vips.Image):
|
||||
return x.bandjoin(y)
|
||||
return x.ibandjoin(y)
|
||||
else:
|
||||
return x + y
|
||||
|
||||
self.run_binary(self.all_images, bandjoin)
|
||||
|
||||
def test_bandjoin_const(self):
|
||||
x = self.colour.bandjoin(1)
|
||||
x = self.colour.ibandjoin(1)
|
||||
self.assertEqual(x.bands, 4)
|
||||
self.assertEqual(x[3].avg(), 1)
|
||||
|
||||
x = self.colour.bandjoin([1,2])
|
||||
x = self.colour.ibandjoin([1,2])
|
||||
self.assertEqual(x.bands, 5)
|
||||
self.assertEqual(x[3].avg(), 1)
|
||||
self.assertEqual(x[4].avg(), 2)
|
||||
@ -382,7 +382,7 @@ class TestConversion(unittest.TestCase):
|
||||
mx = 255
|
||||
alpha = mx / 2.0
|
||||
nalpha = mx - alpha
|
||||
test = self.colour.bandjoin(alpha).cast(fmt)
|
||||
test = self.colour.ibandjoin(alpha).cast(fmt)
|
||||
pixel = test(30, 30)
|
||||
|
||||
predict = [int(x) * alpha / mx for x in pixel[:-1]]
|
||||
@ -413,7 +413,7 @@ class TestConversion(unittest.TestCase):
|
||||
mx = 255
|
||||
alpha = mx / 2.0
|
||||
nalpha = mx - alpha
|
||||
test = self.colour.bandjoin(alpha).cast(fmt)
|
||||
test = self.colour.ibandjoin(alpha).cast(fmt)
|
||||
pixel = test(30, 30)
|
||||
|
||||
predict = [int(x) * alpha / mx for x in pixel[:-1]] + [alpha]
|
||||
@ -433,7 +433,7 @@ class TestConversion(unittest.TestCase):
|
||||
mx = 255
|
||||
alpha = mx / 2.0
|
||||
nalpha = mx - alpha
|
||||
test = self.colour.bandjoin(alpha).cast(fmt)
|
||||
test = self.colour.ibandjoin(alpha).cast(fmt)
|
||||
pixel = test(30, 30)
|
||||
|
||||
predict = [int(x) / (alpha / mx) for x in pixel[:-1]] + [alpha]
|
||||
@ -627,6 +627,34 @@ class TestConversion(unittest.TestCase):
|
||||
a = r(r.width - 5, 5)
|
||||
self.assertAlmostEqualObjects(a, [100, 100, 100])
|
||||
|
||||
def test_arrayjoin(self):
|
||||
max_width = 0
|
||||
max_height = 0
|
||||
max_bands = 0
|
||||
for image in self.all_images:
|
||||
if image.width > max_width:
|
||||
max_width = image.width
|
||||
if image.height > max_height:
|
||||
max_height = image.height
|
||||
if image.bands > max_bands:
|
||||
max_bands = image.bands
|
||||
|
||||
im = Vips.Image.arrayjoin(self.all_images)
|
||||
self.assertEqual(im.width, max_width * len(self.all_images))
|
||||
self.assertEqual(im.height, max_height)
|
||||
self.assertEqual(im.bands, max_bands)
|
||||
|
||||
im = Vips.Image.arrayjoin(self.all_images, across = 1)
|
||||
self.assertEqual(im.width, max_width)
|
||||
self.assertEqual(im.height, max_height * len(self.all_images))
|
||||
self.assertEqual(im.bands, max_bands)
|
||||
|
||||
im = Vips.Image.arrayjoin(self.all_images, shim = 10)
|
||||
self.assertEqual(im.width, max_width * len(self.all_images) +
|
||||
10 * (len(self.all_images) - 1))
|
||||
self.assertEqual(im.height, max_height)
|
||||
self.assertEqual(im.bands, max_bands)
|
||||
|
||||
def test_msb(self):
|
||||
for fmt in unsigned_formats:
|
||||
mx = max_value[fmt]
|
||||
|
@ -48,7 +48,7 @@ class TestForeign(unittest.TestCase):
|
||||
self.colour = Vips.Image.jpegload(self.jpeg_file)
|
||||
self.mono = self.colour.extract_band(1)
|
||||
self.rad = self.colour.float2rad()
|
||||
self.cmyk = self.colour.bandjoin(self.mono)
|
||||
self.cmyk = self.colour.ibandjoin(self.mono)
|
||||
self.cmyk = self.cmyk.copy(interpretation = Vips.Interpretation.CMYK)
|
||||
|
||||
im = Vips.Image.new_from_file(self.gif_file)
|
||||
|
Loading…
Reference in New Issue
Block a user