respect preferred config when png is index-based
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 8 Jul 2009 20:09:23 +0000 (20:09 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 8 Jul 2009 20:09:23 +0000 (20:09 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@261 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkBitmap.h
samplecode/SampleDecode.cpp [new file with mode: 0644]
src/images/SkImageDecoder_libpng.cpp
src/images/SkScaledBitmapSampler.cpp
src/images/SkScaledBitmapSampler.h

index 4c20412..ecf7b2f 100644 (file)
@@ -613,19 +613,22 @@ public:
     */
     const SkPMColor* colors() const { return fColors; }
 
-    /** If a previous bitmap has been locked by this object, unlock its colors
-        first. If the specified bitmap has a colortable, lock its colors and
-        return them.
-    */
-    const SkPMColor* lockColors(const SkBitmap& bm) {
+    /** Locks the table and returns is colors (assuming ctable is not null) and
+        unlocks the previous table if one was present
+     */
+    const SkPMColor* lockColors(SkColorTable* ctable) {
         if (fCTable) {
             fCTable->unlockColors(false);
         }
-        fCTable = bm.getColorTable();
-        fColors = fCTable ? fCTable->lockColors() : NULL;
+        fCTable = ctable;
+        fColors = ctable ? ctable->lockColors() : NULL;
         return fColors;
     }
 
+    const SkPMColor* lockColors(const SkBitmap& bm) {
+        return this->lockColors(bm.getColorTable());
+    }
+
 private:
     SkColorTable*    fCTable;
     const SkPMColor* fColors;
diff --git a/samplecode/SampleDecode.cpp b/samplecode/SampleDecode.cpp
new file mode 100644 (file)
index 0000000..9a80267
--- /dev/null
@@ -0,0 +1,67 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+
+static const struct {
+    SkBitmap::Config    fPrefConfig;
+    bool                fDither;
+} gRec[] = {
+    { SkBitmap::kIndex8_Config,     false },
+    { SkBitmap::kARGB_8888_Config,  false },
+    { SkBitmap::kARGB_4444_Config,  false },
+    { SkBitmap::kARGB_4444_Config,  true },
+    { SkBitmap::kRGB_565_Config,    false },
+    { SkBitmap::kRGB_565_Config,    true },
+};
+
+class DecodeView : public SkView {
+public:
+    SkBitmap fBitmap[SK_ARRAY_COUNT(gRec)];
+
+       DecodeView() {
+        SkFILEStream stream("/skimages/index.png");
+        SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+        for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+            stream.rewind();
+            codec->setDitherImage(gRec[i].fDither);
+            codec->decode(&stream, &fBitmap[i], gRec[i].fPrefConfig,
+                          SkImageDecoder::kDecodePixels_Mode);
+        }
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "ImageDecoder");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+        
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fBitmap); i++) {
+            canvas->drawBitmap(fBitmap[i], 0, 0);
+            canvas->translate(SkIntToScalar(fBitmap[i].width()), 0);
+        }
+    }
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DecodeView; }
+static SkViewRegister reg(MyFactory);
+
index 81e73ef..8f2652a 100644 (file)
@@ -110,6 +110,12 @@ static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
     return reallyHasAlpha;
 }
 
+static inline bool isDirectModel(SkBitmap::Config config) {
+    return  config == SkBitmap::kARGB_8888_Config ||
+    config == SkBitmap::kARGB_4444_Config ||
+    config == SkBitmap::kRGB_565_Config;
+}
+
 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
                                  SkBitmap::Config prefConfig, Mode mode) {
 //    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");
@@ -292,7 +298,7 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
     // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
     // draw lots faster if we can flag the bitmap has being opaque
     bool reallyHasAlpha = false;
-
+    bool upscaleFromPalette = false;
     SkColorTable* colorTable = NULL;
 
     if (color_type == PNG_COLOR_TYPE_PALETTE) {
@@ -346,11 +352,23 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
             *colorPtr = colorPtr[-1];
         }
         colorTable->unlockColors(true);
+
+        // see if we need to upscale to a direct-model
+        if (isDirectModel(prefConfig)) {
+            if (!reallyHasAlpha || SkBitmap::kRGB_565_Config != prefConfig) {
+                upscaleFromPalette = true;
+                config = prefConfig;
+                // need to re-call setConfig
+                decodedBitmap->setConfig(config, sampler.scaledWidth(),
+                                         sampler.scaledHeight(), 0);
+            }
+        }
     }
     
     SkAutoUnref aur(colorTable);
 
-    if (!this->allocPixelRef(decodedBitmap, colorTable)) {
+    if (!this->allocPixelRef(decodedBitmap,
+                             upscaleFromPalette ? NULL : colorTable)) {
         return false;
     }
     
@@ -392,7 +410,7 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
         SkScaledBitmapSampler::SrcConfig sc;
         int srcBytesPerPixel = 4;
         
-        if (SkBitmap::kIndex8_Config == config) {
+        if (colorTable != NULL) {
             sc = SkScaledBitmapSampler::kIndex;
             srcBytesPerPixel = 1;
         } else if (hasAlpha) {
@@ -400,7 +418,13 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
         } else {
             sc = SkScaledBitmapSampler::kRGBX;
         }
-        if (!sampler.begin(decodedBitmap, sc, doDither)) {
+
+        /*  We have to pass the colortable explicitly, since we may have one
+            even if our decodedBitmap doesn't, due to the request that we
+            upscale png's palette to a direct model
+         */
+        SkAutoLockColors ctLock(colorTable);
+        if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
             return false;
         }
         const int height = decodedBitmap->height();
index 15f4432..b51b4e7 100644 (file)
@@ -23,7 +23,7 @@
 
 static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
     for (int x = 0; x < width; x++) {
         dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]);
@@ -34,7 +34,7 @@ static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
     for (int x = 0; x < width; x++) {
         dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
@@ -45,7 +45,7 @@ static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
     unsigned alphaMask = 0xFF;
     for (int x = 0; x < width; x++) {
@@ -61,7 +61,7 @@ static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
 
 static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
                              const uint8_t* SK_RESTRICT src,
-                             int width, int deltaSrc, int) {
+                             int width, int deltaSrc, int, const SkPMColor[]) {
     uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
     for (int x = 0; x < width; x++) {
         dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
@@ -72,7 +72,7 @@ static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
 
 static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
                                const uint8_t* SK_RESTRICT src,
-                               int width, int deltaSrc, int y) {
+                           int width, int deltaSrc, int y, const SkPMColor[]) {
     uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
     DITHER_565_SCAN(y);
     for (int x = 0; x < width; x++) {
@@ -84,7 +84,7 @@ static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
                              const uint8_t* SK_RESTRICT src,
-                             int width, int deltaSrc, int) {
+                             int width, int deltaSrc, int, const SkPMColor[]) {
     uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
     for (int x = 0; x < width; x++) {
         dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
@@ -95,7 +95,7 @@ static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
                                const uint8_t* SK_RESTRICT src,
-                               int width, int deltaSrc, int y) {
+                           int width, int deltaSrc, int y, const SkPMColor[]) {
     uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
     DITHER_565_SCAN(y);
     for (int x = 0; x < width; x++) {
@@ -109,7 +109,7 @@ static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
 
 static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
     for (int x = 0; x < width; x++) {
         unsigned gray = src[0] >> 4;
@@ -121,7 +121,7 @@ static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
 
 static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
                                 const uint8_t* SK_RESTRICT src,
-                                int width, int deltaSrc, int y) {
+                            int width, int deltaSrc, int y, const SkPMColor[]) {
     SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
     DITHER_4444_SCAN(y);
     for (int x = 0; x < width; x++) {
@@ -134,7 +134,7 @@ static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
     for (int x = 0; x < width; x++) {
         dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
@@ -145,7 +145,7 @@ static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
                                 const uint8_t* SK_RESTRICT src,
-                                int width, int deltaSrc, int y) {
+                            int width, int deltaSrc, int y, const SkPMColor[]) {
     SkPMColor16* dst = (SkPMColor16*)dstRow;
     DITHER_4444_SCAN(y);
 
@@ -159,7 +159,7 @@ static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
                               const uint8_t* SK_RESTRICT src,
-                              int width, int deltaSrc, int) {
+                              int width, int deltaSrc, int, const SkPMColor[]) {
     SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
     unsigned alphaMask = 0xFF;
 
@@ -175,7 +175,7 @@ static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
 
 static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
                                 const uint8_t* SK_RESTRICT src,
-                                int width, int deltaSrc, int y) {
+                            int width, int deltaSrc, int y, const SkPMColor[]) {
     SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
     unsigned alphaMask = 0xFF;
     DITHER_4444_SCAN(y);
@@ -192,9 +192,86 @@ static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
 
 // Index
 
+#define A32_MASK_IN_PLACE   (SK_A32_MASK << SK_A32_SHIFT)
+
+static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
+                               const uint8_t* SK_RESTRICT src,
+                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
+
+    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+    SkPMColor cc = A32_MASK_IN_PLACE;
+    for (int x = 0; x < width; x++) {
+        SkPMColor c = ctable[*src];
+        cc &= c;
+        dst[x] = c;
+        src += deltaSrc;
+    }
+    return cc != A32_MASK_IN_PLACE;
+}
+
+static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
+                               const uint8_t* SK_RESTRICT src,
+                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
+
+    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
+    for (int x = 0; x < width; x++) {
+        dst[x] = SkPixel32ToPixel16(ctable[*src]);
+        src += deltaSrc;
+    }
+    return false;
+}
+
+static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
+                                const uint8_t* SK_RESTRICT src, int width,
+                                int deltaSrc, int y, const SkPMColor ctable[]) {
+
+    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
+    DITHER_565_SCAN(y);
+
+    for (int x = 0; x < width; x++) {
+        SkPMColor c = ctable[*src];
+        dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
+                                  SkGetPackedB32(c), DITHER_VALUE(x));
+        src += deltaSrc;
+    }
+    return false;
+}
+
+static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
+                               const uint8_t* SK_RESTRICT src, int width,
+                               int deltaSrc, int y, const SkPMColor ctable[]) {
+
+    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+    SkPMColor cc = A32_MASK_IN_PLACE;
+    for (int x = 0; x < width; x++) {
+        SkPMColor c = ctable[*src];
+        cc &= c;
+        dst[x] = SkPixel32ToPixel4444(c);
+        src += deltaSrc;
+    }
+    return cc != A32_MASK_IN_PLACE;
+}
+
+static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
+                                 const uint8_t* SK_RESTRICT src, int width,
+                                int deltaSrc, int y, const SkPMColor ctable[]) {
+
+    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+    SkPMColor cc = A32_MASK_IN_PLACE;
+    DITHER_4444_SCAN(y);
+
+    for (int x = 0; x < width; x++) {
+        SkPMColor c = ctable[*src];
+        cc &= c;
+        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
+        src += deltaSrc;
+    }
+    return cc != A32_MASK_IN_PLACE;
+}
+
 static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
                             const uint8_t* SK_RESTRICT src,
-                            int width, int deltaSrc, int) {
+                            int width, int deltaSrc, int, const SkPMColor[]) {
     if (1 == deltaSrc) {
         memcpy(dstRow, src, width);
     } else {
@@ -247,25 +324,27 @@ SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
     SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
     
     fRowProc = NULL;
+    fCTable = NULL;
 }
 
-bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither) {
+bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
+                                  const SkPMColor ctable[]) {
     static const RowProc gProcs[] = {
         // 8888 (no dither distinction)
         Sample_Gray_D8888,  Sample_Gray_D8888,
         Sample_RGBx_D8888,  Sample_RGBx_D8888,
         Sample_RGBA_D8888,  Sample_RGBA_D8888,
-        NULL,               NULL,
+        Sample_Index_D8888, Sample_Index_D8888,
         // 565 (no alpha distinction)
         Sample_Gray_D565,   Sample_Gray_D565_D,
         Sample_RGBx_D565,   Sample_RGBx_D565_D,
         Sample_RGBx_D565,   Sample_RGBx_D565_D,
-        NULL,               NULL,
+        Sample_Index_D565,  Sample_Index_D565_D,
         // 4444
         Sample_Gray_D4444,  Sample_Gray_D4444_D,
         Sample_RGBx_D4444,  Sample_RGBx_D4444_D,
         Sample_RGBA_D4444,  Sample_RGBA_D4444_D,
-        NULL,               NULL,
+        Sample_Index_D4444, Sample_Index_D4444_D,
         // Index8
         NULL,               NULL,
         NULL,               NULL,
@@ -273,7 +352,8 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither) {
         Sample_Index_DI,    Sample_Index_DI,
     };
 
-    
+    fCTable = ctable;
+
     int index = 0;
     if (dither) {
         index += 1;
@@ -331,7 +411,7 @@ bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
     SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
 
     bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
-                             fDX * fSrcPixelSize, fCurrY);
+                             fDX * fSrcPixelSize, fCurrY, fCTable);
     fDstRow += fDstRowBytes;
     fCurrY += 1;
     return hadAlpha;
index 0bb9924..84a75ba 100644 (file)
@@ -2,6 +2,7 @@
 #define SkScaledBitmapSampler_DEFINED
 
 #include "SkTypes.h"
+#include "SkColor.h"
 
 class SkBitmap;
 
@@ -26,7 +27,8 @@ public:
     // Given a dst bitmap (with pixels already allocated) and a src-config,
     // prepares iterator to process the src colors and write them into dst.
     // Returns false if the request cannot be fulfulled.
-    bool begin(SkBitmap* dst, SrcConfig sc, bool doDither);
+    bool begin(SkBitmap* dst, SrcConfig sc, bool doDither,
+               const SkPMColor* = NULL);
     // call with row of src pixels, for y = 0...scaledHeight-1.
     // returns true if the row had non-opaque alpha in it
     bool next(const uint8_t* SK_RESTRICT src);
@@ -39,17 +41,21 @@ private:
     int fY0;    // first Y coord (scanline) to sample
     int fDX;    // step between X samples
     int fDY;    // step between Y samples
-    
+
     typedef bool (*RowProc)(void* SK_RESTRICT dstRow,
                             const uint8_t* SK_RESTRICT src,
-                            int width, int deltaSrc, int y);
-    
+                            int width, int deltaSrc, int y,
+                            const SkPMColor[]);
+
     // setup state
     char*   fDstRow; // points into bitmap's pixels
     int     fDstRowBytes;
     int     fCurrY; // used for dithering
     int     fSrcPixelSize;  // 1, 3, 4    
     RowProc fRowProc;
+
+    // optional reference to the src colors if the src is a palette model
+    const SkPMColor* fCTable;
 };
 
 #endif