add load/save jpeg buffer

This commit is contained in:
John Cupitt 2011-11-29 18:13:14 +00:00
parent 099c0c30d6
commit 5bf5a3f2ba
4 changed files with 303 additions and 219 deletions

119
TODO
View File

@ -1,118 +1,3 @@
- argh this is horrible
how about adding a property 'fileloader' ... define this and your object
will be tested by vips_foreign_find_load()
or! put is_a etc. in VipsForeign but only set them for classes which support
it and leave NULL otherwise
consider just properties ... at the moment we have:
VipsForeign (filename)
VipsForeignLoad (disc, flags)
VipsForeignLoadJpeg (shrink, fail)
VipsForeignLoadVips
VipsForeignSave (in)
VipsForeignSaveJpeg (Q, profile)
VipsForeignSaveVips
how about:
VipsForeign
VipsForeignLoad (disc, flags)
VipsForeignLoadJpeg (shrink, fail)
VipsForeignLoadJpegBuffer (buffer)
VipsForeignLoadJpegFile (filename)
VipsForeignLoadVips (source-filename)
VipsForeignLoadTiff (source-filename, page)
VipsForeignSave (in)
VipsForeignSaveJpeg (Q, profile)
VipsForeignSaveJpegFile (filename)
VipsForeignSaveJpegBuffer (buffer)
VipsForeignSaveVips (dest-filename)
VipsForeignSaveTiff (dest-filename, pyramid, comp, etc.)
so all we do is nmove the filename prop of the load/save subclasses, not too
bad
- we can make the interfaces we need much simpler if we use properties for all
data members ... eg. fetch "flags" property if we can
put 'priority' in VipsForeignClass
interfaces become
interface load (header, load)
interface load-from-file (is_a)
interface load-from-buffer (buffer)
interface save (ready, saveable, format_table)
interface save-to-file (filename, suffs)
interface save-to-buffer (buffer)
classes are
VipsForeign (priority)
VipsForeignLoad (disc, flags, out, real, get_flags, header, load)
VipsForeignLoadJpeg (shrink, fail)
VipsForeignLoadJpegFile (filename, is_a)
VipsForeignLoadJpegBuffer (buffer)
VipsForeignSave (in, ready, saveable, format_table)
VipsForeignSaveJpeg (Q, profile)
VipsForeignSaveJpegFile (filename, suffs)
VipsForeignSaveJpegBuffer (buffer)
- at the moment we have:
VipsFile (filename)
VipsFileLoad (disc, flags)
VipsFileLoadJpeg (shrink, fail)
VipsFileSave (in)
VipsFileSaveJpeg (Q, profile)
we want jpeg*_buffer to have everything jpeg* has, except filename and
suffs
reorganise as
VipsForeign (priority)
VipsForeignLoad (disc, flags, out, real, get_flags, header, load)
VipsForeignLoadJpeg (shrink, fail)
VipsForeignLoadJpegFile (filename, is_a)
VipsForeignLoadJpegBuffer (buffer)
VipsForeignSave (in, ready, saveable, format_table)
VipsForeignSaveJpeg (Q, profile)
VipsForeignSaveJpegFile (filename, suffs)
VipsForeignSaveJpegBuffer (buffer)
how do we do 'pick a loader by filename'? we need to find all subclasses of
VipsForeign which implement suffs?
we're going to need to register loaders and savers on a separate list
somewhere :-(
or have load-from-file as an interface?
interface load (priority, disc, flags, out, get_flags, header, load)
interface load-from-file (filename, is_a)
interface load-from-buffer (buffer)
interface save (priority, in, ready, saveable, format_table)
interface save-to-file (filename, suffs)
interface save-to-buffer (buffer)
then walk VipsForeign and test whether each class implements load-from-file
can interfaces have data members?
read up on gobject interfaces
- test vips_foreign_load_vips_get_flags(), sense inverted?
we have various printf()s left in the byteswap codepath
@ -121,9 +6,7 @@
- add classes for read and write jpeg buffers
make compat wrappers for old im_jpeg2vips() and im_vips2jpeg()
- make compat wrappers for old im_jpeg2vips() and im_vips2jpeg()
make sure we are using the operation cache for jpegload

View File

@ -365,11 +365,11 @@ vips_foreign_load_new_from_foreign_sub( VipsForeignLoadClass *load_class,
{
VipsForeignClass *class = VIPS_FOREIGN_CLASS( load_class );
if( load_class->is_a ) {
if( load_class->is_a( filename ) )
return( load_class );
}
else if( vips_filename_suffix_match( filename, class->suffs ) )
if( load_class->is_a &&
load_class->is_a( filename ) )
return( load_class );
else if( class->suffs &&
vips_filename_suffix_match( filename, class->suffs ) )
return( load_class );
return( NULL );
@ -651,7 +651,8 @@ vips_foreign_save_new_from_foreignname_sub( VipsForeignSaveClass *save_class,
{
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
if( vips_filename_suffix_match( filename, class->suffs ) )
if( class->suffs &&
vips_filename_suffix_match( filename, class->suffs ) )
return( save_class );
return( NULL );
@ -1010,14 +1011,18 @@ vips_foreign_write( VipsImage *in, const char *filename, ... )
void
vips_foreign_operation_init( void )
{
extern GType vips_foreign_load_jpeg_get_type( void );
extern GType vips_foreign_save_jpeg_get_type( void );
extern GType vips_foreign_load_jpeg_file_get_type( void );
extern GType vips_foreign_load_jpeg_buffer_get_type( void );
extern GType vips_foreign_save_jpeg_file_get_type( void );
extern GType vips_foreign_save_jpeg_buffer_get_type( void );
extern GType vips_foreign_load_vips_get_type( void );
extern GType vips_foreign_save_vips_get_type( void );
#ifdef HAVE_JPEG
vips_foreign_load_jpeg_get_type();
vips_foreign_save_jpeg_get_type();
vips_foreign_load_jpeg_file_get_type();
vips_foreign_load_jpeg_buffer_get_type();
vips_foreign_save_jpeg_file_get_type();
vips_foreign_save_jpeg_buffer_get_type();
#endif /*HAVE_JPEG*/
vips_foreign_load_vips_get_type();
vips_foreign_save_vips_get_type();

View File

@ -2,6 +2,8 @@
*
* 24/11/11
* - wrap a class around the jpeg writer
* 29/11/11
* - split to make load, load from buffer and load from file
*/
/*
@ -90,15 +92,11 @@ typedef struct _VipsForeignLoadJpeg {
*/
gboolean fail;
/* For some jpeg CMYK formats we have to invert pels on read.
*/
gboolean invert_pels;
} VipsForeignLoadJpeg;
typedef VipsForeignLoadClass VipsForeignLoadJpegClass;
G_DEFINE_TYPE( VipsForeignLoadJpeg, vips_foreign_load_jpeg,
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadJpeg, vips_foreign_load_jpeg,
VIPS_TYPE_FOREIGN_LOAD );
static int
@ -122,68 +120,19 @@ vips_foreign_load_jpeg_build( VipsObject *object )
return( 0 );
}
static gboolean
vips_foreign_load_jpeg_is_a( const char *filename )
{
return( vips__isjpeg( filename ) );
}
/* Read just the image header into ->out.
*/
static int
vips_foreign_load_jpeg_header( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
if( vips__jpeg_read_file( jpeg->filename, load->out,
TRUE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_jpeg_load( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
if( vips__jpeg_read_file( jpeg->filename, load->real,
FALSE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
static void
vips_foreign_load_jpeg_class_init( VipsForeignLoadJpegClass *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 = "jpegload";
object_class->description = _( "load jpeg from file" );
object_class->nickname = "jpegload_base";
object_class->description = _( "load jpeg" );
object_class->build = vips_foreign_load_jpeg_build;
foreign_class->suffs = jpeg_suffs;
load_class->is_a = vips_foreign_load_jpeg_is_a;
load_class->header = vips_foreign_load_jpeg_header;
load_class->load = vips_foreign_load_jpeg_load;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJpeg, filename ),
NULL );
VIPS_ARG_INT( class, "shrink", 10,
_( "Shrink" ),
_( "Shrink factor on load" ),
@ -205,3 +154,153 @@ vips_foreign_load_jpeg_init( VipsForeignLoadJpeg *jpeg )
jpeg->shrink = 1;
}
typedef struct _VipsForeignLoadJpegFile {
VipsForeignLoadJpeg parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignLoadJpegFile;
typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass;
G_DEFINE_TYPE( VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file,
vips_foreign_load_jpeg_get_type() );
static gboolean
vips_foreign_load_jpeg_file_is_a( const char *filename )
{
return( vips__isjpeg( filename ) );
}
static int
vips_foreign_load_jpeg_file_header( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load;
if( vips__jpeg_read_file( file->filename, load->out,
TRUE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_jpeg_file_load( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load;
if( vips__jpeg_read_file( file->filename, load->real,
FALSE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
static void
vips_foreign_load_jpeg_file_class_init( VipsForeignLoadJpegFileClass *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 = "jpegload";
object_class->description = _( "load jpeg from file" );
foreign_class->suffs = jpeg_suffs;
load_class->is_a = vips_foreign_load_jpeg_file_is_a;
load_class->header = vips_foreign_load_jpeg_file_header;
load_class->load = vips_foreign_load_jpeg_file_load;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJpegFile, filename ),
NULL );
}
static void
vips_foreign_load_jpeg_file_init( VipsForeignLoadJpegFile *file )
{
}
typedef struct _VipsForeignLoadJpegBuffer {
VipsForeignLoadJpeg parent_object;
/* Load from a buffer.
*/
VipsArea *buf;
} VipsForeignLoadJpegBuffer;
typedef VipsForeignLoadJpegClass VipsForeignLoadJpegBufferClass;
G_DEFINE_TYPE( VipsForeignLoadJpegBuffer, vips_foreign_load_jpeg_buffer,
vips_foreign_load_jpeg_get_type() );
static int
vips_foreign_load_jpeg_buffer_header( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load;
if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length,
load->out, TRUE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_jpeg_buffer_load( VipsForeignLoad *load )
{
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load;
if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length,
load->real, FALSE, jpeg->shrink, jpeg->fail ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_jpeg_buffer_class_init(
VipsForeignLoadJpegBufferClass *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 = "jpegload_buffer";
object_class->description = _( "load jpeg from buffer" );
load_class->header = vips_foreign_load_jpeg_buffer_header;
load_class->load = vips_foreign_load_jpeg_buffer_load;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJpegBuffer, buf ),
VIPS_TYPE_BLOB );
}
static void
vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer )
{
}

View File

@ -78,10 +78,6 @@
typedef struct _VipsForeignSaveJpeg {
VipsForeignSave parent_object;
/* Filename for load.
*/
char *filename;
/* Quality factor.
*/
int Q;
@ -94,24 +90,8 @@ typedef struct _VipsForeignSaveJpeg {
typedef VipsForeignSaveClass VipsForeignSaveJpegClass;
G_DEFINE_TYPE( VipsForeignSaveJpeg, vips_foreign_save_jpeg, VIPS_TYPE_FOREIGN_SAVE );
static int
vips_foreign_save_jpeg_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object;
if( VIPS_OBJECT_CLASS( vips_foreign_save_jpeg_parent_class )->
build( object ) )
return( -1 );
if( vips__jpeg_write_file( save->ready, jpeg->filename,
jpeg->Q, jpeg->profile ) )
return( -1 );
return( 0 );
}
G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveJpeg, vips_foreign_save_jpeg,
VIPS_TYPE_FOREIGN_SAVE );
#define UC VIPS_FORMAT_UCHAR
@ -127,28 +107,17 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jpegsave";
object_class->description = _( "save image to jpeg file" );
object_class->build = vips_foreign_save_jpeg_build;
foreign_class->suffs = vips__jpeg_suffs;
object_class->nickname = "jpegsave_base";
object_class->description = _( "save jpeg" );
save_class->saveable = VIPS_SAVEABLE_RGB_CMYK;
save_class->format_table = bandfmt_jpeg;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpeg, filename ),
NULL );
VIPS_ARG_INT( class, "Q", 10,
_( "Q" ),
_( "Q factor" ),
@ -169,3 +138,131 @@ vips_foreign_save_jpeg_init( VipsForeignSaveJpeg *jpeg )
{
jpeg->Q = 75;
}
typedef struct _VipsForeignSaveJpegFile {
VipsForeignSaveJpeg parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignSaveJpegFile;
typedef VipsForeignSaveJpegClass VipsForeignSaveJpegFileClass;
G_DEFINE_TYPE( VipsForeignSaveJpegFile, vips_foreign_save_jpeg_file,
vips_foreign_save_jpeg_get_type() );
static int
vips_foreign_save_jpeg_file_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object;
VipsForeignSaveJpegFile *file = (VipsForeignSaveJpegFile *) object;
if( VIPS_OBJECT_CLASS( vips_foreign_save_jpeg_parent_class )->
build( object ) )
return( -1 );
if( vips__jpeg_write_file( save->ready, file->filename,
jpeg->Q, jpeg->profile ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_save_jpeg_file_class_init( VipsForeignSaveJpegFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "jpegsave";
object_class->description = _( "save image to jpeg file" );
object_class->build = vips_foreign_save_jpeg_file_build;
foreign_class->suffs = vips__jpeg_suffs;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpegFile, filename ),
NULL );
}
static void
vips_foreign_save_jpeg_file_init( VipsForeignSaveJpegFile *file )
{
}
typedef struct _VipsForeignSaveJpegBuffer {
VipsForeignSaveJpeg parent_object;
/* Save to a buffer.
*/
VipsArea *buf;
} VipsForeignSaveJpegBuffer;
typedef VipsForeignSaveJpegClass VipsForeignSaveJpegBufferClass;
G_DEFINE_TYPE( VipsForeignSaveJpegBuffer, vips_foreign_save_jpeg_buffer,
vips_foreign_save_jpeg_get_type() );
static int
vips_foreign_save_jpeg_buffer_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object;
VipsForeignSaveJpegBuffer *file = (VipsForeignSaveJpegBuffer *) object;
void *obuf;
size_t olen;
VipsArea *area;
if( VIPS_OBJECT_CLASS( vips_foreign_save_jpeg_parent_class )->
build( object ) )
return( -1 );
if( vips__jpeg_write_buffer( save->ready,
&obuf, &olen, jpeg->Q, jpeg->profile ) )
return( -1 );
area = vips_area_new_blob( (VipsCallbackFn) vips_free, obuf, olen );
g_object_set( file, "buf", area, NULL );
return( 0 );
}
static void
vips_foreign_save_jpeg_buffer_class_init(
VipsForeignSaveJpegBufferClass *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 = "jpegsave_buffer";
object_class->description = _( "save image to jpeg buffer" );
object_class->build = vips_foreign_save_jpeg_buffer_build;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to save to" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpegBuffer, buf ),
VIPS_TYPE_BLOB );
}
static void
vips_foreign_save_jpeg_buffer_init( VipsForeignSaveJpegBuffer *file )
{
}