Search code examples
arrayscbitmappnglibpng

Create png image from array of numbers in memory using libpng


I want to convert bytes that is stored in memory like

// pix is array of bytes with format format R, G, B, A, R, G, B, A, ...
// further image is going to be 250x300, so size is 250*300*4
char pix[250*300*4] = {
0, 255, 0, 0, //1
0, 255, 0, 0, //2
...
0, 255, 0, 0  //250*300
} // green image

to png image with help of libpng. But I have not found any suitable function to do this. So, I am seeking for function like png_bitmap_to_png(void *bitmap, void* png_raw_bytes). If you have other ideas how to convert byte array to png image I am glad to hear them but do not offer usage of other libraries or converters like ImageMagick if it is not necessary, please.


Solution

  • I figured out how to do the thing. Instead of pix array I used row_pointers to store my color numbers, you may create some function to convert pix array to row_pointers if you want. Here is my code, I hope it will help

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <png.h>
    
    #define IMAGE_HEIGHT 250
    #define IMAGE_WIDTH 300
    #define IMAGE_RED_COLOR 0
    #define IMAGE_GREEN_COLOR 255
    #define IMAGE_BLUE_COLOR 0
    #define IMAGE_ALPHA_CHANNEL 255
    
    
    void write_png_image(char* filename)
    {
        png_byte** row_pointers; // pointer to image bytes
        FILE* fp; // file for image
    
        do // one time do-while to properly free memory and close file after error
        {
            row_pointers = (png_byte**)malloc(sizeof(png_byte*) * IMAGE_HEIGHT);
            if (!row_pointers)
            {
                printf("Allocation failed\n");
                break;
            }
            for (int i = 0; i < IMAGE_HEIGHT; i++)
            {
                row_pointers[i] = (png_byte*)malloc(4*IMAGE_WIDTH);
                if (!row_pointers[i])
                {
                    printf("Allocation failed\n");
                    break;
                }
            }
            // fill image with color
            for (int y = 0; y < IMAGE_HEIGHT; y++)
            {
                for (int x = 0; x < IMAGE_WIDTH*4; x+=4)
                {
                    row_pointers[y][x] = IMAGE_RED_COLOR; //r
                    row_pointers[y][x + 1] = IMAGE_GREEN_COLOR; //g
                    row_pointers[y][x + 2] = IMAGE_BLUE_COLOR; //b
                    row_pointers[y][x + 3] = IMAGE_ALPHA_CHANNEL; //a
                }
            }
            //printf("%d %d %d %d\n", row_pointers[0][0], row_pointers[0][1], row_pointers[0][2], row_pointers[0][3]);
    
            fp = fopen(filename, "wb"); //create file for output
            if (!fp)
            {
                printf("Open file failed\n");
                break;
            }
            png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //create structure for write
            if (!png)
            {
                printf("Create write struct failed\n");
                break;
            }
            png_infop info = png_create_info_struct(png); // create info structure
            if (!info)
            {
                printf("Create info struct failed\n");
                break;
            }
            if (setjmp(png_jmpbuf(png))) // this is some routine for errors?
            {
                printf("setjmp failed\n");
            }
            png_init_io(png, fp); //initialize file output
            png_set_IHDR( //set image properties
                png, //pointer to png_struct
                info, //pointer to info_struct
                IMAGE_WIDTH, //image width
                IMAGE_HEIGHT, //image height
                8, //color depth
                PNG_COLOR_TYPE_RGBA, //color type
                PNG_INTERLACE_NONE, //interlace type
                PNG_COMPRESSION_TYPE_DEFAULT, //compression type
                PNG_FILTER_TYPE_DEFAULT //filter type
                );
            png_write_info(png, info); //write png image information to file
            png_write_image(png, row_pointers); //the thing we gathered here for
            png_write_end(png, NULL);
            printf("Image was created successfully\nCheck %s file\n", filename);
        } while(0);
        //close file
        if (fp)
        {
            fclose(fp);
        }
        //free allocated memory
        for (int i = 0; i < IMAGE_HEIGHT; i++)
        {
            if (row_pointers[i])
            {
                free(row_pointers[i]);
            }
        }
        if (row_pointers)
        {
            free(row_pointers);
        }
    }
    
    int main(int argc, char* argv[])
    {
        if(argc == 2)
        {
            write_png_image(argv[1]);
        }
        else
        {
            printf("Usage: %s pngfile.png\n", argv[0]);
        }
        
        return 0;
    }