Exemple #1
0
/**
 * 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;
}
Exemple #2
0
/*!
 *  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;

}
Exemple #3
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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);
 }
Exemple #9
0
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);
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}
Exemple #12
0
static void s_PngWriteFinalize(png_structp& png_ptr,
                              png_infop&    info_ptr)
{
    png_destroy_write_struct(&png_ptr, &info_ptr);
}
Exemple #13
0
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;
}
Exemple #14
0
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);
}
Exemple #16
0
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;
}
Exemple #17
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);
}
Exemple #18
0
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);
}
Exemple #20
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;
}
Exemple #21
0
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);
}
Exemple #22
0
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;
}
Exemple #23
0
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;
}
Exemple #24
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;
}
Exemple #26
0
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
}
Exemple #27
0
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;
}
Exemple #29
0
/* 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;

}