• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
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 "SkPDFBitmap.h"
9 
10 #include "SkColorData.h"
11 #include "SkData.h"
12 #include "SkDeflate.h"
13 #include "SkImage.h"
14 #include "SkJpegInfo.h"
15 #include "SkPDFCanon.h"
16 #include "SkPDFTypes.h"
17 #include "SkPDFUtils.h"
18 #include "SkStream.h"
19 #include "SkUnPreMultiply.h"
20 
image_compute_is_opaque(const SkImage * image)21 bool image_compute_is_opaque(const SkImage* image) {
22     if (image->isOpaque()) {
23         return true;
24     }
25     // keep output PDF small at cost of possible resource use.
26     SkBitmap bm;
27     // if image can not be read, treat as transparent.
28     return SkPDFUtils::ToBitmap(image, &bm) && SkBitmap::ComputeIsOpaque(bm);
29 }
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 
33 static const char kStreamBegin[] = " stream\n";
34 
35 static const char kStreamEnd[] = "\nendstream";
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
39 // write a single byte to a stream n times.
fill_stream(SkWStream * out,char value,size_t n)40 static void fill_stream(SkWStream* out, char value, size_t n) {
41     char buffer[4096];
42     memset(buffer, value, sizeof(buffer));
43     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
44         out->write(buffer, sizeof(buffer));
45     }
46     out->write(buffer, n % sizeof(buffer));
47 }
48 
49 // TODO(reed@): Decide if these five functions belong in SkColorData.h
SkIsBGRA(SkColorType ct)50 static bool SkIsBGRA(SkColorType ct) {
51     SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
52     return kBGRA_8888_SkColorType == ct;
53 }
54 
55 // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
56 // RGBA_8888) and return the appropriate component.  Each component
57 // should be interpreted according to the associated SkAlphaType and
58 // SkColorProfileType.
SkGetA32Component(uint32_t value,SkColorType ct)59 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
60     return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
61 }
SkGetR32Component(uint32_t value,SkColorType ct)62 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
63     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
64 }
SkGetG32Component(uint32_t value,SkColorType ct)65 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
66     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
67 }
SkGetB32Component(uint32_t value,SkColorType ct)68 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
69     return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
70 }
71 
72 // unpremultiply and extract R, G, B components.
pmcolor_to_rgb24(uint32_t color,uint8_t * rgb,SkColorType ct)73 static void pmcolor_to_rgb24(uint32_t color, uint8_t* rgb, SkColorType ct) {
74     SkPMColorAssert(color);
75     uint32_t s = SkUnPreMultiply::GetScale(SkGetA32Component(color, ct));
76     rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetR32Component(color, ct));
77     rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetG32Component(color, ct));
78     rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetB32Component(color, ct));
79 }
80 
81 /* It is necessary to average the color component of transparent
82    pixels with their surrounding neighbors since the PDF renderer may
83    separately re-sample the alpha and color channels when the image is
84    not displayed at its native resolution. Since an alpha of zero
85    gives no information about the color component, the pathological
86    case is a white image with sharp transparency bounds - the color
87    channel goes to black, and the should-be-transparent pixels are
88    rendered as grey because of the separate soft mask and color
89    resizing. e.g.: gm/bitmappremul.cpp */
get_neighbor_avg_color(const SkBitmap & bm,int xOrig,int yOrig,uint8_t rgb[3],SkColorType ct)90 static void get_neighbor_avg_color(const SkBitmap& bm,
91                                    int xOrig,
92                                    int yOrig,
93                                    uint8_t rgb[3],
94                                    SkColorType ct) {
95     unsigned a = 0, r = 0, g = 0, b = 0;
96     // Clamp the range to the edge of the bitmap.
97     int ymin = SkTMax(0, yOrig - 1);
98     int ymax = SkTMin(yOrig + 1, bm.height() - 1);
99     int xmin = SkTMax(0, xOrig - 1);
100     int xmax = SkTMin(xOrig + 1, bm.width() - 1);
101     for (int y = ymin; y <= ymax; ++y) {
102         uint32_t* scanline = bm.getAddr32(0, y);
103         for (int x = xmin; x <= xmax; ++x) {
104             uint32_t color = scanline[x];
105             SkPMColorAssert(color);
106             a += SkGetA32Component(color, ct);
107             r += SkGetR32Component(color, ct);
108             g += SkGetG32Component(color, ct);
109             b += SkGetB32Component(color, ct);
110         }
111     }
112     if (a > 0) {
113         rgb[0] = SkToU8(255 * r / a);
114         rgb[1] = SkToU8(255 * g / a);
115         rgb[2] = SkToU8(255 * b / a);
116     } else {
117         rgb[0] = rgb[1] = rgb[2] = 0;
118     }
119 }
120 
pixel_count(const SkBitmap & bm)121 static size_t pixel_count(const SkBitmap& bm) {
122     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
123 }
124 
supported_colortype(const SkBitmap & input,SkBitmap * copy)125 static const SkBitmap& supported_colortype(const SkBitmap& input, SkBitmap* copy) {
126     switch (input.colorType()) {
127         case kUnknown_SkColorType:
128             SkDEBUGFAIL("kUnknown_SkColorType");
129         case kAlpha_8_SkColorType:
130         case kRGB_565_SkColorType:
131         case kRGBA_8888_SkColorType:
132         case kBGRA_8888_SkColorType:
133         case kGray_8_SkColorType:
134             return input;  // supported
135         default:
136             // if other colortypes are introduced in the future,
137             // they will hit this code.
138             break;
139     }
140     // Fallback for rarely used ARGB_4444 and ARGB_F16: do a wasteful tmp copy.
141     copy->allocPixels(input.info().makeColorType(kN32_SkColorType));
142     SkAssertResult(input.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0));
143     copy->setImmutable();
144     return *copy;
145 }
146 
pdf_color_component_count(SkColorType ct)147 static size_t pdf_color_component_count(SkColorType ct) {
148     switch (ct) {
149         case kUnknown_SkColorType:
150             SkDEBUGFAIL("kUnknown_SkColorType");
151         case kAlpha_8_SkColorType:
152         case kGray_8_SkColorType:
153             return 1;
154         case kRGB_565_SkColorType:
155         case kRGBA_8888_SkColorType:
156         case kBGRA_8888_SkColorType:
157         default:  // converted to N32
158             return 3;
159     }
160 }
161 
bitmap_to_pdf_pixels(const SkBitmap & bitmap,SkWStream * out)162 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
163     if (!bitmap.getPixels()) {
164         size_t size = pixel_count(bitmap) *
165                       pdf_color_component_count(bitmap.colorType());
166         fill_stream(out, '\x00', size);
167         return;
168     }
169     SkBitmap copy;
170     const SkBitmap& bm = supported_colortype(bitmap, &copy);
171     SkColorType colorType = bm.colorType();
172     SkAlphaType alphaType = bm.alphaType();
173     switch (colorType) {
174         case kRGBA_8888_SkColorType:
175         case kBGRA_8888_SkColorType: {
176             SkASSERT(3 == pdf_color_component_count(colorType));
177             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
178             for (int y = 0; y < bm.height(); ++y) {
179                 const uint32_t* src = bm.getAddr32(0, y);
180                 uint8_t* dst = scanline.get();
181                 for (int x = 0; x < bm.width(); ++x) {
182                     if (alphaType == kPremul_SkAlphaType) {
183                         uint32_t color = *src++;
184                         U8CPU alpha = SkGetA32Component(color, colorType);
185                         if (alpha != SK_AlphaTRANSPARENT) {
186                             pmcolor_to_rgb24(color, dst, colorType);
187                         } else {
188                             get_neighbor_avg_color(bm, x, y, dst, colorType);
189                         }
190                         dst += 3;
191                     } else {
192                         uint32_t color = *src++;
193                         *dst++ = SkGetR32Component(color, colorType);
194                         *dst++ = SkGetG32Component(color, colorType);
195                         *dst++ = SkGetB32Component(color, colorType);
196                     }
197                 }
198                 out->write(scanline.get(), 3 * bm.width());
199             }
200             return;
201         }
202         case kRGB_565_SkColorType: {
203             SkASSERT(3 == pdf_color_component_count(colorType));
204             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
205             for (int y = 0; y < bm.height(); ++y) {
206                 const uint16_t* src = bm.getAddr16(0, y);
207                 uint8_t* dst = scanline.get();
208                 for (int x = 0; x < bm.width(); ++x) {
209                     U16CPU color565 = *src++;
210                     *dst++ = SkPacked16ToR32(color565);
211                     *dst++ = SkPacked16ToG32(color565);
212                     *dst++ = SkPacked16ToB32(color565);
213                 }
214                 out->write(scanline.get(), 3 * bm.width());
215             }
216             return;
217         }
218         case kAlpha_8_SkColorType:
219             SkASSERT(1 == pdf_color_component_count(colorType));
220             fill_stream(out, '\x00', pixel_count(bm));
221             return;
222         case kGray_8_SkColorType:
223             SkASSERT(1 == pdf_color_component_count(colorType));
224             // these two formats need no transformation to serialize.
225             for (int y = 0; y < bm.height(); ++y) {
226                 out->write(bm.getAddr8(0, y), bm.width());
227             }
228             return;
229         case kUnknown_SkColorType:
230         case kARGB_4444_SkColorType:
231         default:
232             SkDEBUGFAIL("unexpected color type");
233     }
234 }
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 
bitmap_alpha_to_a8(const SkBitmap & bitmap,SkWStream * out)238 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
239     if (!bitmap.getPixels()) {
240         fill_stream(out, '\xFF', pixel_count(bitmap));
241         return;
242     }
243     SkBitmap copy;
244     const SkBitmap& bm = supported_colortype(bitmap, &copy);
245     SkColorType colorType = bm.colorType();
246     switch (colorType) {
247         case kRGBA_8888_SkColorType:
248         case kBGRA_8888_SkColorType: {
249             SkAutoTMalloc<uint8_t> scanline(bm.width());
250             for (int y = 0; y < bm.height(); ++y) {
251                 uint8_t* dst = scanline.get();
252                 const SkPMColor* src = bm.getAddr32(0, y);
253                 for (int x = 0; x < bm.width(); ++x) {
254                     *dst++ = SkGetA32Component(*src++, colorType);
255                 }
256                 out->write(scanline.get(), bm.width());
257             }
258             return;
259         }
260         case kAlpha_8_SkColorType:
261             for (int y = 0; y < bm.height(); ++y) {
262                 out->write(bm.getAddr8(0, y), bm.width());
263             }
264             return;
265         case kRGB_565_SkColorType:
266         case kGray_8_SkColorType:
267             SkDEBUGFAIL("color type has no alpha");
268             return;
269         case kARGB_4444_SkColorType:
270             SkDEBUGFAIL("4444 color type should have been converted to N32");
271             return;
272         case kUnknown_SkColorType:
273         default:
274             SkDEBUGFAIL("unexpected color type");
275     }
276 }
277 
emit_image_xobject(SkWStream * stream,const SkImage * image,bool alpha,const sk_sp<SkPDFObject> & smask,const SkPDFObjNumMap & objNumMap)278 static void emit_image_xobject(SkWStream* stream,
279                                const SkImage* image,
280                                bool alpha,
281                                const sk_sp<SkPDFObject>& smask,
282                                const SkPDFObjNumMap& objNumMap) {
283     SkBitmap bitmap;
284     if (!SkPDFUtils::ToBitmap(image, &bitmap)) {
285         // no pixels or wrong size: fill with zeros.
286         bitmap.setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
287     }
288 
289     // Write to a temporary buffer to get the compressed length.
290     SkDynamicMemoryWStream buffer;
291     SkDeflateWStream deflateWStream(&buffer);
292     if (alpha) {
293         bitmap_alpha_to_a8(bitmap, &deflateWStream);
294     } else {
295         bitmap_to_pdf_pixels(bitmap, &deflateWStream);
296     }
297     deflateWStream.finalize();  // call before buffer.bytesWritten().
298 
299     SkPDFDict pdfDict("XObject");
300     pdfDict.insertName("Subtype", "Image");
301     pdfDict.insertInt("Width", bitmap.width());
302     pdfDict.insertInt("Height", bitmap.height());
303     if (alpha) {
304         pdfDict.insertName("ColorSpace", "DeviceGray");
305     } else if (1 == pdf_color_component_count(bitmap.colorType())) {
306         pdfDict.insertName("ColorSpace", "DeviceGray");
307     } else {
308         pdfDict.insertName("ColorSpace", "DeviceRGB");
309     }
310     if (smask) {
311         pdfDict.insertObjRef("SMask", smask);
312     }
313     pdfDict.insertInt("BitsPerComponent", 8);
314     pdfDict.insertName("Filter", "FlateDecode");
315     pdfDict.insertInt("Length", buffer.bytesWritten());
316     pdfDict.emitObject(stream, objNumMap);
317 
318     stream->writeText(kStreamBegin);
319     buffer.writeToAndReset(stream);
320     stream->writeText(kStreamEnd);
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 
325 namespace {
326 // This SkPDFObject only outputs the alpha layer of the given bitmap.
327 class PDFAlphaBitmap final : public SkPDFObject {
328 public:
PDFAlphaBitmap(sk_sp<SkImage> image)329     PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap) const330     void emitObject(SkWStream*  stream,
331                     const SkPDFObjNumMap& objNumMap) const override {
332         SkASSERT(fImage);
333         emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
334     }
drop()335     void drop() override { fImage = nullptr; }
336 
337 private:
338     sk_sp<SkImage> fImage;
339 };
340 
341 }  // namespace
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 
345 namespace {
346 class PDFDefaultBitmap final : public SkPDFObject {
347 public:
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap) const348     void emitObject(SkWStream* stream,
349                     const SkPDFObjNumMap& objNumMap) const override {
350         SkASSERT(fImage);
351         emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
352     }
addResources(SkPDFObjNumMap * catalog) const353     void addResources(SkPDFObjNumMap* catalog) const override {
354         catalog->addObjectRecursively(fSMask.get());
355     }
drop()356     void drop() override { fImage = nullptr; fSMask = nullptr; }
PDFDefaultBitmap(sk_sp<SkImage> image,sk_sp<SkPDFObject> smask)357     PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
358         : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); }
359 
360 private:
361     sk_sp<SkImage> fImage;
362     sk_sp<SkPDFObject> fSMask;
363 };
364 }  // namespace
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 
368 namespace {
369 /**
370  *  This PDFObject assumes that its constructor was handed YUV or
371  *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
372  *  into a PDF.
373  */
374 class PDFJpegBitmap final : public SkPDFObject {
375 public:
376     SkISize fSize;
377     sk_sp<SkData> fData;
378     bool fIsYUV;
PDFJpegBitmap(SkISize size,SkData * data,bool isYUV)379     PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
380         : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
381     void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
drop()382     void drop() override { fData = nullptr; }
383 };
384 
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap) const385 void PDFJpegBitmap::emitObject(SkWStream* stream,
386                                const SkPDFObjNumMap& objNumMap) const {
387     SkASSERT(fData);
388     SkPDFDict pdfDict("XObject");
389     pdfDict.insertName("Subtype", "Image");
390     pdfDict.insertInt("Width", fSize.width());
391     pdfDict.insertInt("Height", fSize.height());
392     if (fIsYUV) {
393         pdfDict.insertName("ColorSpace", "DeviceRGB");
394     } else {
395         pdfDict.insertName("ColorSpace", "DeviceGray");
396     }
397     pdfDict.insertInt("BitsPerComponent", 8);
398     pdfDict.insertName("Filter", "DCTDecode");
399     pdfDict.insertInt("ColorTransform", 0);
400     pdfDict.insertInt("Length", SkToInt(fData->size()));
401     pdfDict.emitObject(stream, objNumMap);
402     stream->writeText(kStreamBegin);
403     stream->write(fData->data(), fData->size());
404     stream->writeText(kStreamEnd);
405 }
406 }  // namespace
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 
SkPDFCreateBitmapObject(sk_sp<SkImage> image,int encodingQuality)410 sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, int encodingQuality) {
411     SkASSERT(image);
412     SkASSERT(encodingQuality >= 0);
413     sk_sp<SkData> data = image->refEncodedData();
414     SkJFIFInfo info;
415     if (data && SkIsJFIF(data.get(), &info)) {
416         bool yuv = info.fType == SkJFIFInfo::kYCbCr;
417         if (info.fSize == image->dimensions()) {  // Sanity check.
418             // hold on to data, not image.
419             #ifdef SK_PDF_IMAGE_STATS
420             gJpegImageObjects.fetch_add(1);
421             #endif
422             return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
423         }
424     }
425 
426     const bool isOpaque = image_compute_is_opaque(image.get());
427 
428     if (encodingQuality <= 100 && isOpaque) {
429         data = image->encodeToData(SkEncodedImageFormat::kJPEG, encodingQuality);
430         if (data && SkIsJFIF(data.get(), &info)) {
431             bool yuv = info.fType == SkJFIFInfo::kYCbCr;
432             if (info.fSize == image->dimensions()) {  // Sanity check.
433                 return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
434             }
435         }
436     }
437 
438     sk_sp<SkPDFObject> smask;
439     if (!isOpaque) {
440         smask = sk_make_sp<PDFAlphaBitmap>(image);
441     }
442     #ifdef SK_PDF_IMAGE_STATS
443     gRegularImageObjects.fetch_add(1);
444     #endif
445     return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));
446 }
447