GP32 PNG Decoding Woes...


Toris

Certified Guru
Joined
Apr 6, 2003
Messages
82
I know I've already asked this on the Yahoo dev list, but, I thought there might be some people here who can help who aren't subscribed to the list :) - What can I say? I'm desperate :p

Anyway, following is some code that is meant to decode a PNG, the problem is, is returns with a Z_BUF_ERROR when I try to uncompress the data.

Can anyone spot any obvious mistakes?

Cheers,
-Toris

Code:
// Loads a PNG image into memory from the SMC
u16 C_LoadPNGImage(const char *Directory, const char *Filename, u16 *ImageStore)
{
	F_HANDLE ImageFileHandle;
	u32 AmountRead;
	GpRelativePathSet(Directory);
	
	if(GpFileOpen(Filename, OPEN_R, &ImageFileHandle) == SM_OK)
	{
  char FileTypeTest[8];
  u32 ChunkSize;
  u32 ChunkType;
  u32 ChunkCRC;

  u32 ImageWidth;
  u32 ImageHeight;
  u8 BitDepth;
  u8 ColorType;
  u8 CompressionMethod;
  u8 FilterMethod;
  u8 InterlaceMethod;
  
  u8 *WorkingMem = 0;
  u32 BufferSize = 0;
  
  u16 FileParsed = false;
  u32 TotalChunkSize = 0;

  GpFileRead(ImageFileHandle, &FileTypeTest, 8, &AmountRead);
//  if(FileTypeTest != ".PNG....") { return C_ERROR; }

  while(FileParsed != true)
  {
  	GpFileRead(ImageFileHandle, &ChunkSize, 4, &AmountRead);
  	ChunkSize = ((ChunkSize&0xFF000000)>>24)|((ChunkSize&0x00FF0000)>>8)|((ChunkSize&0x0000FF00)<<8)|((ChunkSize&0x000000FF)<<24);

  	GpFileRead(ImageFileHandle, &ChunkType, 4, &AmountRead);

  	if(ChunkType == 1380206665) // IHDR
  	{
    GpFileSeek(ImageFileHandle, FROM_CURRENT, ChunkSize, NULL);
  	}
  	else if(ChunkType == 1163152464) // PLTE
  	{
    return C_ERROR;
  	}
  	else if(ChunkType == 1413563465) // IDAT
  	{
    TotalChunkSize += ChunkSize;
    GpFileSeek(ImageFileHandle, FROM_CURRENT, ChunkSize, NULL);
  	}
  	else if(ChunkType == 1145980233) // IEND
  	{
    FileParsed = true;
  	}
  	else // Any other chunk
  	{
    GpFileSeek(ImageFileHandle, FROM_CURRENT, ChunkSize, NULL);
  	}
  	GpFileSeek(ImageFileHandle, FROM_CURRENT, 4, NULL);
  }
  
  FileParsed = false;

  u8 *ChunkMem = (u8*)gm_malloc(TotalChunkSize);
  if (ChunkMem == 0) { return C_ERROR_OUTMEM; }
    u32 ChunkAmountRead = 0;
    
  GpFileSeek(ImageFileHandle, FROM_BEGIN, 0, NULL);

  GpFileRead(ImageFileHandle, &FileTypeTest, 8, &AmountRead);
//  if(FileTypeTest != ".PNG....") { return C_ERROR; }

  while(FileParsed != true)
  {
  	GpFileRead(ImageFileHandle, &ChunkSize, 4, &AmountRead);
  	ChunkSize = ((ChunkSize&0xFF000000)>>24)|((ChunkSize&0x00FF0000)>>8)|((ChunkSize&0x0000FF00)<<8)|((ChunkSize&0x000000FF)<<24);

  	GpFileRead(ImageFileHandle, &ChunkType, 4, &AmountRead);
	
  	if(ChunkType == 1380206665) // IHDR
  	{
    GpFileRead(ImageFileHandle, &ImageWidth, 4, &AmountRead);
    ImageWidth = ((ImageWidth&0xFF000000)>>24)|((ImageWidth&0x00FF0000)>>8)|((ImageWidth&0x0000FF00)<<8)|((ImageWidth&0x000000FF)<<24);
    GpFileRead(ImageFileHandle, &ImageHeight, 4, &AmountRead);
    ImageHeight = ((ImageHeight&0xFF000000)>>24)|((ImageHeight&0x00FF0000)>>8)|((ImageHeight&0x0000FF00)<<8)|((ImageHeight&0x000000FF)<<24);
    GpFileRead(ImageFileHandle, &BitDepth, 1, &AmountRead);
    GpFileRead(ImageFileHandle, &ColorType, 1, &AmountRead);
    GpFileRead(ImageFileHandle, &CompressionMethod, 1, &AmountRead);
    GpFileRead(ImageFileHandle, &FilterMethod, 1, &AmountRead);
    GpFileRead(ImageFileHandle, &InterlaceMethod, 1, &AmountRead);

    if(BitDepth != 8) { return C_ERROR; }
    if(ColorType != 2) { return C_ERROR; }
    if(CompressionMethod != 0) { return C_ERROR; }
    if(FilterMethod != 0) { return C_ERROR; }
    if(InterlaceMethod != 0) { return C_ERROR; }
  	}
  	else if(ChunkType == 1163152464) // PLTE
  	{
    return C_ERROR;
  	}
  	else if(ChunkType == 1413563465) // IDAT
  	{
    if(ChunkSize > 0)
    {
    	if(WorkingMem != 0)
    	{
      u8 *ChunkMemAddress = ChunkMem+ChunkAmountRead;
      GpFileRead(ImageFileHandle, ChunkMemAddress, ChunkSize, &AmountRead);
      if(AmountRead != ChunkSize) { return C_ERROR; }
      ChunkAmountRead += ChunkSize;
    	}
    	else { return C_ERROR; }
    }
  	}
  	else if(ChunkType == 1145980233) // IEND
  	{
    FileParsed = true;
  	}
  	else // Any other chunk
  	{
    GpFileSeek(ImageFileHandle, FROM_CURRENT, ChunkSize, NULL);
  	}
  	
  	GpFileRead(ImageFileHandle, &ChunkCRC, 4, &AmountRead);
  }

  WorkingMem = (u8*)gm_malloc((ImageWidth*ImageHeight*3)+ImageHeight);
  BufferSize = (ImageWidth*ImageHeight*3)+ImageHeight;
  if(WorkingMem == 0) { return C_ERROR; }

  int UncompressResult = uncompress(WorkingMem, &BufferSize, ChunkMem, ChunkSize);
  if(UncompressResult == Z_OK) { }
    else if(UncompressResult == Z_BUF_ERROR) { return C_ERROR; }
  else { return C_ERROR; }

  u32 OffsetWorking = 0;
  u32 OffsetImage = 0;
  for(u16 iY=0; iY < ImageHeight; iY++)
  {
  	OffsetWorking++;
  	for(u16 iX=0; iX < ImageWidth; iX++)
  	{
    ImageStore[OffsetImage] = C_GetRGB(WorkingMem[OffsetWorking], WorkingMem[OffsetWorking+1], WorkingMem[OffsetWorking+2]);
    OffsetWorking += 3;
    OffsetImage += 1;
  	}
  }
  gm_free(WorkingMem);
	}
	else
	{
  return C_ERROR;
	}
	GpFileClose(ImageFileHandle);
	return C_OK;
}
 
Here's my question to you: Chui (of SDL-port fame) has already ported libpng to the GP32, you can grab it off the sdl-gp32 page. So why don't you just use that and save yourself a *lot* of trouble? :D
 
Well, for 3 reasons, first, libpng is hugely bloated for my requirements, second, from what I have seen, from the way chui has implemented it, without changing quite a lot of source, it is designed to be used with his SDL lib only, and thirdly, I've written this code now, and it bugs me that it doesn't work ;)
 
if it's returning Z_BUF_ERROR then it seems the error is inside the uncompress() function, debug that and you may find the problem
 
Forgot to mention, ChunkMem seems to contain random information, not the information from the chunks of the PNG.

The uncompress function works fine (it's from ZLib in case anyone was wondering), as I managed to get 1-chunk pngs working with my previous version... now none work at all, but, I'm getting there :p

So, the problem is that ChunkMem doesn't contain what it is meant to, now, it has to be a silly small error... but, I'll be damned if I can spot it :)
 
when i was doing a bitmap loader i had alignment problems through using structures that were packed a different way to the bitmap files. (can't do #pragma pack(1) in GCC)
well anyway this does not seem to be your problem.

i'm thinking it could be an endianess issue, where did you get the code from originally?

you see this bit?
Code:
ChunkSize = ((ChunkSize&0xFF000000)>>24)|((ChunkSize&0x00FF0000)>>8)|((ChunkSize&0x0000FF00)<<8)|((ChunkSize&0x000000FF)<<24);

try commenting it out, and the same for all other occurances, ImageWidth and ImageHeight.
it could be that the dword is already in the correct order, i dunno.
 
Nope, checked, the long vars are in "network byte order", so had to switch them for little endian for the gp32, I tried writing the values for all of those variables, and they all came out correct. In fact, it *all* reads correctly, apart from the ChunkMem... so the problem is in the IDAT reading part somewhere.
 
Well, approx 5 days later, it works!
The problem was 2 things, in the IDAT reading part, I was doing "if(WorkingMem != 0)" before I allocated WorkingMem, so it was never reading in the data, secondly, this line:
"int UncompressResult = uncompress(WorkingMem, &BufferSize, ChunkMem, ChunkSize);" should have been "int UncompressResult = uncompress(WorkingMem, &BufferSize, ChunkMem, TotalChunkSize);", since ChunkSize equals 0 at the end.

Well, cheers for your help guys :)
 
Back
Top