Merge branch 'master' of github.com:libvips/libvips
This commit is contained in:
commit
c13d651f1c
10
ChangeLog
10
ChangeLog
@ -5,6 +5,15 @@
|
||||
- add VipsInterpolate and guint64 support to C++ API
|
||||
- add VImage::new_from_memory_steal [Zeranoe]
|
||||
- vipsthumbnail supports stdin / stdout thumbnailing
|
||||
- have a lock just for pdfium [DarthSim]
|
||||
- better GraphicsMagick image write [bfriesen]
|
||||
- get pdfium load building again [Projkt-James]
|
||||
- add _source load support for pdfium
|
||||
|
||||
18/10/20 started 8.10.3
|
||||
- relax heic is_a rules [hisham]
|
||||
- fix vips7 webp load [barryspearce]
|
||||
- fix out of bounds exif read in heifload
|
||||
|
||||
6/9/20 started 8.10.2
|
||||
- update magicksave/load profile handling [kelilevi]
|
||||
@ -22,6 +31,7 @@
|
||||
- improve seek behaviour on pipes
|
||||
- add "speed" param to heifsave [lovell]
|
||||
- fix regression in C path for dilate / erode [kleisauke]
|
||||
- fix build with libheif save but no load [estepnv]
|
||||
|
||||
9/8/20 started 8.10.1
|
||||
- fix markdown -> xml conversion in doc generation
|
||||
|
61
configure.ac
61
configure.ac
@ -913,18 +913,20 @@ fi
|
||||
AC_ARG_WITH([pdfium],
|
||||
AS_HELP_STRING([--without-pdfium], [build without pdfium (default: test)]))
|
||||
|
||||
# pick 4200 as the starting version number ... no reason, really, it'd
|
||||
# probably work with much older versions
|
||||
if test x"$with_pdfium" != x"no"; then
|
||||
FIND_PDFIUM([
|
||||
if test x"$with_poppler" != x"no"; then
|
||||
AC_MSG_WARN([PDFium found, disabling poppler])
|
||||
with_poppler=no
|
||||
fi
|
||||
EXTRA_LIBS_USED="$EXTRA_LIBS_USED $PDFIUM_LIBS"
|
||||
with_pdfium=yes
|
||||
],[
|
||||
with_pdfium=no
|
||||
]
|
||||
)
|
||||
PKG_CHECK_MODULES(PDFIUM, pdfium >= 4200, [
|
||||
AC_DEFINE(HAVE_PDFIUM,1,[define if you have pdfium > 4200.])
|
||||
if test x"$with_poppler" != x"no"; then
|
||||
AC_MSG_WARN([PDFium found, disabling poppler])
|
||||
with_poppler=no
|
||||
fi
|
||||
with_pdfium=yes
|
||||
PACKAGES_USED="$PACKAGES_USED pdfium"
|
||||
], [
|
||||
with_pdfium=no
|
||||
])
|
||||
fi
|
||||
|
||||
# poppler
|
||||
@ -932,15 +934,14 @@ AC_ARG_WITH([poppler],
|
||||
AS_HELP_STRING([--without-poppler], [build without poppler (default: test)]))
|
||||
|
||||
if test x"$with_poppler" != x"no"; then
|
||||
PKG_CHECK_MODULES(POPPLER, [poppler-glib >= 0.16.0 cairo >= 1.2],
|
||||
[AC_DEFINE(HAVE_POPPLER,1,[define if you have poppler-glib >= 0.16.0 and cairo >= 1.2 installed.])
|
||||
with_poppler=yes
|
||||
PACKAGES_USED="$PACKAGES_USED poppler-glib cairo"
|
||||
],
|
||||
[AC_MSG_WARN([poppler-glib >= 0.16.0 or cairo >= 1.2 not found; disabling PDF load via poppler])
|
||||
with_poppler=no
|
||||
]
|
||||
)
|
||||
PKG_CHECK_MODULES(POPPLER, [poppler-glib >= 0.16.0 cairo >= 1.2], [
|
||||
AC_DEFINE(HAVE_POPPLER,1,[define if you have poppler-glib >= 0.16.0 and cairo >= 1.2 installed.])
|
||||
with_poppler=yes
|
||||
PACKAGES_USED="$PACKAGES_USED poppler-glib cairo"
|
||||
], [
|
||||
AC_MSG_WARN([poppler-glib >= 0.16.0 or cairo >= 1.2 not found; disabling PDF load via poppler])
|
||||
with_poppler=no
|
||||
])
|
||||
fi
|
||||
|
||||
# librsvg
|
||||
@ -949,15 +950,14 @@ AC_ARG_WITH([rsvg],
|
||||
|
||||
# 2.40.3 so we get the UNLIMITED open flag
|
||||
if test x"$with_rsvg" != x"no"; then
|
||||
PKG_CHECK_MODULES(RSVG, [librsvg-2.0 >= 2.40.3 cairo >= 1.2],
|
||||
[AC_DEFINE(HAVE_RSVG,1,[define if you have librsvg-2.0 >= 2.40.3 and cairo >= 1.2 installed.])
|
||||
with_rsvg=yes
|
||||
PACKAGES_USED="$PACKAGES_USED librsvg-2.0 cairo"
|
||||
],
|
||||
[AC_MSG_WARN([librsvg-2.0 >= 2.40.3 or cairo >= 1.2 not found; disabling SVG load via rsvg])
|
||||
with_rsvg=no
|
||||
]
|
||||
)
|
||||
PKG_CHECK_MODULES(RSVG, [librsvg-2.0 >= 2.40.3 cairo >= 1.2], [
|
||||
AC_DEFINE(HAVE_RSVG,1,[define if you have librsvg-2.0 >= 2.40.3 and cairo >= 1.2 installed.])
|
||||
with_rsvg=yes
|
||||
PACKAGES_USED="$PACKAGES_USED librsvg-2.0 cairo"
|
||||
], [
|
||||
AC_MSG_WARN([librsvg-2.0 >= 2.40.3 or cairo >= 1.2 not found; disabling SVG load via rsvg])
|
||||
with_rsvg=no
|
||||
])
|
||||
fi
|
||||
|
||||
# zlib
|
||||
@ -1286,8 +1286,7 @@ if test x"$LIB_FUZZING_ENGINE" = x; then
|
||||
fi
|
||||
|
||||
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
|
||||
VIPS_CFLAGS="$VIPS_CFLAGS $GTHREAD_CFLAGS $GIO_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $SPNG_CFLAGS $PNG_CFLAGS $IMAGEQUANT_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $LIBWEBPMUX_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $PDFIUM_INCLUDES $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS $HEIF_CFLAGS"
|
||||
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
||||
VIPS_CFLAGS="$VIPS_CFLAGS $GTHREAD_CFLAGS $GIO_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $SPNG_CFLAGS $PNG_CFLAGS $IMAGEQUANT_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $LIBWEBPMUX_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $PDFIUM_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS $HEIF_CFLAGS" VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
||||
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES $NIFTI_INCLUDES"
|
||||
VIPS_LIBS="$ZLIB_LIBS $HEIF_LIBS $MAGICK_LIBS $SPNG_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $GIO_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $NIFTI_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
* 10/5/20
|
||||
* - handle mirrored images
|
||||
* - deprecate vips_autorot_get_angle()
|
||||
* 24/10/20
|
||||
* - only remove main image orientation, since we don't rotate the
|
||||
* embedded thumbnail
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -69,8 +72,7 @@ static void *
|
||||
vips_autorot_remove_angle_sub( VipsImage *image,
|
||||
const char *field, GValue *value, void *my_data )
|
||||
{
|
||||
if( vips_isprefix( "exif-", field ) &&
|
||||
vips_ispostfix( field, "-Orientation" ) ) {
|
||||
if( strcmp( field, "exif-ifd0-Orientation" ) == 0 ) {
|
||||
#ifdef DEBUG
|
||||
printf( "vips_autorot_remove_angle: %s\n", field );
|
||||
#endif /*DEBUG*/
|
||||
|
@ -35,32 +35,59 @@
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
/* Convert from ARGB to RGBA and undo premultiplication.
|
||||
/* Convert from Cairo-style premultiplied BGRA to RGBA.
|
||||
*
|
||||
* See also openslide's argb2rgba().
|
||||
*/
|
||||
void
|
||||
vips__cairo2rgba( guint32 * restrict buf, int n )
|
||||
vips__premultiplied_bgra2rgba( guint32 * restrict p, int n )
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
|
||||
for( i = 0; i < n; i++ ) {
|
||||
guint32 * restrict p = buf + i;
|
||||
guint32 x = *p;
|
||||
guint8 a = x >> 24;
|
||||
VipsPel * restrict out = (VipsPel *) p;
|
||||
for( x = 0; x < n; x++ ) {
|
||||
guint32 bgra = GUINT32_FROM_BE( p[x] );
|
||||
guint8 a = bgra & 0xff;
|
||||
|
||||
if( a == 255 )
|
||||
*p = GUINT32_TO_BE( (x << 8) | 255 );
|
||||
else if( a == 0 )
|
||||
*p = GUINT32_TO_BE( x << 8 );
|
||||
else {
|
||||
/* Undo premultiplication.
|
||||
*/
|
||||
out[0] = 255 * ((x >> 16) & 255) / a;
|
||||
out[1] = 255 * ((x >> 8) & 255) / a;
|
||||
out[2] = 255 * (x & 255) / a;
|
||||
out[3] = a;
|
||||
}
|
||||
guint32 rgba;
|
||||
|
||||
if( a == 0 ||
|
||||
a == 255 )
|
||||
rgba =
|
||||
(bgra & 0x00ff00ff) |
|
||||
(bgra & 0x0000ff00) << 16 |
|
||||
(bgra & 0xff000000) >> 16;
|
||||
else
|
||||
/* Undo premultiplication.
|
||||
*/
|
||||
rgba =
|
||||
((255 * ((bgra >> 8) & 0xff) / a) << 24) |
|
||||
((255 * ((bgra >> 16) & 0xff) / a) << 16) |
|
||||
((255 * ((bgra >> 24) & 0xff) / a) << 8) |
|
||||
a;
|
||||
|
||||
p[x] = GUINT32_TO_BE( rgba );
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert from PDFium-style BGRA to RGBA.
|
||||
*/
|
||||
void
|
||||
vips__bgra2rgba( guint32 * restrict p, int n )
|
||||
{
|
||||
int x;
|
||||
|
||||
for( x = 0; x < n; x++ ) {
|
||||
guint32 bgra = GUINT32_FROM_BE( p[x] );
|
||||
|
||||
guint rgba;
|
||||
|
||||
/* Leave G and A, swap R and B.
|
||||
*/
|
||||
rgba =
|
||||
(bgra & 0x00ff00ff) |
|
||||
(bgra & 0x0000ff00) << 16 |
|
||||
(bgra & 0xff000000) >> 16;
|
||||
|
||||
p[x] = GUINT32_TO_BE( rgba );
|
||||
}
|
||||
}
|
||||
|
@ -158,10 +158,18 @@ show_values( ExifData *data )
|
||||
* their default value and we won't know about it.
|
||||
*/
|
||||
static ExifData *
|
||||
vips_exif_load_data_without_fix( const void *data, int length )
|
||||
vips_exif_load_data_without_fix( const void *data, size_t length )
|
||||
{
|
||||
ExifData *ed;
|
||||
|
||||
/* exif_data_load_data() only allows uint for length. Limit it to less
|
||||
* than that: 2**20 should be enough for anyone.
|
||||
*/
|
||||
if( length > 1 << 20 ) {
|
||||
vips_error( "exif", "%s", _( "exif too large" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
if( !(ed = exif_data_new()) ) {
|
||||
vips_error( "exif", "%s", _( "unable to init exif" ) );
|
||||
return( NULL );
|
||||
|
@ -2174,7 +2174,7 @@ vips_foreign_operation_init( void )
|
||||
vips_foreign_save_rad_target_get_type();
|
||||
#endif /*HAVE_RADIANCE*/
|
||||
|
||||
#if defined(HAVE_POPPLER)
|
||||
#ifdef HAVE_POPPLER
|
||||
vips_foreign_load_pdf_file_get_type();
|
||||
vips_foreign_load_pdf_buffer_get_type();
|
||||
vips_foreign_load_pdf_source_get_type();
|
||||
@ -2183,6 +2183,7 @@ vips_foreign_operation_init( void )
|
||||
#ifdef HAVE_PDFIUM
|
||||
vips_foreign_load_pdf_file_get_type();
|
||||
vips_foreign_load_pdf_buffer_get_type();
|
||||
vips_foreign_load_pdf_source_get_type();
|
||||
#endif /*HAVE_PDFIUM*/
|
||||
|
||||
#ifdef HAVE_RSVG
|
||||
|
@ -68,12 +68,33 @@
|
||||
#include <vips/debug.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#ifdef HAVE_HEIF_DECODER
|
||||
/* These are shared with the encoder.
|
||||
*/
|
||||
#if defined(HAVE_HEIF_DECODER) || defined(HAVE_HEIF_ENCODER)
|
||||
|
||||
#include <libheif/heif.h>
|
||||
|
||||
#include "pforeign.h"
|
||||
|
||||
void
|
||||
vips__heif_error( struct heif_error *error )
|
||||
{
|
||||
if( error->code )
|
||||
vips_error( "heif", "%s (%d.%d)", error->message, error->code,
|
||||
error->subcode );
|
||||
}
|
||||
|
||||
const char *vips__heif_suffs[] = {
|
||||
".heic",
|
||||
".heif",
|
||||
".avif",
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /*defined(DECODE) || defined(ENCODE)*/
|
||||
|
||||
#ifdef HAVE_HEIF_DECODER
|
||||
|
||||
#define VIPS_TYPE_FOREIGN_LOAD_HEIF (vips_foreign_load_heif_get_type())
|
||||
#define VIPS_FOREIGN_LOAD_HEIF( obj ) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
|
||||
@ -200,14 +221,6 @@ vips_foreign_load_heif_dispose( GObject *gobject )
|
||||
dispose( gobject );
|
||||
}
|
||||
|
||||
void
|
||||
vips__heif_error( struct heif_error *error )
|
||||
{
|
||||
if( error->code )
|
||||
vips_error( "heif", "%s (%d.%d)", error->message, error->code,
|
||||
error->subcode );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_heif_build( VipsObject *object )
|
||||
{
|
||||
@ -258,7 +271,7 @@ static const char *heif_magic[] = {
|
||||
*
|
||||
* enum heif_filetype_result result = heif_check_filetype( buf, 12 );
|
||||
*
|
||||
* but it's very conservative and seems to be missing some of the Nokia hief
|
||||
* but it's very conservative and seems to be missing some of the Nokia heif
|
||||
* types.
|
||||
*/
|
||||
static int
|
||||
@ -269,7 +282,10 @@ vips_foreign_load_heif_is_a( const char *buf, int len )
|
||||
|
||||
int i;
|
||||
|
||||
if( chunk_len > 32 ||
|
||||
/* We've seen real files with 36 here, so 64 should be
|
||||
* plenty.
|
||||
*/
|
||||
if( chunk_len > 64 ||
|
||||
chunk_len % 4 != 0 )
|
||||
return( 0 );
|
||||
|
||||
@ -449,7 +465,7 @@ vips_foreign_load_heif_set_header( VipsForeignLoadHeif *heif, VipsImage *out )
|
||||
char name[256];
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "metadata type = %s, length = %zd\n", type, length );
|
||||
printf( "metadata type = %s, length = %zu\n", type, length );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !(data = VIPS_ARRAY( out, length, unsigned char )) )
|
||||
@ -464,7 +480,8 @@ vips_foreign_load_heif_set_header( VipsForeignLoadHeif *heif, VipsImage *out )
|
||||
/* We need to skip the first four bytes of EXIF, they just
|
||||
* contain the offset.
|
||||
*/
|
||||
if( g_ascii_strcasecmp( type, "exif" ) == 0 ) {
|
||||
if( length > 4 &&
|
||||
g_ascii_strcasecmp( type, "exif" ) == 0 ) {
|
||||
data += 4;
|
||||
length -= 4;
|
||||
}
|
||||
@ -477,6 +494,7 @@ vips_foreign_load_heif_set_header( VipsForeignLoadHeif *heif, VipsImage *out )
|
||||
if( g_ascii_strcasecmp( type, "exif" ) == 0 )
|
||||
vips_snprintf( name, 256, VIPS_META_EXIF_NAME );
|
||||
else if( g_ascii_strcasecmp( type, "mime" ) == 0 &&
|
||||
length > 10 &&
|
||||
vips_isprefix( "<x:xmpmeta", (const char *) data ) )
|
||||
vips_snprintf( name, 256, VIPS_META_XMP_NAME );
|
||||
else
|
||||
@ -1079,13 +1097,6 @@ vips_foreign_load_heif_file_is_a( const char *filename )
|
||||
return( vips_foreign_load_heif_is_a( buf, 12 ) );
|
||||
}
|
||||
|
||||
const char *vips__heif_suffs[] = {
|
||||
".heic",
|
||||
".heif",
|
||||
".avif",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
vips_foreign_load_heif_file_class_init( VipsForeignLoadHeifFileClass *class )
|
||||
{
|
||||
|
@ -4,6 +4,8 @@
|
||||
*
|
||||
* 24/7/18
|
||||
* - add the sniffer
|
||||
* 16/10/20 [bfriesen]
|
||||
* - set matte and depth appropriately for GM in magick_import_pixels()
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -319,6 +321,7 @@ magick_import_pixels( Image *image, const ssize_t x, const ssize_t y,
|
||||
type, pixels ) );
|
||||
#else /*!HAVE_IMPORTIMAGEPIXELS*/
|
||||
Image *constitute_image;
|
||||
unsigned int storage_type_depth;
|
||||
|
||||
g_assert( image );
|
||||
g_assert( image->signature == MagickSignature );
|
||||
@ -328,7 +331,43 @@ magick_import_pixels( Image *image, const ssize_t x, const ssize_t y,
|
||||
if( !constitute_image )
|
||||
return( MagickFalse );
|
||||
|
||||
/* image needs to inherit these fields from constitute_image.
|
||||
*/
|
||||
switch( type ) {
|
||||
case CharPixel:
|
||||
storage_type_depth = sizeof( unsigned char ) * 8;
|
||||
break;
|
||||
|
||||
case ShortPixel:
|
||||
storage_type_depth = sizeof( unsigned short ) * 8;
|
||||
break;
|
||||
|
||||
case IntegerPixel:
|
||||
storage_type_depth = sizeof( unsigned short ) * 8;
|
||||
break;
|
||||
|
||||
case LongPixel:
|
||||
storage_type_depth = sizeof( unsigned long ) * 8;
|
||||
break;
|
||||
|
||||
case FloatPixel:
|
||||
storage_type_depth = sizeof( float ) * 8;
|
||||
break;
|
||||
|
||||
case DoublePixel:
|
||||
storage_type_depth = sizeof( double ) * 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
storage_type_depth = QuantumDepth;
|
||||
break;
|
||||
|
||||
}
|
||||
image->depth = VIPS_MIN( storage_type_depth, QuantumDepth );
|
||||
image->matte = constitute_image->matte;
|
||||
|
||||
(void) CompositeImage( image, CopyCompositeOp, constitute_image, x, y );
|
||||
|
||||
DestroyImage( constitute_image );
|
||||
|
||||
return( image->exception.severity == UndefinedException );
|
||||
|
@ -8,6 +8,10 @@
|
||||
* - shut down the input file as soon as we can [kleisauke]
|
||||
* 8/8/19
|
||||
* - add locks, since pdfium is not threadsafe in any way
|
||||
* 13/10/20
|
||||
* - have a lock just for pdfium [DarthSim]
|
||||
* - update for current pdfium
|
||||
* - add _source input
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -39,12 +43,41 @@
|
||||
|
||||
/* TODO
|
||||
*
|
||||
* - needs the reopen-after-minimise system that pdfload has, but we'll need
|
||||
* to be able to actually build and test this before we can do that
|
||||
* - what about filename encodings
|
||||
* - what about filename encodings?
|
||||
* - need to test on Windows
|
||||
*/
|
||||
|
||||
/* How to build against PDFium:
|
||||
*
|
||||
* Download the prebuilt binary from:
|
||||
*
|
||||
* https://github.com/bblanchon/pdfium-binaries
|
||||
*
|
||||
* Untar to the libvips install prefix, for example:
|
||||
*
|
||||
* cd ~/vips
|
||||
* tar xf ~/pdfium-linux.tgz
|
||||
*
|
||||
* Create a pdfium.pc like this (update the version number):
|
||||
*
|
||||
|
||||
VIPSHOME=/home/john/vips
|
||||
cat > $VIPSHOME/lib/pkgconfig/pdfium.pc << EOF
|
||||
prefix=$VIPSHOME
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${exec_prefix}/lib
|
||||
includedir=\${prefix}/include
|
||||
Name: pdfium
|
||||
Description: pdfium
|
||||
Version: 4290
|
||||
Requires:
|
||||
Libs: -L\${libdir} -lpdfium
|
||||
Cflags: -I\${includedir}
|
||||
EOF
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
*/
|
||||
@ -73,6 +106,10 @@
|
||||
typedef struct _VipsForeignLoadPdf {
|
||||
VipsForeignLoad parent_object;
|
||||
|
||||
/* Set by subclasses.
|
||||
*/
|
||||
VipsSource *source;
|
||||
|
||||
/* Load this page.
|
||||
*/
|
||||
int page_no;
|
||||
@ -93,8 +130,9 @@ typedef struct _VipsForeignLoadPdf {
|
||||
*/
|
||||
VipsArrayDouble *background;
|
||||
|
||||
FPDF_DOCUMENT *doc;
|
||||
FPDF_PAGE *page;
|
||||
FPDF_FILEACCESS file_access;
|
||||
FPDF_DOCUMENT doc;
|
||||
FPDF_PAGE page;
|
||||
int current_page;
|
||||
|
||||
/* Doc has this many pages.
|
||||
@ -128,6 +166,8 @@ static char *vips_pdfium_errors[] = {
|
||||
"page not found or content error"
|
||||
};
|
||||
|
||||
static GMutex *vips_pdfium_mutex = NULL;
|
||||
|
||||
static void
|
||||
vips_pdfium_error( void )
|
||||
{
|
||||
@ -143,12 +183,12 @@ vips_pdfium_error( void )
|
||||
static void
|
||||
vips_foreign_load_pdf_close( VipsForeignLoadPdf *pdf )
|
||||
{
|
||||
g_mutex_lock( vips__global_lock );
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
|
||||
VIPS_FREEF( FPDF_ClosePage, pdf->page );
|
||||
VIPS_FREEF( FPDF_CloseDocument, pdf->doc );
|
||||
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -177,18 +217,82 @@ vips_pdfium_init_cb( void *dummy )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* This is the m_GetBlock function for FPDF_FILEACCESS.
|
||||
*/
|
||||
static gboolean
|
||||
vips_pdfium_GetBlock( void *param,
|
||||
unsigned long position, unsigned char *pBuf, unsigned long size )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) param;
|
||||
|
||||
/* PDFium guarantees these.
|
||||
*/
|
||||
g_assert( size > 0 );
|
||||
g_assert( position >= 0 );
|
||||
g_assert( position + size <= pdf->file_access.m_FileLen );
|
||||
|
||||
if( vips_source_seek( pdf->source, position, SEEK_SET ) < 0 )
|
||||
return( FALSE );
|
||||
|
||||
while( size > 0 ) {
|
||||
size_t n_read;
|
||||
|
||||
if( (n_read = vips_source_read( pdf->source, pBuf, size )) < 0 )
|
||||
return( FALSE );
|
||||
pBuf += n_read;
|
||||
size -= n_read;
|
||||
}
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_build( VipsObject *object )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object;
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( pdf );
|
||||
|
||||
gint64 length;
|
||||
|
||||
VIPS_ONCE( &once, vips_pdfium_init_cb, NULL );
|
||||
|
||||
if( !vips_object_argument_isset( object, "scale" ) )
|
||||
pdf->scale = pdf->dpi / 72.0;
|
||||
|
||||
/* pdfium must know the file length, unfortunately.
|
||||
*/
|
||||
if( pdf->source ) {
|
||||
if( (length = vips_source_length( pdf->source )) <= 0 )
|
||||
return( -1 );
|
||||
if( length > 1 << 30 ) {
|
||||
vips_error( class->nickname,
|
||||
_( "%s: too large for pdfium" ),
|
||||
vips_connection_nick(
|
||||
VIPS_CONNECTION( pdf->source ) ) );
|
||||
return( -1 );
|
||||
}
|
||||
pdf->file_access.m_FileLen = length;
|
||||
pdf->file_access.m_GetBlock = vips_pdfium_GetBlock;
|
||||
pdf->file_access.m_Param = pdf;
|
||||
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
|
||||
if( !(pdf->doc = FPDF_LoadCustomDocument( &pdf->file_access,
|
||||
NULL )) ) {
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
vips_pdfium_error();
|
||||
vips_error( "pdfload",
|
||||
_( "%s: unable to load" ),
|
||||
vips_connection_nick(
|
||||
VIPS_CONNECTION( pdf->source ) ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
}
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -217,7 +321,7 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
|
||||
if( pdf->current_page != page_no ) {
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( pdf );
|
||||
|
||||
g_mutex_lock( vips__global_lock );
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
|
||||
VIPS_FREEF( FPDF_ClosePage, pdf->page );
|
||||
pdf->current_page = -1;
|
||||
@ -227,7 +331,7 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !(pdf->page = FPDF_LoadPage( pdf->doc, page_no )) ) {
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
vips_pdfium_error();
|
||||
vips_error( class->nickname,
|
||||
_( "unable to load page %d" ), page_no );
|
||||
@ -235,7 +339,7 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
|
||||
}
|
||||
pdf->current_page = page_no;
|
||||
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@ -278,6 +382,8 @@ vips_foreign_load_pdf_set_image( VipsForeignLoadPdf *pdf, VipsImage *out )
|
||||
vips_image_set_int( out, "pdf-n_pages", pdf->n_pages );
|
||||
vips_image_set_int( out, VIPS_META_N_PAGES, pdf->n_pages );
|
||||
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
|
||||
for( i = 0; i < n_metadata; i++ ) {
|
||||
VipsForeignLoadPdfMetadata *metadata =
|
||||
&vips_foreign_load_pdf_metadata[i];
|
||||
@ -285,9 +391,7 @@ vips_foreign_load_pdf_set_image( VipsForeignLoadPdf *pdf, VipsImage *out )
|
||||
char text[1024];
|
||||
int len;
|
||||
|
||||
g_mutex_lock( vips__global_lock );
|
||||
len = FPDF_GetMetaText( pdf->doc, metadata->tag, text, 1024 );
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
if( len > 0 ) {
|
||||
char *str;
|
||||
|
||||
@ -302,6 +406,8 @@ vips_foreign_load_pdf_set_image( VipsForeignLoadPdf *pdf, VipsImage *out )
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
|
||||
/* We need pixels/mm for vips.
|
||||
*/
|
||||
res = pdf->dpi / 25.4;
|
||||
@ -327,9 +433,9 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
|
||||
printf( "vips_foreign_load_pdf_header: %p\n", pdf );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_mutex_lock( vips__global_lock );
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
pdf->n_pages = FPDF_GetPageCount( pdf->doc );
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
|
||||
/* @n == -1 means until the end of the doc.
|
||||
*/
|
||||
@ -400,10 +506,7 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
|
||||
static void
|
||||
vips_foreign_load_pdf_minimise( VipsObject *object, VipsForeignLoadPdf *pdf )
|
||||
{
|
||||
/* In seq mode, we can shut down the input at the end of computation.
|
||||
*/
|
||||
if( VIPS_FOREIGN_LOAD( pdf )->access == VIPS_ACCESS_SEQUENTIAL )
|
||||
vips_foreign_load_pdf_close( pdf );
|
||||
vips_source_minimise( pdf->source );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -411,7 +514,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) a;
|
||||
VipsForeignLoad *load = (VipsForeignLoad *) pdf;
|
||||
VipsRect *r = &or->valid;
|
||||
|
||||
int top;
|
||||
@ -448,7 +550,7 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
|
||||
/* 4 means RGBA.
|
||||
*/
|
||||
g_mutex_lock( vips__global_lock );
|
||||
g_mutex_lock( vips_pdfium_mutex );
|
||||
|
||||
bitmap = FPDFBitmap_CreateEx( rect.width, rect.height, 4,
|
||||
VIPS_REGION_ADDR( or, rect.left, rect.top ),
|
||||
@ -460,26 +562,18 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
|
||||
FPDFBitmap_Destroy( bitmap );
|
||||
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
g_mutex_unlock( vips_pdfium_mutex );
|
||||
|
||||
top += rect.height;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
/* PDFium writes BRGA, we must swap.
|
||||
*
|
||||
* FIXME ... this is a bit slow.
|
||||
/* PDFium writes BGRA, we must swap.
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
VipsPel *p;
|
||||
int x;
|
||||
|
||||
p = VIPS_REGION_ADDR( or, r->left, r->top + y );
|
||||
for( x = 0; x < r->width; x++ ) {
|
||||
VIPS_SWAP( VipsPel, p[0], p[2] );
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
for( y = 0; y < r->height; y++ )
|
||||
vips__bgra2rgba(
|
||||
(guint32 *) VIPS_REGION_ADDR( or, r->left, r->top + y ),
|
||||
r->width );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -522,24 +616,40 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_foreign_load_pdf_once_init( void *client )
|
||||
{
|
||||
/* We must make the mutex on class init (not _build) since we
|
||||
* can lock ebven if build is not called.
|
||||
*/
|
||||
vips_pdfium_mutex = vips_g_mutex_new();
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_class_init( VipsForeignLoadPdfClass *class )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||
|
||||
VIPS_ONCE( &once, vips_foreign_load_pdf_once_init, NULL );
|
||||
|
||||
gobject_class->dispose = vips_foreign_load_pdf_dispose;
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "pdfload_base";
|
||||
object_class->description = _( "load PDF with libpoppler" );
|
||||
object_class->description = _( "load PDF with PDFium" );
|
||||
object_class->build = vips_foreign_load_pdf_build;
|
||||
|
||||
load_class->get_flags_filename =
|
||||
vips_foreign_load_pdf_get_flags_filename;
|
||||
load_class->get_flags = vips_foreign_load_pdf_get_flags;
|
||||
load_class->header = vips_foreign_load_pdf_header;
|
||||
load_class->load = vips_foreign_load_pdf_load;
|
||||
|
||||
VIPS_ARG_INT( class, "page", 10,
|
||||
@ -606,24 +716,12 @@ G_DEFINE_TYPE( VipsForeignLoadPdfFile, vips_foreign_load_pdf_file,
|
||||
static int
|
||||
vips_foreign_load_pdf_file_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load;
|
||||
VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) load;
|
||||
|
||||
g_mutex_lock( vips__global_lock );
|
||||
|
||||
if( !(pdf->doc = FPDF_LoadDocument( file->filename, NULL )) ) {
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
vips_pdfium_error();
|
||||
vips_error( "pdfload",
|
||||
_( "unable to load \"%s\"" ), file->filename );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
|
||||
VIPS_SETSTR( load->out->filename, file->filename );
|
||||
|
||||
return( vips_foreign_load_pdf_header( load ) );
|
||||
return( VIPS_FOREIGN_LOAD_CLASS(
|
||||
vips_foreign_load_pdf_file_parent_class )->header( load ) );
|
||||
}
|
||||
|
||||
static const char *vips_foreign_pdf_suffs[] = {
|
||||
@ -631,6 +729,24 @@ static const char *vips_foreign_pdf_suffs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_file_build( VipsObject *object )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object;
|
||||
VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) pdf;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_foreign_load_pdf_file_build: %s\n", file->filename );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( file->filename &&
|
||||
!(pdf->source = vips_source_new_from_file( file->filename )) )
|
||||
return( -1 );
|
||||
|
||||
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_file_parent_class )->
|
||||
build( object ) );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_file_class_init(
|
||||
VipsForeignLoadPdfFileClass *class )
|
||||
@ -644,6 +760,8 @@ vips_foreign_load_pdf_file_class_init(
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "pdfload";
|
||||
object_class->description = _( "load PDF from file" );
|
||||
object_class->build = vips_foreign_load_pdf_file_build;
|
||||
|
||||
foreign_class->suffs = vips_foreign_pdf_suffs;
|
||||
|
||||
@ -679,26 +797,19 @@ G_DEFINE_TYPE( VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer,
|
||||
vips_foreign_load_pdf_get_type() );
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_buffer_header( VipsForeignLoad *load )
|
||||
vips_foreign_load_pdf_buffer_build( VipsObject *object )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load;
|
||||
VipsForeignLoadPdfBuffer *buffer =
|
||||
(VipsForeignLoadPdfBuffer *) load;
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object;
|
||||
VipsForeignLoadPdfBuffer *buffer = (VipsForeignLoadPdfBuffer *) pdf;
|
||||
|
||||
g_mutex_lock( vips__global_lock );
|
||||
if( buffer->buf &&
|
||||
!(pdf->source = vips_source_new_from_memory(
|
||||
VIPS_AREA( buffer->buf )->data,
|
||||
VIPS_AREA( buffer->buf )->length )) )
|
||||
return( -1 );
|
||||
|
||||
if( !(pdf->doc = FPDF_LoadMemDocument( buffer->buf->data,
|
||||
buffer->buf->length, NULL )) ) {
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
vips_pdfium_error();
|
||||
vips_error( "pdfload",
|
||||
"%s", _( "unable to load from buffer" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
g_mutex_unlock( vips__global_lock );
|
||||
|
||||
return( vips_foreign_load_pdf_header( load ) );
|
||||
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_buffer_parent_class )->
|
||||
build( object ) );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -713,9 +824,10 @@ vips_foreign_load_pdf_buffer_class_init(
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "pdfload_buffer";
|
||||
object_class->description = _( "load PDF from buffer" );
|
||||
object_class->build = vips_foreign_load_pdf_buffer_build;
|
||||
|
||||
load_class->is_a_buffer = vips_foreign_load_pdf_is_a_buffer;
|
||||
load_class->header = vips_foreign_load_pdf_buffer_header;
|
||||
|
||||
VIPS_ARG_BOXED( class, "buffer", 1,
|
||||
_( "Buffer" ),
|
||||
@ -731,4 +843,74 @@ vips_foreign_load_pdf_buffer_init( VipsForeignLoadPdfBuffer *buffer )
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignLoadPdfSource {
|
||||
VipsForeignLoadPdf parent_object;
|
||||
|
||||
VipsSource *source;
|
||||
|
||||
} VipsForeignLoadPdfSource;
|
||||
|
||||
typedef VipsForeignLoadPdfClass VipsForeignLoadPdfSourceClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsForeignLoadPdfSource, vips_foreign_load_pdf_source,
|
||||
vips_foreign_load_pdf_get_type() );
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_source_build( VipsObject *object )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object;
|
||||
VipsForeignLoadPdfSource *source = (VipsForeignLoadPdfSource *) pdf;
|
||||
|
||||
if( source->source ) {
|
||||
pdf->source = source->source;
|
||||
g_object_ref( pdf->source );
|
||||
}
|
||||
|
||||
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_source_parent_class )->
|
||||
build( object ) );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips_foreign_load_pdf_source_is_a_source( VipsSource *source )
|
||||
{
|
||||
const unsigned char *p;
|
||||
|
||||
return( (p = vips_source_sniff( source, 4 )) &&
|
||||
p[0] == '%' &&
|
||||
p[1] == 'P' &&
|
||||
p[2] == 'D' &&
|
||||
p[3] == 'F' );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_source_class_init(
|
||||
VipsForeignLoadPdfSourceClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "pdfload_source";
|
||||
object_class->description = _( "load PDF from source" );
|
||||
object_class->build = vips_foreign_load_pdf_source_build;
|
||||
|
||||
load_class->is_a_source = vips_foreign_load_pdf_source_is_a_source;
|
||||
|
||||
VIPS_ARG_OBJECT( class, "source", 1,
|
||||
_( "Source" ),
|
||||
_( "Source to load from" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadPdfSource, source ),
|
||||
VIPS_TYPE_SOURCE );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_source_init( VipsForeignLoadPdfSource *source )
|
||||
{
|
||||
}
|
||||
|
||||
#endif /*HAVE_PDFIUM*/
|
||||
|
@ -220,8 +220,7 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
|
||||
printf( "vips_foreign_load_pdf_get_page: %d\n", page_no );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !(pdf->page = poppler_document_get_page( pdf->doc,
|
||||
page_no )) ) {
|
||||
if( !(pdf->page = poppler_document_get_page( pdf->doc, page_no )) ) {
|
||||
vips_error( class->nickname,
|
||||
_( "unable to load page %d" ), page_no );
|
||||
return( -1 );
|
||||
@ -368,7 +367,7 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
|
||||
/* Convert the background to the image format.
|
||||
*
|
||||
* FIXME ... we probably should convert this to pre-multiplied BGRA
|
||||
* to match the Cairo convention. See vips__cairo2rgba().
|
||||
* to match the Cairo convention. See vips__premultiplied_bgra2rgba().
|
||||
*/
|
||||
if( !(pdf->ink = vips__vector_to_ink( class->nickname,
|
||||
load->out,
|
||||
@ -453,7 +452,7 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
/* Cairo makes pre-multipled BRGA, we must byteswap and unpremultiply.
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ )
|
||||
vips__cairo2rgba(
|
||||
vips__premultiplied_bgra2rgba(
|
||||
(guint32 *) VIPS_REGION_ADDR( or, r->left, r->top + y ),
|
||||
r->width );
|
||||
|
||||
|
@ -368,7 +368,7 @@ vips_foreign_load_svg_generate( VipsRegion *or,
|
||||
/* Cairo makes pre-multipled BRGA -- we must byteswap and unpremultiply.
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ )
|
||||
vips__cairo2rgba(
|
||||
vips__premultiplied_bgra2rgba(
|
||||
(guint32 *) VIPS_REGION_ADDR( or, r->left, r->top + y ),
|
||||
r->width );
|
||||
|
||||
|
@ -81,6 +81,7 @@
|
||||
/* What we track during a read.
|
||||
*/
|
||||
typedef struct {
|
||||
VipsImage *out;
|
||||
VipsSource *source;
|
||||
|
||||
/* The data we load, as a webp object.
|
||||
@ -340,14 +341,21 @@ read_free( Read *read )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
read_close_cb( VipsImage *image, Read *read )
|
||||
{
|
||||
read_free( read );
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new( VipsSource *source, int page, int n, double scale )
|
||||
read_new( VipsImage *out, VipsSource *source, int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = VIPS_NEW( NULL, Read )) )
|
||||
return( NULL );
|
||||
|
||||
read->out = out;
|
||||
read->source = source;
|
||||
g_object_ref( source );
|
||||
read->page = page;
|
||||
@ -359,15 +367,19 @@ read_new( VipsSource *source, int page, int n, double scale )
|
||||
read->dispose_method = WEBP_MUX_DISPOSE_NONE;
|
||||
read->frame_no = 0;
|
||||
|
||||
/* Everything has to stay open until read has finished, unfortunately,
|
||||
* since webp relies on us mapping the whole file.
|
||||
*/
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( read_close_cb ), read );
|
||||
|
||||
WebPInitDecoderConfig( &read->config );
|
||||
read->config.options.use_threads = 1;
|
||||
read->config.output.is_external_memory = 1;
|
||||
|
||||
if( !(read->data.bytes =
|
||||
vips_source_map( source, &read->data.size )) ) {
|
||||
read_free( read );
|
||||
vips_source_map( source, &read->data.size )) )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( read );
|
||||
}
|
||||
@ -774,16 +786,10 @@ vips__webp_read_header_source( VipsSource *source, VipsImage *out,
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( source, page, n, scale )) )
|
||||
if( !(read = read_new( out, source, page, n, scale )) ||
|
||||
read_header( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
if( read_header( read, out ) ) {
|
||||
read_free( read );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
read_free( read );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -793,16 +799,10 @@ vips__webp_read_source( VipsSource *source, VipsImage *out,
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( source, page, n, scale )) )
|
||||
if( !(read = read_new( out, source, page, n, scale )) ||
|
||||
read_image( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
if( read_image( read, out ) ) {
|
||||
read_free( read );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
read_free( read );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,8 @@ int vips__byteswap_bool( VipsImage *in, VipsImage **out, gboolean swap );
|
||||
|
||||
char *vips__xml_properties( VipsImage *image );
|
||||
|
||||
void vips__cairo2rgba( guint32 *buf, int n );
|
||||
void vips__premultiplied_bgra2rgba( guint32 * restrict p, int n );
|
||||
void vips__bgra2rgba( guint32 * restrict p, int n );
|
||||
void vips__Lab2LabQ_vec( VipsPel *out, float *in, int width );
|
||||
void vips__LabQ2Lab_vec( float *out, VipsPel *in, int width );
|
||||
|
||||
|
@ -260,6 +260,8 @@ vips_source_finalize( GObject *gobject )
|
||||
{
|
||||
VipsSource *source = VIPS_SOURCE( gobject );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_source_finalize: %p\n", source );
|
||||
|
||||
VIPS_FREEF( g_byte_array_unref, source->header_bytes );
|
||||
VIPS_FREEF( g_byte_array_unref, source->sniff );
|
||||
if( source->mmap_baseaddr ) {
|
||||
@ -555,8 +557,6 @@ vips_source_minimise( VipsSource *source )
|
||||
{
|
||||
VipsConnection *connection = VIPS_CONNECTION( source );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_source_minimise:\n" );
|
||||
|
||||
SANITY( source );
|
||||
|
||||
(void) vips_source_test_features( source );
|
||||
@ -565,7 +565,7 @@ vips_source_minimise( VipsSource *source )
|
||||
connection->descriptor != -1 &&
|
||||
connection->tracked_descriptor == connection->descriptor &&
|
||||
!source->is_pipe ) {
|
||||
VIPS_DEBUG_MSG( " tracked_close()\n" );
|
||||
VIPS_DEBUG_MSG( "vips_source_minimise:\n" );
|
||||
vips_tracked_close( connection->tracked_descriptor );
|
||||
connection->tracked_descriptor = -1;
|
||||
connection->descriptor = -1;
|
||||
@ -590,13 +590,13 @@ vips_source_unminimise( VipsSource *source )
|
||||
{
|
||||
VipsConnection *connection = VIPS_CONNECTION( source );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_source_unminimise:\n" );
|
||||
|
||||
if( connection->descriptor == -1 &&
|
||||
connection->tracked_descriptor == -1 &&
|
||||
connection->filename ) {
|
||||
int fd;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_source_unminimise: %p\n", source );
|
||||
|
||||
if( (fd = vips_tracked_open( connection->filename,
|
||||
MODE_READ, 0 )) == -1 ) {
|
||||
vips_error_system( errno,
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
typedef struct _MyInput {
|
||||
const char *filename;
|
||||
const unsigned char *contents;
|
||||
unsigned char *contents;
|
||||
size_t length;
|
||||
size_t read_position;
|
||||
} MyInput;
|
||||
@ -106,7 +106,7 @@ main( int argc, char **argv )
|
||||
VipsTargetCustom *target_custom;
|
||||
VipsImage *image;
|
||||
|
||||
if( VIPS_INIT( NULL ) )
|
||||
if( VIPS_INIT( argv[0] ) )
|
||||
return( -1 );
|
||||
|
||||
if( argc != 3 )
|
||||
@ -153,6 +153,7 @@ main( int argc, char **argv )
|
||||
VIPS_UNREF( image );
|
||||
VIPS_UNREF( source_custom );
|
||||
VIPS_UNREF( target_custom );
|
||||
g_free( my_input.contents );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user