move pdfload on top of source API

and add pdfload_source

see https://github.com/libvips/libvips/issues/1541
This commit is contained in:
John Cupitt 2020-03-11 18:15:15 +00:00
parent d4f12a9999
commit 764b196d50
4 changed files with 161 additions and 79 deletions

View File

@ -6,7 +6,7 @@
- tiffsave has a "depth" param to set max pyr depth
- libtiff LOGLUV images load and save as libvips XYZ
- add gifload_source, csvload_source, csvsave_target, matrixload_source,
matrixsave_source
matrixsave_source, pdfload_source
- revise vipsthumbnail flags
- add VIPS_LEAK env var
- add vips_pipe_read_limit_set(), --vips-pipe-read-limit,

View File

@ -2097,9 +2097,9 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_webp_buffer_get_type( void );
extern GType vips_foreign_save_webp_target_get_type( void );
extern GType vips_foreign_load_pdf_get_type( void );
extern GType vips_foreign_load_pdf_file_get_type( void );
extern GType vips_foreign_load_pdf_buffer_get_type( void );
extern GType vips_foreign_load_pdf_source_get_type( void );
extern GType vips_foreign_load_svg_file_get_type( void );
extern GType vips_foreign_load_svg_buffer_get_type( void );
@ -2151,14 +2151,13 @@ vips_foreign_operation_init( void )
vips_foreign_save_rad_target_get_type();
#endif /*HAVE_RADIANCE*/
#ifdef HAVE_POPPLER
vips_foreign_load_pdf_get_type();
#if defined(HAVE_POPPLER) && defined(HAVE_GIO)
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
vips_foreign_load_pdf_source_get_type();
#endif /*HAVE_POPPLER*/
#ifdef HAVE_PDFIUM
vips_foreign_load_pdf_get_type();
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
#endif /*HAVE_PDFIUM*/

View File

@ -14,6 +14,8 @@
* - shut down the input file as soon as we can
* 19/9/19
* - reopen the input if we minimised too early
* 11/3/20
* - move on top of VipsSource
*/
/*
@ -63,7 +65,10 @@
#include "pforeign.h"
#ifdef HAVE_POPPLER
/* TODO ... put minimise support back in.
*/
#if defined(HAVE_POPPLER) && defined(HAVE_GIO)
#include <cairo.h>
#include <poppler.h>
@ -86,6 +91,12 @@
typedef struct _VipsForeignLoadPdf {
VipsForeignLoad parent_object;
/* The VipsSource we load from, and the GInputStream we wrap around
* it. Set from subclasses.
*/
VipsSource *source;
GInputStream *stream;
/* Load this page.
*/
int page_no;
@ -133,9 +144,6 @@ typedef struct _VipsForeignLoadPdf {
typedef struct _VipsForeignLoadPdfClass {
VipsForeignLoadClass parent_class;
int (*open)( VipsForeignLoadPdf *pdf );
void (*close)( VipsForeignLoadPdf *pdf );
} VipsForeignLoadPdfClass;
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadPdf, vips_foreign_load_pdf,
@ -145,9 +153,11 @@ static void
vips_foreign_load_pdf_dispose( GObject *gobject )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( gobject );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
class->close( pdf );
VIPS_UNREF( pdf->page );
VIPS_UNREF( pdf->doc );
VIPS_UNREF( pdf->source );
VIPS_UNREF( pdf->stream );
G_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->
dispose( gobject );
@ -158,9 +168,18 @@ vips_foreign_load_pdf_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
GError *error = NULL;
if( !vips_object_argument_isset( object, "scale" ) )
pdf->scale = pdf->dpi / 72.0;
pdf->stream = vips_g_input_stream_new_from_source( pdf->source );
if( !(pdf->doc = poppler_document_new_from_stream( pdf->stream,
vips_source_length( pdf->source ), NULL, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->
build( object ) )
return( -1 );
@ -274,8 +293,6 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( load );
VipsForeignLoadPdfClass *pdf_class =
VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
int top;
int i;
@ -284,9 +301,6 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
printf( "vips_foreign_load_pdf_header: %p\n", pdf );
#endif /*DEBUG*/
if( pdf_class->open( pdf ) )
return( -1 );
pdf->n_pages = poppler_document_get_n_pages( pdf->doc );
/* @n == -1 means until the end of the doc.
@ -357,7 +371,7 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
VIPS_AREA( pdf->background )->n )) )
return( -1 );
pdf_class->close( pdf );
vips_source_minimise( pdf->source );
return( 0 );
}
@ -367,7 +381,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( a );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
VipsRect *r = &or->valid;
int top;
@ -380,11 +393,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
r->left, r->top, r->width, r->height );
*/
/* We may have been minimised. Make sure the doc is open.
*/
if( class->open( pdf ) )
return( -1 );
/* Poppler won't always paint the background.
*/
vips_region_paint_pel( or, r, pdf->ink );
@ -445,7 +453,6 @@ static int
vips_foreign_load_pdf_load( VipsForeignLoad *load )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( load );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) load, 2 );
@ -453,9 +460,6 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
printf( "vips_foreign_load_pdf_load: %p\n", pdf );
#endif /*DEBUG*/
if( class->open( pdf ) )
return( -1 );
/* Read to this image, then cache to out, see below.
*/
t[0] = vips_image_new();
@ -484,23 +488,6 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
return( 0 );
}
static int
vips_foreign_load_pdf_open( VipsForeignLoadPdf *pdf )
{
return( 0 );
}
static void
vips_foreign_load_pdf_close( VipsForeignLoadPdf *pdf )
{
#ifdef DEBUG
printf( "vips_foreign_load_pdf_file_close:\n" );
#endif /*DEBUG*/
VIPS_UNREF( pdf->page );
VIPS_UNREF( pdf->doc );
}
static void
vips_foreign_load_pdf_class_init( VipsForeignLoadPdfClass *class )
{
@ -522,9 +509,6 @@ vips_foreign_load_pdf_class_init( VipsForeignLoadPdfClass *class )
load_class->header = vips_foreign_load_pdf_header;
load_class->load = vips_foreign_load_pdf_load;
class->open = vips_foreign_load_pdf_open;
class->close = vips_foreign_load_pdf_close;
VIPS_ARG_INT( class, "page", 20,
_( "Page" ),
_( "Load this page from the file" ),
@ -617,19 +601,18 @@ static const char *vips_foreign_pdf_suffs[] = {
};
static int
vips_foreign_load_pdf_file_open( VipsForeignLoadPdf *pdf )
vips_foreign_load_pdf_file_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) pdf;
GError *error = NULL;
#ifdef DEBUG
printf( "vips_foreign_load_pdf_file_open: %s\n", file->filename );
printf( "vips_foreign_load_pdf_file_build: %s\n", file->filename );
#endif /*DEBUG*/
if( !file->uri &&
file->filename ) {
if( file->filename ) {
char *path;
GError *error = NULL;
/* We need an absolute path for a URI.
*/
@ -640,18 +623,15 @@ vips_foreign_load_pdf_file_open( VipsForeignLoadPdf *pdf )
return( -1 );
}
g_free( path );
if( !(pdf->source =
vips_source_new_from_file( file->filename )) )
return( -1 );
}
if( !pdf->doc &&
file->uri &&
!(pdf->doc = poppler_document_new_from_file(
file->uri, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
return( VIPS_FOREIGN_LOAD_PDF_CLASS(
vips_foreign_load_pdf_file_parent_class )->open( pdf ) );
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_file_parent_class )->
build( object ) );
}
static void
@ -668,14 +648,14 @@ 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;
load_class->is_a = vips_foreign_load_pdf_is_a;
load_class->header = vips_foreign_load_pdf_file_header;
class->open = vips_foreign_load_pdf_file_open;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
@ -705,21 +685,19 @@ G_DEFINE_TYPE( VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer,
vips_foreign_load_pdf_get_type() );
static int
vips_foreign_load_pdf_buffer_open( VipsForeignLoadPdf *pdf )
vips_foreign_load_pdf_buffer_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
VipsForeignLoadPdfBuffer *buffer = (VipsForeignLoadPdfBuffer *) pdf;
GError *error = NULL;
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 &&
!(pdf->doc = poppler_document_new_from_data(
buffer->buf->data, buffer->buf->length, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
return( VIPS_FOREIGN_LOAD_PDF_CLASS(
vips_foreign_load_pdf_buffer_parent_class )->open( pdf ) );
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_buffer_parent_class )->
build( object ) );
}
static void
@ -734,11 +712,11 @@ 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;
class->open = vips_foreign_load_pdf_buffer_open;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
@ -753,7 +731,77 @@ vips_foreign_load_pdf_buffer_init( VipsForeignLoadPdfBuffer *buffer )
{
}
#endif /*HAVE_POPPLER*/
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 = VIPS_FOREIGN_LOAD_PDF( 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 /*defined(HAVE_POPPLER) && defined(HAVE_GIO)*/
/* Also used by the pdfium loader.
*/
@ -889,3 +937,36 @@ vips_pdfload_buffer( void *buf, size_t len, VipsImage **out, ... )
return( result );
}
/**
* vips_pdfload_source:
* @source: source to load from
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page, numbered from zero
* * @n: %gint, load this many pages
* * @dpi: %gdouble, render at this DPI
* * @scale: %gdouble, scale render by this factor
* * @background: #VipsArrayDouble background colour
*
* Exactly as vips_pdfload(), but read from a source.
*
* See also: vips_pdfload()
*
* Returns: 0 on success, -1 on error.
*/
int
vips_pdfload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "pdfload_source", ap, source, out );
va_end( ap );
return( result );
}

View File

@ -610,6 +610,8 @@ int vips_pdfload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pdfload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pdfload_source( VipsSource *source, VipsImage **out, ... )
__attribute__((sentinel));
int vips_svgload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));