如何使用 libpng 将 C 代码中的 png 图像解码为原始字节?

发布于 2024-08-03 08:17:51 字数 90 浏览 2 评论 0原文

我正在寻找一种解码某些 png 文件的方法,我听说过 libpng,但我不明白它是如何工作的。它将 png 文件转换为 ARGB8888 格式的字节数组还是其他格式?

I'm looking for a way to decode some png file, I heard about libpng, but I don't understand how this one works. Does it convert the png file into an array of bytes in the ARGB8888 format or something else ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无言温柔 2024-08-10 08:17:51

可运行示例

此示例读取现有 PNG,对其进行修改,然后将修改后的版本写入磁盘。

修改部分是在原始字节上完成的。

用法:

./a.out [<old-png> [<new-png>]]
  • old-png 默认为 a.png
  • new-png 默认为 b.png

在 Ubuntu 18.04 上测试,libpng 1.6.34,编译为:

gcc -std=c99 main.c -lpng

改编自:https://gist.github.com/niw/ 5963798

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <png.h>

unsigned int width;
unsigned int height;
png_bytep *row_pointers;

static void read_png_file(char *filename) {
    FILE *fp = fopen(filename, "rb");
    png_byte bit_depth;
    png_byte color_type;
    unsigned int y;

    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png) abort();
    png_infop info = png_create_info_struct(png);
    if (!info) abort();
    if (setjmp(png_jmpbuf(png))) abort();
    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);
    /* Read any color_type into 8bit depth, RGBA format. */
    /* See http://www.libpng.org/pub/png/libpng-manual.txt */
    if (bit_depth == 16)
        png_set_strip_16(png);
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png);
    /* PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. */
    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);
    /* These color_type don't have an alpha channel then fill it with 0xff. */
    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);
    row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
    for (y = 0; y < height; y++) {
        row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
    }
    png_read_image(png, row_pointers);
    fclose(fp);
}

static void write_png_file(char *filename) {
    unsigned int y;
    FILE *fp = fopen(filename, "wb");
    if (!fp) abort();
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png) abort();
    png_infop info = png_create_info_struct(png);
    if (!info) abort();
    if (setjmp(png_jmpbuf(png))) abort();
    png_init_io(png, fp);
    png_set_IHDR(
        png,
        info,
        width,
        height,
        8,
        PNG_COLOR_TYPE_RGBA,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT
    );
    png_write_info(png, info);
    /* To remove the alpha channel for PNG_COLOR_TYPE_RGB format, */
    /* Use png_set_filler(). */
    /*png_set_filler(png, 0, PNG_FILLER_AFTER);*/
    png_write_image(png, row_pointers);
    png_write_end(png, NULL);
    for (y = 0; y < height; y++) {
        free(row_pointers[y]);
    }
    free(row_pointers);
    fclose(fp);
}

static void process_png(void) {
    for (unsigned int y = 0; y < height; y++) {
        png_bytep row = row_pointers[y];
        for (unsigned int x = 0; x < width; x++) {
            png_bytep px = &(row[x * 4]);
            /*printf("%4d, %4d = RGBA(%3d, %3d, %3d, %3d)\n", x, y, px[0], px[1], px[2], px[3]);*/
            png_byte old[4 * sizeof(png_byte)];
            memcpy(old, px, sizeof(old));
            px[0] = 255 - old[0];
            px[1] = 255 - old[1];
            px[2] = 255 - old[2];
        }
    }
}

int main(int argc, char *argv[]) {
    char *in;
    char *out;
    if (argc > 1) {
        in = argv[1];
    } else {
        in = "a.png";
    }
    if (argc > 2) {
        out = argv[2];
    } else {
        out = "b.png";
    }
    read_png_file(in);
    process_png();
    write_png_file(out);
    return EXIT_SUCCESS;
}

a.png

在此处输入图像描述

b.png

在此处输入图像描述

图片来源:https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Catherine_of_Aragon.png/430px -Catherine_of_Aragon.png

Runnable example

This example reads and existing PNG, modifies it, and writes a modified version to disk.

The modification part is done on raw bytes.

Usage:

./a.out [<old-png> [<new-png>]]
  • old-png defaults to a.png
  • new-png defaults to b.png

Tested on Ubuntu 18.04, libpng 1.6.34, compile with:

gcc -std=c99 main.c -lpng

Adapted from: https://gist.github.com/niw/5963798

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <png.h>

unsigned int width;
unsigned int height;
png_bytep *row_pointers;

static void read_png_file(char *filename) {
    FILE *fp = fopen(filename, "rb");
    png_byte bit_depth;
    png_byte color_type;
    unsigned int y;

    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png) abort();
    png_infop info = png_create_info_struct(png);
    if (!info) abort();
    if (setjmp(png_jmpbuf(png))) abort();
    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);
    /* Read any color_type into 8bit depth, RGBA format. */
    /* See http://www.libpng.org/pub/png/libpng-manual.txt */
    if (bit_depth == 16)
        png_set_strip_16(png);
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png);
    /* PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. */
    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);
    /* These color_type don't have an alpha channel then fill it with 0xff. */
    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);
    row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
    for (y = 0; y < height; y++) {
        row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
    }
    png_read_image(png, row_pointers);
    fclose(fp);
}

static void write_png_file(char *filename) {
    unsigned int y;
    FILE *fp = fopen(filename, "wb");
    if (!fp) abort();
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png) abort();
    png_infop info = png_create_info_struct(png);
    if (!info) abort();
    if (setjmp(png_jmpbuf(png))) abort();
    png_init_io(png, fp);
    png_set_IHDR(
        png,
        info,
        width,
        height,
        8,
        PNG_COLOR_TYPE_RGBA,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT
    );
    png_write_info(png, info);
    /* To remove the alpha channel for PNG_COLOR_TYPE_RGB format, */
    /* Use png_set_filler(). */
    /*png_set_filler(png, 0, PNG_FILLER_AFTER);*/
    png_write_image(png, row_pointers);
    png_write_end(png, NULL);
    for (y = 0; y < height; y++) {
        free(row_pointers[y]);
    }
    free(row_pointers);
    fclose(fp);
}

static void process_png(void) {
    for (unsigned int y = 0; y < height; y++) {
        png_bytep row = row_pointers[y];
        for (unsigned int x = 0; x < width; x++) {
            png_bytep px = &(row[x * 4]);
            /*printf("%4d, %4d = RGBA(%3d, %3d, %3d, %3d)\n", x, y, px[0], px[1], px[2], px[3]);*/
            png_byte old[4 * sizeof(png_byte)];
            memcpy(old, px, sizeof(old));
            px[0] = 255 - old[0];
            px[1] = 255 - old[1];
            px[2] = 255 - old[2];
        }
    }
}

int main(int argc, char *argv[]) {
    char *in;
    char *out;
    if (argc > 1) {
        in = argv[1];
    } else {
        in = "a.png";
    }
    if (argc > 2) {
        out = argv[2];
    } else {
        out = "b.png";
    }
    read_png_file(in);
    process_png();
    write_png_file(out);
    return EXIT_SUCCESS;
}

a.png

enter image description here

b.png

enter image description here

Image source: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Catherine_of_Aragon.png/430px-Catherine_of_Aragon.png

空宴 2024-08-10 08:17:51

您可能最好查看专用的图像库,它将为您解码图像并返回它处于公认的结构中。当您想对图像进行实际操作(保存、显示等)时,它也将作为一个更好的平台。

You might be better off looking at a dedicated image library that will decode the image for you and return it in a recognised structure. It'll also serve as a better platform when you want to actually do something with the image (saving, displaying, etc).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文