From b3c686195fa01434124079a3c8533d6b2f8b9795 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 21 Nov 2016 20:20:23 -0500 Subject: [PATCH] IMAGE: Add hack to Indeo 4 decoder to guess transparent areas --- image/codecs/indeo/indeo.cpp | 4 +++ image/codecs/indeo/indeo.h | 5 ++++ image/codecs/indeo4.cpp | 48 ++++++++++++++++++++++++++++++++++++ image/codecs/indeo4.h | 5 ++++ 4 files changed, 62 insertions(+) diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp index f82c4829af91..a20a3ec113aa 100644 --- a/image/codecs/indeo/indeo.cpp +++ b/image/codecs/indeo/indeo.cpp @@ -607,6 +607,10 @@ int IndeoDecoderBase::decodeIndeoFrame() { // Free the now un-needed frame data frame->freeFrame(); + // If there's any transparency data, decode it + if (_ctx._hasTransp) + decodeTransparency(); + return 0; } diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h index 068f8c9f25f7..dcb7330318bd 100644 --- a/image/codecs/indeo/indeo.h +++ b/image/codecs/indeo/indeo.h @@ -563,6 +563,11 @@ class IndeoDecoderBase : public Codec { */ virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile) = 0; + /** + * Decodes optional transparency data within Indeo frames + */ + virtual void decodeTransparency() {} + /** * Decodes the Indeo frame from the bit reader already * loaded into the context diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp index 6141bf0fc86e..b3a5d3a2bf8a 100644 --- a/image/codecs/indeo4.cpp +++ b/image/codecs/indeo4.cpp @@ -595,6 +595,54 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) { return 0; } +void Indeo4Decoder::decodeTransparency() { + // FIXME: Since I don't currently know how to decode the transparency layer, + // I'm currently doing a hack where I take the color of the top left corner, + // and mark the range of pixels of that color from the start and end of + // each line as transparent + assert(_surface->format.bytesPerPixel == 4); + byte r, g, b, a; + + if (_surface->format.aBits() == 0) { + // Surface is 4 bytes per pixel, but only RGB. So promote the + // surface to full RGBA, and convert all the existing pixels + Graphics::PixelFormat oldFormat = _pixelFormat; + _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + _surface->format = _pixelFormat; + + for (int y = 0; y < _surface->h; ++y) { + uint32 *lineP = (uint32 *)_surface->getBasePtr(0, y); + for (int x = 0; x < _surface->w; ++x, ++lineP) { + oldFormat.colorToRGB(*lineP, r, g, b); + *lineP = _pixelFormat.ARGBToColor(0xff, r, g, b); + } + } + } else { + // Working on a frame when the surface is already RGBA. In which case, + // start of by defaulting all pixels of the frame to fully opaque + for (int y = 0; y < _surface->h; ++y) { + uint32 *lineP = (uint32 *)_surface->getBasePtr(0, y); + for (int x = 0; x < _surface->w; ++x, ++lineP) + *lineP |= 0xff; + } + } + + // Use the top-left pixel as the key color, and figure out the + // equivalent value as fully transparent + uint32 keyColor = *(const uint32 *)_surface->getPixels(); + uint32 transColor = keyColor & ~0xff; + + for (int y = 0; y < _surface->h; ++y) { + uint32 *startP = (uint32 *)_surface->getBasePtr(0, y); + uint32 *endP = (uint32 *)_surface->getBasePtr(_surface->w - 1, y); + + while (startP <= endP && *startP == keyColor) + *startP++ = transColor; + while (endP > startP && *endP == keyColor) + *endP-- = transColor; + } +} + int Indeo4Decoder::scaleTileSize(int defSize, int sizeFactor) { return sizeFactor == 15 ? defSize : (sizeFactor + 1) << 5; } diff --git a/image/codecs/indeo4.h b/image/codecs/indeo4.h index 420acc3f33e9..8b7fdab3f9d1 100644 --- a/image/codecs/indeo4.h +++ b/image/codecs/indeo4.h @@ -89,6 +89,11 @@ class Indeo4Decoder : public IndeoDecoderBase { * @returns result code: 0 = OK, negative number = error */ virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile); + + /** + * Decodes optional transparency data within Indeo frames + */ + virtual void decodeTransparency(); private: int scaleTileSize(int defSize, int sizeFactor);