loaders: enhance decoding efficiency

enhance decoding efficiency by determining the desired canvas format
during image loading. This allows loaders to preemptively decode
the image in the specified format, to not convert the format again.
This commit is contained in:
Hermet Park 2024-02-07 15:02:48 +09:00
parent c4e6b03b84
commit c64ed2ec03
8 changed files with 45 additions and 21 deletions

View file

@ -126,13 +126,21 @@ bool JpgLoader::read()
if (w == 0 || h == 0) return false;
/* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB
How could we notice the renderer colorspace at this time? */
auto image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[TJPF_BGRX]);
//determine the image format
TJPF format;
if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) {
format = TJPF_BGRX;
surface.cs = ColorSpace::ARGB8888;
} else {
format = TJPF_RGBX;
surface.cs = ColorSpace::ABGR8888;
}
auto image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[format]);
if (!image) return false;
//decompress jpg image
if (tjDecompress2(jpegDecompressor, data, size, image, static_cast<int>(w), 0, static_cast<int>(h), TJPF_BGRX, 0) < 0) {
if (tjDecompress2(jpegDecompressor, data, size, image, static_cast<int>(w), 0, static_cast<int>(h), format, 0) < 0) {
TVGERR("JPG LOADER", "%s", tjGetErrorStr());
tjFree(image);
image = nullptr;
@ -145,7 +153,6 @@ bool JpgLoader::read()
surface.w = w;
surface.h = h;
surface.channelSize = sizeof(uint32_t);
surface.cs = ColorSpace::ARGB8888;
surface.premultiplied = true;
clear();

View file

@ -84,14 +84,15 @@ bool PngLoader::read()
if (w == 0 || h == 0) return false;
png_bytep buffer;
image->format = PNG_FORMAT_BGRA;
buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
if (!buffer) {
//out of memory, only time when libpng doesnt free its data
png_image_free(image);
return false;
if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) {
image->format = PNG_FORMAT_BGRA;
surface.cs = ColorSpace::ARGB8888;
} else {
image->format = PNG_FORMAT_RGBA;
surface.cs = ColorSpace::ABGR8888;
}
auto buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) {
free(buffer);
return false;
@ -103,7 +104,6 @@ bool PngLoader::read()
surface.w = (uint32_t)w;
surface.h = (uint32_t)h;
surface.channelSize = sizeof(uint32_t);
surface.cs = ColorSpace::ARGB8888;
//TODO: we can acquire a pre-multiplied image. See "png_structrp"
surface.premultiplied = false;

View file

@ -35,6 +35,8 @@ void PngLoader::run(unsigned tid)
auto width = static_cast<unsigned>(w);
auto height = static_cast<unsigned>(h);
state.info_raw.colortype = LCT_RGBA; //request this image format
if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) {
TVGERR("PNG", "Failed to decode image");
}
@ -43,6 +45,7 @@ void PngLoader::run(unsigned tid)
surface.stride = width;
surface.w = width;
surface.h = height;
surface.cs = ColorSpace::ABGR8888;
surface.channelSize = sizeof(uint32_t);
if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false;
@ -95,9 +98,6 @@ bool PngLoader::open(const string& path)
w = static_cast<float>(width);
h = static_cast<float>(height);
if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888;
else surface.cs = ColorSpace::ARGB8888;
ret = true;
goto finalize;
@ -127,8 +127,6 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
h = static_cast<float>(height);
this->size = size;
surface.cs = ColorSpace::ABGR8888;
return true;
}

View file

@ -654,6 +654,10 @@ uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
return Decode(MODE_bgrA, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
int* width, int* height) {
return Decode(MODE_rgbA, data, data_size, width, height, NULL);
}
int WebPGetInfo(const uint8_t* data, size_t data_size,
int* width, int* height) {

View file

@ -35,12 +35,17 @@ void WebpLoader::clear()
void WebpLoader::run(unsigned tid)
{
//TODO: we can figure out the requested image format in advance.
surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr);
if (surface.cs == ColorSpace::ARGB8888 || surface.cs == ColorSpace::ARGB8888S) {
surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr);
surface.cs = ColorSpace::ARGB8888;
} else {
surface.buf8 = WebPDecodeRGBA(data, size, nullptr, nullptr);
surface.cs = ColorSpace::ABGR8888;
}
surface.stride = static_cast<uint32_t>(w);
surface.w = static_cast<uint32_t>(w);
surface.h = static_cast<uint32_t>(h);
surface.cs = ColorSpace::ARGB8888;
surface.channelSize = sizeof(uint32_t);
surface.premultiplied = true;
@ -128,6 +133,8 @@ bool WebpLoader::read()
if (!data || w == 0 || h == 0) return false;
surface.cs = this->cs;
TaskScheduler::request(this);
return true;

View file

@ -68,6 +68,8 @@ struct LoadModule
struct ImageLoader : LoadModule
{
static ColorSpace cs; //desired value
float w = 0, h = 0; //default image size
Surface surface;

View file

@ -66,6 +66,8 @@ uint64_t HASH_KEY(const char* data, uint64_t size)
/* Internal Class Implementation */
/************************************************************************/
ColorSpace ImageLoader::cs = ColorSpace::ARGB8888;
static Key key;
static Inlist<LoadModule> _activeLoaders;

View file

@ -21,6 +21,7 @@
*/
#include "tvgCanvas.h"
#include "tvgLoadModule.h"
#ifdef THORVG_SW_RASTER_SUPPORT
#include "tvgSwRenderer.h"
@ -90,6 +91,9 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
//Paints must be updated again with this new target.
Canvas::pImpl->needRefresh();
//FIXME: The value must be associated with an individual canvas instance.
ImageLoader::cs = static_cast<ColorSpace>(cs);
return Result::Success;
#endif
return Result::NonSupport;