I have an animation program that repeatedly decodes a
set of png images that have previously been read into
memory.
png_set_read_fn() works well for that, though I wish I
could supply an address to the filled buffer instead
of having to do a memcpy() in the read function.
libjpeg is implemented this way so that I am able to
supply a pointer into the in-memory copy of the png
file.
I would also like to reuse the read_struct and
info_struct instead of freeing them and re-allocating
for every image.
It seems like the correct way to do this is to call
png_read_destroy() after I'm finished with the current
image. Older png documents suggest this. png.h
comments for png_info_destory() say that function
frees memory and resets struct, but png_read_destroy()
comments say this is an old method and not DLL
exported.
But this doesn't seem to be working. It doesn't seem
like png_read_destroy() is resetting the png_ptr. But
if I make use of the !deprecated! png_read_init_3() to
reinitialize the png_ptr, things work fine.
So my question is, what is the "right
way"(patent
pending) to do this? Is png_read_destroy() supposed to
re-init the png_ptr?
relevent code below. (Hopefully yahoo didn't mangle
the formatting too much, sorry)
thanks,
-brandon
--Description of code:
-There are multiple threaded decoders, so I store a
pointer
my own png_decompress_struct (maybe I should change
the name) in thread-local storage, then each entry
into the decode function, this pointer is retrieved
or created the first time if it does not exist. I
think it is simple enough to ignore.
-xmalloc(),xfree(),x... are just macros around their
respective functions that exit() on failure.
-I also try to enable the asm optimization functions,
will the enabling of these functions be retained
across reinitialization of the png_ptr? or does it
have to be done each time?
struct png_decompress_struct {
png_structp png_ptr;
png_infop info_ptr;
};
struct user_png_decode_buffer {
png_bytep data;
png_size_t len;
};
static void png_user_read_data(png_structp png_ptr,
png_bytep data,
png_size_t length)
{
struct user_png_decode_buffer* data_ptr;
data_ptr = (struct user_png_decode_buffer*)
png_get_io_ptr(png_ptr);
if (data_ptr->len >= length) {
png_memcpy(data, data_ptr->data, length);
data_ptr->data += length;
data_ptr->len -= length;
} else {
png_error(png_ptr,
"decode_png: requested more data than
was available.");
}
}
/* On entry to this function:
* - buf contains the png file in memory
* - len is the size of this buffer
* - width and height initially contain the
* dimensions of the output buffer, but return
* the dimensions of the decoded image (strange
* but there are reasons for this).
* - rgba is a preallocated buffer for the returned
* image
* - alpha selects whether returned data has an
* alpha component or not.
*/
static int decode_png_alpha(unsigned char* buf, size_t
len, int* width,
int* height, unsigned char* rgba, int alpha)
{
struct png_decompress_struct* volatile structptr;
struct user_png_decode_buffer data_ptr;
png_uint_32 pwidth, pheight;
int bit_depth, color_type;
png_uint_32 rowbytes;
int intent;
int elements;
png_bytep rgbptr;
int pass, number_passes;
register int y;
png_color_16 my_background = {255, 255, 255, 255,
255};
/* we're reusing the png structs so each thread
needs one */
if ((structptr =
pthread_getspecific(png_structp_key)) == NULL)
{
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >=
10200)
png_uint_32 mask, flags;
#endif
xmalloc(structptr, sizeof(struct
png_decompress_struct));
structptr->png_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (structptr->png_ptr == NULL) {
fprintf(stderr,"png_create_read_struct
failed.\n");
xfree(structptr);
return 1;
}
/* not sure if this is of much use as long as
we have
* to call png_read_init_3(), does it reset
this? */
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >=
10200)
/* enable PNG runtime optimizations */
flags = png_get_asm_flags(structptr->png_ptr);
mask = png_get_asm_flagmask(PNG_SELECT_READ);
png_set_asm_flags(structptr->png_ptr, flags &
mask);
#endif
structptr->info_ptr =
png_create_info_struct(structptr->png_ptr);
if (structptr->info_ptr == NULL) {
fprintf(stderr,"png_create_info_struct
failed.\n");
png_destroy_read_struct(&(structptr->png_ptr),
png_infopp_NULL,
png_infopp_NULL);
xfree(structptr);
return 1;
}
if (pthread_setspecific(png_structp_key,
structptr) != 0) {
fprintf(stderr, "Failed setting
png_structp_key\n");
png_destroy_read_struct(&structptr->png_ptr,
&structptr->info_ptr,
png_infopp_NULL);
xfree(structptr);
return 1;
}
}
#if 1
/* This is redundant the first time through, but
optimal every
* other time, hopefully we'll be able to remove
this call if
* it's not the right way to do it. */
png_read_init_3(&structptr->png_ptr,
PNG_LIBPNG_VER_STRING,
sizeof(png_struct));
#endif
if (setjmp(png_jmpbuf(structptr->png_ptr))) {
fprintf(stderr,"png must have failed, "
"setjmp returned non-zero in
read_png.\n");
png_read_destroy(structptr->png_ptr,
structptr->info_ptr, NULL);
return 1;
}
data_ptr.data = buf;
data_ptr.len = len;
png_set_read_fn(structptr->png_ptr, &data_ptr,
png_user_read_data);
png_read_info(structptr->png_ptr,
structptr->info_ptr);
png_get_IHDR(structptr->png_ptr,
structptr->info_ptr, &pwidth, &pheight,
&bit_depth, &color_type, int_p_NULL,
int_p_NULL, int_p_NULL);
/* handle 16 bit graphics poorly */
if (bit_depth == 16)
png_set_strip_16(structptr->png_ptr);
/* we need RGB */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(structptr->png_ptr);
/* we need RGB */
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_gray_to_rgb(structptr->png_ptr);
}
if (alpha) {
elements = 4;
/* add alpha channel if we don't have one */
if (png_get_valid(structptr->png_ptr,
structptr->info_ptr,
PNG_INFO_tRNS))
png_set_tRNS_to_alpha(structptr->png_ptr);
else
png_set_filler(structptr->png_ptr, 255,
PNG_FILLER_AFTER);
} else {
elements = 3;
/* set background */
png_set_background(structptr->png_ptr,
&my_background,
PNG_BACKGROUND_GAMMA_FILE,
0, 1.0);
}
/* do nothing if we are already in sRGB space,
* else apply gamma correction
*/
if (!png_get_sRGB(structptr->png_ptr,
structptr->info_ptr, &intent)) {
double image_gamma;
if (png_get_gAMA(structptr->png_ptr,
structptr->info_ptr, &image_gamma))
png_set_gamma(structptr->png_ptr, 2.2,
image_gamma);
}
number_passes =
png_set_interlace_handling(structptr->png_ptr);
/* modify our info_ptr based on the above options
*/
png_read_update_info(structptr->png_ptr,
structptr->info_ptr);
png_get_IHDR(structptr->png_ptr,
structptr->info_ptr, &pwidth, &pheight,
&bit_depth, &color_type, int_p_NULL,
int_p_NULL, int_p_NULL);
if ((png_uint_32) *width * *height < pwidth *
pheight) {
fprintf(stderr, "decode_png: output buffer too
small\n");
png_read_destroy(structptr->png_ptr,
structptr->info_ptr, NULL);
return 1;
}
*width = (int) pwidth;
*height = (int) pheight;
rowbytes = png_get_rowbytes(structptr->png_ptr,
structptr->info_ptr);
for (pass = 0; pass < number_passes; pass++) {
rgbptr = rgba;
for (y = 0; y < *height; y++) {
png_read_rows(structptr->png_ptr,
&rgbptr,
png_bytepp_NULL, 1);
rgbptr += rowbytes;
}
}
/* I believe I can supply NULL for info_ptr here,
* maybe I don't even need to call it? */
#if 0
png_read_end(structptr->png_ptr,
structptr->info_ptr);
#endif
#if 0
png_read_end(structptr->png_ptr, NULL);
#endif
/* Hmm, png_init_destroy says it frees and resets
the
* info ptr, older png documentation (in png man
page) says
* this function can be used if you want to reuse
the png ptr.
* But we get decompress errors if we don't init
with png_read_init_3(),
* called above. Is there another way?, that
function is deprecated. */
png_read_destroy(structptr->png_ptr,
structptr->info_ptr, NULL);
return 0;
}
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection
around
http://mail.yahoo.com
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web
services, security?
Get stuff done quickly with pre-integrated technology to
make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on
Apache Geronimo
http://sel.as-us.falkag.net/
sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
png-mng-implement mailing list
png-mng-implement lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/png-m
ng-implement
|