move ppm save into the class

no separate save function now
This commit is contained in:
John Cupitt 2019-11-15 10:23:45 +00:00
parent 7a047f5332
commit 17b994419b
13 changed files with 523 additions and 529 deletions

View File

@ -16,7 +16,6 @@ libforeign_la_SOURCES = \
radiance.c \
radload.c \
radsave.c \
ppm.c \
ppmload.c \
ppmsave.c \
csv.c \

View File

@ -1135,22 +1135,7 @@ build_scan_properties( VipsImage *image )
char *date;
int i;
#ifdef HAVE_DATE_TIME_FORMAT_ISO8601
{
GDateTime *now;
now = g_date_time_new_now_local();
date = g_date_time_format_iso8601( now );
g_date_time_unref( now );
}
#else /*!HAVE_DATE_TIME_FORMAT_ISO8601*/
{
GTimeVal now;
g_get_current_time( &now );
date = g_time_val_to_iso8601( &now );
}
#endif /*HAVE_DATE_TIME_FORMAT_ISO8601*/
date = vips__get_iso8601();
vips_dbuf_init( &dbuf );
vips_dbuf_writef( &dbuf, "<?xml version=\"1.0\"?>\n" );

View File

@ -1993,7 +1993,7 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_rad_stream_get_type( void );
extern GType vips_foreign_load_mat_get_type( void );
extern GType vips_foreign_load_ppm_file_get_type( void );
extern GType vips_foreign_save_ppm_get_type( void );
extern GType vips_foreign_save_ppm_file_get_type( void );
extern GType vips_foreign_load_png_get_type( void );
extern GType vips_foreign_load_png_buffer_get_type( void );
extern GType vips_foreign_load_png_stream_get_type( void );
@ -2077,7 +2077,7 @@ vips_foreign_operation_init( void )
#ifdef HAVE_PPM
vips_foreign_load_ppm_file_get_type();
vips_foreign_save_ppm_get_type();
vips_foreign_save_ppm_file_get_type();
#endif /*HAVE_PPM*/
#ifdef HAVE_RADIANCE

View File

@ -1,330 +0,0 @@
/* Read a ppm file.
*
* 4/2/10
* - gtkdoc
* 13/11/19
* - redone with streams
*/
/*
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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifdef HAVE_PPM
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pforeign.h"
struct _Write;
typedef int (*write_fn)( struct _Write *write, VipsPel *p );
/* What we track during a PPM write.
*/
typedef struct _Write {
VipsImage *in;
VipsStreamo *streamo;
write_fn fn;
} Write;
static void
write_destroy( Write *write )
{
if( write->streamo )
vips_streamo_finish( write->streamo );
VIPS_UNREF( write->streamo );
vips_free( write );
}
static Write *
write_new( VipsImage *in, VipsStreamo *streamo )
{
Write *write;
if( !(write = VIPS_NEW( NULL, Write )) )
return( NULL );
write->in = in;
write->streamo = streamo;
g_object_ref( streamo );
write->fn = NULL;
return( write );
}
static int
write_ppm_line_ascii( Write *write, VipsPel *p )
{
const int sk = VIPS_IMAGE_SIZEOF_PEL( write->in );
int x, k;
for( x = 0; x < write->in->Xsize; x++ ) {
for( k = 0; k < write->in->Bands; k++ ) {
switch( write->in->BandFmt ) {
case VIPS_FORMAT_UCHAR:
vips_streamo_writef( write->streamo,
"%d ", p[k] );
break;
case VIPS_FORMAT_USHORT:
vips_streamo_writef( write->streamo,
"%d ", ((unsigned short *) p)[k] );
break;
case VIPS_FORMAT_UINT:
vips_streamo_writef( write->streamo,
"%d ", ((unsigned int *) p)[k] );
break;
default:
g_assert_not_reached();
}
}
p += sk;
}
if( vips_streamo_writef( write->streamo, "\n" ) )
return( -1 );
return( 0 );
}
static int
write_ppm_line_ascii_squash( Write *write, VipsPel *p )
{
int x;
for( x = 0; x < write->in->Xsize; x++ )
vips_streamo_writef( write->streamo, "%d ", p[x] ? 0 : 1 );
if( vips_streamo_writef( write->streamo, "\n" ) )
return( -1 );
return( 0 );
}
static int
write_ppm_line_binary( Write *write, VipsPel *p )
{
if( vips_streamo_write( write->streamo,
p, VIPS_IMAGE_SIZEOF_LINE( write->in ) ) )
return( -1 );
return( 0 );
}
static int
write_ppm_line_binary_squash( Write *write, VipsPel *p )
{
int x;
int bits;
int n_bits;
bits = 0;
n_bits = 0;
for( x = 0; x < write->in->Xsize; x++ ) {
bits = VIPS_LSHIFT_INT( bits, 1 );
n_bits += 1;
bits |= p[x] ? 0 : 1;
if( n_bits == 8 ) {
if( VIPS_STREAMO_PUTC( write->streamo, bits ) )
return( -1 );
bits = 0;
n_bits = 0;
}
}
/* Flush any remaining bits in this line.
*/
if( n_bits &&
VIPS_STREAMO_PUTC( write->streamo, bits ) )
return( -1 );
return( 0 );
}
static int
write_ppm_block( VipsRegion *region, VipsRect *area, void *a )
{
Write *write = (Write *) a;
int i;
for( i = 0; i < area->height; i++ ) {
VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + i );
if( write->fn( write, p ) )
return( -1 );
}
return( 0 );
}
static int
write_ppm( Write *write, gboolean ascii, gboolean squash )
{
VipsImage *in = write->in;
char *magic;
time_t timebuf;
magic = "unset";
if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 3 )
magic = "PF";
else if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 1 )
magic = "Pf";
else if( in->Bands == 1 && ascii && squash )
magic = "P1";
else if( in->Bands == 1 && ascii )
magic = "P2";
else if( in->Bands == 1 && !ascii && squash )
magic = "P4";
else if( in->Bands == 1 && !ascii )
magic = "P5";
else if( in->Bands == 3 && ascii )
magic = "P3";
else if( in->Bands == 3 && !ascii )
magic = "P6";
else
g_assert_not_reached();
vips_streamo_writef( write->streamo, "%s\n", magic );
time( &timebuf );
vips_streamo_writef( write->streamo,
"#vips2ppm - %s\n", ctime( &timebuf ) );
vips_streamo_writef( write->streamo, "%d %d\n", in->Xsize, in->Ysize );
if( !squash )
switch( in->BandFmt ) {
case VIPS_FORMAT_UCHAR:
vips_streamo_writef( write->streamo,
"%d\n", UCHAR_MAX );
break;
case VIPS_FORMAT_USHORT:
vips_streamo_writef( write->streamo,
"%d\n", USHRT_MAX );
break;
case VIPS_FORMAT_UINT:
vips_streamo_writef( write->streamo,
"%d\n", UINT_MAX );
break;
case VIPS_FORMAT_FLOAT:
{
double scale;
if( vips_image_get_double( in, "pfm-scale", &scale ) )
scale = 1;
if( !vips_amiMSBfirst() )
scale *= -1;
vips_streamo_writef( write->streamo,
"%g\n", scale );
}
break;
default:
g_assert_not_reached();
}
if( squash )
write->fn = ascii ?
write_ppm_line_ascii_squash :
write_ppm_line_binary_squash;
else
write->fn = ascii ?
write_ppm_line_ascii :
write_ppm_line_binary;
if( vips_sink_disc( write->in, write_ppm_block, write ) )
return( -1 );
return( 0 );
}
int
vips__ppm_save_stream( VipsImage *in, VipsStreamo *streamo,
gboolean ascii, gboolean squash )
{
Write *write;
if( vips_check_uintorf( "vips2ppm", in ) ||
vips_check_bands_1or3( "vips2ppm", in ) ||
vips_check_uncoded( "vips2ppm", in ) ||
vips_image_pio_input( in ) )
return( -1 );
if( ascii &&
in->BandFmt == VIPS_FORMAT_FLOAT ) {
g_warning( "%s",
_( "float images must be binary -- disabling ascii" ) );
ascii = FALSE;
}
/* One bit images must come from a 8 bit, one band source.
*/
if( squash &&
(in->Bands != 1 ||
in->BandFmt != VIPS_FORMAT_UCHAR) ) {
g_warning( "%s",
_( "can only squash 1 band uchar images -- "
"disabling squash" ) );
squash = FALSE;
}
if( !(write = write_new( in, streamo )) )
return( -1 );
if( write_ppm( write, ascii, squash ) ) {
write_destroy( write );
return( -1 );
}
write_destroy( write );
return( 0 );
}
#endif /*HAVE_PPM*/

View File

@ -62,6 +62,12 @@
*/
/* TODO
*
* - make partial
* - only use mmap on filename streams?
*/
/*
#define DEBUG
*/
@ -147,110 +153,32 @@ vips_foreign_load_ppm_is_a_stream( VipsStreami *streami )
return( FALSE );
}
/* The largest number/field/whatever we can read.
*/
#define MAX_THING (80)
/* After this, the next getc will be the first char of the next line (or EOF).
*/
static int
skip_line( VipsStreamib *streamib )
{
int ch;
while( (ch = VIPS_STREAMIB_GETC( streamib )) != '\n' &&
ch != EOF )
;
if( ch == EOF )
return( -1 );
return( 0 );
}
/* After this, the next getc will be the first char of the next block of
* non-whitespace (or EOF).
*/
static int
skip_white_space( VipsStreamib *streamib )
{
int ch;
while( isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) )
;
VIPS_STREAMIB_UNGETC( streamib );
/* # skip comments too.
*/
if( ch == '#' &&
(skip_line( streamib ) ||
skip_white_space( streamib )) )
return( -1 );
return( 0 );
}
/* After this, the next getc will be the first char of the next block of
* whitespace (or EOF). buf will be filled with up to length bytes, and
* null-terminated.
*
* If the first getc is whitespace, stop instantly and return nothing.
*/
static int
read_non_white_space( VipsStreamib *streamib, char *buf, int length )
get_int( VipsStreamib *streamib, int *i )
{
int ch;
int i;
const char *txt;
for( i = 0; i < length - 1 &&
!isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
ch != EOF; i++ )
buf[i] = ch;
buf[i] = '\0';
if( vips_streamib_skip_whitespace( streamib ) ||
!(txt = vips_streamib_get_non_whitespace( streamib )) )
return( -1 );
/* If we stopped before seeing any whitespace, skip to the end of the
* block of non-whitespace.
*/
if( !isspace( ch ) )
while( !isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
ch != EOF )
;
/* If we finally stopped on whitespace, step back one so the next get
* will be whitespace (or EOF).
*/
if( isspace( ch ) )
VIPS_STREAMIB_UNGETC( streamib );
*i = atoi( txt );
return( 0 );
}
static int
read_int( VipsStreamib *streamib, int *i )
get_float( VipsStreamib *streamib, float *f )
{
char buf[MAX_THING];
const char *txt;
if( skip_white_space( streamib ) )
if( vips_streamib_skip_whitespace( streamib ) ||
!(txt = vips_streamib_get_non_whitespace( streamib )) )
return( -1 );
read_non_white_space( streamib, buf, MAX_THING );
*i = atoi( buf );
return( 0 );
}
static int
read_float( VipsStreamib *streamib, float *f )
{
char buf[MAX_THING];
if( skip_white_space( streamib ) )
return( -1 );
read_non_white_space( streamib, buf, MAX_THING );
/* We don't want the locale str -> float conversion.
*/
*f = g_ascii_strtod( buf, NULL );
*f = g_ascii_strtod( txt, NULL );
return( 0 );
}
@ -289,6 +217,9 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
1, 1, 1, 0, 0, 0, 0, 0
};
if( vips_streami_rewind( ppm->streami ) )
return( -1 );
/* Read in the magic number.
*/
buf[0] = VIPS_STREAMIB_GETC( ppm->streamib );
@ -312,8 +243,8 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
/* Read in size.
*/
if( read_int( ppm->streamib, &ppm->width ) ||
read_int( ppm->streamib, &ppm->height ) )
if( get_int( ppm->streamib, &ppm->width ) ||
get_int( ppm->streamib, &ppm->height ) )
return( -1 );
/* Read in max value / scale for >1 bit images.
@ -321,7 +252,7 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
if( ppm->bits > 1 ) {
if( ppm->index == 6 ||
ppm->index == 7 ) {
if( read_float( ppm->streamib, &ppm->scale ) )
if( get_float( ppm->streamib, &ppm->scale ) )
return( -1 );
/* Scale > 0 means big-endian.
@ -329,7 +260,7 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
ppm->msb_first = ppm->scale > 0;
}
else {
if( read_int( ppm->streamib, &ppm->max_value ) )
if( get_int( ppm->streamib, &ppm->max_value ) )
return( -1 );
if( ppm->max_value > 255 )
@ -445,6 +376,8 @@ vips_foreign_load_ppm_header( VipsForeignLoad *load )
vips_foreign_load_ppm_set_image( ppm, load->out );
vips_streami_minimise( ppm->streami );
return( 0 );
}
@ -499,7 +432,7 @@ load_1bit_ascii( VipsForeignLoadPpm *ppm, VipsImage *image )
for( x = 0; x < image->Xsize; x++ ) {
int val;
if( read_int( ppm->streamib, &val ) )
if( get_int( ppm->streamib, &val ) )
return( -1 );
if( val )
@ -567,7 +500,7 @@ load_ascii( VipsForeignLoadPpm *ppm, VipsImage *image )
for( x = 0; x < image->Xsize * image->Bands; x++ ) {
int val;
if( read_int( ppm->streamib, &val ) )
if( get_int( ppm->streamib, &val ) )
return( -1 );
switch( image->BandFmt ) {
@ -620,9 +553,12 @@ vips_foreign_load_ppm_load( VipsForeignLoad *load )
else
loader = load_ascii;
if( loader( ppm, load->real ) )
if( vips_streami_decode( ppm->streami ) ||
loader( ppm, load->real ) )
return( -1 );
vips_streami_minimise( ppm->streami );
return( 0 );
}

View File

@ -46,44 +46,292 @@
#include <string.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pforeign.h"
#ifdef HAVE_PPM
typedef struct _VipsForeignSavePpm VipsForeignSavePpm;
typedef int (*VipsSavePpmFn)( VipsForeignSavePpm *, VipsImage *, VipsPel * );
typedef struct _VipsForeignSavePpm {
VipsForeignSave parent_object;
char *filename;
VipsStreamo *streamo;
gboolean ascii;
gboolean squash;
VipsSavePpmFn fn;
} VipsForeignSavePpm;
typedef VipsForeignSaveClass VipsForeignSavePpmClass;
G_DEFINE_TYPE( VipsForeignSavePpm, vips_foreign_save_ppm,
G_DEFINE_ABSTRACT_TYPE( VipsForeignSavePpm, vips_foreign_save_ppm,
VIPS_TYPE_FOREIGN_SAVE );
static void
vips_foreign_save_ppm_dispose( GObject *gobject )
{
VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) gobject;
if( ppm->streamo )
vips_streamo_finish( ppm->streamo );
VIPS_UNREF( ppm->streamo );
G_OBJECT_CLASS( vips_foreign_save_ppm_parent_class )->
dispose( gobject );
}
static int
vips_foreign_save_ppm_line_ascii( VipsForeignSavePpm *ppm,
VipsImage *image, VipsPel *p )
{
const int n_elements = image->Xsize * image->Bands;
int i;
for( i = 0; i < n_elements; i++ ) {
switch( image->BandFmt ) {
case VIPS_FORMAT_UCHAR:
vips_streamo_writef( ppm->streamo,
"%d ", p[i] );
break;
case VIPS_FORMAT_USHORT:
vips_streamo_writef( ppm->streamo,
"%d ", ((unsigned short *) p)[i] );
break;
case VIPS_FORMAT_UINT:
vips_streamo_writef( ppm->streamo,
"%d ", ((unsigned int *) p)[i] );
break;
default:
g_assert_not_reached();
}
}
if( vips_streamo_writes( ppm->streamo, "\n" ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_save_ppm_line_ascii_squash( VipsForeignSavePpm *ppm,
VipsImage *image, VipsPel *p )
{
int x;
for( x = 0; x < image->Xsize; x++ )
vips_streamo_writef( ppm->streamo, "%d ", p[x] ? 0 : 1 );
if( vips_streamo_writes( ppm->streamo, "\n" ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_save_ppm_line_binary( VipsForeignSavePpm *ppm,
VipsImage *image, VipsPel *p )
{
if( vips_streamo_write( ppm->streamo,
p, VIPS_IMAGE_SIZEOF_LINE( image ) ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_save_ppm_line_binary_squash( VipsForeignSavePpm *ppm,
VipsImage *image, VipsPel *p )
{
int x;
int bits;
int n_bits;
bits = 0;
n_bits = 0;
for( x = 0; x < image->Xsize; x++ ) {
bits = VIPS_LSHIFT_INT( bits, 1 );
n_bits += 1;
bits |= p[x] ? 0 : 1;
if( n_bits == 8 ) {
if( VIPS_STREAMO_PUTC( ppm->streamo, bits ) )
return( -1 );
bits = 0;
n_bits = 0;
}
}
/* Flush any remaining bits in this line.
*/
if( n_bits &&
VIPS_STREAMO_PUTC( ppm->streamo, bits ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_save_ppm_block( VipsRegion *region, VipsRect *area, void *a )
{
VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) a;
VipsImage *image = region->im;
int i;
for( i = 0; i < area->height; i++ ) {
VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + i );
if( ppm->fn( ppm, image, p ) )
return( -1 );
}
return( 0 );
}
static int
vips_foreign_save_ppm( VipsForeignSavePpm *ppm, VipsImage *image )
{
char *magic;
char *date;
magic = "unset";
if( image->BandFmt == VIPS_FORMAT_FLOAT &&
image->Bands == 3 )
magic = "PF";
else if( image->BandFmt == VIPS_FORMAT_FLOAT &&
image->Bands == 1 )
magic = "Pf";
else if( image->Bands == 1 &&
ppm->ascii &&
ppm->squash )
magic = "P1";
else if( image->Bands == 1 &&
ppm->ascii )
magic = "P2";
else if( image->Bands == 1 &&
!ppm->ascii &&
ppm->squash )
magic = "P4";
else if( image->Bands == 1 &&
!ppm->ascii )
magic = "P5";
else if( image->Bands == 3 &&
ppm->ascii )
magic = "P3";
else if( image->Bands == 3 &&
!ppm->ascii )
magic = "P6";
else
g_assert_not_reached();
vips_streamo_writef( ppm->streamo, "%s\n", magic );
date = vips__get_iso8601();
vips_streamo_writef( ppm->streamo,
"#vips2ppm - %s\n", date );
g_free( date );
vips_streamo_writef( ppm->streamo,
"%d %d\n", image->Xsize, image->Ysize );
if( !ppm->squash )
switch( image->BandFmt ) {
case VIPS_FORMAT_UCHAR:
vips_streamo_writef( ppm->streamo,
"%d\n", UCHAR_MAX );
break;
case VIPS_FORMAT_USHORT:
vips_streamo_writef( ppm->streamo,
"%d\n", USHRT_MAX );
break;
case VIPS_FORMAT_UINT:
vips_streamo_writef( ppm->streamo,
"%d\n", UINT_MAX );
break;
case VIPS_FORMAT_FLOAT:
{
double scale;
char buf[G_ASCII_DTOSTR_BUF_SIZE];
if( vips_image_get_double( image,
"pfm-scale", &scale ) )
scale = 1;
if( !vips_amiMSBfirst() )
scale *= -1;
/* Need to be locale independent.
*/
g_ascii_dtostr( buf, G_ASCII_DTOSTR_BUF_SIZE, scale );
vips_streamo_writes( ppm->streamo, buf );
}
break;
default:
g_assert_not_reached();
}
if( ppm->squash )
ppm->fn = ppm->ascii ?
vips_foreign_save_ppm_line_ascii_squash :
vips_foreign_save_ppm_line_binary_squash;
else
ppm->fn = ppm->ascii ?
vips_foreign_save_ppm_line_ascii :
vips_foreign_save_ppm_line_binary;
if( vips_sink_disc( image, vips_foreign_save_ppm_block, ppm ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_save_ppm_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object;
VipsStreamo *streamo;
VipsImage *image;
if( VIPS_OBJECT_CLASS( vips_foreign_save_ppm_parent_class )->
build( object ) )
return( -1 );
if( !(streamo = vips_streamo_new_to_filename( ppm->filename )) )
return( -1 );
if( vips__ppm_save_stream( save->ready, streamo,
ppm->ascii, ppm->squash ) ) {
VIPS_UNREF( streamo );
image = save->ready;
if( vips_check_uintorf( "vips2ppm", image ) ||
vips_check_bands_1or3( "vips2ppm", image ) ||
vips_check_uncoded( "vips2ppm", image ) ||
vips_image_pio_input( image ) )
return( -1 );
if( ppm->ascii &&
image->BandFmt == VIPS_FORMAT_FLOAT ) {
g_warning( "%s",
_( "float images must be binary -- disabling ascii" ) );
ppm->ascii = FALSE;
}
VIPS_UNREF( streamo );
/* One bit images must come from a 8 bit, one band source.
*/
if( ppm->squash &&
(image->Bands != 1 ||
image->BandFmt != VIPS_FORMAT_UCHAR) ) {
g_warning( "%s",
_( "can only squash 1 band uchar images -- "
"disabling squash" ) );
ppm->squash = FALSE;
}
if( vips_foreign_save_ppm( ppm, image ) )
return( -1 );
return( 0 );
}
@ -114,11 +362,12 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class )
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->dispose = vips_foreign_save_ppm_dispose;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "ppmsave";
object_class->description = _( "save image to ppm file" );
object_class->nickname = "ppmsave_base";
object_class->description = _( "save to ppm" );
object_class->build = vips_foreign_save_ppm_build;
foreign_class->suffs = vips__ppm_suffs;
@ -126,13 +375,6 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class )
save_class->saveable = VIPS_SAVEABLE_RGB;
save_class->format_table = bandfmt_ppm;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSavePpm, filename ),
NULL );
VIPS_ARG_BOOL( class, "ascii", 10,
_( "ASCII" ),
_( "save as ascii" ),
@ -146,6 +388,7 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSavePpm, squash ),
FALSE );
}
static void
@ -153,6 +396,60 @@ vips_foreign_save_ppm_init( VipsForeignSavePpm *ppm )
{
}
typedef struct _VipsForeignSavePpmFile {
VipsForeignSavePpm parent_object;
char *filename;
} VipsForeignSavePpmFile;
typedef VipsForeignSavePpmClass VipsForeignSavePpmFileClass;
G_DEFINE_TYPE( VipsForeignSavePpmFile, vips_foreign_save_ppm_file,
vips_foreign_save_ppm_get_type() );
static int
vips_foreign_save_ppm_file_build( VipsObject *object )
{
VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object;
VipsForeignSavePpmFile *file = (VipsForeignSavePpmFile *) object;
if( file->filename &&
!(ppm->streamo =
vips_streamo_new_to_filename( file->filename )) )
return( -1 );
return( VIPS_OBJECT_CLASS( vips_foreign_save_ppm_file_parent_class )->
build( object ) );
}
static void
vips_foreign_save_ppm_file_class_init( VipsForeignSavePpmFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "ppmsave";
object_class->description = _( "save image to ppm file" );
object_class->build = vips_foreign_save_ppm_file_build;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSavePpmFile, filename ),
NULL );
}
static void
vips_foreign_save_ppm_file_init( VipsForeignSavePpmFile *file )
{
}
#endif /*HAVE_PPM*/
/**

View File

@ -506,11 +506,11 @@ getheader( /* get header from file */
)
{
for(;;) {
const unsigned char *line;
const char *line;
if( !(line = vips_streamib_get_line( streamib )) )
return( -1 );
if( strcmp( (char *) line, "" ) == 0 )
if( strcmp( line, "" ) == 0 )
/* Blank line. We've parsed the header successfully.
*/
break;
@ -725,14 +725,14 @@ int
vips__rad_israd( VipsStreami *streami )
{
VipsStreamib *streamib;
const unsigned char *line;
const char *line;
int result;
/* Just test that the first line is the magic string.
*/
streamib = vips_streamib_new( streami );
result = (line = vips_streamib_get_line( streamib )) &&
strcmp( (char *) line, "#?RADIANCE" ) == 0;
strcmp( line, "#?RADIANCE" ) == 0;
VIPS_UNREF( streamib );
return( result );
@ -832,7 +832,7 @@ static int
rad2vips_get_header( Read *read, VipsImage *out )
{
VipsInterpretation interpretation;
const unsigned char *line;
const char *line;
int width;
int height;
int i, j;
@ -1082,7 +1082,7 @@ vips2rad_put_header( Write *write )
{
vips2rad_make_header( write );
vips_streamo_writef( write->streamo, "#?RADIANCE\n" );
vips_streamo_writes( write->streamo, "#?RADIANCE\n" );
vips_streamo_writef( write->streamo, "%s%s\n", FMTSTR, write->format );
vips_streamo_writef( write->streamo, "%s%e\n", EXPOSSTR, write->expos );
vips_streamo_writef( write->streamo,
@ -1099,9 +1099,9 @@ vips2rad_put_header( Write *write )
write->prims[GRN][CIEX], write->prims[GRN][CIEY],
write->prims[BLU][CIEX], write->prims[BLU][CIEY],
write->prims[WHT][CIEX], write->prims[WHT][CIEY] );
vips_streamo_writef( write->streamo, "\n" );
vips_streamo_writef( write->streamo,
"%s", resolu2str( resolu_buf, &write->rs ) );
vips_streamo_writes( write->streamo, "\n" );
vips_streamo_writes( write->streamo,
resolu2str( resolu_buf, &write->rs ) );
return( 0 );
}

View File

@ -297,8 +297,10 @@ int vips_streamib_require( VipsStreamib *streamib, int require );
#define VIPS_STREAMIB_PEEK( S ) ((S)->input_buffer + (S)->read_point)
#define VIPS_STREAMIB_FETCH( S ) ((S)->input_buffer[(S)->read_point++])
const unsigned char *vips_streamib_get_line( VipsStreamib *streamib );
unsigned char *vips_streamib_get_line_copy( VipsStreamib *streamib );
const char *vips_streamib_get_line( VipsStreamib *streamib );
char *vips_streamib_get_line_copy( VipsStreamib *streamib );
const char *vips_streamib_get_non_whitespace( VipsStreamib *streamib );
int vips_streamib_skip_whitespace( VipsStreamib *streamib );
#define VIPS_TYPE_STREAMIW (vips_streamiw_get_type())
#define VIPS_STREAMIW( obj ) \
@ -400,13 +402,12 @@ int vips_streamo_write( VipsStreamo *streamo, const void *data, size_t length );
void vips_streamo_finish( VipsStreamo *streamo );
int vips_streamo_putc( VipsStreamo *streamo, int ch );
#define VIPS_STREAMO_PUTC( S, C ) ( \
(S)->write_point <= VIPS_STREAMO_BUFFER_SIZE ? \
((S)->output_buffer[(S)->write_point++] = (C), 0) : \
vips_streamo_putc( (S), (C) ) \
)
int vips_streamo_writes( VipsStreamo *streamo, const char *str );
int vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... )
__attribute__((format(printf, 2, 3)));

View File

@ -344,6 +344,8 @@ guint32 vips__random_add( guint32 seed, int value );
const char *vips__icc_dir( void );
const char *vips__windows_prefix( void );
char *vips__get_iso8601( void );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -47,6 +47,7 @@
#include <vips/intl.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -326,11 +327,11 @@ vips_streamib_require( VipsStreamib *streamib, int require )
* slower vips_streamib_get_line_copy().
*
* The return value is owned by @streamib and must not be freed. It
* is valid until the next call to vips_streamib_get_line().
* is valid until the next get call @streamib.
*
* Returns: the next line from the file, or NULL on EOF or read error.
* Returns: the next line of text, or NULL on EOF or read error.
*/
const unsigned char *
const char *
vips_streamib_get_line( VipsStreamib *streamib )
{
int write_point;
@ -379,7 +380,7 @@ vips_streamib_get_line( VipsStreamib *streamib )
VIPS_DEBUG_MSG( " %s\n", streamib->line );
return( streamib->line );
return( (const char *) streamib->line );
}
/**
@ -395,9 +396,9 @@ vips_streamib_get_line( VipsStreamib *streamib )
* This is slower than vips_streamib_get_line(), but can work with lines of
* any length.
*
* Returns: the next line from the file, or NULL on EOF or read error.
* Returns: the next line of text, or NULL on EOF or read error.
*/
unsigned char *
char *
vips_streamib_get_line_copy( VipsStreamib *streamib )
{
static const unsigned char null = '\0';
@ -406,7 +407,7 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
GByteArray *buffer;
int ch;
unsigned char *result;
char *result;
buffer = g_byte_array_new();
@ -435,9 +436,87 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
g_byte_array_append( buffer, &null, 1 );
result = (unsigned char *) g_byte_array_free( buffer, FALSE );
result = (char *) g_byte_array_free( buffer, FALSE );
VIPS_DEBUG_MSG( " %s\n", result );
return( result );
}
/**
* vips_streamib_get_non_whitespace:
* @streamib: stream to operate on
*
* Fetch the next chunk of non-whitespace text from the stream, and
* null-terminate it.
*
* After this, the next getc will be the first char of the next block of
* whitespace (or EOF).
*
* If the first getc is whitespace, stop instantly and return the empty
* string.
*
* If the item is longer than some arbitrary (but large) limit, it is
* truncated.
*
* The return value is owned by @streamib and must not be freed. It
* is valid until the next get call @streamib.
*
* Returns: the next block of non-whitespace, or NULL on EOF or read error.
*/
const char *
vips_streamib_get_non_whitespace( VipsStreamib *streamib )
{
int ch;
int i;
for( i = 0; i < VIPS_STREAMIB_BUFFER_SIZE &&
!isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
ch != EOF; i++ )
streamib->line[i] = ch;
streamib->line[i] = '\0';
/* If we stopped before seeing any whitespace, skip to the end of the
* block of non-whitespace.
*/
if( !isspace( ch ) )
while( !isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
ch != EOF )
;
/* If we finally stopped on whitespace, step back one so the next get
* will be whitespace (or EOF).
*/
if( isspace( ch ) )
VIPS_STREAMIB_UNGETC( streamib );
return( (const char *) streamib->line );
}
/**
* vips_streamib_skip_whitespace:
* @streamib: stream to operate on
*
* After this, the next getc will be the first char of the next block of
* non-whitespace (or EOF).
*
* Returns: 0 on success, -1 on error.
*/
int
vips_streamib_skip_whitespace( VipsStreamib *streamib )
{
int ch;
while( isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) )
;
VIPS_STREAMIB_UNGETC( streamib );
/* # skip comments too.
*/
if( ch == '#' &&
(!vips_streamib_get_line( streamib ) ||
vips_streamib_skip_whitespace( streamib )) )
return( -1 );
return( 0 );
}

View File

@ -402,35 +402,6 @@ vips_streamo_finish( VipsStreamo *streamo )
class->finish( streamo );
}
/**
* vips_streamo_writef:
* @streamo: output stream to operate on
* @fmt: <function>printf()</function>-style format string
* @...: arguments to format string
*
* Format the string and write to @streamo.
*
* Returns: 0 on success, and -1 on error.
*/
int
vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... )
{
va_list ap;
char *line;
int result;
va_start( ap, fmt );
line = g_strdup_vprintf( fmt, ap );
va_end( ap );
result = vips_streamo_write( streamo,
(unsigned char *) line, strlen( line ) );
g_free( line );
return( result );
}
/**
* vips_streamo_putc:
* @streamo: output stream to operate on
@ -455,6 +426,50 @@ vips_streamo_putc( VipsStreamo *streamo, int ch )
return( 0 );
}
/**
* vips_streamo_writes:
* @streamo: output stream to operate on
* @str: string to write
*
* Write a null-terminated string to @streamo.
*
* Returns: 0 on success, and -1 on error.
*/
int
vips_streamo_writes( VipsStreamo *streamo, const char *str )
{
return( vips_streamo_write( streamo,
(unsigned char *) str, strlen( str ) ) );
}
/**
* vips_streamo_writef:
* @streamo: output stream to operate on
* @fmt: <function>printf()</function>-style format string
* @...: arguments to format string
*
* Format the string and write to @streamo.
*
* Returns: 0 on success, and -1 on error.
*/
int
vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... )
{
va_list ap;
char *line;
int result;
va_start( ap, fmt );
line = g_strdup_vprintf( fmt, ap );
va_end( ap );
result = vips_streamo_writes( streamo, line );
g_free( line );
return( result );
}
/**
* vips_streamo_write_amp:
* @streamo: output stream to operate on

View File

@ -2024,3 +2024,28 @@ vips__windows_prefix( void )
return( (const char *) g_once( &once,
(GThreadFunc) vips__windows_prefix_once, NULL ) );
}
char *
vips__get_iso8601( void )
{
char *date;
#ifdef HAVE_DATE_TIME_FORMAT_ISO8601
{
GDateTime *now;
now = g_date_time_new_now_local();
date = g_date_time_format_iso8601( now );
g_date_time_unref( now );
}
#else /*!HAVE_DATE_TIME_FORMAT_ISO8601*/
{
GTimeVal now;
g_get_current_time( &now );
date = g_time_val_to_iso8601( &now );
}
#endif /*HAVE_DATE_TIME_FORMAT_ISO8601*/
return( date );
}

View File

@ -957,22 +957,7 @@ vips__xml_properties( VipsImage *image )
VipsDbuf dbuf;
char *date;
#ifdef HAVE_DATE_TIME_FORMAT_ISO8601
{
GDateTime *now;
now = g_date_time_new_now_local();
date = g_date_time_format_iso8601( now );
g_date_time_unref( now );
}
#else /*!HAVE_DATE_TIME_FORMAT_ISO8601*/
{
GTimeVal now;
g_get_current_time( &now );
date = g_time_val_to_iso8601( &now );
}
#endif /*HAVE_DATE_TIME_FORMAT_ISO8601*/
date = vips__get_iso8601();
vips_dbuf_init( &dbuf );
vips_dbuf_writef( &dbuf, "<?xml version=\"1.0\"?>\n" );