diff --git a/libvips/file/Makefile.am b/libvips/file/Makefile.am index 2bdac6e1..ca82fd82 100644 --- a/libvips/file/Makefile.am +++ b/libvips/file/Makefile.am @@ -1,6 +1,8 @@ noinst_LTLIBRARIES = libfile.la libfile_la_SOURCES = \ + jpeg.c \ + jpeg.h \ jpegload.c \ file.c diff --git a/libvips/file/file.c b/libvips/file/file.c index 7a1427aa..bef1dedb 100644 --- a/libvips/file/file.c +++ b/libvips/file/file.c @@ -611,14 +611,217 @@ vips_file_save_print_class( VipsObjectClass *object_class, VipsBuf *buf ) */ } +/* Generate the saveable image. + */ +static int +vips_file_convert_saveable( VipsFileSave *save ) +{ + VipsFileSaveClass *class = VIPS_FILE_SAVE_GET_CLASS( save ); + VipsImage *in = save->in; + + /* If this is an VIPS_CODING_LABQ, we can go straight to RGB. + */ + if( in->Coding == VIPS_CODING_LABQ ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + static void *table = NULL; + + /* Make sure fast LabQ2disp tables are built. 7 is sRGB. + */ + if( !table ) + table = im_LabQ2disp_build_table( NULL, + im_col_displays( 7 ) ); + + if( !t || im_LabQ2disp_table( in, t, table ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* If this is an IM_CODING_RAD, we go to float RGB or XYZ. We should + * probably un-gamma-correct the RGB :( + */ + if( in->Coding == IM_CODING_RAD ) { + IMAGE *t; + + if( !(t = im_open_local( out, "conv:1", "p" )) || + im_rad2float( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* Get the bands right. + */ + if( in->Coding == IM_CODING_NONE ) { + if( in->Bands == 2 && saveable != IM__RGBA ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_extract_band( in, t, 0 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + else if( in->Bands > 3 && saveable == IM__RGB ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || + im_extract_bands( in, t, 0, 3 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + else if( in->Bands > 4 && + (saveable == IM__RGB_CMYK || saveable == IM__RGBA) ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || + im_extract_bands( in, t, 0, 4 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* Else we have saveable IM__ANY and we don't chop bands down. + */ + } + + /* Interpret the Type field for colorimetric images. + */ + if( in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && + in->Type == IM_TYPE_LABS ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_LabS2LabQ( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( in->Coding == IM_CODING_LABQ ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_LabQ2Lab( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( in->Coding != IM_CODING_NONE ) { + im_close( out ); + return( NULL ); + } + + if( in->Bands == 3 && in->Type == IM_TYPE_LCH ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_LCh2Lab( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_YXY ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_Yxy2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_UCS ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_UCS2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_LAB ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_Lab2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_XYZ ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_XYZ2disp( t[0], t[1], im_col_displays( 7 ) ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + /* Cast to the output format. + */ + { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_clip2fmt( in, t, format_table[in->BandFmt] ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( im_copy( in, out ) ) { + im_close( out ); + return( NULL ); + } + + return( out ); +} + static int vips_file_save_build( VipsObject *object ) { + VipsFileSave *save = VIPS_FILE_SAVE( object ); /* VipsFile *file = VIPS_FILE( object ); - VipsFileSave *save = VIPS_FILE_SAVE( object ); */ + if( vips_file_convert_saveable( save ) ) + return( -1 ); + if( VIPS_OBJECT_CLASS( vips_file_save_parent_class )-> build( object ) ) return( -1 ); @@ -766,4 +969,3 @@ vips_file_operation_init( void ) vips_file_load_jpeg_get_type(); #endif /*HAVE_JPEG*/ } - diff --git a/libvips/file/jpeg.c b/libvips/file/jpeg.c new file mode 100644 index 00000000..48e0aac3 --- /dev/null +++ b/libvips/file/jpeg.c @@ -0,0 +1,102 @@ +/* common jpeg definitions + * + * 24/11/11 + * - from im_vips2jpeg.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + +/* jpeglib includes jconfig.h, which can define HAVE_STDLIB_H ... which we + * also define. Make sure it's turned off. + */ +#ifdef HAVE_STDLIB_H +#undef HAVE_STDLIB_H +#endif /*HAVE_STDLIB_H*/ + +#include +#include + +#include "jpeg.h" + +/* New output message method - send to VIPS. + */ +void +vips__new_output_message( j_common_ptr cinfo ) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message)( cinfo, buffer ); + vips_error( "VipsFile*Jpeg", _( "%s" ), buffer ); + +#ifdef DEBUG + printf( "jpeg.c: new_output_message: \"%s\"\n", buffer ); +#endif /*DEBUG*/ +} + +/* New error_exit handler. + */ +void +vips__new_error_exit( j_common_ptr cinfo ) +{ + ErrorManager *eman = (ErrorManager *) cinfo->err; + +#ifdef DEBUG + printf( "jpeg.c: new_error_exit\n" ); +#endif /*DEBUG*/ + + /* Close the fp if necessary. + */ + if( eman->fp ) { + (void) fclose( eman->fp ); + eman->fp = NULL; + } + + /* Send the error message to VIPS. This method is overridden above. + */ + (*cinfo->err->output_message)( cinfo ); + + /* Jump back. + */ + longjmp( eman->jmp, 1 ); +} + diff --git a/libvips/file/jpeg.h b/libvips/file/jpeg.h new file mode 100644 index 00000000..1ad8efc8 --- /dev/null +++ b/libvips/file/jpeg.h @@ -0,0 +1,57 @@ +/* common defs for jpeg read/write + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifndef VIPS_JPEG_H +#define VIPS_JPEG_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/* Define a new error handler for when we bomb out. + */ +typedef struct { + /* Public fields. + */ + struct jpeg_error_mgr pub; + + /* Private stuff for us. + */ + jmp_buf jmp; /* longjmp() here to get back to VIPS */ + FILE *fp; /* fclose() if non-NULL */ +} ErrorManager; + +void vips__new_output_message( j_common_ptr cinfo ); +void vips__new_error_exit( j_common_ptr cinfo ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_JPEG_H*/ diff --git a/libvips/file/jpegload.c b/libvips/file/jpegload.c index 8ef15a37..a74d6d8d 100644 --- a/libvips/file/jpegload.c +++ b/libvips/file/jpegload.c @@ -112,6 +112,8 @@ #include #include +#include "jpeg.h" + typedef struct _VipsFileLoadJpeg { VipsFileLoad parent_object; @@ -166,61 +168,6 @@ vips_file_load_jpeg_is_a( const char *filename ) return( FALSE ); } -/* Define a new error handler for when we bomb out. - */ -typedef struct { - /* Public fields. - */ - struct jpeg_error_mgr pub; - - /* Private stuff for us. - */ - jmp_buf jmp; /* longjmp() here to get back to VIPS */ - FILE *fp; /* fclose() if non-NULL */ -} ErrorManager; - -/* New output message method - send to VIPS. - */ -METHODDEF(void) -new_output_message( j_common_ptr cinfo ) -{ - char buffer[JMSG_LENGTH_MAX]; - - (*cinfo->err->format_message)( cinfo, buffer ); - im_error( "VipsFileLoadJpeg", _( "%s" ), buffer ); - -#ifdef DEBUG - printf( "VipsFileLoadJpeg: new_output_message: \"%s\"\n", buffer ); -#endif /*DEBUG*/ -} - -/* New error_exit handler. - */ -METHODDEF(void) -new_error_exit( j_common_ptr cinfo ) -{ - ErrorManager *eman = (ErrorManager *) cinfo->err; - -#ifdef DEBUG - printf( "VipsFileLoadJpeg: new_error_exit\n" ); -#endif /*DEBUG*/ - - /* Close the fp if necessary. - */ - if( eman->fp ) { - (void) fclose( eman->fp ); - eman->fp = NULL; - } - - /* Send the error message to VIPS. This method is overridden above. - */ - (*cinfo->err->output_message)( cinfo ); - - /* Jump back. - */ - longjmp( eman->jmp, 1 ); -} - /* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to * do 255-pel. */ @@ -801,11 +748,11 @@ vips_file_load_jpeg_header( VipsFileLoad *load ) /* Make jpeg dcompression object. */ cinfo.err = jpeg_std_error( &eman.pub ); - eman.pub.error_exit = new_error_exit; - eman.pub.output_message = new_output_message; + 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 new_error_exit(). + /* Here for longjmp() from vips__new_error_exit(). */ jpeg_destroy_decompress( &cinfo ); @@ -904,11 +851,11 @@ vips_file_load_jpeg_load( VipsFileLoad *load ) /* Make jpeg dcompression object. */ cinfo.err = jpeg_std_error( &eman.pub ); - eman.pub.error_exit = new_error_exit; - eman.pub.output_message = new_output_message; + 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 new_error_exit(). + /* Here for longjmp() from vips__new_error_exit(). */ jpeg_destroy_decompress( &cinfo ); diff --git a/libvips/file/jpegsave.c b/libvips/file/jpegsave.c index 7355c632..c85cda0b 100644 --- a/libvips/file/jpegsave.c +++ b/libvips/file/jpegsave.c @@ -79,6 +79,7 @@ /* #define DEBUG_VERBOSE #define DEBUG +#define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H @@ -106,8 +107,9 @@ #endif /*HAVE_EXIF*/ #include -#include #include +#include +#include /* jpeglib includes jconfig.h, which can define HAVE_STDLIB_H ... which we * also define. Make sure it's turned off. @@ -119,6 +121,8 @@ #include #include +#include "jpeg.h" + typedef struct _VipsFileSaveJpeg { VipsFileSave parent_object; diff --git a/libvips/include/vips/file.h b/libvips/include/vips/file.h index 61c665af..d8523cef 100644 --- a/libvips/include/vips/file.h +++ b/libvips/include/vips/file.h @@ -174,6 +174,23 @@ const char *vips_file_find_load( const char *filename ); (G_TYPE_INSTANCE_GET_CLASS( (obj), \ VIPS_TYPE_FILE_SAVE, VipsFileSaveClass )) +/** + * VipsSaveable: + * @VIPS_SAVEABLE_RGB: 1 or 3 bands (eg. PPM) + * @VIPS_SAVEABLE_RGBA: 1, 2, 3 or 4 bands (eg. PNG) + * @VIPS_SAVEABLE_RGB_CMYK: 1, 3 or 4 bands (eg. JPEG) + * @VIPS_SAVEABLE_ANY: any number of bands (eg. TIFF) + * + * See also: #VipsFileSave. + */ +typedef enum { + VIPS_SAVEABLE_RGB, + VIPS_SAVEABLE_RGBA, + VIPS_SAVEABLE_RGB_CMYK, + VIPS_SAVEABLE_ANY, + VIPS_SAVEABLE_LAST +} VipsSaveable; + typedef struct _VipsFileSave { VipsFile parent_object; /*< public >*/ @@ -182,6 +199,10 @@ typedef struct _VipsFileSave { */ VipsImage *in; + /* The image converted to a saveable format (eg. 8-bit RGB). + */ + VipsImage *in; + } VipsFileSave; typedef struct _VipsFileSaveClass { @@ -189,6 +210,13 @@ typedef struct _VipsFileSaveClass { /*< public >*/ + /* How this format treats bands. + */ + VipsSaveable saveable; + + /* How this format treats band formats. + */ + VipsBandFormat format_table[VIPS_FORMAT_LAST]; } VipsFileSaveClass; GType vips_file_save_get_type( void );