This patch to Andreas Dilger's XV PNG patch 1.2d addresses the following bugs, buglets and typos: - fixes a core-dump triggered by an unfortunate "feature" in libpng 0.97 and later (i.e., libpng frees text buffers it didn't allocate) - forces text comments inherited from GIF or elsewhere to be in proper PNG format (i.e., Unix-style "LF" line-endings); inherited PNG comments are still assumed to be in proper format - corrects argument types for png_xv_error() and png_xv_warning() to match what png_create_write_struct() and png_create_read_struct() expect - changes default ">>" increment on compression dial from 2 to 3 so that maximum compression (level 9) is one click away from default (level 6) - fixes some comment typos and removes overlooked debug code This code has been tested with various versions of libpng, most recently version 1.0.1c4 (precursor to 1.0.2), with no apparent problems. Greg Roelofs, newt@pobox.com 10 May 1998 *** xvpng.c.stock Thu Jun 13 16:42:11 1996 --- xvpng.c Sun May 10 13:02:07 1998 *************** *** 49,54 **** --- 49,57 ---- #define BUTTH 24 + #define LF 10 /* a.k.a. '\n' on ASCII machines */ + #define CR 13 /* a.k.a. '\r' on ASCII machines */ + /*** local functions ***/ static void drawPD PARM((int, int, int, int)); static void clickPD PARM((int, int)); *************** *** 57,64 **** static int WritePNG PARM((FILE *, byte *, int, int, int, byte *, byte *, byte *, int)); ! static void png_xv_error PARM((png_struct *png_ptr, char *message)); ! static void png_xv_warning PARM((png_struct *png_ptr, char *message)); /*** local variables ***/ static char *filename; --- 60,69 ---- static int WritePNG PARM((FILE *, byte *, int, int, int, byte *, byte *, byte *, int)); ! static void png_xv_error PARM((png_structp png_ptr, ! png_const_charp message)); ! static void png_xv_warning PARM((png_structp png_ptr, ! png_const_charp message)); /*** local variables ***/ static char *filename; *************** *** 87,93 **** XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask); DCreate(&cDial, pngW, 12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION, ! (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 2.0, infofg, infobg, hicol, locol, "Compression", NULL); DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2, --- 92,98 ---- XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask); DCreate(&cDial, pngW, 12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION, ! (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 3.0, infofg, infobg, hicol, locol, "Compression", NULL); DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2, *************** *** 594,607 **** int j; p = pic; for(j = 0; j < h; j++) { - fflush(stdout); if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) { int k; for(k = 0; k < w; k++) png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) : remap[p[k]]; png_write_row(png_ptr, png_line); ! } else /* rbg or palette */ png_write_row(png_ptr, p); if((j & 0x1f) == 0) WaitCursor(); p += linesize; --- 606,618 ---- int j; p = pic; for(j = 0; j < h; j++) { if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) { int k; for(k = 0; k < w; k++) png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) : remap[p[k]]; png_write_row(png_ptr, png_line); ! } else /* RGB or palette */ png_write_row(png_ptr, p); if((j & 0x1f) == 0) WaitCursor(); p += linesize; *************** *** 690,700 **** tp++; } } ! /* It is just a generic comment */ else { tp->key = "Comment"; tp->text = key; ! tp->text_length = strlen(tp->text); tp->compression = tp->text_length > 750 ? 0 : -1; info_ptr->num_text++; key = NULL; --- 701,725 ---- tp++; } } ! /* Just a generic comment: make sure line-endings are valid for PNG */ else { + char *p=key, *q=key; /* only deleting chars, not adding any */ + + while (*p) { + if (*p == CR) { /* lone CR or CR/LF: EOL either way */ + *q++ = LF; /* LF is the only allowed PNG line-ending */ + if (p[1] == LF) /* get rid of any original LF */ + ++p; + } else if (*p == LF) /* lone LF */ + *q++ = LF; + else + *q++ = *p; + ++p; + } + *q = '\0'; /* unnecessary...but what the heck */ tp->key = "Comment"; tp->text = key; ! tp->text_length = q - key; tp->compression = tp->text_length > 750 ? 0 : -1; info_ptr->num_text++; key = NULL; *************** *** 712,726 **** info_ptr->valid |= PNG_INFO_tIME; png_write_end(png_ptr, info_ptr); ! png_destroy_write_struct(&png_ptr, &info_ptr); if (text) { free(text); if (savecmnt) free(savecmnt); } return 0; } --- 737,758 ---- info_ptr->valid |= PNG_INFO_tIME; png_write_end(png_ptr, info_ptr); ! fflush(fp); /* just in case we core-dump before finishing... */ if (text) { free(text); + /* must do this or png_destroy_write_struct() 0.97+ will free text again: */ + info_ptr->text = (png_textp)NULL; if (savecmnt) + { free(savecmnt); + savecmnt = (char *)NULL; + } } + png_destroy_write_struct(&png_ptr, &info_ptr); + return 0; } *************** *** 941,948 **** --- 999,1010 ---- /*******************************************/ static void png_xv_error(png_ptr, message) + /* png_struct *png_ptr; char *message; + */ + png_structp png_ptr; + png_const_charp message; { SetISTR(ISTR_WARNING,"%s: libpng error: %s", fbasename, message); *************** *** 953,960 **** --- 1015,1026 ---- /*******************************************/ static void png_xv_warning(png_ptr, message) + /* png_struct *png_ptr; char *message; + */ + png_structp png_ptr; + png_const_charp message; { if (!png_ptr) return;