revised jpeg binding works
This commit is contained in:
parent
ee17946bf9
commit
f7c34a369e
6
TODO
6
TODO
@ -1,8 +1,4 @@
|
|||||||
- fix up jpeg2vips.c
|
- add classes to read and write jpeg buffers
|
||||||
|
|
||||||
fix up jpegload.c
|
|
||||||
|
|
||||||
added 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()
|
||||||
|
|
||||||
|
@ -913,9 +913,6 @@ static int
|
|||||||
vips_file_save_build( VipsObject *object )
|
vips_file_save_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
VipsFileSave *save = VIPS_FILE_SAVE( object );
|
VipsFileSave *save = VIPS_FILE_SAVE( object );
|
||||||
/*
|
|
||||||
VipsFile *file = VIPS_FILE( object );
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( vips_file_convert_saveable( save ) )
|
if( vips_file_convert_saveable( save ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
@ -47,13 +47,15 @@ typedef struct {
|
|||||||
FILE *fp; /* fclose() if non-NULL */
|
FILE *fp; /* fclose() if non-NULL */
|
||||||
} ErrorManager;
|
} ErrorManager;
|
||||||
|
|
||||||
|
extern const char *vips__jpeg_suffs[];
|
||||||
|
|
||||||
void vips__new_output_message( j_common_ptr cinfo );
|
void vips__new_output_message( j_common_ptr cinfo );
|
||||||
void vips__new_error_exit( j_common_ptr cinfo );
|
void vips__new_error_exit( j_common_ptr cinfo );
|
||||||
|
|
||||||
int vips__jpeg_write_file( VipsImage *in,
|
int vips__jpeg_write_file( VipsImage *in,
|
||||||
const char *filename, int Q, const char *profile );
|
const char *filename, int Q, const char *profile );
|
||||||
int vips__jpeg_write_buffer( VipsImage *in,
|
int vips__jpeg_write_buffer( VipsImage *in,
|
||||||
void **obuf, int *olen, int Q, const char *profile );
|
void **obuf, size_t *olen, int Q, const char *profile );
|
||||||
|
|
||||||
int vips__isjpeg( const char *filename );
|
int vips__isjpeg( const char *filename );
|
||||||
int vips__jpeg_read_file( const char *name, VipsImage *out,
|
int vips__jpeg_read_file( const char *name, VipsImage *out,
|
||||||
|
@ -728,12 +728,9 @@ read_jpeg_image( struct jpeg_decompress_struct *cinfo, IMAGE *out,
|
|||||||
/* Read a JPEG file into a VIPS image.
|
/* Read a JPEG file into a VIPS image.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
vips__jpeg2vips( const char *name, VipsImage *out, gboolean header_only,
|
vips__jpeg_read_file( const char *name, VipsImage *out, gboolean header_only,
|
||||||
int shrink, gboolean fail )
|
int shrink, gboolean fail )
|
||||||
{
|
{
|
||||||
char filename[FILENAME_MAX];
|
|
||||||
char mode[FILENAME_MAX];
|
|
||||||
char *p, *q;
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
struct jpeg_decompress_struct cinfo;
|
||||||
ErrorManager eman;
|
ErrorManager eman;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -743,8 +740,8 @@ vips__jpeg2vips( const char *name, VipsImage *out, gboolean header_only,
|
|||||||
/* Make jpeg dcompression object.
|
/* Make jpeg dcompression object.
|
||||||
*/
|
*/
|
||||||
cinfo.err = jpeg_std_error( &eman.pub );
|
cinfo.err = jpeg_std_error( &eman.pub );
|
||||||
eman.pub.error_exit = new_error_exit;
|
eman.pub.error_exit = vips__new_error_exit;
|
||||||
eman.pub.output_message = new_output_message;
|
eman.pub.output_message = vips__new_output_message;
|
||||||
eman.fp = NULL;
|
eman.fp = NULL;
|
||||||
if( setjmp( eman.jmp ) ) {
|
if( setjmp( eman.jmp ) ) {
|
||||||
/* Here for longjmp() from new_error_exit().
|
/* Here for longjmp() from new_error_exit().
|
||||||
@ -757,7 +754,7 @@ vips__jpeg2vips( const char *name, VipsImage *out, gboolean header_only,
|
|||||||
|
|
||||||
/* Make input.
|
/* Make input.
|
||||||
*/
|
*/
|
||||||
if( !(fp = im__file_open_read( filename, NULL, FALSE )) )
|
if( !(fp = im__file_open_read( name, NULL, FALSE )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
eman.fp = fp;
|
eman.fp = fp;
|
||||||
jpeg_stdio_src( &cinfo, fp );
|
jpeg_stdio_src( &cinfo, fp );
|
||||||
@ -967,7 +964,7 @@ buf_source (j_decompress_ptr cinfo, void *buf, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__bufjpeg2vips( void *buf, size_t len, VipsImage *out,
|
vips__jpeg_read_buffer( void *buf, size_t len, VipsImage *out,
|
||||||
gboolean header_only,
|
gboolean header_only,
|
||||||
int shrink, int fail )
|
int shrink, int fail )
|
||||||
{
|
{
|
||||||
@ -979,8 +976,8 @@ vips__bufjpeg2vips( void *buf, size_t len, VipsImage *out,
|
|||||||
/* Make jpeg dcompression object.
|
/* Make jpeg dcompression object.
|
||||||
*/
|
*/
|
||||||
cinfo.err = jpeg_std_error( &eman.pub );
|
cinfo.err = jpeg_std_error( &eman.pub );
|
||||||
eman.pub.error_exit = new_error_exit;
|
eman.pub.error_exit = vips__new_error_exit;
|
||||||
eman.pub.output_message = new_output_message;
|
eman.pub.output_message = vips__new_output_message;
|
||||||
eman.fp = NULL;
|
eman.fp = NULL;
|
||||||
if( setjmp( eman.jmp ) ) {
|
if( setjmp( eman.jmp ) ) {
|
||||||
/* Here for longjmp() from new_error_exit().
|
/* Here for longjmp() from new_error_exit().
|
||||||
|
@ -1,46 +1,7 @@
|
|||||||
/* load jpeg from a file
|
/* save to jpeg
|
||||||
*
|
*
|
||||||
* 28/11/03 JC
|
|
||||||
* - better no-overshoot on tile loop
|
|
||||||
* 12/11/04
|
|
||||||
* - better demand size choice for eval
|
|
||||||
* 30/6/05 JC
|
|
||||||
* - update im_error()/im_warn()
|
|
||||||
* - now loads and saves exif data
|
|
||||||
* 30/7/05
|
|
||||||
* - now loads ICC profiles
|
|
||||||
* - now saves ICC profiles from the VIPS header
|
|
||||||
* 24/8/05
|
|
||||||
* - jpeg load sets vips xres/yres from exif, if possible
|
|
||||||
* - jpeg save sets exif xres/yres from vips, if possible
|
|
||||||
* 29/8/05
|
|
||||||
* - cut from old vips_jpeg.c
|
|
||||||
* 13/10/06
|
|
||||||
* - add </libexif/ prefix if required
|
|
||||||
* 11/2/08
|
|
||||||
* - spot CMYK jpegs and set Type
|
|
||||||
* - spot Adobe CMYK JPEG and invert ink density
|
|
||||||
* 15/2/08
|
|
||||||
* - added "shrink" parameter
|
|
||||||
* 16/6/09
|
|
||||||
* - added "fail" option ... fail on any warnings
|
|
||||||
* 12/10/09
|
|
||||||
* - also set scale_num on shrink (thanks Guido)
|
|
||||||
* 4/2/10
|
|
||||||
* - gtkdoc
|
|
||||||
* 4/12/10
|
|
||||||
* - attach the jpeg thumbnail and multiscan fields (thanks Mike)
|
|
||||||
* 21/2/10
|
|
||||||
* - only accept the first APP1 block which starts "Exif..." as exif
|
|
||||||
* data, some jpegs seem to have several APP1s, argh
|
|
||||||
* 20/4/2011
|
|
||||||
* - added im_bufjpeg2vips()
|
|
||||||
* 12/10/2011
|
|
||||||
* - read XMP data
|
|
||||||
* 3/11/11
|
|
||||||
* - attach exif tags as coded values
|
|
||||||
* 24/11/11
|
* 24/11/11
|
||||||
* - redo as a class
|
* - wrap a class around the jpeg reader
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -125,10 +86,6 @@ typedef struct _VipsFileLoadJpeg {
|
|||||||
*/
|
*/
|
||||||
gboolean fail;
|
gboolean fail;
|
||||||
|
|
||||||
/* For some jpeg CMYK formats we have to invert pels on read.
|
|
||||||
*/
|
|
||||||
gboolean invert_pels;
|
|
||||||
|
|
||||||
} VipsFileLoadJpeg;
|
} VipsFileLoadJpeg;
|
||||||
|
|
||||||
typedef VipsFileLoadClass VipsFileLoadJpegClass;
|
typedef VipsFileLoadClass VipsFileLoadJpegClass;
|
||||||
@ -156,582 +113,6 @@ vips_file_load_jpeg_build( VipsObject *object )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
vips_file_load_jpeg_is_a( const char *filename )
|
|
||||||
{
|
|
||||||
unsigned char buf[2];
|
|
||||||
|
|
||||||
if( vips__get_bytes( filename, buf, 2 ) )
|
|
||||||
if( (int) buf[0] == 0xff && (int) buf[1] == 0xd8 )
|
|
||||||
return( TRUE );
|
|
||||||
|
|
||||||
return( FALSE );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to
|
|
||||||
* do 255-pel.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
vips_file_load_jpeg_read_header( VipsFileLoadJpeg *jpeg,
|
|
||||||
struct jpeg_decompress_struct *cinfo, VipsImage *out )
|
|
||||||
{
|
|
||||||
int type;
|
|
||||||
|
|
||||||
/* Read JPEG header. libjpeg will set out_color_space sanely for us
|
|
||||||
* for YUV YCCK etc.
|
|
||||||
*/
|
|
||||||
jpeg_read_header( cinfo, TRUE );
|
|
||||||
cinfo->scale_denom = jpeg->shrink;
|
|
||||||
cinfo->scale_num = 1;
|
|
||||||
jpeg_calc_output_dimensions( cinfo );
|
|
||||||
|
|
||||||
switch( cinfo->out_color_space ) {
|
|
||||||
case JCS_GRAYSCALE:
|
|
||||||
type = IM_TYPE_B_W;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JCS_CMYK:
|
|
||||||
type = IM_TYPE_CMYK;
|
|
||||||
/* Photoshop writes CMYK JPEG inverted :-( Maybe this is a
|
|
||||||
* way to spot photoshop CMYK JPGs.
|
|
||||||
*/
|
|
||||||
if( cinfo->saw_Adobe_marker )
|
|
||||||
jpeg->invert_pels = TRUE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JCS_RGB:
|
|
||||||
default:
|
|
||||||
type = IM_TYPE_sRGB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set VIPS header.
|
|
||||||
*/
|
|
||||||
vips_image_init_fields( out,
|
|
||||||
cinfo->output_width, cinfo->output_height,
|
|
||||||
cinfo->output_components,
|
|
||||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, type,
|
|
||||||
1.0, 1.0 );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_EXIF
|
|
||||||
#ifdef DEBUG_VERBOSE
|
|
||||||
/* Print exif for debugging ... hacked from exif-0.6.9/actions.c
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
show_tags( ExifData *data )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned int tag;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
printf( "show EXIF tags:\n" );
|
|
||||||
|
|
||||||
for( i = 0; i < EXIF_IFD_COUNT; i++ )
|
|
||||||
printf( "%-7.7s", exif_ifd_get_name( i ) );
|
|
||||||
printf( "\n" );
|
|
||||||
|
|
||||||
for( tag = 0; tag < 0xffff; tag++ ) {
|
|
||||||
name = exif_tag_get_title( tag );
|
|
||||||
if( !name )
|
|
||||||
continue;
|
|
||||||
printf( " 0x%04x %-29.29s", tag, name );
|
|
||||||
for( i = 0; i < EXIF_IFD_COUNT; i++ )
|
|
||||||
if( exif_content_get_entry( data->ifd[i], tag ) )
|
|
||||||
printf( " * " );
|
|
||||||
else
|
|
||||||
printf( " - " );
|
|
||||||
printf( "\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
show_entry( ExifEntry *entry, void *client )
|
|
||||||
{
|
|
||||||
char exif_text[256];
|
|
||||||
|
|
||||||
printf( "%s", exif_tag_get_title( entry->tag ) );
|
|
||||||
printf( "|" );
|
|
||||||
printf( "%s", exif_entry_get_value( entry, exif_text, 256 ) );
|
|
||||||
printf( "|" );
|
|
||||||
printf( "%s", exif_format_get_name( entry->format ) );
|
|
||||||
printf( "|" );
|
|
||||||
printf( "%d bytes", entry->size );
|
|
||||||
printf( "\n" );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
show_ifd( ExifContent *content, void *client )
|
|
||||||
{
|
|
||||||
exif_content_foreach_entry( content, show_entry, client );
|
|
||||||
printf( "-\n" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
show_values( ExifData *data )
|
|
||||||
{
|
|
||||||
ExifByteOrder order;
|
|
||||||
|
|
||||||
order = exif_data_get_byte_order( data );
|
|
||||||
printf( "EXIF tags in '%s' byte order\n",
|
|
||||||
exif_byte_order_get_name( order ) );
|
|
||||||
|
|
||||||
printf( "%-20.20s", "Tag" );
|
|
||||||
printf( "|" );
|
|
||||||
printf( "%-58.58s", "Value" );
|
|
||||||
printf( "\n" );
|
|
||||||
|
|
||||||
exif_data_foreach_content( data, show_ifd, NULL );
|
|
||||||
|
|
||||||
if( data->size )
|
|
||||||
printf( "contains thumbnail of %d bytes\n", data->size );
|
|
||||||
}
|
|
||||||
#endif /*DEBUG_VERBOSE*/
|
|
||||||
#endif /*HAVE_EXIF*/
|
|
||||||
|
|
||||||
#ifdef HAVE_EXIF
|
|
||||||
|
|
||||||
static int
|
|
||||||
vips_exif_get_int( ExifData *ed,
|
|
||||||
ExifEntry *entry, unsigned long component, int *out )
|
|
||||||
{
|
|
||||||
ExifByteOrder bo = exif_data_get_byte_order( ed );
|
|
||||||
size_t sizeof_component = entry->size / entry->components;
|
|
||||||
size_t offset = component * sizeof_component;
|
|
||||||
|
|
||||||
if( entry->format == EXIF_FORMAT_SHORT )
|
|
||||||
*out = exif_get_short( entry->data + offset, bo );
|
|
||||||
else if( entry->format == EXIF_FORMAT_SSHORT )
|
|
||||||
*out = exif_get_sshort( entry->data + offset, bo );
|
|
||||||
else if( entry->format == EXIF_FORMAT_LONG )
|
|
||||||
/* This won't work for huge values, but who cares.
|
|
||||||
*/
|
|
||||||
*out = (int) exif_get_long( entry->data + offset, bo );
|
|
||||||
else if( entry->format == EXIF_FORMAT_SLONG )
|
|
||||||
*out = exif_get_slong( entry->data + offset, bo );
|
|
||||||
else
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
vips_exif_get_double( ExifData *ed,
|
|
||||||
ExifEntry *entry, unsigned long component, double *out )
|
|
||||||
{
|
|
||||||
ExifByteOrder bo = exif_data_get_byte_order( ed );
|
|
||||||
size_t sizeof_component = entry->size / entry->components;
|
|
||||||
size_t offset = component * sizeof_component;
|
|
||||||
|
|
||||||
if( entry->format == EXIF_FORMAT_RATIONAL ) {
|
|
||||||
ExifRational value;
|
|
||||||
|
|
||||||
value = exif_get_rational( entry->data + offset, bo );
|
|
||||||
*out = (double) value.numerator / value.denominator;
|
|
||||||
}
|
|
||||||
else if( entry->format == EXIF_FORMAT_SRATIONAL ) {
|
|
||||||
ExifSRational value;
|
|
||||||
|
|
||||||
value = exif_get_srational( entry->data + offset, bo );
|
|
||||||
*out = (double) value.numerator / value.denominator;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save an exif value to a string in a way that we can restore. We only bother
|
|
||||||
* for the simple formats (that a client might try to change) though.
|
|
||||||
*
|
|
||||||
* Keep in sync with vips_exif_from_s() in vips2jpeg.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
vips_exif_to_s( ExifData *ed, ExifEntry *entry, VipsBuf *buf )
|
|
||||||
{
|
|
||||||
unsigned long i;
|
|
||||||
int iv;
|
|
||||||
double dv;
|
|
||||||
char txt[256];
|
|
||||||
|
|
||||||
if( entry->format == EXIF_FORMAT_ASCII )
|
|
||||||
vips_buf_appendf( buf, "%s ", entry->data );
|
|
||||||
|
|
||||||
else if( entry->components < 10 &&
|
|
||||||
!vips_exif_get_int( ed, entry, 0, &iv ) ) {
|
|
||||||
for( i = 0; i < entry->components; i++ ) {
|
|
||||||
vips_exif_get_int( ed, entry, i, &iv );
|
|
||||||
vips_buf_appendf( buf, "%d ", iv );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( entry->components < 10 &&
|
|
||||||
!vips_exif_get_double( ed, entry, 0, &dv ) ) {
|
|
||||||
for( i = 0; i < entry->components; i++ ) {
|
|
||||||
vips_exif_get_double( ed, entry, i, &dv );
|
|
||||||
/* Need to be locale independent.
|
|
||||||
*/
|
|
||||||
g_ascii_dtostr( txt, 256, dv );
|
|
||||||
vips_buf_appendf( buf, "%s ", txt );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vips_buf_appendf( buf, "%s ",
|
|
||||||
exif_entry_get_value( entry, txt, 256 ) );
|
|
||||||
|
|
||||||
vips_buf_appendf( buf, "(%s, %s, %lu components, %d bytes)",
|
|
||||||
exif_entry_get_value( entry, txt, 256 ),
|
|
||||||
exif_format_get_name( entry->format ),
|
|
||||||
entry->components,
|
|
||||||
entry->size );
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _VipsExif {
|
|
||||||
VipsImage *image;
|
|
||||||
ExifData *ed;
|
|
||||||
} VipsExif;
|
|
||||||
|
|
||||||
static void
|
|
||||||
attach_exif_entry( ExifEntry *entry, VipsExif *ve )
|
|
||||||
{
|
|
||||||
char name_txt[256];
|
|
||||||
VipsBuf name = VIPS_BUF_STATIC( name_txt );
|
|
||||||
char value_txt[256];
|
|
||||||
VipsBuf value = VIPS_BUF_STATIC( value_txt );
|
|
||||||
|
|
||||||
vips_buf_appendf( &name, "exif-%s", exif_tag_get_title( entry->tag ) );
|
|
||||||
vips_exif_to_s( ve->ed, entry, &value );
|
|
||||||
|
|
||||||
/* Can't do anything sensible with the error return.
|
|
||||||
*/
|
|
||||||
(void) im_meta_set_string( ve->image,
|
|
||||||
vips_buf_all( &name ), vips_buf_all( &value ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
attach_exif_content( ExifContent *content, VipsExif *ve )
|
|
||||||
{
|
|
||||||
exif_content_foreach_entry( content,
|
|
||||||
(ExifContentForeachEntryFunc) attach_exif_entry, ve );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Just find the first occurence of the tag (is this correct?)
|
|
||||||
*/
|
|
||||||
static ExifEntry *
|
|
||||||
find_entry( ExifData *ed, ExifTag tag )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i = 0; i < EXIF_IFD_COUNT; i++ ) {
|
|
||||||
ExifEntry *entry;
|
|
||||||
|
|
||||||
if( (entry = exif_content_get_entry( ed->ifd[i], tag )) )
|
|
||||||
return( entry );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_entry_rational( ExifData *ed, ExifTag tag, double *out )
|
|
||||||
{
|
|
||||||
ExifEntry *entry;
|
|
||||||
|
|
||||||
if( !(entry = find_entry( ed, tag )) ||
|
|
||||||
entry->format != EXIF_FORMAT_RATIONAL ||
|
|
||||||
entry->components != 1 )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( vips_exif_get_double( ed, entry, 0, out ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_entry_short( ExifData *ed, ExifTag tag, int *out )
|
|
||||||
{
|
|
||||||
ExifEntry *entry;
|
|
||||||
|
|
||||||
if( !(entry = find_entry( ed, tag )) ||
|
|
||||||
entry->format != EXIF_FORMAT_SHORT ||
|
|
||||||
entry->components != 1 )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( vips_exif_get_int( ed, entry, 0, out ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_vips_resolution( IMAGE *im, ExifData *ed )
|
|
||||||
{
|
|
||||||
double xres, yres;
|
|
||||||
int unit;
|
|
||||||
|
|
||||||
if( get_entry_rational( ed, EXIF_TAG_X_RESOLUTION, &xres ) ||
|
|
||||||
get_entry_rational( ed, EXIF_TAG_Y_RESOLUTION, &yres ) ||
|
|
||||||
get_entry_short( ed, EXIF_TAG_RESOLUTION_UNIT, &unit ) ) {
|
|
||||||
im_warn( "im_jpeg2vips",
|
|
||||||
"%s", _( "error reading resolution" ) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( unit ) {
|
|
||||||
case 2:
|
|
||||||
/* In inches.
|
|
||||||
*/
|
|
||||||
xres /= 25.4;
|
|
||||||
yres /= 25.4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
/* In cm.
|
|
||||||
*/
|
|
||||||
xres /= 10.0;
|
|
||||||
yres /= 10.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
im_warn( "im_jpeg2vips", "%s", _( "bad resolution unit" ) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
im->Xres = xres;
|
|
||||||
im->Yres = yres;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
attach_thumbnail( IMAGE *im, ExifData *ed )
|
|
||||||
{
|
|
||||||
if( ed->size > 0 ) {
|
|
||||||
char *thumb_copy;
|
|
||||||
|
|
||||||
thumb_copy = im_malloc( NULL, ed->size );
|
|
||||||
memcpy( thumb_copy, ed->data, ed->size );
|
|
||||||
|
|
||||||
if( im_meta_set_blob( im, "jpeg-thumbnail-data",
|
|
||||||
(im_callback_fn) im_free, thumb_copy, ed->size ) ) {
|
|
||||||
im_free( thumb_copy );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
#endif /*HAVE_EXIF*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
read_exif( IMAGE *im, void *data, int data_length )
|
|
||||||
{
|
|
||||||
char *data_copy;
|
|
||||||
|
|
||||||
/* Only use the first one.
|
|
||||||
*/
|
|
||||||
if( im_header_get_typeof( im, IM_META_EXIF_NAME ) ) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "read_exif: second EXIF block, ignoring\n" );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "read_exif: attaching %d bytes of exif\n", data_length );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
/* Always attach a copy of the unparsed exif data.
|
|
||||||
*/
|
|
||||||
if( !(data_copy = im_malloc( NULL, data_length )) )
|
|
||||||
return( -1 );
|
|
||||||
memcpy( data_copy, data, data_length );
|
|
||||||
if( im_meta_set_blob( im, IM_META_EXIF_NAME,
|
|
||||||
(im_callback_fn) im_free, data_copy, data_length ) ) {
|
|
||||||
im_free( data_copy );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_EXIF
|
|
||||||
{
|
|
||||||
ExifData *ed;
|
|
||||||
|
|
||||||
if( !(ed = exif_data_new_from_data( data, data_length )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
if( ed->size > 0 ) {
|
|
||||||
VipsExif ve;
|
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
|
||||||
show_tags( ed );
|
|
||||||
show_values( ed );
|
|
||||||
#endif /*DEBUG_VERBOSE*/
|
|
||||||
|
|
||||||
/* Attach informational fields for what we find.
|
|
||||||
|
|
||||||
FIXME ... better to have this in the UI layer?
|
|
||||||
|
|
||||||
Or we could attach non-human-readable tags here (int,
|
|
||||||
double etc) and then move the human stuff to the UI
|
|
||||||
layer?
|
|
||||||
|
|
||||||
*/
|
|
||||||
ve.image = im;
|
|
||||||
ve.ed = ed;
|
|
||||||
exif_data_foreach_content( ed,
|
|
||||||
(ExifDataForeachContentFunc) attach_exif_content, &ve );
|
|
||||||
|
|
||||||
/* Look for resolution fields and use them to set the VIPS
|
|
||||||
* xres/yres fields.
|
|
||||||
*/
|
|
||||||
set_vips_resolution( im, ed );
|
|
||||||
|
|
||||||
attach_thumbnail( im, ed );
|
|
||||||
}
|
|
||||||
|
|
||||||
exif_data_free( ed );
|
|
||||||
}
|
|
||||||
#endif /*HAVE_EXIF*/
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
read_xmp( IMAGE *im, void *data, int data_length )
|
|
||||||
{
|
|
||||||
char *data_copy;
|
|
||||||
|
|
||||||
/* XMP sections start "http". Only use the first one.
|
|
||||||
*/
|
|
||||||
if( im_header_get_typeof( im, VIPS_META_XMP_NAME ) ) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "read_xmp: second XMP block, ignoring\n" );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "read_xmp: attaching %d bytes of XMP\n", data_length );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
/* Always attach a copy of the unparsed exif data.
|
|
||||||
*/
|
|
||||||
if( !(data_copy = im_malloc( NULL, data_length )) )
|
|
||||||
return( -1 );
|
|
||||||
memcpy( data_copy, data, data_length );
|
|
||||||
if( im_meta_set_blob( im, VIPS_META_XMP_NAME,
|
|
||||||
(im_callback_fn) im_free, data_copy, data_length ) ) {
|
|
||||||
im_free( data_copy );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Number of app2 sections we can capture. Each one can be 64k, so 6400k should
|
|
||||||
* be enough for anyone (haha).
|
|
||||||
*/
|
|
||||||
#define MAX_APP2_SECTIONS (100)
|
|
||||||
|
|
||||||
static int
|
|
||||||
vips_file_load_jpeg_meta( VipsFileLoadJpeg *jpeg,
|
|
||||||
struct jpeg_decompress_struct *cinfo, VipsImage *out )
|
|
||||||
{
|
|
||||||
/* Capture app2 sections here for assembly.
|
|
||||||
*/
|
|
||||||
void *app2_data[MAX_APP2_SECTIONS] = { 0 };
|
|
||||||
int app2_data_length[MAX_APP2_SECTIONS] = { 0 };
|
|
||||||
int data_length;
|
|
||||||
jpeg_saved_marker_ptr p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Interlaced jpegs need lots of memory to read, so our caller needs
|
|
||||||
* to know.
|
|
||||||
*/
|
|
||||||
vips_image_set_int( out, "jpeg-multiscan",
|
|
||||||
jpeg_has_multiple_scans( cinfo ) );
|
|
||||||
|
|
||||||
/* Look for EXIF and ICC profile.
|
|
||||||
*/
|
|
||||||
for( p = cinfo->marker_list; p; p = p->next ) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
printf( "vips_file_load_jpeg_read_header: "
|
|
||||||
"seen %d bytes of APP%d\n",
|
|
||||||
p->data_length,
|
|
||||||
p->marker - JPEG_APP0 );
|
|
||||||
|
|
||||||
for( i = 0; i < 10; i++ )
|
|
||||||
printf( "\t%d) '%c' (%d)\n",
|
|
||||||
i, p->data[i], p->data[i] );
|
|
||||||
}
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
switch( p->marker ) {
|
|
||||||
case JPEG_APP0 + 1:
|
|
||||||
/* Possible EXIF or XMP data.
|
|
||||||
*/
|
|
||||||
if( p->data_length > 4 &&
|
|
||||||
im_isprefix( "Exif", (char *) p->data ) &&
|
|
||||||
read_exif( out, p->data, p->data_length ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
if( p->data_length > 4 &&
|
|
||||||
im_isprefix( "http", (char *) p->data ) &&
|
|
||||||
read_xmp( out, p->data, p->data_length ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JPEG_APP0 + 2:
|
|
||||||
/* ICC profile.
|
|
||||||
*/
|
|
||||||
if( p->data_length > 14 &&
|
|
||||||
im_isprefix( "ICC_PROFILE",
|
|
||||||
(char *) p->data ) ) {
|
|
||||||
/* cur_marker numbers from 1, according to
|
|
||||||
* spec.
|
|
||||||
*/
|
|
||||||
int cur_marker = p->data[12] - 1;
|
|
||||||
|
|
||||||
if( cur_marker >= 0 &&
|
|
||||||
cur_marker < MAX_APP2_SECTIONS ) {
|
|
||||||
app2_data[cur_marker] = p->data + 14;
|
|
||||||
app2_data_length[cur_marker] =
|
|
||||||
p->data_length - 14;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assemble ICC sections.
|
|
||||||
*/
|
|
||||||
data_length = 0;
|
|
||||||
for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ )
|
|
||||||
data_length += app2_data_length[i];
|
|
||||||
if( data_length ) {
|
|
||||||
unsigned char *data;
|
|
||||||
int x;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "vips_file_load_jpeg_read_header: "
|
|
||||||
"assembled %d byte ICC profile\n",
|
|
||||||
data_length );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
data = g_malloc( data_length );
|
|
||||||
x = 0;
|
|
||||||
for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) {
|
|
||||||
memcpy( data + x, app2_data[i], app2_data_length[i] );
|
|
||||||
x += app2_data_length[i];
|
|
||||||
}
|
|
||||||
vips_image_set_blob( out, VIPS_META_ICC_NAME,
|
|
||||||
(VipsCallbackFn) g_free, data, data_length );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read just the image header into ->out.
|
/* Read just the image header into ->out.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@ -740,99 +121,9 @@ vips_file_load_jpeg_header( VipsFileLoad *load )
|
|||||||
VipsFile *file = VIPS_FILE( load );
|
VipsFile *file = VIPS_FILE( load );
|
||||||
VipsFileLoadJpeg *jpeg = (VipsFileLoadJpeg *) load;
|
VipsFileLoadJpeg *jpeg = (VipsFileLoadJpeg *) load;
|
||||||
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
if( vips__jpeg_read_file( file->filename, load->out,
|
||||||
ErrorManager eman;
|
TRUE, jpeg->shrink, jpeg->fail ) )
|
||||||
FILE *fp;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
/* Make jpeg dcompression object.
|
|
||||||
*/
|
|
||||||
cinfo.err = jpeg_std_error( &eman.pub );
|
|
||||||
eman.pub.error_exit = vips__new_error_exit;
|
|
||||||
eman.pub.output_message = vips__new_output_message;
|
|
||||||
eman.fp = NULL;
|
|
||||||
if( setjmp( eman.jmp ) ) {
|
|
||||||
/* Here for longjmp() from vips__new_error_exit().
|
|
||||||
*/
|
|
||||||
jpeg_destroy_decompress( &cinfo );
|
|
||||||
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
jpeg_create_decompress( &cinfo );
|
|
||||||
|
|
||||||
/* Make input.
|
|
||||||
*/
|
|
||||||
if( !(fp = vips__file_open_read( file->filename, NULL, FALSE )) )
|
|
||||||
return( -1 );
|
|
||||||
eman.fp = fp;
|
|
||||||
jpeg_stdio_src( &cinfo, fp );
|
|
||||||
|
|
||||||
/* Need to read in APP1 (EXIF metadata) and APP2 (ICC profile).
|
|
||||||
*/
|
|
||||||
jpeg_save_markers( &cinfo, JPEG_APP0 + 1, 0xffff );
|
|
||||||
jpeg_save_markers( &cinfo, JPEG_APP0 + 2, 0xffff );
|
|
||||||
|
|
||||||
/* Convert!
|
|
||||||
*/
|
|
||||||
result = vips_file_load_jpeg_read_header( jpeg, &cinfo, load->out );
|
|
||||||
|
|
||||||
/* Get extra metadata too.
|
|
||||||
*/
|
|
||||||
if( !result )
|
|
||||||
result = vips_file_load_jpeg_meta( jpeg, &cinfo, load->out );
|
|
||||||
|
|
||||||
/* Close and tidy.
|
|
||||||
*/
|
|
||||||
fclose( fp );
|
|
||||||
eman.fp = NULL;
|
|
||||||
jpeg_destroy_decompress( &cinfo );
|
|
||||||
|
|
||||||
return( result );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a cinfo to a VIPS image.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
vips_file_load_jpeg_read_image( VipsFileLoadJpeg *jpeg,
|
|
||||||
struct jpeg_decompress_struct *cinfo, VipsImage *out )
|
|
||||||
{
|
|
||||||
int x, y, sz;
|
|
||||||
JSAMPROW row_pointer[1];
|
|
||||||
|
|
||||||
/* Check VIPS.
|
|
||||||
*/
|
|
||||||
if( vips_image_wio_output( out ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Get size of output line and make a buffer.
|
|
||||||
*/
|
|
||||||
sz = cinfo->output_width * cinfo->output_components;
|
|
||||||
row_pointer[0] = (JSAMPLE *) (*cinfo->mem->alloc_large)
|
|
||||||
( (j_common_ptr) cinfo, JPOOL_IMAGE, sz );
|
|
||||||
|
|
||||||
/* Start up decompressor.
|
|
||||||
*/
|
|
||||||
jpeg_start_decompress( cinfo );
|
|
||||||
|
|
||||||
/* Process image.
|
|
||||||
*/
|
|
||||||
for( y = 0; y < out->Ysize; y++ ) {
|
|
||||||
/* We set an error handler that longjmps() out, so I don't
|
|
||||||
* think this can fail.
|
|
||||||
*/
|
|
||||||
jpeg_read_scanlines( cinfo, &row_pointer[0], 1 );
|
|
||||||
|
|
||||||
if( jpeg->invert_pels ) {
|
|
||||||
for( x = 0; x < sz; x++ )
|
|
||||||
row_pointer[0][x] = 255 - row_pointer[0][x];
|
|
||||||
}
|
|
||||||
if( vips_image_write_line( out, y, row_pointer[0] ) )
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop decompressor.
|
|
||||||
*/
|
|
||||||
jpeg_finish_decompress( cinfo );
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -843,66 +134,13 @@ vips_file_load_jpeg_load( VipsFileLoad *load )
|
|||||||
VipsFile *file = VIPS_FILE( load );
|
VipsFile *file = VIPS_FILE( load );
|
||||||
VipsFileLoadJpeg *jpeg = (VipsFileLoadJpeg *) load;
|
VipsFileLoadJpeg *jpeg = (VipsFileLoadJpeg *) load;
|
||||||
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
if( vips__jpeg_read_file( file->filename, load->real,
|
||||||
ErrorManager eman;
|
FALSE, jpeg->shrink, jpeg->fail ) )
|
||||||
FILE *fp;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
/* Make jpeg dcompression object.
|
|
||||||
*/
|
|
||||||
cinfo.err = jpeg_std_error( &eman.pub );
|
|
||||||
eman.pub.error_exit = vips__new_error_exit;
|
|
||||||
eman.pub.output_message = vips__new_output_message;
|
|
||||||
eman.fp = NULL;
|
|
||||||
if( setjmp( eman.jmp ) ) {
|
|
||||||
/* Here for longjmp() from vips__new_error_exit().
|
|
||||||
*/
|
|
||||||
jpeg_destroy_decompress( &cinfo );
|
|
||||||
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
jpeg_create_decompress( &cinfo );
|
|
||||||
|
|
||||||
/* Make input.
|
return( 0 );
|
||||||
*/
|
|
||||||
if( !(fp = vips__file_open_read( file->filename, NULL, FALSE )) )
|
|
||||||
return( -1 );
|
|
||||||
eman.fp = fp;
|
|
||||||
jpeg_stdio_src( &cinfo, fp );
|
|
||||||
|
|
||||||
/* Convert!
|
|
||||||
*/
|
|
||||||
result = vips_file_load_jpeg_read_header( jpeg, &cinfo, load->real );
|
|
||||||
if( !result )
|
|
||||||
result = vips_file_load_jpeg_read_image( jpeg,
|
|
||||||
&cinfo, load->real );
|
|
||||||
|
|
||||||
/* Close and tidy.
|
|
||||||
*/
|
|
||||||
fclose( fp );
|
|
||||||
eman.fp = NULL;
|
|
||||||
jpeg_destroy_decompress( &cinfo );
|
|
||||||
|
|
||||||
if( eman.pub.num_warnings != 0 ) {
|
|
||||||
if( jpeg->fail ) {
|
|
||||||
vips_error( "VipsFileLoadJpeg",
|
|
||||||
"%s", vips_error_buffer() );
|
|
||||||
result = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vips_warn( "VipsFileLoadJpeg",
|
|
||||||
_( "read gave %ld warnings" ),
|
|
||||||
eman.pub.num_warnings );
|
|
||||||
vips_warn( "VipsFileLoadJpeg",
|
|
||||||
"%s", vips_error_buffer() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return( result );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
|
vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
|
||||||
{
|
{
|
||||||
@ -918,9 +156,9 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
|
|||||||
object_class->description = _( "load jpeg from file" );
|
object_class->description = _( "load jpeg from file" );
|
||||||
object_class->build = vips_file_load_jpeg_build;
|
object_class->build = vips_file_load_jpeg_build;
|
||||||
|
|
||||||
file_class->suffs = jpeg_suffs;
|
file_class->suffs = vips__jpeg_suffs;
|
||||||
|
|
||||||
load_class->is_a = vips_file_load_jpeg_is_a;
|
load_class->is_a = vips__isjpeg;
|
||||||
load_class->header = vips_file_load_jpeg_header;
|
load_class->header = vips_file_load_jpeg_header;
|
||||||
load_class->load = vips_file_load_jpeg_load;
|
load_class->load = vips_file_load_jpeg_load;
|
||||||
|
|
||||||
|
@ -103,7 +103,8 @@ vips_file_save_jpeg_build( VipsObject *object )
|
|||||||
build( object ) )
|
build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( vips__jpeg_write_file( save->in, file->filename,
|
// ->ready loses a ref suring the write??
|
||||||
|
if( vips__jpeg_write_file( save->ready, file->filename,
|
||||||
jpeg->Q, jpeg->profile ) )
|
jpeg->Q, jpeg->profile ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -119,8 +120,6 @@ static int bandfmt_jpeg[10] = {
|
|||||||
UC, UC, UC, UC, UC, UC, UC, UC, UC, UC
|
UC, UC, UC, UC, UC, UC, UC, UC, UC, UC
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class )
|
vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class )
|
||||||
{
|
{
|
||||||
@ -136,7 +135,7 @@ vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class )
|
|||||||
object_class->description = _( "save image to jpeg file" );
|
object_class->description = _( "save image to jpeg file" );
|
||||||
object_class->build = vips_file_save_jpeg_build;
|
object_class->build = vips_file_save_jpeg_build;
|
||||||
|
|
||||||
file_class->suffs = jpeg_suffs;
|
file_class->suffs = vips__jpeg_suffs;
|
||||||
|
|
||||||
save_class->saveable = VIPS_SAVEABLE_RGB_CMYK;
|
save_class->saveable = VIPS_SAVEABLE_RGB_CMYK;
|
||||||
save_class->format_table = bandfmt_jpeg;
|
save_class->format_table = bandfmt_jpeg;
|
||||||
|
@ -177,7 +177,6 @@ static void
|
|||||||
write_destroy( Write *write )
|
write_destroy( Write *write )
|
||||||
{
|
{
|
||||||
jpeg_destroy_compress( &write->cinfo );
|
jpeg_destroy_compress( &write->cinfo );
|
||||||
VIPS_UNREF( write->in );
|
|
||||||
VIPS_FREEF( fclose, write->eman.fp );
|
VIPS_FREEF( fclose, write->eman.fp );
|
||||||
VIPS_FREE( write->row_pointer );
|
VIPS_FREE( write->row_pointer );
|
||||||
VIPS_FREE( write->profile_bytes );
|
VIPS_FREE( write->profile_bytes );
|
||||||
@ -960,8 +959,8 @@ typedef struct {
|
|||||||
|
|
||||||
/* Copy the compressed area here.
|
/* Copy the compressed area here.
|
||||||
*/
|
*/
|
||||||
char **obuf; /* Allocated buffer, and size */
|
void **obuf; /* Allocated buffer, and size */
|
||||||
int *olen;
|
size_t *olen;
|
||||||
} OutputBuffer;
|
} OutputBuffer;
|
||||||
|
|
||||||
/* Init dest method.
|
/* Init dest method.
|
||||||
@ -1012,7 +1011,7 @@ term_destination( j_compress_ptr cinfo )
|
|||||||
{
|
{
|
||||||
OutputBuffer *buf = (OutputBuffer *) cinfo->dest;
|
OutputBuffer *buf = (OutputBuffer *) cinfo->dest;
|
||||||
|
|
||||||
int len;
|
size_t len;
|
||||||
void *obuf;
|
void *obuf;
|
||||||
|
|
||||||
/* Record the number of bytes we wrote in the final buffer.
|
/* Record the number of bytes we wrote in the final buffer.
|
||||||
@ -1041,7 +1040,7 @@ term_destination( j_compress_ptr cinfo )
|
|||||||
/* Set dest to one of our objects.
|
/* Set dest to one of our objects.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
buf_dest( j_compress_ptr cinfo, char **obuf, int *olen )
|
buf_dest( j_compress_ptr cinfo, void **obuf, size_t *olen )
|
||||||
{
|
{
|
||||||
OutputBuffer *buf;
|
OutputBuffer *buf;
|
||||||
|
|
||||||
@ -1073,7 +1072,7 @@ buf_dest( j_compress_ptr cinfo, char **obuf, int *olen )
|
|||||||
|
|
||||||
int
|
int
|
||||||
vips__jpeg_write_buffer( VipsImage *in,
|
vips__jpeg_write_buffer( VipsImage *in,
|
||||||
char **obuf, int *olen, int Q, const char *profile )
|
void **obuf, size_t *olen, int Q, const char *profile )
|
||||||
{
|
{
|
||||||
Write *write;
|
Write *write;
|
||||||
|
|
||||||
@ -1111,3 +1110,5 @@ vips__jpeg_write_buffer( VipsImage *in,
|
|||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *vips__jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
|
||||||
|
@ -141,7 +141,7 @@ typedef struct _VipsFileLoadClass {
|
|||||||
*/
|
*/
|
||||||
gboolean (*is_a)( const char * );
|
gboolean (*is_a)( const char * );
|
||||||
|
|
||||||
/* Get the flags for this file.
|
/* Get the flags for this file. NULL means 0, ie. no flags.
|
||||||
*/
|
*/
|
||||||
int (*get_flags)( VipsFileLoad * );
|
int (*get_flags)( VipsFileLoad * );
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user