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