Merge branch '8.6'

This commit is contained in:
John Cupitt 2018-04-11 09:38:59 +01:00
commit 5b55dd8ed4
3 changed files with 69 additions and 57 deletions

View File

@ -16,8 +16,9 @@
- set "interlaced=1" for interlaced JPG and PNG images - set "interlaced=1" for interlaced JPG and PNG images
12/3/18 started 8.6.4 12/3/18 started 8.6.4
- better fitting of fonts with overhanging edges, thanks Adrià - better fitting of fonts with overhanging edges [Adrià]
- lower stack use in radsave to help musl [Jacob Thrane Lund] - revise C++ example [fangqiao]
- strict round down on jpeg shrink on load [davidwood]
12/2/18 started 8.6.3 12/2/18 started 8.6.3
- use pkg-config to find libjpeg, if we can - use pkg-config to find libjpeg, if we can

View File

@ -26,7 +26,7 @@
<programlisting language="cpp"> <programlisting language="cpp">
/* compile with: /* 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 &lt;vips/vips8&gt; #include &lt;vips/vips8&gt;
@ -34,64 +34,47 @@
using namespace vips; using namespace vips;
int int
main( int argc, char **argv ) main (int argc, char **argv)
{ {
GOptionContext *context; if (VIPS_INIT (argv[0]))
GOptionGroup *main_group; vips_error_exit (NULL);
GError *error = NULL;
if (argc != 3)
vips_error_exit ("usage: %s input-file output-file", argv[0]);
if( VIPS_INIT( argv[0] ) ) VImage in = VImage::new_from_file (argv[1],
vips_error_exit( NULL ); VImage::option ()-&gt;set ("access", VIPS_ACCESS_SEQUENTIAL));
context = g_option_context_new( "" ); double avg = in.avg ();
main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL ); printf ("avg = %g\n", avg);
g_option_context_set_main_group( context, main_group ); printf ("width = %d\n", in.width ());
g_option_context_add_group( context, vips_get_option_group() );
in = VImage::new_from_file (argv[1],
if( !g_option_context_parse( context, &amp;argc, &amp;argv, &amp;error ) ) { VImage::option ()-&gt;set ("access", VIPS_ACCESS_SEQUENTIAL));
if( error ) {
fprintf( stderr, "%s\n", error->message ); VImage out = in.embed (10, 10, 1000, 1000,
g_error_free( error ); VImage::option ()-&gt;
} set ("extend", "background")-&gt;
set ("background", 128));
vips_error_exit( NULL );
} out.write_to_file (argv[2]);
VImage in = VImage::new_from_file( argv[1], vips_shutdown ();
VImage::option()->
set( "access", VIPS_ACCESS_SEQUENTIAL ) ); return (0);
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 );
} }
</programlisting> </programlisting>
<para> <para>
Everything before <code>VImage in = VImage::..</code> is exactly Everything before <code>VImage in = VImage::..</code> is exactly
as the C API. This boilerplate gives the example a set of standard as the C API. vips_error_exit() just prints the arguments plus the
command-line flags. libvips error log and exits with an error code.
</para> </para>
<para> <para>
This line is the C++ equivalent of vips_image_new_from_file(). It works <code>VImage in = VImage::..</code> is the C++ equivalent of
vips_image_new_from_file(). It works
in the same way, the differences being: in the same way, the differences being:
<itemizedlist> <itemizedlist>

View File

@ -96,6 +96,8 @@
* that * that
* 9/4/18 * 9/4/18
* - set interlaced=1 for interlaced images * - set interlaced=1 for interlaced images
* 10/4/18
* - strict round down on shrink-on-load
*/ */
/* /*
@ -153,8 +155,6 @@
/* Stuff we track during a read. /* Stuff we track during a read.
*/ */
typedef struct _ReadJpeg { typedef struct _ReadJpeg {
VipsImage *out;
/* Shrink by this much during load. 1, 2, 4, 8. /* Shrink by this much during load. 1, 2, 4, 8.
*/ */
int shrink; int shrink;
@ -179,6 +179,13 @@ typedef struct _ReadJpeg {
* during load. * during load.
*/ */
gboolean autorotate; 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; } ReadJpeg;
/* This can be called many times. /* This can be called many times.
@ -230,7 +237,6 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate )
if( !(jpeg = VIPS_NEW( out, ReadJpeg )) ) if( !(jpeg = VIPS_NEW( out, ReadJpeg )) )
return( NULL ); return( NULL );
jpeg->out = out;
jpeg->shrink = shrink; jpeg->shrink = shrink;
jpeg->fail = fail; jpeg->fail = fail;
jpeg->filename = NULL; jpeg->filename = NULL;
@ -410,6 +416,18 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL ); 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 /* Interlaced jpegs need lots of memory to read, so our caller needs
* to know. * to know.
*/ */
@ -691,15 +709,20 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
printf( "read_jpeg_image: starting decompress\n" ); printf( "read_jpeg_image: starting decompress\n" );
#endif /*DEBUG*/ #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], if( vips_image_generate( t[0],
NULL, read_jpeg_generate, NULL, NULL, read_jpeg_generate, NULL,
jpeg, NULL ) || jpeg, NULL ) ||
vips_sequential( t[0], &t[1], vips_sequential( t[0], &t[1],
"tile_height", 8, "tile_height", 8,
NULL ) ) NULL ) ||
vips_extract_area( t[1], &t[2],
0, 0, jpeg->output_width, jpeg->output_height, NULL ) )
return( -1 ); return( -1 );
im = t[1]; im = t[2];
if( jpeg->autorotate ) if( jpeg->autorotate )
im = read_jpeg_rotate( VIPS_OBJECT( out ), im ); im = read_jpeg_rotate( VIPS_OBJECT( out ), im );
@ -738,6 +761,11 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
if( read_jpeg_header( jpeg, out ) ) if( read_jpeg_header( jpeg, out ) )
return( -1 ); 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. /* Swap width and height if we're going to rotate this image.
*/ */
if( jpeg->autorotate ) { if( jpeg->autorotate ) {