• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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