*/
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.
};
/**
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;
}
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_ */
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 {
}
+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;
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;
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);
}