/** * Write PNG image data * @param buffer Image data * @param filename A filename of the PNG image to save * @param width Image width in pixels * @param height Image height in pixels * @param depth The bit depth of the image. * Valid values shall include 1, 2, 4, 8, 16. * @return TRUE if it completed successfully or FALSE otherwise */ static bool png_create (char *buffer, const char *filename, Uint32 width, Uint32 height, Sint32 depth) { Uint32 i; FILE *out; LOG_DBG ("Write %s", filename); if (buffer == NULL) { LOG_ERR ("image_to_buffer() failed! (filename = %s)", filename); return FALSE; } out = fopen_data (filename, "w"); if (out == NULL) { LOG_ERR ("can't open \"%s\"", filename); return FALSE; } /* allocate and initialize png_ptr struct for writing */ png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, /* error_ptr */ (png_voidp) NULL, /* error_fn */ NULL, /* warn_fn */ NULL); if (png_ptr == NULL) { LOG_ERR ("png_create_write_struct() failed"); return FALSE; } /* allocate and initialize the info structure */ png_infop info_ptr = png_create_info_struct (png_ptr); if (png_ptr == NULL) { LOG_ERR ("png_create_info_struct() failed"); return FALSE; } /* initialize input/output for PNG file to the default functions */ png_init_io (png_ptr, out); /* set library compression level */ png_set_IHDR (png_ptr, info_ptr, /* width */ width, /* height */ height, /* bit depth */ depth, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_compression_level (png_ptr, Z_BEST_COMPRESSION); png_set_text (png_ptr, info_ptr, text, sizeof text / sizeof text[0]); png_color_16 background; background.red = 0; background.green = 0; background.blue = 0; png_set_bKGD (png_ptr, info_ptr, &background); png_write_info (png_ptr, info_ptr); for (i = 0; i < height; i++) { { png_write_row (png_ptr, (png_byte *) & buffer[i * width * 4]); } } png_write_end (png_ptr, info_ptr); png_destroy_write_struct (&png_ptr, &info_ptr); fclose (out); return TRUE; }
/*! * pixWriteStreamPng() * * Input: stream * pix * gamma (use 0.0 if gamma is not defined) * Return: 0 if OK; 1 on error * * Notes: * (1) If called from pixWriteStream(), the stream is positioned * at the beginning of the file. * (2) To do sequential writes of png format images to a stream, * use pixWriteStreamPng() directly. * (3) gamma is an optional png chunk. If no gamma value is to be * placed into the file, use gamma = 0.0. Otherwise, if * gamma > 0.0, its value is written into the header. * (4) The use of gamma in png is highly problematic. For an illuminating * discussion, see: http://hsivonen.iki.fi/png-gamma/ * (5) What is the effect/meaning of gamma in the png file? This * gamma, which we can call the 'source' gamma, is the * inverse of the gamma that was used in enhance.c to brighten * or darken images. The 'source' gamma is supposed to indicate * the intensity mapping that was done at the time the * image was captured. Display programs typically apply a * 'display' gamma of 2.2 to the output, which is intended * to linearize the intensity based on the response of * thermionic tubes (CRTs). Flat panel LCDs have typically * been designed to give a similar response as CRTs (call it * "backward compatibility"). The 'display' gamma is * in some sense the inverse of the 'source' gamma. * jpeg encoders attached to scanners and cameras will lighten * the pixels, applying a gamma corresponding to approximately * a square-root relation of output vs input: * output = input^(gamma) * where gamma is often set near 0.4545 (1/gamma is 2.2). * This is stored in the image file. Then if the display * program reads the gamma, it will apply a display gamma, * typically about 2.2; the product is 1.0, and the * display program produces a linear output. This works because * the dark colors were appropriately boosted by the scanner, * as described by the 'source' gamma, so they should not * be further boosted by the display program. * (6) As an example, with xv and display, if no gamma is stored, * the program acts as if gamma were 0.4545, multiplies this by 2.2, * and does a linear rendering. Taking this as a baseline * brightness, if the stored gamma is: * > 0.4545, the image is rendered lighter than baseline * < 0.4545, the image is rendered darker than baseline * In contrast, gqview seems to ignore the gamma chunk in png. * (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16 * and 32. However, it is possible, and in some cases desirable, * to write out a png file using an rgb pix that has 24 bpp. * For example, the open source xpdf SplashBitmap class generates * 24 bpp rgb images. Consequently, we anble writing 24 bpp pix. * To generate such a pix, you can make a 24 bpp pix without data * and assign the data array to the pix; e.g., * pix = pixCreateHeader(w, h, 24); * pixSetData(pix, rgbdata); * See pixConvert32To24() for an example, where we get rgbdata * from the 32 bpp pix. Caution: do not call pixSetPadBits(), * because the alignment is wrong and you may erase part of the * last pixel on each line. */ l_int32 pixWriteStreamPng(FILE *fp, PIX *pix, l_float32 gamma) { char commentstring[] = "Comment"; l_int32 i, j, k; l_int32 wpl, d, cmflag; l_int32 ncolors; l_int32 *rmap, *gmap, *bmap; l_uint32 *data, *ppixel; png_byte bit_depth, color_type; png_uint_32 w, h; png_uint_32 xres, yres; png_bytep *row_pointers; png_bytep rowbuffer; png_structp png_ptr; png_infop info_ptr; png_colorp palette; PIX *pixt; PIXCMAP *cmap; char *text; PROCNAME("pixWriteStreamPng"); if (!fp) return ERROR_INT("stream not open", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); /* Allocate the 2 data structures */ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL)) == NULL) return ERROR_INT("png_ptr not made", procName, 1); if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return ERROR_INT("info_ptr not made", procName, 1); } /* Set up png setjmp error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return ERROR_INT("internal png error", procName, 1); } png_init_io(png_ptr, fp); /* With best zlib compression (9), get between 1 and 10% improvement * over default (5), but the compression is 3 to 10 times slower. * Our default compression is the zlib default (5). */ png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION); w = pixGetWidth(pix); h = pixGetHeight(pix); d = pixGetDepth(pix); if ((cmap = pixGetColormap(pix))) cmflag = 1; else cmflag = 0; /* Set the color type and bit depth. */ if (d == 32 && var_PNG_WRITE_ALPHA == 1) { bit_depth = 8; color_type = PNG_COLOR_TYPE_RGBA; /* 6 */ cmflag = 0; /* ignore if it exists */ } else if (d == 24 || d == 32) { bit_depth = 8; color_type = PNG_COLOR_TYPE_RGB; /* 2 */ cmflag = 0; /* ignore if it exists */ } else { bit_depth = d; color_type = PNG_COLOR_TYPE_GRAY; /* 0 */ } if (cmflag) color_type = PNG_COLOR_TYPE_PALETTE; /* 3 */ #if DEBUG fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n", cmflag, bit_depth, color_type); #endif /* DEBUG */ png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Store resolution in ppm, if known */ xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5); yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5); if ((xres == 0) || (yres == 0)) png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN); else png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER); if (cmflag) { pixcmapToArrays(cmap, &rmap, &gmap, &bmap); ncolors = pixcmapGetCount(cmap); /* Make and save the palette */ if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color)))) == NULL) return ERROR_INT("palette not made", procName, 1); for (i = 0; i < ncolors; i++) { palette[i].red = (png_byte)rmap[i]; palette[i].green = (png_byte)gmap[i]; palette[i].blue = (png_byte)bmap[i]; } png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors); FREE(rmap); FREE(gmap); FREE(bmap); } /* 0.4545 is treated as the default by some image * display programs (not gqview). A value > 0.4545 will * lighten an image as displayed by xv, display, etc. */ if (gamma > 0.0) png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma); if ((text = pixGetText(pix))) { png_text text_chunk; text_chunk.compression = PNG_TEXT_COMPRESSION_NONE; text_chunk.key = commentstring; text_chunk.text = text; text_chunk.text_length = strlen(text); #ifdef PNG_ITXT_SUPPORTED text_chunk.itxt_length = 0; text_chunk.lang = NULL; text_chunk.lang_key = NULL; #endif png_set_text(png_ptr, info_ptr, &text_chunk, 1); } /* Write header and palette info */ png_write_info(png_ptr, info_ptr); if ((d != 32) && (d != 24)) { /* not rgb color */ /* Generate a temporary pix with bytes swapped. * For a binary image, there are two conditions in * which you must first invert the data for writing png: * (a) no colormap * (b) colormap with BLACK set to 0 * png writes binary with BLACK = 0, unless contradicted * by a colormap. If the colormap has BLACK = "1" * (typ. about 255), do not invert the data. If there * is no colormap, you must invert the data to store * in default BLACK = 0 state. */ if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) { pixt = pixInvert(NULL, pix); pixEndianByteSwap(pixt); } else pixt = pixEndianByteSwapNew(pix); if (!pixt) { png_destroy_write_struct(&png_ptr, &info_ptr); return ERROR_INT("pixt not made", procName, 1); } /* Make and assign array of image row pointers */ if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL) return ERROR_INT("row-pointers not made", procName, 1); wpl = pixGetWpl(pixt); data = pixGetData(pixt); for (i = 0; i < h; i++) row_pointers[i] = (png_bytep)(data + i * wpl); png_set_rows(png_ptr, info_ptr, row_pointers); /* Transfer the data */ png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); if (cmflag) FREE(palette); FREE(row_pointers); pixDestroy(&pixt); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } /* For rgb, compose and write a row at a time */ data = pixGetData(pix); wpl = pixGetWpl(pix); if (d == 24) { /* See note 7 above: special case of 24 bpp rgb */ for (i = 0; i < h; i++) { ppixel = data + i * wpl; png_write_rows(png_ptr, (png_bytepp)&ppixel, 1); } } else { /* 32 bpp rgb and rgba */ if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL) return ERROR_INT("rowbuffer not made", procName, 1); for (i = 0; i < h; i++) { ppixel = data + i * wpl; for (j = k = 0; j < w; j++) { rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE); if (var_PNG_WRITE_ALPHA == 1) rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL); ppixel++; } png_write_rows(png_ptr, &rowbuffer, 1); } FREE(rowbuffer); } png_write_end(png_ptr, info_ptr); if (cmflag) FREE(palette); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; }
/** * @short Writes an image as png to the response object * * @param image flat buffer with all pixels * @param Bpp Bytes per pixel: 1 grayscale, 2 grayscale with alpha, 3 RGB, 4 RGB with alpha. Negative if in BGR format (cairo) * @param width The width of the image * @param height The height of the image * @param res where to write the image, it sets the necessary structs */ int onion_png_response(unsigned char *image, int Bpp, int width, int height, onion_response *res){ // Many copied from example.c from libpng source code. png_structp png_ptr; png_infop info_ptr; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, error, warning); if (png_ptr == NULL) { return OCS_INTERNAL_ERROR; } /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return OCS_INTERNAL_ERROR; } onion_png_data opd; opd.res=res; opd.sent=0; png_set_write_fn(png_ptr, (void *)&opd, onion_png_write, onion_png_flush); /* where user_io_ptr is a structure you want available to the callbacks */ onion_response_set_header(res, "Content-Type", "image/png"); if (onion_response_write_headers(res)==OR_SKIP_CONTENT) // Maybe it was HEAD. return OCS_PROCESSED; /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ if (Bpp<0){ png_set_bgr(png_ptr); Bpp=-Bpp; } switch(Bpp){ case 1: png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case 2: png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case 3: png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case 4: png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; default: png_error(png_ptr, "Wrong bytes per pixel"); break; } png_uint_32 k; png_bytep row_pointers[height]; if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) png_error (png_ptr, "Image is too tall to process in memory"); for (k = 0; k < height; k++) row_pointers[k] = (png_byte *) (image + k*width*Bpp); // Sets the rows to save at the image png_set_rows(png_ptr, info_ptr, row_pointers); // If header already sent, then there was an error. if (opd.sent){ return OCS_PROCESSED; } opd.sent=1; // Finally WRITE the image. Uses the onion_response_write via onion_png_write helper. png_write_png(png_ptr, info_ptr, 0, NULL); /* Clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); /* That's it */ return OCS_PROCESSED; }
CONVERT_IMAGERESULT write_PNG_file (CONVERT_IMG_ARRAY p_rowarray,CONVERT_IMGCONTEXT *output,CONVERT_IMG_INFO *p_imageinfo,CONVERT_CALLBACKS p_callbacks) { int16 colors,i; int16 maxcolor=MAXCOLORS-1; colorhist_vector chv; pixval maxval=MAXCOLORS-1; colorhash_table cht=NULL; png_structp write_ptr; png_infop info_ptr;/* important!*/ png_bytep rowbuf=NULL; int32 y; int num_pass, pass; CONVERT_IMAGERESULT result=CONV_OK; if (!output||!p_imageinfo) { return CONVERR_INVALIDPARAMS; } /* Figure out the colormap. */ chv = ppm_computecolorhist( (pixel **)p_rowarray, p_imageinfo->m_image_width, p_imageinfo->m_image_height, MAXCOLORS, &colors ); if ( chv == (colorhist_vector) 0 )/*more than 256 colors*/ { result=quantize_colors(p_rowarray,p_imageinfo->m_image_width,p_imageinfo->m_image_height,&maxcolor,&colors,&chv); if (result!=CONV_OK) return result; if ( chv == (colorhist_vector) 0 ) return CONVERR_INVALIDCOLORMAP; } /* And make a hash table for fast lookup. */ cht = ppm_colorhisttocolorhash( chv, colors ); if (!cht) { XP_ASSERT(FALSE); return CONVERR_OUTOFMEMORY; } write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); info_ptr=png_create_info_struct(write_ptr); info_ptr->width=p_imageinfo->m_image_width; info_ptr->height=p_imageinfo->m_image_height; info_ptr->bit_depth=8; info_ptr->color_type=3; /*3= indexed color*/ info_ptr->compression_type=0; /* only option available*/ info_ptr->filter_type=0; /* only valid value for adaptive filtering*/ info_ptr->interlace_type=0;/*0= no interlacing*/ info_ptr->num_palette=colors; /*from quantize_colors*/ info_ptr->palette=XP_ALLOC(3*colors);/*remember to free this*/ info_ptr->valid|=PNG_INFO_PLTE; for (i=0;i<colors;i++) { info_ptr->palette[i].red = PPM_GETR( chv[i].color ); info_ptr->palette[i].green = PPM_GETG( chv[i].color ); info_ptr->palette[i].blue = PPM_GETB( chv[i].color ); } ppm_freecolorhist( chv ); if (!info_ptr->palette) { png_destroy_write_struct(&write_ptr, &info_ptr); } /*transparancy???*/ if (setjmp(write_ptr->jmpbuf)) { png_destroy_write_struct(&write_ptr, &info_ptr); return CONVERR_BADWRITE; } png_init_io(write_ptr, output->m_stream.m_file); png_write_info(write_ptr, info_ptr); num_pass = 1; /*we need to look up each RGB and change it to the index of the color table*/ rowbuf=(png_bytep) XP_ALLOC(p_imageinfo->m_image_width); if (!rowbuf) { png_destroy_write_struct(&write_ptr, &info_ptr); return CONVERR_BADWRITE; } for (pass = 0; pass < num_pass; pass++) { for (y = 0; y < p_imageinfo->m_image_height; y++) { fill_png_row(p_rowarray[y],rowbuf,p_imageinfo->m_image_width,cht); png_write_rows(write_ptr, &rowbuf, 1); } } XP_FREE(rowbuf); png_write_end(write_ptr, NULL); XP_FREE(info_ptr->palette); png_destroy_write_struct(&write_ptr, &info_ptr); fclose(output->m_stream.m_file); return CONV_OK; }
int RE_SavePNG( const char *filename, byte *buf, size_t width, size_t height, int byteDepth ) { fileHandle_t fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int x, y; png_byte ** row_pointers = NULL; /* "status" contains the return value of this function. At first it is set to a value which means 'failure'. When the routine has finished its work, it is set to a value which means 'success'. */ int status = -1; /* The following number is set by trial and error only. I cannot see where it it is documented in the libpng manual. */ int depth = 8; fp = ri->FS_FOpenFileWrite( filename, qtrue ); if ( !fp ) { goto fopen_failed; } png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { goto png_create_write_struct_failed; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { goto png_create_info_struct_failed; } /* Set up error handling. */ if (setjmp (png_jmpbuf (png_ptr))) { goto png_failure; } /* Set image attributes. */ png_set_IHDR (png_ptr, info_ptr, width, height, depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Initialize rows of PNG. */ row_pointers = (png_byte **)png_malloc (png_ptr, height * sizeof (png_byte *)); for ( y=0; y<height; ++y ) { png_byte *row = (png_byte *)png_malloc (png_ptr, sizeof (uint8_t) * width * byteDepth); row_pointers[height-y-1] = row; for (x = 0; x < width; ++x) { byte *px = buf + (width * y + x)*3; *row++ = px[0]; *row++ = px[1]; *row++ = px[2]; } } /* Write the image data to "fp". */ // png_init_io (png_ptr, fp); png_set_write_fn( png_ptr, (png_voidp)&fp, user_write_data, user_flush_data ); png_set_rows (png_ptr, info_ptr, row_pointers); png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); /* The routine has successfully written the file, so we set "status" to a value which indicates success. */ status = 0; for (y = 0; y < height; y++) { png_free (png_ptr, row_pointers[y]); } png_free (png_ptr, row_pointers); png_failure: png_create_info_struct_failed: png_destroy_write_struct (&png_ptr, &info_ptr); png_create_write_struct_failed: ri->FS_FCloseFile( fp ); fopen_failed: return status; }
static int pixbuf2png(GdkPixbuf *pb, const char *output_png) { int i; int width = gdk_pixbuf_get_width(pb); int height = gdk_pixbuf_get_height(pb); int n_channels = gdk_pixbuf_get_n_channels(pb); int rowstride = gdk_pixbuf_get_rowstride(pb); guchar *pixels = gdk_pixbuf_get_pixels(pb); guchar *pixels_out = MALLOC(sizeof(guchar)*width*height*4); //printf("pixbuf2png> opening: %s\n", output_png); FILE *fout = FOPEN(output_png, "wb"); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { asfPrintWarning("Couldn't open png file: %s\n", output_png); return FALSE; } //printf("pixbuf2png> png_create_info_struct\n"); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(fout); asfPrintWarning("Couldn't open png info for %s\n", output_png); return FALSE; } //printf("pixbuf2png> setjmp\n"); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fout); asfPrintWarning("Error writing the png: %s\n", output_png); return FALSE; } //printf("pixbuf2png> png_init_io\n"); png_init_io(png_ptr, fout); //printf("pixbuf2png> png_set_IHDR\n"); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); //printf("pixbuf2png> png_write_info\n"); png_write_info(png_ptr, info_ptr); // add a transparency byte to each pixel in the pixels_out buffer for (i=0; i<height; ++i) { int j; for (j=0; j<width; ++j) { // output: red=k, green=k+1, blue=k+2, alpha=k+3 int out_k = 4*(j + i*width); // input: red=k, green=k+1, blue=k+2 int in_k = j*n_channels + i*rowstride; // make it transparent, if the pixel is black // (i.e., all channels are 0) int trans = pixels[in_k] == 0 && pixels[in_k+1] == 0 && pixels[in_k+2] == 0; pixels_out[out_k] = pixels[in_k]; pixels_out[out_k+1] = pixels[in_k+1]; pixels_out[out_k+2] = pixels[in_k+2]; pixels_out[out_k+3] = trans ? 0 : 255; } } //printf("pixbuf2png> row_pointers\n"); png_bytep *row_pointers = MALLOC(sizeof(png_bytep)*height); for (i=0; i<height; ++i) row_pointers[i] = pixels_out + i*width*4; //printf("pixbuf2png> png_write_image\n"); png_write_image(png_ptr, row_pointers); //printf("pixbuf2png> png_write_end\n"); png_write_end(png_ptr, NULL); //printf("pixbuf2png> png_destroy_write_struct\n"); png_destroy_write_struct(&png_ptr, &info_ptr); //printf("pixbuf2png> fclose\n"); fclose(fout); //printf("pixbuf2png> freeing row pointers\n"); FREE(row_pointers); FREE(pixels_out); return TRUE; }
int main(int argc, char **argv) { unsigned int i; png_byte **row_pointers; unsigned int filesize; png_infop info_ptr; png_structp png_ptr; if(argc!=3) usage(argv[0]); rawfile = fopen(argv[1], "rb"); if(!rawfile) usage(argv[0]); filesize = file_get_size(rawfile); side_size = raw_get_side(filesize); if(side_size == 0) usage(argv[0]); raw_buffer = malloc(filesize); if( !raw_buffer ) { fprintf(stderr, "Not enough memory\n"); fclose(rawfile); exit(EXIT_FAILURE); } if(fread(raw_buffer, sizeof(char), filesize, rawfile) != filesize) { fprintf(stderr, "Raw file reading error\n"); fclose(rawfile); free(raw_buffer); exit(EXIT_FAILURE); } fclose(rawfile); /*Create png file*/ pngfile = fopen(argv[2], "wb"); if(!pngfile) { fprintf(stderr, "Can't open %s for writting\n", argv[2]); free(raw_buffer); exit(EXIT_FAILURE); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "Can't create png file\n"); free(raw_buffer); fclose(pngfile); exit(EXIT_FAILURE); } info_ptr = png_create_info_struct(png_ptr); if (!png_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fprintf(stderr, "Can't create png file\n"); free(raw_buffer); fclose(pngfile); exit(EXIT_FAILURE); } png_init_io(png_ptr, pngfile); png_set_IHDR(png_ptr, info_ptr, side_size, side_size, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); row_pointers = malloc(sizeof(png_byte *)*side_size); if( !row_pointers ) { png_destroy_write_struct(&png_ptr, &info_ptr); fprintf(stderr, "Not enough memory\n"); free(raw_buffer); fclose(pngfile); exit(EXIT_FAILURE); } png_write_info (png_ptr, info_ptr); for(i = 0; i < side_size; i++) row_pointers[i] = raw_buffer+i*side_size; png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(pngfile); exit(EXIT_SUCCESS); }
void end_png() { png_destroy_write_struct(&png_ptr, &info_ptr); }
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) { png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; unsigned char *from, *to; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; /* use the jpeg quality setting for compression */ int compression; compression= (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); compression= compression < 0 ? 0 : (compression > 9 ? 9 : compression); /* for prints */ if (flags & IB_mem) name= "<memory>"; bytesperpixel = (ibuf->planes + 7) >> 3; if ((bytesperpixel > 4) || (bytesperpixel == 2)) { printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); return (0); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot setjmp for file: '%s'\n", name); return 0; } // copy image data pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); if (pixels == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; } from = (unsigned char *) ibuf->rect; to = pixels; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } break; case 3: color_type = PNG_COLOR_TYPE_RGB; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to += 3; from += 4; } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to++; from += 4; } break; } if (flags & IB_mem) { // create image in memory imb_addencodedbufferImBuf(ibuf); ibuf->encodedsize = 0; png_set_write_fn(png_ptr, (png_voidp) ibuf, WriteData, Flush); } else { fp = BLI_fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); MEM_freeN(pixels); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } png_init_io(png_ptr, fp); } #if 0 png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| PNG_ALL_FILTERS); #endif png_set_compression_level(png_ptr, compression); // png image settings png_set_IHDR(png_ptr, info_ptr, ibuf->x, ibuf->y, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* image text info */ if (ibuf->metadata) { png_text* metadata; ImMetaData* iptr; int num_text = 0; iptr = ibuf->metadata; while (iptr) { num_text++; iptr = iptr->next; } metadata = MEM_callocN(num_text*sizeof(png_text), "png_metadata"); iptr = ibuf->metadata; num_text = 0; while (iptr) { metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE; metadata[num_text].key = iptr->key; metadata[num_text].text = iptr->value; num_text++; iptr = iptr->next; } png_set_text(png_ptr, info_ptr, metadata, num_text); MEM_freeN(metadata); } if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER); } // write the file header information png_write_info(png_ptr, info_ptr); // allocate memory for an array of row-pointers row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); MEM_freeN(pixels); if (fp) { fclose(fp); } return 0; } // set the individual row-pointers to point at the correct offsets for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y-1-i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } // write out the entire image data in one call png_write_image(png_ptr, row_pointers); // write the additional chunks to the PNG file (not really needed) png_write_end(png_ptr, info_ptr); // clean up MEM_freeN(pixels); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) { fflush(fp); fclose(fp); } return(1); }
bool KPWriteImage::write2PNG(const QString& destPath) { FILE* file = fopen(QFile::encodeName(destPath), "wb"); if (!file) { kDebug( 51000 ) << "Failed to open PNG file for writing" << endl; return false; } uchar *data = 0; int bitsDepth = d->sixteenBit ? 16 : 8; png_color_8 sig_bit; png_bytep row_ptr; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, file); if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) // Intel png_set_bgr(png_ptr); else // PPC png_set_swap_alpha(png_ptr); if (d->hasAlpha) { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 8 * sizeof(uchar)]; else data = new uchar[d->width * 4 * sizeof(uchar)]; } else { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 6 * sizeof(uchar)]; else data = new uchar[d->width * 3 * sizeof(uchar)]; } sig_bit.red = bitsDepth; sig_bit.green = bitsDepth; sig_bit.blue = bitsDepth; sig_bit.alpha = bitsDepth; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_compression_level(png_ptr, 9); // Write ICC profil. if (!d->iccProfile.isEmpty()) { png_set_iCCP(png_ptr, info_ptr, (png_charp)"icc", PNG_COMPRESSION_TYPE_BASE, d->iccProfile.data(), d->iccProfile.size()); } // Write Software info. QString libpngver(PNG_HEADER_VERSION_STRING); libpngver.replace('\n', ' '); QString soft = d->kipipluginsVer; soft.append(QString(" (%1)").arg(libpngver)); png_text text; text.key = (png_charp)"Software"; text.text = soft.toAscii().data(); text.compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, &(text), 1); // Store Exif data. QByteArray ba = d->metadata.getExif(true); writeRawProfile(png_ptr, info_ptr, (png_charp)"exif", ba.data(), (png_uint_32) ba.size()); // Store Iptc data. QByteArray ba2 = d->metadata.getIptc(); writeRawProfile(png_ptr, info_ptr, (png_charp)"iptc", ba2.data(), (png_uint_32) ba2.size()); // Store Xmp data. QByteArray ba3 = d->metadata.getXmp(); writeRawProfile(png_ptr, info_ptr, (png_charp)("xmp"), ba3.data(), (png_uint_32) ba3.size()); png_write_info(png_ptr, info_ptr); png_set_shift(png_ptr, &sig_bit); png_set_packing(png_ptr); uchar* ptr = (uchar*)d->data.data(); uint x, y, j; for (y = 0; y < d->height; y++) { if (cancel()) { delete [] data; fclose(file); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); return false; } j = 0; for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth()) { if (d->sixteenBit) { if (d->hasAlpha) { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; data[j++] = ptr[x+7]; // Alpha data[j++] = ptr[x+6]; } else { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; } } else { if (d->hasAlpha) { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red data[j++] = ptr[x+3]; // Alpha } else { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red } } } row_ptr = (png_bytep) data; png_write_rows(png_ptr, &row_ptr, 1); ptr += (d->width * bytesDepth()); } delete [] data; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); fclose(file); return true; }
bool PngEncoder::write( const Mat& img, const std::vector<int>& params ) { png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); png_infop info_ptr = 0; FILE * volatile f = 0; int y, width = img.cols, height = img.rows; int depth = img.depth(), channels = img.channels(); volatile bool result = false; AutoBuffer<uchar*> buffer; if( depth != CV_8U && depth != CV_16U ) return false; if( png_ptr ) { info_ptr = png_create_info_struct( png_ptr ); if( info_ptr ) { if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { if( m_buf ) { png_set_write_fn(png_ptr, this, (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf); } else { f = fopen( m_filename.c_str(), "wb" ); if( f ) png_init_io( png_ptr, (png_FILE_p)f ); } int compression_level = -1; // Invalid value to allow setting 0-9 as valid int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy bool isBilevel = false; for( size_t i = 0; i < params.size(); i += 2 ) { if( params[i] == IMWRITE_PNG_COMPRESSION ) { compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy compression_level = params[i+1]; compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION); } if( params[i] == IMWRITE_PNG_STRATEGY ) { compression_strategy = params[i+1]; compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED); } if( params[i] == IMWRITE_PNG_BILEVEL ) { isBilevel = params[i+1] != 0; } } if( m_buf || f ) { if( compression_level >= 0 ) { png_set_compression_level( png_ptr, compression_level ); } else { // tune parameters for speed // (see http://wiki.linuxquestions.org/wiki/Libpng) png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB); png_set_compression_level(png_ptr, Z_BEST_SPEED); } png_set_compression_strategy(png_ptr, compression_strategy); png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16, channels == 1 ? PNG_COLOR_TYPE_GRAY : channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_write_info( png_ptr, info_ptr ); if (isBilevel) png_set_packing(png_ptr); png_set_bgr( png_ptr ); if( !isBigEndian() ) png_set_swap( png_ptr ); buffer.allocate(height); for( y = 0; y < height; y++ ) buffer[y] = img.data + y*img.step; png_write_image( png_ptr, buffer ); png_write_end( png_ptr, info_ptr ); result = true; } } } } png_destroy_write_struct( &png_ptr, &info_ptr ); if(f) fclose( (FILE*)f ); return result; }
static void s_PngWriteFinalize(png_structp& png_ptr, png_infop& info_ptr) { png_destroy_write_struct(&png_ptr, &info_ptr); }
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB) { bool bRet = false; do { CC_BREAK_IF(NULL == pszFilePath); FILE *fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_bytep *row_pointers; fp = fopen(pszFilePath, "wb"); CC_BREAK_IF(NULL == fp); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { fclose(fp); break; } info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); break; } #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA) if (setjmp(png_jmpbuf(png_ptr))) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } #endif png_init_io(png_ptr, fp); if (!bIsToRGB && m_bHasAlpha) { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } else { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = (png_bytep *)malloc(m_nHeight * sizeof(png_bytep)); if(row_pointers == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } if (!m_bHasAlpha) { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } else { if (bIsToRGB) { unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3]; if (NULL == pTempData) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } for (int i = 0; i < m_nHeight; ++i) { for (int j = 0; j < m_nWidth; ++j) { pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4]; pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1]; pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2]; } } for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)pTempData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; CC_SAFE_DELETE_ARRAY(pTempData); } else { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 4; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } } png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); palette = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); bRet = true; } while (0); return bRet; }
bool PngEncoder::write( const Mat& img, const Vector<int>& params ) { int compression_level = 0; for( size_t i = 0; i < params.size(); i += 2 ) { if( params[i] == CV_IMWRITE_PNG_COMPRESSION ) { compression_level = params[i+1]; compression_level = MIN(MAX(compression_level, 0), MAX_MEM_LEVEL); } } png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); png_infop info_ptr = 0; FILE* f = 0; int y, width = img.cols, height = img.rows; int depth = img.depth(), channels = img.channels(); bool result = false; AutoBuffer<uchar*> buffer; if( depth != CV_8U && depth != CV_16U ) return false; if( png_ptr ) { info_ptr = png_create_info_struct( png_ptr ); if( info_ptr ) { if( setjmp( png_ptr->jmpbuf ) == 0 ) { if( m_buf ) { png_set_write_fn(png_ptr, this, (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf); } else { f = fopen( m_filename.c_str(), "wb" ); if( f ) png_init_io( png_ptr, f ); } if( m_buf || f ) { if( compression_level > 0 ) { png_set_compression_mem_level( png_ptr, compression_level ); } else { // tune parameters for speed // (see http://wiki.linuxquestions.org/wiki/Libpng) png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB); png_set_compression_level(png_ptr, Z_BEST_SPEED); } png_set_compression_strategy(png_ptr, Z_HUFFMAN_ONLY); png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? 8 : 16, channels == 1 ? PNG_COLOR_TYPE_GRAY : channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_write_info( png_ptr, info_ptr ); png_set_bgr( png_ptr ); if( !isBigEndian() ) png_set_swap( png_ptr ); buffer.allocate(height); for( y = 0; y < height; y++ ) buffer[y] = img.data + y*img.step; png_write_image( png_ptr, buffer ); png_write_end( png_ptr, info_ptr ); result = true; } } } } png_destroy_write_struct( &png_ptr, &info_ptr ); if(f) fclose( f ); return result; }
void GBTileView::savePNG(const char* name) { uint8_t writeBuffer[1024 * 3]; FILE* fp = fopen(name, "wb"); if (!fp) { systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); return; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); fclose(fp); return; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, NULL); fclose(fp); return; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); uint8_t* b = writeBuffer; int sizeX = w; int sizeY = h; uint8_t* pixU8 = (uint8_t*)data; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { int blue = *pixU8++; int green = *pixU8++; int red = *pixU8++; *b++ = red; *b++ = green; *b++ = blue; } png_write_row(png_ptr, writeBuffer); b = writeBuffer; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); }
int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "usage: %s <input.png> <output_basename> <jpeg-quality>\n", *argv); return 1; } const char *infile = argv[1]; const char *outfile = argv[2]; int jpeg_quality = atoi(argv[3]); FILE *fpin = fopen(infile, "rb"); if (!fpin) { perror(infile); return 1; } unsigned char header[8]; fread(header, 1, 8, fpin); if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "this is not a PNG file\n"); fclose(fpin); return 1; } png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); assert(png_ptr); png_infop info_ptr = png_create_info_struct(png_ptr); assert(info_ptr); png_infop end_info = png_create_info_struct(png_ptr); assert (end_info); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fpin); fprintf(stderr, "failed.\n"); return 1; } png_init_io(png_ptr, fpin); png_set_sig_bytes(png_ptr, 8); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0); png_bytep * row_pointers = png_get_rows(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) { fprintf(stderr, "input PNG must be RGB+Alpha\n"); fclose(fpin); return 1; } if (bit_depth != 8) { fprintf(stderr, "input bit depth must be 8bit!\n"); fclose(fpin); return 1; } printf("png is %ldx%ld\n", width, height); int channels = png_get_channels(png_ptr, info_ptr); if (channels != 4) { fprintf(stderr, "channels must be 4.\n"); fclose(fpin); return 1; } fclose(fpin); /* now write jpeg */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW jrow_pointer[1]; FILE *outfp; char filename[strlen(outfile) + 10]; strcpy(filename, outfile); strcat(filename, ".rgb.jpg"); outfp = fopen(filename, "wb"); if (!outfp) { perror(filename); return 1; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, jpeg_quality, 1); jpeg_start_compress(&cinfo, 1); unsigned char *row = malloc(width * 3); while (cinfo.next_scanline < cinfo.image_height) { int x; jrow_pointer[0] = row; unsigned char *source = row_pointers[cinfo.next_scanline]; for (x = 0; x < width; ++x) { row[x * 3 + 0] = source[0]; row[x * 3 + 1] = source[1]; row[x * 3 + 2] = source[2]; source += 4; } jpeg_write_scanlines(&cinfo, jrow_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(outfp); jpeg_destroy_compress(&cinfo); /* and write png */ strcpy(filename, outfile); strcat(filename, ".a.png"); outfp = fopen(filename, "wb"); if (!outfp) { perror(filename); return 1; } png_structp png_ptr_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop info_ptr_w = png_create_info_struct(png_ptr_w); if (setjmp(png_jmpbuf(png_ptr_w))) { png_destroy_write_struct(&png_ptr_w, &info_ptr_w); fclose(outfp); return 1; } png_init_io(png_ptr_w, outfp); png_set_IHDR(png_ptr_w, info_ptr_w, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* turn RGBA into A, in-place */ int x, y; for (y=0; y < height; ++y) { unsigned char *source = row_pointers[y]; unsigned char *dst = source; for (x=0; x < width; ++x) { *dst++ = source[3]; source += 4; } } png_set_rows(png_ptr_w, info_ptr_w, row_pointers); png_write_png(png_ptr_w, info_ptr_w, PNG_TRANSFORM_IDENTITY, 0); png_write_end(png_ptr_w, info_ptr_w); png_destroy_write_struct(&png_ptr_w, &info_ptr_w); fclose(outfp); return 0; }
void PNGWriteClose(png_structp png, png_infop info) { if (!setjmp(png_jmpbuf(png))) { png_write_end(png, info); } png_destroy_write_struct(&png, &info); }
bool PNGImage::CleanMemoryUsage() { if(mRead == true && mWrite == true) return false; if(mRead == true) { if(mPng != NULL && mInfo != NULL) { png_destroy_read_struct(&mPng, &mInfo, NULL); mPng = NULL; mInfo = NULL; } else { if(mPng != NULL) { png_destroy_read_struct(&mPng, NULL, NULL); mPng = NULL; } else if(mInfo != NULL) { png_read_info(mPng, mInfo); mInfo = NULL; } } for (unsigned int y = 0; y < mHeight; y++) dFree(mRowPointers[y]); dFree(mRowPointers); mRowPointers= NULL; } else if(mWrite == true) { if(mPng != NULL && mInfo != NULL) { png_destroy_write_struct(&mPng, &mInfo); mPng = NULL; mInfo = NULL; } else { if(mPng != NULL) { png_destroy_write_struct(&mPng, NULL); mPng = NULL; } if(mInfo != NULL) { png_read_info(mPng, mInfo); mInfo = NULL; } } for (unsigned int y = 0; y < mHeight; y++) dFree(mRowPointers[y]); dFree(mRowPointers); mRowPointers = NULL; } return true; }
static int _store_picture_to_buffer_png(int width, int height,BYTE *prgb_data, guint8 **data, guint *data_len) { int l=0; //FILE *fp; guint8 *png_buff = g_new0(BYTE, width*height*3); png_structp png_ptr; png_infop info_ptr; png_text text_ptr[3]; png_bytep row_pointers[height]; /* open the file */ // fp = fopen(file_name, "wb"); // if (fp == NULL) // return (1); /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { //fclose(fp); g_free(png_buff); return (2); } /* Allocate/initialize the image information data. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { //fclose(fp); g_free(png_buff); png_destroy_write_struct(&png_ptr, NULL); return (3); } /* Set error handling. REQUIRED if you aren't supplying your own * error handling functions in the png_create_write_struct() call. */ if (setjmp(png_jmpbuf(png_ptr))) { /* If we get here, we had a problem reading the file */ //fclose(fp); g_free(png_buff); png_destroy_write_struct(&png_ptr, &info_ptr); return (4); } /* set up the output control using standard C streams */ //png_init_io(png_ptr, fp); _png_current_write_position = png_buff; voidp write_io_ptr = png_get_io_ptr(png_ptr); png_set_write_fn(png_ptr, write_io_ptr, _png_mem_write_data, _png_mem_flush_data); /* turn on or off filtering, and/or choose specific filters. You can use either a single PNG_FILTER_VALUE_NAME or the bitwise OR of one or more PNG_FILTER_NAME masks. */ /* png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| PNG_ALL_FILTERS);*/ /* set the zlib compression level */ //png_set_compression_level(png_ptr, // Z_BEST_COMPRESSION); /* set other zlib parameters */ //png_set_compression_mem_level(png_ptr, 8); //png_set_compression_strategy(png_ptr, // Z_DEFAULT_STRATEGY); //png_set_compression_window_bits(png_ptr, 15); //png_set_compression_method(png_ptr, 8); //png_set_compression_buffer_size(png_ptr, 8192); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Optional gamma chunk is strongly suggested if you have any guess * as to the correct gamma of the image. */ //png_set_gAMA(png_ptr, info_ptr, gamma); /* Optionally write comments into the image */ text_ptr[0].key = "Title"; //text_ptr[0].text = file_name; text_ptr[0].text = "Snapshot"; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[1].key = "Software"; text_ptr[1].text = "guvcview"; text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[2].key = "Description"; text_ptr[2].text = "File generated by guvcview <http://guvcview.berlios.de>"; text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE; #ifdef PNG_iTXt_SUPPORTED text_ptr[0].lang = NULL; text_ptr[1].lang = NULL; text_ptr[2].lang = NULL; #endif png_set_text(png_ptr, info_ptr, text_ptr, 3); /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); /* flip BGR pixels to RGB */ //png_set_bgr(png_ptr); /*?no longuer required?*/ /* Write the image data.*/ for (l = 0; l < height; l++) row_pointers[l] = prgb_data + l*width*3; png_write_image(png_ptr, row_pointers); /* You can write optional chunks like tEXt, zTXt, and tIME at the end * as well. Shouldn't be necessary in 1.1.0 and up as all the public * chunks are supported and you can use png_set_unknown_chunks() to * register unknown chunks into the info structure to be written out. */ /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* If you png_malloced a palette, free it here (don't free info_ptr->palette, as recommended in versions 1.0.5m and earlier of this example; if libpng mallocs info_ptr->palette, libpng will free it). If you allocated it with malloc() instead of png_malloc(), use free() instead of png_free(). */ //png_free(png_ptr, palette); //palette=NULL; /* Similarly, if you png_malloced any data that you passed in with png_set_something(), such as a hist or trans array, free it here, when you can be sure that libpng is through with it. */ //png_free(png_ptr, trans); //trans=NULL; /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); /* close the file */ #if 0 fflush(fp); //flush data stream to file system if(fsync(fileno(fp)) || fclose(fp)) { perror("PNG ERROR - couldn't write to file"); return(5); } #endif *data_len = _png_current_write_position - png_buff; *data = malloc(*data_len); g_print("png size: %d\n", *data_len); memmove(*data, png_buff, *data_len); g_free(png_buff); for(l=0;l<height;l++) { row_pointers[l]=NULL; } /* that's it */ return (0); }
int svlImageCodecPNG::Write(const svlSampleImage &image, const unsigned int videoch, unsigned char *buffer, size_t &buffersize, const int compression) { if (videoch >= image.GetVideoChannels()) return SVL_FAIL; if (!buffer) return SVL_FAIL; const int width = static_cast<int>(image.GetWidth(videoch)); const int height = static_cast<int>(image.GetHeight(videoch)); const int row_stride = width * 3; unsigned char *src; int i; // Allocate row buffer if not done yet if (!pngRows) { pngRows = new unsigned char*[height]; pngRowsSize = height; } else if (pngRows && pngRowsSize < static_cast<unsigned int>(height)) { delete [] pngRows; pngRows = new unsigned char*[height]; pngRowsSize = height; } PNG_target_mem_info targetinfo; targetinfo.ptr = buffer; targetinfo.size = static_cast<unsigned int>(buffersize); targetinfo.comprsize = 0; targetinfo.error = false; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) return SVL_FAIL; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, reinterpret_cast<png_infopp>(0)); return SVL_FAIL; } // error handling for the following calls if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } png_set_write_fn(png_ptr, &targetinfo, PNG_user_write_data_proc, PNG_user_flush_data_proc); if (targetinfo.error) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // error handling for the following calls if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // set compression options png_set_compression_level(png_ptr, (compression >= 0) ? std::min(compression, 9) : PNG_DEFAULT_QUALITY); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT); png_set_bgr(png_ptr); // write header png_write_info(png_ptr, info_ptr); if (targetinfo.error) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // generate row pointer array src = const_cast<unsigned char*>(image.GetUCharPointer(videoch)); for (i = 0; i < height; i ++) { pngRows[i] = src; src += row_stride; } // error handling for the following call if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // write image data png_write_image(png_ptr, pngRows); if (targetinfo.error) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // error handling for the following call if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return SVL_FAIL; } // write ending png_write_end(png_ptr, 0); // clean up png_destroy_write_struct(&png_ptr, &info_ptr); buffersize = static_cast<int>(targetinfo.comprsize); return SVL_OK; }
bool snapshot_png(int width, int height, const char* path) { FILE *file = fopen(path, "wb"); if(!file) { printf("can't open file %s for writing\n", path); return false; } png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL/*user_error_ptr*/, NULL/*user_error_fn*/, NULL/*user_warning_fn*/); if(!png_ptr) { printf("error: png_create_read_struct returned 0.\n"); fclose(file); return false; } png_info* info_ptr = png_create_info_struct(png_ptr); if(!info_ptr || setjmp(png_jmpbuf(png_ptr))) { printf("error: png_create_read_struct returned 0 or set error handling failed.\n"); png_destroy_write_struct(&png_ptr, (info_ptr==NULL)?NULL:&info_ptr); fclose(file); return false; } png_init_io(png_ptr, file); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ const int bit_depth = 8; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Optional significant bit (sBIT) chunk */ png_color_8 sig_bit; sig_bit.red = bit_depth; sig_bit.green = bit_depth; sig_bit.blue = bit_depth; sig_bit.alpha = 0; // no alpha channel png_set_sBIT(png_ptr, info_ptr, &sig_bit); // Write the file header information. png_write_info(png_ptr, info_ptr); if((png_uint_32)height > PNG_UINT_32_MAX/(sizeof(png_byte*))) png_error(png_ptr, "Image is too tall to process in memory"); png_byte** row_ptrs = (png_byte**)malloc(height * sizeof(png_byte*)); if(!row_ptrs) printf("malloc failed for row_ptrs.\n"); else { const size_t line = sizeof(GLubyte) * width * 3; // RGB components GLubyte *data = (GLubyte*)malloc(line * height); if(data) { /* Make sure the rows are packed as tight as possible (no row padding), * set the pack alignment to 1. */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); /* Set the individual row_ptrs to point at the correct offsets of image * data, note that it's upside down to keep consistent with the screen * coordinate system. */ for(int row = 0; row < height; ++row) row_ptrs[row] = (png_byte*)data + line * row; png_write_image(png_ptr, row_ptrs); png_write_end(png_ptr, info_ptr); free(data); } } png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); free(row_ptrs); return(row_ptrs != NULL); }
bool StreamerPNG::saveBitmap(const Bitmap & bitmap, std::ostream & output) { volatile int colorType = 0; // volatile is needed because of the setjmp later on. volatile int transforms = 0; const PixelFormat & pixelFormat = bitmap.getPixelFormat(); if(pixelFormat == PixelFormat::RGBA) { colorType = PNG_COLOR_TYPE_RGB_ALPHA; transforms = PNG_TRANSFORM_IDENTITY; } else if(pixelFormat == PixelFormat::BGRA) { colorType = PNG_COLOR_TYPE_RGB_ALPHA; transforms = PNG_TRANSFORM_BGR; } else if(pixelFormat == PixelFormat::RGB) { colorType = PNG_COLOR_TYPE_RGB; transforms = PNG_TRANSFORM_IDENTITY; } else if(pixelFormat == PixelFormat::BGR) { colorType = PNG_COLOR_TYPE_RGB; transforms = PNG_TRANSFORM_BGR; } else if(pixelFormat == PixelFormat::MONO) { colorType = PNG_COLOR_TYPE_GRAY; transforms = PNG_TRANSFORM_IDENTITY; } else if(pixelFormat == PixelFormat::MONO_FLOAT) { Reference<Bitmap> tmp = BitmapUtils::convertBitmap(bitmap, PixelFormat::MONO); return saveBitmap(*tmp.get(), output); } else { WARN("Unable to save PNG file. Unsupported color type."); return false; } // Set up the necessary structures for libpng. png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, nullptr); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return false; } struct PNGFunctions { static void writeData(png_structp write_ptr, png_bytep data, png_size_t length) { std::ostream * out = reinterpret_cast<std::ostream *>(png_get_io_ptr(write_ptr)); out->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(length)); } static void flushData(png_structp flush_ptr) { std::ostream * out = reinterpret_cast<std::ostream *>(png_get_io_ptr(flush_ptr)); out->flush(); } }; png_set_write_fn(png_ptr, reinterpret_cast<png_voidp>(&output), PNGFunctions::writeData, PNGFunctions::flushData); const uint32_t width = bitmap.getWidth(); const uint32_t height = bitmap.getHeight(); png_set_IHDR(png_ptr, info_ptr, width, height, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // Write the image. std::vector<png_bytep> row_pointers; row_pointers.reserve(height); const uint8_t bytes = pixelFormat.getBytesPerPixel(); for (uint_fast32_t row = 0; row < height; ++row) { // Take over rows in the same order. row_pointers.push_back(reinterpret_cast<png_bytep>(const_cast<uint8_t *>(bitmap.data()) + row * width * bytes)); } png_set_rows(png_ptr, info_ptr, row_pointers.data()); png_write_png(png_ptr, info_ptr, transforms, nullptr); // Clean up. png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
static int lsave(lua_State *L) { int color_type; int step; int bit_depth = 8; const char *filename = luaL_checkstring(L,1); const char *type = luaL_checkstring(L,2); if (!strcmp(type, "RGBA8")) { color_type = PNG_COLOR_TYPE_RGB_ALPHA; step = 4; } else if (!strcmp(type, "RGB8")) { color_type = PNG_COLOR_TYPE_RGB; step = 3; } else if (!strcmp(type, "GRAY")) { color_type = PNG_COLOR_TYPE_GRAY; step = 1; } else { return luaL_error(L, "png type %s not support", type); } int width = luaL_checkinteger(L,3); int height = luaL_checkinteger(L,4); luaL_checktype(L,5, LUA_TTABLE); int n = lua_rawlen(L,5); if (n != width * height * step) { return luaL_error(L, "Data number %d invalid, should be %d*%d*%d = %d", n, width, height, step, width * height * step); } FILE *fp = fopen(filename, "wb"); if (fp == NULL) { return luaL_error(L, strerror(errno)); } png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_bytep *row_pointers; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) { return luaL_error(L, "png_create_write_struct fail"); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return luaL_error(L, "png_destroy_write_struct fail"); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } uint8_t *buffer = (uint8_t *)malloc(width * height *step); int i; for (i=0; i<height *width; ++i) { lua_rawgeti(L,5,i*step+1); lua_rawgeti(L,5,i*step+2); lua_rawgeti(L,5,i*step+3); lua_rawgeti(L,5,i*step+4); buffer[i*step+0] = (uint8_t)lua_tointeger(L,-4); buffer[i*step+1] = (uint8_t)lua_tointeger(L,-3); buffer[i*step+2] = (uint8_t)lua_tointeger(L,-2); buffer[i*step+3] = (uint8_t)lua_tointeger(L,-1); lua_pop(L,4); } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = (png_bytep*)malloc(height * sizeof(png_bytep)); for (i = 0; i<height; i++) row_pointers[i] = buffer + i* width* step; png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); png_destroy_write_struct(&png_ptr, &info_ptr); free(row_pointers); free(buffer); fclose(fp); return 0; }
void GL_ScreenShot_PNG (void) { byte *rgbdata; FILE *file; char picname[80], checkname[MAX_OSPATH]; int i, j, k; png_structp png_ptr; png_infop info_ptr; //not working yet... ri.Con_Printf (PRINT_ALL, "PNG Screenshot...(^iDisabled^r)\n"); return; // Create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); Sys_Mkdir (checkname); for (i=0 ; i<=999 ; i++) { Com_sprintf (picname, sizeof(picname), "quake2max%i%i%i.png", (int)(i/100)%10, (int)(i/10)%10, i%10); Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname); file = fopen (checkname, "rb"); if (!file) break; // file doesn't exist fclose (file); } if (i==1000) { ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create a file\n"); return; } // Allocate room for a copy of the framebuffer rgbdata = malloc(vid.width * vid.height * 3); if(!rgbdata) return; // Read the framebuffer into our storage qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0,0,0); if (!png_ptr) { free(rgbdata); ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (NO PNG_PTR)\n"); return; } // Allocate/initialize the image information data. REQUIRED info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, 0); free(rgbdata); ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (NO INFO_PTR)\n"); return; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); free(rgbdata); ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (BAD INFO)\n"); return; } // Open the file for Binary Output file = fopen(checkname, "wb"); if(!file) { ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create a file\n"); return; } png_init_io(png_ptr, file); png_set_IHDR(png_ptr, info_ptr, vid.width, vid.height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); for (k = 0; k < vid.height; k++) { void *pointer = rgbdata + k*vid.width*3; png_write_row(png_ptr, pointer); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); // Close File fclose(file); // Free Temp Framebuffer free(rgbdata); // Done! ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname); }
/* This routine is used for all formats. */ static int png_print_page(gx_device_printer * pdev, FILE * file) { gs_memory_t *mem = pdev->memory; int raster = gdev_prn_raster(pdev); /* PNG structures */ byte *row = gs_alloc_bytes(mem, raster, "png raster buffer"); png_struct *png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_info *info_ptr = png_create_info_struct(png_ptr); int height = pdev->height; int depth = pdev->color_info.depth; int y; int code; /* return code */ char software_key[80]; char software_text[256]; png_text text_png; if (row == 0 || png_ptr == 0 || info_ptr == 0) { code = gs_note_error(gs_error_VMerror); goto done; } /* set error handling */ if (setjmp(png_ptr->jmpbuf)) { /* If we get here, we had a problem reading the file */ code = gs_note_error(gs_error_VMerror); goto done; } code = 0; /* for normal path */ /* set up the output control */ png_init_io(png_ptr, file); /* set the file information here */ info_ptr->width = pdev->width; info_ptr->height = pdev->height; /* resolution is in pixels per meter vs. dpi */ info_ptr->x_pixels_per_unit = (png_uint_32) (pdev->HWResolution[0] * (100.0 / 2.54)); info_ptr->y_pixels_per_unit = (png_uint_32) (pdev->HWResolution[1] * (100.0 / 2.54)); info_ptr->phys_unit_type = PNG_RESOLUTION_METER; info_ptr->valid |= PNG_INFO_pHYs; switch (depth) { case 32: info_ptr->bit_depth = 8; info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; png_set_invert_alpha(png_ptr); { gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev; png_color_16 background; background.index = 0; background.red = (ppdev->background >> 16) & 0xff; background.green = (ppdev->background >> 8) & 0xff; background.blue = (ppdev->background) & 0xff; background.gray = 0; png_set_bKGD(png_ptr, info_ptr, &background); } break; case 48: info_ptr->bit_depth = 16; info_ptr->color_type = PNG_COLOR_TYPE_RGB; #if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN) png_set_swap(png_ptr); #endif break; case 24: info_ptr->bit_depth = 8; info_ptr->color_type = PNG_COLOR_TYPE_RGB; break; case 8: info_ptr->bit_depth = 8; if (gx_device_has_color(pdev)) info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; else info_ptr->color_type = PNG_COLOR_TYPE_GRAY; break; case 4: info_ptr->bit_depth = 4; info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; break; case 1: info_ptr->bit_depth = 1; info_ptr->color_type = PNG_COLOR_TYPE_GRAY; /* invert monocrome pixels */ png_set_invert_mono(png_ptr); break; } /* set the palette if there is one */ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int i; int num_colors = 1 << depth; gx_color_value rgb[3]; info_ptr->palette = (void *)gs_alloc_bytes(mem, 256 * sizeof(png_color), "png palette"); if (info_ptr->palette == 0) { code = gs_note_error(gs_error_VMerror); goto done; } info_ptr->num_palette = num_colors; info_ptr->valid |= PNG_INFO_PLTE; for (i = 0; i < num_colors; i++) { (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev, (gx_color_index) i, rgb); info_ptr->palette[i].red = gx_color_value_to_byte(rgb[0]); info_ptr->palette[i].green = gx_color_value_to_byte(rgb[1]); info_ptr->palette[i].blue = gx_color_value_to_byte(rgb[2]); } } /* add comment */ strncpy(software_key, "Software", sizeof(software_key)); sprintf(software_text, "%s %d.%02d", gs_product, (int)(gs_revision / 100), (int)(gs_revision % 100)); text_png.compression = -1; /* uncompressed */ text_png.key = software_key; text_png.text = software_text; text_png.text_length = strlen(software_text); info_ptr->text = &text_png; info_ptr->num_text = 1; /* write the file information */ png_write_info(png_ptr, info_ptr); /* don't write the comments twice */ info_ptr->num_text = 0; info_ptr->text = NULL; /* Write the contents of the image. */ for (y = 0; y < height; y++) { gdev_prn_copy_scan_lines(pdev, y, row, raster); png_write_rows(png_ptr, &row, 1); } /* write the rest of the file */ png_write_end(png_ptr, info_ptr); /* if you alloced the palette, free it here */ gs_free_object(mem, info_ptr->palette, "png palette"); done: /* free the structures */ png_destroy_write_struct(&png_ptr, &info_ptr); gs_free_object(mem, row, "png raster buffer"); return code; }
int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){ #ifdef IMPLEMENT_SAVE_PNG png_structp png_ptr; png_infop info_ptr; SDL_PixelFormat *fmt=NULL; SDL_Surface *tempsurf=NULL; int ret,funky_format; unsigned int i; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_BlendMode temp_blend; bool used_blend = false; #else Uint8 temp_alpha; bool used_alpha = false; #endif png_colorp palette; Uint8 *palette_alpha=NULL; png_byte **row_pointers=NULL; png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1; funky_format=0; if( !src || !surf) { goto savedone; /* Nothing to do. */ } row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*)); if (!row_pointers) { SDL_SetError("Couldn't allocate memory for rowpointers"); goto savedone; } png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!png_ptr){ SDL_SetError("Couldn't allocate memory for PNG file"); goto savedone; } info_ptr= png_create_info_struct(png_ptr); if (!info_ptr){ SDL_SetError("Couldn't allocate image information for PNG file"); goto savedone; } /* setup custom writer functions */ png_set_write_fn(png_ptr,(voidp)src,png_write_data,NULL); if (setjmp(png_jmpbuf(png_ptr))){ SDL_SetError("Unknown error writing PNG"); goto savedone; } if(compression>Z_BEST_COMPRESSION) compression=Z_BEST_COMPRESSION; if(compression == Z_NO_COMPRESSION) // No compression { png_set_filter(png_ptr,0,PNG_FILTER_NONE); png_set_compression_level(png_ptr,Z_NO_COMPRESSION); } else if(compression<0) // Default compression png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION); else png_set_compression_level(png_ptr,compression); fmt=surf->format; if(fmt->BitsPerPixel==8){ /* Paletted */ png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); palette=(png_colorp) malloc(fmt->palette->ncolors * sizeof(png_color)); if (!palette) { SDL_SetError("Couldn't create memory for palette"); goto savedone; } for (i=0;i<fmt->palette->ncolors;i++) { palette[i].red=fmt->palette->colors[i].r; palette[i].green=fmt->palette->colors[i].g; palette[i].blue=fmt->palette->colors[i].b; } png_set_PLTE(png_ptr,info_ptr,palette,fmt->palette->ncolors); #if SDL_VERSION_ATLEAST(2, 0, 0) Uint32 colorkey; if (SDL_GetColorKey(surf, &colorkey) == 0) { #else if (surf->flags&SDL_SRCCOLORKEY) { Uint32 colorkey = fmt->colorkey; #endif palette_alpha=(Uint8 *)malloc((colorkey+1)*sizeof(Uint8)); if (!palette_alpha) { SDL_SetError("Couldn't create memory for palette transparency"); goto savedone; } /* FIXME: memset? */ for (i=0;i<(colorkey+1);i++) { palette_alpha[i]=255; } palette_alpha[colorkey]=0; png_set_tRNS(png_ptr,info_ptr,palette_alpha,colorkey+1,NULL); } }else{ /* Truecolor */ if (fmt->Amask) { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } else { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } } png_write_info(png_ptr, info_ptr); if (fmt->BitsPerPixel==8) { /* Paletted */ for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } }else{ /* Truecolor */ if(fmt->BytesPerPixel==3){ if(fmt->Amask){ /* check for 24 bit with alpha */ funky_format=1; }else{ /* Check for RGB/BGR/GBR/RBG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF0000 || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0x0000FF){ #else if(fmt->Rmask!=0x0000FF || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0xFF0000){ #endif funky_format=1; } } }else if (fmt->BytesPerPixel==4){ if (!fmt->Amask) { /* check for 32bit but no alpha */ funky_format=1; }else{ /* Check for ARGB/ABGR/GBAR/RABG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF000000 || fmt->Gmask!=0x00FF0000 || fmt->Bmask!=0x0000FF00 || fmt->Amask!=0x000000FF){ #else if(fmt->Rmask!=0x000000FF || fmt->Gmask!=0x0000FF00 || fmt->Bmask!=0x00FF0000 || fmt->Amask!=0xFF000000){ #endif funky_format=1; } } }else{ /* 555 or 565 16 bit color */ funky_format=1; } if (funky_format) { /* Allocate non-funky format, and copy pixeldata in*/ if(fmt->Amask){ #if SDL_VERSION_ATLEAST(2, 0, 0) tempsurf = SDL_CreateRGBSurface(0, surf->w, surf->h, 24, SURFACE_MASK_WITH_ALPHA); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, SURFACE_MASK_WITH_ALPHA); #endif }else{ #if SDL_VERSION_ATLEAST(2, 0, 0) tempsurf = SDL_CreateRGBSurface(0, surf->w, surf->h, 24, SURFACE_MASK_WITHOUT_ALPHA); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, SURFACE_MASK_WITHOUT_ALPHA); #endif } if(!tempsurf){ SDL_SetError("Couldn't allocate temp surface"); goto savedone; } #if SDL_VERSION_ATLEAST(2, 0, 0) if(SDL_GetSurfaceBlendMode(surf, &temp_blend) == 0){ used_blend = true; SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE); } #else if(surf->flags&SDL_SRCALPHA) { temp_alpha = fmt->alpha; used_alpha = true; SDL_SetAlpha(surf,0,255); /* Set for an opaque blit */ } #endif if(SDL_BlitSurface(surf, NULL, tempsurf, NULL)!=0){ SDL_SetError("Couldn't blit surface to temp surface"); SDL_FreeSurface(tempsurf); goto savedone; } #if SDL_VERSION_ATLEAST(2, 0, 0) if (used_blend) { SDL_SetSurfaceBlendMode(surf, temp_blend); /* Restore blend settings*/ } #else if(used_alpha) { SDL_SetAlpha(surf, SDL_SRCALPHA, (Uint8)temp_alpha); /* Restore alpha settings*/ } #endif for(i=0;i<tempsurf->h;i++){ row_pointers[i]= ((png_byte*)tempsurf->pixels) + i*tempsurf->pitch; } if(SDL_MUSTLOCK(tempsurf)){ SDL_LockSurface(tempsurf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(tempsurf)){ SDL_UnlockSurface(tempsurf); } SDL_FreeSurface(tempsurf); } else { for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } } } png_write_end(png_ptr, NULL); ret=0; /* got here, so nothing went wrong. YAY! */ savedone: /* clean up and return */ png_destroy_write_struct(&png_ptr,&info_ptr); if (palette) { free(palette); } if (palette_alpha) { free(palette_alpha); } if (row_pointers) { free(row_pointers); } return ret; #else return -1; #endif }
bool ScreenshotManager::encode_png(std::shared_ptr<uint8_t> pxdata, coord::window size) { std::FILE *fout = NULL; coord::pixel_t width = size.x, height = size.y; auto warn_fn = [] (png_structp /*png_ptr*/, png_const_charp message) { log::log(MSG(err) << "Creating screenshot failed: libpng error: " << message); }; auto err_fn = [] (png_structp png_ptr, png_const_charp message) { log::log(MSG(err) << "Creating screenshot failed: libpng error: " << message); longjmp(png_jmpbuf(png_ptr), 1); }; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, err_fn, warn_fn); if (!png_ptr) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return false; } if (setjmp(png_jmpbuf(png_ptr))) { std::fclose(fout); png_destroy_write_struct(&png_ptr, &info_ptr); return false; } std::string filename = this->gen_next_filename(); fout = std::fopen(filename.c_str(), "wb"); if (fout == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); log::log(MSG(err) << "Could not open '"<< filename << "': " << std::string(strerror(errno))); return false; } png_init_io(png_ptr, fout); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // Put image row pointer into info_ptr so that we can use the high-level // write interface. std::vector<png_bytep> row_ptrs; // Invert rows. row_ptrs.reserve(height); for (int i = 1; i <= height; i++) { row_ptrs.push_back(pxdata.get() + (height - i) * 4 * width); } png_set_rows(png_ptr, info_ptr, &row_ptrs[0]); //TODO: print ingame message. log::log(MSG(info) << "Saving screenshot to '" << filename << "'."); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL); std::fclose(fout); png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_colorp palette = NULL; png_uint_32 width, height; BOOL has_alpha_channel = FALSE; RGBQUAD *pal; // pointer to dib palette int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels int palette_entries; int interlace_type; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if ((dib) && (handle)) { try { // create the chunk manage structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return FALSE; } // allocate/initialize the image information data. info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return FALSE; } // Set error handling. REQUIRED if you aren't supplying your own // error handling functions in the png_create_write_struct() call. if (setjmp(png_jmpbuf(png_ptr))) { // if we get here, we had a problem reading the file png_destroy_write_struct(&png_ptr, &info_ptr); return FALSE; } // init the IO png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc); // set physical resolution BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib); png_uint_32 res_x = bih->biXPelsPerMeter; png_uint_32 res_y = bih->biYPelsPerMeter; if ((res_x > 0) && (res_y > 0)) { png_set_pHYs(png_ptr, info_ptr, res_x, res_y, 1); } // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED interlace_type = PNG_INTERLACE_NONE; // Default value width = FreeImage_GetWidth(dib); height = FreeImage_GetHeight(dib); pixel_depth = FreeImage_GetBPP(dib); FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type == FIT_BITMAP) { // standard image type bit_depth = (pixel_depth > 8) ? 8 : pixel_depth; } else { // 16-bit greyscale or 16-bit RGB bit_depth = 16; } switch (FreeImage_GetColorType(dib)) { case FIC_MINISWHITE: // Invert monochrome files to have 0 as black and 1 as white (no break here) png_set_invert_mono(png_ptr); case FIC_MINISBLACK: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case FIC_PALETTE: { png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set the palette palette_entries = 1 << bit_depth; palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color)); pal = FreeImage_GetPalette(dib); for (int i = 0; i < palette_entries; i++) { palette[i].red = pal[i].rgbRed; palette[i].green = pal[i].rgbGreen; palette[i].blue = pal[i].rgbBlue; } png_set_PLTE(png_ptr, info_ptr, palette, palette_entries); // You must not free palette here, because png_set_PLTE only makes a link to // the palette that you malloced. Wait until you are about to destroy // the png structure. break; } case FIC_RGBALPHA : has_alpha_channel = TRUE; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGBA, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #ifndef FREEIMAGE_BIGENDIAN // flip BGR pixels to RGB png_set_bgr(png_ptr); #endif break; case FIC_RGB: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #ifndef FREEIMAGE_BIGENDIAN // flip BGR pixels to RGB if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case FIC_CMYK: break; } // write possible ICC profile FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib); if (iccProfile->size && iccProfile->data) { png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_charp)iccProfile->data, iccProfile->size); } // write metadata WriteMetadata(png_ptr, info_ptr, dib); // Optional gamma chunk is strongly suggested if you have any guess // as to the correct gamma of the image. // png_set_gAMA(png_ptr, info_ptr, gamma); // set the transparency table if ((pixel_depth == 8) && (FreeImage_IsTransparent(dib)) && (FreeImage_GetTransparencyCount(dib) > 0)) png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL); // set the background color if(FreeImage_HasBackgroundColor(dib)) { png_color_16 image_background; RGBQUAD rgbBkColor; FreeImage_GetBackgroundColor(dib, &rgbBkColor); memset(&image_background, 0, sizeof(png_color_16)); image_background.blue = rgbBkColor.rgbBlue; image_background.green = rgbBkColor.rgbGreen; image_background.red = rgbBkColor.rgbRed; image_background.index = rgbBkColor.rgbReserved; png_set_bKGD(png_ptr, info_ptr, &image_background); } // Write the file header information. png_write_info(png_ptr, info_ptr); // write out the image data #ifndef FREEIMAGE_BIGENDIAN if (bit_depth == 16) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif if ((pixel_depth == 32) && (!has_alpha_channel)) { BYTE *buffer = (BYTE *)malloc(width * 3); // transparent conversion to 24-bit for (png_uint_32 k = 0; k < height; k++) { FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); png_write_row(png_ptr, buffer); } free(buffer); } else { for (png_uint_32 k = 0; k < height; k++) { png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); } } // It is REQUIRED to call this to finish writing the rest of the file // Bug with png_flush png_write_end(png_ptr, info_ptr); // clean up after the write, and free any memory allocated if (palette) png_free(png_ptr, palette); png_destroy_write_struct(&png_ptr, &info_ptr); return TRUE; } catch (const char *text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
/* Test one file */ int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { static png_FILE_p fpin; static png_FILE_p fpout; /* "static" prevents setjmp corruption */ png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; #ifdef PNG_WRITE_SUPPORTED png_structp write_ptr; png_infop write_info_ptr; png_infop write_end_info_ptr; #else png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; png_infop write_end_info_ptr = NULL; #endif png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; int num_pass, pass; int bit_depth, color_type; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; #endif #endif char inbuf[256], outbuf[256]; row_buf = NULL; if ((fpin = fopen(inname, "rb")) == NULL) { fprintf(STDERR, "Could not find input file %s\n", inname); return (1); } if ((fpout = fopen(outname, "wb")) == NULL) { fprintf(STDERR, "Could not open output file %s\n", outname); FCLOSE(fpin); return (1); } png_debug(0, "Allocating read and write structures"); #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); #else read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif #ifndef PNG_STDIO_SUPPORTED png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); #endif #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED user_chunk_data[0] = 0; user_chunk_data[1] = 0; user_chunk_data[2] = 0; user_chunk_data[3] = 0; png_set_read_user_chunk_fn(read_ptr, user_chunk_data, read_user_chunk_callback); #endif #ifdef PNG_WRITE_SUPPORTED #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, png_debug_malloc, png_debug_free); #else write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif #ifndef PNG_STDIO_SUPPORTED png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); #endif #endif png_debug(0, "Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); end_info_ptr = png_create_info_struct(read_ptr); #ifdef PNG_WRITE_SUPPORTED write_info_ptr = png_create_info_struct(write_ptr); write_end_info_ptr = png_create_info_struct(write_ptr); #endif #ifdef PNG_SETJMP_SUPPORTED png_debug(0, "Setting jmpbuf for read struct"); #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(read_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); row_buf = NULL; png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); #ifdef PNG_WRITE_SUPPORTED png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif FCLOSE(fpin); FCLOSE(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); #endif #ifdef PNG_WRITE_SUPPORTED png_debug(0, "Setting jmpbuf for write struct"); #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(write_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr); #ifdef PNG_WRITE_SUPPORTED png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif FCLOSE(fpin); FCLOSE(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); #endif #endif #endif png_debug(0, "Initializing input and output streams"); #ifdef PNG_STDIO_SUPPORTED png_init_io(read_ptr, fpin); # ifdef PNG_WRITE_SUPPORTED png_init_io(write_ptr, fpout); # endif #else png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); # ifdef PNG_WRITE_SUPPORTED png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, # ifdef PNG_WRITE_FLUSH_SUPPORTED pngtest_flush); # else NULL); # endif # endif #endif if (status_dots_requested == 1) { #ifdef PNG_WRITE_SUPPORTED png_set_write_status_fn(write_ptr, write_row_callback); #endif png_set_read_status_fn(read_ptr, read_row_callback); } else { #ifdef PNG_WRITE_SUPPORTED png_set_write_status_fn(write_ptr, NULL); #endif png_set_read_status_fn(read_ptr, NULL); } #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED { int i; for (i = 0; i<256; i++) filters_used[i] = 0; png_set_read_user_transform_fn(read_ptr, count_filters); } #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED zero_samples = 0; png_set_write_user_transform_fn(write_ptr, count_zero_samples); #endif #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED # ifndef PNG_HANDLE_CHUNK_ALWAYS # define PNG_HANDLE_CHUNK_ALWAYS 3 # endif png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED # ifndef PNG_HANDLE_CHUNK_IF_SAFE # define PNG_HANDLE_CHUNK_IF_SAFE 2 # endif png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, NULL, 0); #endif png_debug(0, "Reading info struct"); png_read_info(read_ptr, read_info_ptr); png_debug(0, "Transferring info struct"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, #ifdef PNG_WRITE_INTERLACING_SUPPORTED color_type, interlace_type, compression_type, filter_type); #else color_type, PNG_INTERLACE_NONE, compression_type, filter_type); #endif } }
int main(int argc, char *argv[]) { char filename1[MAXNAMELENGTH], filename2[MAXNAMELENGTH]; int idx, k, j; FILE *fd, *lut=NULL; byte *imgarr; int userfill=-1; int colorstyle=GRAYSCALE; int red, green, blue, alpha; int redarr[256], greenarr[256], bluearr[256], alphaarr[256]; unsigned char lutname[MAXNAMELENGTH]; unsigned char verbose=FALSE; png_structp png_ptr; png_infop info_ptr; png_colorp png_palette; png_colorp dest_pal; unsigned char *png_trans; png_structp in_png_ptr; png_infop in_info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; png_uint_32 i, rowbytes; byte *image_data = NULL; png_bytepp row_pointers = NULL; int bytesperpixel; int found; int num_not_found=0; int rednotfound[MAX_NOT_FOUND], greennotfound[MAX_NOT_FOUND], bluenotfound[MAX_NOT_FOUND]; int return_code=0; filename1[0] = '\0'; filename2[0] = '\0'; lutname[0] = '\0'; if (argc < 2) { fprintf(stderr, "Usage: RGBApng2Palpng [-v] -lut=<ColorMap file (must contain RGBA)> -fill=<LUT index value> -of=<output palette PNG file> <input RGBA PNG file>\n"); exit(-1); } for (j=1; j<argc; j++) if ( strcmp(argv[j], "-v") == 0 ) { fprintf(stderr, "Verbose mode requested.\n"); verbose = TRUE; } for (j=1; j<argc; j++) { if (strstr(argv[j], "-of=") == argv[j] ) { if ( sscanf(argv[j], "-of=%s", filename2) != 1 ) { fprintf(stderr, "Cannot read output file\n"); exit(-1); } if (verbose) fprintf(stderr, "Output file: %s\n", filename2); } else if (strstr(argv[j], "-lut=") == argv[j] ) { if ( sscanf(argv[j], "-lut=%s", lutname) != 1 ) { fprintf(stderr, "Cannot parse LUT name\n"); exit(-1); } if (verbose) fprintf(stderr, "Color LUT: %s\n", lutname); colorstyle = COLOR; } else if (strstr(argv[j], "-fill=") == argv[j] ) { if (sscanf(argv[j], "-fill=%d", &userfill) != 1) { fprintf(stderr, "Cannot read user fill value\n"); exit(-1); } if ( userfill < 0 || userfill > 255 ) { fprintf(stderr, "User fill value must be between 0 and 255\n"); exit(-1); } if (verbose) fprintf(stderr, "User fill value: %d\n", userfill); } else if ( strlen(filename2) == 0 && strcmp(argv[j], "-") == 0 ) { strcpy(filename2, "stdout"); if (verbose) fprintf(stderr, "Output file: %s\n", filename2); } else if ( strcmp(argv[j], "-v") != 0 ) { strcpy(filename1, argv[j]); if (verbose) fprintf(stderr, "Input file: %s\n", filename1); } } if ( strlen(filename1) == 0 || strlen(filename2) == 0 || strlen(lutname) == 0 || userfill < 0 ) { fprintf(stderr, "Unable to get all arguments\n"); exit(-1); } if ((fp = fopen(filename1, "rb")) == NULL) { fprintf(stderr, "Unable to open input file: %s\n", filename1); exit(-1); } in_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (in_png_ptr == NULL) { fclose(fp); fprintf(stderr, "Could not allocate PNG read struct\n"); return (-1); } in_info_ptr = png_create_info_struct(in_png_ptr); if (in_info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&in_png_ptr, png_infopp_NULL, png_infopp_NULL); fprintf(stderr, "Could not allocate input PNG info struct\n"); return (-1); } if (setjmp(png_jmpbuf(in_png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&in_png_ptr, &in_info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (-1); } /* Set up the input control if you are using standard C streams */ png_init_io(in_png_ptr, fp); png_read_info(in_png_ptr, in_info_ptr); png_get_IHDR(in_png_ptr, in_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); if (verbose) { fprintf(stderr, "Width: %d\n", width); fprintf(stderr, "Height: %d\n", height); fprintf(stderr, "Bit Depth: %d\n", bit_depth); switch(color_type) { case 0: fprintf(stderr, "Color Type: Gray (0)\n"); break; case 3: fprintf(stderr, "Color Type: Palette (3)\n"); break; case 2: fprintf(stderr, "Color Type: RGB (2)\n"); break; case 6: fprintf(stderr, "Color Type: RGB Alpha (6)\n"); break; case 4: fprintf(stderr, "Color Type: Gray Alpha (4)\n"); break; default: fprintf(stderr, "Unknown Color Type: %d\n", color_type); } switch(interlace_type) { case 0: fprintf(stderr, "Interlace Type: None (0)\n"); break; case 1: fprintf(stderr, "Interlace Type: Adam7 (1)\n"); break; default: fprintf(stderr, "Unknown Interlace Type: %d\n", interlace_type); } } rowbytes = png_get_rowbytes(in_png_ptr, in_info_ptr); if ( verbose ) fprintf(stderr, "Number of bytes per row: %d\n", rowbytes); if ((image_data = (byte *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL); exit(-1); } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL); free(image_data); image_data = NULL; exit(-1); } for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(in_png_ptr, row_pointers); imgarr = (byte *) malloc(height * width * sizeof(byte)); png_palette = (png_colorp)malloc( 256 * sizeof( png_color) ); dest_pal = png_palette; if (colorstyle == GRAYSCALE) for (j=0; j<256; j++) { dest_pal->red = dest_pal->green = dest_pal->blue = j; dest_pal++; redarr[j] = greenarr[j] = bluearr[j] = j; alphaarr[j] = 255; } else { if ( (lut = fopen(lutname, "r")) != NULL ) { if (strlen(lutname) > 4 && ((!strcmp(lutname + strlen(lutname) - 4, ".xml")))) { fprintf(stderr, "Opening colormap file %s\n", lutname); if (lut) { int size = 1024, pos; int c; int j = 0; char *buffer = (char *)malloc(size); const char *entry_key = "ColorMapEntry"; const char *rgb_key = "rgb="; const char *transparent_key = "transparent="; const char *true_str = "\"true\""; do { // read all lines in file pos = 0; do { // read one line c = fgetc(lut); if(c != EOF) buffer[pos++] = (char)c; if(pos >= size - 1) { // increase buffer length - leave room for 0 size *=2; buffer = (char*)realloc(buffer, size); } } while(c != EOF && c != '\n'); buffer[pos] = 0; char *entry = strstr(buffer,entry_key); char *rgb = strstr(buffer,rgb_key); char *transparent = strstr(buffer,transparent_key); // GIBS colormap RGB values if (rgb != NULL && entry != NULL) { char rgb_string[11]; int rgb_length = strlen(rgb); int rgb_pos = pos - rgb_length; memcpy(rgb_string, &buffer[rgb_pos+5], 11); rgb_string[11] = '\0'; // break rgb string into int values int rgb_array[3]; int i = 0; char *rgb_values = strtok(rgb_string, ","); while (rgb_values != NULL) { rgb_array[i++] = strtol(rgb_values,NULL,10); rgb_values = strtok(NULL, ","); } red = rgb_array[0]; green = rgb_array[1]; blue = rgb_array[2]; dest_pal->red = red; dest_pal->green = green; dest_pal->blue = blue; alpha = strstr(transparent, true_str) != NULL ? 0 : 255; dest_pal++; redarr[j] = red; greenarr[j] = green; bluearr[j] = blue; alphaarr[j] = alpha; if ( verbose ) fprintf(stderr, "RGBA: %d %d %d %d \n", redarr[j], greenarr[j] , bluearr[j], alphaarr[j]); j++; } } while(c != EOF);; fclose(lut); free(buffer); } } else { for (j=0; j<256; j++) if ( fscanf(lut, "%d %d %d %d", &red, &green, &blue, &alpha) != 4 ) { fprintf(stderr, "Cannot read color index %d in LUT file\n", j); exit(-1); } else { dest_pal->red = red; dest_pal->green = green; dest_pal->blue = blue; dest_pal++; redarr[j] = red; greenarr[j] = green; bluearr[j] = blue; alphaarr[j] = alpha; } fclose(lut); } } else { fprintf(stderr, "Cannot open LUT file %s.\n", lutname); exit(-1); } } png_trans = (unsigned char *)malloc(256 * sizeof(unsigned char)); for (j=0; j<256; j++) { png_trans[j] = alphaarr[j]; } switch(color_type) { case(PNG_COLOR_TYPE_GRAY): bytesperpixel = 1; break; case(PNG_COLOR_TYPE_PALETTE): bytesperpixel = 1; break; case(PNG_COLOR_TYPE_RGB): bytesperpixel = 3; break; case(PNG_COLOR_TYPE_RGB_ALPHA): bytesperpixel = 4; break; case(PNG_COLOR_TYPE_GRAY_ALPHA): bytesperpixel = 2; break; default: fprintf(stderr, "Unknown Color Type: %d\n", color_type); exit(-1); } if ( color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA ) { fprintf(stderr, "Color Type must be RGB or RGBA.\n"); exit(-1); } if ( verbose ) fprintf(stderr, "Bytes per Pixel: %d\n", bytesperpixel); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { idx = i*width+j; red = image_data[i*width*bytesperpixel+j*bytesperpixel]; green = image_data[i*width*bytesperpixel+j*bytesperpixel+1]; blue = image_data[i*width*bytesperpixel+j*bytesperpixel+2]; found = FALSE; for (k = 0; k < 256; k++) { if ( red == redarr[k] && green == greenarr[k] && blue == bluearr[k] ) { imgarr[idx] = (unsigned char) k; found = TRUE; break; } } if ( !found ) { imgarr[idx] = (unsigned char) userfill; found = FALSE; if ( num_not_found < MAX_NOT_FOUND ) { for (k = 0; k < num_not_found; k++) { if ( red == rednotfound[k] && green == greennotfound[k] && blue == bluenotfound[k] ) { found = TRUE; break; } } if ( !found ) { rednotfound[num_not_found] = red; greennotfound[num_not_found] = green; bluenotfound[num_not_found] = blue; num_not_found++; } } } } } if ( num_not_found > 0 ) { return_code = num_not_found; fprintf(stderr, "%d Colors in image not found in color table\n", num_not_found); for (k = 0; k < num_not_found; k++) { fprintf(stderr, "%3d %3d %3d\n", rednotfound[k], greennotfound[k], bluenotfound[k]); } } // Done with the read, clean up free(row_pointers); row_pointers = NULL; png_read_end(in_png_ptr, NULL); free(image_data); image_data = NULL; fclose(fp); // Start the write if (strcmp(filename2, "stdout") == 0) fd = stdout; else if ( (fd = fopen(filename2, "wb")) == NULL ) { fprintf(stderr, "Cannot open file %s.\n", filename2); exit(-1); } // Initialize write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fprintf(stderr, "Could not allocate PNG write struct\n"); exit(-1); } // Initialize info structure info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fprintf(stderr, "Could not allocate PNG info struct\n"); exit(-1); } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG init_io\n"); exit(-1); } png_init_io(png_ptr, fd); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set header\n"); exit(-1); } // Write header (8 bit colour depth) png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set pallette\n"); exit(-1); } png_set_PLTE(png_ptr, info_ptr, png_palette, 256); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set transparency\n"); exit(-1); } png_set_tRNS(png_ptr, info_ptr, png_trans, 256, NULL); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write info\n"); exit(-1); } png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write row\n"); exit(-1); } for (k=0; k<height; k++) { idx = k * width; png_write_row(png_ptr, &imgarr[idx]); } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write end\n"); exit(-1); } // End write png_write_end(png_ptr, NULL); fclose(fd); free(imgarr); free(png_palette); free(png_trans); if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return return_code; }