Example #1
0
int enc_png(char *data,g2int width,g2int height,g2int nbits,char *pngbuf)
{
 
    int color_type;
    g2int j,bytes,pnglen,bit_depth;
    png_structp png_ptr;
    png_infop info_ptr;
//    png_bytep *row_pointers[height];
    png_bytep **row_pointers;
    png_stream write_io_ptr;

/* create and initialize png_structs  */

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, 
                                      NULL, NULL);
    if (!png_ptr)
       return (-1);

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
       png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
       return (-2);
    }

/*     Set Error callback   */

    if (setjmp(png_jmpbuf(png_ptr)))
    {
       png_destroy_write_struct(&png_ptr, &info_ptr);
       return (-3);
    }

/*    Initialize info for writing PNG stream to memory   */

    write_io_ptr.stream_ptr=(png_voidp)pngbuf;
    write_io_ptr.stream_len=0;

/*    Set new custom write functions    */

    png_set_write_fn(png_ptr,(voidp)&write_io_ptr,(png_rw_ptr)user_write_data,
                    (png_flush_ptr)user_flush_data);
/*    png_init_io(png_ptr, fptr);   */
/*    png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);  */

/*     Set the image size, colortype, filter type, etc...      */

/*    printf("SAGTsettingIHDR %d %d %d\n",width,height,bit_depth); */
    bit_depth=nbits;
    color_type=PNG_COLOR_TYPE_GRAY;
    if (nbits == 24 ) {
        bit_depth=8;
        color_type=PNG_COLOR_TYPE_RGB;
    }
    else if (nbits == 32 ) {
        bit_depth=8;
        color_type=PNG_COLOR_TYPE_RGB_ALPHA;
    }
    png_set_IHDR(png_ptr, info_ptr, width, height,
       bit_depth, color_type, PNG_INTERLACE_NONE,
       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

/*     Put image data into the PNG info structure    */

    /*bytes=bit_depth/8;*/
    bytes=nbits/8;
    row_pointers=malloc(height*sizeof(png_bytep));
    for (j=0;j<height;j++) row_pointers[j]=(png_bytep *)(data+(j*width*bytes));
    png_set_rows(png_ptr, info_ptr, (png_bytepp)row_pointers);

/*     Do the PNG encoding, and write out PNG stream  */

    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

/*     Clean up   */

    png_destroy_write_struct(&png_ptr, &info_ptr);
    free(row_pointers);
    pnglen=write_io_ptr.stream_len;
    return pnglen;

}
Example #2
0
int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst) 
{
	png_structp png_ptr;
	png_infop info_ptr;
	png_colorp pal_ptr;
	SDL_Palette *pal;
	int i, colortype;
#ifdef USE_ROW_POINTERS
	png_bytep *row_pointers;
#endif
	/* Initialize and do basic error checking */
	if (!dst)
	{
		SDL_SetError("Argument 2 to SDL_SavePNG_RW can't be NULL, expecting SDL_RWops*\n");
		return (ERROR);
	}
	if (!surface)
	{
		SDL_SetError("Argument 1 to SDL_SavePNG_RW can't be NULL, expecting SDL_Surface*\n");
		if (freedst) SDL_RWclose(dst);
		return (ERROR);
	}
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_SDL, NULL); /* err_ptr, err_fn, warn_fn */
	if (!png_ptr) 
	{
		SDL_SetError("Unable to png_create_write_struct on %s\n", PNG_LIBPNG_VER_STRING);
		if (freedst) SDL_RWclose(dst);
		return (ERROR);
	}
	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		SDL_SetError("Unable to png_create_info_struct\n");
		png_destroy_write_struct(&png_ptr, NULL);
		if (freedst) SDL_RWclose(dst);
		return (ERROR);
	}
	if (setjmp(png_jmpbuf(png_ptr)))	/* All other errors, see also "png_error_SDL" */
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		if (freedst) SDL_RWclose(dst);
		return (ERROR);
	}

	/* Setup our RWops writer */
	png_set_write_fn(png_ptr, dst, png_write_SDL, NULL); /* w_ptr, write_fn, flush_fn */

	/* Prepare chunks */
	colortype = PNG_COLOR_MASK_COLOR;
	if (surface->format->BytesPerPixel > 0
	&&  surface->format->BytesPerPixel <= 8
	&& (pal = surface->format->palette))
	{
		colortype |= PNG_COLOR_MASK_PALETTE;
		pal_ptr = (png_colorp)malloc(pal->ncolors * sizeof(png_color));
		for (i = 0; i < pal->ncolors; i++) {
			pal_ptr[i].red   = pal->colors[i].r;
			pal_ptr[i].green = pal->colors[i].g;
			pal_ptr[i].blue  = pal->colors[i].b;
		}
		png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
		free(pal_ptr);
	}
	else if (surface->format->BytesPerPixel > 3 || surface->format->Amask)
		colortype |= PNG_COLOR_MASK_ALPHA;

	png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

//	png_set_packing(png_ptr);

	/* Allow BGR surfaces */
	if (surface->format->Rmask == bmask
	&& surface->format->Gmask == gmask
	&& surface->format->Bmask == rmask)
		png_set_bgr(png_ptr);

	/* Write everything */
	png_write_info(png_ptr, info_ptr);
#ifdef USE_ROW_POINTERS
	row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surface->h);
	for (i = 0; i < surface->h; i++)
		row_pointers[i] = (png_bytep)(Uint8*)surface->pixels + i * surface->pitch;
	png_write_image(png_ptr, row_pointers);
	free(row_pointers);
#else
	for (i = 0; i < surface->h; i++)
		png_write_row(png_ptr, (png_bytep)(Uint8*)surface->pixels + i * surface->pitch);
#endif
	png_write_end(png_ptr, info_ptr);

	/* Done */
	png_destroy_write_struct(&png_ptr, &info_ptr);
	if (freedst) SDL_RWclose(dst);
	return (SUCCESS);
}
Example #3
0
// 绘制函数 func ,采用 colorfunction 做配色方案
// 输出为 png 格式
int displayplot(FILE *png_file,
				unsigned width, unsigned height,
				double (*func)(double,double),
				double xmin, double xmax,
				double ymin, double ymax,
				int (*colorfunction)(double))
{
  unsigned row,col;
  //  unsigned r,g,b;
  double x,y,z;
  double xstep,ystep;
  int color;

  png_struct    *png_ptr = NULL;
  png_info      *info_ptr = NULL;
  png_byte      *png_pixels = NULL;
  png_byte      **row_pointers = NULL;
  png_byte      *pix_ptr = NULL;
  png_uint_32   row_bytes;

  int           color_type;
  int           bit_depth = 0;
  int           channels = 3;  // RGB
  unsigned      i;

  if(width<1 || height<1 || xmax<xmin || ymax<ymin)
	return EOF;

  xstep=(xmax-xmin)/width;
  ystep=(ymax-ymin)/height;

  color_type = PNG_COLOR_TYPE_RGB;
  bit_depth = 8;

  /* row_bytes is the width x number of channels x (bit-depth / 8) */
  row_bytes = width * channels;

  if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL)
    return EOF;

  /* read data from PNM file */
  pix_ptr = png_pixels;

  for(row = 0, y = ymax-ystep; row < height; row++, y-=ystep){
	for(col = 0, x = xmin; col < width; col++, x+=xstep){
	  z=func(x,y);
	  color=colorfunction(z);
	  *pix_ptr++ = (color>>16)&0xff;  //R
	  *pix_ptr++ = (color>>8)&0xff;   //G
	  *pix_ptr++ = (color)&0xff;      //B
	}
  }

  /* prepare the standard PNG structures */
  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr)
    return EOF;

  info_ptr = png_create_info_struct (png_ptr);
  if (!info_ptr){
    png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
    return EOF;
  }

  /* setjmp() must be called in every function that calls a PNG-reading libpng function */
  if (setjmp (png_jmpbuf(png_ptr))){
    png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
    return EOF;
  }

  /* initialize the png structure */
  png_init_io (png_ptr, png_file);

  /* we're going to write more or less the same PNG as the input file */
  png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
    PNG_INTERLACE_ADAM7,
    PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  /* write the file header information */
  png_write_info (png_ptr, info_ptr);

  /* if needed we will allocate memory for an new array of row-pointers */
  if (row_pointers == (unsigned char**) NULL)
  {
    if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
    {
      png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
      return EOF;
    }
  }

  /* set the individual row_pointers to point at the correct offsets */
  for (i = 0; i < (height); i++)
    row_pointers[i] = png_pixels + i * row_bytes;

  /* write out the entire image data in one call */
  png_write_image (png_ptr, row_pointers);

  /* write the additional chuncks to the PNG file (not really needed) */
  png_write_end (png_ptr, info_ptr);

  /* clean up after the write, and free any memory allocated */
  png_destroy_write_struct (&png_ptr, (png_infopp) NULL);

  if (row_pointers != (unsigned char**) NULL)
    free (row_pointers);
  if (png_pixels != (unsigned char*) NULL)
    free (png_pixels);

  return 1;
}
Example #4
0
bool SkPngEncoderMgr::setHeader(const SkImageInfo& srcInfo, const SkPngEncoder::Options& options) {
    if (setjmp(png_jmpbuf(fPngPtr))) {
        return false;
    }

    int pngColorType;
    png_color_8 sigBit;
    int bitDepth = 8;
    switch (srcInfo.colorType()) {
        case kRGBA_F16_SkColorType:
        case kRGBA_F32_SkColorType:
            sigBit.red = 16;
            sigBit.green = 16;
            sigBit.blue = 16;
            sigBit.alpha = 16;
            bitDepth = 16;
            pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
            fPngBytesPerPixel = 8;
            break;
        case kGray_8_SkColorType:
            sigBit.gray = 8;
            pngColorType = PNG_COLOR_TYPE_GRAY;
            fPngBytesPerPixel = 1;
            SkASSERT(srcInfo.isOpaque());
            break;
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
            sigBit.red = 8;
            sigBit.green = 8;
            sigBit.blue = 8;
            sigBit.alpha = 8;
            pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
            fPngBytesPerPixel = srcInfo.isOpaque() ? 3 : 4;
            break;
        case kRGB_888x_SkColorType:
            sigBit.red   = 8;
            sigBit.green = 8;
            sigBit.blue  = 8;
            pngColorType = PNG_COLOR_TYPE_RGB;
            fPngBytesPerPixel = 3;
            SkASSERT(srcInfo.isOpaque());
            break;
        case kARGB_4444_SkColorType:
            if (kUnpremul_SkAlphaType == srcInfo.alphaType()) {
                return false;
            }

            sigBit.red = 4;
            sigBit.green = 4;
            sigBit.blue = 4;
            sigBit.alpha = 4;
            pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
            fPngBytesPerPixel = srcInfo.isOpaque() ? 3 : 4;
            break;
        case kRGB_565_SkColorType:
            sigBit.red = 5;
            sigBit.green = 6;
            sigBit.blue = 5;
            pngColorType = PNG_COLOR_TYPE_RGB;
            fPngBytesPerPixel = 3;
            SkASSERT(srcInfo.isOpaque());
            break;
        case kAlpha_8_SkColorType:  // store as gray+alpha, but ignore gray
            sigBit.gray = kGraySigBit_GrayAlphaIsJustAlpha;
            sigBit.alpha = 8;
            pngColorType = PNG_COLOR_TYPE_GRAY_ALPHA;
            fPngBytesPerPixel = 2;
            break;
        case kRGBA_1010102_SkColorType:
            bitDepth     = 16;
            sigBit.red   = 10;
            sigBit.green = 10;
            sigBit.blue  = 10;
            sigBit.alpha = 2;
            pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
            fPngBytesPerPixel = 8;
            break;
        case kRGB_101010x_SkColorType:
            bitDepth     = 16;
            sigBit.red   = 10;
            sigBit.green = 10;
            sigBit.blue  = 10;
            pngColorType = PNG_COLOR_TYPE_RGB;
            fPngBytesPerPixel = 6;
            break;
        default:
            return false;
    }

    png_set_IHDR(fPngPtr, fInfoPtr, srcInfo.width(), srcInfo.height(),
                 bitDepth, pngColorType,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);
    png_set_sBIT(fPngPtr, fInfoPtr, &sigBit);

    int filters = (int)options.fFilterFlags & (int)SkPngEncoder::FilterFlag::kAll;
    SkASSERT(filters == (int)options.fFilterFlags);
    png_set_filter(fPngPtr, PNG_FILTER_TYPE_BASE, filters);

    int zlibLevel = SkTMin(SkTMax(0, options.fZLibLevel), 9);
    SkASSERT(zlibLevel == options.fZLibLevel);
    png_set_compression_level(fPngPtr, zlibLevel);

    // Set comments in tEXt chunk
    const sk_sp<SkDataTable>& comments = options.fComments;
    if (comments != nullptr) {
        std::vector<png_text> png_texts(comments->count());
        std::vector<SkString> clippedKeys;
        for (int i = 0; i < comments->count() / 2; ++i) {
            const char* keyword;
            const char* originalKeyword = comments->atStr(2 * i);
            const char* text = comments->atStr(2 * i + 1);
            if (strlen(originalKeyword) <= PNG_KEYWORD_MAX_LENGTH) {
                keyword = originalKeyword;
            } else {
                SkDEBUGFAILF("PNG tEXt keyword should be no longer than %d.",
                        PNG_KEYWORD_MAX_LENGTH);
                clippedKeys.emplace_back(originalKeyword, PNG_KEYWORD_MAX_LENGTH);
                keyword = clippedKeys.back().c_str();
            }
            // It seems safe to convert png_const_charp to png_charp for key/text,
            // and we don't have to provide text_length and other fields as we're providing
            // 0-terminated c_str with PNG_TEXT_COMPRESSION_NONE (no compression, no itxt).
            png_texts[i].compression = PNG_TEXT_COMPRESSION_NONE;
            png_texts[i].key = (png_charp)keyword;
            png_texts[i].text = (png_charp)text;
        }
        png_set_text(fPngPtr, fInfoPtr, png_texts.data(), png_texts.size());
    }

    return true;
}
/*
 * The function below was taken from http://www.lemoda.net/c/write-png/
 *
 */
int save_png_to_file (_color *bitmap, int screenx, int screeny, const char *path){
    FILE * fp;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t 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 pixel_size = 3;
    int depth = 8;

    fp = fopen (path, "wb");
    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,
            screenx,
            screeny,
            depth,
            PNG_COLOR_TYPE_RGB,
            PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT,
            PNG_FILTER_TYPE_DEFAULT);

    /* Initialize rows of PNG. */

    row_pointers = png_malloc (png_ptr, screeny * sizeof (png_byte *));
    for (y = 0; y < screeny; ++y) {
        png_byte *row = 
            png_malloc (png_ptr, sizeof (uint8_t) * screenx * pixel_size);
        row_pointers[y] = row;
        for (x = 0; x < screenx; ++x) {
            pixel_t pixel;

            pixel.red   = (uint8_t) bitmap[x + y * screenx].r;
            pixel.green = (uint8_t) bitmap[x + y * screenx].g;
            pixel.blue  = (uint8_t) bitmap[x + y * screenx].b;

            *row++ = pixel.red;
            *row++ = pixel.green;
            *row++ = pixel.blue;
        }
    }

    /* Write the image data to "fp". */

    png_init_io (png_ptr, fp);
    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 < screeny; 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:
    fclose (fp);
fopen_failed:
    return status;
}
Example #6
0
/*
 * image is width x height buffer containing int data of size COLOR_CHANNELS
 *
 * image should be in little-endian format, so that low pixel values go into
 * the red channel (instead of alpha channel).
 *
 */
int writePNG(FILE *ofp, void *image, int width, int height, Optinfo optinfo)
{
  int k;
  int ntext = 0;
  png_structp png_ptr;
  png_infop info_ptr;
  png_bytep imptr;
  png_bytep row_pointers[height];
  png_text texts[MAX_TEXT];

  /* set up row pointers for image data */
  imptr = (png_bytep)image;
  for(k=0; k<height; k++){
    row_pointers[k] = imptr +  ((size_t)k * (size_t)width * COLOR_CHANNELS);
  }

  /* 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, NULL, NULL);
  if (png_ptr == NULL){
    fprintf(stderr, "ERROR: can't create PNG write structure");
    exit(1);
  }
  
  /* 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);
    fprintf(stderr, "ERRORL can't create PNG info structure");
    exit(1);
  }
  
  /* 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 writing the file */
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fprintf(stderr, "ERROR: PNG error (via setjmp)");
    exit(1);
  }
  
  /* Set up the output control if you are using standard C streams */
  png_init_io(png_ptr, ofp);
  
  /* 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
   */
  png_set_IHDR(png_ptr, info_ptr, width, height, MY_BIT_DEPTH, 
	       MY_PNG_COLOR_TYPE, PNG_INTERLACE_NONE, 
	       PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  
  /* write text before the image so that the helper program can read it
     without reading the image itself */
  ntext = 0;
  if( optinfo->fitsname && *optinfo->fitsname ){
    if( ntext < MAX_TEXT ){
      texts[ntext].compression = PNG_TEXT_COMPRESSION_NONE;
      texts[ntext].key = "fitsfile";
      texts[ntext].text = optinfo->fitsname;
      ntext++;
    }
  }
  if( optinfo->fitsheader && *optinfo->fitsheader ){
    if( ntext < MAX_TEXT ){
      /* texts[ntext].compression = PNG_TEXT_COMPRESSION_NONE; */
      texts[ntext].compression = PNG_TEXT_COMPRESSION_zTXt;
      texts[ntext].key = "fitsheader";
      texts[ntext].text = optinfo->fitsheader;
      ntext++;
    }
  }
  png_set_text(png_ptr, info_ptr, texts, ntext);

  /* Write the file header information.  REQUIRED */
  png_write_info(png_ptr, info_ptr);
  
  /* Now you can write the image data.  The simplest way to do this
     is in one function call.  If you have the whole image in memory,
     you can just call png_write_image() and libpng will write the
     image.  You will need to pass in an array of pointers to each
     row.  */
  png_write_image(png_ptr, row_pointers);
  
  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);
  
  // clean up 
  png_destroy_write_struct(&png_ptr, &info_ptr);

  return 0;
}
Example #7
0
int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression, struct IMG_PNG_text* text, int num_text){
	png_structp png_ptr;
	png_infop info_ptr;
	SDL_PixelFormat *fmt=NULL;
	SDL_Surface *tempsurf=NULL;
	int ret,funky_format,used_alpha;
	unsigned int i,temp_alpha;
	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 (surf->flags&SDL_SRCCOLORKEY) {
// DJB 
// #ifndef __IPHONE__
#if 0
			palette_alpha=(Uint8 *)malloc((fmt->colorkey+1)*sizeof(Uint8));
			if (!palette_alpha) {
				SDL_SetError("Couldn't create memory for palette transparency");
				goto savedone;
			}
			/* FIXME: memset? */
			for (i=0;i<(fmt->colorkey+1);i++) {
				palette_alpha[i]=255;
			}
			palette_alpha[fmt->colorkey]=0;
			png_set_tRNS(png_ptr,info_ptr,palette_alpha,fmt->colorkey+1,NULL);
#endif
		}
	}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);
		}
	}

	if (num_text) {
		int i;
		png_text* converted_text = (png_text*) malloc(num_text * sizeof(png_text));
		for (i = 0; i < num_text; ++i) {
			converted_text[i].compression = PNG_TEXT_COMPRESSION_NONE;
			converted_text[i].key = text[i].key;
			converted_text[i].text = text[i].value;
		}

		png_set_text(png_ptr, info_ptr, converted_text, num_text);
		free(converted_text);
	}

	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_BYTEORDER == SDL_BIG_ENDIAN
				tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
										0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
#else
				tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
										0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
#endif
			}else{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
				tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
										0xff0000, 0x00ff00, 0x0000ff, 0x00000000);
#else
				tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
										0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
#endif
			}
			if(!tempsurf){
				SDL_SetError("Couldn't allocate temp surface");
				goto savedone;
			}
			if(surf->flags&SDL_SRCALPHA){
// DJB
// #ifndef __IPHONE__
#if 0
				temp_alpha=fmt->alpha;
#endif
				used_alpha=1;
				SDL_SetAlpha(surf,0,255); /* Set for an opaque blit */
			}else{
				used_alpha=0;
			}
			if(SDL_BlitSurface(surf,NULL,tempsurf,NULL)!=0){
				SDL_SetError("Couldn't blit surface to temp surface");
				SDL_FreeSurface(tempsurf);
				goto savedone;
			}
			if (used_alpha) {
				SDL_SetAlpha(surf,SDL_SRCALPHA,(Uint8)temp_alpha); /* Restore alpha settings*/
			}
			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;
}
Example #8
0
static PyObject *Py_write_png(PyObject *self, PyObject *args, PyObject *kwds)
{
    numpy::array_view<unsigned char, 3> buffer;
    PyObject *filein;
    double dpi = 0;
    int compression = 6;
    int filter = -1;
    const char *names[] = { "buffer", "file", "dpi", "compression", "filter", NULL };

    // We don't need strict contiguity, just for each row to be
    // contiguous, and libpng has special handling for getting RGB out
    // of RGBA, ARGB or BGR. But the simplest thing to do is to
    // enforce contiguity using array_view::converter_contiguous.
    if (!PyArg_ParseTupleAndKeywords(args,
                                     kwds,
                                     "O&O|dii:write_png",
                                     (char **)names,
                                     &buffer.converter_contiguous,
                                     &buffer,
                                     &filein,
                                     &dpi,
                                     &compression,
                                     &filter)) {
        return NULL;
    }

    png_uint_32 width = (png_uint_32)buffer.dim(1);
    png_uint_32 height = (png_uint_32)buffer.dim(0);
    int channels = buffer.dim(2);
    std::vector<png_bytep> row_pointers(height);
    for (png_uint_32 row = 0; row < (png_uint_32)height; ++row) {
        row_pointers[row] = (png_bytep)buffer[row].data();
    }

    FILE *fp = NULL;
    mpl_off_t offset = 0;
    bool close_file = false;
    bool close_dup_file = false;
    PyObject *py_file = NULL;

    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    struct png_color_8_struct sig_bit;
    int png_color_type;
    buffer_t buff;
    buff.str = NULL;

    switch (channels) {
    case 1:
	png_color_type = PNG_COLOR_TYPE_GRAY;
	break;
    case 3:
	png_color_type = PNG_COLOR_TYPE_RGB;
	break;
    case 4:
	png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	break;
    default:
        PyErr_SetString(PyExc_ValueError,
			"Buffer must be an NxMxD array with D in 1, 3, 4 "
			"(grayscale, RGB, RGBA)");
        goto exit;
    }

    if (compression < 0 || compression > 9) {
        PyErr_Format(PyExc_ValueError,
                     "compression must be in range 0-9, got %d", compression);
        goto exit;
    }

    if (PyBytes_Check(filein) || PyUnicode_Check(filein)) {
        if ((py_file = mpl_PyFile_OpenFile(filein, (char *)"wb")) == NULL) {
            goto exit;
        }
        close_file = true;
    } else {
        py_file = filein;
    }

    if (filein == Py_None) {
        buff.size = width * height * 4 + 1024;
        buff.str = PyBytes_FromStringAndSize(NULL, buff.size);
        if (buff.str == NULL) {
            goto exit;
        }
        buff.cursor = 0;
    } else if ((fp = mpl_PyFile_Dup(py_file, (char *)"wb", &offset))) {
        close_dup_file = true;
    } else {
        PyErr_Clear();
        PyObject *write_method = PyObject_GetAttrString(py_file, "write");
        if (!(write_method && PyCallable_Check(write_method))) {
            Py_XDECREF(write_method);
            PyErr_SetString(PyExc_TypeError,
                            "Object does not appear to be a 8-bit string path or "
                            "a Python file-like object");
            goto exit;
        }
        Py_XDECREF(write_method);
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL) {
        PyErr_SetString(PyExc_RuntimeError, "Could not create write struct");
        goto exit;
    }

    png_set_compression_level(png_ptr, compression);
    if (filter >= 0) {
        png_set_filter(png_ptr, 0, filter);
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        PyErr_SetString(PyExc_RuntimeError, "Could not create info struct");
        goto exit;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        PyErr_SetString(PyExc_RuntimeError, "libpng signaled error");
        goto exit;
    }

    if (buff.str) {
        png_set_write_fn(png_ptr, (void *)&buff, &write_png_data_buffer, &flush_png_data_buffer);
    } else if (fp) {
        png_init_io(png_ptr, fp);
    } else {
        png_set_write_fn(png_ptr, (void *)py_file, &write_png_data, &flush_png_data);
    }
    png_set_IHDR(png_ptr,
                 info_ptr,
                 width,
                 height,
                 8,
                 png_color_type,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

    // Save the dpi of the image in the file
    if (dpi > 0.0) {
        png_uint_32 dots_per_meter = (png_uint_32)(dpi / (2.54 / 100.0));
        png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER);
    }

    sig_bit.alpha = 0;
    switch (png_color_type) {
    case PNG_COLOR_TYPE_GRAY:
	sig_bit.gray = 8;
	sig_bit.red = 0;
	sig_bit.green = 0;
	sig_bit.blue = 0;
	break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
	sig_bit.alpha = 8;
	// fall through
    case PNG_COLOR_TYPE_RGB:
	sig_bit.gray = 0;
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	break;
    default:
        PyErr_SetString(PyExc_RuntimeError, "internal error, bad png_color_type");
        goto exit;
    }
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    png_write_info(png_ptr, info_ptr);
    png_write_image(png_ptr, &row_pointers[0]);
    png_write_end(png_ptr, info_ptr);

exit:

    if (png_ptr && info_ptr) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    if (close_dup_file) {
        mpl_PyFile_DupClose(py_file, fp, offset);
    }

    if (close_file) {
        mpl_PyFile_CloseFile(py_file);
        Py_DECREF(py_file);
    }

    if (PyErr_Occurred()) {
        Py_XDECREF(buff.str);
        return NULL;
    } else {
        if (buff.str) {
            _PyBytes_Resize(&buff.str, buff.cursor);
            return buff.str;
        }
        Py_RETURN_NONE;
    }
}
Example #9
0
static GstFlowReturn
gst_pngenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstPngEnc *pngenc;
  gint row_index;
  png_byte **row_pointers;
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *encoded_buf = NULL;

  pngenc = GST_PNGENC (gst_pad_get_parent (pad));

  GST_DEBUG_OBJECT (pngenc, "BEGINNING");

  if (G_UNLIKELY (pngenc->width <= 0 || pngenc->height <= 0)) {
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto done;
  }

  if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < pngenc->height * pngenc->stride)) {
    gst_buffer_unref (buf);
    GST_ELEMENT_ERROR (pngenc, STREAM, FORMAT, (NULL),
        ("Provided input buffer is too small, caps problem?"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  /* initialize png struct stuff */
  pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
      (png_voidp) NULL, user_error_fn, user_warning_fn);
  if (pngenc->png_struct_ptr == NULL) {
    gst_buffer_unref (buf);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
        ("Failed to initialize png structure"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
  if (!pngenc->png_info_ptr) {
    gst_buffer_unref (buf);
    png_destroy_write_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
        ("Failed to initialize the png info structure"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  /* non-0 return is from a longjmp inside of libpng */
  if (setjmp (png_jmpbuf (pngenc->png_struct_ptr)) != 0) {
    gst_buffer_unref (buf);
    png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, FAILED, (NULL),
        ("returning from longjmp"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  png_set_filter (pngenc->png_struct_ptr, 0,
      PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
  png_set_compression_level (pngenc->png_struct_ptr, pngenc->compression_level);

  png_set_IHDR (pngenc->png_struct_ptr,
      pngenc->png_info_ptr,
      pngenc->width,
      pngenc->height,
      8,
      pngenc->png_color_type,
      PNG_INTERLACE_NONE,
      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

  png_set_write_fn (pngenc->png_struct_ptr, pngenc,
      (png_rw_ptr) user_write_data, user_flush_data);

  row_pointers = g_new (png_byte *, pngenc->height);

  for (row_index = 0; row_index < pngenc->height; row_index++) {
    row_pointers[row_index] = GST_BUFFER_DATA (buf) +
        (row_index * pngenc->stride);
  }

  /* allocate the output buffer */
  pngenc->buffer_out =
      gst_buffer_new_and_alloc (pngenc->height * pngenc->stride);
  pngenc->written = 0;

  png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
  png_write_image (pngenc->png_struct_ptr, row_pointers);
  png_write_end (pngenc->png_struct_ptr, NULL);

  g_free (row_pointers);

  encoded_buf = gst_buffer_create_sub (pngenc->buffer_out, 0, pngenc->written);

  png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
  png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
  gst_buffer_copy_metadata (encoded_buf, buf, GST_BUFFER_COPY_TIMESTAMPS);
  gst_buffer_unref (buf);
  gst_buffer_set_caps (encoded_buf, GST_PAD_CAPS (pngenc->srcpad));

  if ((ret = gst_pad_push (pngenc->srcpad, encoded_buf)) != GST_FLOW_OK)
    goto done;

  if (pngenc->snapshot) {
    GstEvent *event;

    GST_DEBUG_OBJECT (pngenc, "snapshot mode, sending EOS");
    /* send EOS event, since a frame has been pushed out */
    event = gst_event_new_eos ();

    gst_pad_push_event (pngenc->srcpad, event);
    ret = GST_FLOW_UNEXPECTED;
  }

done:
  GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);

  if (pngenc->buffer_out != NULL) {
    gst_buffer_unref (pngenc->buffer_out);
    pngenc->buffer_out = NULL;
  }

  gst_object_unref (pngenc);
  return ret;
}
Example #10
0
/*---------------------------------------------------------------------------
   Saves a PNG file.

   Image    : Image to save.
   Path     : Path to image file, relative to the current working directory.
   Compress : Specifies the compression level to use for encoding.
  ---------------------------------------------------------------------------*/
void PNG::Save(const Texture &Image, const std::string &Path, CompLevel Compress)
   {
   Destroy();

   //Important - set class to writing mode
   Mode = PNG::ModeWrite;

   vector2u Res = Image.Resolution();
   if (Res.U < 1 || Res.V < 1) {return;}

   #if defined (WINDOWS)
      if (fopen_s(&File, Path.c_str(), "wb") != 0)
         {throw dexception("Failed to open file: %s.", Path.c_str());}
   #else
      File = fopen(Path.c_str(), "wb");
      if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());}
   #endif

   PngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   if (PngPtr == nullptr) {throw dexception("png_create_write_struct( ) failed.");}

   InfoPtr = png_create_info_struct(PngPtr);
   if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");}

   if (setjmp(png_jmpbuf(PngPtr)))
      {throw dexception("setjmp( ) failed.");}

   png_init_io(PngPtr, File);

   png_set_compression_level(PngPtr, (int)Compress);

   int BitDepth, ColourType;
   switch (Image.DataType())
      {
      case Texture::TypeAlpha : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeLum   : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeDepth : BitDepth = 16; ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeRGB   : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_RGB; break;
      case Texture::TypeRGBA  : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_RGB_ALPHA; break;
      default : throw dexception("Unsupported image type."); break;
      }

   png_set_IHDR(PngPtr, InfoPtr, (png_uint_32)Res.U, (png_uint_32)Res.V, BitDepth, ColourType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

   png_set_sRGB(PngPtr, InfoPtr, PNG_sRGB_INTENT_ABSOLUTE);
   png_set_sRGB_gAMA_and_cHRM(PngPtr, InfoPtr, PNG_sRGB_INTENT_ABSOLUTE);

   png_color_16 BackGnd;
   BackGnd.red   = 0;
   BackGnd.green = 0;
   BackGnd.blue  = 0;
   png_set_bKGD(PngPtr, InfoPtr, &BackGnd);

   png_text PngText[2];
   memset(PngText, 0, sizeof(PngText));

   PngText[0].compression = PNG_TEXT_COMPRESSION_NONE;
   PngText[0].key = const_cast<png_charp>("Software");
   PngText[0].text = const_cast<png_charp>(AppName);
   PngText[0].text_length = strlen(PngText[0].text);

   PngText[1].compression = PNG_TEXT_COMPRESSION_NONE;
   PngText[1].key = const_cast<png_charp>("Author");
   PngText[1].text = const_cast<png_charp>(AppAuthor);
   PngText[1].text_length = strlen(PngText[1].text);

   png_set_text(PngPtr, InfoPtr, PngText, 2);

   png_write_info(PngPtr, InfoPtr);

   //Populate row pointer array
   Rows.Create((usize)Res.V);
   for (uiter I = 0; I < (usize)Res.V; I++)
      {
      Rows[I] = Image.Address(0, I);
      }

   //Encode
   png_write_image(PngPtr, Rows.Pointer());
   png_write_end(PngPtr, nullptr);

   //Clean up
   Destroy();
   }
Example #11
0
bool PNG::writeToFile(string const & file_name)
{
	FILE * fp = fopen(file_name.c_str(), "wb");
	if (!fp)
	{
		epng_err("Failed to open file " + file_name);
		return false;
	}

	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		epng_err("Failed to create png struct");
		fclose(fp);
		return false;
	}

	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		epng_err("Failed to create png info struct");
		png_destroy_write_struct(&png_ptr, NULL);
		fclose(fp);
		return false;
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		epng_err("Error initializing libpng io");
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		return false;
	}

	png_init_io(png_ptr, fp);

	// write header
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		epng_err("Error writing image header");
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		return false;
	}
	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);

	png_write_info(png_ptr, info_ptr);

	// write image
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		epng_err("Failed to write image");
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		return false;
	}

	int bpr = png_get_rowbytes(png_ptr, info_ptr);
	png_byte * row = new png_byte[bpr];
	for (int y = 0; y < _height; y++)
	{
		for (int x = 0; x < _width; x++)
		{
			png_byte * pix = &(row[x*4]);
			pix[0] = _pixel(x,y).red;
			pix[1] = _pixel(x,y).green;
			pix[2] = _pixel(x,y).blue;
			pix[3] = _pixel(x,y).alpha;
		}
		png_write_row(png_ptr, row);
	}
	delete [] row;
	png_write_end(png_ptr, NULL);
	png_destroy_write_struct(&png_ptr, &info_ptr);
	fclose(fp);
	return true;
}
Example #12
0
bool  PngEncoder::write(const Mat& img)
{
	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;

	uchar** buffer = NULL;
	if (depth != MCV_8U && depth != MCV_16U)
		return false;

	if (png_ptr){
		info_ptr = png_create_info_struct(png_ptr);

		if (info_ptr){
			if (setjmp(png_jmpbuf(png_ptr)) == 0){
			
					f = fopen(filename_.c_str(), "wb");
					if (f)
						png_init_io(png_ptr, f);
			
				int compression_level = 5; // Invalid value to allow setting 0-9 as valid
				int compression_strategy = Z_RLE; // Default strategy
				bool isBilevel = false;

				if ( f)	{
					if (compression_level >= 0){
						png_set_compression_level(png_ptr, compression_level);
					}
					else{
						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 == MCV_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);

					
					buffer = new uchar*[height];
					
					for (y = 0; y < height; y++)
						buffer[y] = img.data_ + y*img.cols_*img.elemSize();

					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);

	delete[] buffer;
	return result;
return false;
}
Example #13
0
// this code is heavily adapted from the paint license, which is in
// the file paint.license (BSD compatible) included in this
// distribution.  TODO, add license file to MANIFEST.in and CVS
Py::Object 
RendererAgg::write_png(const Py::Tuple& args)
{
  //small memory leak in this function - JDH 2004-06-08
  _VERBOSE("RendererAgg::write_png");
  
  args.verify_length(1);
  
  std::string fileName = Py::String(args[0]);
  const char *file_name = fileName.c_str();
  FILE *fp;
  png_structp png_ptr;
  png_infop info_ptr;
  struct        png_color_8_struct sig_bit;
  png_uint_32 row;
  
  png_bytep row_pointers[height];
  for (row = 0; row < height; ++row) {
    row_pointers[row] = pixBuffer + row * width * 4;
  }
  
  fp = fopen(file_name, "wb");
  if (fp == NULL) 
    throw Py::RuntimeError("could not open file");
  
  
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) {
    fclose(fp);
    throw Py::RuntimeError("could not create write struct");
  }
  
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    fclose(fp);
    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    throw Py::RuntimeError("could not create info struct");
  }
  
  if (setjmp(png_ptr->jmpbuf)) {
    fclose(fp);
    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    throw Py::RuntimeError("error building image");
  }
  
  png_init_io(png_ptr, fp);
  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);
  
  // this a a color image!
  sig_bit.gray = 0;
  sig_bit.red = 8;
  sig_bit.green = 8;
  sig_bit.blue = 8;
  /* if the image has an alpha channel then */
  sig_bit.alpha = 8;
  png_set_sBIT(png_ptr, info_ptr, &sig_bit);
  
  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, row_pointers);
  png_write_end(png_ptr, info_ptr);
  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
  fclose(fp);
  
  return Py::Object();
}
void write_png_file(char* file_name) {
  int j, x, y;
  int color_space = PNG_COLOR_TYPE_RGB_ALPHA;
  volatile unsigned char *ptr = NULL;
  png_structp png_ptr;
  png_infop info_ptr;
//  Buffer *buf;
	FILE *fp = fopen(file_name, "wb");

	if (!result._thumbs[0]->_pixbuf_size) {
    LOG_WARN("PNG compression requires pixbuf data\n");
    return;
  }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr) {
    FATAL("Could not initialize libpng\n");
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    png_destroy_write_struct(&png_ptr, NULL);
    FATAL("Could not initialize libpng\n");
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    if (ptr != NULL)
      free((void *)ptr);
    return;
  }

  png_init_io(png_ptr, fp);

	/* write header */
	if (setjmp(png_jmpbuf(png_ptr)))
				abort_("[write_png_file] Error during writing header");


  // Match output color space with input file
	switch (result._thumbs[0]->channels) {
    case 4:
    case 3:
      LOG_DEBUG("PNG output color space set to RGBA\n");
      color_space = PNG_COLOR_TYPE_RGB_ALPHA;
      break;
    case 2:
    case 1:
      LOG_DEBUG("PNG output color space set to gray alpha\n");
      color_space = PNG_COLOR_TYPE_GRAY_ALPHA;
      break;
  }

  png_set_IHDR(png_ptr, info_ptr, result._thumbs[0]->width, result._thumbs[0]->height, 8, color_space,
               PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

  png_write_info(png_ptr, info_ptr);

	/* write bytes */
	if (setjmp(png_jmpbuf(png_ptr)))
				abort_("[write_png_file] Error during writing bytes");


  ptr = (unsigned char *)malloc(png_get_rowbytes(png_ptr, info_ptr));

  j = 0;

  if (color_space == PNG_COLOR_TYPE_GRAY_ALPHA) {
    for (y = 0; y < result._thumbs[0]->height; y++) {
      for (x = 0; x < result._thumbs[0]->width; x++) {
        ptr[x * 2] = COL_BLUE(result._thumbs[0]->_pixbuf[j]);
        ptr[x * 2 + 1] = COL_ALPHA(result._thumbs[0]->_pixbuf[j]);
        j++;
      }
      png_write_row(png_ptr, (png_bytep) ptr);
    }
  }
  else {                        // RGB  
    for (y = 0; y < result._thumbs[0]->height; y++) {
      for (x = 0; x < result._thumbs[0]->width; x++) {
        ptr[x * 4] = COL_RED(result._thumbs[0]->_pixbuf[j]);
				ptr[x * 4 + 1] = COL_GREEN(result._thumbs[0]->_pixbuf[j]);
        ptr[x * 4 + 2] = COL_BLUE(result._thumbs[0]->_pixbuf[j]);
        ptr[x * 4 + 3] = COL_ALPHA(result._thumbs[0]->_pixbuf[j]);
        j++;
      }
      png_write_row(png_ptr, (png_bytep) ptr);
    }
  }

  free((void *)ptr);

	/* end write */
	if (setjmp(png_jmpbuf(png_ptr)))
				abort_("[write_png_file] Error during end of write");


  png_write_end(png_ptr, info_ptr);

  png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);
}
Example #15
0
void WriteFilePNG(CByteImage img, const char* filename)
{
	img = removeRedundantBands(img);

    CShape sh = img.Shape();
    int width = sh.width, height = sh.height, nBands = sh.nBands;

	// Make sure the image has the smallest number of bands before writing.
	// That is, if it's 4 bands with full alpha, reduce to 3 bands.  
	// If it's 3 bands with constant colors, make it 1-band.

    FILE *stream = fopen(filename, "wb");
    if (stream == 0)
        throw CError("WriteFilePNG: could not open %s", filename);

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
      (png_error_ptr)pngfile_error, (png_error_ptr)NULL);

	if (!png_ptr) {
        fclose(stream);
		throw CError("WriteFilePNG: error creating png structure");
	}

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        fclose(stream);
		throw CError("WriteFilePNG: error creating png structure");
    }

	png_init_io(png_ptr, stream);

	int bits = 8;
	int colortype =
		nBands == 1 ? PNG_COLOR_TYPE_GRAY :
		nBands == 3 ? PNG_COLOR_TYPE_RGB :
	                  PNG_COLOR_TYPE_RGB_ALPHA;
	png_set_IHDR(png_ptr, info_ptr, width, height, 
		bits, colortype,
		PNG_INTERLACE_NONE, 
		PNG_COMPRESSION_TYPE_DEFAULT, 
		PNG_FILTER_TYPE_DEFAULT);

	// write the file header information
	png_write_info(png_ptr, info_ptr);

	// swap the BGR pixels in the DiData structure to RGB
	png_set_bgr(png_ptr);

	//  allocate a vector of row pointers
	std::vector<uchar *> rowPtrs;
	rowPtrs.resize(height);
	for (int y = 0; y<height; y++)
		rowPtrs[y] = &img.Pixel(0, y, 0);

	// write the whole image
	png_write_image(png_ptr, &rowPtrs[0]);

	// write the additional chunks to the PNG file (not really needed)
	png_write_end(png_ptr, info_ptr);

	png_destroy_write_struct(&png_ptr, (png_infopp) NULL);

    fclose (stream);
}
Example #16
0
//---------------------------------------------------------------------------
void __fastcall TDeePNG::SaveToStream(Classes::TStream * Stream)
{
    // SaveToStream method
    // warning: this method would change the pixelformat to pf24bit
    // if the pixelformat is pfDevice, pf15bit, pf16bit, or pfCustom.


    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_bytep row_buffer = NULL;

    try
    {
        // create png_struct
        png_ptr = png_create_write_struct_2
                  (PNG_LIBPNG_VER_STRING,
                   (png_voidp)this, DeePNG_error, DeePNG_warning,
                   (png_voidp)this, DeePNG_malloc, DeePNG_free);


        // create png_info
        info_ptr = png_create_info_struct(png_ptr);

        // set write function
        png_set_write_fn(png_ptr, (png_voidp)Stream,
                         DeePNG_write_data, DeePNG_flush);


        // set IHDR
        if(PixelFormat == pfDevice || PixelFormat == pf15bit ||
                PixelFormat == pf16bit || PixelFormat == pfCustom)
            PixelFormat = pf24bit;

        bool grayscale = IsGrayscaleBitmap(this);
        int colordepth = GetBitmapColorDepth(this);

        int w = Width;
        int h = Height;

        int color_type;
        if(grayscale)
            color_type = PNG_COLOR_TYPE_GRAY;
        else if(colordepth <= 8)
            color_type = PNG_COLOR_TYPE_PALETTE;
        else if(colordepth == 32)
            color_type = PNG_COLOR_TYPE_RGB_ALPHA;
        else
            color_type = PNG_COLOR_TYPE_RGB;

        png_set_IHDR(png_ptr, info_ptr, w, h,
                     colordepth < 8 ? colordepth : 8,
                     color_type, PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_DEFAULT,
                     PNG_FILTER_TYPE_DEFAULT);

        // set oFFs
        if(ofs_set)
            png_set_oFFs(png_ptr, info_ptr, ofs_x, ofs_y, ofs_unit);

        // set palette
        if(color_type == PNG_COLOR_TYPE_PALETTE)
        {
            png_color *palette = (png_colorp)png_malloc(png_ptr, 256 * sizeof(png_color));
            PALETTEENTRY palentry[256];
            int num_palette = GetPaletteEntries(Palette, 0, (1<<colordepth), palentry);
            for(int i = 0; i < num_palette; i++)
            {
                palette[i].red = palentry[i].peRed;
                palette[i].green = palentry[i].peGreen;
                palette[i].blue = palentry[i].peBlue;
            }
            png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
        }

        // write info
        png_write_info(png_ptr, info_ptr);

        // write vpAg private chunk
        if(vpag_set)
        {
            png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};
            unsigned char vpag_chunk_data[9];
#define PNG_write_be32(p, a) (\
			((unsigned char *)(p))[0] = (unsigned char)(((a) >>24) & 0xff), \
			((unsigned char *)(p))[1] = (unsigned char)(((a) >>16) & 0xff), \
			((unsigned char *)(p))[2] = (unsigned char)(((a) >> 8) & 0xff), \
			((unsigned char *)(p))[3] = (unsigned char)(((a)     ) & 0xff)  )
            PNG_write_be32(vpag_chunk_data,     vpag_w);
            PNG_write_be32(vpag_chunk_data + 4, vpag_h);
            vpag_chunk_data[8] = (unsigned char)vpag_unit;
            png_write_chunk(png_ptr, png_vpAg, vpag_chunk_data, 9);
        }

        /*
        		// change RGB order
        		if(color_type = PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        		   png_set_bgr(png_ptr);
        		// ???? why this does not work ?
        */
        // write image
        if(color_type == PNG_COLOR_TYPE_RGB)
        {
            row_buffer = (png_bytep)png_malloc(png_ptr, 3 * w + 6);
            try
            {
                png_bytep row_pointer = row_buffer;

                for(int i = 0; i < h; i++)
                {
                    png_bytep in = (png_bytep)ScanLine[i];
                    png_bytep out = row_buffer;
                    for(int x = 0; x < w; x++)
                    {
                        out[2] = in[0];
                        out[1] = in[1];
                        out[0] = in[2];
                        out += 3;
                        in += 3;
                    }
                    png_write_row(png_ptr, row_pointer);
                }
            }
            catch(...)
            {
                png_free(png_ptr, row_buffer);
                throw;
            }
            png_free(png_ptr, row_buffer);
        }
        else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        {
            row_buffer = (png_bytep)png_malloc(png_ptr, 4 * w + 6);
            try
            {
                png_bytep row_pointer = row_buffer;

                for(int i = 0; i < h; i++)
                {
                    png_bytep in = (png_bytep)ScanLine[i];
                    png_bytep out = row_buffer;
                    for(int x = 0; x < w; x++)
                    {
                        out[2] = in[0];
                        out[1] = in[1];
                        out[0] = in[2];
                        out[3] = in[3];
                        out += 4;
                        in += 4;
                    }
                    png_write_row(png_ptr, row_pointer);
                }
            }
            catch(...)
            {
                png_free(png_ptr, row_buffer);
                throw;
            }
            png_free(png_ptr, row_buffer);
        }
        else
        {
            for(int i = 0; i < h; i++)
            {
                png_bytep row_pointer = (png_bytep)ScanLine[i];
                png_write_row(png_ptr, row_pointer);
            }
        }


        // finish writing
        png_write_end(png_ptr, info_ptr);

    }
    catch(...)
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        throw;
    }

    png_destroy_write_struct(&png_ptr, &info_ptr);
}
Example #17
0
File: qrenc.c Project: yumm007/C
static int writePNG(QRcode *qrcode, const char *outfile)
{
	static FILE *fp; // avoid clobbering by setjmp.
	png_structp png_ptr;
	png_infop info_ptr;
	png_colorp palette;
	png_byte alpha_values[2];
	unsigned char *row, *p, *q;
	int x, y, xx, yy, bit;
	int realwidth;

	realwidth = (qrcode->width + margin * 2) * size;
	row = (unsigned char *)malloc((realwidth + 7) / 8);
	if(row == NULL) {
		fprintf(stderr, "Failed to allocate memory.\n");
		exit(EXIT_FAILURE);
	}

	if(outfile[0] == '-' && outfile[1] == '\0') {
		fp = stdout;
	} else {
		fp = fopen(outfile, "wb");
		if(fp == NULL) {
			fprintf(stderr, "Failed to create file: %s\n", outfile);
			perror(NULL);
			exit(EXIT_FAILURE);
		}
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if(png_ptr == NULL) {
		fprintf(stderr, "Failed to initialize PNG writer.\n");
		exit(EXIT_FAILURE);
	}

	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL) {
		fprintf(stderr, "Failed to initialize PNG write.\n");
		exit(EXIT_FAILURE);
	}

	if(setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fprintf(stderr, "Failed to write PNG image.\n");
		exit(EXIT_FAILURE);
	}

	palette = (png_colorp) malloc(sizeof(png_color) * 2);
	if(palette == NULL) {
		fprintf(stderr, "Failed to allocate memory.\n");
		exit(EXIT_FAILURE);
	}
	palette[0].red   = fg_color[0];
	palette[0].green = fg_color[1];
	palette[0].blue  = fg_color[2];
	palette[1].red   = bg_color[0];
	palette[1].green = bg_color[1];
	palette[1].blue  = bg_color[2];
	alpha_values[0] = fg_color[3];
	alpha_values[1] = bg_color[3];
	png_set_PLTE(png_ptr, info_ptr, palette, 2);
	png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);

	png_init_io(png_ptr, fp);
	png_set_IHDR(png_ptr, info_ptr,
			realwidth, realwidth,
			1,
			PNG_COLOR_TYPE_PALETTE,
			PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_DEFAULT,
			PNG_FILTER_TYPE_DEFAULT);
	png_set_pHYs(png_ptr, info_ptr,
			dpi * INCHES_PER_METER,
			dpi * INCHES_PER_METER,
			PNG_RESOLUTION_METER);
	png_write_info(png_ptr, info_ptr);

	/* top margin */
	memset(row, 0xff, (realwidth + 7) / 8);
	for(y=0; y<margin * size; y++) {
		png_write_row(png_ptr, row);
	}

	/* data */
	p = qrcode->data;
	for(y=0; y<qrcode->width; y++) {
		bit = 7;
		memset(row, 0xff, (realwidth + 7) / 8);
		q = row;
		q += margin * size / 8;
		bit = 7 - (margin * size % 8);
		for(x=0; x<qrcode->width; x++) {
			for(xx=0; xx<size; xx++) {
				*q ^= (*p & 1) << bit;
				bit--;
				if(bit < 0) {
					q++;
					bit = 7;
				}
			}
			p++;
		}
		for(yy=0; yy<size; yy++) {
			png_write_row(png_ptr, row);
		}
	}
	/* bottom margin */
	memset(row, 0xff, (realwidth + 7) / 8);
	for(y=0; y<margin * size; y++) {
		png_write_row(png_ptr, row);
	}

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);
	free(row);
	free(palette);

	return 0;
}
Example #18
0
void GBMapView::savePNG(const char *name)
{
  u8 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);

  u8 *b = writeBuffer;

  int sizeX = w;
  int sizeY = h;

  u8 *pixU8 = (u8 *)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);
}
Example #19
0
static uint8_t png_write( png_structp writePtr, png_image * image, uint32_t flags )
{
	const uint32_t  h = image->height;
	const uint32_t  w = image->width;
	const uint8_t * p = image->data;
	const uint32_t  bitDepth = 8;
	const uint32_t  channels = 4;
	
	png_infop infoPtr = png_create_info_struct( writePtr );
	if (!infoPtr) 
	{
		pngio_error( "Couldn't initialize PNG info struct" );
		png_destroy_write_struct( & writePtr, NULL );
		return 0;
	}
	
	if (setjmp( png_jmpbuf( writePtr ) )) 
	{
		png_destroy_write_struct( & writePtr, & infoPtr );
		pngio_error( "An error occured while writing the PNG file." );
		return 0;
	}

	png_set_filter( writePtr, 0, PNG_FILTER_NONE );
	
	#ifdef PNG_APPLE_MODE_SUPPORTED
	if (png_get_apple_mode())
	{
		png_write_sig( writePtr );
		png_set_sig_bytes( writePtr, 8 );
		png_set_compression_window_bits( writePtr, -15 );
		png_set_write_user_transform_fn( writePtr, png_write_swap_and_premultiply_transform );
		png_set_user_transform_info( writePtr, NULL, bitDepth, channels );
	}
	#endif
	
	png_set_IHDR( writePtr, infoPtr, w, h, bitDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
	png_set_gAMA( writePtr, infoPtr, 0.45455 );
	png_set_cHRM( writePtr, infoPtr, 0.312700, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06 );
	png_set_sRGB( writePtr, infoPtr, 0);
	
	#ifdef PNG_APPLE_MODE_SUPPORTED
	if (png_get_apple_mode())
	{
		png_byte cname[] = { 'C', 'g', 'B', 'I', '\0' };
		png_byte cdata[] = { 0x50, 0x00, 0x20, 0x02 };
		png_write_chunk( writePtr, cname, cdata, 4 );
	}
	#endif

	png_write_info( writePtr, infoPtr );	

	const size_t bytesPerRow = w * 4;
	if (flags & PNG_IMAGE_FLIP_VERTICAL)
	{
		for (size_t i = 0; i < h; i++) 
		{
			png_write_row( writePtr, p + (bytesPerRow * (h - i - 1)) );
		}
	}
	else
	{
		for (size_t i = 0; i < h; i++) 
		{
			png_write_row( writePtr, p + (bytesPerRow * i) );
		}
	}
	
	png_write_end( writePtr, infoPtr );
	png_destroy_write_struct( & writePtr, & infoPtr );
	
	return 1;
}
  //
  // Entry point for conversion
  //
UT_Error IE_ImpGraphic_Win32Native::_convertGraphic(UT_ByteBuf * pBB, std::string& mimetype)
{	
    IPicture* pPicture = NULL;
    IStream* stream;	
    HGLOBAL hG;		
    HBITMAP hBitmap;
    OLE_HANDLE* hB;
    PBITMAPINFO	bi;
    UT_ByteBuf bBufBMP;
    UT_Error err;	

	/* If the system has GDI+, use it*/
	if (isGDIPlusAvailable())
	{
		m_pBB = new UT_ByteBuf();
		return GDIconvertGraphic(pBB, m_pBB, mimetype);		
	}

	// the code below always writes out PNG's for now; we could update it to support
	// native JPEG images as well, or just delete it and always use GDI+.
	mimetype = "image/png";

    // We need to store the incoming bytebuffer in a Windows global heap	
    size_t nBlockLen = pBB->getLength();   	
    hG = GlobalAlloc(GPTR, nBlockLen);
    if (!hG) 
		return UT_IE_NOMEMORY;	
    
    CopyMemory(hG, pBB->getPointer(0), nBlockLen);   	
    
    // Create a stream from heap
    HRESULT hr = CreateStreamOnHGlobal(hG,false,&stream);
    if (!SUCCEEDED(hr) || !stream)
	{
		GlobalFree(hG);
		return UT_IE_NOMEMORY;
	}
    
    hr = OleLoadPicture(stream,0,false,IID_IPicture,(void**)&pPicture);	

    stream->Release();
    GlobalFree(hG);
    
    if (!SUCCEEDED(hr) || !pPicture)
	{
		return UT_IE_UNKNOWNTYPE;
	}

    pPicture->get_Handle((unsigned int*)&hB);
    
    hBitmap = (HBITMAP)CopyImage(hB,IMAGE_BITMAP,0,0,LR_COPYRETURNORG);
    
    HWND hWnd = GetDesktopWindow();
    
    // Create a BMP file from a BITMAP	
    bi = CreateBitmapInfoStruct(hBitmap);						
    CreateBMPFile(hWnd, bBufBMP, bi, hBitmap, GetDC(hWnd));
    LocalFree ((HLOCAL)bi);
    
    InitializePrivateClassData();
    
    /* Read Header Data */
    err = Read_BMP_Header(&bBufBMP);
	
	/* 
	   It's not a bitmap, then we have to rendered it into a device
	   context and get a bitmap from there. Case wmf graphics
	*/
	if (err) 
	{
		if (err!=UT_IE_BOGUSDOCUMENT) 
		{
			pPicture->Release();
			return err;		
		}
		
        long nWidth  = 0;
        long nHeight = 0;
		long nScaleToWidth= 500;
		long nScaleToHeight= 500;		
		RECT rc, rect;				
		BYTE *imagedata;
		HBITMAP hBit;
		HBITMAP hOld;
		BITMAPINFO bmi; 		
		HDC hWndDC = GetDC(hWnd);
		HDC	hMemDC = CreateCompatibleDC(hWndDC);
		HBRUSH hBrush = (HBRUSH)GetCurrentObject(hMemDC, OBJ_BRUSH);
		
		pPicture->get_Width (&nWidth);
		pPicture->get_Height(&nHeight);

		bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 	
		bmi.bmiHeader.biWidth = nScaleToWidth;
		bmi.bmiHeader.biHeight = nScaleToHeight;
		bmi.bmiHeader.biPlanes = 1; 
		bmi.bmiHeader.biBitCount = 24; // as we want true-color
		bmi.bmiHeader.biCompression = BI_RGB; // no compression
		bmi.bmiHeader.biSizeImage = (((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount + 31) & ~31) >> 3) * bmi.bmiHeader.biHeight; 
		bmi.bmiHeader.biXPelsPerMeter = 0;
		bmi.bmiHeader.biYPelsPerMeter = 0; 
		bmi.bmiHeader.biClrImportant = 0;
		bmi.bmiHeader.biClrUsed = 0; // we are not using palette
			
		hBit = CreateDIBSection(hMemDC,&bmi,DIB_RGB_COLORS,(void**)&imagedata,0,0);						
		hOld = (HBITMAP) SelectObject(hMemDC, hBit);			

		
		rect.left = 0;
        rect.top = nScaleToHeight;
        rect.right = nScaleToWidth;
        rect.bottom = 0;

		FillRect(hMemDC, &rect,  hBrush);
		pPicture->Render(hMemDC, 0,0,  nScaleToWidth,	nScaleToHeight, 0,  nHeight, 
						 nWidth, -nHeight, &rc);	
		
		hBit =  (HBITMAP)SelectObject(hMemDC, hOld);
		
		bi =  CreateBitmapInfoStruct(hBit);						
		CreateBMPFile(hWnd, bBufBMP, &bmi, hBit, hMemDC);
		LocalFree ((HLOCAL)bi);

		
		DeleteDC(hMemDC);
		DeleteDC(hWndDC);
	    DeleteObject(hBrush); 
		DeleteObject(hBit);	  
    
		err = Read_BMP_Header(&bBufBMP);
		if (err) 
		{
			pPicture->Release();
			return err;				
		}
		
	}

	pPicture->Release();


    if ((err = Initialize_PNG()))
	{   
		return err;
	}	
    
    /* Read Palette, if no palette set Header accordingly */
    if(m_iBitsPerPlane < 24) 
	{
		if ((err = Convert_BMP_Palette(&bBufBMP))) 
			return err;
	}
    else
	{
		UT_uint16 bitsPerChannel;
		UT_uint16 colorType;

		if (m_iBitsPerPlane == 24) {
			bitsPerChannel = 8;
			colorType = PNG_COLOR_TYPE_RGB;
		} else if (m_iBitsPerPlane == 32) {
			bitsPerChannel = 8;
			colorType = PNG_COLOR_TYPE_RGB_ALPHA;
		} else if (m_iBitsPerPlane == 48) {
			bitsPerChannel = 16;
			colorType = PNG_COLOR_TYPE_RGB;
		} else if (m_iBitsPerPlane == 64) {
			bitsPerChannel = 16;
			colorType = PNG_COLOR_TYPE_RGB_ALPHA;
		} else {		   
			return UT_ERROR;
		}
	
		png_set_IHDR ( m_pPNG,
					   m_pPNGInfo,
					   m_iWidth,
					   m_iHeight,
					   bitsPerChannel,
					   colorType,
					   PNG_INTERLACE_NONE,
					   PNG_COMPRESSION_TYPE_DEFAULT,
					   PNG_FILTER_TYPE_DEFAULT );
	
	}
    if ((err = Convert_BMP(&bBufBMP))) 
	{
		return err;
	}
    
    /* Clean Up Memory Used */
		
    //FREEP(m_pPNGInfo->palette);
    png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
    
    return UT_OK;  	  	
}
Example #21
0
// this code is heavily adapted from the paint license, which is in
// the file paint.license (BSD compatible) included in this
// distribution.  TODO, add license file to MANIFEST.in and CVS
Py::Object _png_module::write_png(const Py::Tuple& args)
{
  args.verify_length(4, 5);

  FILE *fp = NULL;
  bool close_file = false;
  Py::Object buffer_obj = Py::Object(args[0]);
  PyObject* buffer = buffer_obj.ptr();
  if (!PyObject_CheckReadBuffer(buffer)) {
    throw Py::TypeError("First argument must be an rgba buffer.");
  }

  const void* pixBufferPtr = NULL;
  Py_ssize_t pixBufferLength = 0;
  if (PyObject_AsReadBuffer(buffer, &pixBufferPtr, &pixBufferLength)) {
    throw Py::ValueError("Couldn't get data from read buffer.");
  }

  png_byte* pixBuffer = (png_byte*)pixBufferPtr;
  int width = (int)Py::Int(args[1]);
  int height = (int)Py::Int(args[2]);

  if (pixBufferLength < width * height * 4) {
    throw Py::ValueError("Buffer and width, height don't seem to match.");
  }

  Py::Object py_fileobj = Py::Object(args[3]);
  if (py_fileobj.isString()) {
    std::string fileName = Py::String(py_fileobj);
    const char *file_name = fileName.c_str();
    if ((fp = fopen(file_name, "wb")) == NULL)
      throw Py::RuntimeError( Printf("Could not open file %s", file_name).str() );
    close_file = true;
  } else if (PyFile_CheckExact(py_fileobj.ptr())) {
    fp = PyFile_AsFile(py_fileobj.ptr());
  }
  else {
    PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write");
    if (!(write_method && PyCallable_Check(write_method))) {
      Py_XDECREF(write_method);
      throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
    }
    Py_XDECREF(write_method);
  }

  png_bytep *row_pointers = NULL;
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;

  try {
    struct png_color_8_struct sig_bit;
    png_uint_32 row;

    row_pointers = new png_bytep[height];
    for (row = 0; row < (png_uint_32)height; ++row) {
      row_pointers[row] = pixBuffer + row * width * 4;
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL) {
      throw Py::RuntimeError("Could not create write struct");
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
      throw Py::RuntimeError("Could not create info struct");
    }

    if (setjmp(png_ptr->jmpbuf)) {
      throw Py::RuntimeError("Error building image");
    }

    if (fp) {
      png_init_io(png_ptr, fp);
    } else {
      png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(),
		       &write_png_data, &flush_png_data);
    }
    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);

    // Save the dpi of the image in the file
    if (args.size() == 5) {
      double dpi = Py::Float(args[4]);
      size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0));
      png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER);
    }

    // this a a color image!
    sig_bit.gray = 0;
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    /* if the image has an alpha channel then */
    sig_bit.alpha = 8;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    png_write_info(png_ptr, info_ptr);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, info_ptr);
  } catch (...) {
      if (fp && close_file) fclose(fp);
      delete [] row_pointers;
      /* Changed calls to png_destroy_write_struct to follow
         http://www.libpng.org/pub/png/libpng-manual.txt.
         This ensures the info_ptr memory is released.
      */
      if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
      throw;
  }

  png_destroy_write_struct(&png_ptr, &info_ptr);
  delete [] row_pointers;
  if (fp && close_file) fclose(fp);

  return Py::Object();
}
Example #22
0
int GImageWrite_Png(GImage *gi, FILE *fp, int progressive) {
    struct _GImage *base = gi->list_len==0?gi->u.image:gi->u.images[0];
    png_structp png_ptr;
    png_infop info_ptr;
    png_byte **rows;
    int i;
    int bit_depth;
    int color_type;
    int num_palette;
    png_bytep trans_alpha = NULL;
    png_color_16p trans_color = NULL;
    png_colorp palette = NULL;

   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
      (void *)NULL, user_error_fn, user_warning_fn);

   if (!png_ptr) {
return(false);
   }

   info_ptr = png_create_info_struct(png_ptr);
   if (!info_ptr) {
      png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
return(false);
   }

#if (PNG_LIBPNG_VER < 10500)
    if (setjmp(png_ptr->jmpbuf))
#else
   if (setjmp(*png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf))))
#endif
   {
      png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
return(false);
   }

   png_init_io(png_ptr, fp);

   bit_depth = 8;
   num_palette = base->clut==NULL?2:base->clut->clut_len;
   if ( base->image_type==it_index || base->image_type==it_bitmap ) {
       color_type = PNG_COLOR_TYPE_PALETTE;
       if ( num_palette<=2 )
	   bit_depth=1;
       else if ( num_palette<=4 )
	   bit_depth=2;
       else if ( num_palette<=16 )
	   bit_depth=4;
   } else {
       color_type = PNG_COLOR_TYPE_RGB;
       if ( base->image_type == it_rgba )
	   color_type = PNG_COLOR_TYPE_RGB_ALPHA;
   }

   png_set_IHDR(png_ptr, info_ptr, base->width, base->height,
		bit_depth, color_type, progressive,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   if ( base->image_type==it_index || base->image_type==it_bitmap ) {
       palette = (png_color *) galloc(num_palette*sizeof(png_color));
       if ( base->clut==NULL ) {
	    palette[0].red = palette[0].green = palette[0].blue = 0;
	    palette[1].red = palette[1].green = palette[1].blue = 0xff;
       } else {
	   for ( i=0; i<num_palette; ++i ) {
		long col = base->clut->clut[i];
		palette[i].red = COLOR_RED(col);
		palette[i].green = COLOR_GREEN(col);
		palette[i].blue = COLOR_BLUE(col);
	   }
       }
       png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
       if ( num_palette<=16 )
	   png_set_packing(png_ptr);

       if ( base->trans!=-1 ) {
	   trans_alpha = (png_bytep) galloc(1);
	   trans_alpha[0] = base->trans;
       }
   } else {
       if ( base->trans!=-1 ) {
	   trans_color = (png_color_16p) galloc(sizeof(png_color_16));
	   trans_color->red = COLOR_RED(base->trans);
	   trans_color->green = COLOR_GREEN(base->trans);
	   trans_color->blue = COLOR_BLUE(base->trans);
       }
   }
   if ( base->trans!=-1 ) {
       png_set_tRNS(png_ptr, info_ptr, trans_alpha, 1, trans_color);
   }
   png_write_info(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_RGB)
	png_set_filler(png_ptr, '\0', PNG_FILLER_BEFORE);

    rows = (png_byte **) galloc(base->height*sizeof(png_byte *));
    for ( i=0; i<base->height; ++i )
	rows[i] = (png_byte *) (base->data + i*base->bytes_per_line);

    png_write_image(png_ptr,rows);

    png_write_end(png_ptr, info_ptr);

    if ( trans_alpha!=NULL ) gfree(trans_alpha);
    if ( trans_color!=NULL ) gfree(trans_color);
    if ( palette!=NULL ) gfree(palette);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    gfree(rows);
return( 1 );
}
Example #23
0
static int 
writePNG(QRcode *qrcode, 
	const char *outfile,
	int size,
	int margin)
{
	FILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned char *row, *p, *q;
	int x, y, xx, yy, bit;
	int realwidth;
	
	realwidth = (qrcode->width + margin * 2) * size;
	row = (unsigned char *)malloc((realwidth + 7) / 8);

	if(outfile[0] == '-' && outfile[1] == '\0') {
		fp = stdout;
	} else {
		fp = fopen(outfile, "w");
		if(fp == NULL) {
			return -1;
		}
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if(png_ptr == NULL) {
		fclose(fp);
		return -1;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL) {
		fclose(fp);
		return -1;
	}

	if(setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		return -1;
	}

	png_init_io(png_ptr, fp);
	png_set_IHDR(png_ptr, info_ptr,
			realwidth, realwidth,
			1,
			PNG_COLOR_TYPE_GRAY,
			PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_DEFAULT,
			PNG_FILTER_TYPE_DEFAULT);
	png_write_info(png_ptr, info_ptr);

	/* top margin */
	memset(row, 0xff, (realwidth + 7) / 8);
	for(y=0; y<margin * size; y++) {
		png_write_row(png_ptr, row);
	}

	/* data */
	p = qrcode->data;
	for(y=0; y<qrcode->width; y++) {
		bit = 7;
		memset(row, 0xff, (realwidth + 7) / 8);
		q = row;
		q += margin * size / 8;
		bit = 7 - (margin * size % 8);
		for(x=0; x<qrcode->width; x++) {
			for(xx=0; xx<size; xx++) {
				*q ^= (*p & 1) << bit;
				bit--;
				if(bit < 0) {
					q++;
					bit = 7;
				}
			}
			p++;
		}
		for(yy=0; yy<size; yy++) {
			png_write_row(png_ptr, row);
		}
	}
	/* bottom margin */
	memset(row, 0xff, (realwidth + 7) / 8);
	for(y=0; y<margin * size; y++) {
		png_write_row(png_ptr, row);
	}

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);
	free(row);
	return 0;
}
Example #24
0
int WritePNG(char * filename,struct Image * pic)
{

// VARIABLES START ---------------
png_byte color_type;
png_byte bit_depth;

png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers;

int width, height;
// -------------------------------


/* create file */
FILE *fp = fopen(filename, "wb");
if (!fp) { abort_("[write_png_file] File %s could not be opened for writing", filename); return 0; }


/* initialize stuff */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) { abort_("[write_png_file] png_create_write_struct failed"); return 0; }

info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) { abort_("[write_png_file] png_create_info_struct failed"); return 0; }

if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during init_io"); return 0; }

png_init_io(png_ptr, fp);


/* write header */
if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during writing header"); return 0; }

png_set_IHDR(png_ptr, info_ptr, pic->size_x,pic->size_y,8,PNG_COLOR_TYPE_RGB , PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);


/* write bytes */
if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during writing bytes"); return 0; }
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * pic->size_y);
char * raw_pixels=pic->pixels;

unsigned int y;
for (y=0; y<pic->size_y; y++)
 {
   row_pointers[y] = (png_byte*) raw_pixels;
   raw_pixels+=3*pic->size_x;
 }

 png_write_image(png_ptr,row_pointers);


 /* end write */
 if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during end of write"); return 0; }

 png_write_end(png_ptr, NULL);

 /* cleanup heap allocation */
 free(row_pointers);

 fclose(fp);
return 1;
}
bool8 S9xDoScreenshot (int width, int height)
{
	Settings.TakeScreenshot = FALSE;

#ifdef HAVE_LIBPNG
	FILE		*fp;
	png_structp	png_ptr;
	png_infop	info_ptr;
	png_color_8	sig_bit;
	int			imgwidth, imgheight;
	const char	*fname;

	fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);

	fp = fopen(fname, "wb");
	if (!fp)
	{
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	imgwidth  = width;
	imgheight = height;

	if (Settings.StretchScreenshots == 1)
	{
		if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}
	else
	if (Settings.StretchScreenshots == 2)
	{
		if (width  <= SNES_WIDTH)
			imgwidth  = width  << 1;
		if (height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}

	png_init_io(png_ptr, fp);

	png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	sig_bit.red   = 5;
	sig_bit.green = 5;
	sig_bit.blue  = 5;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
	png_set_shift(png_ptr, &sig_bit);

	png_write_info(png_ptr, info_ptr);

	png_set_packing(png_ptr);

	png_byte	*row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
	uint16		*screen = GFX.Screen;

	for (int y = 0; y < height; y++, screen += GFX.RealPPL)
	{
		png_byte	*rowpix = row_pointer;

		for (int x = 0; x < width; x++)
		{
			uint32	r, g, b;

			DECOMPOSE_PIXEL(screen[x], r, g, b);

			*(rowpix++) = r;
			*(rowpix++) = g;
			*(rowpix++) = b;

			if (imgwidth != width)
			{
				*(rowpix++) = r;
				*(rowpix++) = g;
				*(rowpix++) = b;
			}
		}

		png_write_row(png_ptr, row_pointer);
		if (imgheight != height)
			png_write_row(png_ptr, row_pointer);
	}

	delete [] row_pointer;

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);

	fprintf(stderr, "%s saved.\n", fname);

	const char	*base = S9xBasename(fname);
	sprintf(String, "Saved screenshot %s", base);
	S9xMessage(S9X_INFO, 0, String);

	return (TRUE);
#else
	fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n");
	return (FALSE);
#endif
}