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