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