common: Unmultiplicated colorspace
authorMichal Maciola <m.maciola@samsung.com>
Tue, 14 Sep 2021 07:29:14 +0000 (09:29 +0200)
committerJunsuChoi <jsuya.choi@samsung.com>
Tue, 2 Nov 2021 00:41:05 +0000 (09:41 +0900)
This patch introduces _STRAIGHT colorspaces (ABGR8888_STRAIGHT and
ARGB8888_STRAIGHT) whose colors are un-alpha-premultiplied. Unmultiplicated
colors are especially needed for wasm thorvg loader and svg2png / tvg2png.
Only C version now.

@issue: #791

inc/thorvg.h
src/bin/svg2png/svg2png.cpp
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRenderer.cpp
src/wasm/thorvgwasm.cpp

index 1b2afdf..e5dcc66 100644 (file)
@@ -1310,8 +1310,10 @@ public:
      */
     enum Colorspace
     {
-        ABGR8888 = 0, ///< The channels are joined in the order: alpha, blue, green, red.
-        ARGB8888      ///< The channels are joined in the order: alpha, red, green, blue.
+        ABGR8888 = 0,      ///< The channels are joined in the order: alpha, blue, green, red. Colors are alpha-premultiplied.
+        ARGB8888,          ///< The channels are joined in the order: alpha, red, green, blue. Colors are alpha-premultiplied.
+        ABGR8888_STRAIGHT, ///< @BETA_API The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied.
+        ARGB8888_STRAIGHT, ///< @BETA_API The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied.
     };
 
     /**
index 6428c33..c646918 100644 (file)
@@ -90,7 +90,7 @@ public:
             return 1;
         }
 
-        if (canvas->target(buffer, w, w, h, tvg::SwCanvas::ARGB8888) != tvg::Result::Success) {
+        if (canvas->target(buffer, w, w, h, tvg::SwCanvas::ARGB8888_STRAIGHT) != tvg::Result::Success) {
             cout << "Error: Canvas target failure" << endl;
             return 1;
         }
index 4f6968d..85b9052 100644 (file)
@@ -358,5 +358,6 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint
 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
 bool rasterClear(SwSurface* surface);
 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len);
+void rasterUnpremultiply(SwSurface* surface);
 
 #endif /* _TVG_SW_COMMON_H_ */
index 35d0ba4..e4a0092 100644 (file)
@@ -1399,10 +1399,10 @@ void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
 
 bool rasterCompositor(SwSurface* surface)
 {
-    if (surface->cs == SwCanvas::ABGR8888) {
+    if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
         surface->blender.alpha = _colorAlpha;
         surface->blender.join = _abgrJoin;
-    } else if (surface->cs == SwCanvas::ARGB8888) {
+    } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
         surface->blender.alpha = _colorAlpha;
         surface->blender.join = _argbJoin;
     } else {
@@ -1515,6 +1515,31 @@ bool rasterClear(SwSurface* surface)
 }
 
 
+void rasterUnpremultiply(SwSurface* surface)
+{
+    //TODO: Create simd avx and neon version
+    for (uint32_t y = 0; y < surface->h; y++) {
+        auto buffer = surface->buffer + surface->stride * y;
+        for (uint32_t x = 0; x < surface->w; ++x) {
+            uint8_t a = buffer[x] >> 24;
+            if (a == 255) {
+                continue;
+            } else if (a == 0) {
+                buffer[x] = 0x00ffffff;
+            } else {
+                uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
+                uint16_t g = ((buffer[x]) & 0xff00) / a;
+                uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
+                if (r > 0xff) r = 0xff;
+                if (g > 0xff) g = 0xff;
+                if (b > 0xff) b = 0xff;
+                buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
+            }
+        }
+    }
+}
+
+
 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
 {
     Matrix invTransform;
index 81cb80a..8b3ec2c 100644 (file)
@@ -318,6 +318,11 @@ void SwRenderer::clearCompositors()
 
 bool SwRenderer::postRender()
 {
+    //Unmultiply alpha if needed
+    if (surface->cs == SwCanvas::ABGR8888_STRAIGHT || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
+        rasterUnpremultiply(surface);
+    }
+
     tasks.clear();
     clearCompositors();
     return true;
index ba76449..ca615ab 100644 (file)
@@ -224,7 +224,7 @@ private:
         mWidth = width;
         mHeight = height;
         mBuffer = make_unique<uint8_t[]>(mWidth * mHeight * 4);
-        mSwCanvas->target((uint32_t *)mBuffer.get(), mWidth, mWidth, mHeight, SwCanvas::ABGR8888);
+        mSwCanvas->target((uint32_t *)mBuffer.get(), mWidth, mWidth, mHeight, SwCanvas::ABGR8888_STRAIGHT);
 
         if (mPicture) mPicture->size(width, height);
     }