List Info

Thread: reusing png_ptr to decode multiple images




reusing png_ptr to decode multiple images
user name
2006-05-11 19:19:10
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-implementlists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/png-m
ng-implement
reusing png_ptr to decode multiple images
user name
2006-05-13 14:47:51
At 12:19 PM 5/11/2006 -0700, brandon casey wrote:

>I would also like to reuse the read_struct and
>info_struct instead of freeing them and re-allocating
>for every image.

I think you are wasting your time even thinking about that.

Run "pngtest -v pngtest.png pngtest.out" and
look at the memory
activity that happens with a simple copy of a small image:

 Current memory allocation:          0 bytes
 Maximum memory allocation:     331262 bytes
 Total   memory allocation:    1523040 bytes
     Number of allocations:       1614
libpng passes test

If you succeed in reusing the read_struct and info_struct,
you will
have 1612 allocations instead of 1614, and save perhaps 800
bytes
of allocation.

Glenn



-------------------------------------------------------
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-implementlists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/png-m
ng-implement
reusing png_ptr to decode multiple images
user name
2006-05-16 14:52:24

--- Glenn Randers-Pehrson <glennrpcomcast.net> wrote:

> At 12:19 PM 5/11/2006 -0700, brandon casey wrote:
> 
> >I would also like to reuse the read_struct and
> >info_struct instead of freeing them and
> re-allocating
> >for every image.
> 
> I think you are wasting your time even thinking
> about that.
> 
> Run "pngtest -v pngtest.png pngtest.out"
and look at
> the memory
> activity that happens with a simple copy of a small
> image:
> 
>  Current memory allocation:          0 bytes
>  Maximum memory allocation:     331262 bytes
>  Total   memory allocation:    1523040 bytes
>      Number of allocations:       1614
> libpng passes test
> 
> If you succeed in reusing the read_struct and
> info_struct, you will
> have 1612 allocations instead of 1614, and save
> perhaps 800 bytes
> of allocation.
> 
> Glenn

Ok.

In the case of this program I wish I could turn off
malloc's ability to return memory to the system
since I know that it will be required again. Just
trying to squeeze every last bit of efficiency out.

thanks,
-brandon

__________________________________________________
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-implementlists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/png-m
ng-implement
[1-3]

about | contact  Other archives ( Real Estate discussion Medical topics )