final fixups

- add buffer load
- test under valgrind
- code sharing with the poppler pdf loader
This commit is contained in:
John Cupitt 2018-04-11 18:53:38 +01:00
parent 3d696b9c1e
commit c0569d25bf
5 changed files with 57 additions and 79 deletions

View File

@ -14,6 +14,7 @@
- create funcs always make MULTIBAND (ie. no alpha) - create funcs always make MULTIBAND (ie. no alpha)
- use O_TMPFILE, if available [Alexander--] - use O_TMPFILE, if available [Alexander--]
- set "interlaced=1" for interlaced JPG and PNG images - set "interlaced=1" for interlaced JPG and PNG images
- add PDFium PDF loader
12/3/18 started 8.6.4 12/3/18 started 8.6.4
- better fitting of fonts with overhanging edges [Adrià] - better fitting of fonts with overhanging edges [Adrià]

View File

@ -212,7 +212,7 @@ If PDFium is not detected, libvips will look for poppler-glib instead.
### libpoppler ### libpoppler
The usual PDF loader. If this is not present, vips will try to load PDFs The usual PDF loader. If this is not present, vips will try to load PDFs
via imagemagick instead. via imagemagick.
### libgsf-1 ### libgsf-1

View File

@ -55,6 +55,8 @@
#include <vips/buf.h> #include <vips/buf.h>
#include <vips/internal.h> #include <vips/internal.h>
#include "pforeign.h"
#ifdef HAVE_POPPLER #ifdef HAVE_POPPLER
#include <cairo.h> #include <cairo.h>
@ -91,7 +93,7 @@ typedef struct _VipsForeignLoadPdf {
*/ */
int n_pages; int n_pages;
/* We need to read out the side of each page we will render, and lay /* We need to read out the size of each page we will render, and lay
* them out in the final image. * them out in the final image.
*/ */
VipsRect image; VipsRect image;
@ -145,33 +147,6 @@ vips_foreign_load_pdf_get_flags( VipsForeignLoad *load )
return( VIPS_FOREIGN_PARTIAL ); return( VIPS_FOREIGN_PARTIAL );
} }
static gboolean
vips_foreign_load_pdf_is_a_buffer( const void *buf, size_t len )
{
const guchar *str = (const guchar *) buf;
if( len >= 4 &&
str[0] == '%' &&
str[1] == 'P' &&
str[2] == 'D' &&
str[3] == 'F' )
return( 1 );
return( 0 );
}
static gboolean
vips_foreign_load_pdf_is_a( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips_foreign_load_pdf_is_a_buffer( buf, 4 ) )
return( 1 );
return( 0 );
}
static int static int
vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no ) vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
{ {
@ -429,7 +404,7 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
* (again) keep the number of calls to page_render low. * (again) keep the number of calls to page_render low.
*/ */
if( vips_linecache( t[0], &t[1], if( vips_linecache( t[0], &t[1],
"tile_height", 5000, "tile_height", VIPS_MIN( 5000, pdf->pages[0].height ),
NULL ) ) NULL ) )
return( -1 ); return( -1 );
if( vips_image_write( t[1], load->real ) ) if( vips_image_write( t[1], load->real ) )
@ -658,6 +633,37 @@ vips_foreign_load_pdf_buffer_init( VipsForeignLoadPdfBuffer *buffer )
#endif /*HAVE_POPPLER*/ #endif /*HAVE_POPPLER*/
/* Also used by the pdfium loader.
*/
gboolean
vips_foreign_load_pdf_is_a_buffer( const void *buf, size_t len )
{
const guchar *str = (const guchar *) buf;
if( len >= 4 &&
str[0] == '%' &&
str[1] == 'P' &&
str[2] == 'D' &&
str[3] == 'F' )
return( 1 );
return( 0 );
}
/* Also used by the pdfium loader.
*/
gboolean
vips_foreign_load_pdf_is_a( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips_foreign_load_pdf_is_a_buffer( buf, 4 ) )
return( 1 );
return( 0 );
}
/** /**
* vips_pdfload: * vips_pdfload:
* @filename: file to load * @filename: file to load

View File

@ -33,14 +33,8 @@
/* TODO /* TODO
* *
* - more code sharing with pdfload.c, eg. vips_foreign_load_pdf_is_a_buffer()
* and get_flags etc.
* - could share the page layout code too
* - make pdf.c with base stuff in?
* - what about filename encodings * - what about filename encodings
* - I guess we must write RGBA to match poppler output * - need to test on Windows
* - new_from_buffer stuff
*
*/ */
/* /*
@ -57,14 +51,12 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
/* Just until we get rid of the final bits of poppler
*/
#include <cairo.h>
#include <vips/vips.h> #include <vips/vips.h>
#include <vips/buf.h> #include <vips/buf.h>
#include <vips/internal.h> #include <vips/internal.h>
#include "pforeign.h"
#ifdef HAVE_PDFIUM #ifdef HAVE_PDFIUM
#include <fpdfview.h> #include <fpdfview.h>
@ -97,7 +89,7 @@ typedef struct _VipsForeignLoadPdf {
*/ */
int n_pages; int n_pages;
/* We need to read out the side of each page we will render, and lay /* We need to read out the size of each page we will render, and lay
* them out in the final image. * them out in the final image.
*/ */
VipsRect image; VipsRect image;
@ -137,8 +129,8 @@ vips_foreign_load_pdf_dispose( GObject *gobject )
{ {
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) gobject; VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) gobject;
VIPS_FREEF( FPDF_CloseDocument, pdf->doc );
VIPS_FREEF( FPDF_ClosePage, pdf->page ); VIPS_FREEF( FPDF_ClosePage, pdf->page );
VIPS_FREEF( FPDF_CloseDocument, pdf->doc );
G_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->dispose( gobject ); G_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->dispose( gobject );
} }
@ -180,7 +172,8 @@ vips_foreign_load_pdf_build( VipsObject *object )
static VipsForeignFlags static VipsForeignFlags
vips_foreign_load_pdf_get_flags_filename( const char *filename ) vips_foreign_load_pdf_get_flags_filename( const char *filename )
{ {
/* We can render any part of the page on demand. /* We can't render any part of the page on demand, but we can render
* separate pages. Might as well call ourselves partial.
*/ */
return( VIPS_FOREIGN_PARTIAL ); return( VIPS_FOREIGN_PARTIAL );
} }
@ -191,33 +184,6 @@ vips_foreign_load_pdf_get_flags( VipsForeignLoad *load )
return( VIPS_FOREIGN_PARTIAL ); return( VIPS_FOREIGN_PARTIAL );
} }
static gboolean
vips_foreign_load_pdf_is_a_buffer( const void *buf, size_t len )
{
const guchar *str = (const guchar *) buf;
if( len >= 4 &&
str[0] == '%' &&
str[1] == 'P' &&
str[2] == 'D' &&
str[3] == 'F' )
return( 1 );
return( 0 );
}
static gboolean
vips_foreign_load_pdf_is_a( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips_foreign_load_pdf_is_a_buffer( buf, 4 ) )
return( 1 );
return( 0 );
}
static int static int
vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no ) vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
{ {
@ -246,8 +212,8 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no )
/* String-based metadata fields we extract. /* String-based metadata fields we extract.
*/ */
typedef struct _VipsForeignLoadPdfMetadata { typedef struct _VipsForeignLoadPdfMetadata {
char *tag; // as understood by PDFium char *tag; /* as understood by PDFium */
char *field; // as understood by libvips char *field; /* as understood by libvips */
} VipsForeignLoadPdfMetadata; } VipsForeignLoadPdfMetadata;
static VipsForeignLoadPdfMetadata vips_foreign_load_pdf_metadata[] = { static VipsForeignLoadPdfMetadata vips_foreign_load_pdf_metadata[] = {
@ -257,7 +223,7 @@ static VipsForeignLoadPdfMetadata vips_foreign_load_pdf_metadata[] = {
{ "Keywords", "pdf-keywords" }, { "Keywords", "pdf-keywords" },
{ "Creator", "pdf-creator" }, { "Creator", "pdf-creator" },
{ "Producer", "pdf-producer" }, { "Producer", "pdf-producer" },
// poppler has "metadata" as well, but pdfium does not support this /* poppler has "metadata" as well, but pdfium does not support this */
}; };
static int n_metadata = VIPS_NUMBER( vips_foreign_load_pdf_metadata ); static int n_metadata = VIPS_NUMBER( vips_foreign_load_pdf_metadata );
@ -440,6 +406,8 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
} }
/* PDFium writes BRGA, we must swap. /* PDFium writes BRGA, we must swap.
*
* FIXME ... this is a bit slow.
*/ */
for( y = 0; y < r->height; y++ ) { for( y = 0; y < r->height; y++ ) {
VipsPel *p; VipsPel *p;
@ -634,17 +602,17 @@ G_DEFINE_TYPE( VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer,
static int static int
vips_foreign_load_pdf_buffer_header( VipsForeignLoad *load ) vips_foreign_load_pdf_buffer_header( VipsForeignLoad *load )
{ {
/*
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load; VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load;
VipsForeignLoadPdfBuffer *buffer = VipsForeignLoadPdfBuffer *buffer =
(VipsForeignLoadPdfBuffer *) load; (VipsForeignLoadPdfBuffer *) load;
if( !(pdf->doc = poppler_document_new_from_data( if( !(pdf->doc = FPDF_LoadMemDocument( buffer->buf->data,
buffer->buf->data, buffer->buf->length, NULL, &error )) ) { buffer->buf->length, NULL )) ) {
vips_g_error( &error ); vips_pdfium_error();
vips_error( "pdfload",
"%s", _( "unable to load from buffer" ) );
return( -1 ); return( -1 );
} }
*/
return( vips_foreign_load_pdf_header( load ) ); return( vips_foreign_load_pdf_header( load ) );
} }

View File

@ -239,6 +239,9 @@ int vips__openslide_read( const char *filename, VipsImage *out,
int vips__openslide_read_associated( const char *filename, VipsImage *out, int vips__openslide_read_associated( const char *filename, VipsImage *out,
const char *associated ); const char *associated );
gboolean vips_foreign_load_pdf_is_a_buffer( const void *buf, size_t len );
gboolean vips_foreign_load_pdf_is_a( const char *filename );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /*__cplusplus*/ #endif /*__cplusplus*/