mirror of https://github.com/aseprite/aseprite.git
				
				
				
			Added support to load png files through Allegro library (now you can save/load palettes in PNG files)
This commit is contained in:
		
							parent
							
								
									0e0dacb158
								
							
						
					
					
						commit
						33ca3cf8e0
					
				
							
								
								
									
										23
									
								
								makefile.gcc
								
								
								
								
							
							
						
						
									
										23
									
								
								makefile.gcc
								
								
								
								
							| 
						 | 
				
			
			@ -6,12 +6,13 @@ _default: default
 | 
			
		|||
######################################################################
 | 
			
		||||
# Setup CFLAGS and LFLAGS for GCC
 | 
			
		||||
 | 
			
		||||
CFLAGS += -Wall -I. -Isrc -Ithird_party \
 | 
			
		||||
	  -I$(LIBFREETYPE_DIR)/include \
 | 
			
		||||
	  -I$(LIBJPEG_DIR) \
 | 
			
		||||
	  -I$(LIBPNG_DIR) \
 | 
			
		||||
	  -I$(ZLIB_DIR) \
 | 
			
		||||
	  -Wno-deprecated-declarations \
 | 
			
		||||
CFLAGS += -Wall -I. -Isrc -Ithird_party		\
 | 
			
		||||
	  -I$(LIBFREETYPE_DIR)/include		\
 | 
			
		||||
	  -I$(LIBJPEG_DIR)			\
 | 
			
		||||
	  -I$(LIBPNG_DIR)			\
 | 
			
		||||
	  -I$(ZLIB_DIR)				\
 | 
			
		||||
	  -I$(LOADPNG_DIR)			\
 | 
			
		||||
	  -Wno-deprecated-declarations		\
 | 
			
		||||
	  -DPNG_NO_MMX_CODE
 | 
			
		||||
 | 
			
		||||
LFLAGS += $(THIRD_PARTY_LIBS)
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +77,10 @@ $(ZLIB_LIB): $(ZLIB_OBJS)
 | 
			
		|||
	-rm -f $@
 | 
			
		||||
	ar rs $@ $^
 | 
			
		||||
 | 
			
		||||
$(LOADPNG_LIB): $(LOADPNG_OBJS)
 | 
			
		||||
	-rm -f $@
 | 
			
		||||
	ar rs $@ $^
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Rules to build objects and the application
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +123,8 @@ VPATH = src					\
 | 
			
		|||
	$(LIBGD_DIR)				\
 | 
			
		||||
	$(LIBJPEG_DIR)				\
 | 
			
		||||
	$(LIBPNG_DIR)				\
 | 
			
		||||
	$(ZLIB_DIR)
 | 
			
		||||
	$(ZLIB_DIR)				\
 | 
			
		||||
	$(LOADPNG_DIR)
 | 
			
		||||
 | 
			
		||||
ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,6 +155,9 @@ $(OBJ_DIR)/png.%$(OBJ): %.c
 | 
			
		|||
$(OBJ_DIR)/zlib.%$(OBJ): %.c
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR)/loadpng.%$(OBJ): %.c
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Application
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								makefile.lst
								
								
								
								
							
							
						
						
									
										20
									
								
								makefile.lst
								
								
								
								
							| 
						 | 
				
			
			@ -466,6 +466,20 @@ ZLIB_OBJS = $(addprefix $(OBJ_DIR)/zlib.,		\
 | 
			
		|||
	      $(addsuffix $(OBJ),			\
 | 
			
		||||
		$(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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -475,14 +489,16 @@ ALL_OBJS =					\
 | 
			
		|||
	$(LIBART_OBJS)				\
 | 
			
		||||
	$(LIBJPEG_OBJS)				\
 | 
			
		||||
	$(LIBPNG_OBJS)				\
 | 
			
		||||
	$(ZLIB_OBJS)
 | 
			
		||||
	$(ZLIB_OBJS)				\
 | 
			
		||||
	$(LOADPNG_OBJS)
 | 
			
		||||
 | 
			
		||||
THIRD_PARTY_LIBS =				\
 | 
			
		||||
	$(LIBART_LIB)				\
 | 
			
		||||
	$(LIBFREETYPE_LIB)			\
 | 
			
		||||
	$(LIBJPEG_LIB)				\
 | 
			
		||||
	$(LIBPNG_LIB)				\
 | 
			
		||||
	$(ZLIB_LIB)
 | 
			
		||||
	$(ZLIB_LIB)				\
 | 
			
		||||
	$(LOADPNG_LIB)
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Tests
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								makefile.vc
								
								
								
								
							
							
						
						
									
										11
									
								
								makefile.vc
								
								
								
								
							| 
						 | 
				
			
			@ -29,6 +29,7 @@ CFLAGS = -nologo						\
 | 
			
		|||
	 -I$(LIBJPEG_DIR)					\
 | 
			
		||||
	 -I$(LIBPNG_DIR)					\
 | 
			
		||||
	 -I$(ZLIB_DIR)						\
 | 
			
		||||
	 -I$(LOADPNG_DIR)					\
 | 
			
		||||
	 -DPNG_NO_MMX_CODE
 | 
			
		||||
 | 
			
		||||
LFLAGS = -NOLOGO -SUBSYSTEM:WINDOWS -MACHINE:X86
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +112,10 @@ $(ZLIB_LIB): $(ZLIB_OBJS)
 | 
			
		|||
	-rm -f $@
 | 
			
		||||
	lib -NOLOGO -OUT:$@ $^
 | 
			
		||||
 | 
			
		||||
$(LOADPNG_LIB): $(LOADPNG_OBJS)
 | 
			
		||||
	-rm -f $@
 | 
			
		||||
	lib -NOLOGO -OUT:$@ $^
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Rules to build objects and the application
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +158,8 @@ VPATH = src					\
 | 
			
		|||
	$(LIBGD_DIR)				\
 | 
			
		||||
	$(LIBJPEG_DIR)				\
 | 
			
		||||
	$(LIBPNG_DIR)				\
 | 
			
		||||
	$(ZLIB_DIR)
 | 
			
		||||
	$(ZLIB_DIR)				\
 | 
			
		||||
	$(LOADPNG_DIR)
 | 
			
		||||
 | 
			
		||||
ASE_DEPS = $(ASE_OBJS) $(THIRD_PARTY_LIBS)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +187,9 @@ $(OBJ_DIR)/png.%$(OBJ): %.c
 | 
			
		|||
$(OBJ_DIR)/zlib.%$(OBJ): %.c
 | 
			
		||||
	$(CC) $(CFLAGS) -Fo$@ -c $<
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR)/loadpng.%$(OBJ): %.c
 | 
			
		||||
	$(CC) $(CFLAGS) -Fo$@ -c $<
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Application
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -305,7 +305,7 @@ static void select_all_command(JWidget widget)
 | 
			
		|||
static void load_command(JWidget widget)
 | 
			
		||||
{
 | 
			
		||||
  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()) {
 | 
			
		||||
    palette = palette_load(filename.c_str());
 | 
			
		||||
    if (!palette) {
 | 
			
		||||
| 
						 | 
				
			
			@ -324,7 +324,7 @@ static void save_command(JWidget widget)
 | 
			
		|||
  int ret;
 | 
			
		||||
 | 
			
		||||
 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 (exists(filename.c_str())) {
 | 
			
		||||
      ret = jalert("%s<<%s<<%s||%s",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
 | 
			
		||||
#include "ase_exception.h"
 | 
			
		||||
#include "core/app.h"
 | 
			
		||||
#include "loadpng.h"
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Information for "ident".
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,9 @@ public:
 | 
			
		|||
    allegro_init();
 | 
			
		||||
    set_uformat(U_ASCII);
 | 
			
		||||
    install_timer();
 | 
			
		||||
 | 
			
		||||
    // Register PNG as a supported bitmap type
 | 
			
		||||
    register_bitmap_file_type("png", load_png, save_png);
 | 
			
		||||
  }
 | 
			
		||||
  ~Allegro() {
 | 
			
		||||
    remove_timer();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -311,7 +311,8 @@ Palette* palette_load(const char *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, "tga") == 0) ||
 | 
			
		||||
      (ustricmp(ext, "lbm") == 0)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +341,8 @@ bool palette_save(Palette* pal, const char *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, "tga") == 0)) {
 | 
			
		||||
    PALETTE rgbpal;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			@ -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/
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue