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

问题描述

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

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

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

解决方法

我想出了如何做这件事。我使用 pix 代替 row_pointers 数组来存储我的颜色编号,如果需要,您可以创建一些函数将 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); //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;
}