使用 libpng 从内存中的数字数组创建 png 图像

Create png image from array of numbers in memory using libpng

我想转换存储在内存中的字节,如

// 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
libpng 的帮助下

到 png 图像。 但我还没有找到任何合适的功能来做到这一点。所以,我正在寻找类似的功能 png_bitmap_to_png(void *bitmap, void* png_raw_bytes)。 如果您有其他关于如何将字节数组转换为 png 图像的想法,我很高兴听到他们的意见,但如果没有必要,请不要提供其他库或转换器(如 ImageMagick)的使用。

我知道怎么做了。我使用 row_pointers 存储我的颜色编号而不是 pix 数组,如果需要,您可以创建一些函数将 pix 数组转换为 row_pointers。这是我的代码,希望对您有所帮助

#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;
}