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

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

Issue 22889020: Refactor SkPDFImage (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: A slightly different style 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
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 static const int kNoColorTransform = 0;
20 22
21 void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, 23 static bool skip_compression(SkPDFCatalog* catalog) {
22 SkStream** imageData, SkStream** alphaData) { 24 return SkToBool(catalog->getDocumentFlags() &
23 SkMemoryStream* image = NULL; 25 SkPDFDocument::kFavorSpeedOverSize_Flags);
24 SkMemoryStream* alpha = NULL; 26 }
27
28 static size_t get_row_bytes(const SkBitmap& bitmap,
29 const SkIRect& srcRect) {
30 switch (bitmap.getConfig()) {
31 case SkBitmap::kIndex8_Config:
32 return srcRect.width();
33 case SkBitmap::kARGB_4444_Config:
34 return (srcRect.width() * 3 + 1) / 2;
35 case SkBitmap::kRGB_565_Config:
36 return srcRect.width() * 3;
37 case SkBitmap::kARGB_8888_Config:
38 return srcRect.width() * 3;
39 case SkBitmap::kA1_Config:
40 case SkBitmap::kA8_Config:
41 return 1;
42 default:
43 SkASSERT(false);
44 return 0;
45 }
46 }
47
48 static size_t get_uncompressed_size(const SkBitmap& bitmap,
49 const SkIRect& srcRect) {
50 switch (bitmap.getConfig()) {
51 case SkBitmap::kIndex8_Config:
52 case SkBitmap::kARGB_4444_Config:
53 case SkBitmap::kRGB_565_Config:
54 case SkBitmap::kARGB_8888_Config:
55 return get_row_bytes(bitmap, srcRect) * srcRect.height();
vandebo (ex-Chrome) 2013/08/23 05:25:20 Here and extract_index8_image are the only place t
ducky 2013/08/23 06:59:08 Done.
56 case SkBitmap::kA1_Config:
57 case SkBitmap::kA8_Config:
58 return 1;
59 default:
60 SkASSERT(false);
61 return 0;
62 }
63 }
64
65 static SkStream* extract_index8_image(const SkBitmap& bitmap,
66 const SkIRect& srcRect) {
67 const int rowBytes = get_row_bytes(bitmap, srcRect);
68 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
69 (rowBytes * srcRect.height()));
70 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
71
72 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
73 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
74 dst += rowBytes;
75 }
76 return stream;
77 }
78
79 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
80 const SkIRect& srcRect,
81 bool extractAlpha,
82 bool* hasAlpha,
vandebo (ex-Chrome) 2013/08/23 05:25:20 If it doesn't have alpha, or is completely transpa
ducky 2013/08/23 06:59:08 But they're necessary for the optimizations: you n
vandebo (ex-Chrome) 2013/08/23 15:45:35 Ok, but you don't need both of them. I would sugge
ducky 2013/08/23 17:59:50 Both are here so that the final check if transpare
83 bool* isTransparent) {
84 SkStream* stream;
85 uint8_t* dst = NULL;
86 if (extractAlpha) {
87 const int alphaRowBytes = (srcRect.width() + 1) / 2;
88 stream = SkNEW_ARGS(SkMemoryStream,
89 (alphaRowBytes * srcRect.height()));
90 } else {
91 stream = SkNEW_ARGS(SkMemoryStream,
92 (get_uncompressed_size(bitmap, srcRect)));
93 }
94 dst = (uint8_t*)stream->getMemoryBase();
95
96 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
97 uint16_t* src = bitmap.getAddr16(0, y);
98 int x;
99 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
100 if (extractAlpha) {
101 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
102 SkGetPackedA4444(src[x + 1]);
103 if (dst[0] != SK_AlphaOPAQUE) {
vandebo (ex-Chrome) 2013/08/23 05:25:20 This can probably made more streamlined.... hasAl
ducky 2013/08/23 06:59:08 Nice. Will do.
104 *hasAlpha = true;
105 }
106 if (dst[0] != SK_AlphaTRANSPARENT) {
107 *isTransparent = false;
108 }
109 dst++;
110 } else {
111 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
112 SkGetPackedG4444(src[x]);
113 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
114 SkGetPackedR4444(src[x + 1]);
115 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
116 SkGetPackedB4444(src[x + 1]);
117 dst += 3;
118 }
119 }
120 if (srcRect.width() & 1) {
121 if (extractAlpha) {
122 dst[0] = (SkGetPackedA4444(src[x]) << 4);
123 if (dst[0] != (SK_AlphaOPAQUE & 0xF0)) {
124 *hasAlpha = true;
vandebo (ex-Chrome) 2013/08/23 05:25:20 A better name for hasAlpha is probably the opposit
ducky 2013/08/23 06:59:08 Ok. It does become more consistent with SkBitmap t
125 }
126 if (dst[0] != (SK_AlphaTRANSPARENT & 0xF0)) {
127 *isTransparent = false;
128 }
129 dst++;
130
131 } else {
132 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
133 SkGetPackedG4444(src[x]);
134 dst[1] = (SkGetPackedB4444(src[x]) << 4);
135 dst += 2;
136 }
137 }
138 }
139 return stream;
140 }
141
142 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
143 const SkIRect& srcRect) {
144 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
145 (get_uncompressed_size(bitmap,
146 srcRect)));
147 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
148 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
149 uint16_t* src = bitmap.getAddr16(0, y);
150 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
151 dst[0] = SkGetPackedR16(src[x]);
152 dst[1] = SkGetPackedG16(src[x]);
153 dst[2] = SkGetPackedB16(src[x]);
154 dst += 3;
155 }
156 }
157 return stream;
158 }
159
160 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
161 const SkIRect& srcRect,
162 bool extractAlpha,
163 bool* hasAlpha,
164 bool* isTransparent) {
165 SkStream* stream;
166 if (extractAlpha) {
167 stream = SkNEW_ARGS(SkMemoryStream,
168 (srcRect.width() * srcRect.height()));
169 } else {
170 stream = SkNEW_ARGS(SkMemoryStream,
171 (get_uncompressed_size(bitmap, srcRect)));
172 }
173 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
174
175 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
176 uint32_t* src = bitmap.getAddr32(0, y);
177 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
178 if (extractAlpha) {
179 dst[0] = SkGetPackedA32(src[x]);
180 if (dst[0] != SK_AlphaOPAQUE) {
181 *hasAlpha = true;
182 }
183 if (dst[0] != SK_AlphaTRANSPARENT) {
184 *isTransparent = false;
185 }
186 dst++;
187 } else {
188 dst[0] = SkGetPackedR32(src[x]);
189 dst[1] = SkGetPackedG32(src[x]);
190 dst[2] = SkGetPackedB32(src[x]);
191 dst += 3;
192 }
193 }
194 }
195 return stream;
196 }
197
198 static SkStream* extract_a1_alpha(const SkBitmap& bitmap,
199 const SkIRect& srcRect,
200 bool* hasAlpha,
201 bool* isTransparent) {
202 const int alphaRowBytes = (srcRect.width() + 7) / 8;
203 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
204 (alphaRowBytes * srcRect.height()));
205 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
206
207 int offset1 = srcRect.fLeft % 8;
208 int offset2 = 8 - offset1;
209
210 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
211 uint8_t* src = bitmap.getAddr1(0, y);
212 // This may read up to one byte after src, but the
213 // potentially invalid bits are never used for computation.
214 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
215 if (offset1) {
216 alphaDst[0] = src[x / 8] << offset1 |
217 src[x / 8 + 1] >> offset2;
218 } else {
219 alphaDst[0] = src[x / 8];
220 }
221 if (x + 7 < srcRect.fRight && alphaDst[0] != SK_AlphaOPAQUE) {
222 *hasAlpha = true;
223 }
224 if (x + 7 < srcRect.fRight && alphaDst[0] != SK_AlphaTRANSPARENT) {
225 *isTransparent = false;
226 }
227 alphaDst++;
228 }
229 // Calculate the mask of bits we're interested in within the
230 // last byte of alphaDst.
231 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
232 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
233 if (srcRect.width() % 8 &&
234 (alphaDst[-1] & mask) != (SK_AlphaOPAQUE & mask)) {
235 *hasAlpha = true;
236 }
237 if (srcRect.width() % 8 &&
238 (alphaDst[-1] & mask) != (SK_AlphaTRANSPARENT & mask)) {
239 *isTransparent = false;
240 }
241 }
242 return stream;
243 }
244
245 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
246 const SkIRect& srcRect,
247 bool* hasAlpha,
248 bool* isTransparent) {
249 const int alphaRowBytes = srcRect.width();
250 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
251 (alphaRowBytes * srcRect.height()));
252 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
253
254 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
255 uint8_t* src = bitmap.getAddr8(0, y);
256 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
257 alphaDst[0] = src[x];
258 if (alphaDst[0] != SK_AlphaOPAQUE) {
259 *hasAlpha = true;
260 }
261 if (alphaDst[0] != SK_AlphaTRANSPARENT) {
262 *isTransparent = false;
263 }
264 alphaDst++;
265 }
266 }
267 return stream;
268 }
269
270 static SkStream* create_black_image() {
271 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
272 ((uint8_t*)stream->getMemoryBase())[0] = 0;
273 return stream;
274 }
275
276 /**
277 * Extract image data to a SkStream. Interlaced alpha is separated into alpha
vandebo (ex-Chrome) 2013/08/23 05:25:20 Interlaced usually refers to lines/horizontal stri
ducky 2013/08/23 06:59:08 Done.
278 * and image streams.
279 * @param bitmap Bitmap to extract data from.
280 * @param srcRect Region in the bitmap to extract.
281 * @param extractAlpha Set to true to extract the alpha data, or false to
282 * extract the color data.
283 * @param transparent Whether the alpha is completely transparent. Only valid
284 * when extractAlpha == true.
285 * @return Unencoded image data, or NULL if data was not available
286 * OR alpha data was requested but the image was entirely
287 * transparent or opaque.
vandebo (ex-Chrome) 2013/08/23 05:25:20 If Null is returned when the image is transparent,
ducky 2013/08/23 06:59:08 Necessary to differentiate from opaque case (where
288 */
289 static SkStream* extract_image_data(const SkBitmap& bitmap,
290 const SkIRect& srcRect,
291 bool extractAlpha, bool* isTransparent) {
292 SkStream* stream = NULL;
25 bool hasAlpha = false; 293 bool hasAlpha = false;
26 bool isTransparent = false; 294 *isTransparent = true;
27 295
vandebo (ex-Chrome) 2013/08/23 05:25:20 Probably easier to have an early return for the al
ducky 2013/08/23 06:59:08 Ehhhhh - the current style uses consistent mechani
vandebo (ex-Chrome) 2013/08/23 15:45:35 Disagree. Not sure what you mean by consistent me
ducky 2013/08/23 17:59:50 I see - done. On 2013/08/23 15:45:35, vandebo wro
28 bitmap.lockPixels(); 296 bitmap.lockPixels();
29 switch (bitmap.getConfig()) { 297 switch (bitmap.getConfig()) {
30 case SkBitmap::kIndex8_Config: { 298 case SkBitmap::kIndex8_Config:
31 const int rowBytes = srcRect.width(); 299 if (!extractAlpha) {
32 image = new SkMemoryStream(rowBytes * srcRect.height()); 300 stream = extract_index8_image(bitmap, srcRect);
vandebo (ex-Chrome) 2013/08/23 05:25:20 Use of functions makes this one easier to follow.
ducky 2013/08/23 06:59:08 Yeah, the old one was getting super bloated...
33 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 301 } else {
34 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 302 *isTransparent = false;
35 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); 303 }
36 dst += rowBytes; 304 break;
37 } 305 case SkBitmap::kARGB_4444_Config:
38 break; 306 stream = extract_argb4444_data(bitmap, srcRect, extractAlpha,
39 } 307 &hasAlpha, isTransparent);
40 case SkBitmap::kARGB_4444_Config: { 308 break;
41 isTransparent = true; 309 case SkBitmap::kRGB_565_Config:
42 const int rowBytes = (srcRect.width() * 3 + 1) / 2; 310 if (!extractAlpha) {
43 const int alphaRowBytes = (srcRect.width() + 1) / 2; 311 stream = extract_rgb565_image(bitmap, srcRect);
44 image = new SkMemoryStream(rowBytes * srcRect.height()); 312 } else {
45 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 313 *isTransparent = false;
46 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 314 }
47 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 315 break;
48 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 316 case SkBitmap::kARGB_8888_Config:
49 uint16_t* src = bitmap.getAddr16(0, y); 317 stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
50 int x; 318 &hasAlpha, isTransparent);
51 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { 319 break;
52 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 320 case SkBitmap::kA1_Config:
53 SkGetPackedG4444(src[x]); 321 if (extractAlpha) {
54 dst[1] = (SkGetPackedB4444(src[x]) << 4) | 322 stream = extract_a1_alpha(bitmap, srcRect,
55 SkGetPackedR4444(src[x + 1]); 323 &hasAlpha, isTransparent);
56 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | 324 } else {
57 SkGetPackedB4444(src[x + 1]); 325 stream = create_black_image();
58 dst += 3; 326 }
59 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) | 327 break;
60 SkGetPackedA4444(src[x + 1]); 328 case SkBitmap::kA8_Config:
61 if (alphaDst[0] != 0xFF) { 329 if (extractAlpha) {
62 hasAlpha = true; 330 stream = extract_a8_alpha(bitmap, srcRect,
63 } 331 &hasAlpha, isTransparent);
64 if (alphaDst[0]) { 332 } else {
65 isTransparent = false; 333 stream = create_black_image();
66 } 334 }
67 alphaDst++; 335 break;
68 }
69 if (srcRect.width() & 1) {
70 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
71 SkGetPackedG4444(src[x]);
72 dst[1] = (SkGetPackedB4444(src[x]) << 4);
73 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 }
83 }
84 break;
85 }
86 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();
90 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
91 uint16_t* src = bitmap.getAddr16(0, y);
92 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
93 dst[0] = SkGetPackedR16(src[x]);
94 dst[1] = SkGetPackedG16(src[x]);
95 dst[2] = SkGetPackedB16(src[x]);
96 dst += 3;
97 }
98 }
99 break;
100 }
101 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();
107 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
108 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
109 uint32_t* src = bitmap.getAddr32(0, y);
110 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
111 dst[0] = SkGetPackedR32(src[x]);
112 dst[1] = SkGetPackedG32(src[x]);
113 dst[2] = SkGetPackedB32(src[x]);
114 dst += 3;
115 alphaDst[0] = SkGetPackedA32(src[x]);
116 if (alphaDst[0] != 0xFF) {
117 hasAlpha = true;
118 }
119 if (alphaDst[0]) {
120 isTransparent = false;
121 }
122 alphaDst++;
123 }
124 }
125 break;
126 }
127 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;
133 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
134 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
135 int offset1 = srcRect.fLeft % 8;
136 int offset2 = 8 - offset1;
137 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
138 uint8_t* src = bitmap.getAddr1(0, y);
139 // This may read up to one byte after src, but the potentially
140 // invalid bits are never used for computation.
141 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
142 if (offset1) {
143 alphaDst[0] = src[x / 8] << offset1 |
144 src[x / 8 + 1] >> offset2;
145 } else {
146 alphaDst[0] = src[x / 8];
147 }
148 if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) {
149 hasAlpha = true;
150 }
151 if (x + 7 < srcRect.fRight && alphaDst[0]) {
152 isTransparent = false;
153 }
154 alphaDst++;
155 }
156 // Calculate the mask of bits we're interested in within the
157 // last byte of alphaDst.
158 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
159 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
160 if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) {
161 hasAlpha = true;
162 }
163 if (srcRect.width() % 8 && (alphaDst[-1] & mask)) {
164 isTransparent = false;
165 }
166 }
167 break;
168 }
169 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();
175 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
176 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
177 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
178 uint8_t* src = bitmap.getAddr8(0, y);
179 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
180 alphaDst[0] = src[x];
181 if (alphaDst[0] != 0xFF) {
182 hasAlpha = true;
183 }
184 if (alphaDst[0]) {
185 isTransparent = false;
186 }
187 alphaDst++;
188 }
189 }
190 break;
191 }
192 default: 336 default:
193 SkASSERT(false); 337 SkASSERT(false);
194 } 338 }
195 bitmap.unlockPixels(); 339 bitmap.unlockPixels();
196 340
197 if (isTransparent) { 341 if (extractAlpha && (*isTransparent || !hasAlpha)) {
198 SkSafeUnref(image); 342 SkSafeUnref(stream);
199 } else { 343 return NULL;
200 *imageData = image; 344 }
201 } 345 return stream;
202 346 }
203 if (isTransparent || !hasAlpha) { 347
204 SkSafeUnref(alpha); 348 static SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
vandebo (ex-Chrome) 2013/08/23 05:25:20 static functions should have hacker case: make_ind
ducky 2013/08/23 06:59:08 Missed updating this one... done.
205 } else {
206 *alphaData = alpha;
207 }
208 }
209
210 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
211 SkPDFArray* result = new SkPDFArray(); 349 SkPDFArray* result = new SkPDFArray();
212 result->reserve(4); 350 result->reserve(4);
213 result->appendName("Indexed"); 351 result->appendName("Indexed");
214 result->appendName("DeviceRGB"); 352 result->appendName("DeviceRGB");
215 result->appendInt(table->count() - 1); 353 result->appendInt(table->count() - 1);
216 354
217 // Potentially, this could be represented in fewer bytes with a stream. 355 // Potentially, this could be represented in fewer bytes with a stream.
218 // Max size as a string is 1.5k. 356 // Max size as a string is 1.5k.
219 SkString index; 357 SkString index;
220 for (int i = 0; i < table->count(); i++) { 358 for (int i = 0; i < table->count(); i++) {
221 char buf[3]; 359 char buf[3];
222 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); 360 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
223 buf[0] = SkGetPackedR32(color); 361 buf[0] = SkGetPackedR32(color);
224 buf[1] = SkGetPackedG32(color); 362 buf[1] = SkGetPackedG32(color);
225 buf[2] = SkGetPackedB32(color); 363 buf[2] = SkGetPackedB32(color);
226 index.append(buf, 3); 364 index.append(buf, 3);
227 } 365 }
228 result->append(new SkPDFString(index))->unref(); 366 result->append(new SkPDFString(index))->unref();
229 return result; 367 return result;
230 } 368 }
231 369
232 }; // namespace
233
234 // static 370 // static
235 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 371 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
236 const SkIRect& srcRect, 372 const SkIRect& srcRect,
237 EncodeToDCTStream encoder) { 373 EncodeToDCTStream encoder) {
238 if (bitmap.getConfig() == SkBitmap::kNo_Config) { 374 if (bitmap.getConfig() == SkBitmap::kNo_Config) {
239 return NULL; 375 return NULL;
240 } 376 }
241 377
242 SkStream* imageData = NULL; 378 bool isTransparent;
243 SkStream* alphaData = NULL; 379 SkAutoTUnref<SkStream> alphaData(
vandebo (ex-Chrome) 2013/08/23 05:45:10 nit: if bitmap.isOpaque() is set, then you can ski
ducky 2013/08/23 06:59:08 Done, along with cautionary comment. Are there any
244 extractImageData(bitmap, srcRect, &imageData, &alphaData); 380 extract_image_data(bitmap, srcRect, true, &isTransparent));
245 SkAutoUnref unrefImageData(imageData); 381 if (isTransparent) {
246 SkAutoUnref unrefAlphaData(alphaData);
247 if (!imageData) {
248 SkASSERT(!alphaData);
249 return NULL; 382 return NULL;
250 } 383 }
251 384
252 SkPDFImage* image = 385 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder));
253 SkNEW_ARGS(SkPDFImage, (imageData, bitmap, srcRect, false, encoder)); 386 if (alphaData.get() != NULL) {
387 SkAutoTUnref<SkPDFImage> mask(
388 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, srcRect)));
389 image->addSMask(mask);
390 }
254 391
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; 392 return image;
261 } 393 }
262 394
263 SkPDFImage::~SkPDFImage() { 395 SkPDFImage::~SkPDFImage() {
264 fResources.unrefAll(); 396 fResources.unrefAll();
265 } 397 }
266 398
267 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 399 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
268 fResources.push(mask); 400 fResources.push(mask);
269 mask->ref(); 401 mask->ref();
270 insert("SMask", new SkPDFObjRef(mask))->unref(); 402 insert("SMask", new SkPDFObjRef(mask))->unref();
271 return mask; 403 return mask;
272 } 404 }
273 405
274 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 406 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
275 SkTSet<SkPDFObject*>* newResourceObjects) { 407 SkTSet<SkPDFObject*>* newResourceObjects) {
276 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); 408 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
277 } 409 }
278 410
279 SkPDFImage::SkPDFImage(SkStream* imageData, 411 SkPDFImage::SkPDFImage(const SkBitmap& bitmap,
280 const SkBitmap& bitmap,
281 const SkIRect& srcRect, 412 const SkIRect& srcRect,
282 bool doingAlpha,
283 EncodeToDCTStream encoder) 413 EncodeToDCTStream encoder)
284 : SkPDFImageStream(imageData, bitmap, srcRect, encoder) { 414 : fBitmap(bitmap),
285 SkBitmap::Config config = bitmap.getConfig(); 415 fSrcRect(srcRect),
286 bool alphaOnly = (config == SkBitmap::kA1_Config || 416 fEncoder(encoder),
287 config == SkBitmap::kA8_Config); 417 fStreamValid(false) {
418 initImageParams(false);
419 }
420
421 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap,
vandebo (ex-Chrome) 2013/08/23 05:25:20 This constructor is effectively the same as the pr
ducky 2013/08/23 06:59:08 Done - it is cleaner in many regards. I've clarifi
422 const SkIRect& srcRect)
423 : fBitmap(bitmap),
424 fSrcRect(srcRect),
425 fEncoder(NULL),
426 fStreamValid(true) {
427 setData(stream);
428 initImageParams(true);
429 }
430
431 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
432 : SkPDFStream(pdfImage),
433 fBitmap(pdfImage.fBitmap),
434 fSrcRect(pdfImage.fSrcRect),
435 fEncoder(pdfImage.fEncoder),
436 fStreamValid(pdfImage.fStreamValid) {
437 // Nothing to do here - the image params are already copied in SkPDFStream's
438 // constructor, and the bitmap will be regenerated and re-encoded in
vandebo (ex-Chrome) 2013/08/23 05:25:20 "...regenerated and re-encoded..." => encoded
ducky 2013/08/23 06:59:08 Done.
439 // populate.
440 }
441
442 void SkPDFImage::initImageParams(bool isAlpha) {
443 SkBitmap::Config config = fBitmap.getConfig();
288 444
289 insertName("Type", "XObject"); 445 insertName("Type", "XObject");
290 insertName("Subtype", "Image"); 446 insertName("Subtype", "Image");
291 447
292 if (!doingAlpha && alphaOnly) { 448 bool alphaOnly = (config == SkBitmap::kA1_Config ||
449 config == SkBitmap::kA8_Config);
450
451 if (!isAlpha && alphaOnly) {
293 // For alpha only images, we stretch a single pixel of black for 452 // For alpha only images, we stretch a single pixel of black for
294 // the color/shape part. 453 // the color/shape part.
295 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); 454 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
296 insert("Width", one.get()); 455 insert("Width", one.get());
297 insert("Height", one.get()); 456 insert("Height", one.get());
298 } else { 457 } else {
299 insertInt("Width", srcRect.width()); 458 insertInt("Width", fSrcRect.width());
300 insertInt("Height", srcRect.height()); 459 insertInt("Height", fSrcRect.height());
301 } 460 }
302 461
303 // if (!image mask) { 462 if (isAlpha || alphaOnly) {
304 if (doingAlpha || alphaOnly) {
305 insertName("ColorSpace", "DeviceGray"); 463 insertName("ColorSpace", "DeviceGray");
306 } else if (config == SkBitmap::kIndex8_Config) { 464 } else if (config == SkBitmap::kIndex8_Config) {
307 SkAutoLockPixels alp(bitmap); 465 SkAutoLockPixels alp(fBitmap);
308 insert("ColorSpace", 466 insert("ColorSpace",
309 makeIndexedColorSpace(bitmap.getColorTable()))->unref(); 467 makeIndexedColorSpace(fBitmap.getColorTable()))->unref();
310 } else { 468 } else {
311 insertName("ColorSpace", "DeviceRGB"); 469 insertName("ColorSpace", "DeviceRGB");
312 } 470 }
313 // }
314 471
315 int bitsPerComp = 8; 472 int bitsPerComp = 8;
316 if (config == SkBitmap::kARGB_4444_Config) { 473 if (config == SkBitmap::kARGB_4444_Config) {
317 bitsPerComp = 4; 474 bitsPerComp = 4;
318 } else if (doingAlpha && config == SkBitmap::kA1_Config) { 475 } else if (isAlpha && config == SkBitmap::kA1_Config) {
319 bitsPerComp = 1; 476 bitsPerComp = 1;
320 } 477 }
321 insertInt("BitsPerComponent", bitsPerComp); 478 insertInt("BitsPerComponent", bitsPerComp);
322 479
323 if (config == SkBitmap::kRGB_565_Config) { 480 if (config == SkBitmap::kRGB_565_Config) {
481 SkASSERT(!isAlpha);
324 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); 482 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
325 SkAutoTUnref<SkPDFScalar> scale5Val( 483 SkAutoTUnref<SkPDFScalar> scale5Val(
326 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1 484 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1
327 SkAutoTUnref<SkPDFScalar> scale6Val( 485 SkAutoTUnref<SkPDFScalar> scale6Val(
328 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1 486 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1
329 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); 487 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
330 decodeValue->reserve(6); 488 decodeValue->reserve(6);
331 decodeValue->append(zeroVal.get()); 489 decodeValue->append(zeroVal.get());
332 decodeValue->append(scale5Val.get()); 490 decodeValue->append(scale5Val.get());
333 decodeValue->append(zeroVal.get()); 491 decodeValue->append(zeroVal.get());
334 decodeValue->append(scale6Val.get()); 492 decodeValue->append(scale6Val.get());
335 decodeValue->append(zeroVal.get()); 493 decodeValue->append(zeroVal.get());
336 decodeValue->append(scale5Val.get()); 494 decodeValue->append(scale5Val.get());
337 insert("Decode", decodeValue.get()); 495 insert("Decode", decodeValue.get());
338 } 496 }
339 } 497 }
498
499 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
500 if (getState() == kUnused_State) {
501 // Initializing image data for the first time.
502 SkDynamicMemoryWStream dctCompressedWStream;
503 if (!skip_compression(catalog) && fEncoder &&
504 get_uncompressed_size(fBitmap, fSrcRect) > 1 &&
505 fEncoder(&dctCompressedWStream, fBitmap, fSrcRect) &&
506 dctCompressedWStream.getOffset() <
507 get_uncompressed_size(fBitmap, fSrcRect)) {
508 SkAutoTUnref<SkData> data(dctCompressedWStream.copyToData());
509 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
510 setData(stream.get());
511
512 insertName("Filter", "DCTDecode");
513 insertInt("ColorTransform", kNoColorTransform);
514 insertInt("Length", getData()->getLength());
515 setState(kCompressed_State);
516 return true;
517 }
518 // Fallback method
519 if (!fStreamValid) {
vandebo (ex-Chrome) 2013/08/23 05:25:20 Should this be a debug check? You always expect t
ducky 2013/08/23 06:59:08 No - when the alpha channel is generated, the stre
520 bool dummy;
vandebo (ex-Chrome) 2013/08/23 05:25:20 dummy -> no_used, but generally I don't think you
ducky 2013/08/23 06:59:08 Done. Updated code and comments to reflect that th
vandebo (ex-Chrome) 2013/08/23 15:45:35 It should alway be able to be NULL.
ducky 2013/08/23 17:59:50 Done.
521 SkAutoTUnref<SkStream> stream(
522 extract_image_data(fBitmap, fSrcRect, false, &dummy));
523 setData(stream);
524 fStreamValid = true;
525 }
526 return INHERITED::populate(catalog);
527 } else if (getState() == kNoCompression_State &&
528 !skip_compression(catalog) &&
529 (SkFlate::HaveFlate() || fEncoder)) {
530 // Compression has not been requested when the stream was first created,
531 // but the new catalog wants it compressed.
532 if (!getSubstitute()) {
533 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
534 setSubstitute(substitute);
535 catalog->setSubstitute(this, substitute);
536 }
537 return false;
538 }
539 return true;
540 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698