Home | History | Annotate | Download | only in pdf
      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 
     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 
     33 static const char kStreamBegin[] = " stream\n";
     34 
     35 static const char kStreamEnd[] = "\nendstream";
     36 
     37 ////////////////////////////////////////////////////////////////////////////////
     38 
     39 // write a single byte to a stream n times.
     40 static 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
     50 static 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.
     59 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
     60     return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
     61 }
     62 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
     63     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
     64 }
     65 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
     66     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
     67 }
     68 static 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.
     73 static 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 */
     90 static 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 
    121 static size_t pixel_count(const SkBitmap& bm) {
    122     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
    123 }
    124 
    125 static 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 
    147 static 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 
    162 static 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, &copy);
    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 
    238 static 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, &copy);
    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 
    278 static 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 
    325 namespace {
    326 // This SkPDFObject only outputs the alpha layer of the given bitmap.
    327 class PDFAlphaBitmap final : public SkPDFObject {
    328 public:
    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 
    337 private:
    338     sk_sp<SkImage> fImage;
    339 };
    340 
    341 }  // namespace
    342 
    343 ////////////////////////////////////////////////////////////////////////////////
    344 
    345 namespace {
    346 class PDFDefaultBitmap final : public SkPDFObject {
    347 public:
    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 
    360 private:
    361     sk_sp<SkImage> fImage;
    362     sk_sp<SkPDFObject> fSMask;
    363 };
    364 }  // namespace
    365 
    366 ////////////////////////////////////////////////////////////////////////////////
    367 
    368 namespace {
    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  */
    374 class PDFJpegBitmap final : public SkPDFObject {
    375 public:
    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 
    385 void 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 
    410 sk_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