Exemplo n.º 1
0
void PNGAPI
png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
{
   png_debug1(1, "in %s storage function\n", "rows");

   if (png_ptr == NULL || info_ptr == NULL)
      return;

   if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
   info_ptr->row_pointers = row_pointers;
   if(row_pointers)
      info_ptr->valid |= PNG_INFO_IDAT;
}
Exemplo n.º 2
0
bool PNGWriter::write_end()
{
  if (setjmp(png_jmpbuf(png_ptr)))
    return false;

  png_write_end(png_ptr, NULL);

  // cleanup heap allocation
  png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

  fclose(fp);
  return true;
}
Exemplo n.º 3
0
void PNGImage::saveImage(const char* outpath) {
  int error_code = 0;
  FILE* file_descriptor = nullptr;
  png_structp png_ptr = nullptr;
  png_infop info_ptr = nullptr;
  png_bytep row = nullptr;

  file_descriptor = fopen(outpath, "wb");
  if (file_descriptor == nullptr) { error_code = 101; goto ERROR_PNG_write; }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  if (png_ptr == nullptr) { error_code = 10; goto ERROR_PNG_write; }
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == nullptr) { error_code = 5; goto ERROR_PNG_write; }

  if (setjmp(png_jmpbuf(png_ptr))) { error_code = 6; goto ERROR_PNG_write; }

  png_init_io(png_ptr, file_descriptor);

  // Write header (8 bit colour depth)
  png_set_IHDR(png_ptr, info_ptr, m_width, m_height,
        8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  // Allocate memory for one row (3 bytes per pixel - RGB)
  row = (png_bytep) malloc(3 * m_width * sizeof(png_byte));

  for (int y = 0; y < m_height; ++y) {
    for (int x = 0; x < m_width; ++x) {
      setRGB(&(row[x * 3]), m_buffer[y * m_width + x]);
    }
    png_write_row(png_ptr, row);
  }

  png_write_end(png_ptr, nullptr);

  ERROR_PNG_write:
    if (error_code != 0) {
      m_error_code = error_code;
      ERR("Error while writing PNG file: %s, code %i", outpath, m_error_code);
    }
    if (file_descriptor != nullptr) fclose(file_descriptor);
    if (info_ptr != nullptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    if (png_ptr != nullptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    if (row != nullptr) free(row);
}
Exemplo n.º 4
0
void PNGAPI
png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
             png_const_charp name, int compression_type,
             png_const_bytep profile, png_uint_32 proflen)
{
    png_charp new_iccp_name;
    png_bytep new_iccp_profile;
    png_size_t length;

    png_debug1(1, "in %s storage function", "iCCP");

    if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
        return;

    length = png_strlen(name)+1;
    new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length);

    if (new_iccp_name == NULL)
    {
        png_warning(png_ptr, "Insufficient memory to process iCCP chunk");
        return;
    }

    png_memcpy(new_iccp_name, name, length);
    new_iccp_profile = (png_bytep)png_malloc_warn(png_ptr, proflen);

    if (new_iccp_profile == NULL)
    {
        png_free (png_ptr, new_iccp_name);
        png_warning(png_ptr,
                    "Insufficient memory to process iCCP profile");
        return;
    }

    png_memcpy(new_iccp_profile, profile, (png_size_t)proflen);

    png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);

    info_ptr->iccp_proflen = proflen;
    info_ptr->iccp_name = new_iccp_name;
    info_ptr->iccp_profile = new_iccp_profile;
    /* Compression is always zero but is here so the API and info structure
     * does not have to change if we introduce multiple compression types
     */
    info_ptr->iccp_compression = (png_byte)compression_type;
    info_ptr->free_me |= PNG_FREE_ICCP;
    info_ptr->valid |= PNG_INFO_iCCP;
}
Exemplo n.º 5
0
static void write_png(const char *filename, bitmap_t bitmap)
{
  int  j;
  FILE *png;
  png_structp png_ptr;
  png_infop info_ptr;

  png = open_binary_write(filename, "write_png");

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) 
  {
    fprintf(stderr, "write_png(): can't create write structure\n");
    exit(1);
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) 
  {
    fprintf(stderr, "write_png(): can't create info structure\n");
    exit (1);
  }

  if (setjmp(png_jmpbuf(png_ptr))) 
  {
    fprintf(stderr, "write_png(): can't create png\n");
    exit (1);
  }

  png_init_io(png_ptr, png);

  png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height,
               8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  /* --- write png */
  png_write_info(png_ptr, info_ptr);
  for ( j = 0; j < bitmap.height; j++ )
    png_write_row(png_ptr, bitmap.data[j]);
  png_write_end(png_ptr, NULL);
  /* --- */

  fclose(png);
  png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

  return;
}
Exemplo n.º 6
0
/* This is an internal routine to free any memory that the info struct is
 * pointing to before re-using it or freeing the struct itself.  Recall
 * that png_free() checks for NULL pointers for us.
 */
void
png_info_destroy(png_structp png_ptr, png_infop info_ptr)
{
   png_debug(1, "in png_info_destroy\n");

   png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
   if (png_ptr->num_chunk_list)
   {
       png_free(png_ptr, png_ptr->chunk_list);
       png_ptr->num_chunk_list=0;
   }
#endif

   png_info_init(info_ptr);
}
Exemplo n.º 7
0
void MapEditor::finalise_lightmap() {
    delete compile_thread;
    compile_thread = 0;

    /* write PNG */
    create_directory("maps", home_workdir);
    std::string filename = home_workdir + dir_separator +
        "maps" + dir_separator + wmap->get_name() + ".lmp";

    FILE *f = fopen(filename.c_str(), "wb");
    if (!f) {
        show_messagebox(Gui::MessageBoxIconError, "Light Map",
            "Saving failed: " + std::string(strerror(errno)));
        return;
    }

    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, f);
    png_set_IHDR(png_ptr, info_ptr, lightmap_w, lightmap_h, 8, PNG_COLOR_TYPE_RGB_ALPHA,
        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_write_info(png_ptr, info_ptr);

    /* delete image after writing each row */
    for (int y = 0; y < lightmap_h; y++) {
        png_write_row(png_ptr, lightmap[y]);
        delete[] lightmap[y];
    }
    delete[] lightmap;

    /* close file */
    png_write_end(png_ptr, 0);
    if (info_ptr) {
        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    }
    if (png_ptr) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }
    fclose(f);

    if (wmap) {
        wmap->create_lightmap();
    }

    pop_window();
}
Exemplo n.º 8
0
/* This is an internal routine to free any memory that the info struct is
 * pointing to before re-using it or freeing the struct itself.  Recall
 * that png_free() checks for NULL pointers for us.
 */
void /* PRIVATE */
png_info_destroy(png_structp png_ptr, png_infop info_ptr)
{
   png_debug(1, "in png_info_destroy\n");

   png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);

#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   if (png_ptr->num_chunk_list)
   {
       png_free(png_ptr, png_ptr->chunk_list);
       png_ptr->chunk_list=NULL;
       png_ptr->num_chunk_list=0;
   }
#endif

   png_info_init_3(&info_ptr, png_sizeof(png_info));
}
Exemplo n.º 9
0
void PNGAPI
png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
             png_const_colorp palette, int num_palette)
{

    png_debug1(1, "in %s storage function", "PLTE");

    if (png_ptr == NULL || info_ptr == NULL)
        return;

    if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
    {
        if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
            png_error(png_ptr, "Invalid palette length");

        else
        {
            png_warning(png_ptr, "Invalid palette length");
            return;
        }
    }

    /* It may not actually be necessary to set png_ptr->palette here;
     * we do it for backward compatibility with the way the png_handle_tRNS
     * function used to do the allocation.
     */
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);

    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
     * of num_palette entries, in case of an invalid PNG file that has
     * too-large sample values.
     */
    png_ptr->palette = (png_colorp)png_calloc(png_ptr,
                       PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));

    png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color));
    info_ptr->palette = png_ptr->palette;
    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;

    info_ptr->free_me |= PNG_FREE_PLTE;

    info_ptr->valid |= PNG_INFO_PLTE;
}
Exemplo n.º 10
0
void PNGAPI
png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_uint_16p hist)
{
   int i;

   png_debug1(1, "in %s storage function", "hIST");

   if (png_ptr == NULL || info_ptr == NULL)
      return;

   if (info_ptr->num_palette == 0 || info_ptr->num_palette
       > PNG_MAX_PALETTE_LENGTH)
   {
      png_warning(png_ptr,
          "Invalid palette size, hIST allocation skipped");

      return;
   }

   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);

   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
    * version 1.2.1
    */
   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));

   if (info_ptr->hist == NULL)
   {
      png_warning(png_ptr, "Insufficient memory for hIST chunk data");

      return;
   }

   info_ptr->free_me |= PNG_FREE_HIST;

   for (i = 0; i < info_ptr->num_palette; i++)
      info_ptr->hist[i] = hist[i];

   info_ptr->valid |= PNG_INFO_hIST;
}
Exemplo n.º 11
0
	static void
pngstdout(XImage *img)
{
	png_structp png_struct_p;
	png_infop png_info_p;
	void (*convert)(unsigned char *, unsigned char *, XImage *);
	unsigned char *drow = NULL, *srow;
	int h;

	png_struct_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
			NULL);
	png_info_p = png_create_info_struct(png_struct_p);

	if(!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p)))
		die("failed to initialize libpng");

	png_init_io(png_struct_p, stdout);
	png_set_IHDR(png_struct_p, png_info_p, img->width, img->height, 8,
			PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	png_write_info(png_struct_p, png_info_p);

	srow = (unsigned char *)img->data;
	drow = calloc(1, img->width * 4); /* output RGBA */
	if(!drow)
		die("Can't calloc");

	if(img->byte_order == LSBFirst)
		convert = convertrow_lsb;
	else
		convert = convertrow_msb;

	for(h = 0; h < img->height; h++) {
		convert(drow, srow, img);
		srow += img->bytes_per_line;
		png_write_row(png_struct_p, drow);
	}
	png_write_end(png_struct_p, NULL);
	free(drow);
	png_free_data(png_struct_p, png_info_p, PNG_FREE_ALL, -1);
	png_destroy_write_struct(&png_struct_p, NULL);
}
Exemplo n.º 12
0
void PNGAPI
png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
   png_bytep trans, int num_trans, png_color_16p trans_values)
{
   png_debug1(1, "in %s storage function\n", "tRNS");
   if (png_ptr == NULL || info_ptr == NULL)
      return;

   if (trans != NULL)
   {
       /*
        * It may not actually be necessary to set png_ptr->trans here;
        * we do it for backward compatibility with the way the png_handle_tRNS
        * function used to do the allocation.
        */
#ifdef PNG_FREE_ME_SUPPORTED
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
#endif
       /* Changed from num_trans to 256 in version 1.2.1 */
       png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr,
           (png_uint_32)256);
       png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans);
#ifdef PNG_FREE_ME_SUPPORTED
       info_ptr->free_me |= PNG_FREE_TRNS;
#else
       png_ptr->flags |= PNG_FLAG_FREE_TRNS;
#endif
   }

   if (trans_values != NULL)
   {
      png_memcpy(&(info_ptr->trans_values), trans_values,
         sizeof(png_color_16));
      if (num_trans == 0)
        num_trans = 1;
   }
   info_ptr->num_trans = (png_uint_16)num_trans;
   info_ptr->valid |= PNG_INFO_tRNS;
}
Exemplo n.º 13
0
void PNGAPI
png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
{
   int i;

   png_debug1(1, "in %s storage function\n", "hIST");
   if (png_ptr == NULL || info_ptr == NULL)
      return;
   if (info_ptr->num_palette == 0)
   {
       png_warning(png_ptr,
          "Palette size 0, hIST allocation skipped.");
       return;
   }

#ifdef PNG_FREE_ME_SUPPORTED
   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
#endif
   /* Changed from info->num_palette to 256 in version 1.2.1 */
   png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr,
      (png_uint_32)(256 * sizeof (png_uint_16)));
   if (png_ptr->hist == NULL)
     {
       png_warning(png_ptr, "Insufficient memory for hIST chunk data.");
       return;
     }

   for (i = 0; i < info_ptr->num_palette; i++)
       png_ptr->hist[i] = hist[i];
   info_ptr->hist = png_ptr->hist;
   info_ptr->valid |= PNG_INFO_hIST;

#ifdef PNG_FREE_ME_SUPPORTED
   info_ptr->free_me |= PNG_FREE_HIST;
#else
   png_ptr->flags |= PNG_FLAG_FREE_HIST;
#endif
}
Exemplo n.º 14
0
void
get_text(struct PNGImage *png)
{
	png_text *text;
	int i, numtxts, numremoved;

	png_get_text(png->png, png->info, &text, &numtxts);
	for (i = 0; i < numtxts; i++) {
		if (strcmp(text[i].key, "h") == 0 && !*text[i].text) {
			png->horizontal = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "x") == 0) {
			png->trim = strtoul(text[i].text, NULL, 0);
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "t") == 0) {
			png->mapfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
			png->mapout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "p") == 0) {
			png->palfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) {
			png->palout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		}
	}

	/* TODO: Remove this and simply change the warning function not to warn instead. */
	for (i = 0, numremoved = 0; i < numtxts; i++) {
		if (text[i].key == NULL) {
			numremoved++;
		}
		text[i].key = text[i + numremoved].key;
		text[i].text = text[i + numremoved].text;
		text[i].compression = text[i + numremoved].compression;
	}
	png_set_text(png->png, png->info, text, numtxts - numremoved);
}
Exemplo n.º 15
0
void
input_png_file(struct Options opts, struct PNGImage *img)
{
	FILE *f;
	int i, y, num_trans;
	bool has_palette = false;
	png_byte *trans_alpha;
	png_color_16 *trans_values;
	bool *full_alpha;
	png_color *palette;

	f = fopen(opts.infile, "rb");
	if (!f) {
		err(1, "Opening input png file '%s' failed", opts.infile);
	}

	img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!img->png) {
		errx(1, "Creating png structure failed");
	}

	img->info = png_create_info_struct(img->png);
	if (!img->info) {
		errx(1, "Creating png info structure failed");
	}

	/* Better error handling here? */
	if (setjmp(png_jmpbuf(img->png))) {
		exit(1);
	}

	png_init_io(img->png, f);

	png_read_info(img->png, img->info);

	img->width  = png_get_image_width(img->png, img->info);
	img->height = png_get_image_height(img->png, img->info);
	img->depth  = png_get_bit_depth(img->png, img->info);
	img->type   = png_get_color_type(img->png, img->info);

	if (img->type & PNG_COLOR_MASK_ALPHA) {
		png_set_strip_alpha(img->png);
	}

	if (img->depth != depth) {
		if (opts.verbose) {
			warnx("Image bit depth is not %i (is %i).", depth,
			    img->depth);
		}
	}

	if (img->type == PNG_COLOR_TYPE_GRAY) {
		if (img->depth < 8) {
			png_set_expand_gray_1_2_4_to_8(img->png);
		}
		png_set_gray_to_rgb(img->png);
	} else {
		if (img->depth < 8) {
			png_set_expand_gray_1_2_4_to_8(img->png);
		}
		has_palette = png_get_PLTE(img->png, img->info, &palette,
		    &colors);
	}

	if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans,
	    &trans_values)) {
		if (img->type == PNG_COLOR_TYPE_PALETTE) {
			full_alpha = malloc(sizeof(bool) * num_trans);

			for (i = 0; i < num_trans; i++) {
				if (trans_alpha[i] > 0) {
					full_alpha[i] = false;
				} else {
					full_alpha[i] = true;
				}
			}

			for (i = 0; i < num_trans; i++) {
				if (full_alpha[i]) {
					palette[i].red   = 0xFF;
					palette[i].green = 0x00;
					palette[i].blue  = 0xFF;
					/*
					 * Set to the lightest color in the
					 * palette.
					 */
				}
			}

			free(full_alpha);
		} else {
			/* Set to the lightest color in the image. */
		}

		png_free_data(img->png, img->info, PNG_FREE_TRNS, -1);
	}

	if (has_palette) {
		/* Make sure palette only has the amount of colors you want. */
	} else {
		/*
		 * Eventually when this copies colors from the image itself,
		 * make sure order is lightest to darkest.
		 */
		palette = malloc(sizeof(png_color) * colors);

		if (strcmp(opts.infile, "rgb.png") == 0) {
			palette[0].red   = 0xFF;
			palette[0].green = 0xEF;
			palette[0].blue  = 0xFF;

			palette[1].red   = 0xF7;
			palette[1].green = 0xF7;
			palette[1].blue  = 0x8C;

			palette[2].red   = 0x94;
			palette[2].green = 0x94;
			palette[2].blue  = 0xC6;

			palette[3].red   = 0x39;
			palette[3].green = 0x39;
			palette[3].blue  = 0x84;
		} else {
			palette[0].red   = 0xFF;
			palette[0].green = 0xFF;
			palette[0].blue  = 0xFF;

			palette[1].red   = 0xA9;
			palette[1].green = 0xA9;
			palette[1].blue  = 0xA9;

			palette[2].red   = 0x55;
			palette[2].green = 0x55;
			palette[2].blue  = 0x55;

			palette[3].red   = 0x00;
			palette[3].green = 0x00;
			palette[3].blue  = 0x00;
		}
	}

	/*
	 * Also unfortunately, this sets it at 8 bit, and I can't find any
	 * option to reduce to 2 or 1 bit.
	 */
#if PNG_LIBPNG_VER < 10402
	png_set_dither(img->png, palette, colors, colors, NULL, 1);
#else
	png_set_quantize(img->png, palette, colors, colors, NULL, 1);
#endif

	if (!has_palette) {
		png_set_PLTE(img->png, img->info, palette, colors);
		free(palette);
	}

	/*
	 * If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP,
	 * etc.) offer to remove?
	 */

	png_read_update_info(img->png, img->info);

	img->data = malloc(sizeof(png_byte *) * img->height);
	for (y = 0; y < img->height; y++) {
		img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
	}

	png_read_image(img->png, img->data);
	png_read_end(img->png, img->info);

	fclose(f);
}
Exemplo n.º 16
0
void PNGAPI
png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
   int num)
{
   png_debug(1, "in png_free_data\n");
   if (png_ptr == NULL || info_ptr == NULL)
      return;

#if defined(PNG_TEXT_SUPPORTED)
/* free text item num or (if num == -1) all text items */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
#else
if (mask & PNG_FREE_TEXT)
#endif
{
   if (num != -1)
   {
     if (info_ptr->text && info_ptr->text[num].key)
     {
         png_free(png_ptr, info_ptr->text[num].key);
         info_ptr->text[num].key = NULL;
     }
   }
   else
   {
       int i;
       for (i = 0; i < info_ptr->num_text; i++)
           png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
       png_free(png_ptr, info_ptr->text);
       info_ptr->text = NULL;
       info_ptr->num_text=0;
   }
}
#endif

#if defined(PNG_tRNS_SUPPORTED)
/* free any tRNS entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
#else
if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS))
#endif
{
    png_free(png_ptr, info_ptr->trans);
    info_ptr->valid &= ~PNG_INFO_tRNS;
#ifndef PNG_FREE_ME_SUPPORTED
    png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
#endif
    info_ptr->trans = NULL;
}
#endif

#if defined(PNG_sCAL_SUPPORTED)
/* free any sCAL entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
#else
if (mask & PNG_FREE_SCAL)
#endif
{
#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
    png_free(png_ptr, info_ptr->scal_s_width);
    png_free(png_ptr, info_ptr->scal_s_height);
    info_ptr->scal_s_width = NULL;
    info_ptr->scal_s_height = NULL;
#endif
    info_ptr->valid &= ~PNG_INFO_sCAL;
}
#endif

#if defined(PNG_pCAL_SUPPORTED)
/* free any pCAL entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
#else
if (mask & PNG_FREE_PCAL)
#endif
{
    png_free(png_ptr, info_ptr->pcal_purpose);
    png_free(png_ptr, info_ptr->pcal_units);
    info_ptr->pcal_purpose = NULL;
    info_ptr->pcal_units = NULL;
    if (info_ptr->pcal_params != NULL)
    {
        int i;
        for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
        {
          png_free(png_ptr, info_ptr->pcal_params[i]);
          info_ptr->pcal_params[i]=NULL;
        }
        png_free(png_ptr, info_ptr->pcal_params);
        info_ptr->pcal_params = NULL;
    }
    info_ptr->valid &= ~PNG_INFO_pCAL;
}
#endif

#if defined(PNG_iCCP_SUPPORTED)
/* free any iCCP entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
#else
if (mask & PNG_FREE_ICCP)
#endif
{
    png_free(png_ptr, info_ptr->iccp_name);
    png_free(png_ptr, info_ptr->iccp_profile);
    info_ptr->iccp_name = NULL;
    info_ptr->iccp_profile = NULL;
    info_ptr->valid &= ~PNG_INFO_iCCP;
}
#endif

#if defined(PNG_sPLT_SUPPORTED)
/* free a given sPLT entry, or (if num == -1) all sPLT entries */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
#else
if (mask & PNG_FREE_SPLT)
#endif
{
   if (num != -1)
   {
      if(info_ptr->splt_palettes)
      {
          png_free(png_ptr, info_ptr->splt_palettes[num].name);
          png_free(png_ptr, info_ptr->splt_palettes[num].entries);
          info_ptr->splt_palettes[num].name = NULL;
          info_ptr->splt_palettes[num].entries = NULL;
      }
   }
   else
   {
       if(info_ptr->splt_palettes_num)
       {
         int i;
         for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
            png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);

         png_free(png_ptr, info_ptr->splt_palettes);
         info_ptr->splt_palettes = NULL;
         info_ptr->splt_palettes_num = 0;
       }
       info_ptr->valid &= ~PNG_INFO_sPLT;
   }
}
#endif

#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
#else
if (mask & PNG_FREE_UNKN)
#endif
{
   if (num != -1)
   {
       if(info_ptr->unknown_chunks)
       {
          png_free(png_ptr, info_ptr->unknown_chunks[num].data);
          info_ptr->unknown_chunks[num].data = NULL;
       }
   }
   else
   {
       int i;

       if(info_ptr->unknown_chunks_num)
       {
         for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++)
            png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);

         png_free(png_ptr, info_ptr->unknown_chunks);
         info_ptr->unknown_chunks = NULL;
         info_ptr->unknown_chunks_num = 0;
       }
   }
}
#endif

#if defined(PNG_hIST_SUPPORTED)
/* free any hIST entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_HIST)  & info_ptr->free_me)
#else
if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST))
#endif
{
    png_free(png_ptr, info_ptr->hist);
    info_ptr->hist = NULL;
    info_ptr->valid &= ~PNG_INFO_hIST;
#ifndef PNG_FREE_ME_SUPPORTED
    png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
#endif
}
#endif

/* free any PLTE entry that was internally allocated */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
#else
if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE))
#endif
{
    png_zfree(png_ptr, info_ptr->palette);
    info_ptr->palette = NULL;
    info_ptr->valid &= ~PNG_INFO_PLTE;
#ifndef PNG_FREE_ME_SUPPORTED
    png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
#endif
    info_ptr->num_palette = 0;
}

#if defined(PNG_INFO_IMAGE_SUPPORTED)
/* free any image bits attached to the info structure */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
#else
if (mask & PNG_FREE_ROWS)
#endif
{
    if(info_ptr->row_pointers)
    {
       int row;
       for (row = 0; row < (int)info_ptr->height; row++)
       {
          png_free(png_ptr, info_ptr->row_pointers[row]);
          info_ptr->row_pointers[row]=NULL;
       }
       png_free(png_ptr, info_ptr->row_pointers);
       info_ptr->row_pointers=NULL;
    }
    info_ptr->valid &= ~PNG_INFO_IDAT;
}
#endif

#ifdef PNG_FREE_ME_SUPPORTED
   if(num == -1)
     info_ptr->free_me &= ~mask;
   else
     info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
#endif
}
Exemplo n.º 17
0
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first)
{
    PANGOLIN_UNUSED(image);
    PANGOLIN_UNUSED(filename);
    PANGOLIN_UNUSED(top_line_first);

    // Check image has supported bit depth
    for(unsigned int i=1; i < fmt.channels; ++i) {
        if( fmt.channel_bits[i] != fmt.channel_bits[0] ) {
            throw std::runtime_error("PNG Saving only supported for images where each channel has the same bit depth.");
        }
    }

#ifdef HAVE_PNG
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;

    // Open file for writing (binary mode)
    fp = fopen(filename.c_str(), "wb");
    if (fp == NULL) {
        throw std::runtime_error( "PNG Error: Could not open file '" + filename + "' for writing" );
    }

    // Initialize write structure
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL) {
        fclose(fp);
        throw std::runtime_error( "PNG Error: Could not allocate write struct." );
    }

    // Initialize info structure
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        fclose(fp);
        throw std::runtime_error( "PNG Error: Could not allocate info struct." );
    }

    // Setup Exception handling
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        fclose(fp);
        throw std::runtime_error( "PNG Error: Error during png creation." );
    }

    png_init_io(png_ptr, fp);

    const int bit_depth = fmt.channel_bits[0];

    int colour_type;
    switch (fmt.channels) {
    case 1: colour_type = PNG_COLOR_TYPE_GRAY; break;
    case 2: colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
    case 3: colour_type = PNG_COLOR_TYPE_RGB; break;
    case 4: colour_type = PNG_COLOR_TYPE_RGBA; break;
    default:
        throw std::runtime_error( "PNG Error: unexpected image channel number");
    }

    // Write header
    png_set_IHDR(
        png_ptr, info_ptr, (png_uint_32)image.w, (png_uint_32)image.h, bit_depth, colour_type,
        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
    );

    // Setup rows to write:
    std::vector<png_bytep> rows(image.h);
    if(top_line_first) {
        for (unsigned int y = 0; y< image.h; y++) {
            rows[y] = image.ptr + y*image.pitch;
        }
    }else{
        for (unsigned int y = 0; y< image.h; y++) {
            rows[y] = image.ptr + (image.h-1-y)*image.pitch;
        }
    }
    png_set_rows(png_ptr,info_ptr, &rows[0]);

    // Write image data: switch to little-endian byte order, to match host.
    png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, 0);

    // Free resources
    fclose(fp);
    png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

#else
    throw std::runtime_error("PNG Support not enabled. Please rebuild Pangolin.");
#endif
}
Exemplo n.º 18
0
int
export_png_rgb_16(image *i, output *output)
{
	const char *fn;
	int shouldclose;
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 n, x, y, pi;
	pixelref src;
	colour rgb;
	png_bytep pp;
	uint16_t *bp;
	FILE *fp;
	pixel_converter_fn converter;
	
	converter = convert_pixels(i->format, PF_RGB, 16);
	if(!converter)
	{
		fprintf(stderr, "cannot locate a suitable format converter for RGB-16\n");
		return -1;
	}
	fn = output_filename(output, i, &shouldclose);
	fp = fopen(fn, "wb");
	if(!fp)
	{
		return -1;
	}
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if(!png_ptr)
	{
		return -1;
	}
	info_ptr = png_create_info_struct(png_ptr);
	if(!info_ptr)
	{
		return -1;
	}
	png_init_io(png_ptr, fp);
	png_set_IHDR(png_ptr, info_ptr, i->width, i->height, 16, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	png_write_info(png_ptr, info_ptr);
	
	pp = (png_bytep) malloc(i->width * 3 * sizeof(uint16_t));
	bp = (uint16_t *) pp;
	src.pixel[0] = i->pixels[0];
	src.pixel[1] = i->pixels[1];
	src.pixel[2] = i->pixels[2];
	for(y = 0, pi = 0; y < i->height; y++)
	{
		for(n = 0, x = 0; x < i->width; x++, pi++)
		{
			converter(src, &rgb);
			src.pixel[0]++;
			src.pixel[1]++;
			src.pixel[2]++;
			bp[n] = htons(rgb.p.rgb.r);
			n++;
			bp[n] = htons(rgb.p.rgb.g);
			n++;
			bp[n] = htons(rgb.p.rgb.b);
			n++;
		}
		png_write_row(png_ptr, pp);
	}
	png_write_end(png_ptr, NULL);
	free(pp);
	fclose(fp);
	png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	png_destroy_write_struct(&png_ptr, NULL);
	return 0;
}
Exemplo n.º 19
0
/*
 * Reduce the image type to a lower bit depth and color type,
 * by removing redundant bits.
 * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha.
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 * All reductions are performed in a single step.
 */
png_uint_32 /* PRIVATE */
opng_reduce_bits(png_structp png_ptr, png_infop info_ptr,
   png_uint_32 reductions)
{
   png_bytepp row_ptr;
   png_bytep src_ptr, dest_ptr;
   png_uint_32 height, width, i, j;
   unsigned int src_bit_depth, dest_bit_depth;
   unsigned int src_byte_depth, dest_byte_depth;
   unsigned int src_color_type, dest_color_type;
   unsigned int src_channels, dest_channels;
   unsigned int src_sample_size, dest_sample_size;
   unsigned int dest_pixel_depth;
   unsigned int src_offset_alpha;
   unsigned int tran_tbl[8];
   unsigned int k;

   opng_debug(1, "in opng_reduce_bits");

   /* See which reductions may be performed. */
   reductions = opng_analyze_bits(png_ptr, info_ptr, reductions);
   /* Strip the filler even if it is not an alpha channel. */
   if (png_ptr->transformations & PNG_FILLER)
      reductions |= OPNG_REDUCE_STRIP_ALPHA;
   if (reductions == OPNG_REDUCE_NONE)
      return OPNG_REDUCE_NONE;  /* nothing can be reduced */

   /* Compute the new image parameters bit_depth, color_type, etc. */
   src_bit_depth = info_ptr->bit_depth;
   OPNG_ASSERT(src_bit_depth >= 8);
   if (reductions & OPNG_REDUCE_16_TO_8)
   {
      OPNG_ASSERT(src_bit_depth == 16);
      dest_bit_depth = 8;
   }
   else
      dest_bit_depth = src_bit_depth;

   src_byte_depth = src_bit_depth / 8;
   dest_byte_depth = dest_bit_depth / 8;

   src_color_type = dest_color_type = info_ptr->color_type;
   if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR);
      dest_color_type &= ~PNG_COLOR_MASK_COLOR;
   }
   if (reductions & OPNG_REDUCE_STRIP_ALPHA)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA);
      dest_color_type &= ~PNG_COLOR_MASK_ALPHA;
   }

   src_channels  = (png_ptr->usr_channels > 0) ?
      png_ptr->usr_channels : info_ptr->channels;
   dest_channels =
      ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) +
      ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0);

   src_sample_size  = src_channels * src_byte_depth;
   dest_sample_size = dest_channels * dest_byte_depth;
   dest_pixel_depth = dest_channels * dest_bit_depth;

   if (!(png_ptr->transformations & PNG_FILLER) ||
       (png_ptr->flags & PNG_FLAG_FILLER_AFTER))
      src_offset_alpha = (src_channels - 1) * src_byte_depth;
   else
      src_offset_alpha = 0;

   /* Pre-compute the intra-sample translation table. */
   for (k = 0; k < 4 * dest_byte_depth; ++k)
      tran_tbl[k] = k * src_bit_depth / dest_bit_depth;
   /* If rgb -> gray and the alpha channel remains in the right,
      shift the alpha component two positions to the left. */
   if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) &&
       (dest_color_type & PNG_COLOR_MASK_ALPHA) &&
       (src_offset_alpha != 0))
   {
      tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth];
      if (dest_byte_depth == 2)
         tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1];
   }
   /* If alpha is in the left, and it is being stripped,
      shift the components that come after it. */
   if ((src_channels == 2 || src_channels == 4) /* alpha or filler */ &&
       !(dest_color_type & PNG_COLOR_MASK_ALPHA) &&
       (src_offset_alpha == 0))
   {
      for (k = 0; k < dest_sample_size; )
      {
         if (dest_byte_depth == 1)
         {
            tran_tbl[k] = tran_tbl[k + 1];
            ++k;
         }
         else
         {
            tran_tbl[k] = tran_tbl[k + 2];
            tran_tbl[k + 1] = tran_tbl[k + 3];
            k += 2;
         }
      }
   }

   /* Translate the samples to the new image type. */
   OPNG_ASSERT(src_sample_size > dest_sample_size);
   row_ptr = info_ptr->row_pointers;
   height  = info_ptr->height;
   width   = info_ptr->width;
   for (i = 0; i < height; ++i, ++row_ptr)
   {
      src_ptr = dest_ptr = *row_ptr;
      for (j = 0; j < width; ++j)
      {
         for (k = 0; k < dest_sample_size; ++k)
            dest_ptr[k] = src_ptr[tran_tbl[k]];
         src_ptr += src_sample_size;
         dest_ptr += dest_sample_size;
      }
   }

#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
   /* Update the ancillary chunk info. */
   if (info_ptr->valid & PNG_INFO_bKGD)
   {
      png_color_16p background = &info_ptr->background;
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         background->red   &= 255;
         background->green &= 255;
         background->blue  &= 255;
         background->gray  &= 255;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
         background->gray = background->red;
   }
#endif
#if defined(PNG_sBIT_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sBIT)
   {
      png_color_8p sig_bits = &info_ptr->sig_bit;
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (sig_bits->red > 8)
            png_ptr->sig_bit.red   = sig_bits->red   = 8;
         if (sig_bits->green > 8)
            png_ptr->sig_bit.green = sig_bits->green = 8;
         if (sig_bits->blue > 8)
            png_ptr->sig_bit.blue  = sig_bits->blue  = 8;
         if (sig_bits->gray > 8)
            png_ptr->sig_bit.gray  = sig_bits->gray  = 8;
         if (sig_bits->alpha > 8)
            png_ptr->sig_bit.alpha = sig_bits->alpha = 8;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         png_byte max_sig_bit = sig_bits->red;
         if (max_sig_bit < sig_bits->green)
            max_sig_bit = sig_bits->green;
         if (max_sig_bit < sig_bits->blue)
            max_sig_bit = sig_bits->blue;
         png_ptr->sig_bit.gray = sig_bits->gray = max_sig_bit;
      }
   }
#endif
   if (info_ptr->valid & PNG_INFO_tRNS)
   {
      png_color_16p trans_color = &info_ptr->trans_color;
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (trans_color->red   % 257 == 0 &&
             trans_color->green % 257 == 0 &&
             trans_color->blue  % 257 == 0 &&
             trans_color->gray  % 257 == 0)
         {
            trans_color->red   &= 255;
            trans_color->green &= 255;
            trans_color->blue  &= 255;
            trans_color->gray  &= 255;
         }
         else
         {
            /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            info_ptr->valid &= ~PNG_INFO_tRNS;
         }
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         if (trans_color->red == trans_color->green ||
             trans_color->red == trans_color->blue)
            trans_color->gray = trans_color->red;
         else
         {
            /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            info_ptr->valid &= ~PNG_INFO_tRNS;
         }
      }
   }

   /* Update the image info. */
   png_ptr->rowbytes    = info_ptr->rowbytes    = 0;
   png_ptr->bit_depth   = info_ptr->bit_depth   = (png_byte)dest_bit_depth;
   png_ptr->color_type  = info_ptr->color_type  = (png_byte)dest_color_type;
   png_ptr->channels    = info_ptr->channels    = (png_byte)dest_channels;
   png_ptr->pixel_depth = info_ptr->pixel_depth = (png_byte)dest_pixel_depth;
   if (reductions & OPNG_REDUCE_STRIP_ALPHA)
   {
      png_ptr->transformations &= ~PNG_FILLER;
      if (png_ptr->usr_channels > 0)
         --png_ptr->usr_channels;
   }

   return reductions;
}
Exemplo n.º 20
0
/*
 * Reduce the palette (only the fast method is implemented).
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 */
png_uint_32 /* PRIVATE */
opng_reduce_palette(png_structp png_ptr, png_infop info_ptr,
   png_uint_32 reductions)
{
   png_uint_32 result;
   png_colorp palette;
   png_bytep trans_alpha;
   png_bytepp rows;
   png_uint_32 width, height, i, j;
   png_byte is_used[256];
   int num_palette, num_trans, last_color_index, last_trans_index, is_gray, k;
   png_color_16 gray_trans;
   png_byte crt_trans_value, last_trans_value;

   opng_debug(1, "in opng_reduce_palette");

   height      = info_ptr->height;
   width       = info_ptr->width;
   palette     = info_ptr->palette;
   num_palette = info_ptr->num_palette;
   rows        = info_ptr->row_pointers;
   if (info_ptr->valid & PNG_INFO_tRNS)
   {
      trans_alpha = info_ptr->trans_alpha;
      num_trans   = info_ptr->num_trans;
      OPNG_ASSERT(trans_alpha != NULL && num_trans > 0);
   }
   else
   {
      trans_alpha = NULL;
      num_trans   = 0;
   }

   /* Analyze the possible reductions. */
   /* Also check the integrity of PLTE and tRNS. */
   opng_analyze_sample_usage(png_ptr, info_ptr, is_used);
   /* Palette-to-gray does not work (yet) if the bit depth is below 8. */
   is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) &&
             (info_ptr->bit_depth == 8);
   last_color_index = last_trans_index = -1;
   for (k = 0; k < 256; ++k)
   {
      if (!is_used[k])
         continue;
      last_color_index = k;
      if (k < num_trans && trans_alpha[k] < 255)
         last_trans_index = k;
      if (is_gray)
         if (palette[k].red != palette[k].green ||
             palette[k].red != palette[k].blue)
            is_gray = 0;
   }
   OPNG_ASSERT(last_color_index >= 0);
   if (last_color_index >= num_palette)
   {
      png_warning(png_ptr, "Too few colors in palette");
      /* Fix the palette by adding blank entries at the end. */
      num_palette = last_color_index + 1;
      info_ptr->num_palette = (png_uint_16)num_palette;
   }
   if (num_trans > num_palette)
   {
      png_warning(png_ptr, "Too many alpha values in tRNS");
      info_ptr->num_trans = info_ptr->num_palette;
   }
   num_trans = last_trans_index + 1;
   OPNG_ASSERT(num_trans <= num_palette);

   /* Check if tRNS can be reduced to grayscale. */
   if (is_gray && num_trans > 0)
   {
      gray_trans.gray = palette[last_trans_index].red;
      last_trans_value = trans_alpha[last_trans_index];
      for (k = 0; k <= last_color_index; ++k)
      {
         if (!is_used[k])
            continue;
         if (k <= last_trans_index)
         {
            crt_trans_value = trans_alpha[k];
            /* Cannot reduce if different colors have transparency. */
            if (crt_trans_value < 255 && palette[k].red != gray_trans.gray)
            {
               is_gray = 0;
               break;
            }
         }
         else
            crt_trans_value = 255;
         /* Cannot reduce if same color has multiple transparency levels. */
         if (palette[k].red == gray_trans.gray &&
             crt_trans_value != last_trans_value)
         {
            is_gray = 0;
            break;
         }
      }
   }

   /* Initialize result value. */
   result = OPNG_REDUCE_NONE;

   /* Remove tRNS if possible. */
   if ((info_ptr->valid & PNG_INFO_tRNS) && num_trans == 0)
   {
      png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
      info_ptr->valid &= ~PNG_INFO_tRNS;
      result = OPNG_REDUCE_PALETTE_FAST;
   }

   if (reductions & OPNG_REDUCE_PALETTE_FAST)
   {
      if (num_palette != last_color_index + 1)
      {
         /* Reduce PLTE. */
         /* hIST is reduced automatically. */
         info_ptr->num_palette = (png_uint_16)(last_color_index + 1);
         result = OPNG_REDUCE_PALETTE_FAST;
      }

      if ((info_ptr->valid & PNG_INFO_tRNS) &&
          (int)info_ptr->num_trans != num_trans)
      {
         /* Reduce tRNS. */
         info_ptr->num_trans = (png_uint_16)num_trans;
         result = OPNG_REDUCE_PALETTE_FAST;
      }
   }

   if (reductions & OPNG_REDUCE_8_TO_4_2_1)
      result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions);
   if (info_ptr->bit_depth < 8 || !is_gray)
      return result;

   /* Reduce palette -> grayscale. */
   for (i = 0; i < height; ++i)
      for (j = 0; j < width; ++j)
         rows[i][j] = palette[rows[i][j]].red;

#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
   /* Update the ancillary chunk info. */
   if (info_ptr->valid & PNG_INFO_bKGD)
      info_ptr->background.gray = palette[info_ptr->background.index].red;
#endif
#if defined(PNG_hIST_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_hIST)
   {
      png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1);
      info_ptr->valid &= ~PNG_INFO_hIST;
   }
#endif
#if defined(PNG_sBIT_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sBIT)
   {
      png_color_8p sig_bit_ptr = &info_ptr->sig_bit;
      png_byte max_sig_bit = sig_bit_ptr->red;
      if (max_sig_bit < sig_bit_ptr->green)
         max_sig_bit = sig_bit_ptr->green;
      if (max_sig_bit < sig_bit_ptr->blue)
         max_sig_bit = sig_bit_ptr->blue;
      png_ptr->sig_bit.gray = info_ptr->sig_bit.gray = max_sig_bit;
   }
#endif
   if (info_ptr->valid & PNG_INFO_tRNS)
      png_set_tRNS(png_ptr, info_ptr, NULL, 0, &gray_trans);

   /* Update the image info. */
   png_ptr->rowbytes   = info_ptr->rowbytes   = 0;
   png_ptr->color_type = info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1);
   info_ptr->valid &= ~PNG_INFO_PLTE;
   return OPNG_REDUCE_PALETTE_TO_GRAY;  /* ignore the former result */
}
Exemplo n.º 21
0
void PNGAPI
png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_charp name, int compression_type,
    png_const_bytep profile, png_uint_32 proflen)
{
   png_charp new_iccp_name;
   png_bytep new_iccp_profile;
   png_size_t length;

   png_debug1(1, "in %s storage function", "iCCP");

   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
      return;

   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
      png_app_error(png_ptr, "Invalid iCCP compression method");

   /* Set the colorspace first because this validates the profile; do not
    * override previously set app cHRM or gAMA here (because likely as not the
    * application knows better than libpng what the correct values are.)  Pass
    * the info_ptr color_type field to png_colorspace_set_ICC because in the
    * write case it has not yet been stored in png_ptr.
    */
   {
      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
         proflen, profile, info_ptr->color_type);

      png_colorspace_sync_info(png_ptr, info_ptr);

      /* Don't do any of the copying if the profile was bad, or inconsistent. */
      if (result == 0)
         return;

      /* But do write the gAMA and cHRM chunks from the profile. */
      info_ptr->colorspace.flags |=
         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   }

   length = strlen(name)+1;
   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));

   if (new_iccp_name == NULL)
   {
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");

      return;
   }

   memcpy(new_iccp_name, name, length);
   new_iccp_profile = png_voidcast(png_bytep,
      png_malloc_warn(png_ptr, proflen));

   if (new_iccp_profile == NULL)
   {
      png_free(png_ptr, new_iccp_name);
      png_benign_error(png_ptr,
          "Insufficient memory to process iCCP profile");

      return;
   }

   memcpy(new_iccp_profile, profile, proflen);

   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);

   info_ptr->iccp_proflen = proflen;
   info_ptr->iccp_name = new_iccp_name;
   info_ptr->iccp_profile = new_iccp_profile;
   info_ptr->free_me |= PNG_FREE_ICCP;
   info_ptr->valid |= PNG_INFO_iCCP;
}
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
                           int transforms,
                           voidp params)
{
   int row;

   if (png_ptr == NULL)
      return;

   /* png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk).
    */
   png_read_info(png_ptr, info_ptr);
   if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
      png_error(png_ptr, "Image is too high to process with png_read_png()");

   /* -------------- image transformations start here ------------------- */

#ifdef PNG_READ_16_TO_8_SUPPORTED
   /* Tell libpng to strip 16 bit/color files down to 8 bits per color.
    */
   if (transforms & PNG_TRANSFORM_STRIP_16)
      png_set_strip_16(png_ptr);
#endif

#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
   /* Strip alpha bytes from the input data without combining with
    * the background (not recommended).
    */
   if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
      png_set_strip_alpha(png_ptr);
#endif

#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
   /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   if (transforms & PNG_TRANSFORM_PACKING)
      png_set_packing(png_ptr);
#endif

#ifdef PNG_READ_PACKSWAP_SUPPORTED
   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing).
    */
   if (transforms & PNG_TRANSFORM_PACKSWAP)
      png_set_packswap(png_ptr);
#endif

#ifdef PNG_READ_EXPAND_SUPPORTED
   /* Expand paletted colors into true RGB triplets
    * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
    * Expand paletted or RGB images with transparency to full alpha
    * channels so the data will be available as RGBA quartets.
    */
   if (transforms & PNG_TRANSFORM_EXPAND)
      if ((png_ptr->bit_depth < 8) ||
          (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
          (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
         png_set_expand(png_ptr);
#endif

   /* We don't handle background color or gamma transformation or quantizing.
    */

#ifdef PNG_READ_INVERT_SUPPORTED
   /* Invert monochrome files to have 0 as white and 1 as black
    */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
      png_set_invert_mono(png_ptr);
#endif

#ifdef PNG_READ_SHIFT_SUPPORTED
   /* If you want to shift the pixel values from the range [0,255] or
    * [0,65535] to the original [0,7] or [0,31], or whatever range the
    * colors were originally in:
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }
#endif

#ifdef PNG_READ_BGR_SUPPORTED
   /* Flip the RGB pixels to BGR (or RGBA to BGRA)
    */
   if (transforms & PNG_TRANSFORM_BGR)
      png_set_bgr(png_ptr);
#endif

#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
    */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#ifdef PNG_READ_SWAP_SUPPORTED
   /* Swap bytes of 16 bit files to least significant byte first
    */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
      png_set_swap(png_ptr);
#endif

/* Added at libpng-1.2.41 */
#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
   /* Invert the alpha channel from opacity to transparency
    */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
       png_set_invert_alpha(png_ptr);
#endif

/* Added at libpng-1.2.41 */
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
   /* Expand grayscale image to RGB
    */
   if (transforms & PNG_TRANSFORM_GRAY_TO_RGB)
       png_set_gray_to_rgb(png_ptr);
#endif

   /* We don't handle adding filler bytes */

   /* Optional call to gamma correct and add the background to the palette
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (i.e., you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* -------------- image transformations end here ------------------- */

   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
   if (info_ptr->row_pointers == NULL)
   {
    png_uint_32 iptr;

      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
         info_ptr->height * png_sizeof(png_bytep));
      for (iptr=0; iptr<info_ptr->height; iptr++)
         info_ptr->row_pointers[iptr] = NULL;

      info_ptr->free_me |= PNG_FREE_ROWS;

      for (row = 0; row < (int)info_ptr->height; row++)
         info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
            png_get_rowbytes(png_ptr, info_ptr));
   }

   png_read_image(png_ptr, info_ptr->row_pointers);
   info_ptr->valid |= PNG_INFO_IDAT;

   /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
   png_read_end(png_ptr, info_ptr);

   transforms = transforms; /* Quiet compiler warnings */
   params = params;

}
Exemplo n.º 23
0
void Functions::FileImage::SaveToPNG(std::string filename, RGBA* imageRGBA, unsigned short width, unsigned short height){
	FILE *fp = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_bytep row = NULL;

	// Open file for writing (binary mode)
	fp = fopen(filename.c_str(), "wb");
	if (fp == NULL) {
		LOGSYSTEM->Error("Could not open file for writing");
		return;
	}

	// Initialize write structure
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		LOGSYSTEM->Error("Could not allocate write struct");
		fclose(fp);
		return;
	}

	// Initialize info structure
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		LOGSYSTEM->Error("Could not allocate info struct");
		fclose(fp);
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		return;
	}

	// Setup Exception handling
	if (setjmp(png_jmpbuf(png_ptr))) {
		LOGSYSTEM->Error("Error during png creation");
		fclose(fp);
		png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		return;
	}

	png_init_io(png_ptr, fp);

	// Write header (8 bit colour depth)
	png_set_IHDR(png_ptr, info_ptr, width, height,
			8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_write_info(png_ptr, info_ptr);

	// Allocate memory for one row (3 bytes per pixel - RGB)
	row = (png_bytep) malloc(4 * width * sizeof(png_byte));

	// Write image data
	int x, y;
	for (y=0 ; y<height ; y++) {
		for (x=0 ; x<width ; x++) {
			row[x*4] = imageRGBA[y*width + x].R;
			row[x*4+1] = imageRGBA[y*width + x].G;
			row[x*4+2] = imageRGBA[y*width + x].B;
			row[x*4+3] = imageRGBA[y*width + x].A;
		}
		png_write_row(png_ptr, row);
	}

	// End write
	png_write_end(png_ptr, NULL);

	fclose(fp);
	png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
	free(row);
}
/*
 * Reduce the image type to a lower bit depth and color type,
 * by removing redundant bits.
 * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha.
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 * All reductions are performed in a single step.
 */
static png_uint_32  opng_reduce_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_bytep src_ptr, dest_ptr;
   png_uint_32 width, height;
   int interlace_type, compression_type, filter_type, src_bit_depth, dest_bit_depth, src_color_type;
   /* See which reductions may be performed. */
   reductions = opng_analyze_bits(png_ptr, info_ptr, reductions);
   if (reductions == OPNG_REDUCE_NONE)
      return OPNG_REDUCE_NONE;  /* exit early */

   png_get_IHDR(png_ptr, info_ptr, &width, &height,
      &src_bit_depth, &src_color_type,
      &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   /* Compute the new image parameters bit_depth, color_type, etc. */
   OPNG_ASSERT(src_bit_depth >= 8);
   if (reductions & OPNG_REDUCE_16_TO_8)
   {
      OPNG_ASSERT(src_bit_depth == 16);
      dest_bit_depth = 8;
   }
   else
      dest_bit_depth = src_bit_depth;

   int src_byte_depth = src_bit_depth / 8;
   int dest_byte_depth = dest_bit_depth / 8;

   int dest_color_type = src_color_type;
   if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR);
      dest_color_type &= ~PNG_COLOR_MASK_COLOR;
   }
   if (reductions & OPNG_REDUCE_STRIP_ALPHA)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA);
      dest_color_type &= ~PNG_COLOR_MASK_ALPHA;
   }

   int src_channels = png_get_channels(png_ptr, info_ptr);
   int dest_channels =
      ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) +
      ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0);

   int src_sample_size = src_channels * src_byte_depth;
   int dest_sample_size = dest_channels * dest_byte_depth;

   /* Pre-compute the intra-sample translation table. */
   int k;
   int tran_tbl[8];
   for (k = 0; k < 4 * dest_byte_depth; ++k)
      tran_tbl[k] = k * src_bit_depth / dest_bit_depth;
   /* If rgb --> gray, shift the alpha component two positions to the left. */
   if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) &&
       (dest_color_type & PNG_COLOR_MASK_ALPHA))
   {
      tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth];
      if (dest_byte_depth == 2)
         tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1];
   }

   /* Translate the samples to the new image type. */
   OPNG_ASSERT(src_sample_size > dest_sample_size);
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   for (png_uint_32 i = 0; i < height; ++i, ++row_ptr)
   {
      src_ptr = dest_ptr = *row_ptr;
      for (png_uint_32 j = 0; j < width; ++j)
      {
         for (k = 0; k < dest_sample_size; ++k)
            dest_ptr[k] = src_ptr[tran_tbl[k]];
         src_ptr += src_sample_size;
         dest_ptr += dest_sample_size;
      }
   }
   png_color_16p trans_color;
   /* Update the ancillary information. */
   if (png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (trans_color->red   % 257 == 0 &&
             trans_color->green % 257 == 0 &&
             trans_color->blue  % 257 == 0 &&
             trans_color->gray  % 257 == 0)
         {
            trans_color->red   &= 255;
            trans_color->green &= 255;
            trans_color->blue  &= 255;
            trans_color->gray  &= 255;
         }
         else
         {
            /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         if (trans_color->red == trans_color->green ||
             trans_color->red == trans_color->blue)
            trans_color->gray = trans_color->red;
         else
         {
            /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
   }
#ifdef PNG_bKGD_SUPPORTED
   png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         background->red   &= 255;
         background->green &= 255;
         background->blue  &= 255;
         background->gray  &= 255;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
         background->gray = background->red;
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (sig_bits->red > 8)
            sig_bits->red = 8;
         if (sig_bits->green > 8)
            sig_bits->green = 8;
         if (sig_bits->blue > 8)
            sig_bits->blue = 8;
         if (sig_bits->gray > 8)
            sig_bits->gray = 8;
         if (sig_bits->alpha > 8)
            sig_bits->alpha = 8;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         png_byte max_sig_bits = sig_bits->red;
         if (max_sig_bits < sig_bits->green)
            max_sig_bits = sig_bits->green;
         if (max_sig_bits < sig_bits->blue)
            max_sig_bits = sig_bits->blue;
         sig_bits->gray = max_sig_bits;
      }
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height,
      dest_bit_depth, dest_color_type,
      interlace_type, compression_type, filter_type);

   return reductions;
}
Exemplo n.º 25
0
int IMG_SavePNG_RW (SDL_Surface *face, SDL_RWops *src)
{
	png_structp png_ptr = 0;
	png_infop info_ptr = NULL;
	//png_colorp palette = 0;
	png_bytep *row_pointers = NULL;
	int i;
	int colortype;
	int result = -1;
        
	png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, png_user_error, png_user_warn);
	
	if (png_ptr == NULL)
	{
		IMG_SetError ("Couldn't allocate memory for PNG file");
		return -1;
	}
	
	/* Allocate/initialize the image information data.  REQUIRED */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		IMG_SetError("Couldn't create image information for PNG file");
		goto done;
	}
	
	/* Set error handling. */
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		/* If we get here, we had a problem reading the file */
		IMG_SetError("Error writing the PNG file");
		goto done;
	}
	
	png_set_write_fn (png_ptr, src, png_write_data, png_io_flush);
	
	/* 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
	 */
	colortype = png_colortype_from_surface (face);
	png_set_IHDR (png_ptr, info_ptr, face->w, face->h, 8, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	
	/* Write the file header information.  REQUIRED */
	png_write_info (png_ptr, info_ptr);
	
	/* pack pixels into bytes */
	png_set_packing (png_ptr);
	
	/* Create the array of pointers to image data */
	row_pointers = (png_bytep*) malloc (sizeof(png_bytep)*face->h);
	
	if (row_pointers == NULL)
	{
		IMG_SetError("Couldn't allocate PNG row pointers");
		goto done;
	}
	
	for (i = 0; i < face->h; i++)
		row_pointers[i] = (png_bytep)(Uint8 *)face->pixels + i*face->pitch;
	
	/* write out the entire image data in one call */
	png_write_image (png_ptr, row_pointers);
	png_write_end(png_ptr, info_ptr);
	result = 0;  /* success! */
	
done:
	if (row_pointers != NULL)
		free (row_pointers);
	

	if (info_ptr != NULL)
		png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	
	png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
	
	return result;
}
Exemplo n.º 26
0
void PNGAPI
png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
{
   png_debug1(1, "in %s storage function", "tRNS");

   if (png_ptr == NULL || info_ptr == NULL)

      return;

   if (trans_alpha != NULL)
   {
       /* It may not actually be necessary to set png_ptr->trans_alpha here;
        * we do it for backward compatibility with the way the png_handle_tRNS
        * function used to do the allocation.
        *
        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
        * relies on png_set_tRNS storing the information in png_struct
        * (otherwise it won't be there for the code in pngrtran.c).
        */

       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);

       /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
       png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
         png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));

       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
   }

   if (trans_color != NULL)
   {
#ifdef PNG_WARNINGS_SUPPORTED
      if (info_ptr->bit_depth < 16)
      {
         int sample_max = (1 << info_ptr->bit_depth) - 1;

         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
             trans_color->gray > sample_max) ||
             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
             (trans_color->red > sample_max ||
             trans_color->green > sample_max ||
             trans_color->blue > sample_max)))
            png_warning(png_ptr,
               "tRNS chunk has out-of-range samples for bit_depth");
      }
#endif

      info_ptr->trans_color = *trans_color;

      if (num_trans == 0)
         num_trans = 1;
   }

   info_ptr->num_trans = (png_uint_16)num_trans;

   if (num_trans != 0)
   {
      info_ptr->valid |= PNG_INFO_tRNS;
      info_ptr->free_me |= PNG_FREE_TRNS;
   }
}
Exemplo n.º 27
0
int gr_save_screenshot(const char *dest)
{
    uint32_t y, stride_bytes;
    int res = -1;
    GGLContext *gl = NULL;
    GGLSurface surface;
    uint8_t * volatile img_data = NULL;
    uint8_t *ptr;
    FILE *fp = NULL;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;

    fp = fopen(dest, "wb");
    if(!fp)
        goto exit;

    img_data = malloc(vi.xres * vi.yres * 3);
    surface.version = sizeof(surface);
    surface.width = gr_mem_surface.width;
    surface.height = gr_mem_surface.height;
    surface.stride = gr_mem_surface.width;
    surface.data = img_data;
    surface.format = GGL_PIXEL_FORMAT_RGB_888;

    gglInit(&gl);
    gl->colorBuffer(gl, &surface);
    gl->activeTexture(gl, 0);

    gl->bindTexture(gl, &gr_mem_surface);
    gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
    gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
    gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
    gl->enable(gl, GGL_TEXTURE_2D);
    gl->texCoord2i(gl, 0, 0);
    gl->recti(gl, 0, 0, gr_mem_surface.width, gr_mem_surface.height);

    gglUninit(gl);
    gl = NULL;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        goto exit;

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
        goto exit;

    if (setjmp(png_jmpbuf(png_ptr)))
        goto exit;

    png_init_io(png_ptr, fp);
    png_set_IHDR(png_ptr, info_ptr, surface.width, surface.height,
         8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_write_info(png_ptr, info_ptr);

    ptr = img_data;
    stride_bytes = surface.width*3;
    for(y = 0; y < surface.height; ++y)
    {
        png_write_row(png_ptr, ptr);
        ptr += stride_bytes;
    }

    png_write_end(png_ptr, NULL);

    res = 0;
exit:
    if(info_ptr)
        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    if(png_ptr)
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    if(gl)
        gglUninit(gl);
    if(img_data)
        free(img_data);
    if(fp)
        fclose(fp);
    return res;
}
/*
 * Reduce the palette. (Only the fast method is implemented.)
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 */
static png_uint_32 opng_reduce_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_colorp palette;
   png_bytep trans_alpha;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type, compression_type, filter_type;
   int num_palette, num_trans;
   int last_color_index, last_trans_index;
   png_byte crt_trans_value, last_trans_value;
   png_byte is_used[256];
   png_color_16 gray_trans;
   png_uint_32 result = OPNG_REDUCE_NONE;

   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
      &color_type, &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
   {
      palette = 0;
      num_palette = 0;
   }
   if (!png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0))
   {
      trans_alpha = 0;
      num_trans = 0;
   }
   else
      OPNG_ASSERT(trans_alpha && num_trans > 0);

   opng_analyze_sample_usage(png_ptr, info_ptr, is_used);
   /* Palette-to-gray does not work (yet) if the bit depth is below 8. */
   int is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) && (bit_depth == 8);
   last_color_index = last_trans_index = -1;
    int k;
   for (k= 0; k < 256; ++k)
   {
      if (!is_used[k])
         continue;
      last_color_index = k;
      if (k < num_trans && trans_alpha[k] < 255)
         last_trans_index = k;
      if (is_gray)
         if (palette[k].red != palette[k].green ||
             palette[k].red != palette[k].blue)
            is_gray = 0;
   }
   OPNG_ASSERT(last_color_index >= 0);
   OPNG_ASSERT(last_color_index >= last_trans_index);

   /* Check the integrity of PLTE and tRNS. */
   if (last_color_index >= num_palette)
   {
      png_warning(png_ptr, "Too few colors in PLTE");
      /* Fix the palette by adding blank entries at the end. */
      opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
      png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
      OPNG_ASSERT(num_palette == last_color_index + 1);
      result |= OPNG_REDUCE_REPAIR;
   }
   if (num_trans > num_palette)
   {
      png_warning(png_ptr, "Too many alpha values in tRNS");
      /* Transparency will be fixed further below. */
      result |= OPNG_REDUCE_REPAIR;
   }

   /* Check if tRNS can be reduced to grayscale. */
   if (is_gray && last_trans_index >= 0)
   {
      gray_trans.gray = palette[last_trans_index].red;
      last_trans_value = trans_alpha[last_trans_index];
      for (k = 0; k <= last_color_index; ++k)
      {
         if (!is_used[k])
            continue;
         if (k <= last_trans_index)
         {
            crt_trans_value = trans_alpha[k];
            /* Cannot reduce if different colors have transparency. */
            if (crt_trans_value < 255 && palette[k].red != gray_trans.gray)
            {
               is_gray = 0;
               break;
            }
         }
         else
            crt_trans_value = 255;
         /* Cannot reduce if same color has multiple transparency levels. */
         if (palette[k].red == gray_trans.gray &&
             crt_trans_value != last_trans_value)
         {
            is_gray = 0;
            break;
         }
      }
   }

   /* Remove tRNS if it is entirely sterile. */
   if (num_trans > 0 && last_trans_index < 0)
   {
      num_trans = 0;
      png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
      result |= OPNG_REDUCE_PALETTE_FAST;
   }

   if (reductions & OPNG_REDUCE_PALETTE_FAST)
   {
      if (num_palette != last_color_index + 1)
      {
         /* Reduce PLTE. */
         /* hIST is reduced automatically. */
         opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
         OPNG_ASSERT(num_palette == last_color_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }

      if (num_trans > 0 && num_trans != last_trans_index + 1)
      {
         /* Reduce tRNS. */
         opng_realloc_tRNS(png_ptr, info_ptr, last_trans_index + 1);
         png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0);
         OPNG_ASSERT(num_trans == last_trans_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }
   }

   if (reductions & OPNG_REDUCE_8_TO_4_2_1)
   {
      result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions);
      /* Refresh the image information. */
      bit_depth = png_get_bit_depth(png_ptr, info_ptr);
   }
   if ((bit_depth < 8) || !is_gray)
      return result;

   /* Reduce palette --> grayscale. */
   for (png_uint_32 i = 0; i < height; ++i)
   {
      for (png_uint_32 j = 0; j < width; ++j)
         row_ptr[i][j] = palette[row_ptr[i][j]].red;
   }

   /* Update the ancillary information. */
   if (num_trans > 0)
      png_set_tRNS(png_ptr, info_ptr, 0, 0, &gray_trans);
#ifdef PNG_bKGD_SUPPORTED
    png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
      background->gray = palette[background->index].red;
#endif
#ifdef PNG_hIST_SUPPORTED
    png_uint_16p hist;
   if (png_get_hIST(png_ptr, info_ptr, &hist))
   {
      png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_hIST);
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      png_byte max_sig_bits = sig_bits->red;
      if (max_sig_bits < sig_bits->green)
         max_sig_bits = sig_bits->green;
      if (max_sig_bits < sig_bits->blue)
         max_sig_bits = sig_bits->blue;
      sig_bits->gray = max_sig_bits;
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
      PNG_COLOR_TYPE_GRAY, interlace_type, compression_type, filter_type);
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1);
   png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
   return OPNG_REDUCE_PALETTE_TO_GRAY;  /* ignore the former result */
}
/* Free all memory used by the read */
void PNGAPI
png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
   png_infopp end_info_ptr_ptr)
{
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL, end_info_ptr = NULL;
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
   png_voidp mem_ptr = NULL;
#endif

   png_debug(1, "in png_destroy_read_struct");

   if (png_ptr_ptr != NULL)
      png_ptr = *png_ptr_ptr;
   if (png_ptr == NULL)
      return;

#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
   mem_ptr = png_ptr->mem_ptr;
#endif

   if (info_ptr_ptr != NULL)
      info_ptr = *info_ptr_ptr;

   if (end_info_ptr_ptr != NULL)
      end_info_ptr = *end_info_ptr_ptr;

   png_read_destroy(png_ptr, info_ptr, end_info_ptr);

   if (info_ptr != NULL)
   {
#ifdef PNG_TEXT_SUPPORTED
      png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
#endif

#ifdef PNG_USER_MEM_SUPPORTED
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
          (png_voidp)mem_ptr);
#else
      png_destroy_struct((png_voidp)info_ptr);
#endif
      *info_ptr_ptr = NULL;
   }

   if (end_info_ptr != NULL)
   {
#ifdef PNG_READ_TEXT_SUPPORTED
      png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1);
#endif
#ifdef PNG_USER_MEM_SUPPORTED
      png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
#else
      png_destroy_struct((png_voidp)end_info_ptr);
#endif
      *end_info_ptr_ptr = NULL;
   }

   if (png_ptr != NULL)
   {
#ifdef PNG_USER_MEM_SUPPORTED
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
          (png_voidp)mem_ptr);
#else
      png_destroy_struct((png_voidp)png_ptr);
#endif
      *png_ptr_ptr = NULL;
   }
}
Exemplo n.º 30
0
void PNGAPI
png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
    png_const_colorp palette, int num_palette)
{

   png_uint_32 max_palette_length;

   png_debug1(1, "in %s storage function", "PLTE");

   if (png_ptr == NULL || info_ptr == NULL)
      return;

   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;

   if (num_palette < 0 || num_palette > (int) max_palette_length)
   {
      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
         png_error(png_ptr, "Invalid palette length");

      else
      {
         png_warning(png_ptr, "Invalid palette length");

         return;
      }
   }

   if ((num_palette > 0 && palette == NULL) ||
      (num_palette == 0
#        ifdef PNG_MNG_FEATURES_SUPPORTED
            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
#        endif
      ))
   {
      png_error(png_ptr, "Invalid palette");
   }

   /* It may not actually be necessary to set png_ptr->palette here;
    * we do it for backward compatibility with the way the png_handle_tRNS
    * function used to do the allocation.
    *
    * 1.6.0: the above statement appears to be incorrect; something has to set
    * the palette inside png_struct on read.
    */
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);

   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
    * of num_palette entries, in case of an invalid PNG file or incorrect
    * call to png_set_PLTE() with too-large sample values.
    */
   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));

   if (num_palette > 0)
      memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
   info_ptr->palette = png_ptr->palette;
   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;

   info_ptr->free_me |= PNG_FREE_PLTE;

   info_ptr->valid |= PNG_INFO_PLTE;
}