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 "SkColorPriv.h"
9 #include "SkData.h"
10 #include "SkDeflate.h"
11 #include "SkImage_Base.h"
12 #include "SkJpegInfo.h"
13 #include "SkPDFBitmap.h"
14 #include "SkPDFCanon.h"
15 #include "SkStream.h"
16 #include "SkUnPreMultiply.h"
17
image_get_ro_pixels(const SkImage * image,SkBitmap * dst)18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
19 if(as_IB(image)->getROPixels(dst)
20 && dst->dimensions() == image->dimensions()) {
21 if (dst->colorType() != kIndex_8_SkColorType) {
22 return;
23 }
24 // We must check to see if the bitmap has a color table.
25 SkAutoLockPixels autoLockPixels(*dst);
26 if (!dst->getColorTable()) {
27 // We can't use an indexed bitmap with no colortable.
28 dst->reset();
29 } else {
30 return;
31 }
32 }
33 // no pixels or wrong size: fill with zeros.
34 SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
35 dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at));
36 }
37
image_compute_is_opaque(const SkImage * image)38 bool image_compute_is_opaque(const SkImage* image) {
39 if (image->isOpaque()) {
40 return true;
41 }
42 // keep output PDF small at cost of possible resource use.
43 SkBitmap bm;
44 image_get_ro_pixels(image, &bm);
45 return SkBitmap::ComputeIsOpaque(bm);
46 }
47
48 ////////////////////////////////////////////////////////////////////////////////
49
pdf_stream_begin(SkWStream * stream)50 static void pdf_stream_begin(SkWStream* stream) {
51 static const char streamBegin[] = " stream\n";
52 stream->write(streamBegin, strlen(streamBegin));
53 }
54
pdf_stream_end(SkWStream * stream)55 static void pdf_stream_end(SkWStream* stream) {
56 static const char streamEnd[] = "\nendstream";
57 stream->write(streamEnd, strlen(streamEnd));
58 }
59
60 ////////////////////////////////////////////////////////////////////////////////
61
62 // write a single byte to a stream n times.
fill_stream(SkWStream * out,char value,size_t n)63 static void fill_stream(SkWStream* out, char value, size_t n) {
64 char buffer[4096];
65 memset(buffer, value, sizeof(buffer));
66 for (size_t i = 0; i < n / sizeof(buffer); ++i) {
67 out->write(buffer, sizeof(buffer));
68 }
69 out->write(buffer, n % sizeof(buffer));
70 }
71
72 // TODO(reed@): Decide if these five functions belong in SkColorPriv.h
SkIsBGRA(SkColorType ct)73 static bool SkIsBGRA(SkColorType ct) {
74 SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
75 return kBGRA_8888_SkColorType == ct;
76 }
77
78 // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
79 // RGBA_8888) and return the appropriate component. Each component
80 // should be interpreted according to the associated SkAlphaType and
81 // SkColorProfileType.
SkGetA32Component(uint32_t value,SkColorType ct)82 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
83 return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
84 }
SkGetR32Component(uint32_t value,SkColorType ct)85 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
86 return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
87 }
SkGetG32Component(uint32_t value,SkColorType ct)88 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
89 return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
90 }
SkGetB32Component(uint32_t value,SkColorType ct)91 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
92 return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
93 }
94
95
96 // unpremultiply and extract R, G, B components.
pmcolor_to_rgb24(uint32_t color,uint8_t * rgb,SkColorType ct)97 static void pmcolor_to_rgb24(uint32_t color, uint8_t* rgb, SkColorType ct) {
98 uint32_t s = SkUnPreMultiply::GetScale(SkGetA32Component(color, ct));
99 rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetR32Component(color, ct));
100 rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetG32Component(color, ct));
101 rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetB32Component(color, ct));
102 }
103
104 /* It is necessary to average the color component of transparent
105 pixels with their surrounding neighbors since the PDF renderer may
106 separately re-sample the alpha and color channels when the image is
107 not displayed at its native resolution. Since an alpha of zero
108 gives no information about the color component, the pathological
109 case is a white image with sharp transparency bounds - the color
110 channel goes to black, and the should-be-transparent pixels are
111 rendered as grey because of the separate soft mask and color
112 resizing. e.g.: gm/bitmappremul.cpp */
get_neighbor_avg_color(const SkBitmap & bm,int xOrig,int yOrig,uint8_t rgb[3],SkColorType ct)113 static void get_neighbor_avg_color(const SkBitmap& bm,
114 int xOrig,
115 int yOrig,
116 uint8_t rgb[3],
117 SkColorType ct) {
118 unsigned a = 0, r = 0, g = 0, b = 0;
119 // Clamp the range to the edge of the bitmap.
120 int ymin = SkTMax(0, yOrig - 1);
121 int ymax = SkTMin(yOrig + 1, bm.height() - 1);
122 int xmin = SkTMax(0, xOrig - 1);
123 int xmax = SkTMin(xOrig + 1, bm.width() - 1);
124 for (int y = ymin; y <= ymax; ++y) {
125 uint32_t* scanline = bm.getAddr32(0, y);
126 for (int x = xmin; x <= xmax; ++x) {
127 uint32_t color = scanline[x];
128 a += SkGetA32Component(color, ct);
129 r += SkGetR32Component(color, ct);
130 g += SkGetG32Component(color, ct);
131 b += SkGetB32Component(color, ct);
132 }
133 }
134 if (a > 0) {
135 rgb[0] = SkToU8(255 * r / a);
136 rgb[1] = SkToU8(255 * g / a);
137 rgb[2] = SkToU8(255 * b / a);
138 } else {
139 rgb[0] = rgb[1] = rgb[2] = 0;
140 }
141 }
142
pixel_count(const SkBitmap & bm)143 static size_t pixel_count(const SkBitmap& bm) {
144 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
145 }
146
not4444(const SkBitmap & input,SkBitmap * copy)147 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
148 if (input.colorType() != kARGB_4444_SkColorType) {
149 return input;
150 }
151 // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
152 SkAssertResult(input.copyTo(copy, kN32_SkColorType));
153 copy->setImmutable();
154 return *copy;
155 }
156
pdf_color_component_count(SkColorType ct)157 static size_t pdf_color_component_count(SkColorType ct) {
158 switch (ct) {
159 case kRGB_565_SkColorType:
160 case kARGB_4444_SkColorType:
161 case kRGBA_8888_SkColorType:
162 case kBGRA_8888_SkColorType:
163 return 3;
164 case kAlpha_8_SkColorType:
165 case kIndex_8_SkColorType:
166 case kGray_8_SkColorType:
167 return 1;
168 case kUnknown_SkColorType:
169 default:
170 SkDEBUGFAIL("unexpected color type");
171 return 0;
172 }
173 }
174
bitmap_to_pdf_pixels(const SkBitmap & bitmap,SkWStream * out)175 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
176 if (!bitmap.getPixels()) {
177 size_t size = pixel_count(bitmap) *
178 pdf_color_component_count(bitmap.colorType());
179 fill_stream(out, '\x00', size);
180 return;
181 }
182 SkBitmap copy;
183 const SkBitmap& bm = not4444(bitmap, ©);
184 SkAutoLockPixels autoLockPixels(bm);
185 SkColorType colorType = bm.colorType();
186 switch (colorType) {
187 case kRGBA_8888_SkColorType:
188 case kBGRA_8888_SkColorType: {
189 SkASSERT(3 == pdf_color_component_count(colorType));
190 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
191 for (int y = 0; y < bm.height(); ++y) {
192 const uint32_t* src = bm.getAddr32(0, y);
193 uint8_t* dst = scanline.get();
194 for (int x = 0; x < bm.width(); ++x) {
195 uint32_t color = *src++;
196 U8CPU alpha = SkGetA32Component(color, colorType);
197 if (alpha != SK_AlphaTRANSPARENT) {
198 pmcolor_to_rgb24(color, dst, colorType);
199 } else {
200 get_neighbor_avg_color(bm, x, y, dst, colorType);
201 }
202 dst += 3;
203 }
204 out->write(scanline.get(), 3 * bm.width());
205 }
206 return;
207 }
208 case kRGB_565_SkColorType: {
209 SkASSERT(3 == pdf_color_component_count(colorType));
210 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
211 for (int y = 0; y < bm.height(); ++y) {
212 const uint16_t* src = bm.getAddr16(0, y);
213 uint8_t* dst = scanline.get();
214 for (int x = 0; x < bm.width(); ++x) {
215 U16CPU color565 = *src++;
216 *dst++ = SkPacked16ToR32(color565);
217 *dst++ = SkPacked16ToG32(color565);
218 *dst++ = SkPacked16ToB32(color565);
219 }
220 out->write(scanline.get(), 3 * bm.width());
221 }
222 return;
223 }
224 case kAlpha_8_SkColorType:
225 SkASSERT(1 == pdf_color_component_count(colorType));
226 fill_stream(out, '\x00', pixel_count(bm));
227 return;
228 case kGray_8_SkColorType:
229 case kIndex_8_SkColorType:
230 SkASSERT(1 == pdf_color_component_count(colorType));
231 // these two formats need no transformation to serialize.
232 for (int y = 0; y < bm.height(); ++y) {
233 out->write(bm.getAddr8(0, y), bm.width());
234 }
235 return;
236 case kUnknown_SkColorType:
237 case kARGB_4444_SkColorType:
238 default:
239 SkDEBUGFAIL("unexpected color type");
240 }
241 }
242
243 ////////////////////////////////////////////////////////////////////////////////
244
bitmap_alpha_to_a8(const SkBitmap & bitmap,SkWStream * out)245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
246 if (!bitmap.getPixels()) {
247 fill_stream(out, '\xFF', pixel_count(bitmap));
248 return;
249 }
250 SkBitmap copy;
251 const SkBitmap& bm = not4444(bitmap, ©);
252 SkAutoLockPixels autoLockPixels(bm);
253 SkColorType colorType = bm.colorType();
254 switch (colorType) {
255 case kRGBA_8888_SkColorType:
256 case kBGRA_8888_SkColorType: {
257 SkAutoTMalloc<uint8_t> scanline(bm.width());
258 for (int y = 0; y < bm.height(); ++y) {
259 uint8_t* dst = scanline.get();
260 const SkPMColor* src = bm.getAddr32(0, y);
261 for (int x = 0; x < bm.width(); ++x) {
262 *dst++ = SkGetA32Component(*src++, colorType);
263 }
264 out->write(scanline.get(), bm.width());
265 }
266 return;
267 }
268 case kAlpha_8_SkColorType:
269 for (int y = 0; y < bm.height(); ++y) {
270 out->write(bm.getAddr8(0, y), bm.width());
271 }
272 return;
273 case kIndex_8_SkColorType: {
274 SkColorTable* ct = bm.getColorTable();
275 SkASSERT(ct);
276 SkAutoTMalloc<uint8_t> scanline(bm.width());
277 for (int y = 0; y < bm.height(); ++y) {
278 uint8_t* dst = scanline.get();
279 const uint8_t* src = bm.getAddr8(0, y);
280 for (int x = 0; x < bm.width(); ++x) {
281 *dst++ = SkGetPackedA32((*ct)[*src++]);
282 }
283 out->write(scanline.get(), bm.width());
284 }
285 return;
286 }
287 case kRGB_565_SkColorType:
288 case kGray_8_SkColorType:
289 SkDEBUGFAIL("color type has no alpha");
290 return;
291 case kARGB_4444_SkColorType:
292 SkDEBUGFAIL("4444 color type should have been converted to N32");
293 return;
294 case kUnknown_SkColorType:
295 default:
296 SkDEBUGFAIL("unexpected color type");
297 }
298 }
299
make_indexed_color_space(const SkColorTable * table)300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
301 SkPDFArray* result = new SkPDFArray;
302 result->reserve(4);
303 result->appendName("Indexed");
304 result->appendName("DeviceRGB");
305 SkASSERT(table);
306 if (table->count() < 1) {
307 result->appendInt(0);
308 char shortTableArray[3] = {0, 0, 0};
309 SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
310 result->appendString(tableString);
311 return result;
312 }
313 result->appendInt(table->count() - 1); // maximum color index.
314
315 // Potentially, this could be represented in fewer bytes with a stream.
316 // Max size as a string is 1.5k.
317 char tableArray[256 * 3];
318 SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
319 uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
320 const SkPMColor* colors = table->readColors();
321 for (int i = 0; i < table->count(); i++) {
322 pmcolor_to_rgb24(colors[i], tablePtr, kN32_SkColorType);
323 tablePtr += 3;
324 }
325 SkString tableString(tableArray, 3 * table->count());
326 result->appendString(tableString);
327 return result;
328 }
329
emit_image_xobject(SkWStream * stream,const SkImage * image,bool alpha,SkPDFObject * smask,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes)330 static void emit_image_xobject(SkWStream* stream,
331 const SkImage* image,
332 bool alpha,
333 SkPDFObject* smask,
334 const SkPDFObjNumMap& objNumMap,
335 const SkPDFSubstituteMap& substitutes) {
336 SkBitmap bitmap;
337 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test
338 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images.
339
340 // Write to a temporary buffer to get the compressed length.
341 SkDynamicMemoryWStream buffer;
342 SkDeflateWStream deflateWStream(&buffer);
343 if (alpha) {
344 bitmap_alpha_to_a8(bitmap, &deflateWStream);
345 } else {
346 bitmap_to_pdf_pixels(bitmap, &deflateWStream);
347 }
348 deflateWStream.finalize(); // call before detachAsStream().
349 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
350
351 SkPDFDict pdfDict("XObject");
352 pdfDict.insertName("Subtype", "Image");
353 pdfDict.insertInt("Width", bitmap.width());
354 pdfDict.insertInt("Height", bitmap.height());
355 if (alpha) {
356 pdfDict.insertName("ColorSpace", "DeviceGray");
357 } else if (bitmap.colorType() == kIndex_8_SkColorType) {
358 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
359 pdfDict.insertObject("ColorSpace",
360 make_indexed_color_space(bitmap.getColorTable()));
361 } else if (1 == pdf_color_component_count(bitmap.colorType())) {
362 pdfDict.insertName("ColorSpace", "DeviceGray");
363 } else {
364 pdfDict.insertName("ColorSpace", "DeviceRGB");
365 }
366 if (smask) {
367 pdfDict.insertObjRef("SMask", SkRef(smask));
368 }
369 pdfDict.insertInt("BitsPerComponent", 8);
370 pdfDict.insertName("Filter", "FlateDecode");
371 pdfDict.insertInt("Length", asset->getLength());
372 pdfDict.emitObject(stream, objNumMap, substitutes);
373
374 pdf_stream_begin(stream);
375 stream->writeStream(asset.get(), asset->getLength());
376 pdf_stream_end(stream);
377 }
378
379 ////////////////////////////////////////////////////////////////////////////////
380
381 namespace {
382 // This SkPDFObject only outputs the alpha layer of the given bitmap.
383 class PDFAlphaBitmap final : public SkPDFObject {
384 public:
PDFAlphaBitmap(const SkImage * image)385 PDFAlphaBitmap(const SkImage* image) : fImage(SkRef(image)) {}
~PDFAlphaBitmap()386 ~PDFAlphaBitmap() {}
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & subs) const387 void emitObject(SkWStream* stream,
388 const SkPDFObjNumMap& objNumMap,
389 const SkPDFSubstituteMap& subs) const override {
390 emit_image_xobject(stream, fImage, true, nullptr, objNumMap, subs);
391 }
392
393 private:
394 SkAutoTUnref<const SkImage> fImage;
395 };
396
397 } // namespace
398
399 ////////////////////////////////////////////////////////////////////////////////
400
401 namespace {
402 class PDFDefaultBitmap final : public SkPDFObject {
403 public:
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & subs) const404 void emitObject(SkWStream* stream,
405 const SkPDFObjNumMap& objNumMap,
406 const SkPDFSubstituteMap& subs) const override {
407 emit_image_xobject(stream, fImage, false, fSMask, objNumMap, subs);
408 }
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & subs) const409 void addResources(SkPDFObjNumMap* catalog,
410 const SkPDFSubstituteMap& subs) const override {
411 if (fSMask.get()) {
412 SkPDFObject* obj = subs.getSubstitute(fSMask.get());
413 SkASSERT(obj);
414 catalog->addObjectRecursively(obj, subs);
415 }
416 }
PDFDefaultBitmap(const SkImage * image,SkPDFObject * smask)417 PDFDefaultBitmap(const SkImage* image, SkPDFObject* smask)
418 : fImage(SkRef(image)), fSMask(smask) {}
419
420 private:
421 SkAutoTUnref<const SkImage> fImage;
422 const SkAutoTUnref<SkPDFObject> fSMask;
423 };
424 } // namespace
425
426 ////////////////////////////////////////////////////////////////////////////////
427
428 namespace {
429 /**
430 * This PDFObject assumes that its constructor was handed YUV or
431 * Grayscale JFIF Jpeg-encoded data that can be directly embedded
432 * into a PDF.
433 */
434 class PDFJpegBitmap final : public SkPDFObject {
435 public:
436 SkISize fSize;
437 SkAutoTUnref<SkData> fData;
438 bool fIsYUV;
PDFJpegBitmap(SkISize size,SkData * data,bool isYUV)439 PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
440 : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) {}
441 void emitObject(SkWStream*,
442 const SkPDFObjNumMap&,
443 const SkPDFSubstituteMap&) const override;
444 };
445
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substituteMap) const446 void PDFJpegBitmap::emitObject(SkWStream* stream,
447 const SkPDFObjNumMap& objNumMap,
448 const SkPDFSubstituteMap& substituteMap) const {
449 SkPDFDict pdfDict("XObject");
450 pdfDict.insertName("Subtype", "Image");
451 pdfDict.insertInt("Width", fSize.width());
452 pdfDict.insertInt("Height", fSize.height());
453 if (fIsYUV) {
454 pdfDict.insertName("ColorSpace", "DeviceRGB");
455 } else {
456 pdfDict.insertName("ColorSpace", "DeviceGray");
457 }
458 pdfDict.insertInt("BitsPerComponent", 8);
459 pdfDict.insertName("Filter", "DCTDecode");
460 pdfDict.insertInt("ColorTransform", 0);
461 pdfDict.insertInt("Length", SkToInt(fData->size()));
462 pdfDict.emitObject(stream, objNumMap, substituteMap);
463 pdf_stream_begin(stream);
464 stream->write(fData->data(), fData->size());
465 pdf_stream_end(stream);
466 }
467 } // namespace
468
469 ////////////////////////////////////////////////////////////////////////////////
470
SkPDFCreateBitmapObject(const SkImage * image,SkPixelSerializer * pixelSerializer)471 SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image,
472 SkPixelSerializer* pixelSerializer) {
473 SkAutoTUnref<SkData> data(image->refEncoded());
474 SkJFIFInfo info;
475 if (data && SkIsJFIF(data, &info) &&
476 (!pixelSerializer ||
477 pixelSerializer->useEncodedData(data->data(), data->size()))) {
478 // If there is a SkPixelSerializer, give it a chance to
479 // re-encode the JPEG with more compression by returning false
480 // from useEncodedData.
481 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
482 if (info.fSize == image->dimensions()) { // Sanity check.
483 // hold on to data, not image.
484 #ifdef SK_PDF_IMAGE_STATS
485 gJpegImageObjects.fetch_add(1);
486 #endif
487 return new PDFJpegBitmap(info.fSize, data, yuv);
488 }
489 }
490
491 if (pixelSerializer) {
492 SkBitmap bm;
493 SkAutoPixmapUnlock apu;
494 if (as_IB(image)->getROPixels(&bm) && bm.requestLock(&apu)) {
495 data.reset(pixelSerializer->encode(apu.pixmap()));
496 if (data && SkIsJFIF(data, &info)) {
497 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
498 if (info.fSize == image->dimensions()) { // Sanity check.
499 return new PDFJpegBitmap(info.fSize, data, yuv);
500 }
501 }
502 }
503 }
504
505 SkPDFObject* smask =
506 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image);
507 #ifdef SK_PDF_IMAGE_STATS
508 gRegularImageObjects.fetch_add(1);
509 #endif
510 return new PDFDefaultBitmap(image, smask);
511 }
512