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, ©);
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, ©);
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