Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: src/pdf/SkPDFImage.cpp

Issue 22889020: Refactor SkPDFImage (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Simplify comparison in 4-bit case Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright 2010 The Android Open Source Project 2 * Copyright 2010 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkPDFImage.h" 8 #include "SkPDFImage.h"
9 9
10 #include "SkBitmap.h" 10 #include "SkBitmap.h"
11 #include "SkColor.h" 11 #include "SkColor.h"
12 #include "SkColorPriv.h" 12 #include "SkColorPriv.h"
13 #include "SkData.h"
14 #include "SkFlate.h"
13 #include "SkPDFCatalog.h" 15 #include "SkPDFCatalog.h"
14 #include "SkRect.h" 16 #include "SkRect.h"
15 #include "SkStream.h" 17 #include "SkStream.h"
16 #include "SkString.h" 18 #include "SkString.h"
17 #include "SkUnPreMultiply.h" 19 #include "SkUnPreMultiply.h"
18 20
19 namespace { 21 namespace {
vandebo (ex-Chrome) 2013/08/21 22:37:17 Looks like you can probably remove the anonymous n
ducky 2013/08/22 03:48:06 Done.
20 22
21 void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, 23 #define kNoColorTransform 0
vandebo (ex-Chrome) 2013/08/21 22:37:17 const int kNoColorTransform = 0;
ducky 2013/08/22 03:48:06 Done.
22 SkStream** imageData, SkStream** alphaData) {
vandebo (ex-Chrome) 2013/08/21 22:37:17 We talked about the different cases the other day:
ducky 2013/08/22 03:48:06 Done. I think the merged one is less elegant, but
23 SkMemoryStream* image = NULL;
24 SkMemoryStream* alpha = NULL;
25 bool hasAlpha = false;
26 bool isTransparent = false;
27 24
25 static bool skip_compression(SkPDFCatalog* catalog) {
26 return SkToBool(catalog->getDocumentFlags() &
27 SkPDFDocument::kFavorSpeedOverSize_Flags);
28 }
29
30 static size_t get_row_bytes(const SkBitmap& bitmap,
31 const SkIRect& srcRect) {
32 switch (bitmap.getConfig()) {
33 case SkBitmap::kIndex8_Config:
34 return srcRect.width();
35 case SkBitmap::kARGB_4444_Config:
36 return (srcRect.width() * 3 + 1) / 2;
37 case SkBitmap::kRGB_565_Config:
38 return srcRect.width() * 3;
39 case SkBitmap::kARGB_8888_Config:
40 return srcRect.width() * 3;
41 case SkBitmap::kA1_Config:
42 case SkBitmap::kA8_Config:
43 return 1;
44 default:
45 SkASSERT(false);
46 return 0;
47 }
48 }
49
50 static size_t get_uncompressed_size(const SkBitmap& bitmap,
51 const SkIRect& srcRect) {
52 switch (bitmap.getConfig()) {
53 case SkBitmap::kIndex8_Config:
54 case SkBitmap::kARGB_4444_Config:
55 case SkBitmap::kRGB_565_Config:
56 case SkBitmap::kARGB_8888_Config:
57 return get_row_bytes(bitmap, srcRect) * srcRect.height();
58 case SkBitmap::kA1_Config:
59 case SkBitmap::kA8_Config:
60 return 1;
61 default:
62 SkASSERT(false);
63 return 0;
64 }
65 }
66
67 static SkStream* extract_image_data(const SkBitmap& bitmap,
68 const SkIRect& srcRect) {
69 const int rowBytes = get_row_bytes(bitmap, srcRect);
70 SkMemoryStream* image = new SkMemoryStream(get_uncompressed_size(bitmap,
71 srcRect));
28 bitmap.lockPixels(); 72 bitmap.lockPixels();
29 switch (bitmap.getConfig()) { 73 switch (bitmap.getConfig()) {
30 case SkBitmap::kIndex8_Config: { 74 case SkBitmap::kIndex8_Config: {
31 const int rowBytes = srcRect.width();
32 image = new SkMemoryStream(rowBytes * srcRect.height());
33 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 75 uint8_t* dst = (uint8_t*)image->getMemoryBase();
34 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 76 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
35 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); 77 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
36 dst += rowBytes; 78 dst += rowBytes;
37 } 79 }
38 break; 80 break;
39 } 81 }
40 case SkBitmap::kARGB_4444_Config: { 82 case SkBitmap::kARGB_4444_Config: {
41 isTransparent = true;
42 const int rowBytes = (srcRect.width() * 3 + 1) / 2;
43 const int alphaRowBytes = (srcRect.width() + 1) / 2;
44 image = new SkMemoryStream(rowBytes * srcRect.height());
45 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
46 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 83 uint8_t* dst = (uint8_t*)image->getMemoryBase();
47 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
48 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 84 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
49 uint16_t* src = bitmap.getAddr16(0, y); 85 uint16_t* src = bitmap.getAddr16(0, y);
50 int x; 86 int x;
51 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { 87 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
52 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 88 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
vandebo (ex-Chrome) 2013/08/21 22:37:17 UnPreMultiply?
ducky 2013/08/22 03:48:06 I'm going to do unpremul on the bitmap instead of
53 SkGetPackedG4444(src[x]); 89 SkGetPackedG4444(src[x]);
54 dst[1] = (SkGetPackedB4444(src[x]) << 4) | 90 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
55 SkGetPackedR4444(src[x + 1]); 91 SkGetPackedR4444(src[x + 1]);
56 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | 92 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
57 SkGetPackedB4444(src[x + 1]); 93 SkGetPackedB4444(src[x + 1]);
58 dst += 3; 94 dst += 3;
59 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) |
60 SkGetPackedA4444(src[x + 1]);
61 if (alphaDst[0] != 0xFF) {
62 hasAlpha = true;
63 }
64 if (alphaDst[0]) {
65 isTransparent = false;
66 }
67 alphaDst++;
68 } 95 }
69 if (srcRect.width() & 1) { 96 if (srcRect.width() & 1) {
70 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 97 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
71 SkGetPackedG4444(src[x]); 98 SkGetPackedG4444(src[x]);
72 dst[1] = (SkGetPackedB4444(src[x]) << 4); 99 dst[1] = (SkGetPackedB4444(src[x]) << 4);
73 dst += 2; 100 dst += 2;
74 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4);
75 if (alphaDst[0] != 0xF0) {
76 hasAlpha = true;
77 }
78 if (alphaDst[0] & 0xF0) {
79 isTransparent = false;
80 }
81 alphaDst++;
82 } 101 }
83 } 102 }
84 break; 103 break;
85 } 104 }
86 case SkBitmap::kRGB_565_Config: { 105 case SkBitmap::kRGB_565_Config: {
87 const int rowBytes = srcRect.width() * 3;
88 image = new SkMemoryStream(rowBytes * srcRect.height());
89 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 106 uint8_t* dst = (uint8_t*)image->getMemoryBase();
90 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 107 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
91 uint16_t* src = bitmap.getAddr16(0, y); 108 uint16_t* src = bitmap.getAddr16(0, y);
92 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 109 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
93 dst[0] = SkGetPackedR16(src[x]); 110 dst[0] = SkGetPackedR16(src[x]);
94 dst[1] = SkGetPackedG16(src[x]); 111 dst[1] = SkGetPackedG16(src[x]);
95 dst[2] = SkGetPackedB16(src[x]); 112 dst[2] = SkGetPackedB16(src[x]);
96 dst += 3; 113 dst += 3;
97 } 114 }
98 } 115 }
99 break; 116 break;
100 } 117 }
101 case SkBitmap::kARGB_8888_Config: { 118 case SkBitmap::kARGB_8888_Config: {
102 isTransparent = true;
103 const int rowBytes = srcRect.width() * 3;
104 image = new SkMemoryStream(rowBytes * srcRect.height());
105 alpha = new SkMemoryStream(srcRect.width() * srcRect.height());
106 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 119 uint8_t* dst = (uint8_t*)image->getMemoryBase();
107 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
108 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 120 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
109 uint32_t* src = bitmap.getAddr32(0, y); 121 uint32_t* src = bitmap.getAddr32(0, y);
110 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 122 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
111 dst[0] = SkGetPackedR32(src[x]); 123 dst[0] = SkGetPackedR32(src[x]);
112 dst[1] = SkGetPackedG32(src[x]); 124 dst[1] = SkGetPackedG32(src[x]);
113 dst[2] = SkGetPackedB32(src[x]); 125 dst[2] = SkGetPackedB32(src[x]);
114 dst += 3; 126 dst += 3;
115 alphaDst[0] = SkGetPackedA32(src[x]); 127 }
116 if (alphaDst[0] != 0xFF) { 128 }
129 break;
130 }
131 case SkBitmap::kA1_Config:
132 case SkBitmap::kA8_Config: {
133 ((uint8_t*)image->getMemoryBase())[0] = 0;
vandebo (ex-Chrome) 2013/08/21 22:37:17 Sk_ColorBLACK?
ducky 2013/08/22 03:48:06 No can do... SK_ColorBLACK is a 4-byte value conta
134 break;
135 }
136 default:
137 SkASSERT(false);
138 }
139 bitmap.unlockPixels();
140
141 return image;
142 }
143
144 // Extract the alpha data from a SkBitmap and output it in a SkStream.
145 // alphaData may be NULL if there was no alpha data to extract (image
146 // completely opaque).
147 // isTransparent outputs true if the alpha is completely transparent.
148 static SkStream* extract_alpha_data(const SkBitmap& bitmap,
149 const SkIRect& srcRect,
150 bool* isTransparent) {
151 SkMemoryStream* alpha = NULL;
152 bool hasAlpha = false;
153 *isTransparent = true;
154
155 bitmap.lockPixels();
156 switch (bitmap.getConfig()) {
157 case SkBitmap::kARGB_4444_Config: {
158 const int alphaRowBytes = (srcRect.width() + 1) / 2;
159 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
160 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
161 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
162 uint16_t* src = bitmap.getAddr16(0, y);
163 int x;
164 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
165 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) |
166 SkGetPackedA4444(src[x + 1]);
167 if (alphaDst[0] != SK_AlphaOPAQUE) {
117 hasAlpha = true; 168 hasAlpha = true;
118 } 169 }
119 if (alphaDst[0]) { 170 if (alphaDst[0] != SK_AlphaTRANSPARENT) {
120 isTransparent = false; 171 *isTransparent = false;
121 } 172 }
122 alphaDst++; 173 alphaDst++;
123 } 174 }
175 if (srcRect.width() & 1) {
176 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4);
177 if (alphaDst[0] != (SK_AlphaOPAQUE & 0xF0)) {
178 hasAlpha = true;
179 }
180 if (alphaDst[0] != (SK_AlphaTRANSPARENT & 0xF0)) {
181 *isTransparent = false;
182 }
183 alphaDst++;
184 }
185 }
186 break;
187 }
188 case SkBitmap::kARGB_8888_Config: {
189 alpha = new SkMemoryStream(srcRect.width() * srcRect.height());
190 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
191 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
192 uint32_t* src = bitmap.getAddr32(0, y);
193 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
194 alphaDst[0] = SkGetPackedA32(src[x]);
195 if (alphaDst[0] != SK_AlphaOPAQUE) {
196 hasAlpha = true;
197 }
198 if (alphaDst[0] != SK_AlphaTRANSPARENT) {
199 *isTransparent = false;
200 }
201 alphaDst++;
202 }
124 } 203 }
125 break; 204 break;
126 } 205 }
127 case SkBitmap::kA1_Config: { 206 case SkBitmap::kA1_Config: {
128 isTransparent = true;
129 image = new SkMemoryStream(1);
130 ((uint8_t*)image->getMemoryBase())[0] = 0;
131
132 const int alphaRowBytes = (srcRect.width() + 7) / 8; 207 const int alphaRowBytes = (srcRect.width() + 7) / 8;
133 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 208 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
134 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 209 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
135 int offset1 = srcRect.fLeft % 8; 210 int offset1 = srcRect.fLeft % 8;
136 int offset2 = 8 - offset1; 211 int offset2 = 8 - offset1;
137 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 212 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
138 uint8_t* src = bitmap.getAddr1(0, y); 213 uint8_t* src = bitmap.getAddr1(0, y);
139 // This may read up to one byte after src, but the potentially 214 // This may read up to one byte after src, but the potentially
140 // invalid bits are never used for computation. 215 // invalid bits are never used for computation.
141 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { 216 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
142 if (offset1) { 217 if (offset1) {
143 alphaDst[0] = src[x / 8] << offset1 | 218 alphaDst[0] = src[x / 8] << offset1 |
144 src[x / 8 + 1] >> offset2; 219 src[x / 8 + 1] >> offset2;
145 } else { 220 } else {
146 alphaDst[0] = src[x / 8]; 221 alphaDst[0] = src[x / 8];
147 } 222 }
148 if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) { 223 if (x + 7 < srcRect.fRight &&
224 alphaDst[0] != SK_AlphaOPAQUE) {
149 hasAlpha = true; 225 hasAlpha = true;
150 } 226 }
151 if (x + 7 < srcRect.fRight && alphaDst[0]) { 227 if (x + 7 < srcRect.fRight &&
152 isTransparent = false; 228 alphaDst[0] != SK_AlphaTRANSPARENT) {
229 *isTransparent = false;
153 } 230 }
154 alphaDst++; 231 alphaDst++;
155 } 232 }
156 // Calculate the mask of bits we're interested in within the 233 // Calculate the mask of bits we're interested in within the
157 // last byte of alphaDst. 234 // last byte of alphaDst.
158 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE 235 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
159 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); 236 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
160 if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) { 237 if (srcRect.width() % 8 &&
238 ((alphaDst[-1] & mask) != (SK_AlphaOPAQUE & mask))) {
161 hasAlpha = true; 239 hasAlpha = true;
162 } 240 }
163 if (srcRect.width() % 8 && (alphaDst[-1] & mask)) { 241 if (srcRect.width() % 8 &&
164 isTransparent = false; 242 ((alphaDst[-1] & mask) != (SK_AlphaTRANSPARENT & mask))) {
243 *isTransparent = false;
165 } 244 }
166 } 245 }
167 break; 246 break;
168 } 247 }
169 case SkBitmap::kA8_Config: { 248 case SkBitmap::kA8_Config: {
170 isTransparent = true;
171 image = new SkMemoryStream(1);
172 ((uint8_t*)image->getMemoryBase())[0] = 0;
173
174 const int alphaRowBytes = srcRect.width(); 249 const int alphaRowBytes = srcRect.width();
175 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 250 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
176 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 251 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
177 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 252 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
178 uint8_t* src = bitmap.getAddr8(0, y); 253 uint8_t* src = bitmap.getAddr8(0, y);
179 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 254 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
180 alphaDst[0] = src[x]; 255 alphaDst[0] = src[x];
181 if (alphaDst[0] != 0xFF) { 256 if (alphaDst[0] != SK_AlphaOPAQUE) {
182 hasAlpha = true; 257 hasAlpha = true;
183 } 258 }
184 if (alphaDst[0]) { 259 if (alphaDst[0] != SK_AlphaTRANSPARENT) {
185 isTransparent = false; 260 *isTransparent = false;
186 } 261 }
187 alphaDst++; 262 alphaDst++;
188 } 263 }
189 } 264 }
190 break; 265 break;
191 } 266 }
267 case SkBitmap::kRGB_565_Config:
268 case SkBitmap::kIndex8_Config: {
269 *isTransparent = false;
270 break;
271 }
192 default: 272 default:
193 SkASSERT(false); 273 SkASSERT(false);
194 } 274 }
195 bitmap.unlockPixels(); 275 bitmap.unlockPixels();
196 276
197 if (isTransparent) { 277 if (!hasAlpha || *isTransparent) {
198 SkSafeUnref(image); 278 SkSafeUnref(alpha);
279 return NULL;
199 } else { 280 } else {
200 *imageData = image; 281 return alpha;
201 }
202
203 if (isTransparent || !hasAlpha) {
204 SkSafeUnref(alpha);
205 } else {
206 *alphaData = alpha;
207 } 282 }
208 } 283 }
209 284
210 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { 285 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
211 SkPDFArray* result = new SkPDFArray(); 286 SkPDFArray* result = new SkPDFArray();
212 result->reserve(4); 287 result->reserve(4);
213 result->appendName("Indexed"); 288 result->appendName("Indexed");
214 result->appendName("DeviceRGB"); 289 result->appendName("DeviceRGB");
215 result->appendInt(table->count() - 1); 290 result->appendInt(table->count() - 1);
216 291
(...skipping 14 matching lines...) Expand all
231 306
232 }; // namespace 307 }; // namespace
233 308
234 // static 309 // static
235 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 310 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
236 const SkIRect& srcRect, 311 const SkIRect& srcRect,
237 EncodeToDCTStream encoder) { 312 EncodeToDCTStream encoder) {
238 if (bitmap.getConfig() == SkBitmap::kNo_Config) { 313 if (bitmap.getConfig() == SkBitmap::kNo_Config) {
239 return NULL; 314 return NULL;
240 } 315 }
316 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder));
241 317
242 SkStream* imageData = NULL; 318 if (image->isEmpty()) {
vandebo (ex-Chrome) 2013/08/21 22:37:17 isEmpty just checks srcRect. 1) I think that's a
ducky 2013/08/22 03:48:06 Good point, it probably does change behavior. What
243 SkStream* alphaData = NULL; 319 image->unref();
244 extractImageData(bitmap, srcRect, &imageData, &alphaData);
245 SkAutoUnref unrefImageData(imageData);
246 SkAutoUnref unrefAlphaData(alphaData);
247 if (!imageData) {
248 SkASSERT(!alphaData);
249 return NULL; 320 return NULL;
321 } else {
322 return image;
250 } 323 }
251
252 SkPDFImage* image =
253 SkNEW_ARGS(SkPDFImage, (imageData, bitmap, srcRect, false, encoder));
254
255 if (alphaData != NULL) {
256 // Don't try to use DCT compression with alpha because alpha is small
257 // anyway and it could lead to artifacts.
258 image->addSMask(SkNEW_ARGS(SkPDFImage, (alphaData, bitmap, srcRect, true , NULL)))->unref();
259 }
260 return image;
261 } 324 }
262 325
263 SkPDFImage::~SkPDFImage() { 326 SkPDFImage::~SkPDFImage() {
264 fResources.unrefAll(); 327 fResources.unrefAll();
265 } 328 }
266 329
267 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 330 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
268 fResources.push(mask); 331 fResources.push(mask);
269 mask->ref(); 332 mask->ref();
270 insert("SMask", new SkPDFObjRef(mask))->unref(); 333 insert("SMask", new SkPDFObjRef(mask))->unref();
271 return mask; 334 return mask;
272 } 335 }
273 336
274 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 337 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
275 SkTSet<SkPDFObject*>* newResourceObjects) { 338 SkTSet<SkPDFObject*>* newResourceObjects) {
276 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); 339 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
277 } 340 }
278 341
279 SkPDFImage::SkPDFImage(SkStream* imageData, 342 SkPDFImage::SkPDFImage(const SkBitmap& bitmap,
280 const SkBitmap& bitmap,
281 const SkIRect& srcRect, 343 const SkIRect& srcRect,
282 bool doingAlpha,
283 EncodeToDCTStream encoder) 344 EncodeToDCTStream encoder)
284 : SkPDFImageStream(imageData, bitmap, srcRect, encoder) { 345 : fBitmap(bitmap),
285 SkBitmap::Config config = bitmap.getConfig(); 346 fSrcRect(srcRect),
286 bool alphaOnly = (config == SkBitmap::kA1_Config || 347 fEncoder(encoder) {
287 config == SkBitmap::kA8_Config); 348 bool isTransparent;
349 SkAutoTUnref<SkStream> alphaData(extract_alpha_data(bitmap, srcRect,
350 &isTransparent));
351 if (isTransparent) {
352 fSrcRect = SkIRect::MakeEmpty();
353 return;
354 }
355 if (alphaData.get() != NULL) {
356 addSMask(SkNEW_ARGS(SkPDFImage,
357 (alphaData.get(), bitmap, srcRect)))->unref();
358 }
359
360 initImageParams(false);
361 }
362
363 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap,
364 const SkIRect& srcRect)
365 : fBitmap(bitmap),
366 fSrcRect(srcRect),
367 fEncoder(NULL) {
368 setData(stream);
369 insertInt("Length", getData()->getLength());
370 setState(kNoCompression_State);
371
372 initImageParams(true);
373 }
374
375 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
376 : SkPDFStream(pdfImage),
377 fBitmap(pdfImage.fBitmap),
378 fSrcRect(pdfImage.fSrcRect),
379 fEncoder(pdfImage.fEncoder){
380 // Nothing to do here - the image params are already copied in SkPDFStream's
vandebo (ex-Chrome) 2013/08/21 22:37:17 Remove comment.
ducky 2013/08/22 03:48:06 I think the comment about SkPDFStream is helpful -
381 // constructor, and the bitmap will be regenerated and re-encoded in
382 // populate.
383 }
384
385 void SkPDFImage::initImageParams(bool isAlpha) {
386 SkBitmap::Config config = fBitmap.getConfig();
288 387
289 insertName("Type", "XObject"); 388 insertName("Type", "XObject");
290 insertName("Subtype", "Image"); 389 insertName("Subtype", "Image");
291 390
292 if (!doingAlpha && alphaOnly) { 391 bool alphaOnly = (config == SkBitmap::kA1_Config ||
392 config == SkBitmap::kA8_Config);
393
394 if (!isAlpha && alphaOnly) {
293 // For alpha only images, we stretch a single pixel of black for 395 // For alpha only images, we stretch a single pixel of black for
294 // the color/shape part. 396 // the color/shape part.
295 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); 397 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
296 insert("Width", one.get()); 398 insert("Width", one.get());
297 insert("Height", one.get()); 399 insert("Height", one.get());
298 } else { 400 } else {
299 insertInt("Width", srcRect.width()); 401 insertInt("Width", fSrcRect.width());
300 insertInt("Height", srcRect.height()); 402 insertInt("Height", fSrcRect.height());
301 } 403 }
302 404
303 // if (!image mask) { 405 if (isAlpha || alphaOnly) {
304 if (doingAlpha || alphaOnly) {
305 insertName("ColorSpace", "DeviceGray"); 406 insertName("ColorSpace", "DeviceGray");
306 } else if (config == SkBitmap::kIndex8_Config) { 407 } else if (config == SkBitmap::kIndex8_Config) {
307 SkAutoLockPixels alp(bitmap); 408 SkAutoLockPixels alp(fBitmap);
308 insert("ColorSpace", 409 insert("ColorSpace",
309 makeIndexedColorSpace(bitmap.getColorTable()))->unref(); 410 makeIndexedColorSpace(fBitmap.getColorTable()))->unref();
310 } else { 411 } else {
311 insertName("ColorSpace", "DeviceRGB"); 412 insertName("ColorSpace", "DeviceRGB");
312 } 413 }
313 // }
314 414
315 int bitsPerComp = 8; 415 int bitsPerComp = 8;
316 if (config == SkBitmap::kARGB_4444_Config) { 416 if (config == SkBitmap::kARGB_4444_Config) {
317 bitsPerComp = 4; 417 bitsPerComp = 4;
318 } else if (doingAlpha && config == SkBitmap::kA1_Config) { 418 } else if (isAlpha && config == SkBitmap::kA1_Config) {
319 bitsPerComp = 1; 419 bitsPerComp = 1;
320 } 420 }
321 insertInt("BitsPerComponent", bitsPerComp); 421 insertInt("BitsPerComponent", bitsPerComp);
322 422
323 if (config == SkBitmap::kRGB_565_Config) { 423 if (config == SkBitmap::kRGB_565_Config) {
424 SkASSERT(!isAlpha);
324 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); 425 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
325 SkAutoTUnref<SkPDFScalar> scale5Val( 426 SkAutoTUnref<SkPDFScalar> scale5Val(
326 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1 427 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1
327 SkAutoTUnref<SkPDFScalar> scale6Val( 428 SkAutoTUnref<SkPDFScalar> scale6Val(
328 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1 429 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1
329 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); 430 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
330 decodeValue->reserve(6); 431 decodeValue->reserve(6);
331 decodeValue->append(zeroVal.get()); 432 decodeValue->append(zeroVal.get());
332 decodeValue->append(scale5Val.get()); 433 decodeValue->append(scale5Val.get());
333 decodeValue->append(zeroVal.get()); 434 decodeValue->append(zeroVal.get());
334 decodeValue->append(scale6Val.get()); 435 decodeValue->append(scale6Val.get());
335 decodeValue->append(zeroVal.get()); 436 decodeValue->append(zeroVal.get());
336 decodeValue->append(scale5Val.get()); 437 decodeValue->append(scale5Val.get());
337 insert("Decode", decodeValue.get()); 438 insert("Decode", decodeValue.get());
338 } 439 }
339 } 440 }
441
442 SkStream* SkPDFImage::getCompressedStream() {
443 SkDynamicMemoryWStream dctCompressedWStream;
444 if (fEncoder && fEncoder(&dctCompressedWStream, fBitmap, fSrcRect)) {
vandebo (ex-Chrome) 2013/08/21 22:37:17 This doesn't handle the case where the image has a
ducky 2013/08/22 03:48:06 Yeah, this regressed a quite a few tests... fixed.
445 // Ensure compressed version is smaller than the uncompressed version
446 if (dctCompressedWStream.getOffset() <
447 get_uncompressed_size(fBitmap, fSrcRect)) {
vandebo (ex-Chrome) 2013/08/21 22:37:17 if get_uncompressed_size is 1, you probably should
ducky 2013/08/22 03:48:06 Done.
448 SkData* data = dctCompressedWStream.copyToData();
449 SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (data));
450 data->unref();
451 return stream;
452 }
453 }
454 return NULL;
455 }
456
457 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
458 if (getState() == kUnused_State) {
459 // Initializing image data for the first time.
460 if (!skip_compression(catalog)) {
461 SkAutoTUnref<SkStream> stream(getCompressedStream());
462 if (stream.get() != NULL) {
463 setData(stream.get());
464 insertName("Filter", "DCTDecode");
465 insertInt("ColorTransform", kNoColorTransform);
466 insertInt("Length", getData()->getLength());
467 setState(kCompressed_State);
468 }
469 }
470
471 // Fallback if it doesn't work.
472 if (getState() == kUnused_State) {
473 SkAutoTUnref<SkStream> stream(extract_image_data(fBitmap,
474 fSrcRect));
475 setData(stream.get());
476 return INHERITED::populate(catalog);
477 }
478 } else if (getState() == kNoCompression_State &&
479 !skip_compression(catalog) &&
480 (SkFlate::HaveFlate() || fEncoder)) {
481 // Compression has not been requested when the stream was first created.
482 // But a new Catalog would want it compressed.
vandebo (ex-Chrome) 2013/08/21 22:37:17 ...created, but the new catalog wants it compresse
ducky 2013/08/22 03:48:06 Done.
483 if (!getSubstitute()) {
484 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
485 setSubstitute(substitute);
486 catalog->setSubstitute(this, substitute);
487 }
488 return false;
489 }
490 return true;
491 }
OLDNEW
« src/pdf/SkPDFImage.h ('K') | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698