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 21bool 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 33static const char kStreamBegin[] = " stream\n"; 34 35static const char kStreamEnd[] = "\nendstream"; 36 37//////////////////////////////////////////////////////////////////////////////// 38 39// write a single byte to a stream n times. 40static 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 50static 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. 59static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) { 60 return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF; 61} 62static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) { 63 return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF; 64} 65static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) { 66 return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF; 67} 68static 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. 73static 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 */ 90static 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 121static size_t pixel_count(const SkBitmap& bm) { 122 return SkToSizeT(bm.width()) * SkToSizeT(bm.height()); 123} 124 125static 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 147static 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 162static 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 238static 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 278static 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 325namespace { 326// This SkPDFObject only outputs the alpha layer of the given bitmap. 327class PDFAlphaBitmap final : public SkPDFObject { 328public: 329 PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); } 330 void emitObject(SkWStream* stream, 331 const SkPDFObjNumMap& objNumMap) const override { 332 SkASSERT(fImage); 333 emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap); 334 } 335 void drop() override { fImage = nullptr; } 336 337private: 338 sk_sp<SkImage> fImage; 339}; 340 341} // namespace 342 343//////////////////////////////////////////////////////////////////////////////// 344 345namespace { 346class PDFDefaultBitmap final : public SkPDFObject { 347public: 348 void emitObject(SkWStream* stream, 349 const SkPDFObjNumMap& objNumMap) const override { 350 SkASSERT(fImage); 351 emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap); 352 } 353 void addResources(SkPDFObjNumMap* catalog) const override { 354 catalog->addObjectRecursively(fSMask.get()); 355 } 356 void drop() override { fImage = nullptr; fSMask = nullptr; } 357 PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask) 358 : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); } 359 360private: 361 sk_sp<SkImage> fImage; 362 sk_sp<SkPDFObject> fSMask; 363}; 364} // namespace 365 366//////////////////////////////////////////////////////////////////////////////// 367 368namespace { 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 */ 374class PDFJpegBitmap final : public SkPDFObject { 375public: 376 SkISize fSize; 377 sk_sp<SkData> fData; 378 bool fIsYUV; 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; 382 void drop() override { fData = nullptr; } 383}; 384 385void 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 410sk_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