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