将字节数组(从内存)加载到 LibPNG C++

Loading byte array (from memory) to LibPNG c++

我尝试使用 'png_set_read_fn' 而不是使用 'png_init_io' 来提供自定义函数以从内存而不是从文件加载字节数组。

为什么会发生这种情况。它似乎在以下位置失败:

if (setjmp(png_jmpbuf(png_ctx)) != 0)
{
    png_destroy_read_struct(&png_ctx, &info_ctx, NULL);
    free(img_data); free(row_data);

    return (1); /* libpng feedback (?) */
}

到目前为止,这是我的代码,PNG 数据在文件末尾

#ifndef __EMBEDDEDPNG_H__
#define __EMBEDDEDPNG_H__

#include <png.h>

typedef struct {
    const png_byte* data;
    const png_size_t size;
} DataHandle;

typedef struct {
    const DataHandle data;
    png_size_t offset;
} ReadDataHandle;

#include <GL/gl.h>

#include <algorithm>

#define PNG_SIG_BYTES (8) /* bytes in the PNG file signature. */

using byte = unsigned char;

#define PNG_RGBA_PIXEL_LIMIT (0x1000000)
static int
png_rgba_pixel_limit(png_uint_32 w, png_uint_32 h)
{
    double da;

    /* assert(w != 0 && h != 0); */

    if (w > PNG_RGBA_PIXEL_LIMIT || h > PNG_RGBA_PIXEL_LIMIT)
        return (1); /* since both (w) and (h) are non-zero. */

                    /* since an IEEE-754 double has a 53 bit mantissa, it can
                    * represent the maximum area: (w * h == 2^48) exactly. */

    da = ((double)w) * ((double)h);

    if (da > ((double)PNG_RGBA_PIXEL_LIMIT))
        return (1);

    return (0); /* the PNG image is within the pixel limit. */
}

class EmbeddedPNG
{
public:

    byte *Data;

public:
    size_t Read(byte* dest, const size_t byteCount);

    unsigned int Load(int &width, int &height);
};

void ReadDataFromInputStream(
    png_structp png_ptr, png_byte* raw_data, png_size_t read_length) {

    ReadDataHandle* handle = (ReadDataHandle*)png_get_io_ptr(png_ptr);
    const png_byte* png_src = handle->data.data + handle->offset;

    memcpy(raw_data, png_src, read_length);
    handle->offset += read_length;
}


size_t EmbeddedPNG::Read(byte* dest, const size_t byteCount)
{
    std::copy(Data + 0, Data + byteCount, dest);
    return byteCount;
}


unsigned int EmbeddedPNG::Load(int &width, int &height)
{

    png_byte magic[PNG_SIG_BYTES]; /* (signature byte buffer) */

    png_structp png_ctx;
    png_infop info_ctx;

    png_uint_32 img_width, img_height, row;
    png_byte img_depth, img_color_type;

    /* 'volatile' qualifier forces reload in setjmp cleanup: */

    png_byte *volatile img_data = NULL;
    png_bytep *volatile row_data = NULL;

    ;//*buf = NULL;


     /* it is assumed that 'longjmp' can be invoked within this
     * code to efficiently unwind resources for *all* errors. */

     /* PNG structures and resource unwinding: */

    if ((png_ctx = png_create_read_struct(
        PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL)
        return (1); /* ENOMEM (?) */

    if ((info_ctx = png_create_info_struct(png_ctx)) == NULL)
    {
        png_destroy_read_struct(&png_ctx, NULL, NULL);
        return (1); /* ENOMEM (?) */
    }

    if (setjmp(png_jmpbuf(png_ctx)) != 0)
    {
        png_destroy_read_struct(&png_ctx, &info_ctx, NULL);
        free(img_data); free(row_data);

        return (1); /* libpng feedback (?) */
    }


    /* check PNG file signature: */

    //if (fread(magic, (1), PNG_SIG_BYTES, fp) != PNG_SIG_BYTES)
    //  png_error(png_ctx, "invalid PNG file");

    Read(magic, PNG_SIG_BYTES);

    if (png_sig_cmp(magic, 0, PNG_SIG_BYTES))
        png_error(png_ctx, "invalid PNG file");


    /* set the input file stream and get the PNG image info: */

    //png_init_io(png_ctx, fp);

    ReadDataHandle a = ReadDataHandle{ { Data, 898 }, 0 };


    png_set_read_fn(png_ctx, &a, ReadDataFromInputStream);

    //png_set_read_fn(png_ptr, NULL, ReadDataFromInputStream);

    png_set_sig_bytes(png_ctx, PNG_SIG_BYTES);

    //////////////// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    png_read_info(png_ctx, info_ctx);

    img_width = png_get_image_width(png_ctx, info_ctx);
    img_height = png_get_image_height(png_ctx, info_ctx);

#if (1) /* PNG doesn't support zero area image? */

    if (img_width == 0 || img_height == 0)
        png_error(png_ctx, "zero area PNG image");
#endif

    if (png_rgba_pixel_limit(img_width, img_height))
        png_error(png_ctx, "PNG image exceeds pixel limits");

    img_depth = png_get_bit_depth(png_ctx, info_ctx);
    img_color_type = png_get_color_type(png_ctx, info_ctx);

    /* ignored image interlacing, compression and filtering. */

    /* force 8-bit color channels: */

    if (img_depth == 16)
        png_set_strip_16(png_ctx);

    else if (img_depth < 8)
        png_set_packing(png_ctx);

    /* force formats to RGB: */

    if (img_color_type != PNG_COLOR_TYPE_RGBA)
        png_set_expand(png_ctx);

    if (img_color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ctx);

    if (img_color_type == PNG_COLOR_TYPE_GRAY)
        png_set_gray_to_rgb(png_ctx);

    if (img_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ctx);

    /* add full opacity alpha channel if required: */

    if (img_color_type != PNG_COLOR_TYPE_RGBA)
        png_set_filler(png_ctx, 0xff, PNG_FILLER_AFTER);

    /* apply the output transforms before reading image data: */

    png_read_update_info(png_ctx, info_ctx);


    /* allocate RGBA image data: */

    img_data = (png_byte *)
        malloc((size_t)(img_width * img_height * (4)));

    if (img_data == NULL)
        png_error(png_ctx, "error allocating image buffer");

    /* allocate row pointers: */

    row_data = (png_bytep *)
        malloc((size_t)(img_height * sizeof(png_bytep)));

    if (row_data == NULL)
        png_error(png_ctx, "error allocating row pointers");

    /* set the row pointers and read the RGBA image data: */

    for (row = 0; row < img_height; row++)
        row_data[row] = img_data +
        (img_height - (row + 1)) * (img_width * (4));

    png_read_image(png_ctx, row_data);

    /* libpng and dynamic resource unwinding: */

    png_read_end(png_ctx, NULL);
    png_destroy_read_struct(&png_ctx, &info_ctx, NULL);

    free(row_data);

    //*w = (unsigned) img_width, *h = (unsigned) img_height;
    width = img_width;
    height = img_height;
    //*buf = img_data; /* (asserts png_byte is an unsigned char) */

    //Now generate the OpenGL texture object
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Important!


    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
        GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)img_data);


        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);



    return texture;
}


class EmbeddedPNG_Icon_HandShake
    : public EmbeddedPNG
{
public:
    EmbeddedPNG_Icon_HandShake()
    {
        Data = new byte[898]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x04, 0x00, 0x00, 0x00, 0xD9, 0x73, 0xB2, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4D, 0x00, 0x00, 0x7A, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x80, 0xE8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xEA, 0x60, 0x00, 0x00, 0x3A, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9C, 0xBA, 0x51, 0x3C, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4B, 0x47, 0x44, 0x00, 0x00, 0xAA, 0x8D, 0x23, 0x32, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0D, 0xD7, 0x00, 0x00, 0x0D, 0xD7, 0x01, 0x42, 0x28, 0x9B, 0x78, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xE1, 0x05, 0x1D, 0x15, 0x3A, 0x07, 0xDA, 0x7F, 0x48, 0xF4, 0x00, 0x00, 0x02, 0x50, 0x49, 0x44, 0x41, 0x54, 0x48, 0xC7, 0xD5, 0xD3, 0x4B, 0x68, 0x94, 0x57, 0x18, 0x06, 0xE0, 0x6F, 0x4C, 0x0C, 0x9A, 0xE2, 0x2D, 0x1A, 0xD1, 0x8A, 0x44, 0x57, 0x5A, 0xCD, 0xA2, 0xA8, 0xB1, 0x20, 0x8A, 0x97, 0x95, 0x08, 0x8A, 0x5D, 0xB4, 0x44, 0xC4, 0x8D, 0x08, 0xB6, 0x12, 0x21, 0x04, 0x84, 0xA2, 0x20, 0x48, 0xBB, 0xE8, 0xA2, 0x8B, 0x6E, 0x5A, 0x6C, 0xAD, 0x45, 0xB0, 0x14, 0x06, 0xB4, 0xA8, 0x64, 0x61, 0x16, 0x82, 0x08, 0x46, 0x4A, 0xB5, 0x68, 0x5C, 0x18, 0x35, 0xE8, 0xAC, 0x92, 0x8A, 0xA0, 0x62, 0xEE, 0x66, 0xC8, 0xD3, 0x45, 0x7E, 0xC7, 0xC9, 0xDC, 0x12, 0xBA, 0x28, 0xF8, 0xAD, 0x0E, 0x67, 0xCE, 0xFB, 0xF0, 0xFE, 0xE7, 0xFF, 0x27, 0xE2, 0x3D, 0x1A, 0xCB, 0x7C, 0xE7, 0x86, 0x83, 0x52, 0x53, 0x1D, 0x4C, 0x59, 0xA5, 0xD1, 0x5A, 0xB3, 0x26, 0xED, 0xAE, 0x90, 0xF1, 0xDC, 0x15, 0xFC, 0x58, 0x81, 0x50, 0xAD, 0x4D, 0x8F, 0x89, 0xC9, 0x7A, 0x20, 0xED, 0x84, 0xDD, 0x1A, 0x7C, 0xA0, 0x47, 0x9F, 0xD5, 0x11, 0xBE, 0xAA, 0x40, 0x98, 0xE9, 0x0F, 0x59, 0x69, 0xBB, 0x6D, 0xB5, 0xCB, 0x31, 0xE7, 0xDD, 0x35, 0x0A, 0x46, 0xB1, 0x31, 0x39, 0x55, 0x9E, 0xF0, 0x83, 0x37, 0x3E, 0x2D, 0xEA, 0xB4, 0x56, 0xB3, 0x8B, 0x68, 0xCD, 0xED, 0x95, 0x26, 0x2C, 0x34, 0xE4, 0x54, 0x99, 0x47, 0x9B, 0xE1, 0x37, 0xE3, 0xBE, 0xAC, 0x48, 0x68, 0x95, 0xF5, 0x61, 0xB2, 0xAE, 0x29, 0x22, 0xAA, 0xA6, 0x24, 0xA4, 0xDD, 0x4B, 0x56, 0x4D, 0x06, 0x0C, 0xCB, 0xF8, 0x53, 0x5A, 0x43, 0x45, 0xA2, 0x35, 0x1F, 0xB8, 0xE5, 0x62, 0xB2, 0xFA, 0xC6, 0x80, 0xAF, 0xFD, 0xEC, 0x92, 0xE7, 0x9E, 0x96, 0x26, 0x1C, 0x50, 0xED, 0xAC, 0xC7, 0x61, 0xA9, 0xDA, 0xE4, 0xE7, 0xAB, 0x1E, 0x4A, 0x45, 0x98, 0xED, 0x91, 0x6B, 0xC9, 0xDE, 0x6A, 0x7D, 0x32, 0x56, 0x14, 0x12, 0x6A, 0x9C, 0xD6, 0xE0, 0xB6, 0x8E, 0xD0, 0xE9, 0x6F, 0x75, 0x11, 0x11, 0xF6, 0xE2, 0xBA, 0x16, 0x1D, 0xD8, 0x93, 0x8B, 0x94, 0x23, 0xE6, 0xEA, 0x34, 0x62, 0x4B, 0xD8, 0xAC, 0x3F, 0x47, 0x1C, 0xD1, 0x87, 0x7F, 0x1C, 0x9E, 0x74, 0x7D, 0xA5, 0x89, 0x1E, 0x23, 0x76, 0x4E, 0x6C, 0xE4, 0x13, 0x55, 0xE6, 0xAB, 0x2A, 0x7A, 0x03, 0x85, 0xC4, 0x02, 0x2F, 0x73, 0xF1, 0x42, 0xA2, 0xCC, 0x77, 0x90, 0x47, 0x98, 0xE3, 0xD6, 0xA4, 0x78, 0x42, 0x0C, 0x4F, 0x8F, 0x30, 0xC7, 0xCD, 0xA2, 0x78, 0x84, 0x56, 0x28, 0x47, 0xA8, 0xB5, 0x47, 0x4D, 0x42, 0x74, 0x96, 0x8A, 0x7F, 0x84, 0x5F, 0xED, 0x93, 0x2D, 0x4D, 0x58, 0x22, 0xEB, 0x72, 0x42, 0x70, 0xA8, 0xF8, 0xC0, 0x51, 0x2C, 0xF6, 0x89, 0xFE, 0xE2, 0x16, 0x6A, 0xAD, 0x8C, 0xB0, 0x2F, 0x8F, 0xC8, 0xA8, 0x2F, 0x04, 0x96, 0x19, 0xD5, 0x6B, 0x50, 0x97, 0x96, 0xC2, 0x16, 0x36, 0x1B, 0x77, 0x24, 0x42, 0x73, 0x8E, 0x18, 0x72, 0xB2, 0xB8, 0x43, 0x93, 0x6B, 0xD8, 0x62, 0x9E, 0xEE, 0x77, 0x2D, 0x54, 0x99, 0x29, 0xE5, 0x34, 0x5A, 0x22, 0x7C, 0x6E, 0xCC, 0x15, 0xDB, 0xBC, 0x70, 0xBE, 0xD4, 0x45, 0xD5, 0x19, 0x70, 0x5F, 0xB7, 0x01, 0xDF, 0xBE, 0x6D, 0xE1, 0x0B, 0xAF, 0x6C, 0x94, 0xF2, 0x13, 0x8E, 0x46, 0xF8, 0x0C, 0x8C, 0xD8, 0x54, 0xFA, 0x45, 0x6D, 0xF7, 0x17, 0xF6, 0x47, 0xE8, 0x98, 0x68, 0xA1, 0x5E, 0x97, 0x57, 0x36, 0x48, 0x39, 0x83, 0x36, 0x4B, 0x3C, 0x73, 0xA9, 0xE8, 0x06, 0x26, 0x5D, 0xD8, 0x33, 0x37, 0x5C, 0x40, 0x7A, 0xA2, 0x85, 0x7A, 0x5D, 0x5E, 0x5A, 0x2F, 0xE5, 0x2C, 0x18, 0xB7, 0x26, 0x2A, 0x8D, 0x1D, 0xBA, 0xF1, 0x4B, 0x84, 0xEF, 0xF3, 0x5A, 0xBC, 0xB0, 0xCE, 0xC7, 0x68, 0xB7, 0x2A, 0xA6, 0x1A, 0xD5, 0x9E, 0xE8, 0x74, 0xDC, 0xA8, 0x9B, 0xFA, 0xDD, 0xB1, 0x40, 0xBD, 0x2E, 0x83, 0xBA, 0x8D, 0x59, 0x3E, 0x65, 0x3C, 0x22, 0xC2, 0x4E, 0x19, 0x63, 0x7E, 0x37, 0xFB, 0xED, 0x7F, 0x44, 0x33, 0xDA, 0x35, 0x4D, 0x2B, 0x1E, 0x11, 0x61, 0x86, 0x45, 0xB9, 0xAF, 0xA0, 0x5F, 0xAF, 0x8C, 0xD7, 0xE6, 0x4E, 0x3B, 0x5E, 0x80, 0x35, 0x3A, 0xA7, 0xDD, 0x8E, 0xFF, 0x18, 0xFF, 0x1F, 0xE6, 0x5F, 0x1F, 0xA9, 0x98, 0xCC, 0x0D, 0x77, 0xF1, 0x32, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x30, 0x35, 0x2D, 0x32, 0x39, 0x54, 0x32, 0x31, 0x3A, 0x35, 0x38, 0x3A, 0x30, 0x37, 0x2B, 0x30, 0x32, 0x3A, 0x30, 0x30, 0x19, 0xBB, 0x75, 0xB7, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x6D, 0x6F, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x30, 0x35, 0x2D, 0x32, 0x39, 0x54, 0x32, 0x31, 0x3A, 0x35, 0x38, 0x3A, 0x30, 0x37, 0x2B, 0x30, 0x32, 0x3A, 0x30, 0x30, 0x68, 0xE6, 0xCD, 0x0B, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
    }
};

#endif

不要打电话

png_set_sig_bytes(png_ctx, PNG_SIG_BYTES);

这表明 libpng 跳过读取签名字节,导致您的 offset 在您开始读取 png 数据时出错。 Offset 指向零,libpng 假定它已经是 8(或者更准确地说,流中没有签名)。

来源:我运行这是通过调试器实现的。