add mmap ppm input

This commit is contained in:
John Cupitt 2019-11-15 15:56:28 +00:00
parent 5f4b995551
commit 9a3842919a
4 changed files with 81 additions and 38 deletions

View File

@ -64,7 +64,7 @@
/* TODO
*
* - load filename streams with mmap ... we'll need to add get_flags_stream
* - load filename streams with mmap
*/
/*
@ -330,22 +330,25 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
static VipsForeignFlags
vips_foreign_load_ppm_get_flags( VipsForeignLoad *load )
{
VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load;
VipsForeignFlags flags;
flags = 0;
/* reenable this when mmap load goes back in
*
VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load;
/* If this streami supports fast mmap and this PPM is >=8 bit binary,
* then we can mmap the file and support partial load. Otherwise,
* it's sequential.
*/
if( !ppm->have_read_header &&
vips_foreign_load_ppm_parse_header( ppm ) )
return( 0 );
if( !ppm->ascii && ppm->bits >= 8 )
if( vips_streami_is_mappable( ppm->streami ) &&
!ppm->ascii &&
ppm->bits >= 8 )
flags |= VIPS_FOREIGN_PARTIAL;
*/
flags |= VIPS_FOREIGN_SEQUENTIAL;
else
flags |= VIPS_FOREIGN_SEQUENTIAL;
return( flags );
}
@ -388,7 +391,9 @@ vips_foreign_load_ppm_header( VipsForeignLoad *load )
}
/* Read a ppm/pgm file using mmap().
load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image )
*/
static int
vips_foreign_load_ppm_map( VipsForeignLoadPpm *ppm, VipsImage *image )
{
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( ppm ), 3 );
@ -400,7 +405,8 @@ load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image )
vips_streamib_unbuffer( ppm->streamib );
header_offset = vips_streami_seek( ppm->streami, 0, SEEK_CUR );
data = vips_streami_map( ppm->streami, &length );
if( header_offset < 0 || !data )
if( header_offset < 0 ||
!data )
return( -1 );
data += header_offset;
length -= header_offset;
@ -416,7 +422,6 @@ load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image )
return( 0 );
}
*/
static int
vips_foreign_load_ppm_generate_binary( VipsRegion *or,
@ -556,34 +561,46 @@ vips_foreign_load_ppm_load( VipsForeignLoad *load )
VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) load, 2 );
VipsGenerateFn generate;
if( !ppm->have_read_header &&
vips_foreign_load_ppm_parse_header( ppm ) )
return( 0 );
/* What sort of read are we doing?
/* If the stream is mappable and this is a binary file, we can map it.
*/
if( !ppm->ascii && ppm->bits >= 8 ) {
generate = vips_foreign_load_ppm_generate_binary;
/* The binary loader does not use the buffered IO object.
*/
vips_streamib_unbuffer( ppm->streamib );
if( vips_streami_is_mappable( ppm->streami ) &&
!ppm->ascii &&
ppm->bits >= 8 ) {
if( vips_foreign_load_ppm_map( ppm, load->real ) )
return( -1 );
}
else if( !ppm->ascii && ppm->bits == 1 )
generate = vips_foreign_load_ppm_generate_1bit_binary;
else if( ppm->ascii && ppm->bits == 1 )
generate = vips_foreign_load_ppm_generate_1bit_ascii;
else
generate = vips_foreign_load_ppm_generate_ascii_int;
else {
VipsGenerateFn generate;
t[0] = vips_image_new();
vips_foreign_load_ppm_set_image( ppm, t[0] );
if( vips_image_generate( t[0], NULL, generate, NULL, ppm, NULL ) ||
vips_sequential( t[0], &t[1], NULL ) ||
vips_image_write( t[1], load->real ) )
return( -1 );
/* What sort of read are we doing?
*/
if( !ppm->ascii && ppm->bits >= 8 ) {
generate = vips_foreign_load_ppm_generate_binary;
/* The binary loader does not use the buffered IO
* object.
*/
vips_streamib_unbuffer( ppm->streamib );
}
else if( !ppm->ascii && ppm->bits == 1 )
generate = vips_foreign_load_ppm_generate_1bit_binary;
else if( ppm->ascii && ppm->bits == 1 )
generate = vips_foreign_load_ppm_generate_1bit_ascii;
else
generate = vips_foreign_load_ppm_generate_ascii_int;
t[0] = vips_image_new();
vips_foreign_load_ppm_set_image( ppm, t[0] );
if( vips_image_generate( t[0],
NULL, generate, NULL, ppm, NULL ) ||
vips_sequential( t[0], &t[1], NULL ) ||
vips_image_write( t[1], load->real ) )
return( -1 );
}
if( vips_streami_decode( ppm->streami ) )
return( -1 );

View File

@ -197,7 +197,8 @@ typedef struct _VipsForeignLoadClass {
* of flags. If you don't define it, vips will default to 0 (no flags
* set).
*
* This operation is necessary for vips7 compatibility.
* This method is necessary for vips7 compatibility. Don't define
* it if you don't need vips7.
*/
VipsForeignFlags (*get_flags_filename)( const char *filename );
@ -217,8 +218,7 @@ typedef struct _VipsForeignLoadClass {
* @header() needs to set the dhint on the image .. otherwise you get
* the default SMALLTILE.
*
* Return 0 for success, -1 for error, setting
* vips_error().
* Return 0 for success, -1 for error, setting vips_error().
*/
int (*header)( VipsForeignLoad *load );

View File

@ -209,6 +209,7 @@ int vips_streami_unminimise( VipsStreami *streami );
int vips_streami_decode( VipsStreami *streami );
ssize_t vips_streami_read( VipsStreami *streami, void *data, size_t length );
const void *vips_streami_map( VipsStreami *streami, size_t *length );
gboolean vips_streami_is_mappable( VipsStreami *streami );
gint64 vips_streami_seek( VipsStreami *streami, gint64 offset, int whence );
int vips_streami_rewind( VipsStreami *streami );
size_t vips_streami_sniff_at_most( VipsStreami *streami,

View File

@ -817,10 +817,11 @@ vips_streami_descriptor_to_memory( VipsStreami *streami )
* @streami: input stream to operate on
* @length_out: return the file length here, or NULL
*
* Map the stream object entirely into memory, and return a pointer to the
* Map the stream object entirely into memory and return a pointer to the
* start. If @length_out is non-NULL, the file size if written to it.
*
* This operation can take a long time.
* This operation can take a long time. Use vips_streami_is_mappable() to
* check if a streami can be mapped efficiently.
*
* Returns: a pointer to the start of the file contents, or NULL on error.
*/
@ -860,6 +861,30 @@ vips_streami_map( VipsStreami *streami, size_t *length_out )
return( streami->data );
}
/**
* vips_streami_map:
* @streami: input stream to operate on
* @length_out: return the file length here, or NULL
*
* Map the stream object entirely into memory and return a pointer to the
* start. If @length_out is non-NULL, the file size if written to it.
*
* This operation can take a long time. Use vips_streami_is_mappable() to check
* if a streami can be mapped efficiently.
*
* Returns: a pointer to the start of the file contents, or NULL on error.
*/
gboolean
vips_streami_is_mappable( VipsStreami *streami )
{
/* Already a memory object, or there's a filename we can map, or
* there's a seekable descriptor.
*/
return( streami->data ||
VIPS_STREAM( streami )->filename ||
(streami->is_pipe && VIPS_STREAM( streami )->descriptor) );
}
/**
* vips_streami_seek:
* @streami: input stream to operate on