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