GP2X Using Libpng


Still Fresh
Sep 19, 2005
Gothenburg, Sweden

I have been trying to get a function that loads PNG files working tonight, to use with rlyeh's minilib, but without much success... bbull found me a nice snipped that was coded for GP32,, even though it was ment to be used with Mr.Mirko's SDK it should be fixable.

But the problem is that it doesn't seem that to include libpng or something, here's what I get:
C:\devkitGP2X\vid_test_01>arm-linux-gcc minimal.c png_loader.c main.c -static -l
png_loader.c: In function 'gp_canvasCreateFromPngBuf':
png_loader.c:139: warning: incompatible implicit declaration of built-in functio
n 'malloc'
png_loader.c: In function 'gp_canvasCreateFromPng':
png_loader.c:210: warning: assignment from incompatible pointer type
png_loader.c:218: warning: incompatible implicit declaration of built-in functio
n 'malloc'
png_loader.c:219: warning: passing argument 4 of 'fread' from incompatible point
er type
png_loader.c:222: warning: passing argument 1 of 'fclose' from incompatible poin
ter type
C:\DOCUME~1\work\LOKALA~1\Temp/ccukcaaa.o: In function `pngReadBufferFunc':
png_loader.c:(.text+0x20): undefined reference to `png_get_io_ptr'
C:\DOCUME~1\work\LOKALA~1\Temp/ccukcaaa.o: In function `gp_canvasCreateFromPngBuf':
png_loader.c:(.text+0xd0): undefined reference to `png_create_read_struct'
png_loader.c:(.text+0x100): undefined reference to `png_create_info_struct'
png_loader.c:(.text+0x114): undefined reference to `png_create_info_struct'
png_loader.c:(.text+0x134): undefined reference to `png_set_read_fn'
png_loader.c:(.text+0x14c): undefined reference to `png_read_info'
png_loader.c:(.text+0x19c): undefined reference to `png_get_IHDR'
png_loader.c:(.text+0x1b8): undefined reference to `png_get_gAMA'
png_loader.c:(.text+0x204): undefined reference to `png_set_gamma'
png_loader.c:(.text+0x228): undefined reference to `png_set_gamma'
png_loader.c:(.text+0x240): undefined reference to `png_read_update_info'
png_loader.c:(.text+0x24c): undefined reference to `png_set_expand'
png_loader.c:(.text+0x258): undefined reference to `png_set_gray_to_rgb'
png_loader.c:(.text+0x270): undefined reference to `png_get_rowbytes'
png_loader.c:(.text+0x32c): undefined reference to `png_read_image'
png_loader.c:(.text+0x3a4): undefined reference to `gp_colorRGB24to16'
png_loader.c:(.text+0x544): undefined reference to `gp_colorRGB24to16'
png_loader.c:(.text+0x69c): undefined reference to `png_read_end'
png_loader.c:(.text+0x6c0): undefined reference to `png_destroy_read_struct'
C:\DOCUME~1\work\LOKALA~1\Temp/ccukcaaa.o: In function `exitClean.3928':
png_loader.c:(.text+0x728): undefined reference to `png_destroy_read_struct'
png_loader.c:(.text+0x734): undefined reference to `gp_canvasFree'
C:\DOCUME~1\work\LOKALA~1\Temp/ccukcaaa.o: In function `gp_canvasCreateFromPng':

png_loader.c:(.text+0x79c): undefined reference to `smc_filesize'

And my current code (png_loader.c):
 * PNG loader library for GP32
 * by PEA (
 * ---
 * based on a stripped down version of:
 * PNG loader library for OpenGL v1.45 (10/07/00)
 * by Ben Wyatt
 * Using LibPNG 1.0.2 and ZLib 1.1.3
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the author be held liable for any damages arising from the
 * use of this software.
 * Permission is hereby granted to use, copy, modify, and distribute this
 * source code, or portions hereof, for any purpose, without fee, subject to
 * the following restrictions:
 * 1. The origin of this source code must not be misrepresented. You must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered versions must be plainly marked as such and must not be
 *    misrepresented as being the original source.
 * 3. This notice must not be removed or altered from any source distribution.
 * ---
 * 2005/01/22 - Remove unneeded functions, includes and GL references
 *              and format for use with Mr.Mirko SDK. 

//#include <gp32.h>
#include "C:/devkitGP2X/include/png.h"

// screenGamma = displayGamma/viewingGamma
// displayGamma = CRT has gamma of ~2.2
// viewingGamma depends on platform. 
// PC is 1.0, 
// Mac is 1.45, 
// SGI defaults to 1.7
static double screenGamma = 2.2 / 1.0;
static char gammaExplicit = 0;

typedef struct tGP_pngFileBuffer{
	unsigned char *buffer;
	int pos;
} tGP_pngFileBuffer;

typedef struct {
  char path[256];
  char mode;
  unsigned int pos;
  unsigned int size;
  char *wbuffer;

typedef struct tGP_canvas{
unsigned short width;
unsigned short height;
unsigned short *data;
unsigned char *mask;
unsigned char frames;

void pngReadBufferFunc(png_struct *png, png_bytep buf, png_size_t size){
	tGP_pngFileBuffer *pngFileBuffer=(tGP_pngFileBuffer*)png_get_io_ptr(png);

tGP_canvas* gp_canvasCreateFromPngBuf( unsigned char *pngdata, char rotate90, unsigned char frames, int *outError ){
	unsigned char header[8];
	png_structp png;
	png_infop   info;
	png_infop   endinfo;
	png_bytep   data;
  png_bytep  *row_p;
  double	fileGamma;
	unsigned long width, height;
	int depth, color;
	unsigned long i, x, y;
	unsigned long rowbytes, channels, pcount;
	tGP_pngFileBuffer pngFileBuffer;
	tGP_canvas *canvas = NULL;
	unsigned short *pdata;
	unsigned char *praw;
	unsigned char *pmask;
	int res;
	void exitClean( void ){
  png_destroy_read_struct(&png, &info, &endinfo);
  gp_canvasFree( canvas );
	// Init the file buffer
	pngFileBuffer.pos = 0;
	pngFileBuffer.buffer = pngdata;

	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (*outError){
  return NULL;	
	info = png_create_info_struct(png);
	endinfo = png_create_info_struct(png);

	// Set a custom read function, and read/process all PNG data up
	// until the IDAT (image data) chunk.
	png_read_info(png, info);

	// Get the image data 
	png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
	// Create the canvas
	//if (frames<1){ frames=1; }
	//canvas = gp_canvasCreate( height, width, frames, GPC_BLACK );

	// Gamma correction. See if file contains gamma info and use that
	// or else use user defined value.
	if (png_get_gAMA(png, info, &fileGamma) && (!gammaExplicit))
  png_set_gamma(png, screenGamma, fileGamma);
  png_set_gamma(png, screenGamma, 1.0/2.2);
	// Update the 'info' struct with the new gamma information
	png_read_update_info(png, info);
	// Set expand function to expand paletted images, gray scale images, and
	// palletted alpha channels to full channels
	// Set strip function to reduce 16bpp down to 8bpp if applicable 
	// Set function to convert grayscale (single channel) image to full RGB channels

	// Allocate a row of pointers to store the image data
	rowbytes = png_get_rowbytes(png, info);
	//channels = png_get_channels(png, info);
	channels = rowbytes/width;
	data = (png_bytep)malloc(rowbytes*height);
	row_p = (png_bytep*)malloc(sizeof(png_bytep)*height);
	for (i=0; i<height; i++){ row_p[i] = data+i*rowbytes; }

	// Read the image data
	png_read_image(png, row_p);
	// Copy image data to the canvas
	pcount = width*height;
	if (!rotate90){
  // Copy image as-is
  pdata = canvas->data;
  praw = data;
  for (i=0; i<pcount; i++){
  	*pdata = gp_colorRGB24to16( *praw, *(praw+1), *(praw+2) );
  	praw += channels; pdata++;
  // Create alpha mask if required
  if (channels==4){ 
  	canvas->mask=(unsigned char*)malloc( pcount ); 
  	praw = data+3;
  	pmask = canvas->mask;
  	for (i=0; i<pcount; i++){
    *pmask = (*praw)>>3;
    praw += channels; pmask++;
  canvas->width = width;
  canvas->height = height;
  // Copy image with rotation
  pdata = canvas->data;
  for(x=0; x<width; x++){
  	for(y=0; y<height; y++){
    praw = data + ((height-y-1)*width+x)*channels;
    *pdata = gp_colorRGB24to16( *praw, *(praw+1), *(praw+2) );
  // Create alpha mask if required
  if (channels==4){ 
  	canvas->mask=(unsigned char*)malloc( pcount ); 
  	pmask = canvas->mask;
  	for(x=0; x<width; x++){
    for(y=0; y<height; y++){
    	praw = data + ((height-y-1)*width+x)*channels + 3;
    	*pmask = (*praw)>>3;
	// Destroy raw image
	free( data );

	// Check the rest of the image for additional tags
  png_read_end(png, endinfo);
  // Clean up and return the canvas
	png_destroy_read_struct(&png, &info, &endinfo);
	return canvas;
tGP_canvas* gp_canvasCreateFromPng( char *filename, char rotate90, unsigned char frames, int *outError ){
	int pngsize, readsize;
	GPFILE *pngfile;
	unsigned char *file;
	tGP_canvas *canvas;

	// Attempt to open the file in read mode. Return error on fail
	pngfile = fopen(filename,"r");
	if (pngfile==NULL){
  return NULL;

	// Get the raw PNG filesize, allocate memory for it, and load the file
	pngsize = smc_filesize( pngfile );
	file = (unsigned char *)malloc( pngsize );
	readsize = fread( (void *)file, pngsize, 1, pngfile );
	// Close the file

	// If the full PNG wasn't read properly, return error
  free( file );
  return NULL;
	// Read PNG
	canvas = gp_canvasCreateFromPngBuf( file, rotate90, frames, outError );
	// Free file and return canvas
	free( file );
	return canvas;

void gp_canvasSetPngGamma(double viewingGamma) {
	if(viewingGamma > 0){
  gammaExplicit = 1;
  screenGamma = 2.2/viewingGamma;
	}else {
  gammaExplicit = 0;
  screenGamma = 2.2;

Does anyone know what I could be doing wrong? And has anyone else got libpng working (I heard there was some problems with SDL_image, which is also using libpng)? Or do someone else have any sweet PNG loading function that they would want to share?
The error message means that the linker does not know where to find the library, so you need to add -lpng. Also, using a Makefile would make thing a lot easier.