Search code examples
c++cimageimage-processinglibpng

How to get an image char array by using libpng?


Although I have successfully utilized stb_image/CImg/lodepng open source to get a char array, the memory usage is too huge that I can't implement it in a low power embedded system.

Therefore, I try to use libpng to read a png type image, and get a char array.

However, I am completely not familiar with libpng......

Anyone can help?


According to some website sample programs, I write the following function. But I encounter Segmentation Fault, I think that I have problem dealing with the variables, raw_pointers and image. Anyone can review my code and give me some suggestions?

unsigned char* read_png_file(const char *filename) 
{
    FILE *fp = fopen(filename, "rb");
    int bit_depth;
    int color_type;
    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop info = png_create_info_struct(png);
    png_init_io(png, fp);
    png_read_info(png, info);

    width = png_get_image_width(png, info);
    height = png_get_image_height(png, info);
    color_type = png_get_color_type(png, info);
    bit_depth = png_get_bit_depth(png, info);

    int numchan = 4;

    // Set up row pointers
    row_pointers = (unsigned char**) malloc(sizeof(unsigned char) * height);
    for (int y=0; y<height; y++)
        row_pointers[y] = (unsigned char*) malloc(sizeof(unsigned char) * width);
    png_read_image(png, row_pointers);

    // Put row pointers data into image
    unsigned char * image = (unsigned char *) malloc (numchan*width*height);
    for (unsigned int i=0;i<height;i++)
        for (unsigned int j=0;j<width;i++)
            *image++ = row_pointers[j][i];
    fclose(fp);

    cout << height << ", " << width << ", " << bit_depth << ", " << numchan << endl;

    return image;
}

Solution

  • I successfully use libpng to get a char array.

    However, the memory usage is up to 915.1KB which is higher than stb_image !!! (Use Valgrind)

    Ah... Could anyone tell me some directions to optimize the memory usage?

    unsigned char* read_png_file(const char *filename) 
    {
        FILE *fp = fopen(filename, "rb");
        png_byte bit_depth;
        png_byte color_type;
        png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        png_infop info = png_create_info_struct(png);
        png_init_io(png, fp);
        png_read_info(png, info);
    
        width = png_get_image_width(png, info);
        height = png_get_image_height(png, info);
        color_type = png_get_color_type(png, info);
        bit_depth = png_get_bit_depth(png, info);
    
        if(color_type == PNG_COLOR_TYPE_PALETTE)
            png_set_palette_to_rgb(png);
        if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
            png_set_expand_gray_1_2_4_to_8(png);
        if(png_get_valid(png, info, PNG_INFO_tRNS))
            png_set_tRNS_to_alpha(png);
        if(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
            png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
        if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png);
    
        png_read_update_info(png, info);
    
        int numchan = 4;
    
        // Set up row pointer
        png_bytep *row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
        unsigned int i, j;
        for (i = 0; i < height; i++)
            row_pointers[i] = (png_bytep)malloc(png_get_rowbytes(png,info));
        png_read_image(png, row_pointers);
    
        // Put row pointers data into image
        unsigned char *image = (unsigned char *) malloc (numchan*width*height);
        int count = 0;
        for (i = 0 ; i < height ; i++)
        {
            for (j = 0 ; j < numchan*width ; j++)
            {
                image[count] = row_pointers[i][j];
                count += 1;
            }
        }
        fclose(fp);
        for (i = 0; i < height; i++)
            free(row_pointers[i]) ;
        free(row_pointers) ;
    
        return image;     
    }