iDevGames Forums
Trouble writing PNGs with 16 bits per channel using libpng - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Graphics & Audio Programming (/forum-9.html)
+--- Thread: Trouble writing PNGs with 16 bits per channel using libpng (/thread-3946.html)



Trouble writing PNGs with 16 bits per channel using libpng - flash - Aug 27, 2006 06:17 AM

I've been working on a more sophisticated height map implementation (hopefully on the way to proper bump mapping) and I've been using PNGs with the red channel as the height data and the green, blue and alpha channels as the x,y and z components of the normals for each vertex.

I wrote a program to read in an image, calculate the normals and write out such a PNG. I got it all working using 8bit precision and it looks ok, but not as good as calculating the normals in the rendering program at higher precision. So I converted my program to use a 16bit colour depth and it works up til writing out the PNG at which point gdb says:

mi_cmd_stack_list_frames: Not enough frames in stack.

This is in png_malloc when in png_create_write_struct2 it seems.

I'm using a test image of 16x16 (the 8bit program works with 512x512 ) so I find it hard to believe there really isn't enough space on the stack, butI'd freely admit I don't really understand what's going on.

My write function is here:

Code:
bool PNGLoader::writePNG16File(const string file_name, short* image_data, int width, int height, int bits_per_channel)
{
    if(bits_per_channel!=16)
    {
#ifdef IVORDEBUG_PNG
        printf("PNGLoader:writePNGFile: bits per channel must be 8 or 16!\n", file_name.c_str());
#endif
        return false;
    }
    
    // open file
    FILE *fp = fopen(file_name.c_str(), "wb");
    if (!fp)
    {
#ifdef IVORDEBUG_PNG
        printf("PNGLoader:writePNGFile: File %s could not be opened for writing.\n", file_name.c_str());
#endif
        fclose(fp);
        return false;
    }
    
    write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!write_ptr)
    {
#ifdef IVORDEBUG_PNG
        cout <<"PNGLoader:writePNGFile: write_ptr not created.\n";
#endif
        fclose(fp);
        return false;
    }
    info_ptr = png_create_info_struct(write_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&write_ptr, (png_infopp)NULL);
#ifdef IVORDEBUG_PNG
        printf("PNGLoader:writePNGFile: could not create info_ptr.\n", file_name.c_str());
#endif
        fclose(fp);
        return false;
    }
    
    if (setjmp(png_jmpbuf(write_ptr)))
    {     // on an error libpng needs to know where to jump back to
#ifdef IVORDEBUG_PNG
        printf("PNGLoader:writePNGFile: Error during init_io");
#endif
        fclose(fp);
        return false;
    }
    
    png_init_io(write_ptr, fp);
    
       /* turn on or off filtering, and/or choose
        specific filters.  You can use either a single
        PNG_FILTER_VALUE_NAME or the logical OR of one
        or more PNG_FILTER_NAME masks. */
    png_set_filter(write_ptr, 0, PNG_FILTER_NONE);
    
    // set the zlib compression level
    png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
    
    png_set_IHDR(write_ptr, info_ptr, width, height,
                 bits_per_channel, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    
    row_pointers = (png_byte**) png_malloc(write_ptr, height*sizeof(png_bytep));
    for (int i=0; i<height; i++)
        row_pointers[i]= (png_byte*) png_malloc(write_ptr, width*4*sizeof(short));
    
    // flips image vertically - back from how opengl likes it
    for(int i=0;i<height;i++)
        for(int j=0;j<width*4;j++)
        {
            row_pointers[height-i-1][j] = image_data[(i*width*4+j)*sizeof(short)];
        }
            png_set_rows(write_ptr, info_ptr, row_pointers);
    
    png_write_png(write_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL);    // PNG_TRANSFORM_SWAP_ENDIAN
    
    
#ifdef IVORDEBUG_PNG
    cout << "PNG Written\n";
#endif
    return true; // success    
}

Any help most appreciated - sorry for the rather long post.


Trouble writing PNGs with 16 bits per channel using libpng - Frogblast - Aug 27, 2006 01:30 PM

Post the code that calls this function. Specifically, how do you allocate the buffer pointed to by image_data?


Trouble writing PNGs with 16 bits per channel using libpng - flash - Aug 28, 2006 11:01 AM

I actually got it working - I was overrunning an array way back in the code. Now it seems I'm not getting all 16 bits when I read a PNG. I'll just have to keep hacking I suppose...