Stop the queue if error saving, Issue 2257 and Segfault on indexed PNG, Issue 2556

This commit is contained in:
Ingo
2014-11-28 00:09:55 +01:00
parent fb6861e481
commit 5980774a76
6 changed files with 154 additions and 68 deletions

View File

@@ -267,21 +267,21 @@ int ImageIO::loadPNG (Glib::ustring fname) {
//retrieving image information
png_uint_32 width,height;
int bit_depth,color_type,interlace_type,compression_type,filter_method;
png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,&compression_type, &filter_method);
png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
//converting to 32bpp format
if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
if (color_type==PNG_COLOR_TYPE_PALETTE || interlace_type!=PNG_INTERLACE_NONE ) {
// we don't support interlaced png or png with palette
png_destroy_read_struct (&png, &info, &end_info);
fclose (file);
printf("%s uses an unsupported feature: <palette-indexed colors|interlacing>. Skipping.\n",fname.data());
return IMIO_VARIANTNOTSUPPORTED;
}
if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
if (interlace_type!=PNG_INTERLACE_NONE) {
png_destroy_read_struct (&png, &info, &end_info);
fclose (file);
return IMIO_VARIANTNOTSUPPORTED;
}
if (png_get_valid(png,info,PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if (color_type & PNG_COLOR_MASK_ALPHA)
png_set_strip_alpha(png);
@@ -302,7 +302,15 @@ int ImageIO::loadPNG (Glib::ustring fname) {
allocate (width, height);
int rowlen = width*3*bit_depth/8;
unsigned char *row = new unsigned char [rowlen];
unsigned char *row = new unsigned char [rowlen];
// set a new jump point to avoid memory leak
if (setjmp (png_jmpbuf(png))) {
png_destroy_read_struct (&png, &info, &end_info);
fclose (file);
delete [] row;
return IMIO_READERROR;
}
for (unsigned int i=0;i<height;i++) {
@@ -753,7 +761,7 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) {
FILE *file = safe_g_fopen_WriteBinLock (fname);
if (!file)
return IMIO_CANNOTREADFILE;
return IMIO_CANNOTWRITEFILE;
if (pl) {
pl->setProgressStr ("PROGRESSBAR_SAVEPNG");
@@ -775,7 +783,7 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) {
if (setjmp(png_jmpbuf(png))) {
png_destroy_write_struct (&png,&info);
fclose(file);
return IMIO_READERROR;
return IMIO_CANNOTWRITEFILE;
}
png_set_write_fn (png, file, png_write_data, png_flush);
@@ -825,20 +833,62 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) {
return IMIO_SUCCESS;
}
typedef struct {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
} my_error_mgr;
void my_error_exit (j_common_ptr cinfo) {
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_mgr *myerr = (my_error_mgr*) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
#if defined( WIN32 ) && defined( __x86_64__ )
__builtin_longjmp(myerr->setjmp_buffer, 1);
#else
longjmp(myerr->setjmp_buffer, 1);
#endif
}
// Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high
int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
FILE *file = safe_g_fopen_WriteBinLock (fname);
if (!file)
return IMIO_CANNOTWRITEFILE;
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error (&jerr);
jpeg_compress_struct cinfo;
/* We use our private extension JPEG error handler.
Note that this struct must live as long as the main JPEG parameter
struct, to avoid dangling-pointer problems.
*/
my_error_mgr jerr;
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
#if defined( WIN32 ) && defined( __x86_64__ )
if (__builtin_setjmp(jerr.setjmp_buffer)) {
#else
if (setjmp(jerr.setjmp_buffer)) {
#endif
/* If we get here, the JPEG code has signaled an error.
We need to clean up the JPEG object, close the file, remove the already saved part of the file and return.
*/
jpeg_destroy_compress(&cinfo);
fclose(file);
safe_g_remove(fname);
return IMIO_CANNOTWRITEFILE;
}
jpeg_create_compress (&cinfo);
FILE *file = safe_g_fopen_WriteBinLock (fname);
if (!file)
return IMIO_CANNOTREADFILE;
if (pl) {
pl->setProgressStr ("PROGRESSBAR_SAVEJPEG");
@@ -887,13 +937,13 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
unsigned char* buffer = new unsigned char[165535]; //FIXME: no buffer size check so it can be overflowed in createJPEGMarker() for large tags, and then software will crash
unsigned int size;
// assemble and write exif marker
if (exifRoot) {
if (exifRoot) {
int size = rtexif::ExifManager::createJPEGMarker (exifRoot, exifChange, cinfo.image_width, cinfo.image_height, buffer);
if (size>0 && size<65530)
jpeg_write_marker(&cinfo, JPEG_APP0+1, buffer, size);
}
// assemble and write iptc marker
if (iptc) {
if (iptc) {
unsigned char* iptcdata;
bool error = false;
if (iptc_data_save (iptc, &iptcdata, &size)) {
@@ -909,7 +959,9 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
}
if (!error)
jpeg_write_marker(&cinfo, JPEG_APP0+13, buffer, bytes);
}
}
delete [] buffer;
// write icc profile to the output
if (profileData)
write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength);
@@ -917,30 +969,44 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
// write image data
int rowlen = width*3;
unsigned char *row = new unsigned char [rowlen];
/* To avoid memory leaks we establish a new setjmp return context for my_error_exit to use. */
#if defined( WIN32 ) && defined( __x86_64__ )
if (__builtin_setjmp(jerr.setjmp_buffer)) {
#else
if (setjmp(jerr.setjmp_buffer)) {
#endif
/* If we get here, the JPEG code has signaled an error.
We need to clean up the JPEG object, close the file, remove the already saved part of the file and return.
*/
delete [] row;
jpeg_destroy_compress(&cinfo);
fclose(file);
safe_g_remove(fname);
return IMIO_CANNOTWRITEFILE;
}
while (cinfo.next_scanline < cinfo.image_height) {
getScanline (cinfo.next_scanline, row, 8);
if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) {
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
fclose (file);
return IMIO_READERROR;
jpeg_destroy_compress (&cinfo);
delete [] row;
fclose (file);
safe_g_remove(fname);
return IMIO_CANNOTWRITEFILE;
}
if (pl && !(cinfo.next_scanline%100))
pl->setProgress ((double)(cinfo.next_scanline)/cinfo.image_height);
}
jpeg_finish_compress (&cinfo);
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
delete [] row;
delete [] buffer;
fclose (file);
if (pl) {
pl->setProgressStr ("PROGRESSBAR_READY");
pl->setProgress (1.0);
@@ -952,7 +1018,7 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
//TODO: Handling 32 bits floating point output images!
bool writeOk = true;
int width = getW ();
int height = getH ();
@@ -967,7 +1033,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
if (!file) {
delete [] linebuffer;
return IMIO_CANNOTREADFILE;
return IMIO_CANNOTWRITEFILE;
}
if (pl) {
@@ -1007,7 +1073,9 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
pl->setProgress ((double)(i+1)/height);
}
delete [] buffer;
if (ferror(file))
writeOk = false;
fclose (file);
}
else {
@@ -1022,7 +1090,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
#endif
if (!out) {
delete [] linebuffer;
return IMIO_CANNOTREADFILE;
return IMIO_CANNOTWRITEFILE;
}
if (pl) {
@@ -1089,11 +1157,14 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
TIFFClose (out);
delete [] linebuffer;
return IMIO_READERROR;
return IMIO_CANNOTWRITEFILE;
}
if (pl && !(row%100))
pl->setProgress ((double)(row+1)/height);
}
}
if (TIFFFlush(out)!=1)
writeOk = false;
TIFFClose (out);
}
@@ -1103,7 +1174,12 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) {
pl->setProgress (1.0);
}
return IMIO_SUCCESS;
if(writeOk)
return IMIO_SUCCESS;
else {
safe_g_remove(fname);
return IMIO_CANNOTWRITEFILE;
}
}
// PNG read and write routines: