diff --git a/libvips/foreign/ppmload.c b/libvips/foreign/ppmload.c index 50365785..b38fc281 100644 --- a/libvips/foreign/ppmload.c +++ b/libvips/foreign/ppmload.c @@ -64,8 +64,7 @@ /* TODO * - * - make partial - * - only use mmap on filename streams? + * - load filename streams with mmap ... we'll need to add get_flags_stream */ /* @@ -331,17 +330,22 @@ 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( !ppm->have_read_header && vips_foreign_load_ppm_parse_header( ppm ) ) return( 0 ); - - flags = 0; if( !ppm->ascii && ppm->bits >= 8 ) flags |= VIPS_FOREIGN_PARTIAL; + */ + + flags |= VIPS_FOREIGN_SEQUENTIAL; return( flags ); } @@ -353,6 +357,8 @@ vips_foreign_load_ppm_set_image( VipsForeignLoadPpm *ppm, VipsImage *image ) ppm->width, ppm->height, ppm->bands, ppm->format, VIPS_CODING_NONE, ppm->interpretation, 1.0, 1.0 ); + vips_image_pipelinev( image, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); + if( ppm->index == 6 || ppm->index == 7 ) vips_image_set_double( image, @@ -382,8 +388,6 @@ vips_foreign_load_ppm_header( VipsForeignLoad *load ) } /* Read a ppm/pgm file using mmap(). - */ -static int load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image ) { VipsImage **t = (VipsImage **) @@ -404,7 +408,6 @@ load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image ) if( !(t[0] = vips_image_new_from_memory( data, length, ppm->width, ppm->height, ppm->bands, ppm->format )) ) return( -1 ); - vips_foreign_load_ppm_set_image( ppm, t[0] ); if( vips__byteswap_bool( t[0], &t[1], vips_amiMSBfirst() != ppm->msb_first ) || @@ -413,22 +416,47 @@ load_mmap( VipsForeignLoadPpm *ppm, VipsImage *image ) return( 0 ); } - -/* Read an ascii 1 bit file. */ + static int -load_1bit_ascii( VipsForeignLoadPpm *ppm, VipsImage *image ) +vips_foreign_load_ppm_generate_binary( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) { + VipsRect *r = &or->valid; + VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; + VipsImage *image = or->im; + size_t sizeof_line = VIPS_IMAGE_SIZEOF_LINE( image ); + + int y; + + for( y = 0; y < r->height; y++ ) { + VipsPel *q = VIPS_REGION_ADDR( or, 0, r->top + y ); + + size_t bytes_read; + + bytes_read = vips_streami_read( ppm->streami, q, sizeof_line ); + if( bytes_read != sizeof_line ) { + vips_error( "ppmload", "%s", _( "file truncated" ) ); + return( -1 ); + } + } + + return( 0 ); +} + +static int +vips_foreign_load_ppm_generate_1bit_ascii( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) +{ + VipsRect *r = &or->valid; + VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; + VipsImage *image = or->im; + int x, y; - VipsPel *buf; - vips_foreign_load_ppm_set_image( ppm, image ); + for( y = 0; y < r->height; y++ ) { + VipsPel *q = VIPS_REGION_ADDR( or, 0, r->top + y ); - if( !(buf = VIPS_ARRAY( image, - VIPS_IMAGE_SIZEOF_LINE( image ), VipsPel )) ) - return( -1 ); - - for( y = 0; y < image->Ysize; y++ ) { for( x = 0; x < image->Xsize; x++ ) { int val; @@ -436,37 +464,32 @@ load_1bit_ascii( VipsForeignLoadPpm *ppm, VipsImage *image ) return( -1 ); if( val ) - buf[x] = 0; + q[x] = 0; else - buf[x] = 255; + q[x] = 255; } - - if( vips_image_write_line( image, y, buf ) ) - return( -1 ); } return( 0 ); } -/* Read a 1 bit binary file. - */ static int -load_1bit_binary( VipsForeignLoadPpm *ppm, VipsImage *image ) +vips_foreign_load_ppm_generate_1bit_binary( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) { + VipsRect *r = &or->valid; + VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; + VipsImage *image = or->im; + int x, y; int bits; - VipsPel *buf; - - vips_foreign_load_ppm_set_image( ppm, image ); - - if( !(buf = VIPS_ARRAY( image, - VIPS_IMAGE_SIZEOF_LINE( image ), VipsPel )) ) - return( -1 ); bits = VIPS_STREAMIB_GETC( ppm->streamib ); - for( y = 0; y < image->Ysize; y++ ) { + for( y = 0; y < r->height; y++ ) { + VipsPel *q = VIPS_REGION_ADDR( or, 0, r->top + y ); + for( x = 0; x < image->Xsize; x++ ) { - buf[x] = (bits & 128) ? 0 : 255; + q[x] = (bits & 128) ? 0 : 255; bits = VIPS_LSHIFT_INT( bits, 1 ); if( (x & 7) == 7 ) bits = VIPS_STREAMIB_GETC( ppm->streamib ); @@ -476,28 +499,26 @@ load_1bit_binary( VipsForeignLoadPpm *ppm, VipsImage *image ) */ if( (x & 7) != 0 ) bits = VIPS_STREAMIB_GETC( ppm->streamib ); - - if( vips_image_write_line( image, y, buf ) ) - return( -1 ); } return( 0 ); } -/* Read an ascii ppm/pgm file. - */ static int -load_ascii( VipsForeignLoadPpm *ppm, VipsImage *image ) +vips_foreign_load_ppm_generate_ascii_int( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) { - int x, y; - VipsPel *buf; + VipsRect *r = &or->valid; + VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; + VipsImage *image = or->im; + int n_elements = image->Xsize * image->Bands; - if( !(buf = - VIPS_ARRAY( image, VIPS_IMAGE_SIZEOF_LINE( image ), VipsPel )) ) - return( -1 ); + int i, y; - for( y = 0; y < image->Ysize; y++ ) { - for( x = 0; x < image->Xsize * image->Bands; x++ ) { + for( y = 0; y < r->height; y++ ) { + VipsPel *q = VIPS_REGION_ADDR( or, r->left, r->top + y ); + + for( i = 0; i < n_elements; i++ ) { int val; if( get_int( ppm->streamib, &val ) ) @@ -505,25 +526,22 @@ load_ascii( VipsForeignLoadPpm *ppm, VipsImage *image ) switch( image->BandFmt ) { case VIPS_FORMAT_UCHAR: - buf[x] = VIPS_CLIP( 0, val, 255 ); + q[i] = VIPS_CLIP( 0, val, 255 ); break; case VIPS_FORMAT_USHORT: - ((unsigned short *) buf)[x] = + ((unsigned short *) q)[i] = VIPS_CLIP( 0, val, 65535 ); break; case VIPS_FORMAT_UINT: - ((unsigned int *) buf)[x] = val; + ((unsigned int *) q)[i] = val; break; default: g_assert_not_reached(); } } - - if( vips_image_write_line( image, y, buf ) ) - return( -1 ); } return( 0 ); @@ -535,8 +553,10 @@ static int vips_foreign_load_ppm_load( VipsForeignLoad *load ) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; + VipsImage **t = (VipsImage **) + vips_object_local_array( (VipsObject *) load, 2 ); - VipsPpmLoaderFn loader; + VipsGenerateFn generate; if( !ppm->have_read_header && vips_foreign_load_ppm_parse_header( ppm ) ) @@ -544,20 +564,29 @@ vips_foreign_load_ppm_load( VipsForeignLoad *load ) /* What sort of read are we doing? */ - if( !ppm->ascii && ppm->bits >= 8 ) - loader = load_mmap; - else if( !ppm->ascii && ppm->bits == 1 ) - loader = load_1bit_binary; - else if( ppm->ascii && ppm->bits == 1 ) - loader = load_1bit_ascii; - else - loader = load_ascii; + if( !ppm->ascii && ppm->bits >= 8 ) { + generate = vips_foreign_load_ppm_generate_binary; - if( vips_streami_decode( ppm->streami ) || - loader( ppm, load->real ) ) + /* 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 ); - vips_streami_minimise( ppm->streami ); + if( vips_streami_decode( ppm->streami ) ) + return( -1 ); return( 0 ); } diff --git a/libvips/foreign/ppmload.old.c b/libvips/foreign/ppmload.old.c deleted file mode 100644 index 862ee780..00000000 --- a/libvips/foreign/ppmload.old.c +++ /dev/null @@ -1,226 +0,0 @@ -/* load ppm from a file - * - * 5/12/11 - * - from tiffload.c - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include - -#include -#include -#include - -#include "pforeign.h" - -#ifdef HAVE_PPM - -typedef struct _VipsForeignLoadPpm { - VipsForeignLoad parent_object; - - /* Filename for load. - */ - char *filename; - -} VipsForeignLoadPpm; - -typedef VipsForeignLoadClass VipsForeignLoadPpmClass; - -G_DEFINE_TYPE( VipsForeignLoadPpm, vips_foreign_load_ppm, - VIPS_TYPE_FOREIGN_LOAD ); - -static gboolean -vips_foreign_load_ppm_is_a( const char *filename ) -{ - VipsStreami *streami; - gboolean result; - - if( !(streami = vips_streami_new_from_filename( filename )) ) - return( FALSE ); - result = vips__ppm_isppm_stream( streami ); - VIPS_UNREF( streami ); - - return( result ); -} - -static VipsForeignFlags -vips_foreign_load_ppm_get_flags_filename( const char *filename ) -{ - VipsStreami *streami; - VipsStreamib *streamib; - VipsForeignFlags flags; - - if( !(streami = vips_streami_new_from_filename( filename )) ) - return( 0 ); - streamib = vips_streamib_new( streami ); - VIPS_UNREF( streami ); - - flags = vips__ppm_flags_stream( streamib ); - - VIPS_UNREF( streamib ); - - return( flags ); -} - -static VipsForeignFlags -vips_foreign_load_ppm_get_flags( VipsForeignLoad *load ) -{ - VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; - - return( vips_foreign_load_ppm_get_flags_filename( ppm->filename ) ); -} - -static int -vips_foreign_load_ppm_header( VipsForeignLoad *load ) -{ - VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; - - VipsStreami *streami; - VipsStreamib *streamib; - - if( !(streami = vips_streami_new_from_filename( ppm->filename )) ) - return( -1 ); - streamib = vips_streamib_new( streami ); - VIPS_UNREF( streami ); - - if( vips__ppm_header_stream( streamib, load->out ) ) { - VIPS_UNREF( streamib ); - return( -1 ); - } - - VIPS_UNREF( streamib ); - - return( 0 ); -} - -static int -vips_foreign_load_ppm_load( VipsForeignLoad *load ) -{ - VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; - - VipsStreami *streami; - VipsStreamib *streamib; - - if( !(streami = vips_streami_new_from_filename( ppm->filename )) ) - return( -1 ); - streamib = vips_streamib_new( streami ); - VIPS_UNREF( streami ); - - if( vips__ppm_load_stream( streamib, load->real ) ) { - VIPS_UNREF( streamib ); - return( -1 ); - } - - VIPS_UNREF( streamib ); - - return( 0 ); -} - -static void -vips_foreign_load_ppm_class_init( VipsForeignLoadPpmClass *class ) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS( class ); - VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsForeignClass *foreign_class = (VipsForeignClass *) 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 = "ppmload"; - object_class->description = _( "load ppm from file" ); - - foreign_class->suffs = vips__ppm_suffs; - - /* We are fast at is_a(), so high priority. - */ - foreign_class->priority = 200; - - load_class->is_a = vips_foreign_load_ppm_is_a; - load_class->get_flags_filename = - vips_foreign_load_ppm_get_flags_filename; - load_class->get_flags = vips_foreign_load_ppm_get_flags; - load_class->header = vips_foreign_load_ppm_header; - load_class->load = vips_foreign_load_ppm_load; - - VIPS_ARG_STRING( class, "filename", 1, - _( "Filename" ), - _( "Filename to load from" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignLoadPpm, filename ), - NULL ); -} - -static void -vips_foreign_load_ppm_init( VipsForeignLoadPpm *ppm ) -{ -} - -#endif /*HAVE_PPM*/ - -/** - * vips_ppmload: - * @filename: file to load - * @out: (out): output image - * @...: %NULL-terminated list of optional named arguments - * - * Read a PPM/PBM/PGM/PFM file into a VIPS image. - * - * It can read 1, 8, 16 and 32 bit images, colour or monochrome, - * stored in binary or in ASCII. One bit images become 8 bit VIPS images, - * with 0 and 255 for 0 and 1. - * - * See also: vips_image_new_from_file(). - * - * Returns: 0 on success, -1 on error. - */ -int -vips_ppmload( const char *filename, VipsImage **out, ... ) -{ - va_list ap; - int result; - - va_start( ap, out ); - result = vips_call_split( "ppmload", ap, filename, out ); - va_end( ap ); - - return( result ); -} - diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index f650e46e..d453e60c 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -1918,17 +1918,25 @@ vips_image_new_from_file( const char *name, ... ) /* Search with the new stream API first, then fall back to the older * mechanism in case the loader we need has not been converted yet. + * + * We need to hide any errors from this first phase. */ if( !(streami = vips_streami_new_from_filename( filename )) ) return( NULL ); - if( (operation_name = vips_foreign_find_load_stream( streami )) ) { + vips_error_freeze(); + operation_name = vips_foreign_find_load_stream( streami ); + vips_error_thaw(); + + if( operation_name ) { va_start( ap, name ); result = vips_call_split_option_string( operation_name, option_string, ap, streami, &out ); va_end( ap ); } else { + /* Fall back to the old file loader system. + */ if( !(operation_name = vips_foreign_find_load( filename )) ) return( NULL );