Merge branch 'master' into add-jxl

This commit is contained in:
John Cupitt 2021-04-14 15:08:46 +01:00
commit 4483a2edbc
16 changed files with 384 additions and 156 deletions

View File

@ -60,7 +60,8 @@ jobs:
- name: Install macOS dependencies - name: Install macOS dependencies
if: contains(matrix.os, 'macos') if: contains(matrix.os, 'macos')
run: run: |
brew update
brew install brew install
autoconf automake libtool autoconf automake libtool
gtk-doc gobject-introspection gtk-doc gobject-introspection

View File

@ -23,6 +23,7 @@
- add GIF load with libnsgif - add GIF load with libnsgif
- add JPEG2000 load and save - add JPEG2000 load and save
- add JPEG-XL load and save - add JPEG-XL load and save
- add "rgba" flag to vips_text() to enable full colour text rendering
22/12/20 start 8.10.6 22/12/20 start 8.10.6
- don't seek on bad file descriptors [kleisauke] - don't seek on bad file descriptors [kleisauke]

View File

@ -22,7 +22,7 @@ operations, frequency filtering, colour, resampling,
statistics and others. It supports a large range of [numeric statistics and others. It supports a large range of [numeric
types](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat), types](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat),
from 8-bit int to 128-bit complex. Images can have any number of bands. from 8-bit int to 128-bit complex. Images can have any number of bands.
It supports a good range of image formats, including JPEG, TIFF, PNG, It supports a good range of image formats, including JPEG, JPEG2000, TIFF, PNG,
WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM, WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM,
CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images
via ImageMagick or GraphicsMagick, letting it work with formats like DICOM. via ImageMagick or GraphicsMagick, letting it work with formats like DICOM.
@ -243,10 +243,10 @@ If you are going to be using libvips with untrusted images, perhaps in a
web server, for example, you should consider the security implications of web server, for example, you should consider the security implications of
enabling a package with such a large attack surface. enabling a package with such a large attack surface.
### pangoft2 ### pangocairo
If available, libvips adds support for text rendering. You need the If available, libvips adds support for text rendering. You need the
package pangoft2 in `pkg-config --list-all`. package pangocairo in `pkg-config --list-all`.
### orc-0.4 ### orc-0.4
@ -274,6 +274,10 @@ If available, vips can load and save NIfTI images.
If available, libvips will directly read (but not write, sadly) If available, libvips will directly read (but not write, sadly)
OpenEXR images. OpenEXR images.
### OpenJPEG
If available, libvips will read and write JPEG2000 images.
### OpenSlide ### OpenSlide
If available, libvips can load OpenSlide-supported virtual slide If available, libvips can load OpenSlide-supported virtual slide

View File

@ -1105,25 +1105,25 @@ fi
VIPS_CFLAGS="$VIPS_CFLAGS $LIBWEBP_CFLAGS" VIPS_CFLAGS="$VIPS_CFLAGS $LIBWEBP_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $LIBWEBP_LIBS" VIPS_LIBS="$VIPS_LIBS $LIBWEBP_LIBS"
# pangoft2 # pangocairo for text rendering
AC_ARG_WITH([pangoft2], AC_ARG_WITH([pangocairo],
AS_HELP_STRING([--without-pangoft2], AS_HELP_STRING([--without-pangocairo],
[build without pangoft2 (default: test)])) [build without pangocairo (default: test)]))
if test x"$with_pangoft2" != x"no"; then if test x"$with_pangocairo" != x"no"; then
PKG_CHECK_MODULES(PANGOFT2, pangoft2, PKG_CHECK_MODULES(PANGOCAIRO, pangocairo,
[AC_DEFINE(HAVE_PANGOFT2,1,[define if you have pangoft2 installed.]) [AC_DEFINE(HAVE_PANGOCAIRO,1,[define if you have pangocairo installed.])
with_pangoft2=yes with_pangocairo=yes
PACKAGES_USED="$PACKAGES_USED pangoft2" PACKAGES_USED="$PACKAGES_USED pangocairo"
], ],
[AC_MSG_WARN([pangoft2 not found; disabling pangoft2 support]) [AC_MSG_WARN([pangocairo not found; disabling pangocairo support])
with_pangoft2=no with_pangocairo=no
] ]
) )
fi fi
VIPS_CFLAGS="$VIPS_CFLAGS $PANGOFT2_CFLAGS" VIPS_CFLAGS="$VIPS_CFLAGS $PANGOCAIRO_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $PANGOFT2_LIBS" VIPS_LIBS="$VIPS_LIBS $PANGOCAIRO_LIBS"
# look for TIFF with pkg-config ... fall back to our tester # look for TIFF with pkg-config ... fall back to our tester
# pkgconfig support for libtiff starts with libtiff-4 # pkgconfig support for libtiff starts with libtiff-4
@ -1347,7 +1347,7 @@ use fftw3 for FFT: $with_fftw, \
accelerate loops with orc: $with_orc, \ accelerate loops with orc: $with_orc, \
ICC profile support with lcms: $with_lcms, \ ICC profile support with lcms: $with_lcms, \
zlib: $with_zlib, \ zlib: $with_zlib, \
text rendering with pangoft2: $with_pangoft2, \ text rendering with pangocairo: $with_pangocairo, \
EXIF metadata support with libexif: $with_libexif, \ EXIF metadata support with libexif: $with_libexif, \
JPEG load/save with libjpeg: $with_jpeg, \ JPEG load/save with libjpeg: $with_jpeg, \
PNG load with libspng: $with_libspng, \ PNG load with libspng: $with_libspng, \
@ -1449,7 +1449,7 @@ accelerate loops with orc: $with_orc
(requires orc-0.4.11 or later) (requires orc-0.4.11 or later)
ICC profile support with lcms: $with_lcms ICC profile support with lcms: $with_lcms
zlib: $with_zlib zlib: $with_zlib
text rendering with pangoft2: $with_pangoft2 text rendering with pangocairo: $with_pangocairo
EXIF metadata support with libexif: $with_libexif EXIF metadata support with libexif: $with_libexif
## File format support ## File format support

View File

@ -32143,6 +32143,64 @@ static VipsProfileFallback vips__profile_fallback_cmyk = {
} }
}; };
static VipsProfileFallback vips__profile_fallback_p3 = {
"p3",
736,
{
0x78, 0xDA, 0x7D, 0xD0, 0x03, 0xA0, 0xE4, 0x30, 0x14, 0x05, 0xD0, 0x57,
0x7C, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0x8D, 0xB1, 0xD1, 0xCE, 0xDA, 0xB6,
0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0xED, 0x74, 0xED, 0x5B, 0x9D, 0xC6,
0x09, 0x00, 0x7E, 0x49, 0xCC, 0x92, 0x50, 0xB8, 0x21, 0x80, 0x44, 0x4A,
0x2B, 0x8B, 0x33, 0x92, 0x1D, 0x2B, 0xAB, 0xAA, 0x1D, 0x35, 0xAE, 0x00,
0x01, 0xA6, 0xA0, 0x05, 0xFA, 0x60, 0xD7, 0xC4, 0xA2, 0xE4, 0x79, 0x25,
0xE9, 0xA5, 0x80, 0x42, 0x35, 0xB5, 0xA4, 0x58, 0xB4, 0x52, 0x0C, 0xBF,
0xE4, 0xC5, 0x09, 0xC0, 0x98, 0xEF, 0x51, 0x3F, 0x7E, 0x93, 0x94, 0xDD,
0x56, 0x66, 0xB0, 0xF7, 0x52, 0x5A, 0x52, 0x78, 0x42, 0x41, 0x6A, 0xD8,
0x5E, 0xEB, 0x1E, 0x56, 0xF0, 0xFF, 0x68, 0xB1, 0x39, 0x14, 0x0B, 0x7D,
0x1F, 0xA1, 0xA7, 0x9E, 0x25, 0x57, 0xD2, 0x00, 0x98, 0x2E, 0xB2, 0x6E,
0x4B, 0x5A, 0xCE, 0xD8, 0x12, 0xD9, 0x54, 0x89, 0x16, 0x85, 0xEC, 0xCB,
0x98, 0xF7, 0xC5, 0x89, 0x8C, 0x9B, 0xBF, 0xB8, 0x94, 0xB1, 0xB2, 0xB4,
0x38, 0x05, 0x99, 0x8F, 0x9E, 0x56, 0xBC, 0x9F, 0xDC, 0xFC, 0x93, 0xBF,
0xCE, 0xC5, 0x44, 0x8D, 0x2A, 0x0C, 0x41, 0xE5, 0x3F, 0x42, 0x73, 0x5A,
0xD1, 0xCC, 0x37, 0x25, 0x25, 0x10, 0x98, 0x33, 0xF8, 0x52, 0xFA, 0xB4,
0x08, 0x30, 0xF4, 0xC1, 0xCC, 0xF7, 0xFD, 0x28, 0xEB, 0x7A, 0x11, 0x20,
0x6E, 0x23, 0xA3, 0x1F, 0x65, 0xD9, 0xE8, 0x7F, 0x71, 0x04, 0x80, 0xF6,
0xF2, 0x1F, 0x65, 0x9E, 0x91, 0x00, 0x46, 0xDA, 0x00, 0xBB, 0x5A, 0xB1,
0x54, 0xCA, 0x16, 0xF0, 0x25, 0x2B, 0xD0, 0x63, 0x0B, 0x91, 0x50, 0x0A,
0x72, 0xE8, 0x07, 0xB3, 0x60, 0x1B, 0x5C, 0xC6, 0x00, 0x73, 0xC6, 0xD2,
0x31, 0x09, 0x36, 0x1C, 0xDB, 0x8C, 0x3D, 0xC2, 0x1D, 0xF1, 0x32, 0xBC,
0x2F, 0xBE, 0x8D, 0xC0, 0x88, 0x04, 0xA2, 0x0B, 0xB1, 0x83, 0xD4, 0x27,
0xAB, 0xC8, 0x99, 0xE4, 0x6B, 0xB5, 0x5C, 0xB5, 0x69, 0x6A, 0x1F, 0xD4,
0x6B, 0xD5, 0x37, 0x68, 0x38, 0x69, 0xF4, 0xD1, 0x78, 0xA6, 0xC9, 0xD2,
0x3C, 0xAE, 0x95, 0xA5, 0xB5, 0x55, 0x3B, 0x41, 0x7B, 0xA3, 0x4E, 0xB2,
0xCE, 0x6E, 0xDD, 0x52, 0xDD, 0xCB, 0x7A, 0xB4, 0xBE, 0x96, 0xFE, 0x14,
0x83, 0x44, 0x83, 0x4B, 0x86, 0xDD, 0x8D, 0xFC, 0x8C, 0xCE, 0x18, 0xF7,
0x31, 0x89, 0x37, 0x79, 0x61, 0xBA, 0xC4, 0x4C, 0x61, 0x1E, 0x6E, 0xFE,
0xDE, 0x62, 0x8F, 0xE5, 0x68, 0x2B, 0xA9, 0x75, 0xBA, 0x8D, 0xB3, 0x2D,
0x61, 0x7B, 0xD3, 0xEE, 0x90, 0xFD, 0x7A, 0x87, 0x05, 0x8E, 0xD3, 0x9C,
0x26, 0x38, 0x8F, 0x73, 0x99, 0xE8, 0x3A, 0xDD, 0x6D, 0xB1, 0xFB, 0x26,
0x8F, 0xE3, 0x9E, 0xF7, 0xBD, 0xB5, 0x7D, 0x7C, 0x7C, 0x8B, 0xFC, 0xDA,
0xF9, 0xCF, 0x09, 0xB8, 0x10, 0x64, 0x1E, 0x5C, 0x1C, 0x32, 0x2C, 0xF4,
0x74, 0xB8, 0x6B, 0x04, 0x15, 0xB9, 0x23, 0xDA, 0x31, 0xA6, 0x5D, 0xEC,
0xC5, 0xF8, 0xB4, 0x84, 0x45, 0x49, 0x4E, 0xC9, 0x23, 0x52, 0x0D, 0xD3,
0x06, 0x66, 0x18, 0x67, 0x8E, 0xCD, 0xF6, 0xCC, 0x59, 0x9B, 0x57, 0x94,
0xFF, 0xA0, 0x70, 0x60, 0x71, 0x58, 0xC9, 0xA5, 0xB2, 0x41, 0x15, 0x69,
0x55, 0x50, 0xBD, 0xA1, 0xB6, 0x5B, 0x7D, 0x6E, 0xA3, 0x4D, 0xD3, 0x43,
0xD6, 0x4E, 0xCE, 0x0C, 0x5E, 0x6F, 0x81, 0x42, 0xD4, 0x20, 0x29, 0x92,
0x65, 0x2B, 0xD2, 0xA9, 0x6C, 0x55, 0x51, 0xCB, 0xFA, 0xD6, 0x8A, 0xB6,
0xBD, 0xDA, 0xCF, 0xE8, 0xB8, 0xAB, 0xF3, 0xA3, 0x6E, 0xF6, 0x3D, 0x0A,
0x7B, 0xF5, 0xEE, 0xB3, 0xBD, 0xBF, 0xD6, 0xC0, 0xA2, 0xC1, 0x13, 0x87,
0x3E, 0x1D, 0x91, 0x33, 0x6A, 0xEE, 0x58, 0xFD, 0xF1, 0xAD, 0x26, 0xDE,
0x9C, 0x52, 0x33, 0xED, 0xC4, 0xCC, 0xF2, 0xD9, 0x67, 0xE7, 0xF1, 0x16,
0xBC, 0x5C, 0x3C, 0x70, 0x99, 0xF7, 0x8A, 0x7D, 0xAB, 0xE9, 0x75, 0x4E,
0x1B, 0x8E, 0x6F, 0xEE, 0xBF, 0x2D, 0x77, 0xA7, 0xE1, 0xEE, 0x33, 0xFB,
0xE6, 0x1E, 0xEC, 0x78, 0xA4, 0xF6, 0x78, 0xDC, 0x29, 0xD7, 0xB3, 0xC6,
0x17, 0xC8, 0x4B, 0x1F, 0xAE, 0xBE, 0xBB, 0x89, 0xDD, 0xD1, 0xBD, 0x6F,
0xFB, 0x28, 0xF4, 0x69, 0xE1, 0x0B, 0xEA, 0xF5, 0xD8, 0x77, 0x7B, 0x3E,
0x7E, 0xFC, 0x04, 0xD4, 0xCA, 0xD2, 0x46,
}
};
static VipsProfileFallback vips__profile_fallback_sRGB = { static VipsProfileFallback vips__profile_fallback_sRGB = {
"sRGB", "sRGB",
6922, 6922,
@ -32348,6 +32406,7 @@ static VipsProfileFallback vips__profile_fallback_sRGB = {
VipsProfileFallback *vips__profile_fallback_table[] = { VipsProfileFallback *vips__profile_fallback_table[] = {
&vips__profile_fallback_cmyk, &vips__profile_fallback_cmyk,
&vips__profile_fallback_p3,
&vips__profile_fallback_sRGB, &vips__profile_fallback_sRGB,
NULL NULL
}; };

View File

@ -1,3 +1,4 @@
EXTRA_DIST = \ EXTRA_DIST = \
p3.icm \
cmyk.icm \ cmyk.icm \
sRGB.icm sRGB.icm

Binary file not shown.

View File

@ -116,9 +116,9 @@ vips_create_operation_init( void )
extern GType vips_gaussmat_get_type( void ); extern GType vips_gaussmat_get_type( void );
extern GType vips_logmat_get_type( void ); extern GType vips_logmat_get_type( void );
extern GType vips_gaussnoise_get_type( void ); extern GType vips_gaussnoise_get_type( void );
#ifdef HAVE_PANGOFT2 #ifdef HAVE_PANGOCAIRO
extern GType vips_text_get_type( void ); extern GType vips_text_get_type( void );
#endif /*HAVE_PANGOFT2*/ #endif /*HAVE_PANGOCAIRO*/
extern GType vips_xyz_get_type( void ); extern GType vips_xyz_get_type( void );
extern GType vips_eye_get_type( void ); extern GType vips_eye_get_type( void );
extern GType vips_grey_get_type( void ); extern GType vips_grey_get_type( void );
@ -146,9 +146,9 @@ vips_create_operation_init( void )
vips_gaussmat_get_type(); vips_gaussmat_get_type();
vips_logmat_get_type(); vips_logmat_get_type();
vips_gaussnoise_get_type(); vips_gaussnoise_get_type();
#ifdef HAVE_PANGOFT2 #ifdef HAVE_PANGOCAIRO
vips_text_get_type(); vips_text_get_type();
#endif /*HAVE_PANGOFT2*/ #endif /*HAVE_PANGOCAIRO*/
vips_xyz_get_type(); vips_xyz_get_type();
vips_eye_get_type(); vips_eye_get_type();
vips_grey_get_type(); vips_grey_get_type();

View File

@ -32,6 +32,9 @@
* - fitting could occasionally terminate early [levmorozov] * - fitting could occasionally terminate early [levmorozov]
* 16/5/20 [keiviv] * 16/5/20 [keiviv]
* - don't add fontfiles repeatedly * - don't add fontfiles repeatedly
* 12/4/21
* - switch to cairo for text rendering
* - add rgba flag
*/ */
/* /*
@ -74,11 +77,14 @@
#include <string.h> #include <string.h>
#include <vips/vips.h> #include <vips/vips.h>
#include <vips/internal.h>
#ifdef HAVE_PANGOFT2 #ifdef HAVE_PANGOCAIRO
#include <cairo.h>
#include <pango/pango.h> #include <pango/pango.h>
#include <pango/pangoft2.h> #include <pango/pangocairo.h>
#include <fontconfig/fontconfig.h>
#include "pcreate.h" #include "pcreate.h"
@ -94,8 +100,8 @@ typedef struct _VipsText {
gboolean justify; gboolean justify;
int dpi; int dpi;
char *fontfile; char *fontfile;
gboolean rgba;
FT_Bitmap bitmap;
PangoContext *context; PangoContext *context;
PangoLayout *layout; PangoLayout *layout;
@ -129,7 +135,6 @@ vips_text_dispose( GObject *gobject )
VIPS_UNREF( text->layout ); VIPS_UNREF( text->layout );
VIPS_UNREF( text->context ); VIPS_UNREF( text->context );
VIPS_FREE( text->bitmap.buffer );
G_OBJECT_CLASS( vips_text_parent_class )->dispose( gobject ); G_OBJECT_CLASS( vips_text_parent_class )->dispose( gobject );
} }
@ -186,8 +191,8 @@ vips_text_get_extents( VipsText *text, VipsRect *extents )
PangoRectangle ink_rect; PangoRectangle ink_rect;
PangoRectangle logical_rect; PangoRectangle logical_rect;
pango_ft2_font_map_set_resolution( pango_cairo_font_map_set_resolution(
PANGO_FT2_FONT_MAP( vips_text_fontmap ), text->dpi, text->dpi ); PANGO_CAIRO_FONT_MAP( vips_text_fontmap ), text->dpi );
VIPS_UNREF( text->layout ); VIPS_UNREF( text->layout );
if( !(text->layout = text_layout_new( text->context, if( !(text->layout = text_layout_new( text->context,
@ -340,9 +345,12 @@ vips_text_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsCreate *create = VIPS_CREATE( object ); VipsCreate *create = VIPS_CREATE( object );
VipsText *text = (VipsText *) object; VipsText *text = (VipsText *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 );
VipsRect extents; VipsRect extents;
int y; VipsImage *image;
cairo_surface_t *surface;
cairo_t *cr;
if( VIPS_OBJECT_CLASS( vips_text_parent_class )->build( object ) ) if( VIPS_OBJECT_CLASS( vips_text_parent_class )->build( object ) )
return( -1 ); return( -1 );
@ -356,7 +364,7 @@ vips_text_build( VipsObject *object )
g_mutex_lock( vips_text_lock ); g_mutex_lock( vips_text_lock );
if( !vips_text_fontmap ) if( !vips_text_fontmap )
vips_text_fontmap = pango_ft2_font_map_new(); vips_text_fontmap = pango_cairo_font_map_new();
if( !vips_text_fontfiles ) if( !vips_text_fontfiles )
vips_text_fontfiles = vips_text_fontfiles =
g_hash_table_new( g_str_hash, g_str_equal ); g_hash_table_new( g_str_hash, g_str_equal );
@ -399,40 +407,65 @@ vips_text_build( VipsObject *object )
return( -1 ); return( -1 );
} }
text->bitmap.width = extents.width; /* Set DPI as pixels/mm.
text->bitmap.pitch = (text->bitmap.width + 3) & ~3; */
text->bitmap.rows = extents.height; image = t[0] = vips_image_new_memory();
if( !(text->bitmap.buffer = vips_image_init_fields( image,
VIPS_ARRAY( NULL, extents.width, extents.height, 4,
text->bitmap.pitch * text->bitmap.rows, VipsPel )) ) { VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_sRGB,
text->dpi / 25.4, text->dpi / 25.4 );
vips_image_pipelinev( image, VIPS_DEMAND_STYLE_ANY, NULL );
image->Xoffset = extents.left;
image->Yoffset = extents.top;
if( vips_image_write_prepare( image ) ) {
g_mutex_unlock( vips_text_lock ); g_mutex_unlock( vips_text_lock );
return( -1 ); return( -1 );
} }
text->bitmap.num_grays = 256;
text->bitmap.pixel_mode = ft_pixel_mode_grays;
memset( text->bitmap.buffer, 0x00,
text->bitmap.pitch * text->bitmap.rows );
pango_ft2_render_layout( &text->bitmap, text->layout, surface = cairo_image_surface_create_for_data(
-extents.left, -extents.top ); VIPS_IMAGE_ADDR( image, 0, 0 ),
CAIRO_FORMAT_ARGB32,
image->Xsize, image->Ysize,
VIPS_IMAGE_SIZEOF_LINE( image ) );
cr = cairo_create( surface );
cairo_surface_destroy( surface );
cairo_translate( cr, -extents.left, -extents.top );
pango_cairo_show_layout( cr, text->layout );
cairo_destroy( cr );
g_mutex_unlock( vips_text_lock ); g_mutex_unlock( vips_text_lock );
vips_image_init_fields( create->out, if( text->rgba ) {
text->bitmap.width, text->bitmap.rows, 1, int y;
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_MULTIBAND,
1.0, 1.0 );
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
create->out->Xoffset = extents.left;
create->out->Yoffset = extents.top;
for( y = 0; y < text->bitmap.rows; y++ ) /* Cairo makes pre-multipled BRGA -- we must byteswap and
if( vips_image_write_line( create->out, y, * unpremultiply.
(VipsPel *) text->bitmap.buffer + */
y * text->bitmap.pitch ) ) for( y = 0; y < image->Ysize; y++ )
vips__premultiplied_bgra2rgba(
(guint32 *)
VIPS_IMAGE_ADDR( image, 0, y ),
image->Xsize );
}
else {
/* We just want the alpha channel.
*/
if( vips_extract_band( image, &t[1], 3, NULL ) ||
vips_copy( t[1], &t[2],
"interpretation", VIPS_INTERPRETATION_MULTIBAND,
NULL ) )
return( -1 ); return( -1 );
image = t[2];
}
if( vips_image_write( image, create->out ) )
return( -1 );
return( 0 ); return( 0 );
} }
@ -534,6 +567,13 @@ vips_text_class_init( VipsTextClass *class )
G_STRUCT_OFFSET( VipsText, fontfile ), G_STRUCT_OFFSET( VipsText, fontfile ),
NULL ); NULL );
VIPS_ARG_BOOL( class, "rgba", 9,
_( "RGBA" ),
_( "Enable RGBA output" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsText, rgba ),
FALSE );
} }
static void static void
@ -541,11 +581,10 @@ vips_text_init( VipsText *text )
{ {
text->align = VIPS_ALIGN_LOW; text->align = VIPS_ALIGN_LOW;
text->dpi = 72; text->dpi = 72;
text->bitmap.buffer = NULL;
VIPS_SETSTR( text->font, "sans 12" ); VIPS_SETSTR( text->font, "sans 12" );
} }
#endif /*HAVE_PANGOFT2*/ #endif /*HAVE_PANGOCAIRO*/
/** /**
* vips_text: * vips_text:
@ -563,17 +602,22 @@ vips_text_init( VipsText *text )
* * @justify: %gboolean, justify lines * * @justify: %gboolean, justify lines
* * @dpi: %gint, render at this resolution * * @dpi: %gint, render at this resolution
* * @autofit_dpi: %gint, read out auto-fitted DPI * * @autofit_dpi: %gint, read out auto-fitted DPI
* * @rgba: %gboolean, enable RGBA output
* * @spacing: %gint, space lines by this in points * * @spacing: %gint, space lines by this in points
* *
* Draw the string @text to an image. @out is a one-band 8-bit * Draw the string @text to an image. @out is normally a one-band 8-bit
* unsigned char image, with 0 for no text and 255 for text. Values between * unsigned char image, with 0 for no text and 255 for text. Values between
* are used for anti-aliasing. * are used for anti-aliasing.
* *
* Set @rgba to enable RGBA output. This is useful for colour emoji rendering,
* or support for pango markup features like `<span
* foreground="red">Red!</span>`.
*
* @text is the text to render as a UTF-8 string. It can contain Pango markup, * @text is the text to render as a UTF-8 string. It can contain Pango markup,
* for example "&lt;i&gt;The&lt;/i&gt;Guardian". * for example `<i>The</i>Guardian`.
* *
* @font is the font to render with, as a fontconfig name. Examples might be * @font is the font to render with, as a fontconfig name. Examples might be
* "sans 12" or perhaps "bitstream charter bold 10". * `sans 12` or perhaps `bitstream charter bold 10`.
* *
* You can specify a font to load with @fontfile. You'll need to also set the * You can specify a font to load with @fontfile. You'll need to also set the
* name of the font with @font. * name of the font with @font.

View File

@ -33,8 +33,8 @@
/* /*
#define DEBUG_VERBOSE #define DEBUG_VERBOSE
#define DEBUG
*/ */
#define DEBUG
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
@ -58,10 +58,7 @@
/* TODO: /* TODO:
* *
* - libjxl seems to only work in one shot mode, so there's no way to read in * - add metadata support
* chunks
*
* - preview image? EXIF? XMP?
* *
* - check scRGB load * - check scRGB load
* *
@ -285,6 +282,74 @@ vips_foreign_load_jxl_print_status( JxlDecoderStatus status )
g_assert_not_reached(); g_assert_not_reached();
} }
} }
static void
vips_foreign_load_jxl_print_info( JxlBasicInfo *info )
{
printf( "JxlBasicInfo:\n" );
printf( " have_container = %d\n", info->have_container );
printf( " xsize = %d\n", info->xsize );
printf( " ysize = %d\n", info->ysize );
printf( " bits_per_sample = %d\n", info->bits_per_sample );
printf( " exponent_bits_per_sample = %d\n",
info->exponent_bits_per_sample );
printf( " intensity_target = %g\n", info->intensity_target );
printf( " min_nits = %g\n", info->min_nits );
printf( " relative_to_max_display = %d\n",
info->relative_to_max_display );
printf( " linear_below = %g\n", info->linear_below );
printf( " uses_original_profile = %d\n",
info->uses_original_profile );
printf( " have_preview = %d\n", info->have_preview );
printf( " have_animation = %d\n", info->have_animation );
printf( " orientation = %d\n", info->orientation );
printf( " num_color_channels = %d\n", info->num_color_channels );
printf( " num_extra_channels = %d\n", info->num_extra_channels );
printf( " alpha_bits = %d\n", info->alpha_bits );
printf( " alpha_exponent_bits = %d\n", info->alpha_exponent_bits );
printf( " alpha_premultiplied = %d\n", info->alpha_premultiplied );
printf( " preview.xsize = %d\n", info->preview.xsize );
printf( " preview.ysize = %d\n", info->preview.ysize );
printf( " animation.tps_numerator = %d\n",
info->animation.tps_numerator );
printf( " animation.tps_denominator = %d\n",
info->animation.tps_denominator );
printf( " animation.num_loops = %d\n", info->animation.num_loops );
printf( " animation.have_timecodes = %d\n",
info->animation.have_timecodes );
}
static void
vips_foreign_load_jxl_print_format( JxlPixelFormat *format )
{
printf( "JxlPixelFormat:\n" );
printf( " data_type = " );
switch( format->data_type ) {
case JXL_TYPE_UINT8:
printf( "JXL_TYPE_UINT8" );
break;
case JXL_TYPE_UINT16:
printf( "JXL_TYPE_UINT16" );
break;
case JXL_TYPE_UINT32:
printf( "JXL_TYPE_UINT32" );
break;
case JXL_TYPE_FLOAT:
printf( "JXL_TYPE_FLOAT" );
break;
default:
printf( "(unknown)" );
break;
}
printf( "\n" );
printf( " num_channels = %d\n", format->num_channels );
printf( " endianness = %d\n", format->endianness );
printf( " align = %zd\n", format->align );
}
#endif /*DEBUG*/ #endif /*DEBUG*/
static JxlDecoderStatus static JxlDecoderStatus
@ -312,44 +377,6 @@ vips_foreign_load_jxl_process( VipsForeignLoadJxl *jxl )
return( status ); return( status );
} }
#ifdef DEBUG
static void
vips_foreign_load_jxl_print_info( VipsForeignLoadJxl *jxl )
{
printf( "vips_foreign_load_jxl_print_info:\n" );
printf( " have_container = %d\n", jxl->info.have_container );
printf( " xsize = %d\n", jxl->info.xsize );
printf( " ysize = %d\n", jxl->info.ysize );
printf( " bits_per_sample = %d\n", jxl->info.bits_per_sample );
printf( " exponent_bits_per_sample = %d\n",
jxl->info.exponent_bits_per_sample );
printf( " intensity_target = %g\n", jxl->info.intensity_target );
printf( " min_nits = %g\n", jxl->info.min_nits );
printf( " relative_to_max_display = %d\n",
jxl->info.relative_to_max_display );
printf( " linear_below = %g\n", jxl->info.linear_below );
printf( " uses_original_profile = %d\n",
jxl->info.uses_original_profile );
printf( " have_preview = %d\n", jxl->info.have_preview );
printf( " have_animation = %d\n", jxl->info.have_animation );
printf( " orientation = %d\n", jxl->info.orientation );
printf( " num_color_channels = %d\n", jxl->info.num_color_channels );
printf( " num_extra_channels = %d\n", jxl->info.num_extra_channels );
printf( " alpha_bits = %d\n", jxl->info.alpha_bits );
printf( " alpha_exponent_bits = %d\n", jxl->info.alpha_exponent_bits );
printf( " alpha_premultiplied = %d\n", jxl->info.alpha_premultiplied );
printf( " preview.xsize = %d\n", jxl->info.preview.xsize );
printf( " preview.ysize = %d\n", jxl->info.preview.ysize );
printf( " animation.tps_numerator = %d\n",
jxl->info.animation.tps_numerator );
printf( " animation.tps_denominator = %d\n",
jxl->info.animation.tps_denominator );
printf( " animation.num_loops = %d\n", jxl->info.animation.num_loops );
printf( " animation.have_timecodes = %d\n",
jxl->info.animation.have_timecodes );
}
#endif /*DEBUG*/
static int static int
vips_foreign_load_jxl_set_header( VipsForeignLoadJxl *jxl, VipsImage *out ) vips_foreign_load_jxl_set_header( VipsForeignLoadJxl *jxl, VipsImage *out )
{ {
@ -479,7 +506,7 @@ vips_foreign_load_jxl_header( VipsForeignLoad *load )
return( -1 ); return( -1 );
} }
#ifdef DEBUG #ifdef DEBUG
vips_foreign_load_jxl_print_info( jxl ); vips_foreign_load_jxl_print_info( &jxl->info );
#endif /*DEBUG*/ #endif /*DEBUG*/
/* Pick a pixel format to decode to. /* Pick a pixel format to decode to.
@ -499,6 +526,10 @@ vips_foreign_load_jxl_header( VipsForeignLoad *load )
jxl->format.endianness = JXL_NATIVE_ENDIAN; jxl->format.endianness = JXL_NATIVE_ENDIAN;
jxl->format.align = 0; jxl->format.align = 0;
#ifdef DEBUG
vips_foreign_load_jxl_print_format( &jxl->format );
#endif /*DEBUG*/
break; break;
case JXL_DEC_COLOR_ENCODING: case JXL_DEC_COLOR_ENCODING:

View File

@ -135,18 +135,35 @@ static void
vips_foreign_save_jxl_print_info( JxlBasicInfo *info ) vips_foreign_save_jxl_print_info( JxlBasicInfo *info )
{ {
printf( "JxlBasicInfo:\n" ); printf( "JxlBasicInfo:\n" );
printf( " xsize = %d\n", info->xsize ); printf( " have_container = %d\n", info->have_container );
printf( " ysize = %d\n", info->ysize ); printf( " xsize = %d\n", info->xsize );
printf( " num_color_channels = %d\n", info->num_color_channels ); printf( " ysize = %d\n", info->ysize );
printf( " num_extra_channels = %d\n", info->num_extra_channels ); printf( " bits_per_sample = %d\n", info->bits_per_sample );
printf( " bits_per_sample = %d\n", info->bits_per_sample ); printf( " exponent_bits_per_sample = %d\n",
printf( " exponent_bits_per_sample = %d\n",
info->exponent_bits_per_sample ); info->exponent_bits_per_sample );
printf( " alpha_bits = %d\n", info->alpha_bits ); printf( " intensity_target = %g\n", info->intensity_target );
printf( " alpha_exponent_bits = %d\n", info->alpha_exponent_bits ); printf( " min_nits = %g\n", info->min_nits );
printf( " intensity_target = %g\n", info->intensity_target ); printf( " relative_to_max_display = %d\n",
printf( " uses_original_profile = %d\n", info->relative_to_max_display );
info->uses_original_profile ); printf( " linear_below = %g\n", info->linear_below );
printf( " uses_original_profile = %d\n", info->uses_original_profile );
printf( " have_preview = %d\n", info->have_preview );
printf( " have_animation = %d\n", info->have_animation );
printf( " orientation = %d\n", info->orientation );
printf( " num_color_channels = %d\n", info->num_color_channels );
printf( " num_extra_channels = %d\n", info->num_extra_channels );
printf( " alpha_bits = %d\n", info->alpha_bits );
printf( " alpha_exponent_bits = %d\n", info->alpha_exponent_bits );
printf( " alpha_premultiplied = %d\n", info->alpha_premultiplied );
printf( " preview.xsize = %d\n", info->preview.xsize );
printf( " preview.ysize = %d\n", info->preview.ysize );
printf( " animation.tps_numerator = %d\n",
info->animation.tps_numerator );
printf( " animation.tps_denominator = %d\n",
info->animation.tps_denominator );
printf( " animation.num_loops = %d\n", info->animation.num_loops );
printf( " animation.have_timecodes = %d\n",
info->animation.have_timecodes );
} }
static void static void

View File

@ -79,34 +79,17 @@ gif_initialise_sprite(gif_animation *gif,
unsigned int width, unsigned int width,
unsigned int height) unsigned int height)
{ {
unsigned int max_width; /* Already allocated? */
unsigned int max_height; if (gif->frame_image) {
struct bitmap *buffer;
/* Check if we've changed */
if ((width <= gif->width) && (height <= gif->height)) {
return GIF_OK; return GIF_OK;
} }
/* Get our maximum values */
max_width = (width > gif->width) ? width : gif->width;
max_height = (height > gif->height) ? height : gif->height;
/* Allocate some more memory */
assert(gif->bitmap_callbacks.bitmap_create); assert(gif->bitmap_callbacks.bitmap_create);
buffer = gif->bitmap_callbacks.bitmap_create(max_width, max_height); gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
if (buffer == NULL) { if (gif->frame_image == NULL) {
return GIF_INSUFFICIENT_MEMORY; return GIF_INSUFFICIENT_MEMORY;
} }
assert(gif->bitmap_callbacks.bitmap_destroy);
gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
gif->frame_image = buffer;
gif->width = max_width;
gif->height = max_height;
/* Invalidate our currently decoded image */
gif->decoded_frame = GIF_INVALID_FRAME;
return GIF_OK; return GIF_OK;
} }
@ -392,10 +375,12 @@ static gif_result gif_initialise_frame(gif_animation *gif)
gif->frames[frame].redraw_required = ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) || gif->frames[frame].redraw_required = ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
(gif->frames[frame].disposal_method == GIF_FRAME_RESTORE)); (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
/* Boundary checking - shouldn't ever happen except with junk data */ /* Frame size may have grown.
if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height))) { */
return GIF_INSUFFICIENT_MEMORY; gif->width = (offset_x + width > gif->width) ?
} offset_x + width : gif->width;
gif->height = (offset_y + height > gif->height) ?
offset_y + height : gif->height;
/* Decode the flags */ /* Decode the flags */
flags = gif_data[9]; flags = gif_data[9];
@ -739,6 +724,12 @@ gif_internal_decode_frame(gif_animation *gif,
goto gif_decode_frame_exit; goto gif_decode_frame_exit;
} }
/* Make sure we have a buffer to decode to.
*/
if (gif_initialise_sprite(gif, gif->width, gif->height)) {
return GIF_INSUFFICIENT_MEMORY;
}
/* Decode the flags */ /* Decode the flags */
flags = gif_data[9]; flags = gif_data[9];
colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK); colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
@ -1115,14 +1106,6 @@ gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data)
} }
gif->frame_holders = 1; gif->frame_holders = 1;
/* Initialise the bitmap header */
assert(gif->bitmap_callbacks.bitmap_create);
gif->frame_image = gif->bitmap_callbacks.bitmap_create(gif->width, gif->height);
if (gif->frame_image == NULL) {
gif_finalise(gif);
return GIF_INSUFFICIENT_MEMORY;
}
/* Remember we've done this now */ /* Remember we've done this now */
gif->buffer_position = gif_data - gif->gif_data; gif->buffer_position = gif_data - gif->gif_data;
} }

View File

@ -0,0 +1,86 @@
--- libnsgif-orig.c 2021-04-03 12:23:43.700260070 +0100
+++ libnsgif.c 2021-04-03 12:24:44.079567702 +0100
@@ -79,34 +79,17 @@
unsigned int width,
unsigned int height)
{
- unsigned int max_width;
- unsigned int max_height;
- struct bitmap *buffer;
-
- /* Check if we've changed */
- if ((width <= gif->width) && (height <= gif->height)) {
+ /* Already allocated? */
+ if (gif->frame_image) {
return GIF_OK;
}
- /* Get our maximum values */
- max_width = (width > gif->width) ? width : gif->width;
- max_height = (height > gif->height) ? height : gif->height;
-
- /* Allocate some more memory */
assert(gif->bitmap_callbacks.bitmap_create);
- buffer = gif->bitmap_callbacks.bitmap_create(max_width, max_height);
- if (buffer == NULL) {
+ gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+ if (gif->frame_image == NULL) {
return GIF_INSUFFICIENT_MEMORY;
}
- assert(gif->bitmap_callbacks.bitmap_destroy);
- gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
- gif->frame_image = buffer;
- gif->width = max_width;
- gif->height = max_height;
-
- /* Invalidate our currently decoded image */
- gif->decoded_frame = GIF_INVALID_FRAME;
return GIF_OK;
}
@@ -392,10 +375,12 @@
gif->frames[frame].redraw_required = ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
(gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
- /* Boundary checking - shouldn't ever happen except with junk data */
- if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height))) {
- return GIF_INSUFFICIENT_MEMORY;
- }
+ /* Frame size may have grown.
+ */
+ gif->width = (offset_x + width > gif->width) ?
+ offset_x + width : gif->width;
+ gif->height = (offset_y + height > gif->height) ?
+ offset_y + height : gif->height;
/* Decode the flags */
flags = gif_data[9];
@@ -739,6 +724,12 @@
goto gif_decode_frame_exit;
}
+ /* Make sure we have a buffer to decode to.
+ */
+ if (gif_initialise_sprite(gif, gif->width, gif->height)) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
/* Decode the flags */
flags = gif_data[9];
colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
@@ -1115,14 +1106,6 @@
}
gif->frame_holders = 1;
- /* Initialise the bitmap header */
- assert(gif->bitmap_callbacks.bitmap_create);
- gif->frame_image = gif->bitmap_callbacks.bitmap_create(gif->width, gif->height);
- if (gif->frame_image == NULL) {
- gif_finalise(gif);
- return GIF_INSUFFICIENT_MEMORY;
- }
-
/* Remember we've done this now */
gif->buffer_position = gif_data - gif->gif_data;
}

View File

@ -534,17 +534,19 @@ vips_foreign_load_nsgif_class_init( VipsForeignLoadNsgifClass *class )
static void * static void *
vips_foreign_load_nsgif_bitmap_create( int width, int height ) vips_foreign_load_nsgif_bitmap_create( int width, int height )
{ {
/* Check GIF dimensions fit within 16-bit unsigned. /* Enforce max GIF dimensions of 16383 (0x7FFF). This should be enough
* for anyone, and will prevent the worst GIF bombs.
*/ */
if( width <= 0 || if( width <= 0 ||
width > 65535 || width > 16383 ||
height <= 0 || height <= 0 ||
height > 65535 ) { height > 16383 ) {
vips_error( "gifload", vips_error( "gifload",
"%s", _( "dimensions out of range ") ); "%s", _( "bad image dimensions") );
return( NULL ); return( NULL );
} }
return g_malloc0( width * height * 4 );
return g_malloc0( (gsize) width * height * 4 );
} }
static void static void

View File

@ -115,7 +115,7 @@ G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveTiff, vips_foreign_save_tiff,
#define UC VIPS_FORMAT_UCHAR #define UC VIPS_FORMAT_UCHAR
/* Type promotion for save ... just always go to uchar. /* Type promotion for jpeg-in-tiff save ... just always go to uchar.
*/ */
static int bandfmt_jpeg[10] = { static int bandfmt_jpeg[10] = {
/* UC C US S UI I F X D DX */ /* UC C US S UI I F X D DX */

View File

@ -2,7 +2,6 @@ cplusplus/include/vips/VConnection8.h
cplusplus/include/vips/VError8.h cplusplus/include/vips/VError8.h
cplusplus/include/vips/VImage8.h cplusplus/include/vips/VImage8.h
cplusplus/include/vips/VInterpolate8.h cplusplus/include/vips/VInterpolate8.h
cplusplus/include/vips/vips-operators.h
libvips/include/vips/arithmetic.h libvips/include/vips/arithmetic.h
libvips/include/vips/basic.h libvips/include/vips/basic.h
libvips/include/vips/buf.h libvips/include/vips/buf.h