2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkColorPriv.h"
10 #include "SkDeflate.h"
11 #include "SkImage_Base.h"
12 #include "SkJpegInfo.h"
13 #include "SkPDFBitmap.h"
14 #include "SkPDFCanon.h"
15 #include "SkPDFTypes.h"
17 #include "SkUnPreMultiply.h"
19 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
20 SkColorSpace* legacyColorSpace = nullptr;
21 if(as_IB(image)->getROPixels(dst, legacyColorSpace)
22 && dst->dimensions() == image->dimensions()) {
23 if (dst->colorType() != kIndex_8_SkColorType) {
26 // We must check to see if the bitmap has a color table.
27 SkAutoLockPixels autoLockPixels(*dst);
28 if (!dst->getColorTable()) {
29 // We can't use an indexed bitmap with no colortable.
35 // no pixels or wrong size: fill with zeros.
36 dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
39 bool image_compute_is_opaque(const SkImage* image) {
40 if (image->isOpaque()) {
43 // keep output PDF small at cost of possible resource use.
45 image_get_ro_pixels(image, &bm);
46 return SkBitmap::ComputeIsOpaque(bm);
49 ////////////////////////////////////////////////////////////////////////////////
51 static void pdf_stream_begin(SkWStream* stream) {
52 static const char streamBegin[] = " stream\n";
53 stream->write(streamBegin, strlen(streamBegin));
56 static void pdf_stream_end(SkWStream* stream) {
57 static const char streamEnd[] = "\nendstream";
58 stream->write(streamEnd, strlen(streamEnd));
61 ////////////////////////////////////////////////////////////////////////////////
63 // write a single byte to a stream n times.
64 static void fill_stream(SkWStream* out, char value, size_t n) {
66 memset(buffer, value, sizeof(buffer));
67 for (size_t i = 0; i < n / sizeof(buffer); ++i) {
68 out->write(buffer, sizeof(buffer));
70 out->write(buffer, n % sizeof(buffer));
73 // TODO(reed@): Decide if these five functions belong in SkColorPriv.h
74 static bool SkIsBGRA(SkColorType ct) {
75 SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
76 return kBGRA_8888_SkColorType == ct;
79 // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
80 // RGBA_8888) and return the appropriate component. Each component
81 // should be interpreted according to the associated SkAlphaType and
82 // SkColorProfileType.
83 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
84 return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
86 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
87 return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
89 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
90 return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
92 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
93 return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
96 // unpremultiply and extract R, G, B components.
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));
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 */
113 static void get_neighbor_avg_color(const SkBitmap& bm,
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);
135 rgb[0] = SkToU8(255 * r / a);
136 rgb[1] = SkToU8(255 * g / a);
137 rgb[2] = SkToU8(255 * b / a);
139 rgb[0] = rgb[1] = rgb[2] = 0;
143 static size_t pixel_count(const SkBitmap& bm) {
144 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
147 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
148 if (input.colorType() != kARGB_4444_SkColorType) {
151 // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
152 SkAssertResult(input.copyTo(copy, kN32_SkColorType));
153 copy->setImmutable();
157 static size_t pdf_color_component_count(SkColorType ct) {
159 case kRGB_565_SkColorType:
160 case kARGB_4444_SkColorType:
161 case kRGBA_8888_SkColorType:
162 case kBGRA_8888_SkColorType:
164 case kAlpha_8_SkColorType:
165 case kIndex_8_SkColorType:
166 case kGray_8_SkColorType:
168 case kUnknown_SkColorType:
170 SkDEBUGFAIL("unexpected color type");
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);
183 const SkBitmap& bm = not4444(bitmap, ©);
184 SkAutoLockPixels autoLockPixels(bm);
185 SkColorType colorType = bm.colorType();
186 SkAlphaType alphaType = bm.alphaType();
188 case kRGBA_8888_SkColorType:
189 case kBGRA_8888_SkColorType: {
190 SkASSERT(3 == pdf_color_component_count(colorType));
191 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
192 for (int y = 0; y < bm.height(); ++y) {
193 const uint32_t* src = bm.getAddr32(0, y);
194 uint8_t* dst = scanline.get();
195 for (int x = 0; x < bm.width(); ++x) {
196 if (alphaType == kPremul_SkAlphaType) {
197 uint32_t color = *src++;
198 U8CPU alpha = SkGetA32Component(color, colorType);
199 if (alpha != SK_AlphaTRANSPARENT) {
200 pmcolor_to_rgb24(color, dst, colorType);
202 get_neighbor_avg_color(bm, x, y, dst, colorType);
206 uint32_t color = *src++;
207 *dst++ = SkGetR32Component(color, colorType);
208 *dst++ = SkGetG32Component(color, colorType);
209 *dst++ = SkGetB32Component(color, colorType);
212 out->write(scanline.get(), 3 * bm.width());
216 case kRGB_565_SkColorType: {
217 SkASSERT(3 == pdf_color_component_count(colorType));
218 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
219 for (int y = 0; y < bm.height(); ++y) {
220 const uint16_t* src = bm.getAddr16(0, y);
221 uint8_t* dst = scanline.get();
222 for (int x = 0; x < bm.width(); ++x) {
223 U16CPU color565 = *src++;
224 *dst++ = SkPacked16ToR32(color565);
225 *dst++ = SkPacked16ToG32(color565);
226 *dst++ = SkPacked16ToB32(color565);
228 out->write(scanline.get(), 3 * bm.width());
232 case kAlpha_8_SkColorType:
233 SkASSERT(1 == pdf_color_component_count(colorType));
234 fill_stream(out, '\x00', pixel_count(bm));
236 case kGray_8_SkColorType:
237 case kIndex_8_SkColorType:
238 SkASSERT(1 == pdf_color_component_count(colorType));
239 // these two formats need no transformation to serialize.
240 for (int y = 0; y < bm.height(); ++y) {
241 out->write(bm.getAddr8(0, y), bm.width());
244 case kUnknown_SkColorType:
245 case kARGB_4444_SkColorType:
247 SkDEBUGFAIL("unexpected color type");
251 ////////////////////////////////////////////////////////////////////////////////
253 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
254 if (!bitmap.getPixels()) {
255 fill_stream(out, '\xFF', pixel_count(bitmap));
259 const SkBitmap& bm = not4444(bitmap, ©);
260 SkAutoLockPixels autoLockPixels(bm);
261 SkColorType colorType = bm.colorType();
263 case kRGBA_8888_SkColorType:
264 case kBGRA_8888_SkColorType: {
265 SkAutoTMalloc<uint8_t> scanline(bm.width());
266 for (int y = 0; y < bm.height(); ++y) {
267 uint8_t* dst = scanline.get();
268 const SkPMColor* src = bm.getAddr32(0, y);
269 for (int x = 0; x < bm.width(); ++x) {
270 *dst++ = SkGetA32Component(*src++, colorType);
272 out->write(scanline.get(), bm.width());
276 case kAlpha_8_SkColorType:
277 for (int y = 0; y < bm.height(); ++y) {
278 out->write(bm.getAddr8(0, y), bm.width());
281 case kIndex_8_SkColorType: {
282 SkColorTable* ct = bm.getColorTable();
284 SkAutoTMalloc<uint8_t> scanline(bm.width());
285 for (int y = 0; y < bm.height(); ++y) {
286 uint8_t* dst = scanline.get();
287 const uint8_t* src = bm.getAddr8(0, y);
288 for (int x = 0; x < bm.width(); ++x) {
289 *dst++ = SkGetPackedA32((*ct)[*src++]);
291 out->write(scanline.get(), bm.width());
295 case kRGB_565_SkColorType:
296 case kGray_8_SkColorType:
297 SkDEBUGFAIL("color type has no alpha");
299 case kARGB_4444_SkColorType:
300 SkDEBUGFAIL("4444 color type should have been converted to N32");
302 case kUnknown_SkColorType:
304 SkDEBUGFAIL("unexpected color type");
308 static sk_sp<SkPDFArray> make_indexed_color_space(
309 const SkColorTable* table,
310 SkAlphaType alphaType) {
311 auto result = sk_make_sp<SkPDFArray>();
313 result->appendName("Indexed");
314 result->appendName("DeviceRGB");
316 if (table->count() < 1) {
317 result->appendInt(0);
318 char shortTableArray[3] = {0, 0, 0};
319 SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
320 result->appendString(tableString);
323 result->appendInt(table->count() - 1); // maximum color index.
325 // Potentially, this could be represented in fewer bytes with a stream.
326 // Max size as a string is 1.5k.
327 char tableArray[256 * 3];
328 SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
329 uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
330 const SkPMColor* colors = table->readColors();
331 for (int i = 0; i < table->count(); i++) {
332 if (alphaType == kPremul_SkAlphaType) {
333 pmcolor_to_rgb24(colors[i], tablePtr, kN32_SkColorType);
336 *tablePtr++ = SkGetR32Component(colors[i], kN32_SkColorType);
337 *tablePtr++ = SkGetG32Component(colors[i], kN32_SkColorType);
338 *tablePtr++ = SkGetB32Component(colors[i], kN32_SkColorType);
341 SkString tableString(tableArray, 3 * table->count());
342 result->appendString(tableString);
346 static void emit_image_xobject(SkWStream* stream,
347 const SkImage* image,
349 const sk_sp<SkPDFObject>& smask,
350 const SkPDFObjNumMap& objNumMap) {
352 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test
353 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images.
355 // Write to a temporary buffer to get the compressed length.
356 SkDynamicMemoryWStream buffer;
357 SkDeflateWStream deflateWStream(&buffer);
359 bitmap_alpha_to_a8(bitmap, &deflateWStream);
361 bitmap_to_pdf_pixels(bitmap, &deflateWStream);
363 deflateWStream.finalize(); // call before detachAsStream().
364 std::unique_ptr<SkStreamAsset> asset(buffer.detachAsStream());
366 SkPDFDict pdfDict("XObject");
367 pdfDict.insertName("Subtype", "Image");
368 pdfDict.insertInt("Width", bitmap.width());
369 pdfDict.insertInt("Height", bitmap.height());
371 pdfDict.insertName("ColorSpace", "DeviceGray");
372 } else if (bitmap.colorType() == kIndex_8_SkColorType) {
373 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
374 pdfDict.insertObject("ColorSpace",
375 make_indexed_color_space(bitmap.getColorTable(),
376 bitmap.alphaType()));
377 } else if (1 == pdf_color_component_count(bitmap.colorType())) {
378 pdfDict.insertName("ColorSpace", "DeviceGray");
380 pdfDict.insertName("ColorSpace", "DeviceRGB");
383 pdfDict.insertObjRef("SMask", smask);
385 pdfDict.insertInt("BitsPerComponent", 8);
386 pdfDict.insertName("Filter", "FlateDecode");
387 pdfDict.insertInt("Length", asset->getLength());
388 pdfDict.emitObject(stream, objNumMap);
390 pdf_stream_begin(stream);
391 stream->writeStream(asset.get(), asset->getLength());
392 pdf_stream_end(stream);
395 ////////////////////////////////////////////////////////////////////////////////
398 // This SkPDFObject only outputs the alpha layer of the given bitmap.
399 class PDFAlphaBitmap final : public SkPDFObject {
401 PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
402 void emitObject(SkWStream* stream,
403 const SkPDFObjNumMap& objNumMap) const override {
405 emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
407 void drop() override { fImage = nullptr; }
410 sk_sp<SkImage> fImage;
415 ////////////////////////////////////////////////////////////////////////////////
418 class PDFDefaultBitmap final : public SkPDFObject {
420 void emitObject(SkWStream* stream,
421 const SkPDFObjNumMap& objNumMap) const override {
423 emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
425 void addResources(SkPDFObjNumMap* catalog) const override {
426 catalog->addObjectRecursively(fSMask.get());
428 void drop() override { fImage = nullptr; fSMask = nullptr; }
429 PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
430 : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); }
433 sk_sp<SkImage> fImage;
434 sk_sp<SkPDFObject> fSMask;
438 ////////////////////////////////////////////////////////////////////////////////
442 * This PDFObject assumes that its constructor was handed YUV or
443 * Grayscale JFIF Jpeg-encoded data that can be directly embedded
446 class PDFJpegBitmap final : public SkPDFObject {
451 PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
452 : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
453 void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
454 void drop() override { fData = nullptr; }
457 void PDFJpegBitmap::emitObject(SkWStream* stream,
458 const SkPDFObjNumMap& objNumMap) const {
460 SkPDFDict pdfDict("XObject");
461 pdfDict.insertName("Subtype", "Image");
462 pdfDict.insertInt("Width", fSize.width());
463 pdfDict.insertInt("Height", fSize.height());
465 pdfDict.insertName("ColorSpace", "DeviceRGB");
467 pdfDict.insertName("ColorSpace", "DeviceGray");
469 pdfDict.insertInt("BitsPerComponent", 8);
470 pdfDict.insertName("Filter", "DCTDecode");
471 pdfDict.insertInt("ColorTransform", 0);
472 pdfDict.insertInt("Length", SkToInt(fData->size()));
473 pdfDict.emitObject(stream, objNumMap);
474 pdf_stream_begin(stream);
475 stream->write(fData->data(), fData->size());
476 pdf_stream_end(stream);
480 ////////////////////////////////////////////////////////////////////////////////
482 sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image,
483 SkPixelSerializer* pixelSerializer) {
485 sk_sp<SkData> data(image->refEncoded());
487 if (data && SkIsJFIF(data.get(), &info) &&
489 pixelSerializer->useEncodedData(data->data(), data->size()))) {
490 // If there is a SkPixelSerializer, give it a chance to
491 // re-encode the JPEG with more compression by returning false
492 // from useEncodedData.
493 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
494 if (info.fSize == image->dimensions()) { // Sanity check.
495 // hold on to data, not image.
496 #ifdef SK_PDF_IMAGE_STATS
497 gJpegImageObjects.fetch_add(1);
499 return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
503 if (pixelSerializer) {
505 SkAutoPixmapUnlock apu;
506 SkColorSpace* legacyColorSpace = nullptr;
507 if (as_IB(image.get())->getROPixels(&bm, legacyColorSpace) &&
508 bm.requestLock(&apu)) {
509 data.reset(pixelSerializer->encode(apu.pixmap()));
510 if (data && SkIsJFIF(data.get(), &info)) {
511 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
512 if (info.fSize == image->dimensions()) { // Sanity check.
513 return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
519 sk_sp<SkPDFObject> smask;
520 if (!image_compute_is_opaque(image.get())) {
521 smask = sk_make_sp<PDFAlphaBitmap>(image);
523 #ifdef SK_PDF_IMAGE_STATS
524 gRegularImageObjects.fetch_add(1);
526 return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));