PDA

View Full Version : PNG library that works on Win32, Linux and MacOS X...



savage
08-11-2006, 08:11 AM
Does anyone know of a pure Pascal PNG library that works on Win32, Linux and MacOS X? I could go down the route of using libpng, but that requires shipping it with ones game/app which means compiling for each OS/Platform.

Any suggestions/ideas?

JernejL
08-11-2006, 08:52 AM
Any pascal implementation of png using paszlib should work fine on any platform...

savage
08-11-2006, 09:31 AM
I think I may have found a pure pascal implemation here - http://www.colosseumbuilders.com/sourcecode.htm

Will need to test it before I give it the thumbs up.

JernejL
08-11-2006, 12:53 PM
what about http://pngdelphi.sourceforge.net/ ?

It even works without Delphi VCL, which would be a great portability point and make it useful for games. the only problem is, that it uses delphi's zlib OBJ files, which efficiently bind it to delphi-only, but making it use PasZlib shouldn't be a problem imo - just replace PNGZLIB.PAS with another unit, that will use paszlib.

savage
08-11-2006, 01:01 PM
I'm currently using pngdelphi on win32 and it does work very well, but since it uses the *.o is why I was looking for an alternative.
Paszlib looks very good, but has not been updated in ages. So that would require that I update it to the very latest version of zlib.
Lastly, the colosseumbuilders pascal implementation seems to work partially, or at least seems to be partial as the rendering example that is ships with does not display the toucan image correctly. So that looks like it may need updating as well.

So all in all, at the moment, any way I go, I need to get my hands dirty. Now which path will be the least hassle and will benefit the most people?

JernejL
08-11-2006, 02:11 PM
I'd say getting pngdelphi to work with paszlib would be better, it has better loader and alpha support, paszlib may be "a little" old, but still works great.

savage
08-11-2006, 02:47 PM
I'd say getting pngdelphi to work with paszlib would be better, it has better loader and alpha support, paszlib may be "a little" old, but still works great.

Strangely, this is exactly what I was thinking, and after about 7 minutes of replacing, TPngImage seems to work quite well with PasZlib. It's a pity it has not been updated, just to keep it current if for nothing else.

marmin
08-11-2006, 02:58 PM
A few months ago I asked myself the same question.

Lazarus comes with PNG support. LoadPNG().

JernejL
08-11-2006, 09:26 PM
A few months ago I asked myself the same question.

Lazarus comes with PNG support. LoadPNG().

That's not useful outside of lazarus - such as kylix and delphi, also, does it support alpha channels?

cragwolf
08-11-2006, 10:04 PM
Since you want it to work on Win32, Linux and MacOS X, you're clearly looking for a Free Pascal solution, so Kylix and Delphi support is irrelevant. Doesn't Free Pascal support PNG with the fpimage unit? I haven't tried it outside of compiling and running the associated demo program (see imgconv.pp), but it seems to support transparency as far as I can tell. Also, as far as I can tell it doesn't require libpng, but correct me if I'm wrong. It's part of the FCL, which is poorly documented. You'll have to look at the source code to see what it can do. It's in the fcl/image sub-directory.

JernejL
09-11-2006, 05:24 AM
Since you want it to work on Win32, Linux and MacOS X, you're clearly looking for a Free Pascal solution, so Kylix and Delphi support is irrelevant. Doesn't Free Pascal support PNG with the fpimage unit? I haven't tried it outside of compiling and running the associated demo program (see imgconv.pp), but it seems to support transparency as far as I can tell. Also, as far as I can tell it doesn't require libpng, but correct me if I'm wrong. It's part of the FCL, which is poorly documented. You'll have to look at the source code to see what it can do. It's in the fcl/image sub-directory.

I compile my programs on win32 with delphi, and kylix on other platforms, since so far, delphi still leads the performance for code execution on win32.

cragwolf
09-11-2006, 08:09 AM
Correct me if I'm wrong, but neither Delphi nor Kylix work on MacOS X. So I think I made a reasonable assumption in concentrating the discussion on Free Pascal, which does work on MacOS X. Also I just noticed that this is the Free Pascal forum. I should read more carefully. :oops:

Anyway, I did some testing with the fpImage unit, and found that while it does support the reading of alpha channel information from PNG files, it crashes when you try to write such information. Writing is fine when you don't have an alpha channel. I submitted it as a bug to the FPC guys.

Personally, I stick with TGA files. This image format is so simple that even someone as dumb as me can create a reader/writer class for it. Compression tends to be 2 or 3 times worse than PNG but I can live with that. :D

dmantione
09-11-2006, 09:47 AM
Paszlib looks very good, but has not been updated in ages. So that would require that I update it to the very latest version of zlib.


The paszlib in the Free Pascal SVN is maintained, but not actively developed. But it works very well, is definately usable to read png graphics.

savage
09-11-2006, 09:54 AM
Hi Cragwold, have you tried TPngImage ( pngdelphi.sf.net )? I have tested it across the wholes PNG test suite and it's the only Pascal solution that seems to handle 99% of PNG images. I say 99, but I have actually never seen it mess up an image yet. If we can convince Gustavo to remove his dependency from *.o file and use paszlib for example, it would be a great portable Pascal PNG library.

cragwolf
09-11-2006, 07:37 PM
I tried TPngImage years ago in my Delphi/Win32 days. It was great then, too. This was after I had written my own very inefficient and restricted PNG writer (blood, sweat and tears included). I could never properly understand the Adam7 interlacing business, so I never got quite as far as a reader.

marmin
10-11-2006, 09:00 AM
I also love the TGA format.. it reads in Delphi, lazarus without problems and full transperency.

cragwolf
10-11-2006, 06:13 PM
Do RLE-compressed TGA's work on Lazarus? I think Lazarus just uses Free Pascal's fpImage unit, and I recall that unit having trouble with RLE-compressed TGA files.

savage
12-11-2006, 01:26 PM
Hmm I tried to compile TPngObject on MacOS X and it throws up a few too many errors. Looks like it needs a fair amount of work to allow FreePascal to compile it.
I've sent emails to Gustavo Daud about making TPngObject more portable, but he is not responding to his email at the moment.

savage
27-11-2006, 11:32 AM
After further investigation I think getting libpng support via a binding will be the most cross-platform way to handle PNG file. It would be great to have a pure Pascal implementation, but the work involved in decoupling GDI specifics from the Gustavo Daud's work, make it prohibitive due to my limited time.

savage
05-12-2006, 09:29 PM
OK I have created a more up to date version of libpng.pas which works with a Win32 DLL called lpng-px.dll. Does anyone else have libpng.so installed on their Linux box that would be able to test my header file?

I tried to past the code into here, but something is causing it to kill phpBB.
So you'll have to download the unit from http://jedi-sdl.pascalgamedevelopment.com/files/libpng.zip.

Any feedback/corrections welcome.

cragwolf
06-12-2006, 04:10 AM
It compiles on Linux. Only a few warnings:


libpng.pas(1629,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1635,44) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1642,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1648,47) Warning: Mixing signed expressions and longwords gives a 64bit result

But I wouldn't have a clue how to test it. Those libpng functions look pretty complicated. It would be nice to have a demo program, or a simple-to-use class that wraps everything up.

savage
06-12-2006, 08:18 AM
I think the simplest test would be something like this...

program PngTest;

{$APPTYPE CONSOLE}

var
temp : string;
FPngStruct : png_structp;
FPngInfo : png_infop;
begin
temp := png_get_libpng_ver ( nil );
WriteLn( 'Version : ' + temp );
FPngStruct := png_create_read_struct( PNG_LIBPNG_VER_STRING, nil, nil, nil );
if assigned( FPngStruct ) then
begin
FPngInfo := png_create_info_struct( FPngStruct );
if assigned( FPngInfo ) then
begin
WriteLn( 'We can start decoding now' );
end
else
begin
WriteLn( 'Failed to Create PngInfo struct!' );
end;
end
else
begin
WriteLn( 'Failed to Create PngStruct!' );
end;

ReadLn;
end.


If you get the *start decoding* message then everything is else should just work. The steps after that would involve introducing call back functions for reading the PNG file.
If this works for you, I can send you a more complete JEDI-SDL example.

cragwolf
06-12-2006, 08:02 PM
Linking errors! OK, so first of all, you need to rename libPng.so to libpng.so, keep it all lower-case. Second, you need to add zlib to the uses clause. After that, the following linking errors remain:


libpng.o(.text+0xb1): In function `LIBPNG_PNG_SIG_BYTES$$PNG_BYTEP':
: undefined reference to `png_sig_bytes'
libpng.o(.text+0x411): In function `LIBPNG_PNG_GET_SCAL_S$POINTER$PNG_INFOP$LONGINT$P NG_CHARPP$PNG_CHARPP$$LONGWORD':
: undefined reference to `png_get_sCAL_s'
libpng.o(.text+0x871): In function `LIBPNG_PNG_SET_ITXT$POINTER$PNG_INFOP$PNG_TEXTP$L ONGINT':
: undefined reference to `png_set_itxt'
libpng.o(.text+0x9a1): In function `LIBPNG_PNG_SET_SCAL_S$POINTER$PNG_INFOP$LONGINT$P CHAR$PCHAR':
: undefined reference to `png_set_sCAL_s'
/usr/lib/libpng.so: undefined reference to `pow'
pngtest.pp(32,1) Error: Error while linking

The undefined reference to `pow' can be fixed by adding {$LINKLIB m} to your libpng unit (alternatively I can just add -lm to my compiler command-line). If I comment out the declarations to the other 4 functions, I can compile it fine. And when I run it, everything works, I see the "We can start decoding now" message. I have version 1.2.12 of libpng.

cragwolf
06-12-2006, 08:05 PM
Oh yeah, you are aware that Free Pascal has a unit for the libpng library? It's called 'png'. It compiles fine with your test program, as long as I add the -lm parameter. I guess you also want Delphi compatibility, though.

savage
07-12-2006, 12:06 AM
Thanks for testing it out on Linux Cragwolf. Yes the idea is that it should be Delphi/Kylix friendly as well.

Ok I have removed png_sig_bytes and png_set_itxt and IFDEFed png_get_sCAL_s and png_set_sCAL_s.

Can you please clarify why I need zlib and where is it picking up the reference to "pow" as that does not exist anywhere in the source code?
I'm trying to avoid adding {$LINKLIB m} and the unit zlib, unless there is a really good reason to do so. Under Linux wouldn't Zlib be another dynamically linked shared object or are you statically linking it by adding zlib to the uses clause?

cragwolf
07-12-2006, 08:37 AM
I have no idea why the compiler complained about requiring zlib and libm earlier this morning when I tried it. Now even after deleting everything and starting again, it all works fine. Just take care of those four functions like you have, and use lower-case on libpng.so and all is good.

savage
07-12-2006, 01:58 PM
phew I thought there was some magic going on somewhere. Thanks again cragwolf. I'm just trying to create a proper zlib.dll and libpng.dll on Win32 at the moment and it's not easy as I'm using Borland C/C++ compilers.

savage
05-03-2007, 10:30 PM
hi cragwolf,
I've uploaded a new version of libpng.pas with the modifications you mentioned @ http://jedi-sdl.pascalgamedevelopment.com/files/libpng.zip.
It's also version 1.2.16 now.

When you have a spare moment, could you give it a quick test.


Thanks.

cragwolf
06-03-2007, 02:24 AM
Works fine, fpc 2.0.4, Linux. Just the same old warnings about mixing different types:


libpng.pas(1630,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1636,44) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1643,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1649,47) Warning: Mixing signed expressions and longwords gives a 64bit result

I can't see any signed expressions there. Maybe the compiler is too dumb to realise that there are none.

savage
06-03-2007, 09:26 AM
Thanks for testing it. Good to see that the basics are working.

If I upload my Siege of Avalon layering demo, could you try and compile and run it under Linux? It works under Win32, but it would be nice to see if the TPngImage class it uses for Load/Save Stream is also cross-platform enough.

savage
06-03-2007, 10:36 AM
If you or anyone else has the chance to test it on OSes other than Win32 the file with source can be downloaded from - http://jedi-sdl.pascalgamedevelopment.com/files/SDLPoxDemo.zip.

The code is extremely untidy and hacked together, but it serves as a proof of concept for now. I've included a Win32 exe for those who just want to have a look at it.

cragwolf
07-03-2007, 12:02 PM
I'll try it out tomorrow; I spent today reinstalling and configuring a new version of my Linux distribution, and it takes a while to get it just how I want it.

cragwolf
09-03-2007, 12:33 PM
I tested it. It reached this point:


Compiling PNGImage.pas
Fatal: Can't find unit Windows

I don't think you can use the Windows unit in Linux. I notice also that you use the unit Graphics, which I don't think even exists in FPC.

savage
10-03-2007, 12:12 AM
Ah Damn, I'll see if I can trim it down so that it is not so dependent on Windows and Graphics.

savage
10-03-2007, 01:37 AM
Hi Cragwolf, I've just uploaded a new version of that demo with loads of non-relevant stuff IFDEFed out. This works under Windows so I'm hoping this will be enough for it work under Linux.

Thanks.

cragwolf
10-03-2007, 04:46 AM
It works, but you need to make the following simple changes. In PNGImage.pas, the procedures ReadData, WriteData, FlushData, and IOCallback, should have cdecl calling conventions instead of stdcall calling conventions. So I guess all you need is the appropriate ifdef's for that. After you do that, it seems to work: I see a man and a dog, animated, and you can cast a spell on the dog, revive the dog, and remove hair, pants, and breastplate (?) from the man.

There are some warnings as well, here they are:


Compiling SDLPoxDemo.dpr
Compiling sdl.pas
Compiling sdl_image.pas
Compiling SoAoSSprite.pas
SoAoSSprite.pas(143,23) Warning: Function result does not seem to be set
SoAoSSprite.pas(150,27) Warning: Function result does not seem to be set
SoAoSSprite.pas(79,5) Note: Private field "TSoAoSSprite.Flags" is never used
SoAoSSprite.pas(80,5) Note: Private field "TSoAoSSprite.isDead" is never used
Compiling sdlcolor.pas
Compiling stringini.pas
Compiling PNGImage.pas
Compiling libpng.pas
libpng.pas(1630,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1636,44) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1643,30) Warning: Mixing signed expressions and longwords gives a 64bit result
libpng.pas(1649,47) Warning: Mixing signed expressions and longwords gives a 64bit result
PNGImage.pas(828,9) Warning: Symbol "png_set_gray_1_2_4_to_8" is deprecated
SDLPoxDemo.dpr(89,3) Note: Local variable "MouseX" is assigned but never used
SDLPoxDemo.dpr(90,3) Note: Local variable "MouseY" is assigned but never used
SDLPoxDemo.dpr(93,3) Note: Local variable "Header" not used
SDLPoxDemo.dpr(95,3) Note: Local variable "ChunkName" not used
SDLPoxDemo.dpr(96,3) Note: Local variable "IHDRData" not used
SDLPoxDemo.dpr(97,3) Note: Local variable "DataPointer" not used
SDLPoxDemo.dpr(98,3) Note: Local variable "CheckCRC" not used
SDLPoxDemo.dpr(45,3) Note: Local variable "FrameWidth" is assigned but never used
SDLPoxDemo.dpr(45,15) Note: Local variable "FrameHeight" is assigned but never used
Compiling resource SDLPoxDemo.res
Linking SDLPoxDemo
9489 Lines compiled, 0.7 sec

savage
10-03-2007, 10:35 AM
It works, but you need to make the following simple changes. In PNGImage.pas, the procedures ReadData, WriteData, FlushData, and IOCallback, should have cdecl calling conventions instead of stdcall calling conventions. So I guess all you need is the appropriate ifdef's for that. After you do that, it seems to work: I see a man and a dog, animated, and you can cast a spell on the dog, revive the dog, and remove hair, pants, and breastplate (?) from the man.

Hey this is great! There are bound to be warnings, as I said this is probably the worst code I have cobbled together. It literally was a case of hacking everything together to just get something up and running. So for that I am happy. The removing stuff is just to test the SoAoS layering system to make sure it all works and is part of the looting part of the original game. You could literally pilfer the shirt off an adversaries back :).

Could you post a screen shot of the animation running as I'd like to add it to the SoAoS website as progress on the project. I will also clean up the demo code before making it public.

Thanks again for taking the time to test it all out.

cragwolf
11-03-2007, 03:14 AM
Here is a screenshot of my desktop with SDLPoxDemo running:

http://img185.imageshack.us/img185/9479/shotqv1.th.png (http://img185.imageshack.us/my.php?image=shotqv1.png)