loader: Support ABGR colorspace

Since the color space is set at the time of specifying the target buffer of the canvas,
there is no way to know the color space when the picture is loaded.
So, check the color space applied to SwCanvas at the time of reload()
and change the color space.

There is an issue of BGR color space support for each loader.
The external_jpg loader resets the TJPF color space and calls read() to get a new buffer.
In the case of external_png, we need to change the color value directly
because it have to start over from begin_read_*.

This solution can affect performance as much as it access again image buffer
that have already been `read()` done. However, this only happens once.
This commit is contained in:
JunsuChoi 2023-01-20 13:13:01 +09:00 committed by JunsuChoi
parent a05816e219
commit 507b11829c
17 changed files with 165 additions and 32 deletions

View file

@ -123,6 +123,13 @@ bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp)
}
int32_t GlRenderer::colorSpace()
{
//TODO: return a proper color space value.
return -1;
}
bool GlRenderer::renderImage(TVG_UNUSED void* data)
{
return false;

View file

@ -50,6 +50,8 @@ public:
bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
bool endComposite(Compositor* cmp) override;
uint32_t colorSpace() override;
static GlRenderer* gen();
static int init(TVG_UNUSED uint32_t threads);
static int32_t init();

View file

@ -296,7 +296,7 @@ bool SwRenderer::viewport(const RenderRegion& vp)
}
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace)
{
if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
@ -306,7 +306,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
surface->stride = stride;
surface->w = w;
surface->h = h;
surface->cs = cs;
surface->cs = colorSpace;
vport.x = vport.y = 0;
vport.w = surface->w;
@ -661,6 +661,13 @@ SwRenderer::SwRenderer():mpool(globalMpool)
}
uint32_t SwRenderer::colorSpace()
{
if (surface) return surface->cs;
return tvg::SwCanvas::ARGB8888;
}
bool SwRenderer::init(uint32_t threads)
{
if ((initEngineCnt++) > 0) return true;

View file

@ -50,7 +50,7 @@ public:
bool clear() override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace);
bool mempool(bool shared);
Compositor* target(const RenderRegion& region) override;
@ -58,6 +58,8 @@ public:
bool endComposite(Compositor* cmp) override;
void clearCompositors();
uint32_t colorSpace() override;
static SwRenderer* gen();
static bool init(uint32_t threads);
static int32_t init();

View file

@ -37,6 +37,7 @@ public:
float vw = 0;
float vh = 0;
float w = 0, h = 0; //default image size
uint32_t colorSpace = SwCanvas::ARGB8888;
virtual ~LoadModule() {}
@ -49,7 +50,7 @@ public:
virtual bool read() = 0;
virtual bool close() = 0;
virtual unique_ptr<Surface> bitmap() { return nullptr; }
virtual unique_ptr<Surface> bitmap(uint32_t colorSpace) { return nullptr; }
virtual unique_ptr<Paint> paint() { return nullptr; }
};

View file

@ -69,6 +69,7 @@ struct Picture::Impl
void* rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
uint32_t rendererColorSpace = 0;
~Impl()
{
@ -104,7 +105,7 @@ struct Picture::Impl
}
}
free(surface);
if ((surface = loader->bitmap().release())) {
if ((surface = loader->bitmap(rendererColorSpace).release())) {
loader->close();
return RenderUpdateFlag::Image;
}
@ -128,6 +129,7 @@ struct Picture::Impl
void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
{
rendererColorSpace = renderer.colorSpace();
auto flag = reload();
if (surface) {

View file

@ -203,6 +203,8 @@ public:
virtual Compositor* target(const RenderRegion& region) = 0;
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
virtual bool endComposite(Compositor* cmp) = 0;
virtual uint32_t colorSpace() = 0;
};
}

View file

@ -37,6 +37,24 @@ void JpgLoader::clear()
freeData = false;
}
uint32_t convertColorSpaceType(uint32_t colorSpace)
{
uint32_t tjpfColorSpace = TJPF_RGBX;
switch (colorSpace)
{
case SwCanvas::ARGB8888:
case SwCanvas::ARGB8888_STRAIGHT:
default:
tjpfColorSpace = TJPF_BGRX;
break;
case SwCanvas::ABGR8888:
case SwCanvas::ABGR8888_STRAIGHT:
tjpfColorSpace = TJPF_RGBX;
break;
}
return tjpfColorSpace;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -127,11 +145,11 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy)
bool JpgLoader::read()
{
if (image) tjFree(image);
image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[TJPF_BGRX]);
image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[convertColorSpaceType(colorSpace)]);
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), convertColorSpaceType(colorSpace), 0) < 0) {
TVGERR("JPG LOADER", "%s", tjGetErrorStr());
tjFree(image);
image = nullptr;
@ -149,16 +167,20 @@ bool JpgLoader::close()
}
unique_ptr<Surface> JpgLoader::bitmap()
unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
{
if (!image) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
read();
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->stride = w;
surface->w = w;
surface->h = h;
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View file

@ -38,7 +38,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
private:
void clear();

View file

@ -42,6 +42,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
}
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
PngLoader::PngLoader()
{
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
@ -110,16 +128,21 @@ bool PngLoader::close()
return true;
}
unique_ptr<Surface> PngLoader::bitmap()
unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
{
if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->buffer = content;
surface->stride = w;
surface->w = w;
surface->h = h;
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View file

@ -37,11 +37,11 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
private:
png_imagep image = nullptr;
const uint32_t* content = nullptr;
uint32_t* content = nullptr;
};
#endif //_TVG_PNG_LOADER_H_

View file

@ -28,6 +28,24 @@
/* Internal Class Implementation */
/************************************************************************/
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
void JpgLoader::clear()
{
jpgdDelete(decoder);
@ -110,18 +128,22 @@ bool JpgLoader::close()
}
unique_ptr<Surface> JpgLoader::bitmap()
unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
{
this->done();
if (!image) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(reinterpret_cast<uint32_t*>(image), w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->buffer = reinterpret_cast<uint32_t*>(image);
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View file

@ -45,7 +45,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
void run(unsigned tid) override;
};

View file

@ -49,6 +49,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
}
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
void PngLoader::clear()
{
lodepng_state_cleanup(&state);
@ -163,18 +181,22 @@ bool PngLoader::close()
}
unique_ptr<Surface> PngLoader::bitmap()
unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
{
this->done();
if (!image) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(reinterpret_cast<uint32_t*>(image), w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->buffer = reinterpret_cast<uint32_t*>(image);
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View file

@ -48,7 +48,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
void run(unsigned tid) override;
};

View file

@ -29,6 +29,23 @@
/* Internal Class Implementation */
/************************************************************************/
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -55,7 +72,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
if (!content) return false;
memcpy((void*)content, data, sizeof(uint32_t) * w * h);
}
else content = data;
else content = const_cast<uint32_t*>(data);
return true;
}
@ -73,16 +90,20 @@ bool RawLoader::close()
}
unique_ptr<Surface> RawLoader::bitmap()
unique_ptr<Surface> RawLoader::bitmap(uint32_t colorSpace)
{
if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->stride = (uint32_t)w;
surface->w = (uint32_t)w;
surface->h = (uint32_t)h;
surface->cs = SwCanvas::ARGB8888;
surface->buffer = content;
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View file

@ -26,7 +26,7 @@
class RawLoader : public LoadModule
{
public:
const uint32_t* content = nullptr;
uint32_t* content = nullptr;
bool copy = false;
~RawLoader();
@ -36,7 +36,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
};