Added support to load png files through Allegro library (now you can save/load palettes in PNG files)

This commit is contained in:
David Capello 2009-11-19 00:34:07 +00:00
parent 0e0dacb158
commit 33ca3cf8e0
13 changed files with 1137 additions and 14 deletions

View File

@ -6,12 +6,13 @@ _default: default
###################################################################### ######################################################################
# Setup CFLAGS and LFLAGS for GCC # Setup CFLAGS and LFLAGS for GCC
CFLAGS += -Wall -I. -Isrc -Ithird_party \ CFLAGS += -Wall -I. -Isrc -Ithird_party \
-I$(LIBFREETYPE_DIR)/include \ -I$(LIBFREETYPE_DIR)/include \
-I$(LIBJPEG_DIR) \ -I$(LIBJPEG_DIR) \
-I$(LIBPNG_DIR) \ -I$(LIBPNG_DIR) \
-I$(ZLIB_DIR) \ -I$(ZLIB_DIR) \
-Wno-deprecated-declarations \ -I$(LOADPNG_DIR) \
-Wno-deprecated-declarations \
-DPNG_NO_MMX_CODE -DPNG_NO_MMX_CODE
LFLAGS += $(THIRD_PARTY_LIBS) LFLAGS += $(THIRD_PARTY_LIBS)
@ -76,6 +77,10 @@ $(ZLIB_LIB): $(ZLIB_OBJS)
-rm -f $@ -rm -f $@
ar rs $@ $^ ar rs $@ $^
$(LOADPNG_LIB): $(LOADPNG_OBJS)
-rm -f $@
ar rs $@ $^
###################################################################### ######################################################################
# Rules to build objects and the application # Rules to build objects and the application
@ -118,7 +123,8 @@ VPATH = src \
$(LIBGD_DIR) \ $(LIBGD_DIR) \
$(LIBJPEG_DIR) \ $(LIBJPEG_DIR) \
$(LIBPNG_DIR) \ $(LIBPNG_DIR) \
$(ZLIB_DIR) $(ZLIB_DIR) \
$(LOADPNG_DIR)
ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS) ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS)
@ -149,6 +155,9 @@ $(OBJ_DIR)/png.%$(OBJ): %.c
$(OBJ_DIR)/zlib.%$(OBJ): %.c $(OBJ_DIR)/zlib.%$(OBJ): %.c
$(CC) $(CFLAGS) -o $@ -c $< $(CC) $(CFLAGS) -o $@ -c $<
$(OBJ_DIR)/loadpng.%$(OBJ): %.c
$(CC) $(CFLAGS) -o $@ -c $<
###################################################################### ######################################################################
# Application # Application

View File

@ -466,6 +466,20 @@ ZLIB_OBJS = $(addprefix $(OBJ_DIR)/zlib., \
$(addsuffix $(OBJ), \ $(addsuffix $(OBJ), \
$(notdir $(basename $(ZLIB_SOURCES))))) $(notdir $(basename $(ZLIB_SOURCES)))))
######################################################################
# loadpng
LOADPNG_LIB = $(OBJ_DIR)/libloadpng$(LIB_EXT)
LOADPNG_DIR = third_party/loadpng
LOADPNG_SOURCES = \
$(LOADPNG_DIR)/loadpng.c \
$(LOADPNG_DIR)/savepng.c \
$(LOADPNG_DIR)/regpng.c
LOADPNG_OBJS = $(addprefix $(OBJ_DIR)/loadpng., \
$(addsuffix $(OBJ), \
$(notdir $(basename $(LOADPNG_SOURCES)))))
###################################################################### ######################################################################
# All objects and libraries # All objects and libraries
@ -475,14 +489,16 @@ ALL_OBJS = \
$(LIBART_OBJS) \ $(LIBART_OBJS) \
$(LIBJPEG_OBJS) \ $(LIBJPEG_OBJS) \
$(LIBPNG_OBJS) \ $(LIBPNG_OBJS) \
$(ZLIB_OBJS) $(ZLIB_OBJS) \
$(LOADPNG_OBJS)
THIRD_PARTY_LIBS = \ THIRD_PARTY_LIBS = \
$(LIBART_LIB) \ $(LIBART_LIB) \
$(LIBFREETYPE_LIB) \ $(LIBFREETYPE_LIB) \
$(LIBJPEG_LIB) \ $(LIBJPEG_LIB) \
$(LIBPNG_LIB) \ $(LIBPNG_LIB) \
$(ZLIB_LIB) $(ZLIB_LIB) \
$(LOADPNG_LIB)
###################################################################### ######################################################################
# Tests # Tests

View File

@ -29,6 +29,7 @@ CFLAGS = -nologo \
-I$(LIBJPEG_DIR) \ -I$(LIBJPEG_DIR) \
-I$(LIBPNG_DIR) \ -I$(LIBPNG_DIR) \
-I$(ZLIB_DIR) \ -I$(ZLIB_DIR) \
-I$(LOADPNG_DIR) \
-DPNG_NO_MMX_CODE -DPNG_NO_MMX_CODE
LFLAGS = -NOLOGO -SUBSYSTEM:WINDOWS -MACHINE:X86 LFLAGS = -NOLOGO -SUBSYSTEM:WINDOWS -MACHINE:X86
@ -111,6 +112,10 @@ $(ZLIB_LIB): $(ZLIB_OBJS)
-rm -f $@ -rm -f $@
lib -NOLOGO -OUT:$@ $^ lib -NOLOGO -OUT:$@ $^
$(LOADPNG_LIB): $(LOADPNG_OBJS)
-rm -f $@
lib -NOLOGO -OUT:$@ $^
###################################################################### ######################################################################
# Rules to build objects and the application # Rules to build objects and the application
@ -153,7 +158,8 @@ VPATH = src \
$(LIBGD_DIR) \ $(LIBGD_DIR) \
$(LIBJPEG_DIR) \ $(LIBJPEG_DIR) \
$(LIBPNG_DIR) \ $(LIBPNG_DIR) \
$(ZLIB_DIR) $(ZLIB_DIR) \
$(LOADPNG_DIR)
ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS) ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS)
@ -181,6 +187,9 @@ $(OBJ_DIR)/png.%$(OBJ): %.c
$(OBJ_DIR)/zlib.%$(OBJ): %.c $(OBJ_DIR)/zlib.%$(OBJ): %.c
$(CC) $(CFLAGS) -Fo$@ -c $< $(CC) $(CFLAGS) -Fo$@ -c $<
$(OBJ_DIR)/loadpng.%$(OBJ): %.c
$(CC) $(CFLAGS) -Fo$@ -c $<
###################################################################### ######################################################################
# Application # Application

View File

@ -305,7 +305,7 @@ static void select_all_command(JWidget widget)
static void load_command(JWidget widget) static void load_command(JWidget widget)
{ {
Palette *palette; Palette *palette;
jstring filename = ase_file_selector(_("Load Palette"), "", "pcx,bmp,tga,lbm,col"); jstring filename = ase_file_selector(_("Load Palette"), "", "png,pcx,bmp,tga,lbm,col");
if (!filename.empty()) { if (!filename.empty()) {
palette = palette_load(filename.c_str()); palette = palette_load(filename.c_str());
if (!palette) { if (!palette) {
@ -324,7 +324,7 @@ static void save_command(JWidget widget)
int ret; int ret;
again: again:
filename = ase_file_selector(_("Save Palette"), "", "pcx,bmp,tga,col"); filename = ase_file_selector(_("Save Palette"), "", "png,pcx,bmp,tga,col");
if (!filename.empty()) { if (!filename.empty()) {
if (exists(filename.c_str())) { if (exists(filename.c_str())) {
ret = jalert("%s<<%s<<%s||%s", ret = jalert("%s<<%s<<%s||%s",

View File

@ -23,6 +23,7 @@
#include "ase_exception.h" #include "ase_exception.h"
#include "core/app.h" #include "core/app.h"
#include "loadpng.h"
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Information for "ident". // Information for "ident".
@ -40,6 +41,9 @@ public:
allegro_init(); allegro_init();
set_uformat(U_ASCII); set_uformat(U_ASCII);
install_timer(); install_timer();
// Register PNG as a supported bitmap type
register_bitmap_file_type("png", load_png, save_png);
} }
~Allegro() { ~Allegro() {
remove_timer(); remove_timer();

View File

@ -311,7 +311,8 @@ Palette* palette_load(const char *filename)
ustrcpy(ext, get_extension(filename)); ustrcpy(ext, get_extension(filename));
if ((ustricmp(ext, "pcx") == 0) || if ((ustricmp(ext, "png") == 0) ||
(ustricmp(ext, "pcx") == 0) ||
(ustricmp(ext, "bmp") == 0) || (ustricmp(ext, "bmp") == 0) ||
(ustricmp(ext, "tga") == 0) || (ustricmp(ext, "tga") == 0) ||
(ustricmp(ext, "lbm") == 0)) { (ustricmp(ext, "lbm") == 0)) {
@ -340,7 +341,8 @@ bool palette_save(Palette* pal, const char *filename)
ustrcpy(ext, get_extension(filename)); ustrcpy(ext, get_extension(filename));
if ((ustricmp(ext, "pcx") == 0) || if ((ustricmp(ext, "png") == 0) ||
(ustricmp(ext, "pcx") == 0) ||
(ustricmp(ext, "bmp") == 0) || (ustricmp(ext, "bmp") == 0) ||
(ustricmp(ext, "tga") == 0)) { (ustricmp(ext, "tga") == 0)) {
PALETTE rgbpal; PALETTE rgbpal;

165
third_party/loadpng/CHANGES.txt vendored Normal file
View File

@ -0,0 +1,165 @@
------- April 1999 -------
?? Wrote load_png wrapper
??+1 Cleaned up a bit, tried getting grayscale and
auto-MagicPink conversion working.
9 Now can read gamma from environment variable.
Changed default gamma to 2.2.
13 Added save_png, using pieces from allpng.c
15 Fixed stupid bug I created in save_hicolour.
Added copyright notice.
Now uses packfile routines.
Added #ifdef __cplusplus hack.
Released: version 0.1.
------- December 1999 -------
22 Updated to work with Allegro 3.9.xx.
Fixed alpha channel support.
Added alpha.c
test.c renamed to example.c
Released: version 0.2
------- January 1999 -------
3 Applied fix for < 8 bpp images (thanks to Dave Dribin)
Released: version 0.3
------- October 2000 -------
12 Updated const-correctness in accordance with Allegro.
Released: version 0.4
------- April 2001 -------
11 "Fixed" RGB/BGR problem with loading RGBA images.
Use GFX_AUTODETECT in examples (GFX_SAFE changed in Allegro).
Released: version 0.5
------- July 2001 -------
13 Reverted to 0.4 codebase, as 0.5 was really broken (oops).
Added "depth" argument to examples.
Commented out the BGR flipping code, which was incorrect I think
anyway. Someone with a BGR card should check it out.
Released: version 0.6
------- January 2002 -------
03 allegro/aintern.h -> allegro/internal/aintern.h (Allegro 4.0)
Released: version 0.7
------- February 2002 -------
25 Fixed a problem with passing NULL for pal to load_png.
Released: version 0.8
------- March 2002 -------
30 Tentative fixes for loading/saving RGBA images.
Thanks to Chris Graham for reporting the problem.
Minor changes to examples and makefile.
------- May 2002 -------
06 Added shared library (unix) and install support into makefiles,
and cleaned them up. Thanks to Robbert Haarman for the start.
Minor changes for -W warnings.
07 Dave Dribin fixed a problem that surfaced with some buggy versions
of libpng (1.0.13, 1.2.2).
Moved the thanks section into a separate document.
08 Fixed a puny mistake in the makefile.
12 Released: version 0.9
16 Tentative fixes for sometimes-problems loading RGB images.
19 Released: version 0.10
------- September 2002 -------
03 Dave Dribin fixed two problems with images with alpha channels.
04 Released: version 0.11
------- April 2003 -------
27 Mostly incorporated Ceniza's changes (load_memory_png and loading
from datafile support, plus an example).
28 Reworked those changes a little.
------- May 2003 -------
02 Miscellaneous changes; put examples into separate directory
(now that we have three!).
04 Signal errors on read/write failure.
Released: version 1.0.
20 Calling load_png with NULL for palette argument was not converting
paletted images to high/truecolour properly. Fixed. Thanks to
Lothar May for pointing it out.
Released: version 1.1.
------- October 2003 -------
13 Changed the method of scaling of palette values from 6 bits
to 8 bits. Instead of just multiplying by 4, now we use
_rgb_scale_6[] so that e.g. 0 -> 0, but 63 -> 255.
Thanks Nicolas Lemal for the idea.
Released: version 1.2.
16 MSVC doesn't like pointer arithmetic on void*'s, pointed out by
Chris Condrat.
Re-released: version 1.2 (I forgot to update version constants anyway).
------- April 2004 -------
26 Jon Rafkind suggested to use _getpixel*/_putpixel* in loader to
speed up loading of large images.
Split up the code into three files. This prevents the linker pulling
in unused code, e.g. many people don't need save_png.
28 It turns out that loadpng's origin (example.c from libpng docs) was in
the public domain, so now loadpng is in the public domain as well.
Released: version 1.3.
------- October 2004 -------
09 Made save_png handle non-memory bitmaps as well.
10 Fixed some bugs with load_png(). Now everything in PngSuite loads
properly, and with correct gamma correction, except for:
- bKGD chunks (solid background colours) are not respected.
I chose this in the past, but I wonder if I should change it?
- pHYs chunks (physical dimensions) are not respected.
(BTW, this was all tested with Valgrind - no errors)
_png_screen_gamma can now be 0.0 to disable gamma correction, i.e. if
you don't know the screen gamma, it might be best not to guess.
Got rid of inefficient BGR-handling hack and did things properly.
New example: browse.c (for mass testing, e.g. PngSuite)
Released: version 1.4pre1.
------- August 2005 -------
18 Emmanuel Anne made _png_compression_level actually work.
Released: version 1.4.
------- April 2006 -------
9 Fix an endianness on big-endian machines, from Siarhei Siamashka.
I haven't tested it.
Released: version 1.5.

53
third_party/loadpng/README.txt vendored Normal file
View File

@ -0,0 +1,53 @@
loadpng: glue for Allegro and libpng
This wrapper is mostly a copy and paste job from example.c in the
libpng docs, stripping out the useless transformations and making it
use Allegro BITMAP and PALETTE structures. It is placed in the public
domain.
Requirements:
Allegro http://alleg.sourceforge.net/
libpng http://www.libpng.org/pub/png/
zlib http://www.gzip.org/zlib/
Usage:
See loadpng.h for functions and their descriptions. There is a
simple example program called example.c, a program demonstrating
alpha translucency in exalpha.c, and a program demonstrating how to
load a PNG object from a datafile in exdata.c.
To compile, just run "make" (or perhaps "mingw32-make"). To use
loadpng, you need to link with libpng, zlib in addition to loadpng
itself, e.g.
gcc mygame.c -lldpng -lpng -lz -lalleg
I recommend you copy loadpng's files into your own project's directory
and compile loadpng as part of your project.
Notes:
- Grayscale images will be loaded in as 24 bit images, or 32 bit
images if they contain an alpha channel. These will then be
converted as usual, according to Allegro's conversion semantics. Be
aware of this if you have disabled automatic colour depth
conversion.
- save_png() doesn't save any gamma chunk. I'm thinking of making it
write an sRGB chunk by default. If you want tight control of how
your images are saved, I recommend hacking save_png() to suit your
needs. There's simply too many options.
Enjoy!
Peter Wang (tjaden@users.sf.net)
http://members.ozadsl.com.au/~tjaden/
http://tjaden.strangesoft.net/

16
third_party/loadpng/THANKS.txt vendored Normal file
View File

@ -0,0 +1,16 @@
Peter Wang is me.
Thanks to Martijn Versteegh for allpng.c, from which I took the actual
routine which saves 15 / 16 bpp images.
The following people reported or fixed bugs or did something else
(assuming I didn't forget):
- Dave Dribin
- Lennart Steinke
- Chris Graham
- Robbert Haarman
- Ceniza
- Nicolas Lemal
- Jon Rafkind
- Emmanuel Anne

400
third_party/loadpng/loadpng.c vendored Normal file
View File

@ -0,0 +1,400 @@
/* 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;
}

75
third_party/loadpng/loadpng.h vendored Normal file
View File

@ -0,0 +1,75 @@
/* 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 */

68
third_party/loadpng/regpng.c vendored Normal file
View File

@ -0,0 +1,68 @@
/* 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;
}

306
third_party/loadpng/savepng.c vendored Normal file
View File

@ -0,0 +1,306 @@
/* 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;
}