From f3842dcc4bcaa69208b3807f6ab11a43d003e922 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 8 Apr 2018 11:44:15 +0100 Subject: [PATCH 1/6] update cpp example thanks fangqiao see https://github.com/jcupitt/libvips/issues/932 --- ChangeLog | 4 +-- doc/using-cpp.xml | 83 +++++++++++++++++++---------------------------- 2 files changed, 35 insertions(+), 52 deletions(-) diff --git a/ChangeLog b/ChangeLog index 65a91921..627d8e64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ 12/3/18 started 8.6.4 -- better fitting of fonts with overhanging edges, thanks Adrià -- lower stack use in radsave to help musl [Jacob Thrane Lund] +- better fitting of fonts with overhanging edges [Adrià] +- revise C++ example [fangqiao] 12/2/18 started 8.6.3 - use pkg-config to find libjpeg, if we can diff --git a/doc/using-cpp.xml b/doc/using-cpp.xml index a5fb9d39..be1cbeae 100644 --- a/doc/using-cpp.xml +++ b/doc/using-cpp.xml @@ -26,7 +26,7 @@ /* compile with: - * g++ -g -Wall try.cc `pkg-config vips-cpp --cflags --libs` + * g++ -g -Wall example.cc `pkg-config vips-cpp --cflags --libs` */ #include <vips/vips8> @@ -34,64 +34,47 @@ using namespace vips; int -main( int argc, char **argv ) -{ - GOptionContext *context; - GOptionGroup *main_group; - GError *error = NULL; +main (int argc, char **argv) +{ + if (VIPS_INIT (argv[0])) + vips_error_exit (NULL); + + if (argc != 3) + vips_error_exit ("usage: %s input-file output-file", argv[0]); - if( VIPS_INIT( argv[0] ) ) - vips_error_exit( NULL ); - - context = g_option_context_new( "" ); - - main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL ); - g_option_context_set_main_group( context, main_group ); - g_option_context_add_group( context, vips_get_option_group() ); - - if( !g_option_context_parse( context, &argc, &argv, &error ) ) { - if( error ) { - fprintf( stderr, "%s\n", error->message ); - g_error_free( error ); - } - - vips_error_exit( NULL ); - } - - VImage in = VImage::new_from_file( argv[1], - VImage::option()-> - set( "access", VIPS_ACCESS_SEQUENTIAL ) ); - - double avg = in.avg(); - - printf( "avg = %g\n", avg ); - printf( "width = %d\n", in.width() ); - - VImage in = VImage::new_from_file( argv[1], - VImage::option()-> - set( "access", VIPS_ACCESS_SEQUENTIAL ) ); - - VImage out = in.embed( 10, 10, 1000, 1000, - VImage::option()-> - set( "extend", "background" )-> - set( "background", 128 ) ); - - out.write_to_file( argv[2] ); - - vips_shutdown(); - - return( 0 ); + VImage in = VImage::new_from_file (argv[1], + VImage::option ()->set ("access", VIPS_ACCESS_SEQUENTIAL)); + + double avg = in.avg (); + + printf ("avg = %g\n", avg); + printf ("width = %d\n", in.width ()); + + in = VImage::new_from_file (argv[1], + VImage::option ()->set ("access", VIPS_ACCESS_SEQUENTIAL)); + + VImage out = in.embed (10, 10, 1000, 1000, + VImage::option ()-> + set ("extend", "background")-> + set ("background", 128)); + + out.write_to_file (argv[2]); + + vips_shutdown (); + + return (0); } Everything before VImage in = VImage::.. is exactly - as the C API. This boilerplate gives the example a set of standard - command-line flags. + as the C API. vips_error_exit() just prints the arguments plus the + libvips error log and exits with an error code. - This line is the C++ equivalent of vips_image_new_from_file(). It works + VImage in = VImage::.. is the C++ equivalent of + vips_image_new_from_file(). It works in the same way, the differences being: From 06802e41107d7125f12168b32fcbb045782d4c13 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 9 Apr 2018 13:27:57 +0100 Subject: [PATCH 2/6] use O_TMPFILE, if available If O_TNMPFILE is available, use it. This is a linux extension that creates an unlinked file, so it'll be closed by the system when the last associated fd is closed. see https://github.com/jcupitt/libvips/pull/930 --- ChangeLog | 1 + libvips/iofuncs/vips.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index c1d3066f..e81501d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,7 @@ - drop incompatible ICC profiles before save - better hasalpha rules - create funcs always make MULTIBAND (ie. no alpha) +- use O_TMPFILE, if available [Alexander--] 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 49e6614f..2a537e43 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -21,6 +21,8 @@ * - use expat for xml read, printf for xml write * 16/8/17 * - validate strs as being utf-8 before we write + * 9/4/18 Alexander-- + * - use O_TMPFILE, if available */ /* @@ -55,6 +57,10 @@ #define DEBUG */ +/* Enable linux extensions like O_TMPFILE, if available. + */ +#define _GNU_SOURCE + #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ @@ -69,12 +75,12 @@ #include #include #include -#include #include +#include +#include #ifdef HAVE_SYS_FILE_H #include #endif /*HAVE_SYS_FILE_H*/ -#include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ @@ -181,8 +187,26 @@ vips__open_image_write( const char *filename, gboolean temp ) flags = MODE_WRITE; +#ifdef O_TMPFILE + /* Linux-only extension creates an unlinked file. CREAT and TRUNC must + * be clear. The filename arg to open() must name a directory. + */ + if( temp ) { + char *dirname; + + flags |= O_TMPFILE; + flags &= ~O_CREAT; + flags &= ~O_TRUNC; + + dirname = g_path_get_dirname( filename ); + fd = vips_tracked_open( dirname, flags, 0666 ); + g_free( dirname ); + } + else + fd = vips_tracked_open( filename, flags, 0666 ); +#else /*!O_TMPFILE*/ #ifdef _O_TEMPORARY - /* On Windows, setting O_TEMP gets the file automatically + /* On Windows, setting _O_TEMPORARY gets the file automatically * deleted on process exit, even if the processes crashes. See * vips_image_rewind() for what we do to help on *nix. */ @@ -190,10 +214,12 @@ vips__open_image_write( const char *filename, gboolean temp ) flags |= _O_TEMPORARY; #endif /*_O_TEMPORARY*/ - if( (fd = vips_tracked_open( filename, flags, 0666 )) < 0 ) { + fd = vips_tracked_open( filename, flags, 0666 ); +#endif /*O_TMPFILE*/ + + if( fd < 0 ) { vips_error_system( errno, "VipsImage", - _( "unable to write to \"%s\"" ), - filename ); + _( "unable to write to \"%s\"" ), filename ); return( -1 ); } From 15abbbe9863629227e7b0a04c78ef1b2d3aeb4b2 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 9 Apr 2018 17:14:38 +0100 Subject: [PATCH 3/6] set "interlaced" for jpg and png set "interlaced" for interlaced png and jpg images --- ChangeLog | 1 + libvips/foreign/jpeg2vips.c | 7 +++++++ libvips/foreign/vipspng.c | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/ChangeLog b/ChangeLog index e81501d0..41d6dd9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ - better hasalpha rules - create funcs always make MULTIBAND (ie. no alpha) - use O_TMPFILE, if available [Alexander--] +- set "interlaced=1" for interlaced JPG and PNG images 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index ceed5918..a3320606 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -94,6 +94,8 @@ * - revert previous warning change: libvips reports serious corruption, * like a truncated file, as a warning and we need to be able to catch * that + * 9/4/18 + * - set interlaced=1 for interlaced images */ /* @@ -414,6 +416,11 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out ) (void) vips_image_set_int( out, "jpeg-multiscan", jpeg_has_multiple_scans( cinfo ) ); + /* 8.7 adds this for PNG as well, so we have a new format-neutral name. + */ + if( jpeg_has_multiple_scans( cinfo ) ) + vips_image_set_int( out, "interlaced", 1 ); + /* Look for EXIF and ICC profile. */ for( p = cinfo->marker_list; p; p = p->next ) { diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index a7aaf963..1a98000b 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -65,6 +65,8 @@ * - better behaviour for truncated png files, thanks Yury * 26/4/17 * - better @fail handling with truncated PNGs + * 9/4/18 + * - set interlaced=1 for interlaced images */ /* @@ -438,6 +440,11 @@ png2vips_header( Read *read, VipsImage *out ) return( -1 ); } + /* Let our caller know. These are very expensive to decode. + */ + if( interlace_type != PNG_INTERLACE_NONE ) + vips_image_set_int( out, "interlaced", 1 ); + return( 0 ); } From f1f2a9de55effda07295009b40e485a7b964db7f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 10 Apr 2018 15:14:09 +0100 Subject: [PATCH 4/6] fix a warning if tiff is disabled --- libvips/deprecated/im_tiff2vips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvips/deprecated/im_tiff2vips.c b/libvips/deprecated/im_tiff2vips.c index d94019e9..a5ded395 100644 --- a/libvips/deprecated/im_tiff2vips.c +++ b/libvips/deprecated/im_tiff2vips.c @@ -54,6 +54,7 @@ static int tiff2vips( const char *name, IMAGE *out, gboolean header_only ) { +#ifdef HAVE_TIFF char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q; @@ -84,7 +85,6 @@ tiff2vips( const char *name, IMAGE *out, gboolean header_only ) * malloc if all we are doing is looking at fields. */ -#ifdef HAVE_TIFF if( !header_only && !seq && !vips__istifftiled( filename ) && From d1dd41a21fe8251dd57d9069ae388e1b7ae30764 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 10 Apr 2018 15:18:18 +0100 Subject: [PATCH 5/6] strict round down on jpeg shrink libjpeg rounds up on shrink-on-load. In some cases this can leave a dark line along the right and bottom edge, since it only contains (for example) 1/4 of a pixel of data. This change adds a crop after jpeg load so that only complete pixels are output. See https://github.com/lovell/sharp/issues/1185 --- ChangeLog | 1 + libvips/foreign/jpeg2vips.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 627d8e64..c0c417a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges [Adrià] - revise C++ example [fangqiao] +- strict round down on jpeg shrink on load [davidwood] 12/2/18 started 8.6.3 - use pkg-config to find libjpeg, if we can diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index eb59427e..cf4b39d1 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -94,6 +94,8 @@ * - revert previous warning change: libvips reports serious corruption, * like a truncated file, as a warning and we need to be able to catch * that + * 10/4/18 + * - strict round down on shrink-on-load */ /* @@ -151,8 +153,6 @@ /* Stuff we track during a read. */ typedef struct _ReadJpeg { - VipsImage *out; - /* Shrink by this much during load. 1, 2, 4, 8. */ int shrink; @@ -177,6 +177,13 @@ typedef struct _ReadJpeg { * during load. */ gboolean autorotate; + + /* cinfo->output_width and height can be larger than we want since + * libjpeg rounds up on shrink-on-load. This is the real size we will + * output, as opposed to the size we decompress to. + */ + int output_width; + int output_height; } ReadJpeg; /* This can be called many times. @@ -228,7 +235,6 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate ) if( !(jpeg = VIPS_NEW( out, ReadJpeg )) ) return( NULL ); - jpeg->out = out; jpeg->shrink = shrink; jpeg->fail = fail; jpeg->filename = NULL; @@ -408,6 +414,18 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out ) vips_image_pipelinev( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL ); + /* cinfo->output_width and cinfo->output_height round up with + * shrink-on-load. For example, if the image is 1801 pixels across and + * we shrink by 4, the output will be 450.25 pixels across, + * cinfo->output_width with be 451, and libjpeg will write a black + * column of pixels down the right. + * + * We must strictly round down, since we don't want fractional pixels + * along the bottom and right. + */ + jpeg->output_width = cinfo->image_width / jpeg->shrink; + jpeg->output_height = cinfo->image_height / jpeg->shrink; + /* Interlaced jpegs need lots of memory to read, so our caller needs * to know. */ @@ -691,12 +709,14 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out ) if( vips_image_generate( t[0], NULL, read_jpeg_generate, NULL, jpeg, NULL ) || - vips_sequential( t[0], &t[1], + vips_extract_area( t[0], &t[1], + 0, 0, jpeg->output_width, jpeg->output_height, NULL ) || + vips_sequential( t[1], &t[2], "tile_height", 8, NULL ) ) return( -1 ); - im = t[1]; + im = t[2]; if( jpeg->autorotate ) im = read_jpeg_rotate( VIPS_OBJECT( out ), im ); @@ -735,6 +755,11 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only ) if( read_jpeg_header( jpeg, out ) ) return( -1 ); + /* Patch in the correct size. + */ + out->Xsize = jpeg->output_width; + out->Ysize = jpeg->output_height; + /* Swap width and height if we're going to rotate this image. */ if( jpeg->autorotate ) { From 24b146790f0628c65500e66effd29855c3fb1d14 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 10 Apr 2018 15:39:51 +0100 Subject: [PATCH 6/6] oop reorder crop to come after cache or we'll write beyond the buffer end --- libvips/foreign/jpeg2vips.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index cf4b39d1..08265baa 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -706,14 +706,17 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out ) printf( "read_jpeg_image: starting decompress\n" ); #endif /*DEBUG*/ + /* We must crop after the seq, or our generate may not be asked for + * full lines of pixels and will attempt to write beyond the buffer. + */ if( vips_image_generate( t[0], NULL, read_jpeg_generate, NULL, jpeg, NULL ) || - vips_extract_area( t[0], &t[1], - 0, 0, jpeg->output_width, jpeg->output_height, NULL ) || - vips_sequential( t[1], &t[2], + vips_sequential( t[0], &t[1], "tile_height", 8, - NULL ) ) + NULL ) || + vips_extract_area( t[1], &t[2], + 0, 0, jpeg->output_width, jpeg->output_height, NULL ) ) return( -1 ); im = t[2];