Merge branch 'master' into libspng-experiment
@ -15,12 +15,18 @@
|
||||
- add subsample_mode, deprecate no_subsample in jpegsave [Elad-Laufer]
|
||||
- add vips_isdirf()
|
||||
- add PAGENUMBER support to tiff write [jclavoie-jive]
|
||||
- add all to smartcrop
|
||||
- add "all" mode to smartcrop
|
||||
- flood fill could stop half-way for some very complex shapes
|
||||
- better handling of unaligned reads in multipage tiffs [petoor]
|
||||
- add experimental libspng reader
|
||||
- mark old --delete option to vipsthumbnail as deprecated [UweOhse]
|
||||
- png save with a bad ICC profile just gives a warning
|
||||
- add "premultipled" option to vips_affine(), clarified vips_resize()
|
||||
behaviour with alpha channels
|
||||
- improve bioformats support with read and write of tiff subifd pyramids
|
||||
- thumbnail exploits subifd pyramids
|
||||
- handle all EXIF orientation cases, deprecate
|
||||
vips_autorot_get_angle() [Elad-Laufer]
|
||||
|
||||
24/4/20 started 8.9.3
|
||||
- better iiif tile naming [IllyaMoskvin]
|
||||
|
@ -855,14 +855,16 @@ if test x"$with_heif" != x"no"; then
|
||||
PKG_CHECK_MODULES(HEIF, libheif,
|
||||
[with_heif=yes
|
||||
have_h265_decoder=`$PKG_CONFIG libheif --variable builtin_h265_decoder`
|
||||
have_avif_decoder=`$PKG_CONFIG libheif --variable builtin_avif_decoder`
|
||||
# test for !=no so that we work for older libheif which does not have
|
||||
# this variable
|
||||
if test x"$have_h265_decoder" != x"no"; then
|
||||
if test x"$have_h265_decoder" != x"no" -o x"$have_avif_decoder" = x"yes"; then
|
||||
AC_DEFINE(HAVE_HEIF_DECODER,1,
|
||||
[define if your libheif has decode support.])
|
||||
fi
|
||||
have_h265_encoder=`$PKG_CONFIG libheif --variable builtin_h265_encoder`
|
||||
if test x"$have_h265_encoder" != x"no"; then
|
||||
have_avif_encoder=`$PKG_CONFIG libheif --variable builtin_avif_encoder`
|
||||
if test x"$have_h265_encoder" != x"no" -o x"$have_avif_encoder" = x"yes"; then
|
||||
AC_DEFINE(HAVE_HEIF_ENCODER,1,
|
||||
[define if your libheif has encode support.])
|
||||
fi
|
||||
@ -872,6 +874,8 @@ if test x"$with_heif" != x"no"; then
|
||||
with_heif=no
|
||||
have_h265_decoder=
|
||||
have_h265_encoder=
|
||||
have_avif_decoder=
|
||||
have_avif_encoder=
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
@ -260,10 +260,10 @@ $ ls -l tn_shark.jpg
|
||||
-rw-r–r– 1 john john 7295 Nov 9 14:33 tn_shark.jpg
|
||||
</programlisting>
|
||||
<para>
|
||||
Now encode with sRGB and delete any embedded profile:
|
||||
Now transform to sRGB and don’t attach a profile (you can also use <literal>strip</literal>, though that will remove <emphasis>all</emphasis> metadata from the image):
|
||||
</para>
|
||||
<programlisting>
|
||||
$ vipsthumbnail shark.jpg --eprofile srgb --delete
|
||||
$ vipsthumbnail shark.jpg --eprofile srgb -o tn_shark.jpg[profile=none]
|
||||
$ ls -l tn_shark.jpg
|
||||
-rw-r–r– 1 john john 4229 Nov 9 14:33 tn_shark.jpg
|
||||
</programlisting>
|
||||
@ -299,6 +299,7 @@ $ vipsthumbnail kgdev.jpg --iprofile cmyk
|
||||
<programlisting>
|
||||
$ vipsthumbnail fred.jpg \
|
||||
--size 128 \
|
||||
--eprofile srgb \
|
||||
-o tn_%s.jpg[optimize_coding,strip] \
|
||||
--eprofile srgb
|
||||
</programlisting>
|
||||
|
@ -6,6 +6,9 @@
|
||||
* - test and remove orientation from every ifd
|
||||
* 6/10/18
|
||||
* - don't remove orientation if it's one of the cases we don't handle
|
||||
* 10/5/20
|
||||
* - handle mirrored images
|
||||
* - deprecate vips_autorot_get_angle()
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -54,6 +57,7 @@ typedef struct _VipsAutorot {
|
||||
VipsImage *in;
|
||||
|
||||
VipsAngle angle;
|
||||
gboolean flip;
|
||||
|
||||
} VipsAutorot;
|
||||
|
||||
@ -61,79 +65,6 @@ typedef VipsConversionClass VipsAutorotClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsAutorot, vips_autorot, VIPS_TYPE_CONVERSION );
|
||||
|
||||
/**
|
||||
* vips_autorot_get_angle:
|
||||
* @image: image to fetch orientation from
|
||||
*
|
||||
* Examine the metadata on @im and return the #VipsAngle to rotate by to turn
|
||||
* the image upright.
|
||||
*
|
||||
* See also: vips_autorot().
|
||||
*
|
||||
* Returns: the #VipsAngle to rotate by to make the image upright.
|
||||
*/
|
||||
VipsAngle
|
||||
vips_autorot_get_angle( VipsImage *im )
|
||||
{
|
||||
int orientation;
|
||||
VipsAngle angle;
|
||||
|
||||
if( !vips_image_get_typeof( im, VIPS_META_ORIENTATION ) ||
|
||||
vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) )
|
||||
orientation = 1;
|
||||
|
||||
switch( orientation ) {
|
||||
case 6:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Other values do rotate + mirror, don't bother handling them
|
||||
* though, how common can mirroring be.
|
||||
*/
|
||||
angle = VIPS_ANGLE_D0;
|
||||
break;
|
||||
}
|
||||
|
||||
return( angle );
|
||||
}
|
||||
|
||||
/* TRUE if this is one of the cases we handle.
|
||||
*/
|
||||
static gboolean
|
||||
vips_autorot_handled( VipsImage *im )
|
||||
{
|
||||
int orientation;
|
||||
gboolean handled;
|
||||
|
||||
if( !vips_image_get_typeof( im, VIPS_META_ORIENTATION ) ||
|
||||
vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) )
|
||||
orientation = 1;
|
||||
|
||||
switch( orientation ) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 6:
|
||||
case 8:
|
||||
handled = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
handled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return( handled );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_autorot_remove_angle_sub( VipsImage *image,
|
||||
const char *field, GValue *value, void *my_data )
|
||||
@ -154,14 +85,14 @@ vips_autorot_remove_angle_sub( VipsImage *image,
|
||||
* vips_autorot_remove_angle: (method)
|
||||
* @image: image to remove orientation from
|
||||
*
|
||||
* Remove the orientation tag on @image. Also remove any exif orientation tags.
|
||||
*
|
||||
* See also: vips_autorot_get_angle().
|
||||
* Remove the orientation tag on @image. Also remove any exif orientation tags.
|
||||
* You must vips_copy() the image before calling this function since it
|
||||
* modifies metadata.
|
||||
*/
|
||||
void
|
||||
vips_autorot_remove_angle( VipsImage *image )
|
||||
{
|
||||
(void) vips_image_remove( image, VIPS_META_ORIENTATION );
|
||||
(void) vips_image_remove( image, VIPS_META_ORIENTATION );
|
||||
(void) vips_image_map( image, vips_autorot_remove_angle_sub, NULL );
|
||||
}
|
||||
|
||||
@ -170,27 +101,87 @@ vips_autorot_build( VipsObject *object )
|
||||
{
|
||||
VipsConversion *conversion = VIPS_CONVERSION( object );
|
||||
VipsAutorot *autorot = (VipsAutorot *) object;
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 );
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_autorot_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
VipsAngle angle;
|
||||
gboolean flip;
|
||||
VipsImage *in;
|
||||
|
||||
g_object_set( object,
|
||||
"angle", vips_autorot_get_angle( autorot->in ),
|
||||
NULL );
|
||||
in = autorot->in;
|
||||
|
||||
switch( vips_image_get_orientation( in ) ) {
|
||||
case 2:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
default:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
if( vips_autorot_handled( autorot->in ) ) {
|
||||
if( vips_rot( autorot->in, &t[0], autorot->angle, NULL ) ||
|
||||
vips_copy( t[0], &t[1], NULL ) )
|
||||
return( -1 );
|
||||
vips_autorot_remove_angle( t[1] );
|
||||
}
|
||||
else {
|
||||
if( vips_copy( autorot->in, &t[1], NULL ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_image_write( t[1], conversion->out ) )
|
||||
g_object_set( object,
|
||||
"angle", angle,
|
||||
"flip", flip,
|
||||
NULL );
|
||||
|
||||
if( angle != VIPS_ANGLE_D0 ) {
|
||||
if( vips_rot( in, &t[0], angle, NULL ) )
|
||||
return( -1 );
|
||||
in = t[0];
|
||||
}
|
||||
|
||||
if( flip ) {
|
||||
if( vips_flip( in, &t[1], VIPS_DIRECTION_HORIZONTAL, NULL ) )
|
||||
return( -1 );
|
||||
in = t[1];
|
||||
}
|
||||
|
||||
/* We must copy before modifying metadata.
|
||||
*/
|
||||
if( vips_copy( in, &t[2], NULL ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
vips_autorot_remove_angle( in );
|
||||
|
||||
if( vips_image_write( in, conversion->out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -220,13 +211,21 @@ vips_autorot_class_init( VipsAutorotClass *class )
|
||||
_( "Angle image was rotated by" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsAutorot, angle ),
|
||||
VIPS_TYPE_ANGLE, VIPS_ANGLE_D0 );
|
||||
VIPS_TYPE_ANGLE, VIPS_ANGLE_D0 );
|
||||
|
||||
VIPS_ARG_BOOL( class, "flip", 7,
|
||||
_( "Flip" ),
|
||||
_( "Whether the image was flipped or not" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsAutorot, flip ),
|
||||
FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_autorot_init( VipsAutorot *autorot )
|
||||
{
|
||||
autorot->angle = VIPS_ANGLE_D0;
|
||||
autorot->flip = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,18 +237,14 @@ vips_autorot_init( VipsAutorot *autorot )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @angle: output #VipsAngle the image was rotated by
|
||||
* * @flip: output %gboolean whether the image was flipped
|
||||
*
|
||||
* Look at the image metadata and rotate the image to make it upright. The
|
||||
* #VIPS_META_ORIENTATION tag is removed from @out to prevent accidental
|
||||
* double rotation.
|
||||
* Look at the image metadata and rotate and flip the image to make it
|
||||
* upright. The #VIPS_META_ORIENTATION tag is removed from @out to prevent
|
||||
* accidental double rotation.
|
||||
*
|
||||
* Read @angle to find the amount the image was rotated by.
|
||||
*
|
||||
* vips only supports the four simple rotations, it does not support the
|
||||
* various mirror modes. If the image is using one of these mirror modes, the
|
||||
* image is not rotated and the #VIPS_META_ORIENTATION tag is not removed.
|
||||
*
|
||||
* See also: vips_autorot_get_angle(), vips_autorot_remove_angle(), vips_rot().
|
||||
* Read @angle to find the amount the image was rotated by. Read @flip to
|
||||
* see if the image was also flipped.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
@ -265,4 +260,3 @@ vips_autorot( VipsImage *in, VipsImage **out, ... )
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
* - set Xoffset/Yoffset to ink left/top
|
||||
* 27/6/19
|
||||
* - fitting could occasionally terminate early [levmorozov]
|
||||
* 16/5/20 [keiviv]
|
||||
* - don't add fontfiles repeatedly
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -103,6 +105,10 @@ typedef VipsCreateClass VipsTextClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsText, vips_text, VIPS_TYPE_CREATE );
|
||||
|
||||
/* ... single-thread the body of vips_text() with this.
|
||||
*/
|
||||
static GMutex *vips_text_lock = NULL;
|
||||
|
||||
/* Just have one of these and reuse it.
|
||||
*
|
||||
* This does not unref cleanly on many platforms, so we will leak horribly
|
||||
@ -111,9 +117,10 @@ G_DEFINE_TYPE( VipsText, vips_text, VIPS_TYPE_CREATE );
|
||||
*/
|
||||
static PangoFontMap *vips_text_fontmap = NULL;
|
||||
|
||||
/* ... single-thread the body of vips_text() with this.
|
||||
/* All the fontfiles we've loaded. fontconfig lets you add a fontfile
|
||||
* repeatedly, and we obviously don't want that.
|
||||
*/
|
||||
static GMutex *vips_text_lock = NULL;
|
||||
static GHashTable *vips_text_fontfiles = NULL;
|
||||
|
||||
static void
|
||||
vips_text_dispose( GObject *gobject )
|
||||
@ -350,17 +357,26 @@ vips_text_build( VipsObject *object )
|
||||
|
||||
if( !vips_text_fontmap )
|
||||
vips_text_fontmap = pango_ft2_font_map_new();
|
||||
if( !vips_text_fontfiles )
|
||||
vips_text_fontfiles =
|
||||
g_hash_table_new( g_str_hash, g_str_equal );
|
||||
|
||||
text->context = pango_font_map_create_context(
|
||||
PANGO_FONT_MAP( vips_text_fontmap ) );
|
||||
|
||||
if( text->fontfile &&
|
||||
!FcConfigAppFontAddFile( NULL,
|
||||
!g_hash_table_lookup( vips_text_fontfiles, text->fontfile ) ) {
|
||||
if( !FcConfigAppFontAddFile( NULL,
|
||||
(const FcChar8 *) text->fontfile ) ) {
|
||||
vips_error( class->nickname,
|
||||
_( "unable to load font \"%s\"" ), text->fontfile );
|
||||
g_mutex_unlock( vips_text_lock );
|
||||
return( -1 );
|
||||
vips_error( class->nickname,
|
||||
_( "unable to load font \"%s\"" ),
|
||||
text->fontfile );
|
||||
g_mutex_unlock( vips_text_lock );
|
||||
return( -1 );
|
||||
}
|
||||
g_hash_table_insert( vips_text_fontfiles,
|
||||
text->fontfile,
|
||||
g_strdup( text->fontfile ) );
|
||||
}
|
||||
|
||||
/* If our caller set height and not dpi, we adjust dpi until
|
||||
@ -543,7 +559,7 @@ vips_text_init( VipsText *text )
|
||||
* * @fontfile: %gchararray, load this font file
|
||||
* * @width: %gint, image should be no wider than this many pixels
|
||||
* * @height: %gint, image should be no higher than this many pixels
|
||||
* * @align: #VipsAlign, left/centre/right alignment
|
||||
* * @align: #VipsAlign, set justification alignment
|
||||
* * @justify: %gboolean, justify lines
|
||||
* * @dpi: %gint, render at this resolution
|
||||
* * @autofit_dpi: %gint, read out auto-fitted DPI
|
||||
@ -564,11 +580,12 @@ vips_text_init( VipsText *text )
|
||||
*
|
||||
* @width is the number of pixels to word-wrap at. Lines of text wider than
|
||||
* this will be broken at word boundaries.
|
||||
* @align can be used to set the alignment style for multi-line
|
||||
* text. Note that the output image can be wider than @width if there are no
|
||||
* word breaks, or narrower if the lines don't break exactly at @width.
|
||||
*
|
||||
* Set @justify to turn on line justification.
|
||||
* @align can be used to set the alignment style for multi-line
|
||||
* text to the low (left) edge centre, or high (right) edge. Note that the
|
||||
* output image can be wider than @width if there are no
|
||||
* word breaks, or narrower if the lines don't break exactly at @width.
|
||||
*
|
||||
* @height is the maximum number of pixels high the generated text can be. This
|
||||
* only takes effect when @dpi is not set, and @width is set, making a box.
|
||||
|
@ -76,7 +76,7 @@ im_tiff_read_header( const char *filename, VipsImage *out,
|
||||
if( !(source = vips_source_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_header_source( source,
|
||||
out, page, n, autorotate ) ) {
|
||||
out, page, n, autorotate, -1 ) ) {
|
||||
VIPS_UNREF( source );
|
||||
return( -1 );
|
||||
}
|
||||
@ -93,7 +93,7 @@ im_tiff_read( const char *filename, VipsImage *out,
|
||||
|
||||
if( !(source = vips_source_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_source( source, out, page, n, autorotate ) ) {
|
||||
if( vips__tiff_read_source( source, out, page, n, autorotate, -1 ) ) {
|
||||
VIPS_UNREF( source );
|
||||
return( -1 );
|
||||
}
|
||||
|
@ -801,3 +801,15 @@ vips_warn( const char *domain, const char *fmt, ... )
|
||||
va_end( ap );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_autorot_get_angle:
|
||||
* @image: image to fetch orientation from
|
||||
*
|
||||
* This function is deprecated. Use vips_autorot() instead.
|
||||
*/
|
||||
VipsAngle
|
||||
vips_autorot_get_angle( VipsImage *im )
|
||||
{
|
||||
return( VIPS_ANGLE_D0 );
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@
|
||||
* to be a slow way to do it. This is where the draw operations come in.
|
||||
*
|
||||
* To use these operations, use vips_copy() to make a copy of the image you
|
||||
* want to modify, to ensure that no one else is using it, then call a
|
||||
* want to modify to ensure that no one else is using it, then call a
|
||||
* series of draw operations.
|
||||
* Once you are done drawing, return to normal use of vips operations. Any time
|
||||
* you want to start drawing again, you'll need to copy again.
|
||||
|
@ -413,6 +413,10 @@ vips_foreign_load_csv_load( VipsForeignLoad *load )
|
||||
for( y = 0; y < load->real->Ysize; y++ ) {
|
||||
csv->colno = 0;
|
||||
|
||||
/* Not needed, but stops a used-before-set compiler warning.
|
||||
*/
|
||||
ch = EOF;
|
||||
|
||||
for( x = 0; x < load->real->Xsize; x++ ) {
|
||||
double value;
|
||||
|
||||
|
@ -523,7 +523,8 @@ vips__exif_parse( VipsImage *image )
|
||||
int orientation;
|
||||
|
||||
orientation = atoi( str );
|
||||
if( orientation < 1 || orientation > 8 )
|
||||
if( orientation < 1 ||
|
||||
orientation > 8 )
|
||||
orientation = 1;
|
||||
vips_image_set_int( image, VIPS_META_ORIENTATION, orientation );
|
||||
}
|
||||
|
@ -237,7 +237,8 @@ static const char *heif_magic[] = {
|
||||
"ftyphevm", /* Multiview sequence */
|
||||
"ftyphevs", /* Scaleable sequence */
|
||||
"ftypmif1", /* Nokia alpha_ image */
|
||||
"ftypmsf1" /* Nokia animation image */
|
||||
"ftypmsf1", /* Nokia animation image */
|
||||
"ftypavif" /* AV1 image format */
|
||||
};
|
||||
|
||||
/* THe API has:
|
||||
|
@ -830,40 +830,6 @@ read_jpeg_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Auto-rotate, if rotate_image is set.
|
||||
*/
|
||||
static VipsImage *
|
||||
read_jpeg_rotate( VipsObject *process, VipsImage *im )
|
||||
{
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( process, 3 );
|
||||
VipsAngle angle = vips_autorot_get_angle( im );
|
||||
|
||||
if( angle != VIPS_ANGLE_D0 ) {
|
||||
/* Need to copy to memory or disc, we have to stay seq.
|
||||
*/
|
||||
const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE( im );
|
||||
const guint64 disc_threshold = vips_get_disc_threshold();
|
||||
|
||||
if( image_size > disc_threshold )
|
||||
t[0] = vips_image_new_temp_file( "%s.v" );
|
||||
else
|
||||
t[0] = vips_image_new_memory();
|
||||
|
||||
if( vips_image_write( im, t[0] ) ||
|
||||
vips_rot( t[0], &t[1], angle, NULL ) )
|
||||
return( NULL );
|
||||
im = t[1];
|
||||
|
||||
if( vips_copy( im, &t[2], NULL ) )
|
||||
return( NULL );
|
||||
im = t[2];
|
||||
|
||||
vips_autorot_remove_angle( im );
|
||||
}
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Read a cinfo to a VIPS image.
|
||||
*/
|
||||
static int
|
||||
@ -871,7 +837,7 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
{
|
||||
struct jpeg_decompress_struct *cinfo = &jpeg->cinfo;
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 3 );
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *im;
|
||||
|
||||
@ -902,10 +868,16 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
vips_extract_area( t[1], &t[2],
|
||||
0, 0, jpeg->output_width, jpeg->output_height, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
im = t[2];
|
||||
if( jpeg->autorotate )
|
||||
im = read_jpeg_rotate( VIPS_OBJECT( out ), im );
|
||||
|
||||
if( jpeg->autorotate &&
|
||||
vips_image_get_orientation( im ) != 1 ) {
|
||||
/* This will go via a huge memory buffer :-(
|
||||
*/
|
||||
if( vips_autorot( im, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
im = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( im, out ) )
|
||||
return( -1 );
|
||||
@ -948,15 +920,9 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
|
||||
|
||||
/* Swap width and height if we're going to rotate this image.
|
||||
*/
|
||||
if( jpeg->autorotate ) {
|
||||
VipsAngle angle = vips_autorot_get_angle( out );
|
||||
|
||||
if( angle == VIPS_ANGLE_D90 ||
|
||||
angle == VIPS_ANGLE_D270 )
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
|
||||
/* We won't be returning an orientation tag.
|
||||
*/
|
||||
if( jpeg->autorotate &&
|
||||
vips_image_get_orientation_swap( out ) ) {
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
vips_autorot_remove_angle( out );
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ int vips__tiff_write( VipsImage *in, const char *filename,
|
||||
VipsRegionShrink region_shrink,
|
||||
int level,
|
||||
gboolean lossless,
|
||||
VipsForeignDzDepth depth );
|
||||
VipsForeignDzDepth depth,
|
||||
gboolean subifd );
|
||||
|
||||
int vips__tiff_write_buf( VipsImage *in,
|
||||
void **obuf, size_t *olen,
|
||||
@ -81,14 +82,15 @@ int vips__tiff_write_buf( VipsImage *in,
|
||||
VipsRegionShrink region_shrink,
|
||||
int level,
|
||||
gboolean lossless,
|
||||
VipsForeignDzDepth depth );
|
||||
VipsForeignDzDepth depth,
|
||||
gboolean subifd );
|
||||
|
||||
gboolean vips__istiff_source( VipsSource *source );
|
||||
gboolean vips__istifftiled_source( VipsSource *source );
|
||||
int vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate );
|
||||
int page, int n, gboolean autorotate, int subifd );
|
||||
int vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate );
|
||||
int page, int n, gboolean autorotate, int subifd );
|
||||
|
||||
extern const char *vips__foreign_tiff_suffs[];
|
||||
|
||||
|
@ -197,6 +197,8 @@
|
||||
* - read logluv images as XYZ
|
||||
* 11/4/20 petoor
|
||||
* - better handling of aligned reads in multipage tiffs
|
||||
* 28/5/20
|
||||
* - add subifd
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -269,7 +271,7 @@ typedef struct _RtiffHeader {
|
||||
int alpha_band;
|
||||
uint16 compression;
|
||||
|
||||
/* Result of TIFFIsTiled().
|
||||
/* Is this directory tiled.
|
||||
*/
|
||||
gboolean tiled;
|
||||
|
||||
@ -302,6 +304,15 @@ typedef struct _RtiffHeader {
|
||||
/* Scale factor to get absolute cd/m2 from XYZ.
|
||||
*/
|
||||
double stonits;
|
||||
|
||||
/* Number of subifds, if any.
|
||||
*/
|
||||
int subifd_count;
|
||||
|
||||
/* Optional IMAGEDESCRIPTION.
|
||||
*/
|
||||
char *image_description;
|
||||
|
||||
} RtiffHeader;
|
||||
|
||||
/* Scanline-type process function.
|
||||
@ -320,6 +331,7 @@ typedef struct _Rtiff {
|
||||
int page;
|
||||
int n;
|
||||
gboolean autorotate;
|
||||
int subifd;
|
||||
|
||||
/* The TIFF we read.
|
||||
*/
|
||||
@ -527,7 +539,7 @@ rtiff_minimise_cb( VipsImage *image, Rtiff *rtiff )
|
||||
|
||||
static Rtiff *
|
||||
rtiff_new( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate )
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
@ -540,6 +552,7 @@ rtiff_new( VipsSource *source, VipsImage *out,
|
||||
rtiff->page = page;
|
||||
rtiff->n = n;
|
||||
rtiff->autorotate = autorotate;
|
||||
rtiff->subifd = subifd;
|
||||
rtiff->tiff = NULL;
|
||||
rtiff->n_pages = 0;
|
||||
rtiff->current_page = -1;
|
||||
@ -608,7 +621,8 @@ rtiff_set_page( Rtiff *rtiff, int page )
|
||||
{
|
||||
if( rtiff->current_page != page ) {
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_set_page: selecting page %d\n", page );
|
||||
printf( "rtiff_set_page: selecting page %d, subifd %d\n",
|
||||
page, rtiff->subifd );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !TIFFSetDirectory( rtiff->tiff, page ) ) {
|
||||
@ -617,7 +631,43 @@ rtiff_set_page( Rtiff *rtiff, int page )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( rtiff->subifd >= 0 ) {
|
||||
int subifd_count;
|
||||
toff_t *subifd_offsets;
|
||||
|
||||
if( !TIFFGetField( rtiff->tiff, TIFFTAG_SUBIFD,
|
||||
&subifd_count, &subifd_offsets ) ) {
|
||||
vips_error( "tiff2vips",
|
||||
"%s", _( "no SUBIFD tag" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( subifd_count <= 0 ||
|
||||
rtiff->subifd >= subifd_count ) {
|
||||
vips_error( "tiff2vips",
|
||||
_( "subifd %d out of range, "
|
||||
"only 0-%d available" ),
|
||||
rtiff->subifd,
|
||||
subifd_count - 1 );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( !TIFFSetSubDirectory( rtiff->tiff,
|
||||
subifd_offsets[rtiff->subifd] ) ) {
|
||||
vips_error( "tiff2vips",
|
||||
"%s", _( "subdirectory unreadable" ) );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
rtiff->current_page = page;
|
||||
|
||||
/* This can get unset when we change directories. Make sure
|
||||
* it's set again.
|
||||
*/
|
||||
if( rtiff->header.compression == COMPRESSION_JPEG )
|
||||
TIFFSetField( rtiff->tiff,
|
||||
TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@ -633,7 +683,9 @@ rtiff_n_pages( Rtiff *rtiff )
|
||||
for( n = 1; TIFFReadDirectory( rtiff->tiff ); n++ )
|
||||
;
|
||||
|
||||
(void) TIFFSetDirectory( rtiff->tiff, rtiff->current_page );
|
||||
/* Make sure the nest set_page() will set the directory.
|
||||
*/
|
||||
rtiff->current_page = -1;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_n_pages: found %d pages\n", n );
|
||||
@ -1512,6 +1564,10 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out )
|
||||
vips_image_set_int( out,
|
||||
VIPS_META_PAGE_HEIGHT, rtiff->header.height );
|
||||
|
||||
if( rtiff->header.subifd_count > 0 )
|
||||
vips_image_set_int( out,
|
||||
VIPS_META_N_SUBIFDS, rtiff->header.subifd_count );
|
||||
|
||||
vips_image_set_int( out, VIPS_META_N_PAGES, rtiff->n_pages );
|
||||
|
||||
/* Even though we could end up serving tiled data, always hint
|
||||
@ -1520,17 +1576,6 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out )
|
||||
*/
|
||||
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_set_header: header.samples_per_pixel = %d\n",
|
||||
rtiff->header.samples_per_pixel );
|
||||
printf( "rtiff_set_header: header.bits_per_sample = %d\n",
|
||||
rtiff->header.bits_per_sample );
|
||||
printf( "rtiff_set_header: header.sample_format = %d\n",
|
||||
rtiff->header.sample_format );
|
||||
printf( "rtiff_set_header: header.orientation = %d\n",
|
||||
rtiff->header.orientation );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* We have a range of output paths. Look at the tiff header and try to
|
||||
* route the input image to the best output path.
|
||||
*/
|
||||
@ -1540,18 +1585,16 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out )
|
||||
/* Read any ICC profile.
|
||||
*/
|
||||
if( TIFFGetField( rtiff->tiff,
|
||||
TIFFTAG_ICCPROFILE, &data_length, &data ) ) {
|
||||
TIFFTAG_ICCPROFILE, &data_length, &data ) )
|
||||
vips_image_set_blob_copy( out,
|
||||
VIPS_META_ICC_NAME, data, data_length );
|
||||
}
|
||||
|
||||
/* Read any XMP metadata.
|
||||
*/
|
||||
if( TIFFGetField( rtiff->tiff,
|
||||
TIFFTAG_XMLPACKET, &data_length, &data ) ) {
|
||||
TIFFTAG_XMLPACKET, &data_length, &data ) )
|
||||
vips_image_set_blob_copy( out,
|
||||
VIPS_META_XMP_NAME, data, data_length );
|
||||
}
|
||||
|
||||
/* Read any IPTC metadata.
|
||||
*/
|
||||
@ -1569,20 +1612,13 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out )
|
||||
/* Read any photoshop metadata.
|
||||
*/
|
||||
if( TIFFGetField( rtiff->tiff,
|
||||
TIFFTAG_PHOTOSHOP, &data_length, &data ) ) {
|
||||
TIFFTAG_PHOTOSHOP, &data_length, &data ) )
|
||||
vips_image_set_blob_copy( out,
|
||||
VIPS_META_PHOTOSHOP_NAME, data, data_length );
|
||||
}
|
||||
|
||||
/* IMAGEDESCRIPTION often has useful metadata.
|
||||
*/
|
||||
if( TIFFGetField( rtiff->tiff, TIFFTAG_IMAGEDESCRIPTION, &data ) ) {
|
||||
/* libtiff makes sure that data is null-terminated and contains
|
||||
* no embedded null characters.
|
||||
*/
|
||||
vips_image_set_string( out,
|
||||
VIPS_META_IMAGEDESCRIPTION, (char *) data );
|
||||
}
|
||||
if( rtiff->header.image_description )
|
||||
vips_image_set_string( out, VIPS_META_IMAGEDESCRIPTION,
|
||||
rtiff->header.image_description );
|
||||
|
||||
if( get_resolution( rtiff->tiff, out ) )
|
||||
return( -1 );
|
||||
@ -1689,7 +1725,7 @@ rtiff_fill_region_unaligned( VipsRegion *out,
|
||||
/* Not necessary, but it stops static analyzers complaining
|
||||
* about a used-before-set.
|
||||
*/
|
||||
tile.height = 0;
|
||||
hit.height = 0;
|
||||
|
||||
x = 0;
|
||||
while( x < r->width ) {
|
||||
@ -1753,10 +1789,13 @@ rtiff_fill_region_unaligned( VipsRegion *out,
|
||||
q, p, hit.width, rtiff->client );
|
||||
}
|
||||
|
||||
x += tile.width;
|
||||
x += hit.width;
|
||||
}
|
||||
|
||||
y += tile.height;
|
||||
/* This will be the same for all tiles in the row we've just
|
||||
* done.
|
||||
*/
|
||||
y += hit.height;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@ -1823,59 +1862,6 @@ rtiff_seq_stop( void *seq, void *a, void *b )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Auto-rotate handling.
|
||||
*/
|
||||
static int
|
||||
rtiff_autorotate( Rtiff *rtiff, VipsImage *in, VipsImage **out )
|
||||
{
|
||||
VipsAngle angle = vips_autorot_get_angle( in );
|
||||
|
||||
if( rtiff->autorotate &&
|
||||
angle != VIPS_ANGLE_D0 ) {
|
||||
/* Need to copy to memory or disc, we have to stay seq.
|
||||
*/
|
||||
const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE( in );
|
||||
const guint64 disc_threshold = vips_get_disc_threshold();
|
||||
|
||||
VipsImage *im;
|
||||
VipsImage *x;
|
||||
|
||||
if( image_size > disc_threshold )
|
||||
im = vips_image_new_temp_file( "%s.v" );
|
||||
else
|
||||
im = vips_image_new_memory();
|
||||
|
||||
if( vips_image_write( in, im ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_rot( im, &x, angle, NULL ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( im );
|
||||
im = x;
|
||||
|
||||
if( vips_copy( im, out, NULL ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( im );
|
||||
|
||||
/* We must remove the tag to prevent accidental
|
||||
* double rotations.
|
||||
*/
|
||||
vips_autorot_remove_angle( *out );
|
||||
}
|
||||
else {
|
||||
*out = in;
|
||||
g_object_ref( in );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Unpremultiply associative alpha, if any.
|
||||
*/
|
||||
static int
|
||||
@ -1913,6 +1899,8 @@ rtiff_read_tilewise( Rtiff *rtiff, VipsImage *out )
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: rtiff_read_tilewise\n" );
|
||||
#endif /*DEBUG*/
|
||||
@ -1952,21 +1940,31 @@ rtiff_read_tilewise( Rtiff *rtiff, VipsImage *out )
|
||||
*/
|
||||
vips_image_pipelinev( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||
|
||||
if( vips_image_generate( t[0],
|
||||
rtiff_seq_start, rtiff_fill_region, rtiff_seq_stop,
|
||||
rtiff, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Copy to out, adding a cache. Enough tiles for two complete rows.
|
||||
/* Generate to out, adding a cache. Enough tiles for two complete rows.
|
||||
*/
|
||||
if( vips_tilecache( t[0], &t[1],
|
||||
"tile_width", tile_width,
|
||||
"tile_height", tile_height,
|
||||
"max_tiles", 2 * (1 + t[0]->Xsize / tile_width),
|
||||
NULL ) ||
|
||||
rtiff_autorotate( rtiff, t[1], &t[2] ) ||
|
||||
rtiff_unpremultiply( rtiff, t[2], &t[3] ) ||
|
||||
vips_image_write( t[3], out ) )
|
||||
if(
|
||||
vips_image_generate( t[0],
|
||||
rtiff_seq_start, rtiff_fill_region, rtiff_seq_stop,
|
||||
rtiff, NULL ) ||
|
||||
vips_tilecache( t[0], &t[1],
|
||||
"tile_width", tile_width,
|
||||
"tile_height", tile_height,
|
||||
"max_tiles", 2 * (1 + t[0]->Xsize / tile_width),
|
||||
NULL ) ||
|
||||
rtiff_unpremultiply( rtiff, t[1], &t[2] ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
/* Only do this if we have to.
|
||||
*/
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation( in ) != 1 ) {
|
||||
if( vips_autorot( in, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
in = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -2187,6 +2185,8 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out )
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: rtiff_read_stripwise\n" );
|
||||
#endif /*DEBUG*/
|
||||
@ -2197,19 +2197,6 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out )
|
||||
|
||||
vips_image_pipelinev( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_read_stripwise: header.rows_per_strip = %u\n",
|
||||
rtiff->header.rows_per_strip );
|
||||
printf( "rtiff_read_stripwise: header.strip_size = %zd\n",
|
||||
rtiff->header.strip_size );
|
||||
printf( "rtiff_read_stripwise: header.number_of_strips = %d\n",
|
||||
rtiff->header.number_of_strips );
|
||||
printf( "rtiff_read_stripwise: header.read_height = %u\n",
|
||||
rtiff->header.read_height );
|
||||
printf( "rtiff_read_stripwise: header.read_size = %zd\n",
|
||||
rtiff->header.read_size );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Double check: in memcpy mode, the vips linesize should exactly
|
||||
* match the tiff line size.
|
||||
*/
|
||||
@ -2275,9 +2262,20 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out )
|
||||
vips_sequential( t[0], &t[1],
|
||||
"tile_height", rtiff->header.read_height,
|
||||
NULL ) ||
|
||||
rtiff_autorotate( rtiff, t[1], &t[2] ) ||
|
||||
rtiff_unpremultiply( rtiff, t[2], &t[3] ) ||
|
||||
vips_image_write( t[3], out ) )
|
||||
rtiff_unpremultiply( rtiff, t[1], &t[2] ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
/* Only do this if we have to.
|
||||
*/
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation( in ) != 1 ) {
|
||||
if( vips_autorot( in, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
in = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -2290,6 +2288,8 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
{
|
||||
uint16 extra_samples_count;
|
||||
uint16 *extra_samples_types;
|
||||
toff_t *subifd_offsets;
|
||||
char *image_description;
|
||||
|
||||
if( !tfget32( rtiff->tiff, TIFFTAG_IMAGEWIDTH,
|
||||
&header->width ) ||
|
||||
@ -2387,10 +2387,42 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
header->separate = TRUE;
|
||||
}
|
||||
|
||||
/* Stays zero if there's no SUBIFD.
|
||||
*/
|
||||
TIFFGetField( rtiff->tiff, TIFFTAG_SUBIFD,
|
||||
&header->subifd_count, &subifd_offsets );
|
||||
|
||||
/* IMAGEDESCRIPTION often has useful metadata. libtiff makes sure
|
||||
* that data is null-terminated and contains no embedded null
|
||||
* characters.
|
||||
*/
|
||||
if( TIFFGetField( rtiff->tiff,
|
||||
TIFFTAG_IMAGEDESCRIPTION, &image_description ) )
|
||||
header->image_description =
|
||||
vips_strdup( VIPS_OBJECT( rtiff->out ),
|
||||
image_description );
|
||||
|
||||
/* Tiles and strip images have slightly different fields.
|
||||
*/
|
||||
header->tiled = TIFFIsTiled( rtiff->tiff );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_header_read: header.width = %d\n",
|
||||
header->width );
|
||||
printf( "rtiff_header_read: header.height = %d\n",
|
||||
header->height );
|
||||
printf( "rtiff_header_read: header.samples_per_pixel = %d\n",
|
||||
header->samples_per_pixel );
|
||||
printf( "rtiff_header_read: header.bits_per_sample = %d\n",
|
||||
header->bits_per_sample );
|
||||
printf( "rtiff_header_read: header.sample_format = %d\n",
|
||||
header->sample_format );
|
||||
printf( "rtiff_header_read: header.orientation = %d\n",
|
||||
header->orientation );
|
||||
printf( "rtiff_header_read: header.tiled = %d\n",
|
||||
header->tiled );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( header->tiled ) {
|
||||
if( !tfget32( rtiff->tiff,
|
||||
TIFFTAG_TILEWIDTH, &header->tile_width ) ||
|
||||
@ -2398,6 +2430,13 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
TIFFTAG_TILELENGTH, &header->tile_height ) )
|
||||
return( -1 );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_header_read: header.tile_width = %d\n",
|
||||
header->tile_width );
|
||||
printf( "rtiff_header_read: header.tile_height = %d\n",
|
||||
header->tile_height );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Arbitrary sanity-checking limits.
|
||||
*/
|
||||
if( header->tile_width <= 0 ||
|
||||
@ -2412,6 +2451,13 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
header->tile_size = TIFFTileSize( rtiff->tiff );
|
||||
header->tile_row_size = TIFFTileRowSize( rtiff->tiff );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_header_read: header.tile_size = %zd\n",
|
||||
header->tile_size );
|
||||
printf( "rtiff_header_read: header.tile_row_size = %zd\n",
|
||||
header->tile_row_size );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Fuzzed TIFFs can give crazy values for tile_size. Sanity
|
||||
* check at 100mb per tile.
|
||||
*/
|
||||
@ -2440,6 +2486,17 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
header->scanline_size = TIFFScanlineSize( rtiff->tiff );
|
||||
header->number_of_strips = TIFFNumberOfStrips( rtiff->tiff );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_header_read: header.rows_per_strip = %d\n",
|
||||
header->rows_per_strip );
|
||||
printf( "rtiff_header_read: header.strip_size = %zd\n",
|
||||
header->strip_size );
|
||||
printf( "rtiff_header_read: header.scanline_size = %zd\n",
|
||||
header->scanline_size );
|
||||
printf( "rtiff_header_read: header.number_of_strips = %d\n",
|
||||
header->number_of_strips );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* libtiff has two strip-wise readers. TIFFReadEncodedStrip()
|
||||
* decompresses an entire strip to memory. It's fast, but it
|
||||
* will need a lot of ram if the strip is large.
|
||||
@ -2478,6 +2535,15 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header )
|
||||
header->read_size = header->strip_size;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_header_read: header.read_scanlinewise = %d\n",
|
||||
header->read_scanlinewise );
|
||||
printf( "rtiff_header_read: header.read_height = %d\n",
|
||||
header->read_height );
|
||||
printf( "rtiff_header_read: header.read_size = %zd\n",
|
||||
header->read_size );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Stop some compiler warnings.
|
||||
*/
|
||||
header->tile_width = 0;
|
||||
@ -2545,7 +2611,8 @@ static int
|
||||
rtiff_header_read_all( Rtiff *rtiff )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: reading header for page %d ...\n", rtiff->page );
|
||||
printf( "rtiff_header_read_all: "
|
||||
"reading header for page %d ...\n", rtiff->page );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( rtiff_set_page( rtiff, rtiff->page ) ||
|
||||
@ -2567,7 +2634,8 @@ rtiff_header_read_all( Rtiff *rtiff )
|
||||
RtiffHeader header;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: verifying header for page %d ...\n",
|
||||
printf( "rtiff_header_read_all: "
|
||||
"verifying header for page %d ...\n",
|
||||
rtiff->page + i );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
@ -2587,29 +2655,6 @@ rtiff_header_read_all( Rtiff *rtiff )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* On a header-only read, we can just swap width/height if orientation is 6 or
|
||||
* 8.
|
||||
*/
|
||||
static void
|
||||
vips__tiff_read_header_orientation( Rtiff *rtiff, VipsImage *out )
|
||||
{
|
||||
int orientation;
|
||||
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_typeof( out, VIPS_META_ORIENTATION ) &&
|
||||
!vips_image_get_int( out,
|
||||
VIPS_META_ORIENTATION, &orientation ) ) {
|
||||
if( orientation == 3 ||
|
||||
orientation == 6 )
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
|
||||
/* We must remove VIPS_META_ORIENTATION to prevent accidental
|
||||
* double rotations.
|
||||
*/
|
||||
vips_image_remove( out, VIPS_META_ORIENTATION );
|
||||
}
|
||||
}
|
||||
|
||||
typedef gboolean (*TiffPropertyFn)( TIFF *tif );
|
||||
|
||||
static gboolean
|
||||
@ -2646,20 +2691,24 @@ vips__istifftiled_source( VipsSource *source )
|
||||
|
||||
int
|
||||
vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate )
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
vips__tiff_init();
|
||||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate )) ||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate, subifd )) ||
|
||||
rtiff_header_read_all( rtiff ) )
|
||||
return( -1 );
|
||||
|
||||
if( rtiff_set_header( rtiff, out ) )
|
||||
return( -1 );
|
||||
|
||||
vips__tiff_read_header_orientation( rtiff, out );
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation_swap( out ) ) {
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
vips_autorot_remove_angle( out );
|
||||
}
|
||||
|
||||
/* We never call vips_source_decode() since we need to be able to
|
||||
* seek() the whole way through the file. Just minimise instead,
|
||||
@ -2671,7 +2720,7 @@ vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
|
||||
int
|
||||
vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate )
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
@ -2681,7 +2730,7 @@ vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
|
||||
vips__tiff_init();
|
||||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate )) ||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate, subifd )) ||
|
||||
rtiff_header_read_all( rtiff ) )
|
||||
return( -1 );
|
||||
|
||||
|
@ -69,6 +69,10 @@ typedef struct _VipsForeignLoadTiff {
|
||||
*/
|
||||
int n;
|
||||
|
||||
/* Select subifd index. -1 for main image.
|
||||
*/
|
||||
int subifd;
|
||||
|
||||
/* Autorotate using orientation tag.
|
||||
*/
|
||||
gboolean autorotate;
|
||||
@ -133,7 +137,7 @@ vips_foreign_load_tiff_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
||||
|
||||
if( vips__tiff_read_header_source( tiff->source, load->out,
|
||||
tiff->page, tiff->n, tiff->autorotate ) )
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -145,7 +149,7 @@ vips_foreign_load_tiff_load( VipsForeignLoad *load )
|
||||
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
||||
|
||||
if( vips__tiff_read_source( tiff->source, load->real,
|
||||
tiff->page, tiff->n, tiff->autorotate ) )
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -203,6 +207,14 @@ vips_foreign_load_tiff_class_init( VipsForeignLoadTiffClass *class )
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadTiff, autorotate ),
|
||||
FALSE );
|
||||
|
||||
VIPS_ARG_INT( class, "subifd", 21,
|
||||
_( "subifd" ),
|
||||
_( "Select subifd index" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadTiff, subifd ),
|
||||
-1, 100000, -1 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -210,6 +222,7 @@ vips_foreign_load_tiff_init( VipsForeignLoadTiff *tiff )
|
||||
{
|
||||
tiff->page = 0;
|
||||
tiff->n = 1;
|
||||
tiff->subifd = -1;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignLoadTiffSource {
|
||||
@ -454,6 +467,7 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer )
|
||||
* * @n: %gint, load this many pages
|
||||
* * @autorotate: %gboolean, use orientation tag to rotate the image
|
||||
* during load
|
||||
* * @subifd: %gint, select this subifd index
|
||||
*
|
||||
* Read a TIFF file into a VIPS image. It is a full baseline TIFF 6 reader,
|
||||
* with extensions for tiled images, multipage images, XYZ and LAB colour
|
||||
@ -478,6 +492,14 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer )
|
||||
* operations will use #VIPS_META_ORIENTATION, if present, to set the
|
||||
* orientation of output images.
|
||||
*
|
||||
* If @autorotate is TRUE, the image will be rotated upright during load and
|
||||
* no metadata attached. This can be very slow.
|
||||
*
|
||||
* If @subifd is -1 (the default), the main image is selected for each page.
|
||||
* If it is 0 or greater and there is a SUBIFD tag, the indexed SUBIFD is
|
||||
* selected. This can be used to read lower resolution layers from
|
||||
* bioformats-style image pyramids.
|
||||
*
|
||||
* Any ICC profile is read and attached to the VIPS image as
|
||||
* #VIPS_META_ICC_NAME. Any XMP metadata is read and attached to the image
|
||||
* as #VIPS_META_XMP_NAME. Any IPTC is attached as #VIPS_META_IPTC_NAME. The
|
||||
@ -515,6 +537,7 @@ vips_tiffload( const char *filename, VipsImage **out, ... )
|
||||
* * @n: %gint, load this many pages
|
||||
* * @autorotate: %gboolean, use orientation tag to rotate the image
|
||||
* during load
|
||||
* * @subifd: %gint, select this subifd index
|
||||
*
|
||||
* Read a TIFF-formatted memory block into a VIPS image. Exactly as
|
||||
* vips_tiffload(), but read from a memory source.
|
||||
@ -558,6 +581,7 @@ vips_tiffload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
* * @n: %gint, load this many pages
|
||||
* * @autorotate: %gboolean, use orientation tag to rotate the image
|
||||
* during load
|
||||
* * @subifd: %gint, select this subifd index
|
||||
*
|
||||
* Exactly as vips_tiffload(), but read from a source.
|
||||
*
|
||||
|
@ -21,6 +21,8 @@
|
||||
* - xres/yres params were in pixels/cm
|
||||
* 26/1/20
|
||||
* - add "depth" to set pyr depth
|
||||
* 12/5/20
|
||||
* - add "subifd" to create pyr layers as sub-directories
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -98,6 +100,8 @@ typedef struct _VipsForeignSaveTiff {
|
||||
int level;
|
||||
gboolean lossless;
|
||||
VipsForeignDzDepth depth;
|
||||
gboolean subifd;
|
||||
|
||||
} VipsForeignSaveTiff;
|
||||
|
||||
typedef VipsForeignSaveClass VipsForeignSaveTiffClass;
|
||||
@ -327,7 +331,7 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
|
||||
1, 22, 10 );
|
||||
|
||||
VIPS_ARG_BOOL( class, "lossless", 24,
|
||||
_( "lossless" ),
|
||||
_( "Lossless" ),
|
||||
_( "Enable WEBP lossless mode" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, lossless ),
|
||||
@ -340,6 +344,13 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, depth ),
|
||||
VIPS_TYPE_FOREIGN_DZ_DEPTH, VIPS_FOREIGN_DZ_DEPTH_ONETILE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "subifd", 24,
|
||||
_( "Sub-IFD" ),
|
||||
_( "Save pyr layers as sub-IFDs" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, subifd ),
|
||||
FALSE );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -396,7 +407,8 @@ vips_foreign_save_tiff_file_build( VipsObject *object )
|
||||
tiff->region_shrink,
|
||||
tiff->level,
|
||||
tiff->lossless,
|
||||
tiff->depth ) )
|
||||
tiff->depth,
|
||||
tiff->subifd ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -468,7 +480,8 @@ vips_foreign_save_tiff_buffer_build( VipsObject *object )
|
||||
tiff->region_shrink,
|
||||
tiff->level,
|
||||
tiff->lossless,
|
||||
tiff->depth ) )
|
||||
tiff->depth,
|
||||
tiff->subifd ) )
|
||||
return( -1 );
|
||||
|
||||
/* vips__tiff_write_buf() makes a buffer that needs g_free(), not
|
||||
@ -537,6 +550,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
|
||||
* * @level: %gint, Zstd compression level
|
||||
* * @lossless: %gboolean, WebP losssless mode
|
||||
* * @depth: #VipsForeignDzDepth how deep to make the pyramid
|
||||
* * @subifd: %gboolean write pyr layers as sub-ifds
|
||||
*
|
||||
* Write a VIPS image to a file as TIFF.
|
||||
*
|
||||
@ -620,6 +634,10 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
|
||||
* #VIPS_META_PHOTOSHOP_NAME (if set) is used to set the value of the PHOTOSHOP
|
||||
* tag.
|
||||
*
|
||||
* By default, pyramid layers are saved as consecutive pages.
|
||||
* Set @subifd to save pyramid layers as sub-directories of the main image.
|
||||
* Setting this option can improve compatibility with formats like OME.
|
||||
*
|
||||
* See also: vips_tiffload(), vips_image_write_to_file().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
@ -665,6 +683,7 @@ vips_tiffsave( VipsImage *in, const char *filename, ... )
|
||||
* * @level: %gint, Zstd compression level
|
||||
* * @lossless: %gboolean, WebP losssless mode
|
||||
* * @depth: #VipsForeignDzDepth how deep to make the pyramid
|
||||
* * @subifd: %gboolean write pyr layers as sub-ifds
|
||||
*
|
||||
* As vips_tiffsave(), but save to a memory buffer.
|
||||
*
|
||||
|
@ -193,6 +193,8 @@
|
||||
* - write XYZ images as logluv
|
||||
* 7/2/20 [jclavoie-jive]
|
||||
* - add PAGENUMBER support
|
||||
* 23/5/20
|
||||
* - add support for subifd pyramid layers
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -247,6 +249,21 @@
|
||||
#include "pforeign.h"
|
||||
#include "tiff.h"
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* - add a flag for plane-separate write
|
||||
*
|
||||
* At the moment, we write bioformats-style TIFFs by splitting bands up,
|
||||
* making a toilet-roll image and writing out in pages. The TIFFs we make
|
||||
* are not tagged as plane-separate and do not have (eg.) RGB photometric
|
||||
* interpretation. Moreover, when working from an RGB source, we'll end
|
||||
* up reading the input three times.
|
||||
*
|
||||
* A write-plane-separate flag to the TIFF writer could let us set the
|
||||
* photometric interpretation correctly, and save all planes in a single
|
||||
* pass before doing a final gather sweep.
|
||||
*/
|
||||
|
||||
/* Max number of alpha channels we allow.
|
||||
*/
|
||||
#define MAX_ALPHA (64)
|
||||
@ -334,6 +351,7 @@ struct _Wtiff {
|
||||
int level; /* zstd compression level */
|
||||
gboolean lossless; /* webp lossless mode */
|
||||
VipsForeignDzDepth depth; /* Pyr depth */
|
||||
gboolean subifd; /* Write pyr layers into subifds */
|
||||
|
||||
/* True if we've detected a toilet-roll image, plus the page height,
|
||||
* which has been checked to be a factor of im->Ysize. page_number
|
||||
@ -395,40 +413,62 @@ embed_profile_meta( TIFF *tif, VipsImage *im )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static Layer *
|
||||
wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
|
||||
static void
|
||||
wtiff_layer_init( Wtiff *wtiff, Layer **layer, Layer *above,
|
||||
int width, int height )
|
||||
{
|
||||
Layer *layer;
|
||||
if( !*layer ) {
|
||||
*layer = VIPS_NEW( wtiff->ready, Layer );
|
||||
(*layer)->wtiff = wtiff;
|
||||
(*layer)->width = width;
|
||||
(*layer)->height = height;
|
||||
|
||||
layer = VIPS_NEW( wtiff->ready, Layer );
|
||||
layer->wtiff = wtiff;
|
||||
layer->width = width;
|
||||
layer->height = height;
|
||||
if( !above )
|
||||
/* Top of pyramid.
|
||||
*/
|
||||
(*layer)->sub = 1;
|
||||
else
|
||||
(*layer)->sub = above->sub * 2;
|
||||
|
||||
if( !above )
|
||||
/* Top of pyramid.
|
||||
(*layer)->lname = NULL;
|
||||
(*layer)->buf = NULL;
|
||||
(*layer)->len = 0;
|
||||
(*layer)->tif = NULL;
|
||||
(*layer)->image = NULL;
|
||||
(*layer)->write_y = 0;
|
||||
(*layer)->y = 0;
|
||||
(*layer)->strip = NULL;
|
||||
(*layer)->copy = NULL;
|
||||
|
||||
(*layer)->below = NULL;
|
||||
(*layer)->above = above;
|
||||
|
||||
/* The name for the top layer is the output filename.
|
||||
*
|
||||
* We need lname to be freed automatically: it has to stay
|
||||
* alive until after wtiff_gather().
|
||||
*/
|
||||
layer->sub = 1;
|
||||
else
|
||||
layer->sub = above->sub * 2;
|
||||
if( wtiff->filename ) {
|
||||
if( !above )
|
||||
(*layer)->lname = vips_strdup(
|
||||
VIPS_OBJECT( wtiff->ready ),
|
||||
wtiff->filename );
|
||||
else {
|
||||
char *lname;
|
||||
|
||||
layer->lname = NULL;
|
||||
layer->buf = NULL;
|
||||
layer->len = 0;
|
||||
layer->tif = NULL;
|
||||
layer->image = NULL;
|
||||
layer->write_y = 0;
|
||||
layer->y = 0;
|
||||
layer->strip = NULL;
|
||||
layer->copy = NULL;
|
||||
lname = vips__temp_name( "%s.tif" );
|
||||
(*layer)->lname = vips_strdup(
|
||||
VIPS_OBJECT( wtiff->ready ),
|
||||
lname );
|
||||
g_free( lname );
|
||||
}
|
||||
}
|
||||
|
||||
layer->below = NULL;
|
||||
layer->above = above;
|
||||
|
||||
/*
|
||||
printf( "wtiff_layer_new: sub = %d, width = %d, height = %d\n",
|
||||
layer->sub, width, height );
|
||||
*/
|
||||
/*
|
||||
printf( "wtiff_layer_init: sub = %d, width = %d, height = %d\n",
|
||||
(*layer)->sub, width, height );
|
||||
*/
|
||||
}
|
||||
|
||||
if( wtiff->pyramid ) {
|
||||
int limitw, limith;
|
||||
@ -458,34 +498,13 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
|
||||
* Very tall or wide images might end up with a smallest layer
|
||||
* larger than one tile.
|
||||
*/
|
||||
if( (layer->width > limitw ||
|
||||
layer->height > limith) &&
|
||||
layer->width > 1 &&
|
||||
layer->height > 1 )
|
||||
layer->below = wtiff_layer_new( wtiff, layer,
|
||||
if( ((*layer)->width > limitw ||
|
||||
(*layer)->height > limith) &&
|
||||
(*layer)->width > 1 &&
|
||||
(*layer)->height > 1 )
|
||||
wtiff_layer_init( wtiff, &(*layer)->below, *layer,
|
||||
width / 2, height / 2 );
|
||||
}
|
||||
|
||||
/* The name for the top layer is the output filename.
|
||||
*
|
||||
* We need lname to be freed automatically: it has to stay
|
||||
* alive until after wtiff_gather().
|
||||
*/
|
||||
if( wtiff->filename ) {
|
||||
if( !above )
|
||||
layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
|
||||
wtiff->filename );
|
||||
else {
|
||||
char *lname;
|
||||
|
||||
lname = vips__temp_name( "%s.tif" );
|
||||
layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
|
||||
lname );
|
||||
g_free( lname );
|
||||
}
|
||||
}
|
||||
|
||||
return( layer );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -617,6 +636,11 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
|
||||
|
||||
int orientation;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_header: sub %d, width %d, height %d\n",
|
||||
layer->sub, layer->width, layer->height );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Output base header fields.
|
||||
*/
|
||||
TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, layer->width );
|
||||
@ -845,40 +869,56 @@ wtiff_allocate_layers( Wtiff *wtiff )
|
||||
{
|
||||
Layer *layer;
|
||||
|
||||
g_assert( wtiff->layer );
|
||||
|
||||
for( layer = wtiff->layer; layer; layer = layer->below ) {
|
||||
layer->image = vips_image_new();
|
||||
if( vips_image_pipelinev( layer->image,
|
||||
VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL ) )
|
||||
return( -1 );
|
||||
layer->image->Xsize = layer->width;
|
||||
layer->image->Ysize = layer->height;
|
||||
if( !layer->image ) {
|
||||
layer->image = vips_image_new();
|
||||
if( vips_image_pipelinev( layer->image,
|
||||
VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL ) )
|
||||
return( -1 );
|
||||
layer->image->Xsize = layer->width;
|
||||
layer->image->Ysize = layer->height;
|
||||
|
||||
layer->strip = vips_region_new( layer->image );
|
||||
layer->copy = vips_region_new( layer->image );
|
||||
layer->strip = vips_region_new( layer->image );
|
||||
layer->copy = vips_region_new( layer->image );
|
||||
|
||||
/* The regions will get used in the bg thread callback, so
|
||||
* make sure we don't own them.
|
||||
*/
|
||||
vips__region_no_ownership( layer->strip );
|
||||
vips__region_no_ownership( layer->copy );
|
||||
/* The regions will get used in the bg thread callback,
|
||||
* so make sure we don't own them.
|
||||
*/
|
||||
vips__region_no_ownership( layer->strip );
|
||||
vips__region_no_ownership( layer->copy );
|
||||
|
||||
if( layer->lname )
|
||||
layer->tif = vips__tiff_openout(
|
||||
layer->lname, wtiff->bigtiff );
|
||||
else {
|
||||
layer->tif = vips__tiff_openout_buffer(
|
||||
wtiff->ready, wtiff->bigtiff,
|
||||
&layer->buf, &layer->len );
|
||||
}
|
||||
if( !layer->tif )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( wtiff_layer_rewind( wtiff, layer ) )
|
||||
return( -1 );
|
||||
|
||||
if( layer->lname )
|
||||
layer->tif = vips__tiff_openout(
|
||||
layer->lname, wtiff->bigtiff );
|
||||
else {
|
||||
layer->tif = vips__tiff_openout_buffer( wtiff->ready,
|
||||
wtiff->bigtiff, &layer->buf, &layer->len );
|
||||
}
|
||||
if( !layer->tif )
|
||||
return( -1 );
|
||||
|
||||
if( wtiff_write_header( wtiff, layer ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( !wtiff->tbuf ) {
|
||||
if( wtiff->tile )
|
||||
wtiff->tbuf = vips_malloc( NULL,
|
||||
TIFFTileSize( wtiff->layer->tif ) );
|
||||
else
|
||||
wtiff->tbuf = vips_malloc( NULL,
|
||||
TIFFScanlineSize( wtiff->layer->tif ) );
|
||||
if( !wtiff->tbuf )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -1032,7 +1072,8 @@ wtiff_new( VipsImage *input, const char *filename,
|
||||
VipsRegionShrink region_shrink,
|
||||
int level,
|
||||
gboolean lossless,
|
||||
VipsForeignDzDepth depth )
|
||||
VipsForeignDzDepth depth,
|
||||
gboolean subifd )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -1064,6 +1105,7 @@ wtiff_new( VipsImage *input, const char *filename,
|
||||
wtiff->level = level;
|
||||
wtiff->lossless = lossless;
|
||||
wtiff->depth = depth;
|
||||
wtiff->subifd = subifd;
|
||||
wtiff->toilet_roll = FALSE;
|
||||
wtiff->page_height = vips_image_get_page_height( input );
|
||||
wtiff->page_number = 0;
|
||||
@ -1096,28 +1138,6 @@ wtiff_new( VipsImage *input, const char *filename,
|
||||
wtiff->toilet_roll = TRUE;
|
||||
wtiff->image_height = wtiff->page_height;
|
||||
wtiff->n_pages = wtiff->ready->Ysize / wtiff->page_height;
|
||||
|
||||
/* We can't pyramid toilet roll images.
|
||||
*/
|
||||
if( wtiff->pyramid ) {
|
||||
g_warning( "%s",
|
||||
_( "can't pyramid multi page images --- "
|
||||
"disabling pyramid" ) );
|
||||
wtiff->pyramid = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* In strip mode we use tileh to set rowsperstrip, and that does not
|
||||
* have the multiple-of-16 restriction.
|
||||
*/
|
||||
if( tile ) {
|
||||
if( (wtiff->tilew & 0xf) != 0 ||
|
||||
(wtiff->tileh & 0xf) != 0 ) {
|
||||
wtiff_free( wtiff );
|
||||
vips_error( "vips2tiff",
|
||||
"%s", _( "tile size not a multiple of 16" ) );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* We can only pyramid LABQ and non-complex images.
|
||||
@ -1133,6 +1153,41 @@ wtiff_new( VipsImage *input, const char *filename,
|
||||
}
|
||||
}
|
||||
|
||||
/* Pyramid images must be tiled.
|
||||
*/
|
||||
if( wtiff->pyramid &&
|
||||
!wtiff->tile )
|
||||
wtiff->tile = TRUE;
|
||||
|
||||
/* Multi-page pyramids must be in subifd mode.
|
||||
*/
|
||||
if( wtiff->pyramid &&
|
||||
wtiff->toilet_roll )
|
||||
wtiff->subifd = TRUE;
|
||||
|
||||
/* If compression is off and we're writing a >4gb image, automatically
|
||||
* enable bigtiff.
|
||||
*
|
||||
* This won't always work. If the image data is just under 4gb but
|
||||
* there's a lot of metadata, we could be pushed over the 4gb limit.
|
||||
*/
|
||||
if( wtiff->compression == COMPRESSION_NONE &&
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( wtiff->ready ) > UINT_MAX )
|
||||
wtiff->bigtiff = TRUE;
|
||||
|
||||
/* In strip mode we use tileh to set rowsperstrip, and that does not
|
||||
* have the multiple-of-16 restriction.
|
||||
*/
|
||||
if( wtiff->tile ) {
|
||||
if( (wtiff->tilew & 0xf) != 0 ||
|
||||
(wtiff->tileh & 0xf) != 0 ) {
|
||||
wtiff_free( wtiff );
|
||||
vips_error( "vips2tiff",
|
||||
"%s", _( "tile size not a multiple of 16" ) );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Can only squash 8 bit mono. 3-band float should have been squashed
|
||||
* above.
|
||||
*/
|
||||
@ -1190,42 +1245,6 @@ wtiff_new( VipsImage *input, const char *filename,
|
||||
wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) *
|
||||
wtiff->tilew;
|
||||
|
||||
/* If compression is off and we're writing a >4gb image, automatically
|
||||
* enable bigtiff.
|
||||
*
|
||||
* This won't always work. If the image data is just under 4gb but
|
||||
* there's a lot of metadata, we could be pushed over the 4gb limit.
|
||||
*/
|
||||
if( wtiff->compression == COMPRESSION_NONE &&
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( wtiff->ready ) > UINT_MAX &&
|
||||
!wtiff->bigtiff ) {
|
||||
g_warning( "%s", _( "image over 4gb, enabling bigtiff" ) );
|
||||
wtiff->bigtiff = TRUE;
|
||||
}
|
||||
|
||||
/* Build the pyramid framework.
|
||||
*/
|
||||
wtiff->layer = wtiff_layer_new( wtiff, NULL,
|
||||
wtiff->ready->Xsize, wtiff->image_height );
|
||||
|
||||
/* Fill all the layers.
|
||||
*/
|
||||
if( wtiff_allocate_layers( wtiff ) ) {
|
||||
wtiff_free( wtiff );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
if( tile )
|
||||
wtiff->tbuf = vips_malloc( NULL,
|
||||
TIFFTileSize( wtiff->layer->tif ) );
|
||||
else
|
||||
wtiff->tbuf = vips_malloc( NULL,
|
||||
TIFFScanlineSize( wtiff->layer->tif ) );
|
||||
if( !wtiff->tbuf ) {
|
||||
wtiff_free( wtiff );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( wtiff );
|
||||
}
|
||||
|
||||
@ -1693,10 +1712,10 @@ write_strip( VipsRegion *region, VipsRect *area, void *a )
|
||||
Wtiff *wtiff = (Wtiff *) a;
|
||||
Layer *layer = wtiff->layer;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "write_strip: strip at %d, height %d\n",
|
||||
area->top, area->height );
|
||||
#endif/*DEBUG*/
|
||||
#endif/*DEBUG_VERBOSE*/
|
||||
|
||||
for(;;) {
|
||||
VipsRect *to = &layer->strip->valid;
|
||||
@ -1858,7 +1877,7 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Append all of the lower layers we wrote to the output.
|
||||
/* Append all of the layers we wrote to the output.
|
||||
*/
|
||||
static int
|
||||
wtiff_gather( Wtiff *wtiff )
|
||||
@ -1873,13 +1892,12 @@ wtiff_gather( Wtiff *wtiff )
|
||||
TIFF *in;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "Appending layer %s ...\n", layer->lname );
|
||||
printf( "appending layer %s ...\n", layer->lname );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( layer->lname ) {
|
||||
if( !(source =
|
||||
vips_source_new_from_file(
|
||||
layer->lname )) )
|
||||
if( !(source = vips_source_new_from_file(
|
||||
layer->lname )) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
@ -1892,12 +1910,14 @@ wtiff_gather( Wtiff *wtiff )
|
||||
VIPS_UNREF( source );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
VIPS_UNREF( source );
|
||||
|
||||
if( wtiff_copy_tiff( wtiff, wtiff->layer->tif, in ) ) {
|
||||
TIFFClose( in );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
TIFFClose( in );
|
||||
|
||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
||||
@ -1907,77 +1927,109 @@ wtiff_gather( Wtiff *wtiff )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Three types of write: single image, multipage and pyramid.
|
||||
/* Write one page from our input image, optionally pyramiding it.
|
||||
*/
|
||||
static int
|
||||
wtiff_write_page( Wtiff *wtiff, VipsImage *page )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_page:\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Init the pyramid framework for this page. This will just make a
|
||||
* single layer if we're not pyramiding.
|
||||
*/
|
||||
wtiff_layer_init( wtiff, &wtiff->layer, NULL,
|
||||
page->Xsize, page->Ysize );
|
||||
|
||||
/* Fill all the layers and write the TIFF headers.
|
||||
*/
|
||||
if( wtiff_allocate_layers( wtiff ) )
|
||||
return( -1 );
|
||||
|
||||
/* In ifd mode, we write the pyramid layers as subdirectories of this
|
||||
* page.
|
||||
*/
|
||||
if( wtiff->subifd ) {
|
||||
int n_layers;
|
||||
toff_t *subifd_offsets;
|
||||
Layer *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_page: OME pyr mode\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* This magic tag makes the n_layers directories we write
|
||||
* after this one into subdirectories. We set the offsets to 0
|
||||
* and libtiff will fill them in automatically.
|
||||
*/
|
||||
for( n_layers = 0, p = wtiff->layer->below; p; p = p->below )
|
||||
n_layers += 1;
|
||||
subifd_offsets = VIPS_ARRAY( NULL, n_layers, toff_t );
|
||||
memset( subifd_offsets, 0, n_layers * sizeof( toff_t ) );
|
||||
TIFFSetField( wtiff->layer->tif, TIFFTAG_SUBIFD,
|
||||
n_layers, subifd_offsets );
|
||||
g_free( subifd_offsets );
|
||||
}
|
||||
|
||||
if( vips_sink_disc( page, write_strip, wtiff ) )
|
||||
return( -1 );
|
||||
|
||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
||||
return( -1 );
|
||||
|
||||
/* Append any pyr layers, if necessary.
|
||||
*/
|
||||
if( wtiff->layer->below ) {
|
||||
/* Free any lower pyramid resources ... this will
|
||||
* TIFFClose() (but not delete) the smaller layers
|
||||
* ready for us to read from them again.
|
||||
*/
|
||||
layer_free_all( wtiff->layer->below );
|
||||
|
||||
/* Append smaller layers to the main file.
|
||||
*/
|
||||
if( wtiff_gather( wtiff ) )
|
||||
return( -1 );
|
||||
|
||||
/* We can delete any temps now ready for the next page.
|
||||
*/
|
||||
wtiff_delete_temps( wtiff );
|
||||
|
||||
/* And free all lower pyr layers ready to be rebuilt for the
|
||||
* next page.
|
||||
*/
|
||||
VIPS_FREEF( layer_free_all, wtiff->layer->below );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Write all pages.
|
||||
*/
|
||||
static int
|
||||
wtiff_write_image( Wtiff *wtiff )
|
||||
{
|
||||
if( wtiff->toilet_roll ) {
|
||||
int y;
|
||||
int y;
|
||||
|
||||
for( y = 0; y < wtiff->ready->Ysize; y += wtiff->page_height ) {
|
||||
VipsImage *page;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_image: toilet-roll mode\n" );
|
||||
printf( "writing page %d ...\n", wtiff->page_number );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
y = 0;
|
||||
for(;;) {
|
||||
VipsImage *page;
|
||||
|
||||
if( vips_crop( wtiff->ready, &page,
|
||||
0, y, wtiff->ready->Xsize, wtiff->page_height,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_sink_disc( page, write_strip, wtiff ) ) {
|
||||
g_object_unref( page );
|
||||
return( -1 );
|
||||
}
|
||||
if( vips_crop( wtiff->ready, &page,
|
||||
0, y, wtiff->ready->Xsize, wtiff->page_height,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( wtiff_write_page( wtiff, page ) ) {
|
||||
g_object_unref( page );
|
||||
|
||||
wtiff->page_number += 1;
|
||||
y += wtiff->page_height;
|
||||
if( y >= wtiff->ready->Ysize )
|
||||
break;
|
||||
|
||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) ||
|
||||
wtiff_layer_rewind( wtiff,
|
||||
wtiff->layer ) ||
|
||||
wtiff_write_header( wtiff,
|
||||
wtiff->layer ) )
|
||||
return( -1 );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
else if( wtiff->pyramid ) {
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_image: pyramid mode\n" );
|
||||
#endif /*DEBUG*/
|
||||
g_object_unref( page );
|
||||
|
||||
if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
|
||||
return( -1 );
|
||||
|
||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
||||
return( -1 );
|
||||
|
||||
if( wtiff->pyramid ) {
|
||||
/* Free lower pyramid resources ... this will
|
||||
* TIFFClose() (but not delete) the smaller layers
|
||||
* ready for us to read from them again.
|
||||
*/
|
||||
if( wtiff->layer->below )
|
||||
layer_free_all( wtiff->layer->below );
|
||||
|
||||
/* Append smaller layers to the main file.
|
||||
*/
|
||||
if( wtiff_gather( wtiff ) )
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
printf( "wtiff_write_image: single-image mode\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
|
||||
return( -1 );
|
||||
wtiff->page_number += 1;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@ -1999,7 +2051,8 @@ vips__tiff_write( VipsImage *input, const char *filename,
|
||||
VipsRegionShrink region_shrink,
|
||||
int level,
|
||||
gboolean lossless,
|
||||
VipsForeignDzDepth depth )
|
||||
VipsForeignDzDepth depth,
|
||||
gboolean subifd )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -2013,7 +2066,8 @@ vips__tiff_write( VipsImage *input, const char *filename,
|
||||
compression, Q, predictor, profile,
|
||||
tile, tile_width, tile_height, pyramid, squash,
|
||||
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,
|
||||
properties, strip, region_shrink, level, lossless, depth )) )
|
||||
properties, strip, region_shrink, level, lossless, depth,
|
||||
subifd )) )
|
||||
return( -1 );
|
||||
|
||||
if( wtiff_write_image( wtiff ) ) {
|
||||
@ -2043,7 +2097,8 @@ vips__tiff_write_buf( VipsImage *input,
|
||||
VipsRegionShrink region_shrink,
|
||||
int level,
|
||||
gboolean lossless,
|
||||
VipsForeignDzDepth depth )
|
||||
VipsForeignDzDepth depth,
|
||||
gboolean subifd )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -2053,7 +2108,8 @@ vips__tiff_write_buf( VipsImage *input,
|
||||
compression, Q, predictor, profile,
|
||||
tile, tile_width, tile_height, pyramid, squash,
|
||||
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,
|
||||
properties, strip, region_shrink, level, lossless, depth )) )
|
||||
properties, strip, region_shrink, level, lossless, depth,
|
||||
subifd )) )
|
||||
return( -1 );
|
||||
|
||||
wtiff->obuf = obuf;
|
||||
|
@ -292,6 +292,8 @@ void vips_info( const char *domain, const char *fmt, ... )
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void vips_vinfo( const char *domain, const char *fmt, va_list ap );
|
||||
|
||||
VipsAngle vips_autorot_get_angle( VipsImage *image );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -192,7 +192,6 @@ int vips_rot270( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_rot45( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
VipsAngle vips_autorot_get_angle( VipsImage *image );
|
||||
void vips_autorot_remove_angle( VipsImage *image );
|
||||
int vips_autorot( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
@ -150,6 +150,13 @@ extern "C" {
|
||||
*/
|
||||
#define VIPS_META_N_PAGES "n-pages"
|
||||
|
||||
/**
|
||||
* VIPS_META_N_SUBIFDS:
|
||||
*
|
||||
* If set, the number of subifds in the first page of the file.
|
||||
*/
|
||||
#define VIPS_META_N_SUBIFDS "n-subifds"
|
||||
|
||||
guint64 vips_format_sizeof( VipsBandFormat format );
|
||||
guint64 vips_format_sizeof_unsafe( VipsBandFormat format );
|
||||
|
||||
@ -171,6 +178,9 @@ double vips_image_get_scale( const VipsImage *image );
|
||||
double vips_image_get_offset( const VipsImage *image );
|
||||
int vips_image_get_page_height( VipsImage *image );
|
||||
int vips_image_get_n_pages( VipsImage *image );
|
||||
int vips_image_get_n_subifds( VipsImage *image );
|
||||
int vips_image_get_orientation( VipsImage *image );
|
||||
gboolean vips_image_get_orientation_swap( VipsImage *image );
|
||||
const void *vips_image_get_data( VipsImage *image );
|
||||
|
||||
void vips_image_init_fields( VipsImage *image,
|
||||
|
@ -818,7 +818,7 @@ vips_image_get_page_height( VipsImage *image )
|
||||
* vips_image_get_n_pages: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check VIPS_META_N_PAGES. Default to 1 if not present or
|
||||
* Fetch and sanity-check #VIPS_META_N_PAGES. Default to 1 if not present or
|
||||
* crazy.
|
||||
*
|
||||
* This is the number of pages in the image file, not the number of pages that
|
||||
@ -840,6 +840,70 @@ vips_image_get_n_pages( VipsImage *image )
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_n_subifds: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check #VIPS_META_N_SUBIFDS. Default to 0 if not present or
|
||||
* crazy.
|
||||
*
|
||||
* Returns: the number of subifds in the image file
|
||||
*/
|
||||
int
|
||||
vips_image_get_n_subifds( VipsImage *image )
|
||||
{
|
||||
int n_subifds;
|
||||
|
||||
if( vips_image_get_typeof( image, VIPS_META_N_SUBIFDS ) &&
|
||||
!vips_image_get_int( image, VIPS_META_N_SUBIFDS, &n_subifds ) &&
|
||||
n_subifds > 1 &&
|
||||
n_subifds < 1000 )
|
||||
return( n_subifds );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_orientation: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check #VIPS_META_ORIENTATION. Default to 1 (no rotate,
|
||||
* no flip) if not present or crazy.
|
||||
*
|
||||
* Returns: the image orientation.
|
||||
*/
|
||||
int
|
||||
vips_image_get_orientation( VipsImage *image )
|
||||
{
|
||||
int orientation;
|
||||
|
||||
if( vips_image_get_typeof( image, VIPS_META_ORIENTATION ) &&
|
||||
!vips_image_get_int( image, VIPS_META_ORIENTATION,
|
||||
&orientation ) &&
|
||||
orientation > 0 &&
|
||||
orientation < 9 )
|
||||
return( orientation );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_orientation_swap: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Return %TRUE if applying the orientation would swap width and height.
|
||||
*
|
||||
* Returns: if width/height will swap
|
||||
*/
|
||||
gboolean
|
||||
vips_image_get_orientation_swap( VipsImage *image )
|
||||
{
|
||||
int orientation = vips_image_get_orientation( image );
|
||||
|
||||
return( orientation >= 5 &&
|
||||
orientation <= 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_data: (method)
|
||||
* @image: image to get data for
|
||||
@ -934,14 +998,11 @@ static int
|
||||
meta_cp( VipsImage *dst, const VipsImage *src )
|
||||
{
|
||||
if( src->meta ) {
|
||||
/* Loop, copying fields.
|
||||
*/
|
||||
meta_init( dst );
|
||||
|
||||
/* We lock with vips_image_set() to stop races in highly-
|
||||
* threaded applications.
|
||||
*/
|
||||
g_mutex_lock( vips__meta_lock );
|
||||
meta_init( dst );
|
||||
vips_slist_map2( src->meta_traverse,
|
||||
(VipsSListMap2Fn) meta_cp_field, dst, NULL );
|
||||
g_mutex_unlock( vips__meta_lock );
|
||||
@ -1032,8 +1093,6 @@ vips_image_set( VipsImage *image, const char *name, GValue *value )
|
||||
g_assert( name );
|
||||
g_assert( value );
|
||||
|
||||
meta_init( image );
|
||||
|
||||
/* We lock between modifying metadata and copying metadata between
|
||||
* images, see meta_cp().
|
||||
*
|
||||
@ -1042,6 +1101,7 @@ vips_image_set( VipsImage *image, const char *name, GValue *value )
|
||||
* highly-threaded applications.
|
||||
*/
|
||||
g_mutex_lock( vips__meta_lock );
|
||||
meta_init( image );
|
||||
(void) meta_new( image, name, value );
|
||||
g_mutex_unlock( vips__meta_lock );
|
||||
|
||||
|
@ -88,6 +88,8 @@
|
||||
* - add "background" parameter
|
||||
* - better clipping means we have no jaggies on edges
|
||||
* - premultiply alpha
|
||||
* 18/5/20
|
||||
* - add "premultiplied" flag
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -166,6 +168,10 @@ typedef struct _VipsAffine {
|
||||
*/
|
||||
VipsPel *ink;
|
||||
|
||||
/* True if the input is already premultiplied (and we don't need to).
|
||||
*/
|
||||
gboolean premultiplied;
|
||||
|
||||
} VipsAffine;
|
||||
|
||||
typedef VipsResampleClass VipsAffineClass;
|
||||
@ -524,11 +530,13 @@ vips_affine_build( VipsObject *object )
|
||||
affine->trn.idx -= 1;
|
||||
affine->trn.idy -= 1;
|
||||
|
||||
/* If there's an alpha, we have to premultiply before resampling. See
|
||||
/* If there's an alpha and we've not premultiplied, we have to
|
||||
* premultiply before resampling. See
|
||||
* https://github.com/libvips/libvips/issues/291
|
||||
*/
|
||||
have_premultiplied = FALSE;
|
||||
if( vips_image_hasalpha( in ) ) {
|
||||
if( vips_image_hasalpha( in ) &&
|
||||
!affine->premultiplied ) {
|
||||
if( vips_premultiply( in, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
have_premultiplied = TRUE;
|
||||
@ -680,6 +688,13 @@ vips_affine_class_init( VipsAffineClass *class )
|
||||
G_STRUCT_OFFSET( VipsAffine, background ),
|
||||
VIPS_TYPE_ARRAY_DOUBLE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "premultiplied", 117,
|
||||
_( "Premultiplied" ),
|
||||
_( "Images have premultiplied alpha" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, premultiplied ),
|
||||
FALSE );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -709,6 +724,7 @@ vips_affine_init( VipsAffine *affine )
|
||||
* * @ody: %gdouble, output vertical offset
|
||||
* * @extend: #VipsExtend how to generate new pixels
|
||||
* * @background: #VipsArrayDouble colour for new pixels
|
||||
* * @premultiplied: %gboolean, images are already premultiplied
|
||||
*
|
||||
* This operator performs an affine transform on an image using @interpolate.
|
||||
*
|
||||
@ -737,6 +753,10 @@ vips_affine_init( VipsAffine *affine )
|
||||
*
|
||||
* @idx, @idy, @odx, @ody default to zero.
|
||||
*
|
||||
* Image are normally treated as unpremultiplied, so this operation can be used
|
||||
* directly on PNG images. If your images have been through vips_premultiply(),
|
||||
* set @premultiplied.
|
||||
*
|
||||
* This operation does not change xres or yres. The image resolution needs to
|
||||
* be updated by the application.
|
||||
*
|
||||
|
@ -289,6 +289,7 @@ vips_resize_build( VipsObject *object )
|
||||
"idx", id,
|
||||
"idy", id,
|
||||
"extend", VIPS_EXTEND_COPY,
|
||||
"premultiplied", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
in = t[4];
|
||||
@ -300,6 +301,7 @@ vips_resize_build( VipsObject *object )
|
||||
"idx", id,
|
||||
"idy", id,
|
||||
"extend", VIPS_EXTEND_COPY,
|
||||
"premultiplied", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
in = t[4];
|
||||
@ -311,6 +313,7 @@ vips_resize_build( VipsObject *object )
|
||||
"idx", id,
|
||||
"idy", id,
|
||||
"extend", VIPS_EXTEND_COPY,
|
||||
"premultiplied", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
in = t[4];
|
||||
@ -444,7 +447,10 @@ vips_resize_init( VipsResize *resize )
|
||||
* This operation does not change xres or yres. The image resolution needs to
|
||||
* be updated by the application.
|
||||
*
|
||||
* See also: vips_shrink(), vips_reduce().
|
||||
* This operation does not premultiply alpha. If your image has an alpha
|
||||
* channel, you should use vips_premultiply() on it first.
|
||||
*
|
||||
* See also: vips_premultiply(), vips_shrink(), vips_reduce().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -28,6 +28,8 @@
|
||||
* - smarter heif thumbnail selection
|
||||
* 12/10/19
|
||||
* - add thumbnail_source
|
||||
* 2/6/20
|
||||
* - add subifd pyr support
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -114,9 +116,11 @@ typedef struct _VipsThumbnail {
|
||||
int input_width;
|
||||
int input_height;
|
||||
int page_height;
|
||||
VipsAngle angle; /* From vips_autorot_get_angle() */
|
||||
int orientation; /* From vips_image_get_orientation() */
|
||||
gboolean swap; /* If we must swap width / height */
|
||||
int n_pages; /* Pages in file */
|
||||
int n_loaded_pages; /* Pages we've loaded from file */
|
||||
int n_subifds; /* Number of subifds */
|
||||
|
||||
/* For openslide, we need to read out the size of each level too.
|
||||
*
|
||||
@ -131,6 +135,10 @@ typedef struct _VipsThumbnail {
|
||||
int heif_thumbnail_width;
|
||||
int heif_thumbnail_height;
|
||||
|
||||
/* For TIFF sources, open subifds rather than pages to get pyr layers.
|
||||
*/
|
||||
gboolean subifd_pyramid;
|
||||
|
||||
} VipsThumbnail;
|
||||
|
||||
typedef struct _VipsThumbnailClass {
|
||||
@ -196,9 +204,11 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
|
||||
{
|
||||
thumbnail->input_width = image->Xsize;
|
||||
thumbnail->input_height = image->Ysize;
|
||||
thumbnail->angle = vips_autorot_get_angle( image );
|
||||
thumbnail->orientation = vips_image_get_orientation( image );
|
||||
thumbnail->swap = vips_image_get_orientation_swap( image );
|
||||
thumbnail->page_height = vips_image_get_page_height( image );
|
||||
thumbnail->n_pages = vips_image_get_n_pages( image );
|
||||
thumbnail->n_subifds = vips_image_get_n_subifds( image );
|
||||
|
||||
/* VIPS_META_N_PAGES is the number of pages in the document,
|
||||
* not the number we've read out into this image. We calculate
|
||||
@ -235,15 +245,24 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
|
||||
}
|
||||
}
|
||||
|
||||
/* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
* We just look for two or more pages following roughly /2 shrinks.
|
||||
/* Detect a TIFF pyramid made of pages following a roughly /2 shrink.
|
||||
*
|
||||
* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
*/
|
||||
static void
|
||||
vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail )
|
||||
{
|
||||
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_page:\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Tell open() that we want to open pages rather than subifds.
|
||||
*/
|
||||
thumbnail->subifd_pyramid = FALSE;
|
||||
|
||||
for( i = 0; i < thumbnail->n_pages; i++ ) {
|
||||
VipsImage *page;
|
||||
int level_width;
|
||||
@ -276,8 +295,68 @@ vips_thumbnail_get_tiff_pyramid( VipsThumbnail *thumbnail )
|
||||
/* Now set level_count. This signals that we've found a pyramid.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid: %d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_page: "
|
||||
"%d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
#endif /*DEBUG*/
|
||||
thumbnail->level_count = thumbnail->n_pages;
|
||||
}
|
||||
|
||||
/* Detect a TIFF pyramid made of subifds following a roughly /2 shrink.
|
||||
*
|
||||
* This may not be a pyr tiff, so no error if we can't find the layers.
|
||||
*/
|
||||
static void
|
||||
vips_thumbnail_get_tiff_pyramid_subifd( VipsThumbnail *thumbnail )
|
||||
{
|
||||
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_subifd:\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Tell open() that we want to open subifds rather than pages.
|
||||
*/
|
||||
thumbnail->subifd_pyramid = TRUE;
|
||||
|
||||
for( i = 0; i < thumbnail->n_subifds; i++ ) {
|
||||
VipsImage *page;
|
||||
int level_width;
|
||||
int level_height;
|
||||
int expected_level_width;
|
||||
int expected_level_height;
|
||||
|
||||
if( !(page = class->open( thumbnail, i )) )
|
||||
return;
|
||||
level_width = page->Xsize;
|
||||
level_height = page->Ysize;
|
||||
VIPS_UNREF( page );
|
||||
|
||||
/* The main image is size 1, subifd 0 is half that.
|
||||
*/
|
||||
expected_level_width = thumbnail->input_width / (2 << i);
|
||||
expected_level_height = thumbnail->input_height / (2 << i);
|
||||
|
||||
/* This won't be exact due to rounding etc.
|
||||
*/
|
||||
if( abs( level_width - expected_level_width ) > 5 ||
|
||||
level_width < 2 )
|
||||
return;
|
||||
if( abs( level_height - expected_level_height ) > 5 ||
|
||||
level_height < 2 )
|
||||
return;
|
||||
|
||||
thumbnail->level_width[i] = level_width;
|
||||
thumbnail->level_height[i] = level_height;
|
||||
}
|
||||
|
||||
/* Now set level_count. This signals that we've found a pyramid.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_get_tiff_pyramid_subifd: "
|
||||
"%d layer pyramid detected\n",
|
||||
thumbnail->n_pages );
|
||||
#endif /*DEBUG*/
|
||||
thumbnail->level_count = thumbnail->n_pages;
|
||||
}
|
||||
@ -313,11 +392,10 @@ static void
|
||||
vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail,
|
||||
int input_width, int input_height, double *hshrink, double *vshrink )
|
||||
{
|
||||
/* If we will be rotating, swap the target width and height.
|
||||
/* If we will be rotating, swap the target width and height.
|
||||
*/
|
||||
gboolean rotate =
|
||||
(thumbnail->angle == VIPS_ANGLE_D90 ||
|
||||
thumbnail->angle == VIPS_ANGLE_D270) &&
|
||||
thumbnail->swap &&
|
||||
thumbnail->auto_rotate;
|
||||
int target_width = rotate ?
|
||||
thumbnail->height : thumbnail->width;
|
||||
@ -459,11 +537,18 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
|
||||
g_info( "input size is %d x %d",
|
||||
thumbnail->input_width, thumbnail->input_height );
|
||||
|
||||
/* For tiff, we need a separate ->open() for each page to
|
||||
* get all the pyramid levels.
|
||||
/* For tiff, scan the image and try to spot page-based and ifd-based
|
||||
* pyramids.
|
||||
*/
|
||||
if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) )
|
||||
vips_thumbnail_get_tiff_pyramid( thumbnail );
|
||||
if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
|
||||
/* Test for a subifd pyr first, since we can do that from just
|
||||
* one page.
|
||||
*/
|
||||
vips_thumbnail_get_tiff_pyramid_subifd( thumbnail );
|
||||
|
||||
if( thumbnail->level_count == 0 )
|
||||
vips_thumbnail_get_tiff_pyramid_page( thumbnail );
|
||||
}
|
||||
|
||||
/* For heif, we need to fetch the thumbnail size, in case we can use
|
||||
* that as the source.
|
||||
@ -524,13 +609,12 @@ vips_thumbnail_build( VipsObject *object )
|
||||
{
|
||||
VipsThumbnail *thumbnail = VIPS_THUMBNAIL( object );
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 15 );
|
||||
VipsInterpretation interpretation = thumbnail->linear ?
|
||||
VIPS_INTERPRETATION_scRGB : VIPS_INTERPRETATION_sRGB;
|
||||
|
||||
VipsImage *in;
|
||||
int preshrunk_page_height;
|
||||
double hshrink;
|
||||
double vshrink;
|
||||
VipsInterpretation interpretation;
|
||||
|
||||
/* TRUE if we've done the import of an ICC transform and still need to
|
||||
* export.
|
||||
@ -628,6 +712,12 @@ vips_thumbnail_build( VipsObject *object )
|
||||
*/
|
||||
if( in->Type == VIPS_INTERPRETATION_CMYK )
|
||||
have_imported = TRUE;
|
||||
if( thumbnail->linear )
|
||||
interpretation = VIPS_INTERPRETATION_scRGB;
|
||||
else if( in->Bands < 3 )
|
||||
interpretation = VIPS_INTERPRETATION_B_W;
|
||||
else
|
||||
interpretation = VIPS_INTERPRETATION_sRGB;
|
||||
g_info( "converting to processing space %s",
|
||||
vips_enum_nick( VIPS_TYPE_INTERPRETATION, interpretation ) );
|
||||
if( vips_colourspace( in, &t[2], interpretation, NULL ) )
|
||||
@ -742,21 +832,12 @@ vips_thumbnail_build( VipsObject *object )
|
||||
}
|
||||
|
||||
if( thumbnail->auto_rotate &&
|
||||
thumbnail->angle != VIPS_ANGLE_D0 ) {
|
||||
VipsAngle angle = vips_autorot_get_angle( in );
|
||||
|
||||
g_info( "rotating by %s",
|
||||
vips_enum_nick( VIPS_TYPE_ANGLE, angle ) );
|
||||
|
||||
/* Need to copy to memory, we have to stay seq.
|
||||
*/
|
||||
if( !(t[9] = vips_image_copy_memory( in )) ||
|
||||
vips_rot( t[9], &t[10], angle, NULL ) ||
|
||||
vips_copy( t[10], &t[14], NULL ) )
|
||||
return( -1 );
|
||||
thumbnail->orientation != 1 ) {
|
||||
g_info( "rotating by EXIF orientation %d",
|
||||
thumbnail->orientation );
|
||||
if( vips_autorot( in, &t[14], NULL ) )
|
||||
return( -1 );
|
||||
in = t[14];
|
||||
|
||||
vips_autorot_remove_angle( in );
|
||||
}
|
||||
|
||||
/* Crop after rotate so we don't need to rotate the crop box.
|
||||
@ -962,10 +1043,16 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
|
||||
NULL ) );
|
||||
}
|
||||
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"page", (int) factor,
|
||||
NULL ) );
|
||||
if( thumbnail->subifd_pyramid )
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"subifd", (int) factor,
|
||||
NULL ) );
|
||||
else
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
"page", (int) factor,
|
||||
NULL ) );
|
||||
}
|
||||
else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) {
|
||||
return( vips_image_new_from_file( file->filename,
|
||||
|
668
po/POTFILES.in
@ -1,435 +1,393 @@
|
||||
libvips/arithmetic/hough_circle.c
|
||||
libvips/arithmetic/boolean.c
|
||||
libvips/arithmetic/complex.c
|
||||
libvips/arithmetic/hough_line.c
|
||||
libvips/arithmetic/profile.c
|
||||
libvips/arithmetic/sign.c
|
||||
libvips/arithmetic/hough.c
|
||||
libvips/arithmetic/getpoint.c
|
||||
libvips/arithmetic/remainder.c
|
||||
libvips/arithmetic/math.c
|
||||
libvips/arithmetic/sum.c
|
||||
libvips/arithmetic/hist_find_ndim.c
|
||||
libvips/arithmetic/subtract.c
|
||||
libvips/arithmetic/statistic.c
|
||||
libvips/arithmetic/unary.c
|
||||
libvips/arithmetic/abs.c
|
||||
libvips/arithmetic/round.c
|
||||
libvips/arithmetic/measure.c
|
||||
libvips/arithmetic/linear.c
|
||||
libvips/arithmetic/relational.c
|
||||
libvips/arithmetic/multiply.c
|
||||
libvips/arithmetic/deviate.c
|
||||
libvips/arithmetic/unaryconst.c
|
||||
libvips/arithmetic/min.c
|
||||
libvips/arithmetic/add.c
|
||||
libvips/arithmetic/nary.c
|
||||
libvips/arithmetic/sum.c
|
||||
libvips/arithmetic/stats.c
|
||||
libvips/arithmetic/binary.c
|
||||
libvips/arithmetic/project.c
|
||||
libvips/arithmetic/hist_find.c
|
||||
libvips/arithmetic/arithmetic.c
|
||||
libvips/arithmetic/divide.c
|
||||
libvips/arithmetic/invert.c
|
||||
libvips/arithmetic/hough_line.c
|
||||
libvips/arithmetic/binary.c
|
||||
libvips/arithmetic/deviate.c
|
||||
libvips/arithmetic/max.c
|
||||
libvips/arithmetic/statistic.c
|
||||
libvips/arithmetic/nary.c
|
||||
libvips/arithmetic/invert.c
|
||||
libvips/arithmetic/remainder.c
|
||||
libvips/arithmetic/boolean.c
|
||||
libvips/arithmetic/sign.c
|
||||
libvips/arithmetic/hist_find_ndim.c
|
||||
libvips/arithmetic/multiply.c
|
||||
libvips/arithmetic/hough_circle.c
|
||||
libvips/arithmetic/measure.c
|
||||
libvips/arithmetic/hist_find.c
|
||||
libvips/arithmetic/find_trim.c
|
||||
libvips/arithmetic/math2.c
|
||||
libvips/arithmetic/getpoint.c
|
||||
libvips/arithmetic/add.c
|
||||
libvips/arithmetic/divide.c
|
||||
libvips/arithmetic/relational.c
|
||||
libvips/arithmetic/hough.c
|
||||
libvips/arithmetic/arithmetic.c
|
||||
libvips/arithmetic/abs.c
|
||||
libvips/arithmetic/avg.c
|
||||
libvips/arithmetic/linear.c
|
||||
libvips/arithmetic/round.c
|
||||
libvips/arithmetic/math2.c
|
||||
libvips/arithmetic/unaryconst.c
|
||||
libvips/arithmetic/complex.c
|
||||
libvips/arithmetic/profile.c
|
||||
libvips/arithmetic/unary.c
|
||||
libvips/arithmetic/subtract.c
|
||||
libvips/arithmetic/hist_find_indexed.c
|
||||
libvips/colour/dE76.c
|
||||
libvips/colour/scRGB2XYZ.c
|
||||
libvips/arithmetic/math.c
|
||||
libvips/colour/LabQ2LabS.c
|
||||
libvips/colour/profile_load.c
|
||||
libvips/colour/rad2float.c
|
||||
libvips/colour/XYZ2scRGB.c
|
||||
libvips/colour/Lab2LabS.c
|
||||
libvips/colour/LabS2LabQ.c
|
||||
libvips/colour/UCS2LCh.c
|
||||
libvips/colour/XYZ2CMYK.c
|
||||
libvips/colour/CMYK2XYZ.c
|
||||
libvips/colour/profiles.c
|
||||
libvips/colour/float2rad.c
|
||||
libvips/colour/scRGB2XYZ.c
|
||||
libvips/colour/LabQ2Lab.c
|
||||
libvips/colour/HSV2sRGB.c
|
||||
libvips/colour/XYZ2Lab.c
|
||||
libvips/colour/UCS2LCh.c
|
||||
libvips/colour/dE76.c
|
||||
libvips/colour/colour.c
|
||||
libvips/colour/sRGB2HSV.c
|
||||
libvips/colour/Lab2LabQ.c
|
||||
libvips/colour/LCh2UCS.c
|
||||
libvips/colour/sRGB2scRGB.c
|
||||
libvips/colour/dECMC.c
|
||||
libvips/colour/LCh2Lab.c
|
||||
libvips/colour/Yxy2XYZ.c
|
||||
libvips/colour/XYZ2Lab.c
|
||||
libvips/colour/scRGB2BW.c
|
||||
libvips/colour/sRGB2HSV.c
|
||||
libvips/colour/LabQ2Lab.c
|
||||
libvips/colour/LabQ2sRGB.c
|
||||
libvips/colour/Lab2XYZ.c
|
||||
libvips/colour/CMYK2XYZ.c
|
||||
libvips/colour/XYZ2Yxy.c
|
||||
libvips/colour/XYZ2scRGB.c
|
||||
libvips/colour/colour.c
|
||||
libvips/colour/profile_load.c
|
||||
libvips/colour/Lab2LCh.c
|
||||
libvips/colour/rad2float.c
|
||||
libvips/colour/XYZ2CMYK.c
|
||||
libvips/colour/Lab2LabQ.c
|
||||
libvips/colour/dECMC.c
|
||||
libvips/colour/colourspace.c
|
||||
libvips/colour/scRGB2sRGB.c
|
||||
libvips/colour/sRGB2scRGB.c
|
||||
libvips/colour/LCh2UCS.c
|
||||
libvips/colour/icc_transform.c
|
||||
libvips/colour/dE00.c
|
||||
libvips/colour/float2rad.c
|
||||
libvips/colour/HSV2sRGB.c
|
||||
libvips/colour/Lab2LabS.c
|
||||
libvips/colour/LabS2Lab.c
|
||||
libvips/conversion/bandjoin.c
|
||||
libvips/colour/LabQ2sRGB.c
|
||||
libvips/colour/scRGB2BW.c
|
||||
libvips/colour/Lab2LCh.c
|
||||
libvips/colour/icc_transform.c
|
||||
libvips/colour/scRGB2sRGB.c
|
||||
libvips/colour/dE00.c
|
||||
libvips/colour/Lab2XYZ.c
|
||||
libvips/colour/XYZ2Yxy.c
|
||||
libvips/colour/colourspace.c
|
||||
libvips/conversion/conversion.c
|
||||
libvips/conversion/embed.c
|
||||
libvips/conversion/zoom.c
|
||||
libvips/conversion/transpose3d.c
|
||||
libvips/conversion/replicate.c
|
||||
libvips/conversion/bandfold.c
|
||||
libvips/conversion/wrap.c
|
||||
libvips/conversion/arrayjoin.c
|
||||
libvips/conversion/premultiply.c
|
||||
libvips/conversion/switch.c
|
||||
libvips/conversion/scale.c
|
||||
libvips/conversion/flatten.c
|
||||
libvips/conversion/conversion.c
|
||||
libvips/conversion/rot.c
|
||||
libvips/conversion/sequential.c
|
||||
libvips/conversion/gamma.c
|
||||
libvips/conversion/msb.c
|
||||
libvips/conversion/autorot.c
|
||||
libvips/conversion/smartcrop.c
|
||||
libvips/conversion/bandmean.c
|
||||
libvips/conversion/copy.c
|
||||
libvips/conversion/tilecache.c
|
||||
libvips/conversion/extract.c
|
||||
libvips/conversion/bandbool.c
|
||||
libvips/conversion/grid.c
|
||||
libvips/conversion/transpose3d.c
|
||||
libvips/conversion/unpremultiply.c
|
||||
libvips/conversion/bandrank.c
|
||||
libvips/conversion/ifthenelse.c
|
||||
libvips/conversion/join.c
|
||||
libvips/conversion/falsecolour.c
|
||||
libvips/conversion/cache.c
|
||||
libvips/conversion/embed.c
|
||||
libvips/conversion/insert.c
|
||||
libvips/conversion/replicate.c
|
||||
libvips/conversion/rot45.c
|
||||
libvips/conversion/byteswap.c
|
||||
libvips/conversion/bandunfold.c
|
||||
libvips/conversion/cast.c
|
||||
libvips/conversion/flip.c
|
||||
libvips/conversion/zoom.c
|
||||
libvips/conversion/bandfold.c
|
||||
libvips/conversion/flatten.c
|
||||
libvips/conversion/copy.c
|
||||
libvips/conversion/bandjoin.c
|
||||
libvips/conversion/rot45.c
|
||||
libvips/conversion/msb.c
|
||||
libvips/conversion/extract.c
|
||||
libvips/conversion/cast.c
|
||||
libvips/conversion/bandunfold.c
|
||||
libvips/conversion/tilecache.c
|
||||
libvips/conversion/sequential.c
|
||||
libvips/conversion/smartcrop.c
|
||||
libvips/conversion/premultiply.c
|
||||
libvips/conversion/bandmean.c
|
||||
libvips/conversion/falsecolour.c
|
||||
libvips/conversion/byteswap.c
|
||||
libvips/conversion/subsample.c
|
||||
libvips/conversion/bandbool.c
|
||||
libvips/conversion/recomb.c
|
||||
libvips/conversion/bandary.c
|
||||
libvips/conversion/ifthenelse.c
|
||||
libvips/conversion/gamma.c
|
||||
libvips/conversion/join.c
|
||||
libvips/conversion/cache.c
|
||||
libvips/conversion/grid.c
|
||||
libvips/conversion/scale.c
|
||||
libvips/conversion/insert.c
|
||||
libvips/conversion/autorot.c
|
||||
libvips/conversion/rot.c
|
||||
libvips/conversion/bandrank.c
|
||||
libvips/conversion/switch.c
|
||||
libvips/convolution/spcor.c
|
||||
libvips/convolution/conva.c
|
||||
libvips/convolution/correlation.c
|
||||
libvips/convolution/gaussblur.c
|
||||
libvips/convolution/conv.c
|
||||
libvips/convolution/fastcor.c
|
||||
libvips/convolution/sobel.c
|
||||
libvips/convolution/canny.c
|
||||
libvips/convolution/convi.c
|
||||
libvips/convolution/compass.c
|
||||
libvips/convolution/convolution.c
|
||||
libvips/convolution/convf.c
|
||||
libvips/convolution/gaussblur.c
|
||||
libvips/convolution/convasep.c
|
||||
libvips/convolution/convsep.c
|
||||
libvips/convolution/sharpen.c
|
||||
libvips/convolution/convolution.c
|
||||
libvips/convolution/fastcor.c
|
||||
libvips/convolution/canny.c
|
||||
libvips/convolution/convf.c
|
||||
libvips/convolution/spcor.c
|
||||
libvips/convolution/compass.c
|
||||
libvips/convolution/convasep.c
|
||||
libvips/convolution/sobel.c
|
||||
libvips/create/perlin.c
|
||||
libvips/create/worley.c
|
||||
libvips/create/zone.c
|
||||
libvips/create/mask_ideal_band.c
|
||||
libvips/create/gaussmat.c
|
||||
libvips/convolution/conv.c
|
||||
libvips/convolution/correlation.c
|
||||
libvips/create/sines.c
|
||||
libvips/create/grey.c
|
||||
libvips/create/buildlut.c
|
||||
libvips/create/mask_ideal.c
|
||||
libvips/create/create.c
|
||||
libvips/create/fractsurf.c
|
||||
libvips/create/black.c
|
||||
libvips/create/mask_gaussian.c
|
||||
libvips/create/xyz.c
|
||||
libvips/create/invertlut.c
|
||||
libvips/create/mask.c
|
||||
libvips/create/mask_butterworth.c
|
||||
libvips/create/mask_ideal_ring.c
|
||||
libvips/create/point.c
|
||||
libvips/create/tonelut.c
|
||||
libvips/create/mask_ideal.c
|
||||
libvips/create/text.c
|
||||
libvips/create/mask_butterworth_ring.c
|
||||
libvips/create/mask_gaussian.c
|
||||
libvips/create/gaussnoise.c
|
||||
libvips/create/mask_butterworth_band.c
|
||||
libvips/create/sines.c
|
||||
libvips/create/mask_gaussian_ring.c
|
||||
libvips/create/eye.c
|
||||
libvips/create/logmat.c
|
||||
libvips/create/identity.c
|
||||
libvips/create/gaussmat.c
|
||||
libvips/create/worley.c
|
||||
libvips/create/mask_gaussian_ring.c
|
||||
libvips/create/gaussnoise.c
|
||||
libvips/create/zone.c
|
||||
libvips/create/tonelut.c
|
||||
libvips/create/perlin.c
|
||||
libvips/create/point.c
|
||||
libvips/create/mask.c
|
||||
libvips/create/mask_butterworth_band.c
|
||||
libvips/create/mask_ideal_ring.c
|
||||
libvips/create/mask_butterworth.c
|
||||
libvips/create/mask_gaussian_band.c
|
||||
libvips/create/fractsurf.c
|
||||
libvips/create/identity.c
|
||||
libvips/create/text.c
|
||||
libvips/create/mask_fractal.c
|
||||
libvips/draw/drawink.c
|
||||
libvips/create/eye.c
|
||||
libvips/create/black.c
|
||||
libvips/create/mask_ideal_band.c
|
||||
libvips/create/buildlut.c
|
||||
libvips/draw/draw_line.c
|
||||
libvips/draw/draw_circle.c
|
||||
libvips/draw/draw_flood.c
|
||||
libvips/draw/draw_rect.c
|
||||
libvips/draw/draw_smudge.c
|
||||
libvips/draw/draw_image.c
|
||||
libvips/draw/draw_mask.c
|
||||
libvips/draw/draw.c
|
||||
libvips/foreign/vipssave.c
|
||||
libvips/foreign/dzsave.c
|
||||
libvips/foreign/csv.c
|
||||
libvips/foreign/niftiload.c
|
||||
libvips/foreign/magick.c
|
||||
libvips/foreign/ppmload.c
|
||||
libvips/foreign/openslideload.c
|
||||
libvips/foreign/tiffload.c
|
||||
libvips/foreign/tiff2vips.c
|
||||
libvips/foreign/radsave.c
|
||||
libvips/foreign/analyze2vips.c
|
||||
libvips/foreign/fits.c
|
||||
libvips/foreign/csvsave.c
|
||||
libvips/foreign/analyzeload.c
|
||||
libvips/foreign/ppmsave.c
|
||||
libvips/foreign/radload.c
|
||||
libvips/foreign/pdfload.c
|
||||
libvips/foreign/fitssave.c
|
||||
libvips/foreign/rawload.c
|
||||
libvips/foreign/heifload.c
|
||||
libvips/foreign/jpeg2vips.c
|
||||
libvips/foreign/vips2jpeg.c
|
||||
libvips/foreign/pdfiumload.c
|
||||
libvips/foreign/webpsave.c
|
||||
libvips/foreign/magick7load.c
|
||||
libvips/foreign/csvload.c
|
||||
libvips/foreign/heifsave.c
|
||||
libvips/foreign/radiance.c
|
||||
libvips/foreign/pngload.c
|
||||
libvips/foreign/openslide2vips.c
|
||||
libvips/foreign/matrixsave.c
|
||||
libvips/foreign/tiffsave.c
|
||||
libvips/foreign/magickload.c
|
||||
libvips/foreign/jpegsave.c
|
||||
libvips/foreign/webpload.c
|
||||
libvips/foreign/gifload.c
|
||||
libvips/foreign/pngsave.c
|
||||
libvips/foreign/exif.c
|
||||
libvips/foreign/magick2vips.c
|
||||
libvips/foreign/openexr2vips.c
|
||||
libvips/foreign/matload.c
|
||||
libvips/foreign/vips2webp.c
|
||||
libvips/foreign/openexrload.c
|
||||
libvips/foreign/rawsave.c
|
||||
libvips/foreign/fitsload.c
|
||||
libvips/foreign/niftisave.c
|
||||
libvips/foreign/tiff.c
|
||||
libvips/foreign/quantise.c
|
||||
libvips/foreign/webp2vips.c
|
||||
libvips/foreign/vips2tiff.c
|
||||
libvips/foreign/cairo.c
|
||||
libvips/foreign/magicksave.c
|
||||
libvips/foreign/svgload.c
|
||||
libvips/foreign/jpegload.c
|
||||
libvips/foreign/vipsload.c
|
||||
libvips/foreign/matlab.c
|
||||
libvips/draw/draw_smudge.c
|
||||
libvips/draw/drawink.c
|
||||
libvips/draw/draw_circle.c
|
||||
libvips/draw/draw_flood.c
|
||||
libvips/draw/draw_rect.c
|
||||
libvips/foreign/foreign.c
|
||||
libvips/foreign/csvsave.c
|
||||
libvips/foreign/webp2vips.c
|
||||
libvips/foreign/pngload.c
|
||||
libvips/foreign/matlab.c
|
||||
libvips/foreign/webpload.c
|
||||
libvips/foreign/pdfiumload.c
|
||||
libvips/foreign/pngsave.c
|
||||
libvips/foreign/magicksave.c
|
||||
libvips/foreign/niftiload.c
|
||||
libvips/foreign/tiff2vips.c
|
||||
libvips/foreign/fitsload.c
|
||||
libvips/foreign/matrixsave.c
|
||||
libvips/foreign/vips2webp.c
|
||||
libvips/foreign/tiff.c
|
||||
libvips/foreign/ppmsave.c
|
||||
libvips/foreign/csvload.c
|
||||
libvips/foreign/vipspng.c
|
||||
libvips/foreign/heifsave.c
|
||||
libvips/foreign/vips2jpeg.c
|
||||
libvips/foreign/ppmload.c
|
||||
libvips/foreign/magickload.c
|
||||
libvips/foreign/openexr2vips.c
|
||||
libvips/foreign/gifload.c
|
||||
libvips/foreign/magick7load.c
|
||||
libvips/foreign/openslide2vips.c
|
||||
libvips/foreign/exif.c
|
||||
libvips/foreign/fitssave.c
|
||||
libvips/foreign/pdfload.c
|
||||
libvips/foreign/heifload.c
|
||||
libvips/foreign/magick2vips.c
|
||||
libvips/foreign/fits.c
|
||||
libvips/foreign/cairo.c
|
||||
libvips/foreign/openslideload.c
|
||||
libvips/foreign/rawload.c
|
||||
libvips/foreign/jpeg2vips.c
|
||||
libvips/foreign/tiffsave.c
|
||||
libvips/foreign/svgload.c
|
||||
libvips/foreign/radsave.c
|
||||
libvips/foreign/dzsave.c
|
||||
libvips/foreign/radload.c
|
||||
libvips/foreign/niftisave.c
|
||||
libvips/foreign/openexrload.c
|
||||
libvips/foreign/vipssave.c
|
||||
libvips/foreign/webpsave.c
|
||||
libvips/foreign/radiance.c
|
||||
libvips/foreign/rawsave.c
|
||||
libvips/foreign/jpegsave.c
|
||||
libvips/foreign/analyze2vips.c
|
||||
libvips/foreign/matrixload.c
|
||||
libvips/foreign/jpegload.c
|
||||
libvips/foreign/magick.c
|
||||
libvips/foreign/analyzeload.c
|
||||
libvips/foreign/vips2tiff.c
|
||||
libvips/foreign/matload.c
|
||||
libvips/foreign/quantise.c
|
||||
libvips/foreign/vipsload.c
|
||||
libvips/foreign/tiffload.c
|
||||
libvips/freqfilt/spectrum.c
|
||||
libvips/freqfilt/phasecor.c
|
||||
libvips/freqfilt/fwfft.c
|
||||
libvips/freqfilt/freqmult.c
|
||||
libvips/freqfilt/freqfilt.c
|
||||
libvips/freqfilt/invfft.c
|
||||
libvips/freqfilt/freqmult.c
|
||||
libvips/freqfilt/spectrum.c
|
||||
libvips/freqfilt/fwfft.c
|
||||
libvips/freqfilt/phasecor.c
|
||||
libvips/histogram/hist_norm.c
|
||||
libvips/histogram/hist_cum.c
|
||||
libvips/histogram/histogram.c
|
||||
libvips/histogram/hist_match.c
|
||||
libvips/histogram/hist_entropy.c
|
||||
libvips/histogram/hist_plot.c
|
||||
libvips/histogram/stdif.c
|
||||
libvips/histogram/percent.c
|
||||
libvips/histogram/hist_ismonotonic.c
|
||||
libvips/histogram/hist_equal.c
|
||||
libvips/histogram/maplut.c
|
||||
libvips/histogram/hist_unary.c
|
||||
libvips/histogram/case.c
|
||||
libvips/histogram/hist_match.c
|
||||
libvips/histogram/hist_cum.c
|
||||
libvips/histogram/hist_equal.c
|
||||
libvips/histogram/stdif.c
|
||||
libvips/histogram/histogram.c
|
||||
libvips/histogram/hist_entropy.c
|
||||
libvips/histogram/hist_ismonotonic.c
|
||||
libvips/histogram/hist_norm.c
|
||||
libvips/histogram/hist_plot.c
|
||||
libvips/histogram/hist_unary.c
|
||||
libvips/histogram/hist_local.c
|
||||
libvips/histogram/percent.c
|
||||
libvips/histogram/maplut.c
|
||||
libvips/introspect.c
|
||||
libvips/iofuncs/target.c
|
||||
libvips/iofuncs/sinkscreen.c
|
||||
libvips/iofuncs/vipsmarshal.c
|
||||
libvips/iofuncs/init.c
|
||||
libvips/iofuncs/dbuf.c
|
||||
libvips/iofuncs/buffer.c
|
||||
libvips/iofuncs/operation.c
|
||||
libvips/iofuncs/sbuf.c
|
||||
libvips/iofuncs/sinkmemory.c
|
||||
libvips/iofuncs/window.c
|
||||
libvips/iofuncs/reorder.c
|
||||
libvips/iofuncs/targetcustom.c
|
||||
libvips/iofuncs/source.c
|
||||
libvips/iofuncs/memory.c
|
||||
libvips/iofuncs/sinkdisc.c
|
||||
libvips/iofuncs/region.c
|
||||
libvips/iofuncs/rect.c
|
||||
libvips/iofuncs/util.c
|
||||
libvips/iofuncs/vips.c
|
||||
libvips/iofuncs/cache.c
|
||||
libvips/iofuncs/type.c
|
||||
libvips/iofuncs/semaphore.c
|
||||
libvips/iofuncs/gate.c
|
||||
libvips/iofuncs/sourcecustom.c
|
||||
libvips/iofuncs/mapfile.c
|
||||
libvips/iofuncs/sink.c
|
||||
libvips/iofuncs/enumtypes.c
|
||||
libvips/iofuncs/vector.c
|
||||
libvips/iofuncs/header.c
|
||||
libvips/iofuncs/error.c
|
||||
libvips/iofuncs/generate.c
|
||||
libvips/iofuncs/gate.c
|
||||
libvips/iofuncs/type.c
|
||||
libvips/iofuncs/image.c
|
||||
libvips/iofuncs/connection.c
|
||||
libvips/iofuncs/threadpool.c
|
||||
libvips/iofuncs/buf.c
|
||||
libvips/iofuncs/buffer.c
|
||||
libvips/iofuncs/mapfile.c
|
||||
libvips/iofuncs/reorder.c
|
||||
libvips/iofuncs/sbuf.c
|
||||
libvips/iofuncs/enumtypes.c
|
||||
libvips/iofuncs/sinkdisc.c
|
||||
libvips/iofuncs/target.c
|
||||
libvips/iofuncs/vector.c
|
||||
libvips/iofuncs/operation.c
|
||||
libvips/iofuncs/sinkmemory.c
|
||||
libvips/iofuncs/generate.c
|
||||
libvips/iofuncs/dbuf.c
|
||||
libvips/iofuncs/window.c
|
||||
libvips/iofuncs/ginputsource.c
|
||||
libvips/iofuncs/targetcustom.c
|
||||
libvips/iofuncs/sourcecustom.c
|
||||
libvips/iofuncs/source.c
|
||||
libvips/iofuncs/system.c
|
||||
libvips/iofuncs/header.c
|
||||
libvips/iofuncs/init.c
|
||||
libvips/iofuncs/rect.c
|
||||
libvips/iofuncs/region.c
|
||||
libvips/iofuncs/cache.c
|
||||
libvips/iofuncs/vips.c
|
||||
libvips/iofuncs/error.c
|
||||
libvips/iofuncs/util.c
|
||||
libvips/iofuncs/semaphore.c
|
||||
libvips/iofuncs/memory.c
|
||||
libvips/iofuncs/sinkscreen.c
|
||||
libvips/iofuncs/object.c
|
||||
libvips/morphology/labelregions.c
|
||||
libvips/iofuncs/connection.c
|
||||
libvips/iofuncs/buf.c
|
||||
libvips/iofuncs/vipsmarshal.c
|
||||
libvips/morphology/morph.c
|
||||
libvips/morphology/nearest.c
|
||||
libvips/morphology/morphology.c
|
||||
libvips/morphology/rank.c
|
||||
libvips/morphology/hitmiss.c
|
||||
libvips/morphology/countlines.c
|
||||
libvips/mosaicing/global_balance.c
|
||||
libvips/mosaicing/im_lrmosaic.c
|
||||
libvips/mosaicing/im_initialize.c
|
||||
libvips/mosaicing/im_remosaic.c
|
||||
libvips/mosaicing/im_improve.c
|
||||
libvips/mosaicing/im_lrcalcon.c
|
||||
libvips/mosaicing/mosaic1.c
|
||||
libvips/mosaicing/im_chkpair.c
|
||||
libvips/mosaicing/im_tbcalcon.c
|
||||
libvips/mosaicing/mosaicing.c
|
||||
libvips/mosaicing/mosaic.c
|
||||
libvips/mosaicing/im_avgdxdy.c
|
||||
libvips/mosaicing/im_clinear.c
|
||||
libvips/mosaicing/merge.c
|
||||
libvips/mosaicing/im_tbmosaic.c
|
||||
libvips/mosaicing/match.c
|
||||
libvips/mosaicing/im_lrmerge.c
|
||||
libvips/morphology/nearest.c
|
||||
libvips/morphology/labelregions.c
|
||||
libvips/morphology/morphology.c
|
||||
libvips/morphology/hitmiss.c
|
||||
libvips/mosaicing/im_tbmerge.c
|
||||
libvips/resample/shrinkh.c
|
||||
libvips/resample/shrinkv.c
|
||||
libvips/resample/reduce.c
|
||||
libvips/resample/transform.c
|
||||
libvips/resample/resize.c
|
||||
libvips/resample/mapim.c
|
||||
libvips/resample/thumbnail.c
|
||||
libvips/resample/resample.c
|
||||
libvips/mosaicing/im_improve.c
|
||||
libvips/mosaicing/im_chkpair.c
|
||||
libvips/mosaicing/im_lrmosaic.c
|
||||
libvips/mosaicing/im_tbcalcon.c
|
||||
libvips/mosaicing/merge.c
|
||||
libvips/mosaicing/im_remosaic.c
|
||||
libvips/mosaicing/im_lrcalcon.c
|
||||
libvips/mosaicing/im_initialize.c
|
||||
libvips/mosaicing/mosaicing.c
|
||||
libvips/mosaicing/global_balance.c
|
||||
libvips/mosaicing/im_avgdxdy.c
|
||||
libvips/mosaicing/im_lrmerge.c
|
||||
libvips/mosaicing/mosaic.c
|
||||
libvips/mosaicing/im_tbmosaic.c
|
||||
libvips/mosaicing/im_clinear.c
|
||||
libvips/mosaicing/match.c
|
||||
libvips/mosaicing/mosaic1.c
|
||||
libvips/resample/affine.c
|
||||
libvips/resample/shrinkv.c
|
||||
libvips/resample/mapim.c
|
||||
libvips/resample/resize.c
|
||||
libvips/resample/transform.c
|
||||
libvips/resample/reduce.c
|
||||
libvips/resample/shrinkh.c
|
||||
libvips/resample/resample.c
|
||||
libvips/resample/quadratic.c
|
||||
libvips/resample/interpolate.c
|
||||
libvips/resample/similarity.c
|
||||
libvips/resample/thumbnail.c
|
||||
libvips/resample/shrink.c
|
||||
libvips/resample/similarity.c
|
||||
libvips/resample/interpolate.c
|
||||
tools/vips.c
|
||||
tools/vipsedit.c
|
||||
tools/vipsheader.c
|
||||
tools/vipsthumbnail.c
|
||||
cplusplus/include/vips/VImage8.h
|
||||
cplusplus/include/vips/VInterpolate8.h
|
||||
cplusplus/include/vips/VError8.h
|
||||
cplusplus/include/vips/vips-operators.h
|
||||
cplusplus/include/vips/VConnection8.h
|
||||
cplusplus/include/vips/VImage8.h
|
||||
cplusplus/include/vips/VInterpolate8.h
|
||||
libvips/arithmetic/binary.h
|
||||
libvips/arithmetic/unary.h
|
||||
libvips/arithmetic/parithmetic.h
|
||||
libvips/arithmetic/hough.h
|
||||
libvips/arithmetic/nary.h
|
||||
libvips/arithmetic/statistic.h
|
||||
libvips/arithmetic/unaryconst.h
|
||||
libvips/colour/profiles.h
|
||||
libvips/colour/pcolour.h
|
||||
libvips/conversion/bandary.h
|
||||
libvips/conversion/pconversion.h
|
||||
libvips/convolution/correlation.h
|
||||
libvips/convolution/pconvolution.h
|
||||
libvips/create/pmask.h
|
||||
libvips/create/pcreate.h
|
||||
libvips/create/point.h
|
||||
libvips/draw/pdraw.h
|
||||
libvips/draw/drawink.h
|
||||
libvips/foreign/tiff.h
|
||||
libvips/foreign/pforeign.h
|
||||
libvips/foreign/dbh.h
|
||||
libvips/foreign/magick.h
|
||||
libvips/foreign/jpeg.h
|
||||
libvips/freqfilt/pfreqfilt.h
|
||||
libvips/histogram/phistogram.h
|
||||
libvips/histogram/hist_unary.h
|
||||
libvips/include/vips/freqfilt.h
|
||||
libvips/include/vips/arithmetic.h
|
||||
libvips/include/vips/buf.h
|
||||
libvips/include/vips/histogram.h
|
||||
libvips/include/vips/intl.h
|
||||
libvips/include/vips/threadpool.h
|
||||
libvips/include/vips/operation.h
|
||||
libvips/include/vips/connection.h
|
||||
libvips/include/vips/x.h
|
||||
libvips/include/vips/enumtypes.h
|
||||
libvips/include/vips/video.h
|
||||
libvips/include/vips/memory.h
|
||||
libvips/include/vips/conversion.h
|
||||
libvips/include/vips/internal.h
|
||||
libvips/include/vips/histogram.h
|
||||
libvips/include/vips/cimg_funcs.h
|
||||
libvips/include/vips/buf.h
|
||||
libvips/include/vips/thread.h
|
||||
libvips/include/vips/region.h
|
||||
libvips/include/vips/mask.h
|
||||
libvips/include/vips/private.h
|
||||
libvips/include/vips/interpolate.h
|
||||
libvips/include/vips/internal.h
|
||||
libvips/include/vips/basic.h
|
||||
libvips/include/vips/region.h
|
||||
libvips/include/vips/foreign.h
|
||||
libvips/include/vips/gate.h
|
||||
libvips/include/vips/almostdeprecated.h
|
||||
libvips/include/vips/dispatch.h
|
||||
libvips/include/vips/image.h
|
||||
libvips/include/vips/mosaicing.h
|
||||
libvips/include/vips/vector.h
|
||||
libvips/include/vips/cimg_funcs.h
|
||||
libvips/include/vips/dbuf.h
|
||||
libvips/include/vips/error.h
|
||||
libvips/include/vips/connection.h
|
||||
libvips/include/vips/sbuf.h
|
||||
libvips/include/vips/type.h
|
||||
libvips/include/vips/soname.h
|
||||
libvips/include/vips/vips7compat.h
|
||||
libvips/include/vips/create.h
|
||||
libvips/include/vips/generate.h
|
||||
libvips/include/vips/format.h
|
||||
libvips/include/vips/util.h
|
||||
libvips/include/vips/convolution.h
|
||||
libvips/include/vips/thread.h
|
||||
libvips/include/vips/rect.h
|
||||
libvips/include/vips/dispatch.h
|
||||
libvips/include/vips/version.h
|
||||
libvips/include/vips/error.h
|
||||
libvips/include/vips/debug.h
|
||||
libvips/include/vips/vips.h
|
||||
libvips/include/vips/morphology.h
|
||||
libvips/include/vips/resample.h
|
||||
libvips/include/vips/object.h
|
||||
libvips/include/vips/vips.h
|
||||
libvips/include/vips/generate.h
|
||||
libvips/include/vips/basic.h
|
||||
libvips/include/vips/inlines.h
|
||||
libvips/include/vips/transform.h
|
||||
libvips/include/vips/draw.h
|
||||
libvips/include/vips/semaphore.h
|
||||
libvips/include/vips/vips7compat.h
|
||||
libvips/include/vips/sbuf.h
|
||||
libvips/include/vips/header.h
|
||||
libvips/include/vips/soname.h
|
||||
libvips/include/vips/rect.h
|
||||
libvips/include/vips/type.h
|
||||
libvips/include/vips/semaphore.h
|
||||
libvips/include/vips/image.h
|
||||
libvips/include/vips/dbuf.h
|
||||
libvips/include/vips/vector.h
|
||||
libvips/include/vips/intl.h
|
||||
libvips/include/vips/gate.h
|
||||
libvips/include/vips/freqfilt.h
|
||||
libvips/include/vips/colour.h
|
||||
libvips/include/vips/mask.h
|
||||
libvips/include/vips/debug.h
|
||||
libvips/include/vips/morphology.h
|
||||
libvips/include/vips/enumtypes.h
|
||||
libvips/include/vips/deprecated.h
|
||||
libvips/include/vips/version.h
|
||||
libvips/iofuncs/sink.h
|
||||
libvips/iofuncs/vipsmarshal.h
|
||||
libvips/morphology/pmorphology.h
|
||||
libvips/mosaicing/pmosaicing.h
|
||||
libvips/mosaicing/global_balance.h
|
||||
libvips/resample/presample.h
|
||||
libvips/resample/templates.h
|
||||
cplusplus/examples/invert.cpp
|
||||
cplusplus/examples/avg.cpp
|
||||
cplusplus/examples/test.cpp
|
||||
cplusplus/examples/resize.cpp
|
||||
cplusplus/examples/buffer.cpp
|
||||
cplusplus/examples/embed.cpp
|
||||
cplusplus/examples/profile.cpp
|
||||
cplusplus/examples/test_overloads.cpp
|
||||
libvips/include/vips/arithmetic.h
|
||||
libvips/include/vips/threadpool.h
|
||||
libvips/include/vips/format.h
|
||||
libvips/include/vips/conversion.h
|
||||
libvips/include/vips/draw.h
|
||||
libvips/include/vips/mosaicing.h
|
||||
libvips/include/vips/util.h
|
||||
libvips/include/vips/convolution.h
|
||||
libvips/include/vips/foreign.h
|
||||
libvips/include/vips/transform.h
|
||||
libvips/include/vips/memory.h
|
||||
cplusplus/VConnection.cpp
|
||||
cplusplus/VError.cpp
|
||||
cplusplus/VImage.cpp
|
||||
cplusplus/VInterpolate.cpp
|
||||
cplusplus/vips-operators.cpp
|
||||
cplusplus/VConnection.cpp
|
||||
libvips/conversion/composite.cpp
|
||||
libvips/resample/reduceh.cpp
|
||||
libvips/resample/vsqbs.cpp
|
||||
libvips/resample/lbb.cpp
|
||||
libvips/resample/nohalo.cpp
|
||||
libvips/resample/reducev.cpp
|
||||
libvips/resample/bicubic.cpp
|
||||
libvips/resample/vsqbs.cpp
|
||||
libvips/resample/nohalo.cpp
|
||||
libvips/resample/lbb.cpp
|
||||
libvips/resample/reducev.cpp
|
||||
|
@ -28,7 +28,7 @@ find */* -name "*.cxx" >> po/POTFILES.in
|
||||
find */* -name "*.cpp" >> po/POTFILES.in
|
||||
|
||||
regenerate the list of files to search for strings ... don't forget to
|
||||
remove autogenerated files, fuzzer sources, deprecated stuff etc.
|
||||
remove: fuzz/ test/ deprecated/ examples/ non-public includes
|
||||
|
||||
intltool-update --pot
|
||||
|
||||
|
BIN
test/test-suite/images/rotation/0.png
Normal file
After Width: | Height: | Size: 661 KiB |
BIN
test/test-suite/images/rotation/1.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
test/test-suite/images/rotation/2.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
test/test-suite/images/rotation/3.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
test/test-suite/images/rotation/4.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
test/test-suite/images/rotation/5.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
test/test-suite/images/rotation/6.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
test/test-suite/images/rotation/7.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
test/test-suite/images/rotation/8.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
@ -1,17 +1,24 @@
|
||||
# vim: set fileencoding=utf-8 :
|
||||
import filecmp
|
||||
from functools import reduce
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
import pyvips
|
||||
from helpers import JPEG_FILE, unsigned_formats, \
|
||||
from helpers import IMAGES, JPEG_FILE, unsigned_formats, \
|
||||
signed_formats, float_formats, int_formats, \
|
||||
noncomplex_formats, all_formats, max_value, \
|
||||
sizeof_format, rot45_angles, rot45_angle_bonds, \
|
||||
rot_angles, rot_angle_bonds, run_cmp, run_cmp2, \
|
||||
assert_almost_equal_objects
|
||||
assert_almost_equal_objects, temp_filename
|
||||
|
||||
|
||||
class TestConversion:
|
||||
tempdir = None
|
||||
|
||||
# run a function on an image,
|
||||
# 50,50 and 10,10 should have different values on the test image
|
||||
# don't loop over band elements
|
||||
@ -37,6 +44,7 @@ class TestConversion:
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.tempdir = tempfile.mkdtemp()
|
||||
im = pyvips.Image.mask_ideal(100, 100, 0.5,
|
||||
reject=True, optical=True)
|
||||
cls.colour = (im * [1, 2, 3] + [2, 3, 4]).copy(interpretation="srgb")
|
||||
@ -46,6 +54,7 @@ class TestConversion:
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
shutil.rmtree(cls.tempdir, ignore_errors=True)
|
||||
cls.colour = None
|
||||
cls.mono = None
|
||||
cls.image = None
|
||||
@ -738,6 +747,39 @@ class TestConversion:
|
||||
diff = (after - im).abs().max()
|
||||
assert diff == 0
|
||||
|
||||
def test_autorot(self):
|
||||
rotation_images = os.path.join(IMAGES, 'rotation')
|
||||
files = os.listdir(rotation_images)
|
||||
files.sort()
|
||||
|
||||
meta = {
|
||||
0: {'w': 290, 'h': 442},
|
||||
1: {'w': 308, 'h': 410},
|
||||
2: {'w': 308, 'h': 410},
|
||||
3: {'w': 308, 'h': 410},
|
||||
4: {'w': 308, 'h': 410},
|
||||
5: {'w': 231, 'h': 308},
|
||||
6: {'w': 231, 'h': 308},
|
||||
7: {'w': 231, 'h': 308},
|
||||
8: {'w': 231, 'h': 308},
|
||||
}
|
||||
|
||||
i = 0
|
||||
for f in files:
|
||||
if '.autorot.' not in f and not f.startswith('.'):
|
||||
source_filename = os.path.join(rotation_images, f)
|
||||
|
||||
actual_filename = temp_filename(self.tempdir, '.jpg')
|
||||
|
||||
pyvips.Image.new_from_file(source_filename).autorot().write_to_file(actual_filename)
|
||||
|
||||
actual = pyvips.Image.new_from_file(actual_filename)
|
||||
|
||||
assert actual.width == meta[i]['w']
|
||||
assert actual.height == meta[i]['h']
|
||||
assert actual.get('orientation') if actual.get_typeof('orientation') else None is None
|
||||
i = i + 1
|
||||
|
||||
def test_scaleimage(self):
|
||||
for fmt in noncomplex_formats:
|
||||
test = self.colour.cast(fmt)
|
||||
|
@ -340,8 +340,12 @@ class TestForeign:
|
||||
self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile,pyramid]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile,pyramid,subifd]", self.colour, 0)
|
||||
self.save_load_file(".tif",
|
||||
"[tile,pyramid,compression=jpeg]", self.colour, 80)
|
||||
self.save_load_file(".tif",
|
||||
"[tile,pyramid,subifd,compression=jpeg]",
|
||||
self.colour, 80)
|
||||
self.save_load_file(".tif", "[bigtiff]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[compression=jpeg]", self.colour, 80)
|
||||
self.save_load_file(".tif",
|
||||
|
@ -24,7 +24,7 @@ bin_SCRIPTS = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
vipsprofile \
|
||||
vips-8.9 \
|
||||
vips-8.10 \
|
||||
light_correct.in \
|
||||
shrink_width.in \
|
||||
batch_image_convert.in \
|
||||
|