tiff save converts for jpg in jpg mode

when jpg compression is on, tiffsave now converts the input image for
jpg save ... previously, it would try to send a tiff-formatted image
(eg. perhaps with an alpha channel, or float data), which would fail

see https://github.com/jcupitt/libvips/issues/449
This commit is contained in:
John Cupitt 2016-05-31 22:04:07 +01:00
parent 45b6345e7f
commit 7a91eaa583
6 changed files with 115 additions and 54 deletions

View File

@ -11,6 +11,7 @@
- added radsave_buffer [Henri Chain] - added radsave_buffer [Henri Chain]
- support tiff orientation tag - support tiff orientation tag
- autorotate option for tiff load - autorotate option for tiff load
- tiffsave converts for jpg if jpg compression is turned on
18/5/16 started 8.3.2 18/5/16 started 8.3.2
- more robust vips image reading - more robust vips image reading

30
TODO
View File

@ -1,5 +1,3 @@
- save a 16-bit image to tiff with jpg compression ... should it autoconvert?
- try: - try:
$ vipsheader blankpage.pdf $ vipsheader blankpage.pdf
@ -9,8 +7,6 @@
try other files in test/images try other files in test/images
- see https://github.com/jcupitt/libvips/issues/243
- try - try
http://www.camerafv5.com/files/photos/raw1/rope.dng http://www.camerafv5.com/files/photos/raw1/rope.dng
@ -20,7 +16,31 @@
hangs 50% of the time, the other 50 it fails with a 16-bit error hangs 50% of the time, the other 50 it fails with a 16-bit error
- save a 16-bit image to tiff with jpg compression ... should it autoconvert? save a 16-bit image to tiff with jpg compression ... should it autoconvert?
tiff should use convert for save in jpeg mode if jpeg compression is enabled
- try
$ vipsthumbnail ~/pics/*.jpg
vips warning: vips_image_get: field "orientation" not found
vips_image_get: field "orientation" not found
vips_image_get: field "orientation" not found
vips_image_get: field "orientation" not found
...
ugly!
- try adding a coz progress point to vipsthumbnail's main loop
see
https://github.com/plasma-umass/coz
- tiff write does not support [strip] - tiff write does not support [strip]

View File

@ -1052,14 +1052,13 @@ vips_foreign_save_new_from_string( const char *string )
return( VIPS_OBJECT( save ) ); return( VIPS_OBJECT( save ) );
} }
/* Generate the saveable image. /* Convert an image for saving.
*/ */
static int int
vips_foreign_convert_saveable( VipsForeignSave *save ) vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready,
VipsSaveable saveable, VipsBandFormat *format, VipsCoding *coding,
VipsArrayDouble *background )
{ {
VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_GET_CLASS( save );
VipsImage *in = save->in;
/* in holds a reference to the output of our chain as we build it. /* in holds a reference to the output of our chain as we build it.
*/ */
g_object_ref( in ); g_object_ref( in );
@ -1068,10 +1067,8 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
* Nothing to do. * Nothing to do.
*/ */
if( in->Coding != VIPS_CODING_NONE && if( in->Coding != VIPS_CODING_NONE &&
class->coding[in->Coding] ) { coding[in->Coding] ) {
VIPS_UNREF( save->ready ); *ready = in;
save->ready = in;
return( 0 ); return( 0 );
} }
@ -1079,11 +1076,9 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
* format we have nothing to do. * format we have nothing to do.
*/ */
if( in->Coding == VIPS_CODING_NONE && if( in->Coding == VIPS_CODING_NONE &&
class->saveable == VIPS_SAVEABLE_ANY && saveable == VIPS_SAVEABLE_ANY &&
class->format_table[in->BandFmt] == in->BandFmt ) { format[in->BandFmt] == in->BandFmt ) {
VIPS_UNREF( save->ready ); *ready = in;
save->ready = in;
return( 0 ); return( 0 );
} }
@ -1122,7 +1117,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
/* If the saver supports RAD, we need to go to scRGB or XYZ. /* If the saver supports RAD, we need to go to scRGB or XYZ.
*/ */
if( class->coding[VIPS_CODING_RAD] ) { if( coding[VIPS_CODING_RAD] ) {
if( in->Type != VIPS_INTERPRETATION_scRGB && if( in->Type != VIPS_INTERPRETATION_scRGB &&
in->Type != VIPS_INTERPRETATION_XYZ ) { in->Type != VIPS_INTERPRETATION_XYZ ) {
VipsImage *out; VipsImage *out;
@ -1141,22 +1136,21 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
/* If this is something other than CMYK or RAD, eg. maybe a LAB image, /* If this is something other than CMYK or RAD, eg. maybe a LAB image,
* we need to transform to RGB. * we need to transform to RGB.
*/ */
if( !class->coding[VIPS_CODING_RAD] && if( !coding[VIPS_CODING_RAD] &&
in->Bands >= 3 && in->Bands >= 3 &&
in->Type != VIPS_INTERPRETATION_CMYK && in->Type != VIPS_INTERPRETATION_CMYK &&
vips_colourspace_issupported( in ) && vips_colourspace_issupported( in ) &&
(class->saveable == VIPS_SAVEABLE_RGB || (saveable == VIPS_SAVEABLE_RGB ||
class->saveable == VIPS_SAVEABLE_RGBA || saveable == VIPS_SAVEABLE_RGBA ||
class->saveable == VIPS_SAVEABLE_RGBA_ONLY || saveable == VIPS_SAVEABLE_RGBA_ONLY ||
class->saveable == VIPS_SAVEABLE_RGB_CMYK) ) { saveable == VIPS_SAVEABLE_RGB_CMYK) ) {
VipsImage *out; VipsImage *out;
VipsInterpretation interpretation; VipsInterpretation interpretation;
/* Do we make RGB or RGB16? We don't want to squash a 16-bit /* Do we make RGB or RGB16? We don't want to squash a 16-bit
* RGB down to 8 bits if the saver supports 16. * RGB down to 8 bits if the saver supports 16.
*/ */
if( vips_band_format_is8bit( if( vips_band_format_is8bit( format[in->BandFmt] ) )
class->format_table[in->BandFmt] ) )
interpretation = VIPS_INTERPRETATION_sRGB; interpretation = VIPS_INTERPRETATION_sRGB;
else else
interpretation = VIPS_INTERPRETATION_RGB16; interpretation = VIPS_INTERPRETATION_RGB16;
@ -1173,18 +1167,17 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
/* VIPS_SAVEABLE_RGBA_ONLY does not support 1 or 2 bands ... convert /* VIPS_SAVEABLE_RGBA_ONLY does not support 1 or 2 bands ... convert
* to sRGB. * to sRGB.
*/ */
if( !class->coding[VIPS_CODING_RAD] && if( !coding[VIPS_CODING_RAD] &&
in->Bands < 3 && in->Bands < 3 &&
vips_colourspace_issupported( in ) && vips_colourspace_issupported( in ) &&
class->saveable == VIPS_SAVEABLE_RGBA_ONLY ) { saveable == VIPS_SAVEABLE_RGBA_ONLY ) {
VipsImage *out; VipsImage *out;
VipsInterpretation interpretation; VipsInterpretation interpretation;
/* Do we make RGB or RGB16? We don't want to squash a 16-bit /* Do we make RGB or RGB16? We don't want to squash a 16-bit
* RGB down to 8 bits if the saver supports 16. * RGB down to 8 bits if the saver supports 16.
*/ */
if( vips_band_format_is8bit( if( vips_band_format_is8bit( format[in->BandFmt] ) )
class->format_table[in->BandFmt] ) )
interpretation = VIPS_INTERPRETATION_sRGB; interpretation = VIPS_INTERPRETATION_sRGB;
else else
interpretation = VIPS_INTERPRETATION_RGB16; interpretation = VIPS_INTERPRETATION_RGB16;
@ -1209,13 +1202,13 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
if( (in->Bands == 2 || if( (in->Bands == 2 ||
(in->Bands == 4 && (in->Bands == 4 &&
in->Type != VIPS_INTERPRETATION_CMYK)) && in->Type != VIPS_INTERPRETATION_CMYK)) &&
(class->saveable == VIPS_SAVEABLE_MONO || (saveable == VIPS_SAVEABLE_MONO ||
class->saveable == VIPS_SAVEABLE_RGB || saveable == VIPS_SAVEABLE_RGB ||
class->saveable == VIPS_SAVEABLE_RGB_CMYK) ) { saveable == VIPS_SAVEABLE_RGB_CMYK) ) {
VipsImage *out; VipsImage *out;
if( vips_flatten( in, &out, if( vips_flatten( in, &out,
"background", save->background, "background", background,
NULL ) ) { NULL ) ) {
g_object_unref( in ); g_object_unref( in );
return( -1 ); return( -1 );
@ -1230,8 +1223,8 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
*/ */
else if( in->Bands > 3 && else if( in->Bands > 3 &&
(class->saveable == VIPS_SAVEABLE_RGB || (saveable == VIPS_SAVEABLE_RGB ||
(class->saveable == VIPS_SAVEABLE_RGB_CMYK && (saveable == VIPS_SAVEABLE_RGB_CMYK &&
in->Type != VIPS_INTERPRETATION_CMYK)) ) { in->Type != VIPS_INTERPRETATION_CMYK)) ) {
VipsImage *out; VipsImage *out;
@ -1253,10 +1246,10 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
in = out; in = out;
} }
else if( in->Bands > 4 && else if( in->Bands > 4 &&
((class->saveable == VIPS_SAVEABLE_RGB_CMYK && ((saveable == VIPS_SAVEABLE_RGB_CMYK &&
in->Type == VIPS_INTERPRETATION_CMYK) || in->Type == VIPS_INTERPRETATION_CMYK) ||
class->saveable == VIPS_SAVEABLE_RGBA || saveable == VIPS_SAVEABLE_RGBA ||
class->saveable == VIPS_SAVEABLE_RGBA_ONLY) ) { saveable == VIPS_SAVEABLE_RGBA_ONLY) ) {
VipsImage *out; VipsImage *out;
if( vips_extract_band( in, &out, 0, if( vips_extract_band( in, &out, 0,
@ -1270,7 +1263,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
in = out; in = out;
} }
else if( in->Bands > 1 && else if( in->Bands > 1 &&
class->saveable == VIPS_SAVEABLE_MONO ) { saveable == VIPS_SAVEABLE_MONO ) {
VipsImage *out; VipsImage *out;
if( vips_extract_band( in, &out, 0, NULL ) ) { if( vips_extract_band( in, &out, 0, NULL ) ) {
@ -1303,8 +1296,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
* it down. This is the behaviour we want for saving an RGB16 * it down. This is the behaviour we want for saving an RGB16
* image as JPG, for example. * image as JPG, for example.
*/ */
if( class->format_table[VIPS_FORMAT_USHORT] == if( format[VIPS_FORMAT_USHORT] == VIPS_FORMAT_USHORT ) {
VIPS_FORMAT_USHORT ) {
VipsImage *out; VipsImage *out;
if( vips_cast( in, &out, VIPS_FORMAT_USHORT, NULL ) ) { if( vips_cast( in, &out, VIPS_FORMAT_USHORT, NULL ) ) {
@ -1344,8 +1336,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
{ {
VipsImage *out; VipsImage *out;
if( vips_cast( in, &out, if( vips_cast( in, &out, format[in->BandFmt], NULL ) ) {
class->format_table[in->BandFmt], NULL ) ) {
g_object_unref( in ); g_object_unref( in );
return( -1 ); return( -1 );
} }
@ -1357,11 +1348,11 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
/* Does this class want a coded image? Search the coding table for the /* Does this class want a coded image? Search the coding table for the
* first one. * first one.
*/ */
if( class->coding[VIPS_CODING_NONE] ) { if( coding[VIPS_CODING_NONE] ) {
/* Already NONE, nothing to do. /* Already NONE, nothing to do.
*/ */
} }
else if( class->coding[VIPS_CODING_LABQ] ) { else if( coding[VIPS_CODING_LABQ] ) {
VipsImage *out; VipsImage *out;
if( vips_Lab2LabQ( in, &out, NULL ) ) { if( vips_Lab2LabQ( in, &out, NULL ) ) {
@ -1372,7 +1363,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
in = out; in = out;
} }
else if( class->coding[VIPS_CODING_RAD] ) { else if( coding[VIPS_CODING_RAD] ) {
VipsImage *out; VipsImage *out;
if( vips_float2rad( in, &out, NULL ) ) { if( vips_float2rad( in, &out, NULL ) ) {
@ -1384,8 +1375,7 @@ vips_foreign_convert_saveable( VipsForeignSave *save )
in = out; in = out;
} }
VIPS_UNREF( save->ready ); *ready = in;
save->ready = in;
return( 0 ); return( 0 );
} }
@ -1395,9 +1385,19 @@ vips_foreign_save_build( VipsObject *object )
{ {
VipsForeignSave *save = VIPS_FOREIGN_SAVE( object ); VipsForeignSave *save = VIPS_FOREIGN_SAVE( object );
if( save->in && if( save->in ) {
vips_foreign_convert_saveable( save ) ) VipsForeignSaveClass *class =
return( -1 ); VIPS_FOREIGN_SAVE_GET_CLASS( save );
VipsImage *ready;
if( vips__foreign_convert_saveable( save->in, &ready,
class->saveable, class->format_table, class->coding,
save->background ) )
return( -1 );
VIPS_UNREF( save->ready );
save->ready = ready;
}
if( VIPS_OBJECT_CLASS( vips_foreign_save_parent_class )-> if( VIPS_OBJECT_CLASS( vips_foreign_save_parent_class )->
build( object ) ) build( object ) )

View File

@ -139,6 +139,8 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
foreign_class->suffs = vips__jpeg_suffs; foreign_class->suffs = vips__jpeg_suffs;
/* See also vips_foreign_save_tiff_build() when saving JPEG in TIFF.
*/
save_class->saveable = VIPS_SAVEABLE_RGB_CMYK; save_class->saveable = VIPS_SAVEABLE_RGB_CMYK;
save_class->format_table = bandfmt_jpeg; save_class->format_table = bandfmt_jpeg;

View File

@ -8,6 +8,8 @@
* - add rgbjpeg flag * - add rgbjpeg flag
* 21/12/15 * 21/12/15
* - add properties flag * - add properties flag
* 31/5/16
* - convert for jpg if jpg compression is on
*/ */
/* /*
@ -52,6 +54,7 @@
#include <string.h> #include <string.h>
#include <vips/vips.h> #include <vips/vips.h>
#include <vips/internal.h>
#ifdef HAVE_TIFF #ifdef HAVE_TIFF
@ -89,14 +92,44 @@ typedef VipsForeignSaveClass VipsForeignSaveTiffClass;
G_DEFINE_TYPE( VipsForeignSaveTiff, vips_foreign_save_tiff, G_DEFINE_TYPE( VipsForeignSaveTiff, vips_foreign_save_tiff,
VIPS_TYPE_FOREIGN_SAVE ); VIPS_TYPE_FOREIGN_SAVE );
#define UC VIPS_FORMAT_UCHAR
/* Type promotion for save ... just always go to uchar.
*/
static int bandfmt_jpeg[10] = {
/* UC C US S UI I F X D DX */
UC, UC, UC, UC, UC, UC, UC, UC, UC, UC
};
static int static int
vips_foreign_save_tiff_build( VipsObject *object ) vips_foreign_save_tiff_build( VipsObject *object )
{ {
VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_GET_CLASS( object );
VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object; VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object;
const char *p; const char *p;
/* If we are saving jpeg-in-tiff, we need a different convert_saveable
* path. The regular tiff one will let through things like float and
* 16-bit and alpha for example, which will make the jpeg saver choke.
*/
if( save->in &&
tiff->compression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG ) {
VipsImage *x;
/* See also vips_foreign_save_jpeg_class_init().
*/
if( vips__foreign_convert_saveable( save->in, &x,
VIPS_SAVEABLE_RGB_CMYK, bandfmt_jpeg, class->coding,
save->background ) )
return( -1 );
g_object_set( object, "in", x, NULL );
g_object_unref( x );
}
if( VIPS_OBJECT_CLASS( vips_foreign_save_tiff_parent_class )-> if( VIPS_OBJECT_CLASS( vips_foreign_save_tiff_parent_class )->
build( object ) ) build( object ) )
return( -1 ); return( -1 );

View File

@ -246,6 +246,11 @@ typedef struct _VipsImagePixels {
gint64 npels; /* Number of pels calculated so far */ gint64 npels; /* Number of pels calculated so far */
} VipsImagePixels; } VipsImagePixels;
int
vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready,
VipsSaveable saveable, VipsBandFormat *format, VipsCoding *coding,
VipsArrayDouble *background );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /*__cplusplus*/ #endif /*__cplusplus*/