From b2dc9433f70278c29b659081627399ecd3dfd6b9 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 20 Jan 2023 13:13:01 +0900 Subject: [PATCH] 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. Change-Id: Ib7f25b5bc5871cfe59ad3963d26536269b48a3f5 --- src/lib/gl_engine/tvgGlRenderer.cpp | 7 +++++++ src/lib/gl_engine/tvgGlRenderer.h | 2 ++ src/lib/sw_engine/tvgSwRenderer.cpp | 11 ++++++++-- src/lib/sw_engine/tvgSwRenderer.h | 4 +++- src/lib/tvgLoadModule.h | 3 ++- src/lib/tvgPictureImpl.h | 4 +++- src/lib/tvgRender.h | 2 ++ src/loaders/external_jpg/tvgJpgLoader.cpp | 30 ++++++++++++++++++++++---- src/loaders/external_jpg/tvgJpgLoader.h | 2 +- src/loaders/external_png/tvgPngLoader.cpp | 29 ++++++++++++++++++++++--- src/loaders/external_png/tvgPngLoader.h | 4 ++-- src/loaders/jpg/tvgJpgLoader.cpp | 28 ++++++++++++++++++++++--- src/loaders/jpg/tvgJpgLoader.h | 2 +- src/loaders/png/tvgPngLoader.cpp | 28 ++++++++++++++++++++++--- src/loaders/png/tvgPngLoader.h | 2 +- src/loaders/raw/tvgRawLoader.cpp | 35 ++++++++++++++++++++++++------- src/loaders/raw/tvgRawLoader.h | 4 ++-- 17 files changed, 165 insertions(+), 32 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 517e64e..fcd33ad 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -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; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 4d1bb87..3263231 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -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(); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 17dff57..6a1a881 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -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; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index c3eadbd..690b7ff 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -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(); diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index 2c2ffda..4637c90 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -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 bitmap() { return nullptr; } + virtual unique_ptr bitmap(uint32_t colorSpace) { return nullptr; } virtual unique_ptr paint() { return nullptr; } }; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index b7e2ba0..6ef2313 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -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& clips, RenderUpdateFlag pFlag, bool clipper) { + rendererColorSpace = renderer.colorSpace(); auto flag = reload(); if (surface) { diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index e9ad821..55bbec1 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -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; }; } diff --git a/src/loaders/external_jpg/tvgJpgLoader.cpp b/src/loaders/external_jpg/tvgJpgLoader.cpp index 5920f7c..7ead54c 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -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(w) * static_cast(h) * tjPixelSize[TJPF_BGRX]); + image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[convertColorSpaceType(colorSpace)]); if (!image) return false; //decompress jpg image - if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), TJPF_BGRX, 0) < 0) { + if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), convertColorSpaceType(colorSpace), 0) < 0) { TVGERR("JPG LOADER", "%s", tjGetErrorStr()); tjFree(image); image = nullptr; @@ -149,16 +167,20 @@ bool JpgLoader::close() } -unique_ptr JpgLoader::bitmap() +unique_ptr JpgLoader::bitmap(uint32_t colorSpace) { if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + read(); + } auto surface = static_cast(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); } diff --git a/src/loaders/external_jpg/tvgJpgLoader.h b/src/loaders/external_jpg/tvgJpgLoader.h index c8c9345..da7b59e 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.h +++ b/src/loaders/external_jpg/tvgJpgLoader.h @@ -38,7 +38,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; private: void clear(); diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index 4061a49..2dbedd8 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -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(calloc(1, sizeof(png_image))); @@ -110,16 +128,21 @@ bool PngLoader::close() return true; } -unique_ptr PngLoader::bitmap() +unique_ptr PngLoader::bitmap(uint32_t colorSpace) { if (!content) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(content, w, h); + } auto surface = static_cast(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); } + diff --git a/src/loaders/external_png/tvgPngLoader.h b/src/loaders/external_png/tvgPngLoader.h index 39d5fdb..48f44f5 100644 --- a/src/loaders/external_png/tvgPngLoader.h +++ b/src/loaders/external_png/tvgPngLoader.h @@ -37,11 +37,11 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; private: png_imagep image = nullptr; - const uint32_t* content = nullptr; + uint32_t* content = nullptr; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp index dc50848..2b16090 100644 --- a/src/loaders/jpg/tvgJpgLoader.cpp +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -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 JpgLoader::bitmap() +unique_ptr JpgLoader::bitmap(uint32_t colorSpace) { this->done(); if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(reinterpret_cast(image), w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(image); + surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/jpg/tvgJpgLoader.h b/src/loaders/jpg/tvgJpgLoader.h index 6d2febe..02aee45 100644 --- a/src/loaders/jpg/tvgJpgLoader.h +++ b/src/loaders/jpg/tvgJpgLoader.h @@ -45,7 +45,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; void run(unsigned tid) override; }; diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index cc44b0d..7233f30 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -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 PngLoader::bitmap() +unique_ptr PngLoader::bitmap(uint32_t colorSpace) { this->done(); if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(reinterpret_cast(image), w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(image); + surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/png/tvgPngLoader.h b/src/loaders/png/tvgPngLoader.h index 579d197..5e3c930 100644 --- a/src/loaders/png/tvgPngLoader.h +++ b/src/loaders/png/tvgPngLoader.h @@ -48,7 +48,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; void run(unsigned tid) override; }; diff --git a/src/loaders/raw/tvgRawLoader.cpp b/src/loaders/raw/tvgRawLoader.cpp index d8c0559..524cff1 100644 --- a/src/loaders/raw/tvgRawLoader.cpp +++ b/src/loaders/raw/tvgRawLoader.cpp @@ -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(data); return true; } @@ -73,16 +90,20 @@ bool RawLoader::close() } -unique_ptr RawLoader::bitmap() +unique_ptr RawLoader::bitmap(uint32_t colorSpace) { if (!content) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(content, w, h); + } auto surface = static_cast(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(w); + surface->w = static_cast(w); + surface->h = static_cast(h); + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/raw/tvgRawLoader.h b/src/loaders/raw/tvgRawLoader.h index d381010..a5e3d59 100644 --- a/src/loaders/raw/tvgRawLoader.h +++ b/src/loaders/raw/tvgRawLoader.h @@ -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 bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; }; -- 2.7.4