From 41eb58e65123317e31a7bd811c3789e6950e6ae5 Mon Sep 17 00:00:00 2001 From: Michal Maciola <71131832+mmaciola@users.noreply.github.com> Date: Mon, 1 Nov 2021 08:10:22 +0100 Subject: [PATCH] loaders: Consider colorspaces (#838) * common: added colorSpace() function This patch introduces colorSpace() function for SW and GL engine. * infra: change LoadModule:read() into LoadModule:read(uint32_t colorspace) This patch changes LoadModule:read() into LoadModule:read(uint32_t colorspace) * picture: implement passing colorspace into loader This patch implements passing colorspace into loaders. Loader->read is now called on the first update. * external_jpg_loader: support colorspaces * external_png_loader: support colorspaces --- inc/thorvg.h | 3 -- src/lib/gl_engine/tvgGlRenderer.cpp | 7 +++++ src/lib/gl_engine/tvgGlRenderer.h | 1 + src/lib/sw_engine/tvgSwRenderer.cpp | 6 ++++ src/lib/sw_engine/tvgSwRenderer.h | 1 + src/lib/tvgLoadModule.h | 2 +- src/lib/tvgPictureImpl.h | 16 ++++++++-- src/lib/tvgRender.h | 2 ++ src/loaders/external_jpg/tvgJpgLoader.cpp | 5 +-- src/loaders/external_jpg/tvgJpgLoader.h | 2 +- src/loaders/external_png/tvgPngLoader.cpp | 38 +++++++++++++++++++++-- src/loaders/external_png/tvgPngLoader.h | 6 +++- src/loaders/jpg/tvgJpgLoader.cpp | 3 +- src/loaders/jpg/tvgJpgLoader.h | 2 +- src/loaders/png/tvgPngLoader.cpp | 2 +- src/loaders/png/tvgPngLoader.h | 2 +- src/loaders/raw/tvgRawLoader.cpp | 3 +- src/loaders/raw/tvgRawLoader.h | 2 +- src/loaders/svg/tvgSvgLoader.cpp | 2 +- src/loaders/svg/tvgSvgLoader.h | 2 +- src/loaders/tvg/tvgTvgLoader.cpp | 2 +- src/loaders/tvg/tvgTvgLoader.h | 2 +- 22 files changed, 86 insertions(+), 25 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index e5dcc668..dea2b2b8 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -1099,7 +1099,6 @@ public: * @retval Result::Success When succeed. * @retval Result::InvalidArguments In case the @p path is invalid. * @retval Result::NonSupport When trying to load a file with an unknown extension. - * @retval Result::Unknown If an error occurs at a later stage. * * @note The Load behavior can be asynchronous if the assigned thread number is greater than zero. * @see Initializer::init() @@ -1116,7 +1115,6 @@ public: * @retval Result::Success When succeed. * @retval Result::InvalidArguments In case no data are provided or the @p size is zero or less. * @retval Result::NonSupport When trying to load a file with an unknown extension. - * @retval Result::Unknown If an error occurs at a later stage. * * @warning: you have responsibility to release the @p data memory if the @p copy is true * @deprecated Use load(const char* data, uint32_t size, const std::string& mimeType, bool copy) instead. @@ -1135,7 +1133,6 @@ public: * @retval Result::Success When succeed. * @retval Result::InvalidArguments In case no data are provided or the @p size is zero or less. * @retval Result::NonSupport When trying to load a file with an unknown extension. - * @retval Result::Unknown If an error occurs at a later stage. * * @warning: It's the user responsibility to release the @p data memory if the @p copy is @c true. * diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index e05bc615..3e2ba18f 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -246,6 +246,13 @@ bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp) } +uint32_t GlRenderer::colorSpace() +{ + //TODO: + return 0; +} + + int GlRenderer::init(uint32_t threads) { if ((initEngineCnt++) > 0) return true; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 0935284e..63e7514b 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -40,6 +40,7 @@ public: RenderRegion region(RenderData data) override; RenderRegion viewport() override; bool viewport(const RenderRegion& vp) override; + uint32_t colorSpace() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool sync() override; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8b3ec2c1..3740d0df 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -299,6 +299,12 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } +uint32_t SwRenderer::colorSpace() +{ + return surface->cs; +} + + bool SwRenderer::preRender() { return rasterClear(surface); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 51eed5db..66550b77 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -45,6 +45,7 @@ public: RenderRegion region(RenderData data) override; RenderRegion viewport() override; bool viewport(const RenderRegion& vp) override; + uint32_t colorSpace() override; bool clear() override; bool sync() override; diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index 70b95b76..60ff01f7 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -47,7 +47,7 @@ public: //Override this if the vector-format has own resizing policy. virtual bool resize(Paint* paint, float w, float h) { return false; }; - virtual bool read() = 0; + virtual bool read(uint32_t colorspace) = 0; virtual bool close() = 0; virtual const uint32_t* pixels() { return nullptr; }; virtual unique_ptr paint() { return nullptr; }; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 8a56f106..a84184f3 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -66,6 +66,7 @@ struct Picture::Impl void* rdata = nullptr; //engine data float w = 0, h = 0; bool resizing = false; + bool justloaded = false; Impl(Picture* p) : picture(p) { @@ -90,7 +91,7 @@ struct Picture::Impl uint32_t reload() { - if (loader) { + if (loader && !justloaded) { if (!paint) { if (auto p = loader->paint()) { paint = p.release(); @@ -127,6 +128,14 @@ struct Picture::Impl void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) { + if (loader && justloaded) { + justloaded = false; + if (!loader->read(renderer.colorSpace())) { + TVGERR("Picture", "Loader read failure!"); + return nullptr; + } + } + auto flag = reload(); if (pixels) { @@ -194,9 +203,9 @@ struct Picture::Impl if (invalid) return Result::InvalidArguments; return Result::NonSupport; } - if (!loader->read()) return Result::Unknown; w = loader->w; h = loader->h; + justloaded = true; return Result::Success; } @@ -206,9 +215,9 @@ struct Picture::Impl if (loader) loader->close(); loader = LoaderMgr::loader(data, size, mimeType, copy); if (!loader) return Result::NonSupport; - if (!loader->read()) return Result::Unknown; w = loader->w; h = loader->h; + justloaded = true; return Result::Success; } @@ -220,6 +229,7 @@ struct Picture::Impl if (!loader) return Result::NonSupport; this->w = loader->w; this->h = loader->h; + justloaded = true; return Result::Success; } diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index b45405ad..3d841b68 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -100,6 +100,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 76ccdde3..8fd9e7e4 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -124,14 +124,15 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) } -bool JpgLoader::read() +bool JpgLoader::read(uint32_t colorspace) { if (image) tjFree(image); image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[TJPF_BGRX]); if (!image) return false; //decompress jpg image - if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), TJPF_BGRX, 0) < 0) { + auto pixelFormat = (colorspace == tvg::SwCanvas::ABGR8888) ? TJPF_RGBX : TJPF_BGRX; + if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), pixelFormat, 0) < 0) { TVGERR("JPG LOADER", "%s", tjGetErrorStr()); tjFree(image); image = nullptr; diff --git a/src/loaders/external_jpg/tvgJpgLoader.h b/src/loaders/external_jpg/tvgJpgLoader.h index 1aeaa04c..03dbae56 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.h +++ b/src/loaders/external_jpg/tvgJpgLoader.h @@ -34,7 +34,7 @@ public: using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; const uint32_t* pixels() override; diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index faafc62a..c663d8d5 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -20,9 +20,27 @@ * SOFTWARE. */ +#include #include "tvgLoader.h" #include "tvgPngLoader.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +void PngLoader::clear() +{ + if (freeData) free(data); + data = nullptr; + freeData = false; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + PngLoader::PngLoader() { image = static_cast(calloc(1, sizeof(png_image))); @@ -32,6 +50,9 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { + if (freeData) free(data); + data = nullptr; + if (content) { free((void*)content); content = nullptr; @@ -41,6 +62,7 @@ PngLoader::~PngLoader() bool PngLoader::open(const string& path) { + clear(); image->opaque = NULL; if (!png_image_begin_read_from_file(image, path.c_str())) return false; @@ -53,9 +75,19 @@ bool PngLoader::open(const string& path) bool PngLoader::open(const char* data, uint32_t size, bool copy) { + clear(); image->opaque = NULL; - if (!png_image_begin_read_from_memory(image, data, size)) return false; + if (copy) { + this->data = (char *) malloc(size); + if (!this->data) return false; + memcpy(this->data, data, size); + freeData = true; + } else { + this->data = (char *) data; + } + + if (!png_image_begin_read_from_memory(image, this->data, size)) return false; w = (float)image->width; h = (float)image->height; @@ -63,10 +95,10 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) return true; } -bool PngLoader::read() +bool PngLoader::read(uint32_t colorspace) { png_bytep buffer; - image->format = PNG_FORMAT_BGRA; + image->format = (colorspace == tvg::SwCanvas::ABGR8888) ? PNG_FORMAT_RGBA : PNG_FORMAT_BGRA; buffer = static_cast(malloc(PNG_IMAGE_SIZE((*image)))); if (!buffer) { //out of memory, only time when libpng doesnt free its data diff --git a/src/loaders/external_png/tvgPngLoader.h b/src/loaders/external_png/tvgPngLoader.h index ab2c8169..d36a06f0 100644 --- a/src/loaders/external_png/tvgPngLoader.h +++ b/src/loaders/external_png/tvgPngLoader.h @@ -33,12 +33,16 @@ public: using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; const uint32_t* pixels() override; private: + void clear(); + + char* data = nullptr; + bool freeData = false; png_imagep image = nullptr; const uint32_t* content = nullptr; }; diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp index 599d2fea..8e875994 100644 --- a/src/loaders/jpg/tvgJpgLoader.cpp +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -90,8 +90,7 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) } - -bool JpgLoader::read() +bool JpgLoader::read(uint32_t colorspace) { if (!decoder || w <= 0 || h <= 0) return false; diff --git a/src/loaders/jpg/tvgJpgLoader.h b/src/loaders/jpg/tvgJpgLoader.h index e7ec3ab4..e69d2876 100644 --- a/src/loaders/jpg/tvgJpgLoader.h +++ b/src/loaders/jpg/tvgJpgLoader.h @@ -41,7 +41,7 @@ public: using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; const uint32_t* pixels() override; diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index e50f34e0..f7d690ab 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -123,7 +123,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) } -bool PngLoader::read() +bool PngLoader::read(uint32_t colorspace) { if (!data || w <= 0 || h <= 0) return false; diff --git a/src/loaders/png/tvgPngLoader.h b/src/loaders/png/tvgPngLoader.h index fa1860c4..864751f4 100644 --- a/src/loaders/png/tvgPngLoader.h +++ b/src/loaders/png/tvgPngLoader.h @@ -44,7 +44,7 @@ public: using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; const uint32_t* pixels() override; diff --git a/src/loaders/raw/tvgRawLoader.cpp b/src/loaders/raw/tvgRawLoader.cpp index a38dc5ef..5b9caaba 100644 --- a/src/loaders/raw/tvgRawLoader.cpp +++ b/src/loaders/raw/tvgRawLoader.cpp @@ -60,8 +60,9 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) } -bool RawLoader::read() +bool RawLoader::read(uint32_t colorspace) { + //NOTE: raw data is used "as it is"- developer must take care of it so the same color space used return true; } diff --git a/src/loaders/raw/tvgRawLoader.h b/src/loaders/raw/tvgRawLoader.h index f6eed20e..4abd4c79 100644 --- a/src/loaders/raw/tvgRawLoader.h +++ b/src/loaders/raw/tvgRawLoader.h @@ -32,7 +32,7 @@ public: using LoadModule::open; bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; const uint32_t* pixels() override; diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 3ca7bdb2..f142cfda 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2927,7 +2927,7 @@ bool SvgLoader::resize(Paint* paint, float w, float h) } -bool SvgLoader::read() +bool SvgLoader::read(uint32_t colorspace) { if (!content || size == 0) return false; diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 468f0580..104dff8b 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -45,7 +45,7 @@ public: bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool resize(Paint* paint, float w, float h) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; unique_ptr paint() override; diff --git a/src/loaders/tvg/tvgTvgLoader.cpp b/src/loaders/tvg/tvgTvgLoader.cpp index d7f31844..deb54406 100644 --- a/src/loaders/tvg/tvgTvgLoader.cpp +++ b/src/loaders/tvg/tvgTvgLoader.cpp @@ -188,7 +188,7 @@ bool TvgLoader::resize(Paint* paint, float w, float h) } -bool TvgLoader::read() +bool TvgLoader::read(uint32_t colorspace) { if (!ptr || size == 0) return false; diff --git a/src/loaders/tvg/tvgTvgLoader.h b/src/loaders/tvg/tvgTvgLoader.h index d276ded3..f7cbc47b 100644 --- a/src/loaders/tvg/tvgTvgLoader.h +++ b/src/loaders/tvg/tvgTvgLoader.h @@ -47,7 +47,7 @@ public: using LoadModule::open; bool open(const string &path) override; bool open(const char *data, uint32_t size, bool copy) override; - bool read() override; + bool read(uint32_t colorspace) override; bool close() override; bool resize(Paint* paint, float w, float h) override; unique_ptr paint() override; -- 2.34.1