New version of PNG library (now v3.2.q)
-
- Posts: 2428
- Joined: Jul 19, 2006 19:17
- Location: Sunnyvale, CA
- Contact:
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.
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.
-
- Posts: 2428
- Joined: Jul 19, 2006 19:17
- Location: Sunnyvale, CA
- Contact:
But then how do things like this still work?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: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 beCode: 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 )
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.
gp = cast(Ubyte Ptr, someimage + 1)
Is that safe for .21?
-
- Site Admin
- Posts: 6323
- Joined: Jul 05, 2005 17:32
- Location: Manchester, Lancs
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.)
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.)
-
- Posts: 2428
- Joined: Jul 19, 2006 19:17
- Location: Sunnyvale, CA
- Contact:
So then these would both do the same thing?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.)
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?
-
- Site Admin
- Posts: 6323
- Joined: Jul 05, 2005 17:32
- Location: Manchester, Lancs
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.
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.
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.
-
- Posts: 2428
- Joined: Jul 19, 2006 19:17
- Location: Sunnyvale, CA
- Contact:
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.
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.
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:
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. :(
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
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().
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().
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:
to
change the end of png_dimensions from this:
Code: Select all
w = get_u32( @tmp1 )
h = get_u32( @tmp2 )
end sub
Code: Select all
w = get_u32( @tmp1 )
h = get_u32( @tmp2 )
fclose( hfile )
end sub
For now I'm using:
to make my code as compatible as possible.
Code: Select all
#IFNDEF png_destroy
#DEFINE png_destroy imagedestroy
#ENDIF
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
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).
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
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.
Hi Vince, here is an example of using it static with test1.basvdecampo 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
That unpacks the fbpng and copies the 3 needed files into a test directorytar -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/
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
Hope that helps.