Home | History | Annotate | Download | only in images
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkChunkAlloc.h"
      9 #include "SkPackBits.h"
     10 #include "SkBitmap.h"
     11 #include "SkPixelRef.h"
     12 
     13 class RLEPixelRef : public SkPixelRef {
     14 public:
     15     RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable);
     16     virtual ~RLEPixelRef();
     17 
     18 protected:
     19     // overrides from SkPixelRef
     20     virtual void* onLockPixels(SkColorTable**);
     21     virtual void onUnlockPixels();
     22 
     23 private:
     24     SkBitmap::RLEPixels* fRLEPixels;
     25     SkColorTable*        fCTable;
     26 };
     27 
     28 RLEPixelRef::RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable)
     29         : SkPixelRef(NULL) {
     30     fRLEPixels = rlep;  // we now own this ptr
     31     fCTable = ctable;
     32     SkSafeRef(ctable);
     33 }
     34 
     35 RLEPixelRef::~RLEPixelRef() {
     36     SkDELETE(fRLEPixels);
     37     SkSafeUnref(fCTable);
     38 }
     39 
     40 void* RLEPixelRef::onLockPixels(SkColorTable** ct) {
     41     *ct = fCTable;
     42     return fRLEPixels;
     43 }
     44 
     45 void RLEPixelRef::onUnlockPixels() {
     46     // nothing to do
     47 }
     48 
     49 /////////////////////////////////////////////////////////////////////////////
     50 
     51 class ChunkRLEPixels : public SkBitmap::RLEPixels {
     52 public:
     53     ChunkRLEPixels(int width, int height, size_t chunkSize)
     54         : SkBitmap::RLEPixels(width, height), fStorage(chunkSize) {
     55     }
     56 
     57     SkChunkAlloc fStorage;
     58 };
     59 
     60 SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
     61 SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src) {
     62 
     63     if (SkBitmap::kIndex8_Config != src.config() &&
     64             SkBitmap::kA8_Config != src.config()) {
     65         return NULL;
     66     }
     67 
     68     size_t maxPacked = SkPackBits::ComputeMaxSize8(src.width());
     69 
     70     // estimate the rle size based on the original size
     71     size_t size = src.getSize() >> 3;
     72     if (size < maxPacked) {
     73         size = maxPacked;
     74     }
     75 
     76     ChunkRLEPixels* rlePixels = SkNEW_ARGS(ChunkRLEPixels,
     77                                            (src.width(), src.height(), size));
     78 
     79     uint8_t* dstRow = NULL;
     80     size_t free = 0;
     81     size_t totalPacked = 0;
     82 
     83     for (int y = 0; y < src.height(); y++) {
     84         const uint8_t* srcRow = src.getAddr8(0, y);
     85 
     86         if (free < maxPacked) {
     87             dstRow = (uint8_t*)rlePixels->fStorage.allocThrow(size);
     88             free = size;
     89         }
     90         size_t packedSize = SkPackBits::Pack8(srcRow, src.width(), dstRow);
     91         SkASSERT(packedSize <= free);
     92         rlePixels->setPackedAtY(y, dstRow);
     93 
     94         dstRow += packedSize;
     95         free -= packedSize;
     96 
     97         totalPacked += packedSize;
     98     }
     99 
    100 //#ifdef SK_DEBUG
    101 #if 0
    102     // test
    103     uint8_t* buffer = new uint8_t[src.width()];
    104     for (int y = 0; y < src.height(); y++) {
    105         const uint8_t* srcRow = src.getAddr8(0, y);
    106         SkPackBits::Unpack8(buffer, 0, src.width(), rlePixels->packedAtY(y));
    107         int n = memcmp(buffer, srcRow, src.width());
    108         if (n) {
    109             SkDebugf("----- memcmp returned %d on line %d\n", n, y);
    110         }
    111         SkASSERT(n == 0);
    112     }
    113     delete[] buffer;
    114 
    115     size_t totalAlloc = src.height() * sizeof(uint8_t*) + totalPacked;
    116 
    117     SkDebugf("--- RLE: orig [%d %d] %d, rle %d %d savings %g\n",
    118              src.width(), src.height(), src.getSize(),
    119              src.height() * sizeof(uint8_t*), totalPacked,
    120              (float)totalAlloc / src.getSize());
    121 
    122 #endif
    123 
    124     // transfer ownership of rlePixels to our pixelref
    125     return SkNEW_ARGS(RLEPixelRef, (rlePixels, src.getColorTable()));
    126 }
    127 
    128