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

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

Issue 1024113002: Revert of PDF: remove last use of SkPDFImage (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 9 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
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2010 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkPDFImage.h"
9
10 #include "SkBitmap.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkData.h"
14 #include "SkFlate.h"
15 #include "SkPDFBitmap.h"
16 #include "SkPDFCatalog.h"
17 #include "SkPixelRef.h"
18 #include "SkRect.h"
19 #include "SkStream.h"
20 #include "SkString.h"
21 #include "SkUnPreMultiply.h"
22
23 static size_t get_uncompressed_size(const SkBitmap& bitmap,
24 const SkIRect& srcRect) {
25 switch (bitmap.colorType()) {
26 case kIndex_8_SkColorType:
27 return srcRect.width() * srcRect.height();
28 case kARGB_4444_SkColorType:
29 return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
30 case kRGB_565_SkColorType:
31 return srcRect.width() * 3 * srcRect.height();
32 case kRGBA_8888_SkColorType:
33 case kBGRA_8888_SkColorType:
34 case kGray_8_SkColorType:
35 return srcRect.width() * 3 * srcRect.height();
36 case kAlpha_8_SkColorType:
37 return 1;
38 default:
39 SkASSERT(false);
40 return 0;
41 }
42 }
43
44 static SkStream* extract_index8_image(const SkBitmap& bitmap,
45 const SkIRect& srcRect) {
46 const int rowBytes = srcRect.width();
47 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
48 (get_uncompressed_size(bitmap, srcRect)));
49 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
50
51 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
52 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
53 dst += rowBytes;
54 }
55 return stream;
56 }
57
58 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
59 const SkIRect& srcRect,
60 bool extractAlpha,
61 bool* isOpaque,
62 bool* isTransparent) {
63 SkStream* stream;
64 uint8_t* dst = NULL;
65 if (extractAlpha) {
66 const int alphaRowBytes = (srcRect.width() + 1) / 2;
67 stream = SkNEW_ARGS(SkMemoryStream,
68 (alphaRowBytes * srcRect.height()));
69 } else {
70 stream = SkNEW_ARGS(SkMemoryStream,
71 (get_uncompressed_size(bitmap, srcRect)));
72 }
73 dst = (uint8_t*)stream->getMemoryBase();
74
75 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
76 uint16_t* src = bitmap.getAddr16(0, y);
77 int x;
78 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
79 if (extractAlpha) {
80 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
81 SkGetPackedA4444(src[x + 1]);
82 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
83 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
84 dst++;
85 } else {
86 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
87 SkGetPackedG4444(src[x]);
88 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
89 SkGetPackedR4444(src[x + 1]);
90 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
91 SkGetPackedB4444(src[x + 1]);
92 dst += 3;
93 }
94 }
95 if (srcRect.width() & 1) {
96 if (extractAlpha) {
97 dst[0] = (SkGetPackedA4444(src[x]) << 4);
98 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
99 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
100 dst++;
101
102 } else {
103 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
104 SkGetPackedG4444(src[x]);
105 dst[1] = (SkGetPackedB4444(src[x]) << 4);
106 dst += 2;
107 }
108 }
109 }
110 return stream;
111 }
112
113 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
114 const SkIRect& srcRect) {
115 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
116 (get_uncompressed_size(bitmap,
117 srcRect)));
118 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
119 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
120 uint16_t* src = bitmap.getAddr16(0, y);
121 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
122 dst[0] = SkGetPackedR16(src[x]);
123 dst[1] = SkGetPackedG16(src[x]);
124 dst[2] = SkGetPackedB16(src[x]);
125 dst += 3;
126 }
127 }
128 return stream;
129 }
130
131 static SkStream* extract_gray8_image(const SkBitmap& bitmap, const SkIRect& srcR ect) {
132 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
133 (get_uncompressed_size(bitmap, srcRect)));
134 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
135 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
136 uint8_t* src = bitmap.getAddr8(0, y);
137 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
138 dst[0] = dst[1] = dst[2] = src[x];
139 dst += 3;
140 }
141 }
142 return stream;
143 }
144
145 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
146 int xOrig,
147 int yOrig);
148
149 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
150 const SkIRect& srcRect,
151 bool extractAlpha,
152 bool* isOpaque,
153 bool* isTransparent) {
154 size_t streamSize = extractAlpha ? srcRect.width() * srcRect.height()
155 : get_uncompressed_size(bitmap, srcRect);
156 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (streamSize));
157 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
158
159 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
160
161 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
162 uint32_t* src = bitmap.getAddr32(0, y);
163 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
164 SkPMColor c = src[x];
165 U8CPU alpha = SkGetPackedA32(c);
166 if (extractAlpha) {
167 *isOpaque &= alpha == SK_AlphaOPAQUE;
168 *isTransparent &= alpha == SK_AlphaTRANSPARENT;
169 *dst++ = alpha;
170 } else {
171 if (SK_AlphaTRANSPARENT == alpha) {
172 // It is necessary to average the color component of
173 // transparent pixels with their surrounding neighbors
174 // since the PDF renderer may separately re-sample the
175 // alpha and color channels when the image is not
176 // displayed at its native resolution. Since an alpha of
177 // zero gives no information about the color component,
178 // the pathological case is a white image with sharp
179 // transparency bounds - the color channel goes to black,
180 // and the should-be-transparent pixels are rendered
181 // as grey because of the separate soft mask and color
182 // resizing.
183 c = get_argb8888_neighbor_avg_color(bitmap, x, y);
184 *dst++ = SkGetPackedR32(c);
185 *dst++ = SkGetPackedG32(c);
186 *dst++ = SkGetPackedB32(c);
187 } else {
188 SkUnPreMultiply::Scale s = scaleTable[alpha];
189 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
190 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(c));
191 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
192 }
193 }
194 }
195 }
196 SkASSERT(dst == streamSize + (uint8_t*)stream->getMemoryBase());
197 return stream;
198 }
199
200 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
201 const SkIRect& srcRect,
202 bool* isOpaque,
203 bool* isTransparent) {
204 const int alphaRowBytes = srcRect.width();
205 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
206 (alphaRowBytes * srcRect.height()));
207 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
208
209 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
210 uint8_t* src = bitmap.getAddr8(0, y);
211 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
212 alphaDst[0] = src[x];
213 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
214 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
215 alphaDst++;
216 }
217 }
218 return stream;
219 }
220
221 static SkStream* create_black_image() {
222 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
223 ((uint8_t*)stream->getMemoryBase())[0] = 0;
224 return stream;
225 }
226
227 /**
228 * Extract either the color or image data from a SkBitmap into a SkStream.
229 * @param bitmap Bitmap to extract data from.
230 * @param srcRect Region in the bitmap to extract.
231 * @param extractAlpha Set to true to extract the alpha data or false to
232 * extract the color data.
233 * @param isTransparent Pointer to a bool to output whether the alpha is
234 * completely transparent. May be NULL. Only valid when
235 * extractAlpha == true.
236 * @return Unencoded image data, or NULL if either data was not
237 * available or alpha data was requested but the image was
238 * entirely transparent or opaque.
239 */
240 static SkStream* extract_image_data(const SkBitmap& bitmap,
241 const SkIRect& srcRect,
242 bool extractAlpha, bool* isTransparent) {
243 SkColorType colorType = bitmap.colorType();
244 if (extractAlpha && (kIndex_8_SkColorType == colorType ||
245 kRGB_565_SkColorType == colorType ||
246 kGray_8_SkColorType == colorType)) {
247 if (isTransparent != NULL) {
248 *isTransparent = false;
249 }
250 return NULL;
251 }
252
253 SkAutoLockPixels lock(bitmap);
254 if (NULL == bitmap.getPixels()) {
255 return NULL;
256 }
257
258 bool isOpaque = true;
259 bool transparent = extractAlpha;
260 SkAutoTDelete<SkStream> stream;
261
262 switch (colorType) {
263 case kIndex_8_SkColorType:
264 if (!extractAlpha) {
265 stream.reset(extract_index8_image(bitmap, srcRect));
266 }
267 break;
268 case kARGB_4444_SkColorType:
269 stream.reset(extract_argb4444_data(bitmap, srcRect, extractAlpha,
270 &isOpaque, &transparent));
271 break;
272 case kRGB_565_SkColorType:
273 if (!extractAlpha) {
274 stream.reset(extract_rgb565_image(bitmap, srcRect));
275 }
276 break;
277 case kGray_8_SkColorType:
278 if (!extractAlpha) {
279 stream.reset(extract_gray8_image(bitmap, srcRect));
280 }
281 break;
282 case kN32_SkColorType:
283 stream.reset(extract_argb8888_data(bitmap, srcRect, extractAlpha,
284 &isOpaque, &transparent));
285 break;
286 case kAlpha_8_SkColorType:
287 if (!extractAlpha) {
288 stream.reset(create_black_image());
289 } else {
290 stream.reset(extract_a8_alpha(bitmap, srcRect,
291 &isOpaque, &transparent));
292 }
293 break;
294 default:
295 SkASSERT(false);
296 }
297
298 if (isTransparent != NULL) {
299 *isTransparent = transparent;
300 }
301 if (extractAlpha && (transparent || isOpaque)) {
302 return NULL;
303 }
304 return stream.detach();
305 }
306
307 static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
308 SkPDFArray* result = new SkPDFArray();
309 result->reserve(4);
310 result->appendName("Indexed");
311 result->appendName("DeviceRGB");
312 result->appendInt(table->count() - 1);
313
314 // Potentially, this could be represented in fewer bytes with a stream.
315 // Max size as a string is 1.5k.
316 SkString index;
317 for (int i = 0; i < table->count(); i++) {
318 char buf[3];
319 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
320 buf[0] = SkGetPackedR32(color);
321 buf[1] = SkGetPackedG32(color);
322 buf[2] = SkGetPackedB32(color);
323 index.append(buf, 3);
324 }
325 result->append(new SkPDFString(index))->unref();
326 return result;
327 }
328
329 /**
330 * Removes the alpha component of an ARGB color (including unpremultiply) while
331 * keeping the output in the same format as the input.
332 */
333 static uint32_t remove_alpha_argb8888(uint32_t pmColor) {
334 SkColor color = SkUnPreMultiply::PMColorToColor(pmColor);
335 return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
336 SkColorGetR(color),
337 SkColorGetG(color),
338 SkColorGetB(color));
339 }
340
341 static uint16_t remove_alpha_argb4444(uint16_t pmColor) {
342 return SkPixel32ToPixel4444(
343 remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor)));
344 }
345
346 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
347 int xOrig, int yOrig) {
348 uint8_t count = 0;
349 uint16_t r = 0;
350 uint16_t g = 0;
351 uint16_t b = 0;
352
353 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
354 if (y < 0 || y >= bitmap.height()) {
355 continue;
356 }
357 uint32_t* src = bitmap.getAddr32(0, y);
358 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
359 if (x < 0 || x >= bitmap.width()) {
360 continue;
361 }
362 if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) {
363 uint32_t color = remove_alpha_argb8888(src[x]);
364 r += SkGetPackedR32(color);
365 g += SkGetPackedG32(color);
366 b += SkGetPackedB32(color);
367 count++;
368 }
369 }
370 }
371
372 if (count == 0) {
373 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
374 } else {
375 return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
376 r / count, g / count, b / count);
377 }
378 }
379
380 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap,
381 int xOrig, int yOrig) {
382 uint8_t count = 0;
383 uint8_t r = 0;
384 uint8_t g = 0;
385 uint8_t b = 0;
386
387 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
388 if (y < 0 || y >= bitmap.height()) {
389 continue;
390 }
391 uint16_t* src = bitmap.getAddr16(0, y);
392 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
393 if (x < 0 || x >= bitmap.width()) {
394 continue;
395 }
396 if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) {
397 uint16_t color = remove_alpha_argb4444(src[x]);
398 r += SkGetPackedR4444(color);
399 g += SkGetPackedG4444(color);
400 b += SkGetPackedB4444(color);
401 count++;
402 }
403 }
404 }
405
406 if (count == 0) {
407 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
408 } else {
409 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
410 r / count, g / count, b / count);
411 }
412 }
413
414 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
415 const SkIRect& srcRect) {
416 SkBitmap outBitmap;
417 outBitmap.allocPixels(bitmap.info().makeWH(srcRect.width(), srcRect.height() ));
418 int dstRow = 0;
419
420 SkAutoLockPixels outBitmapPixelLock(outBitmap);
421 SkAutoLockPixels bitmapPixelLock(bitmap);
422 switch (bitmap.colorType()) {
423 case kARGB_4444_SkColorType: {
424 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
425 uint16_t* dst = outBitmap.getAddr16(0, dstRow);
426 uint16_t* src = bitmap.getAddr16(0, y);
427 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
428 uint8_t a = SkGetPackedA4444(src[x]);
429 // It is necessary to average the color component of
430 // transparent pixels with their surrounding neighbors
431 // since the PDF renderer may separately re-sample the
432 // alpha and color channels when the image is not
433 // displayed at its native resolution. Since an alpha of
434 // zero gives no information about the color component,
435 // the pathological case is a white image with sharp
436 // transparency bounds - the color channel goes to black,
437 // and the should-be-transparent pixels are rendered
438 // as grey because of the separate soft mask and color
439 // resizing.
440 if (a == (SK_AlphaTRANSPARENT & 0x0F)) {
441 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y);
442 } else {
443 *dst = remove_alpha_argb4444(src[x]);
444 }
445 dst++;
446 }
447 dstRow++;
448 }
449 break;
450 }
451 case kN32_SkColorType: {
452 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
453 uint32_t* dst = outBitmap.getAddr32(0, dstRow);
454 uint32_t* src = bitmap.getAddr32(0, y);
455 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
456 uint8_t a = SkGetPackedA32(src[x]);
457 if (a == SK_AlphaTRANSPARENT) {
458 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y);
459 } else {
460 *dst = remove_alpha_argb8888(src[x]);
461 }
462 dst++;
463 }
464 dstRow++;
465 }
466 break;
467 }
468 default:
469 SkASSERT(false);
470 }
471
472 outBitmap.setImmutable();
473
474 return outBitmap;
475 }
476
477 // static
478 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
479 const SkIRect& srcRect) {
480 if (bitmap.colorType() == kUnknown_SkColorType) {
481 return NULL;
482 }
483
484 bool isTransparent = false;
485 SkAutoTDelete<SkStream> alphaData;
486 if (!bitmap.isOpaque()) {
487 // Note that isOpaque is not guaranteed to return false for bitmaps
488 // with alpha support but a completely opaque alpha channel,
489 // so alphaData may still be NULL if we have a completely opaque
490 // (or transparent) bitmap.
491 alphaData.reset(
492 extract_image_data(bitmap, srcRect, true, &isTransparent));
493 }
494 if (isTransparent) {
495 return NULL;
496 }
497
498 SkPDFImage* image;
499 SkColorType colorType = bitmap.colorType();
500 if (alphaData.get() != NULL && (kN32_SkColorType == colorType ||
501 kARGB_4444_SkColorType == colorType)) {
502 if (kN32_SkColorType == colorType) {
503 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false,
504 SkIRect::MakeWH(srcRect.width(),
505 srcRect.height())));
506 } else {
507 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
508 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false,
509 SkIRect::MakeWH(srcRect.width(),
510 srcRect.height())));
511 }
512 } else {
513 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect));
514 }
515 if (alphaData.get() != NULL) {
516 SkAutoTUnref<SkPDFImage> mask(
517 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, true, srcRect)) );
518 image->insert("SMask", new SkPDFObjRef(mask))->unref();
519 }
520 return image;
521 }
522
523 SkPDFImage::~SkPDFImage() {}
524
525 SkPDFImage::SkPDFImage(SkStream* stream,
526 const SkBitmap& bitmap,
527 bool isAlpha,
528 const SkIRect& srcRect)
529 : fIsAlpha(isAlpha),
530 fSrcRect(srcRect) {
531
532 if (bitmap.isImmutable()) {
533 fBitmap = bitmap;
534 } else {
535 bitmap.deepCopyTo(&fBitmap);
536 fBitmap.setImmutable();
537 }
538
539 if (stream != NULL) {
540 this->setData(stream);
541 fStreamValid = true;
542 } else {
543 fStreamValid = false;
544 }
545
546 SkColorType colorType = fBitmap.colorType();
547
548 insertName("Type", "XObject");
549 insertName("Subtype", "Image");
550
551 bool alphaOnly = (kAlpha_8_SkColorType == colorType);
552
553 if (!isAlpha && alphaOnly) {
554 // For alpha only images, we stretch a single pixel of black for
555 // the color/shape part.
556 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
557 insert("Width", one.get());
558 insert("Height", one.get());
559 } else {
560 insertInt("Width", fSrcRect.width());
561 insertInt("Height", fSrcRect.height());
562 }
563
564 if (isAlpha || alphaOnly) {
565 insertName("ColorSpace", "DeviceGray");
566 } else if (kIndex_8_SkColorType == colorType) {
567 SkAutoLockPixels alp(fBitmap);
568 insert("ColorSpace",
569 make_indexed_color_space(fBitmap.getColorTable()))->unref();
570 } else {
571 insertName("ColorSpace", "DeviceRGB");
572 }
573
574 int bitsPerComp = 8;
575 if (kARGB_4444_SkColorType == colorType) {
576 bitsPerComp = 4;
577 }
578 insertInt("BitsPerComponent", bitsPerComp);
579
580 if (kRGB_565_SkColorType == colorType) {
581 SkASSERT(!isAlpha);
582 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
583 SkAutoTUnref<SkPDFScalar> scale5Val(
584 new SkPDFScalar(8.2258f)); // 255/2^5-1
585 SkAutoTUnref<SkPDFScalar> scale6Val(
586 new SkPDFScalar(4.0476f)); // 255/2^6-1
587 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
588 decodeValue->reserve(6);
589 decodeValue->append(zeroVal.get());
590 decodeValue->append(scale5Val.get());
591 decodeValue->append(zeroVal.get());
592 decodeValue->append(scale6Val.get());
593 decodeValue->append(zeroVal.get());
594 decodeValue->append(scale5Val.get());
595 insert("Decode", decodeValue.get());
596 }
597 }
598
599 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
600 : SkPDFStream(pdfImage),
601 fBitmap(pdfImage.fBitmap),
602 fIsAlpha(pdfImage.fIsAlpha),
603 fSrcRect(pdfImage.fSrcRect),
604 fStreamValid(pdfImage.fStreamValid) {
605 // Nothing to do here - the image params are already copied in SkPDFStream's
606 // constructor, and the bitmap will be regenerated and encoded in
607 // populate.
608 }
609
610 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
611 if (getState() == kUnused_State) {
612 // Initializing image data for the first time.
613 // Fallback method
614 if (!fStreamValid) {
615 SkAutoTDelete<SkStream> stream(
616 extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
617 this->setData(stream);
618 fStreamValid = true;
619 }
620 return INHERITED::populate(catalog);
621 }
622 #ifndef SK_NO_FLATE
623 else if (getState() == kNoCompression_State) {
624 // Compression has not been requested when the stream was first created,
625 // but the new catalog wants it compressed.
626 if (!getSubstitute()) {
627 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
628 setSubstitute(substitute);
629 catalog->setSubstitute(this, substitute);
630 }
631 return false;
632 }
633 #endif // SK_NO_FLATE
634 return true;
635 }
636
637 #if 0 // reenable when we can figure out the JPEG colorspace
638 namespace {
639 /**
640 * This PDFObject assumes that its constructor was handed
641 * Jpeg-encoded data that can be directly embedded into a PDF.
642 */
643 class PDFJPEGImage : public SkPDFObject {
644 SkAutoTUnref<SkData> fData;
645 int fWidth;
646 int fHeight;
647 public:
648 PDFJPEGImage(SkData* data, int width, int height)
649 : fData(SkRef(data)), fWidth(width), fHeight(height) {}
650 virtual void emitObject(
651 SkWStream* stream,
652 SkPDFCatalog* catalog, bool indirect) SK_OVERRIDE {
653 if (indirect) {
654 this->emitIndirectObject(stream, catalog);
655 return;
656 }
657 SkASSERT(fData.get());
658 const char kPrefaceFormat[] =
659 "<<"
660 "/Type /XObject\n"
661 "/Subtype /Image\n"
662 "/Width %d\n"
663 "/Height %d\n"
664 "/ColorSpace /DeviceRGB\n" // or DeviceGray
665 "/BitsPerComponent 8\n"
666 "/Filter /DCTDecode\n"
667 "/ColorTransform 0\n"
668 "/Length " SK_SIZE_T_SPECIFIER "\n"
669 ">> stream\n";
670 SkString preface(
671 SkStringPrintf(kPrefaceFormat, fWidth, fHeight, fData->size()));
672 const char kPostface[] = "\nendstream";
673 stream->write(preface.c_str(), preface.size());
674 stream->write(fData->data(), fData->size());
675 stream->write(kPostface, sizeof(kPostface));
676 }
677 };
678
679 /**
680 * If the bitmap is not subsetted, return its encoded data, if
681 * availible.
682 */
683 static inline SkData* ref_encoded_data(const SkBitmap& bm) {
684 if ((NULL == bm.pixelRef())
685 || !bm.pixelRefOrigin().isZero()
686 || (bm.info().dimensions() != bm.pixelRef()->info().dimensions())) {
687 return NULL;
688 }
689 return bm.pixelRef()->refEncodedData();
690 }
691
692 /*
693 * This functions may give false negatives but no false positives.
694 */
695 static bool is_jfif_jpeg(SkData* data) {
696 if (!data || (data->size() < 11)) {
697 return false;
698 }
699 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0};
700 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0};
701 // 0 1 2 3 4 5 6 7 8 9 10
702 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ...
703 return ((0 == memcmp(data->bytes(), bytesZeroToThree,
704 sizeof(bytesZeroToThree)))
705 && (0 == memcmp(data->bytes() + 6, bytesSixToTen,
706 sizeof(bytesSixToTen))));
707 }
708 } // namespace
709 #endif
710
711 SkPDFObject* SkPDFCreateImageObject(SkPDFCanon* canon,
712 const SkBitmap& bitmap,
713 const SkIRect& subset) {
714 if (SkPDFObject* pdfBitmap = SkPDFBitmap::Create(canon, bitmap, subset)) {
715 return pdfBitmap;
716 }
717 #if 0 // reenable when we can figure out the JPEG colorspace
718 if (SkIRect::MakeWH(bitmap.width(), bitmap.height()) == subset) {
719 SkAutoTUnref<SkData> encodedData(ref_encoded_data(bitmap));
720 if (is_jfif_jpeg(encodedData)) {
721 return SkNEW_ARGS(PDFJPEGImage,
722 (encodedData, bitmap.width(), bitmap.height()));
723 }
724 }
725 #endif
726 return SkPDFImage::CreateImage(bitmap, subset);
727 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698