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
RLEPixelRef(SkBitmap::RLEPixels * rlep,SkColorTable * ctable)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
~RLEPixelRef()35 RLEPixelRef::~RLEPixelRef() {
36 SkDELETE(fRLEPixels);
37 SkSafeUnref(fCTable);
38 }
39
onLockPixels(SkColorTable ** ct)40 void* RLEPixelRef::onLockPixels(SkColorTable** ct) {
41 *ct = fCTable;
42 return fRLEPixels;
43 }
44
onUnlockPixels()45 void RLEPixelRef::onUnlockPixels() {
46 // nothing to do
47 }
48
49 /////////////////////////////////////////////////////////////////////////////
50
51 class ChunkRLEPixels : public SkBitmap::RLEPixels {
52 public:
ChunkRLEPixels(int width,int height,size_t chunkSize)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);
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