blob: 63998f4a1ae4d47417c553b878c5290e517b9c60 [file] [log] [blame]
#ifdef RIVE_RENDERER_TESS
#include "viewer/tess/bitmap_decoder.hpp"
#include "png.h"
struct EncodedImageBuffer
{
const uint8_t* bytes;
size_t position;
size_t size;
};
static void ReadDataFromMemory(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead)
{
png_voidp a = png_get_io_ptr(png_ptr);
if (a == nullptr)
{
return;
}
EncodedImageBuffer& stream = *(EncodedImageBuffer*)a;
size_t bytesRead = std::min(byteCountToRead, (stream.size - stream.position));
memcpy(outBytes, stream.bytes + stream.position, bytesRead);
stream.position += bytesRead;
if ((png_size_t)bytesRead != byteCountToRead)
{
// Report image error?
}
}
std::unique_ptr<Bitmap> DecodePng(rive::Span<const uint8_t> bytes)
{
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png_ptr == nullptr)
{
printf("DecodePng - libpng failed (png_create_read_struct).");
return nullptr;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
printf("DecodePng - libpng failed (png_create_info_struct).");
return nullptr;
}
EncodedImageBuffer stream = {
.bytes = bytes.data(),
.size = bytes.size(),
.position = 0,
};
png_set_read_fn(png_ptr, &stream, ReadDataFromMemory);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr,
info_ptr,
&width,
&height,
&bit_depth,
&color_type,
&interlace_type,
NULL,
NULL);
png_set_strip_16(png_ptr);
int bitDepth = 0;
if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_RGB)
{
png_set_expand(png_ptr);
bitDepth = 24;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_expand(png_ptr);
bitDepth += 8;
}
}
else if (color_type == PNG_COLOR_TYPE_GRAY)
{
png_set_expand(png_ptr);
bitDepth = 8;
}
else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_expand(png_ptr);
png_set_gray_to_rgb(png_ptr);
bitDepth = 32;
}
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_set_expand(png_ptr);
bitDepth = 32;
}
int pixelBytes = bitDepth / 8;
auto pixelBuffer = new uint8_t[width * height * pixelBytes];
png_bytep* row_pointers = new png_bytep[height];
for (unsigned row = 0; row < height; row++)
{
unsigned int rIndex = row;
// if (flipY) {
// rIndex = height - row - 1;
// }
row_pointers[rIndex] = pixelBuffer + (row * (width * pixelBytes));
}
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr);
delete[] row_pointers;
Bitmap::PixelFormat pixelFormat;
assert(bitDepth == 32 || bitDepth == 24 || bitDepth == 8);
switch (bitDepth)
{
case 32:
pixelFormat = Bitmap::PixelFormat::RGBA;
break;
case 24:
pixelFormat = Bitmap::PixelFormat::RGB;
break;
case 8:
pixelFormat = Bitmap::PixelFormat::R;
break;
}
return rivestd::make_unique<Bitmap>(width, height, pixelFormat, pixelBuffer);
}
#endif