| #include "SkChunkAlloc.h" |
| #include "SkPackBits.h" |
| #include "SkBitmap.h" |
| #include "SkPixelRef.h" |
| |
| class RLEPixelRef : public SkPixelRef { |
| public: |
| RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable); |
| virtual ~RLEPixelRef(); |
| |
| protected: |
| // overrides from SkPixelRef |
| virtual void* onLockPixels(SkColorTable**); |
| virtual void onUnlockPixels(); |
| |
| private: |
| SkBitmap::RLEPixels* fRLEPixels; |
| SkColorTable* fCTable; |
| }; |
| |
| RLEPixelRef::RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable) |
| : SkPixelRef(NULL) { |
| fRLEPixels = rlep; // we now own this ptr |
| fCTable = ctable; |
| SkSafeRef(ctable); |
| } |
| |
| RLEPixelRef::~RLEPixelRef() { |
| SkDELETE(fRLEPixels); |
| SkSafeUnref(fCTable); |
| } |
| |
| void* RLEPixelRef::onLockPixels(SkColorTable** ct) { |
| *ct = fCTable; |
| return fRLEPixels; |
| } |
| |
| void RLEPixelRef::onUnlockPixels() { |
| // nothing to do |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| class ChunkRLEPixels : public SkBitmap::RLEPixels { |
| public: |
| ChunkRLEPixels(int width, int height, size_t chunkSize) |
| : SkBitmap::RLEPixels(width, height), fStorage(chunkSize) { |
| } |
| |
| SkChunkAlloc fStorage; |
| }; |
| |
| SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src); |
| SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src) { |
| |
| if (SkBitmap::kIndex8_Config != src.config() && |
| SkBitmap::kA8_Config != src.config()) { |
| return NULL; |
| } |
| |
| size_t maxPacked = SkPackBits::ComputeMaxSize8(src.width()); |
| |
| // estimate the rle size based on the original size |
| size_t size = src.getSize() >> 3; |
| if (size < maxPacked) { |
| size = maxPacked; |
| } |
| |
| ChunkRLEPixels* rlePixels = SkNEW_ARGS(ChunkRLEPixels, |
| (src.width(), src.height(), size)); |
| |
| uint8_t* dstRow = NULL; |
| size_t free = 0; |
| size_t totalPacked = 0; |
| |
| for (int y = 0; y < src.height(); y++) { |
| const uint8_t* srcRow = src.getAddr8(0, y); |
| |
| if (free < maxPacked) { |
| dstRow = (uint8_t*)rlePixels->fStorage.allocThrow(size); |
| free = size; |
| } |
| size_t packedSize = SkPackBits::Pack8(srcRow, src.width(), dstRow); |
| SkASSERT(packedSize <= free); |
| rlePixels->setPackedAtY(y, dstRow); |
| |
| dstRow += packedSize; |
| free -= packedSize; |
| |
| totalPacked += packedSize; |
| } |
| |
| //#ifdef SK_DEBUG |
| #if 0 |
| // test |
| uint8_t* buffer = new uint8_t[src.width()]; |
| for (int y = 0; y < src.height(); y++) { |
| const uint8_t* srcRow = src.getAddr8(0, y); |
| SkPackBits::Unpack8(buffer, 0, src.width(), rlePixels->packedAtY(y)); |
| int n = memcmp(buffer, srcRow, src.width()); |
| if (n) { |
| SkDebugf("----- memcmp returned %d on line %d\n", n, y); |
| } |
| SkASSERT(n == 0); |
| } |
| delete[] buffer; |
| |
| size_t totalAlloc = src.height() * sizeof(uint8_t*) + totalPacked; |
| |
| SkDebugf("--- RLE: orig [%d %d] %d, rle %d %d savings %g\n", |
| src.width(), src.height(), src.getSize(), |
| src.height() * sizeof(uint8_t*), totalPacked, |
| (float)totalAlloc / src.getSize()); |
| |
| #endif |
| |
| // transfer ownership of rlePixels to our pixelref |
| return SkNEW_ARGS(RLEPixelRef, (rlePixels, src.getColorTable())); |
| } |
| |