Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
22 KB
Referenced Files
None
Subscribers
None
diff --git a/util/loadpng/loadpng.c b/util/loadpng/loadpng.c
new file mode 100644
index 00000000..3e5d9612
--- /dev/null
+++ b/util/loadpng/loadpng.c
@@ -0,0 +1,404 @@
+#ifdef USE_ALLEGRO
+
+/* loadpng, Allegro wrapper routines for libpng
+ * by Peter Wang (tjaden@users.sf.net).
+ *
+ * This file is hereby placed in the public domain.
+ */
+
+
+#include <png.h>
+#include <allegro.h>
+#include <allegro/internal/aintern.h>
+#include "loadpng.h"
+
+/* We need internals _color_load_depth and _fixup_loaded_bitmap. The
+ * first can be replaced by the new get_color_depth() function which
+ * is in Allegro 4.1 branch. But it's not worth it to break 4.0
+ * compatibility.
+ */
+
+
+
+double _png_screen_gamma = -1.0;
+int _png_compression_level = Z_BEST_COMPRESSION;
+
+
+
+/* get_gamma:
+ * Get screen gamma value one of three ways.
+ */
+static double get_gamma(void)
+{
+ if (_png_screen_gamma == -1.0) {
+ /* Use the environment variable if available.
+ * 2.2 is a good guess for PC monitors.
+ * 1.1 is good for my laptop.
+ */
+ AL_CONST char *gamma_str = getenv("SCREEN_GAMMA");
+ return (gamma_str) ? atof(gamma_str) : 2.2;
+ }
+
+ return _png_screen_gamma;
+}
+
+
+
+/* read_data:
+ * Custom read function to use Allegro packfile routines,
+ * rather than C streams (so we can read from datafiles!)
+ */
+static void read_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+{
+ PACKFILE *f = (PACKFILE *)png_get_io_ptr(png_ptr);
+ if ((png_uint_32)pack_fread(data, length, f) != length)
+ png_error(png_ptr, "read error (loadpng calling pack_fread)");
+}
+
+
+
+/* check_if_png:
+ * Check if input file is really PNG format.
+ */
+#define PNG_BYTES_TO_CHECK 4
+
+static int check_if_png(PACKFILE *fp)
+{
+ unsigned char buf[PNG_BYTES_TO_CHECK];
+
+ ASSERT(fp);
+
+ if (pack_fread(buf, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
+ return 0;
+
+ return (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0);
+}
+
+
+
+/* really_load_png:
+ * Worker routine, used by load_png and load_memory_png.
+ */
+static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal)
+{
+ BITMAP *bmp;
+ PALETTE tmppal;
+ png_uint_32 width, height, rowbytes;
+ int bit_depth, color_type, interlace_type;
+ double image_gamma, screen_gamma;
+ int intent;
+ int bpp, dest_bpp;
+ int tRNS_to_alpha = FALSE;
+ int number_passes, pass;
+
+ ASSERT(png_ptr && info_ptr && rgb);
+
+ /* The call to 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);
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+ /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ png_set_packing(png_ptr);
+
+ /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+ if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
+ png_set_expand(png_ptr);
+
+ /* Adds a full alpha channel if there is transparency information
+ * in a tRNS chunk. */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(png_ptr);
+ tRNS_to_alpha = TRUE;
+ }
+
+ /* Convert 16-bits per colour component to 8-bits per colour component. */
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ /* Convert grayscale to RGB triplets */
+ if ((color_type == PNG_COLOR_TYPE_GRAY) ||
+ (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ png_set_gray_to_rgb(png_ptr);
+
+ /* Optionally, tell libpng to handle the gamma correction for us. */
+ if (_png_screen_gamma != 0.0) {
+ screen_gamma = get_gamma();
+
+ if (png_get_sRGB(png_ptr, info_ptr, &intent))
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ else {
+ if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
+ png_set_gamma(png_ptr, screen_gamma, image_gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ }
+ }
+
+ /* Turn on interlace handling. */
+ number_passes = png_set_interlace_handling(png_ptr);
+
+ /* Call to gamma correct and add the background to the palette
+ * and update info structure.
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* Even if the user doesn't supply space for a palette, we want
+ * one for the load process.
+ */
+ if (!pal)
+ pal = tmppal;
+
+ /* Palettes. */
+ if (color_type & PNG_COLOR_MASK_PALETTE) {
+ int num_palette, i;
+ png_colorp palette;
+
+ if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
+ /* We don't actually dither, we just copy the palette. */
+ for (i = 0; ((i < num_palette) && (i < 256)); i++) {
+ pal[i].r = palette[i].red >> 2; /* 256 -> 64 */
+ pal[i].g = palette[i].green >> 2;
+ pal[i].b = palette[i].blue >> 2;
+ }
+
+ for (; i < 256; i++)
+ pal[i].r = pal[i].g = pal[i].b = 0;
+ }
+ }
+ else {
+ generate_332_palette(pal);
+ }
+
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+ /* Allocate the memory to hold the image using the fields of info_ptr. */
+ bpp = rowbytes * 8 / width;
+
+ /* Allegro cannot handle less than 8 bpp. */
+ if (bpp < 8)
+ bpp = 8;
+
+ dest_bpp = _color_load_depth(bpp, (bpp == 32));
+ bmp = create_bitmap_ex(bpp, width, height);
+
+ /* Maybe flip RGB to BGR. */
+ if ((bpp == 24) || (bpp == 32)) {
+ int c = makecol_depth(bpp, 0, 0, 255);
+ unsigned char *pc = (unsigned char *)&c;
+ if (pc[0] == 255)
+ png_set_bgr(png_ptr);
+#ifdef ALLEGRO_BIG_ENDIAN
+ png_set_swap_alpha(png_ptr);
+#endif
+ }
+
+ /* Read the image, one line at a line (easier to debug!) */
+ for (pass = 0; pass < number_passes; pass++) {
+ png_uint_32 y;
+ for (y = 0; y < height; y++)
+ png_read_row(png_ptr, bmp->line[y], NULL);
+ }
+
+ /* Let Allegro convert the image into the desired colour depth. */
+ if (dest_bpp != bpp)
+ bmp = _fixup_loaded_bitmap(bmp, pal, dest_bpp);
+
+ /* Read rest of file, and get additional chunks in info_ptr. */
+ png_read_end(png_ptr, info_ptr);
+
+ return bmp;
+}
+
+
+
+/* load_png:
+ * Load a PNG file from disk, doing colour coversion if required.
+ */
+BITMAP *load_png(AL_CONST char *filename, RGB *pal)
+{
+ PACKFILE *fp;
+ BITMAP *bmp;
+
+ ASSERT(filename);
+
+ fp = pack_fopen(filename, "r");
+ if (!fp)
+ return NULL;
+
+ bmp = load_png_pf(fp, pal);
+
+ pack_fclose(fp);
+
+ return bmp;
+}
+
+
+
+/* load_png_pf:
+ * Load a PNG file from disk, doing colour coversion if required.
+ */
+BITMAP *load_png_pf(PACKFILE *fp, RGB *pal)
+{
+ BITMAP *bmp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ ASSERT(fp);
+
+ if (!check_if_png(fp)) {
+ return NULL;
+ }
+
+ /* 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 supply the
+ * the compiler header file version, so that we know if the application
+ * was compiled with a compatible version of the library.
+ */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)NULL, NULL, NULL);
+ if (!png_ptr) {
+ return NULL;
+ }
+
+ /* Allocate/initialize the memory for image information. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return NULL;
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+ if (setjmp(png_ptr->jmpbuf)) {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ /* If we get here, we had a problem reading the file */
+ return NULL;
+ }
+
+ /* Use Allegro packfile routines. */
+ png_set_read_fn(png_ptr, fp, (png_rw_ptr)read_data);
+
+ /* We have already read some of the signature. */
+ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
+
+ /* Really load the image now. */
+ bmp = really_load_png(png_ptr, info_ptr, pal);
+
+ /* Clean up after the read, and free any memory allocated. */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ return bmp;
+}
+
+
+
+/* read_data_memory:
+ * Custom reader function to read a PNG file from a memory buffer.
+ */
+
+typedef struct {
+ AL_CONST unsigned char *buffer;
+ png_uint_32 bufsize;
+ png_uint_32 current_pos;
+} MEMORY_READER_STATE;
+
+static void read_data_memory(png_structp png_ptr, png_bytep data, png_uint_32 length)
+{
+ MEMORY_READER_STATE *f = (MEMORY_READER_STATE *)png_get_io_ptr(png_ptr);
+
+ if (length > (f->bufsize - f->current_pos))
+ png_error(png_ptr, "read error in read_data_memory (loadpng)");
+
+ memcpy(data, f->buffer + f->current_pos, length);
+ f->current_pos += length;
+}
+
+
+
+/* check_if_png_memory:
+ * Check if input buffer is really PNG format.
+ */
+static int check_if_png_memory(AL_CONST void *buffer)
+{
+ unsigned char *buf = (unsigned char *)buffer;
+ return (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0);
+}
+
+
+
+/* load_memory_png:
+ * Load a PNG file from memory, doing colour coversion if required.
+ */
+BITMAP *load_memory_png(AL_CONST void *buffer, int bufsize, RGB *pal)
+{
+ MEMORY_READER_STATE memory_reader_state;
+ BITMAP *bmp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ if (!buffer || (bufsize <= 0))
+ return NULL;
+
+ if (!check_if_png_memory(buffer))
+ return NULL;
+
+ /* 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 supply the
+ * the compiler header file version, so that we know if the application
+ * was compiled with a compatible version of the library.
+ */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ (void *)NULL, NULL, NULL);
+ if (!png_ptr)
+ return NULL;
+
+ /* Allocate/initialize the memory for image information. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return NULL;
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+ if (setjmp(png_ptr->jmpbuf)) {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ /* If we get here, we had a problem reading the file */
+ return NULL;
+ }
+
+ /* Set up the reader state. */
+ memory_reader_state.buffer = (unsigned char *)buffer;
+ memory_reader_state.bufsize = bufsize;
+ memory_reader_state.current_pos = PNG_BYTES_TO_CHECK;
+
+ /* Tell libpng to use our custom reader. */
+ png_set_read_fn(png_ptr, &memory_reader_state, (png_rw_ptr)read_data_memory);
+
+ /* We have already read some of the signature. */
+ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
+
+ /* Really load the image now. */
+ bmp = really_load_png(png_ptr, info_ptr, pal);
+
+ /* Clean up after the read, and free any memory allocated. */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ return bmp;
+}
+
+#endif
diff --git a/util/loadpng/loadpng.h b/util/loadpng/loadpng.h
new file mode 100644
index 00000000..c666b4ab
--- /dev/null
+++ b/util/loadpng/loadpng.h
@@ -0,0 +1,79 @@
+#ifdef USE_ALLEGRO
+
+/* loadpng.h */
+/* This file is hereby placed in the public domain. */
+#ifndef _included_loadpng_h_
+#define _included_loadpng_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* Overkill :-) */
+#define LOADPNG_VERSION 1
+#define LOADPNG_SUBVERSION 5
+#define LOADPNG_VERSIONSTR "1.5"
+
+
+/* _png_screen_gamma is slightly overloaded (sorry):
+ *
+ * A value of 0.0 means: Don't do any gamma correction in load_png()
+ * and load_memory_png(). This meaning was introduced in v1.4.
+ *
+ * A value of -1.0 means: Use the value from the environment variable
+ * SCREEN_GAMMA (if available), otherwise fallback to a value of 2.2
+ * (a good guess for PC monitors, and the value for sRGB colourspace).
+ * This is the default.
+ *
+ * Otherwise, the value of _png_screen_gamma is taken as-is.
+ */
+extern double _png_screen_gamma;
+
+
+/* Choose zlib compression level for saving file.
+ * Default is Z_BEST_COMPRESSION.
+ */
+extern int _png_compression_level;
+
+
+/* Load a PNG from disk. */
+extern BITMAP *load_png(AL_CONST char *filename, RGB *pal);
+
+/* Load a PNG from some place. */
+extern BITMAP *load_png_pf(PACKFILE *fp, RGB *pal);
+
+/* Load a PNG from memory. */
+extern BITMAP *load_memory_png(AL_CONST void *buffer, int buffer_size, RGB *pal);
+
+/* Save a bitmap to disk in PNG format. */
+extern int save_png(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal);
+
+/* Adds `PNG' to Allegro's internal file type table.
+ * You can then just use load_bitmap and save_bitmap as usual.
+ */
+extern void register_png_file_type(void);
+
+/* Register an datafile type ID with Allegro, so that when an object
+ * with that type ID is encountered while loading a datafile, that
+ * object will be loaded as a PNG file.
+ */
+extern void register_png_datafile_object(int id);
+
+/* This is supposed to resemble jpgalleg_init in JPGalleg 2.0, just in
+ * case you are lazier than lazy. It contains these 3 lines of code:
+ * register_png_datafile_object(DAT_ID('P','N','G',' '));
+ * register_png_file_type();
+ * return 0;
+ */
+extern int loadpng_init(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _included_loadpng_h */
+
+#endif
diff --git a/util/loadpng/regpng.c b/util/loadpng/regpng.c
new file mode 100644
index 00000000..ecf7e40f
--- /dev/null
+++ b/util/loadpng/regpng.c
@@ -0,0 +1,72 @@
+#ifdef USE_ALLEGRO
+
+/* loadpng, Allegro wrapper routines for libpng
+ * by Peter Wang (tjaden@users.sf.net).
+ *
+ * This file is hereby placed in the public domain.
+ */
+
+
+#include <allegro.h>
+#include "loadpng.h"
+
+
+
+/* register_png_file_type:
+ */
+void register_png_file_type(void)
+{
+ register_bitmap_file_type("png", load_png, save_png);
+}
+
+
+
+/* register_png_datafile_object:
+ */
+
+static void *load_datafile_png(PACKFILE *f, long size)
+{
+ BITMAP *bmp;
+ void *buffer;
+
+ buffer = malloc(size);
+ if (!buffer)
+ return NULL;
+
+ if (pack_fread(buffer, size, f) != size) {
+ free(buffer);
+ return NULL;
+ }
+
+ bmp = load_memory_png(buffer, size, NULL);
+
+ free(buffer);
+
+ return bmp;
+}
+
+static void destroy_datafile_png(void *data)
+{
+ if (data) {
+ destroy_bitmap((BITMAP *)data);
+ }
+}
+
+void register_png_datafile_object(int id)
+{
+ register_datafile_object(id, load_datafile_png, destroy_datafile_png);
+}
+
+
+
+/* loadpng_init:
+ * This is supposed to resemble jpgalleg_init in JPGalleg 2.0.
+ */
+int loadpng_init(void)
+{
+ register_png_datafile_object(DAT_ID('P','N','G',' '));
+ register_png_file_type();
+ return 0;
+}
+
+#endif
diff --git a/util/loadpng/savepng.c b/util/loadpng/savepng.c
new file mode 100644
index 00000000..2138fdfa
--- /dev/null
+++ b/util/loadpng/savepng.c
@@ -0,0 +1,310 @@
+#ifdef USE_ALLEGRO
+
+/* loadpng, Allegro wrapper routines for libpng
+ * by Peter Wang (tjaden@users.sf.net).
+ *
+ * This file is hereby placed in the public domain.
+ */
+
+
+#include <png.h>
+#include <allegro.h>
+#include "loadpng.h"
+
+
+
+/* write_data:
+ * Custom write function to use Allegro packfile routines,
+ * rather than C streams.
+ */
+static void write_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+{
+ PACKFILE *f = (PACKFILE *)png_get_io_ptr(png_ptr);
+ if ((png_uint_32)pack_fwrite(data, length, f) != length)
+ png_error(png_ptr, "write error (loadpng calling pack_fwrite)");
+}
+
+/* Don't think Allegro has any problem with buffering
+ * (rather, Allegro provides no way to flush packfiles).
+ */
+static void flush_data(png_structp png_ptr) { (void)png_ptr; }
+
+
+
+/* save_indexed:
+ * Core save routine for 8 bpp images.
+ * */
+static int save_indexed(png_structp png_ptr, BITMAP *bmp)
+{
+ ASSERT(bitmap_color_depth(bmp) == 8);
+
+ if (is_memory_bitmap(bmp)) { /* fast path */
+ int y;
+
+ for (y=0; y<bmp->h; y++) {
+ png_write_row(png_ptr, bmp->line[y]);
+ }
+
+ return 1;
+ }
+ else { /* generic case */
+ unsigned char *rowdata;
+ int x, y;
+
+ rowdata = (unsigned char *)malloc(bmp->w * 3);
+ if (!rowdata)
+ return 0;
+
+ for (y=0; y<bmp->h; y++) {
+ unsigned char *p = rowdata;
+
+ for (x=0; x<bmp->w; x++) {
+ *p++ = getpixel(bmp, x, y);
+ }
+
+ png_write_row(png_ptr, rowdata);
+ }
+
+ free(rowdata);
+
+ return 1;
+ }
+}
+
+
+
+/* save_rgb:
+ * Core save routine for 15/16/24 bpp images (original by Martijn Versteegh).
+ */
+static int save_rgb(png_structp png_ptr, BITMAP *bmp)
+{
+ AL_CONST int depth = bitmap_color_depth(bmp);
+ unsigned char *rowdata;
+ int y, x;
+
+ ASSERT(depth == 15 || depth == 16 || depth == 24);
+
+ rowdata = (unsigned char *)malloc(bmp->w * 3);
+ if (!rowdata)
+ return 0;
+
+ for (y=0; y<bmp->h; y++) {
+ unsigned char *p = rowdata;
+
+ if (depth == 15) {
+ for (x = 0; x < bmp->w; x++) {
+ int c = getpixel(bmp, x, y);
+ *p++ = getr15(c);
+ *p++ = getg15(c);
+ *p++ = getb15(c);
+ }
+ }
+ else if (depth == 16) {
+ for (x = 0; x < bmp->w; x++) {
+ int c = getpixel(bmp, x, y);
+ *p++ = getr16(c);
+ *p++ = getg16(c);
+ *p++ = getb16(c);
+ }
+ }
+ else { /* depth == 24 */
+ for (x = 0; x < bmp->w; x++) {
+ int c = getpixel(bmp, x, y);
+ *p++ = getr24(c);
+ *p++ = getg24(c);
+ *p++ = getb24(c);
+ }
+ }
+
+ png_write_row(png_ptr, rowdata);
+ }
+
+ free(rowdata);
+
+ return 1;
+}
+
+
+
+/* save_rgba:
+ * Core save routine for 32 bpp images.
+ */
+static int save_rgba(png_structp png_ptr, BITMAP *bmp)
+{
+ unsigned char *rowdata;
+ int x, y;
+
+ ASSERT(bitmap_color_depth(bmp) == 32);
+
+ rowdata = (unsigned char *)malloc(bmp->w * 4);
+ if (!rowdata)
+ return 0;
+
+ for (y=0; y<bmp->h; y++) {
+ unsigned char *p = rowdata;
+
+ for (x=0; x<bmp->w; x++) {
+ int c = getpixel(bmp, x, y);
+ *p++ = getr32(c);
+ *p++ = getg32(c);
+ *p++ = getb32(c);
+ *p++ = geta32(c);
+ }
+
+ png_write_row(png_ptr, rowdata);
+ }
+
+ free(rowdata);
+
+ return 1;
+}
+
+
+
+/* save_png:
+ * Writes a non-interlaced, no-frills PNG, taking the usual save_xyz
+ * parameters. Returns non-zero on error.
+ */
+static int really_save_png(PACKFILE *fp, BITMAP *bmp, AL_CONST RGB *pal)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int depth;
+ int colour_type;
+
+ depth = bitmap_color_depth(bmp);
+ if (depth == 8 && !pal)
+ return -1;
+
+ /* Create and initialize the png_struct with the
+ * desired error handler functions.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ (void *)NULL, NULL, NULL);
+ if (!png_ptr)
+ goto Error;
+
+ /* Allocate/initialize the image information data. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ goto Error;
+
+ /* Set error handling. */
+ if (setjmp(png_ptr->jmpbuf)) {
+ /* If we get here, we had a problem reading the file. */
+ goto Error;
+ }
+
+ /* Use packfile routines. */
+ png_set_write_fn(png_ptr, fp, (png_rw_ptr)write_data, flush_data);
+
+ /* 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.
+ */
+ if (depth == 8)
+ colour_type = PNG_COLOR_TYPE_PALETTE;
+ else if (depth == 32)
+ colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else
+ colour_type = PNG_COLOR_TYPE_RGB;
+
+ /* Set compression level. */
+ png_set_compression_level(png_ptr, _png_compression_level);
+
+ png_set_IHDR(png_ptr, info_ptr, bmp->w, bmp->h, 8, colour_type,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
+ PNG_FILTER_TYPE_BASE);
+
+ /* Set the palette if there is one. Required for indexed-color images. */
+ if (colour_type == PNG_COLOR_TYPE_PALETTE) {
+ png_color palette[256];
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ palette[i].red = _rgb_scale_6[pal[i].r]; /* 64 -> 256 */
+ palette[i].green = _rgb_scale_6[pal[i].g];
+ palette[i].blue = _rgb_scale_6[pal[i].b];
+ }
+
+ /* Set palette colors. */
+ png_set_PLTE(png_ptr, info_ptr, palette, 256);
+ }
+
+ /* Optionally write comments into the image ... Nah. */
+
+ /* Write the file header information. */
+ png_write_info(png_ptr, info_ptr);
+
+ /* Once we write out the header, the compression type on the text
+ * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+ * at the end.
+ */
+
+ /* Save the data. */
+ switch (depth) {
+ case 8:
+ if (!save_indexed(png_ptr, bmp))
+ goto Error;
+ break;
+ case 15:
+ case 16:
+ case 24:
+ if (!save_rgb(png_ptr, bmp))
+ goto Error;
+ break;
+ case 32:
+ if (!save_rgba(png_ptr, bmp))
+ goto Error;
+ break;
+ default:
+ ASSERT(FALSE);
+ goto Error;
+ }
+
+ png_write_end(png_ptr, info_ptr);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ return 0;
+
+ Error:
+
+ if (png_ptr) {
+ if (info_ptr)
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ else
+ png_destroy_write_struct(&png_ptr, NULL);
+ }
+
+ return -1;
+}
+
+
+int save_png(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal)
+{
+ PACKFILE *fp;
+ int result;
+
+ ASSERT(filename);
+ ASSERT(bmp);
+
+ fp = pack_fopen(filename, "w");
+ if (!fp)
+ return -1;
+
+ acquire_bitmap(bmp);
+ result = really_save_png(fp, bmp, pal);
+ release_bitmap(bmp);
+
+ pack_fclose(fp);
+
+ return result;
+}
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 12:01 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68938
Default Alt Text
(22 KB)

Event Timeline