New version of PNG library (now v3.2.q)

User contributed sources that have become inactive, deprecated, or generally unusable. But ... we don't really want to throw them away either.
Post Reply
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Post by KristopherWindsor »

Thanks; I'll try it when FB .21 comes out. :)
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Post by yetifoot »

Zire has let me know about a problem when using the static zlib version, it still relies on zlib.dll

The way to stop that is to remove these lines from fbpng.bi

#ifndef PNG_STATICZ
#inclib "z"
#endif

Or to do

#define PNG_STATICZ 1
#include "fbpng.bi"

in your program.

These changes are only needed if you use the static version, I will make an update to the package soon with these changes and I'll probably roll in some of the other suggestions I agree with.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Post by KristopherWindsor »

counting_pine wrote:It should be possible to modify the routines so that they return an image in a format that can be destroyed with the current version of imagedestroy.
If you go into png_image_convert.bas, and change the "out_img = callocate(...)" lines to "out_img = callocate_aligned(...)", and change png_destroy.bas to use deallocate_aligned() instead of deallocate(), then that should work.

Here are the replacement functions you need:

Code: Select all

function callocate_aligned( byval size as long ) as any ptr
    
    assert( sizeof(long) = sizeof(any ptr) )
    
    if size <= 0 then return 0
    
    dim as long buf, buf2
    
    dim as long size2 = size + sizeof(long) + &hf
    
    buf = clng( callocate( size2 ) )
    if buf = 0 then return 0
    
    
    buf2 = (buf + sizeof(any ptr) + &hf) and (not &hf)
    assert( size2 - (buf2 - buf) >= size )
    
    cptr(long ptr, buf2)[-1] = buf
    
    return cptr(any ptr, buf2)
    
end function

sub deallocate_aligned( byval buf as any ptr )
    
    dim as any ptr p = any
    
    if buf <= sizeof(any ptr) then return
    
    p = cptr(any ptr ptr, buf)[-1]
    
    deallocate cptr(any ptr ptr, buf)[-1]
    
end sub

'' example:

var p = callocate_aligned( 10 )

print hex(p)

deallocate_aligned( p )
The significant difference in the _aligned versions is that a pointer to the actual allocated memory is stored 4 bytes before the pointer that's returned, and it's this that needs to be deallocated. But I've also done the necessary work to make callocate_aligned return a pointer that's 16-byte aligned. Otherwise, it would be

deallocate_aligned should be compatible with imagedestroy, although as a courtesy I added a simple pointer check.

But, barring any future changes, either function will successfully destroy images created with either imagecreate or with an appropriately modified fbpng.
But then how do things like this still work?
gp = cast(Ubyte Ptr, someimage + 1)
Is that safe for .21?
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

Used as a pair, callocate_aligned and deallocate_aligned will give effectively the same results as callocate/deallocate.

Pointer arithmetic will obviously work the same on someimage, no matter how you derived the pointer for it, although I can't remember whether yetifoot's library returns the new or old style header by default. If you can't be sure, I suggest using ImageInfo.

You've mentioned crashes with upgrading FB, so you're probably affected by the alignment issue. You could use #if to only use the aligned routines only for versions after 0.20, then whatever's created will be freeable with that version of FB's ImageDestroy routine.


(...Hmm, looks like I didn't finish one of the paragraphs in that post. I was probably thinking something along the lines of "otherwise, it would be false advertising", or something. Anyway, either way the important thing is just that the pointer to the actual allocated address is stored just before the returned address, and not that there's any special alignment.)
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Post by KristopherWindsor »

counting_pine wrote:Anyway, either way the important thing is just that the pointer to the actual allocated address is stored just before the returned address, and not that there's any special alignment.)
So then these would both do the same thing?
gp = cast(Ubyte Ptr, someimage + 1)
gp = *cptr(ubyte ptr ptr, cptr(Ubyte Ptr, someimage) - 4)

It seems unnecessary to point to some data when you already know where it is.

I thought the png problem was that png_load made images of a different size because the pitch was different. Isn't that why it crashed for me? (I use png_load + imagedestroy.) Or why is it crashing if imagedestroy deallocates the proper data?
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

Those lines aren't equivalent at all.

The pointer stored before the image doesn't point to the image data, but the allocated memory in which are stored: some padding, said pointer, and the image itself.

Code: Select all

'' set the pixel value of the top-left pixel in someimage to 0
'' (assuming 8-bit image with new-style header):
*cast(Ubyte Ptr, someimage + 1) = 0 

'' take the pointer to the (unaligned) memory block that (aligned) someimage is stored in, and free it:
deallocate *cptr(ubyte ptr ptr, cptr(Ubyte Ptr, someimage) - 4)
'' or:
deallocate cptr(ubyte ptr ptr, someimage)[-1]

Imagedestroy shouldn't be used with png_load, unless you know what you're doing. As it stands, png_load doesn't align its data or store a pointer before the start of the image, making it unsuitable for the latest version of FB's imagedestroy.
As I said, that can be fixed by changing the library's code to use callocate_aligned instead of callocate, in recentish 0.21b builds of FB.

There are no pitch issues, as far as I know.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Post by KristopherWindsor »

OK, but I still don't understand the purpose of the pointer. :P
It seems like you have these things in memory, right after the other: {new pointer, fb.image, pixel data}, and you need the pointer to the fb.image before you can get the address of the new pointer, and the new pointer just points to itself or the fb.image?
Or is it like {padding, new pointer, fb.image, pixel data}, and the new pointer points to the beginning of the padding?

TBH... upgrading to .21 isn't worth the trouble of recompiling FBPNG. ;P
FBPNG seems to be the only reason my breakout game crashes in .21.
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Post by 1000101 »

The alignment issue comes in because the FB.IMAGE buffers where supposed to be paragraph aligned (aligned to 16-byte boundaries) as part of the update to include the pitch which is also supposed to be parapgraph aligned. The correct code to calculate the pitch was done but alignment of the buffer as a whole was forgotten. .21 corrects this by making sure the buffers are paragraph aligned and thus the pixel data is paragraph aligned. The reason for the alignment is for possible SSE code to work on the buffers without being penalized for unaligned data (can use movaps instead of movups).

Now we know why we have the change, let's look at how and hopefully this will answer everyone ones questions on this matter.

The code itself is quite simple:

Code: Select all

'' Add in 15 bytes for alignment and 4 bytes to store the original pointer
Aligned_Bytes = Buffer_Bytes + 15 + 4

'' Call the allocation function
Unaligned_Pointer = Callocate( Aligned_Bytes )

'' Align the pointer to paragraph alignment
Aligned_Pointer = ( Unaligned_Pointer + 15 + 4 ) And ( Not 15 )

'' Record the orignal pointer for deallocation, the aligned dealloc with simply look at Aligned_Pointer[ -1 ] for the pointer to the whole memory.
cPtr( uInteger Ptr, Aligned_Pointer )[ -1 ] = Unaligned_Pointer

'' Fill out the FB.IMAGE structure and then return the aligned pointer
The above code is an ancient hack of programers who have needed alignment which the OS does not provide. Would that the OS itself had an aligned allocate function, but not all do. :(
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Post by yetifoot »

I've put up a new version of fbpng, now at version 1.9.2

This version will be SSE compatible, and match the new ImageCreate allocation method. However, as stated you should really be using png_destroy() now, that is the 'cleanest' way, but this will now mean if you use 0.21, and your old code still uses imagedestroy it shouldn't crash. Read the first post for more information.

Thanks to counting_pine, whose patch I modifed and added, and to sir_mud for compiling the windows libraries.

For most people this update won't affect them in any way, if they were already using 1.9.1 and png_destroy().
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Post by yetifoot »

Thanks to KristopherW, a bug has been spotted in png_dimensions. At the moment it doesn't close the file, which will be a problem if you want to delete it while the program is still running apparently. I will do another release soon, but for now if you want to use that function, and this bug would effect you can make the patch like this:

change the end of png_dimensions from this:

Code: Select all

	w = get_u32( @tmp1 )
	h = get_u32( @tmp2 )

end sub
to

Code: Select all

	w = get_u32( @tmp1 )
	h = get_u32( @tmp2 )

	fclose( hfile )

end sub
Landeel
Posts: 777
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Post by Landeel »

For now I'm using:

Code: Select all

#IFNDEF png_destroy

	#DEFINE png_destroy imagedestroy

#ENDIF

to make my code as compatible as possible.
agamemnus
Posts: 1842
Joined: Jun 02, 2005 4:48

Post by agamemnus »

Again, great job...
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Post by 1000101 »

I thought it a bit silly that we are well beyond fbc 0.16.0, only 8-bit buffers use the old image format and yet the default return buffer type is PNG_TARGET_FBOLD so I made a slight modification to my fbpng.bi include file.

To avoid having to explicitly specify the new buffer format on compilers which started implementing them, the following change was made:

fbpng.bi

Code: Select all

enum png_target_e
	PNG_TARGET_BAD
	PNG_TARGET_FBOLD
	PNG_TARGET_FBNEW
	PNG_TARGET_OPENGL
#If	__FB_MIN_VERSION__( 0, 17, 0 )
	PNG_TARGET_DEFAULT		= PNG_TARGET_FBNEW
#Else
	PNG_TARGET_DEFAULT		= PNG_TARGET_FBOLD
#EndIf
end enum

declare function png_load cdecl alias "png_load" _
	( _
		byref filename as string, _
		byval target   as png_target_e = PNG_TARGET_DEFAULT _
	) as any ptr

declare function png_load_mem cdecl alias "png_load_mem" _
	( _
		byval buffer     as any ptr, _
		byval buffer_len as integer, _
		byval target     as png_target_e = PNG_TARGET_DEFAULT _
	) as any ptr
This change makes the default image format dependant on the compiler version. If it's pre-0.17.0 then it will use the old buffers by default, if it's 0.17.0 or newer then it will use the new buffers by default.

Anyway, great lib (although it would be nice to be able to load 8-bit pngs to 8-bit buffers, even in 32-bit video modes).
Last edited by 1000101 on Jul 05, 2009 20:11, edited 1 time in total.
vdecampo
Posts: 2992
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Post by vdecampo »

Maybe I am misunderstanding but I thought that by adding the line...

#define PNG_STATICZ 1

would make it so I do not require the zlib dll. But when I run test1.bas it gives an error that it cannot find the dll.

Am I doing something wrong or do I just need the dll?

-Vince
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Post by yetifoot »

vdecampo wrote:Maybe I am misunderstanding but I thought that by adding the line...

#define PNG_STATICZ 1

would make it so I do not require the zlib dll. But when I run test1.bas it gives an error that it cannot find the dll.

Am I doing something wrong or do I just need the dll?

-Vince
Hi Vince, here is an example of using it static with test1.bas

tar -xvvf fbpng_v1_9_2.tar.gz
mkdir test
cp fbpng_v1_9_2/build/prebuilt/linux/static/libfbpng.a test/
cp fbpng_v1_9_2/inc/fbpng.bi test/
cp fbpng_v1_9_2/tests/test1.bas test/
That unpacks the fbpng and copies the 3 needed files into a test directory

I then modified that new test/test1.bas so that the top looked like this (I removed the include for png_image, it wasn't needed here)

Code: Select all

#define PNG_STATICZ 1

#include once "crt.bi"
#include once "fbpng.bi"

const as integer scr_width = 600
const as integer scr_height = 350
Then when I compiled, it correctly compiled as static. I was able to confirm this works here because a) I don't have libz-dev installed b) I used ldd to list the dependencies.

Hope that helps.
Post Reply