mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
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:
parent
8a4862bc37
commit
5fe9b432ec
8 changed files with 45 additions and 21 deletions
|
@ -126,13 +126,21 @@ bool JpgLoader::read()
|
||||||
|
|
||||||
if (w == 0 || h == 0) return false;
|
if (w == 0 || h == 0) return false;
|
||||||
|
|
||||||
/* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB
|
//determine the image format
|
||||||
How could we notice the renderer colorspace at this time? */
|
TJPF format;
|
||||||
auto image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[TJPF_BGRX]);
|
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;
|
if (!image) return false;
|
||||||
|
|
||||||
//decompress jpg image
|
//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());
|
TVGERR("JPG LOADER", "%s", tjGetErrorStr());
|
||||||
tjFree(image);
|
tjFree(image);
|
||||||
image = nullptr;
|
image = nullptr;
|
||||||
|
@ -145,7 +153,6 @@ bool JpgLoader::read()
|
||||||
surface.w = w;
|
surface.w = w;
|
||||||
surface.h = h;
|
surface.h = h;
|
||||||
surface.channelSize = sizeof(uint32_t);
|
surface.channelSize = sizeof(uint32_t);
|
||||||
surface.cs = ColorSpace::ARGB8888;
|
|
||||||
surface.premultiplied = true;
|
surface.premultiplied = true;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
|
@ -84,14 +84,15 @@ bool PngLoader::read()
|
||||||
|
|
||||||
if (w == 0 || h == 0) return false;
|
if (w == 0 || h == 0) return false;
|
||||||
|
|
||||||
png_bytep buffer;
|
if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) {
|
||||||
image->format = PNG_FORMAT_BGRA;
|
image->format = PNG_FORMAT_BGRA;
|
||||||
buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
|
surface.cs = ColorSpace::ARGB8888;
|
||||||
if (!buffer) {
|
} else {
|
||||||
//out of memory, only time when libpng doesnt free its data
|
image->format = PNG_FORMAT_RGBA;
|
||||||
png_image_free(image);
|
surface.cs = ColorSpace::ABGR8888;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
|
||||||
if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) {
|
if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return false;
|
return false;
|
||||||
|
@ -103,7 +104,6 @@ bool PngLoader::read()
|
||||||
surface.w = (uint32_t)w;
|
surface.w = (uint32_t)w;
|
||||||
surface.h = (uint32_t)h;
|
surface.h = (uint32_t)h;
|
||||||
surface.channelSize = sizeof(uint32_t);
|
surface.channelSize = sizeof(uint32_t);
|
||||||
surface.cs = ColorSpace::ARGB8888;
|
|
||||||
//TODO: we can acquire a pre-multiplied image. See "png_structrp"
|
//TODO: we can acquire a pre-multiplied image. See "png_structrp"
|
||||||
surface.premultiplied = false;
|
surface.premultiplied = false;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ void PngLoader::run(unsigned tid)
|
||||||
auto width = static_cast<unsigned>(w);
|
auto width = static_cast<unsigned>(w);
|
||||||
auto height = static_cast<unsigned>(h);
|
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)) {
|
if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) {
|
||||||
TVGERR("PNG", "Failed to decode image");
|
TVGERR("PNG", "Failed to decode image");
|
||||||
}
|
}
|
||||||
|
@ -43,6 +45,7 @@ void PngLoader::run(unsigned tid)
|
||||||
surface.stride = width;
|
surface.stride = width;
|
||||||
surface.w = width;
|
surface.w = width;
|
||||||
surface.h = height;
|
surface.h = height;
|
||||||
|
surface.cs = ColorSpace::ABGR8888;
|
||||||
surface.channelSize = sizeof(uint32_t);
|
surface.channelSize = sizeof(uint32_t);
|
||||||
|
|
||||||
if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false;
|
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);
|
w = static_cast<float>(width);
|
||||||
h = static_cast<float>(height);
|
h = static_cast<float>(height);
|
||||||
|
|
||||||
if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888;
|
|
||||||
else surface.cs = ColorSpace::ARGB8888;
|
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
goto finalize;
|
goto finalize;
|
||||||
|
@ -127,8 +127,6 @@ bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r
|
||||||
h = static_cast<float>(height);
|
h = static_cast<float>(height);
|
||||||
this->size = size;
|
this->size = size;
|
||||||
|
|
||||||
surface.cs = ColorSpace::ABGR8888;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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 WebPGetInfo(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height) {
|
int* width, int* height) {
|
||||||
|
|
|
@ -35,12 +35,17 @@ void WebpLoader::clear()
|
||||||
|
|
||||||
void WebpLoader::run(unsigned tid)
|
void WebpLoader::run(unsigned tid)
|
||||||
{
|
{
|
||||||
//TODO: we can figure out the requested image format in advance.
|
if (surface.cs == ColorSpace::ARGB8888 || surface.cs == ColorSpace::ARGB8888S) {
|
||||||
surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr);
|
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.stride = static_cast<uint32_t>(w);
|
||||||
surface.w = static_cast<uint32_t>(w);
|
surface.w = static_cast<uint32_t>(w);
|
||||||
surface.h = static_cast<uint32_t>(h);
|
surface.h = static_cast<uint32_t>(h);
|
||||||
surface.cs = ColorSpace::ARGB8888;
|
|
||||||
surface.channelSize = sizeof(uint32_t);
|
surface.channelSize = sizeof(uint32_t);
|
||||||
surface.premultiplied = true;
|
surface.premultiplied = true;
|
||||||
|
|
||||||
|
@ -128,6 +133,8 @@ bool WebpLoader::read()
|
||||||
|
|
||||||
if (!data || w == 0 || h == 0) return false;
|
if (!data || w == 0 || h == 0) return false;
|
||||||
|
|
||||||
|
surface.cs = this->cs;
|
||||||
|
|
||||||
TaskScheduler::request(this);
|
TaskScheduler::request(this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -68,6 +68,8 @@ struct LoadModule
|
||||||
|
|
||||||
struct ImageLoader : LoadModule
|
struct ImageLoader : LoadModule
|
||||||
{
|
{
|
||||||
|
static ColorSpace cs; //desired value
|
||||||
|
|
||||||
float w = 0, h = 0; //default image size
|
float w = 0, h = 0; //default image size
|
||||||
Surface surface;
|
Surface surface;
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,8 @@ uint64_t HASH_KEY(const char* data, uint64_t size)
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
ColorSpace ImageLoader::cs = ColorSpace::ARGB8888;
|
||||||
|
|
||||||
static Key key;
|
static Key key;
|
||||||
static Inlist<LoadModule> _activeLoaders;
|
static Inlist<LoadModule> _activeLoaders;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tvgCanvas.h"
|
#include "tvgCanvas.h"
|
||||||
|
#include "tvgLoadModule.h"
|
||||||
|
|
||||||
#ifdef THORVG_SW_RASTER_SUPPORT
|
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||||
#include "tvgSwRenderer.h"
|
#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.
|
//Paints must be updated again with this new target.
|
||||||
Canvas::pImpl->needRefresh();
|
Canvas::pImpl->needRefresh();
|
||||||
|
|
||||||
|
//FIXME: The value must be associated with an individual canvas instance.
|
||||||
|
ImageLoader::cs = static_cast<ColorSpace>(cs);
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
#endif
|
#endif
|
||||||
return Result::NonSupport;
|
return Result::NonSupport;
|
||||||
|
|
Loading…
Add table
Reference in a new issue