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 "SkColorPriv.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 void pdf_stream_begin(SkWStream* stream) {
     34     static const char streamBegin[] = " stream\n";
     35     stream->write(streamBegin, strlen(streamBegin));
     36 }
     37 
     38 static void pdf_stream_end(SkWStream* stream) {
     39     static const char streamEnd[] = "\nendstream";
     40     stream->write(streamEnd, strlen(streamEnd));
     41 }
     42 
     43 ////////////////////////////////////////////////////////////////////////////////
     44 
     45 // write a single byte to a stream n times.
     46 static void fill_stream(SkWStream* out, char value, size_t n) {
     47     char buffer[4096];
     48     memset(buffer, value, sizeof(buffer));
     49     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
     50         out->write(buffer, sizeof(buffer));
     51     }
     52     out->write(buffer, n % sizeof(buffer));
     53 }
     54 
     55 // TODO(reed@): Decide if these five functions belong in SkColorPriv.h
     56 static bool SkIsBGRA(SkColorType ct) {
     57     SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
     58     return kBGRA_8888_SkColorType == ct;
     59 }
     60 
     61 // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
     62 // RGBA_8888) and return the appropriate component.  Each component
     63 // should be interpreted according to the associated SkAlphaType and
     64 // SkColorProfileType.
     65 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
     66     return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
     67 }
     68 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
     69     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
     70 }
     71 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
     72     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
     73 }
     74 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
     75     return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
     76 }
     77 
     78 // unpremultiply and extract R, G, B components.
     79 static void pmcolor_to_rgb24(uint32_t color, uint8_t* rgb, SkColorType ct) {
     80     SkPMColorAssert(color);
     81     uint32_t s = SkUnPreMultiply::GetScale(SkGetA32Component(color, ct));
     82     rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetR32Component(color, ct));
     83     rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetG32Component(color, ct));
     84     rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetB32Component(color, ct));
     85 }
     86 
     87 /* It is necessary to average the color component of transparent
     88    pixels with their surrounding neighbors since the PDF renderer may
     89    separately re-sample the alpha and color channels when the image is
     90    not displayed at its native resolution. Since an alpha of zero
     91    gives no information about the color component, the pathological
     92    case is a white image with sharp transparency bounds - the color
     93    channel goes to black, and the should-be-transparent pixels are
     94    rendered as grey because of the separate soft mask and color
     95    resizing. e.g.: gm/bitmappremul.cpp */
     96 static void get_neighbor_avg_color(const SkBitmap& bm,
     97                                    int xOrig,
     98                                    int yOrig,
     99                                    uint8_t rgb[3],
    100                                    SkColorType ct) {
    101     unsigned a = 0, r = 0, g = 0, b = 0;
    102     // Clamp the range to the edge of the bitmap.
    103     int ymin = SkTMax(0, yOrig - 1);
    104     int ymax = SkTMin(yOrig + 1, bm.height() - 1);
    105     int xmin = SkTMax(0, xOrig - 1);
    106     int xmax = SkTMin(xOrig + 1, bm.width() - 1);
    107     for (int y = ymin; y <= ymax; ++y) {
    108         uint32_t* scanline = bm.getAddr32(0, y);
    109         for (int x = xmin; x <= xmax; ++x) {
    110             uint32_t color = scanline[x];
    111             SkPMColorAssert(color);
    112             a += SkGetA32Component(color, ct);
    113             r += SkGetR32Component(color, ct);
    114             g += SkGetG32Component(color, ct);
    115             b += SkGetB32Component(color, ct);
    116         }
    117     }
    118     if (a > 0) {
    119         rgb[0] = SkToU8(255 * r / a);
    120         rgb[1] = SkToU8(255 * g / a);
    121         rgb[2] = SkToU8(255 * b / a);
    122     } else {
    123         rgb[0] = rgb[1] = rgb[2] = 0;
    124     }
    125 }
    126 
    127 static size_t pixel_count(const SkBitmap& bm) {
    128     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
    129 }
    130 
    131 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
    132     if (input.colorType() != kARGB_4444_SkColorType) {
    133         return input;
    134     }
    135     // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
    136     copy->allocPixels(input.info().makeColorType(kN32_SkColorType));
    137     SkAssertResult(input.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0));
    138     copy->setImmutable();
    139     return *copy;
    140 }
    141 
    142 static size_t pdf_color_component_count(SkColorType ct) {
    143     switch (ct) {
    144         case kRGB_565_SkColorType:
    145         case kARGB_4444_SkColorType:
    146         case kRGBA_8888_SkColorType:
    147         case kBGRA_8888_SkColorType:
    148             return 3;
    149         case kAlpha_8_SkColorType:
    150         case kGray_8_SkColorType:
    151             return 1;
    152         case kUnknown_SkColorType:
    153         default:
    154             SkDEBUGFAIL("unexpected color type");
    155             return 0;
    156     }
    157 }
    158 
    159 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
    160     if (!bitmap.getPixels()) {
    161         size_t size = pixel_count(bitmap) *
    162                       pdf_color_component_count(bitmap.colorType());
    163         fill_stream(out, '\x00', size);
    164         return;
    165     }
    166     SkBitmap copy;
    167     const SkBitmap& bm = not4444(bitmap, &copy);
    168     SkColorType colorType = bm.colorType();
    169     SkAlphaType alphaType = bm.alphaType();
    170     switch (colorType) {
    171         case kRGBA_8888_SkColorType:
    172         case kBGRA_8888_SkColorType: {
    173             SkASSERT(3 == pdf_color_component_count(colorType));
    174             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    175             for (int y = 0; y < bm.height(); ++y) {
    176                 const uint32_t* src = bm.getAddr32(0, y);
    177                 uint8_t* dst = scanline.get();
    178                 for (int x = 0; x < bm.width(); ++x) {
    179                     if (alphaType == kPremul_SkAlphaType) {
    180                         uint32_t color = *src++;
    181                         U8CPU alpha = SkGetA32Component(color, colorType);
    182                         if (alpha != SK_AlphaTRANSPARENT) {
    183                             pmcolor_to_rgb24(color, dst, colorType);
    184                         } else {
    185                             get_neighbor_avg_color(bm, x, y, dst, colorType);
    186                         }
    187                         dst += 3;
    188                     } else {
    189                         uint32_t color = *src++;
    190                         *dst++ = SkGetR32Component(color, colorType);
    191                         *dst++ = SkGetG32Component(color, colorType);
    192                         *dst++ = SkGetB32Component(color, colorType);
    193                     }
    194                 }
    195                 out->write(scanline.get(), 3 * bm.width());
    196             }
    197             return;
    198         }
    199         case kRGB_565_SkColorType: {
    200             SkASSERT(3 == pdf_color_component_count(colorType));
    201             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    202             for (int y = 0; y < bm.height(); ++y) {
    203                 const uint16_t* src = bm.getAddr16(0, y);
    204                 uint8_t* dst = scanline.get();
    205                 for (int x = 0; x < bm.width(); ++x) {
    206                     U16CPU color565 = *src++;
    207                     *dst++ = SkPacked16ToR32(color565);
    208                     *dst++ = SkPacked16ToG32(color565);
    209                     *dst++ = SkPacked16ToB32(color565);
    210                 }
    211                 out->write(scanline.get(), 3 * bm.width());
    212             }
    213             return;
    214         }
    215         case kAlpha_8_SkColorType:
    216             SkASSERT(1 == pdf_color_component_count(colorType));
    217             fill_stream(out, '\x00', pixel_count(bm));
    218             return;
    219         case kGray_8_SkColorType:
    220             SkASSERT(1 == pdf_color_component_count(colorType));
    221             // these two formats need no transformation to serialize.
    222             for (int y = 0; y < bm.height(); ++y) {
    223                 out->write(bm.getAddr8(0, y), bm.width());
    224             }
    225             return;
    226         case kUnknown_SkColorType:
    227         case kARGB_4444_SkColorType:
    228         default:
    229             SkDEBUGFAIL("unexpected color type");
    230     }
    231 }
    232 
    233 ////////////////////////////////////////////////////////////////////////////////
    234 
    235 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
    236     if (!bitmap.getPixels()) {
    237         fill_stream(out, '\xFF', pixel_count(bitmap));
    238         return;
    239     }
    240     SkBitmap copy;
    241     const SkBitmap& bm = not4444(bitmap, &copy);
    242     SkColorType colorType = bm.colorType();
    243     switch (colorType) {
    244         case kRGBA_8888_SkColorType:
    245         case kBGRA_8888_SkColorType: {
    246             SkAutoTMalloc<uint8_t> scanline(bm.width());
    247             for (int y = 0; y < bm.height(); ++y) {
    248                 uint8_t* dst = scanline.get();
    249                 const SkPMColor* src = bm.getAddr32(0, y);
    250                 for (int x = 0; x < bm.width(); ++x) {
    251                     *dst++ = SkGetA32Component(*src++, colorType);
    252                 }
    253                 out->write(scanline.get(), bm.width());
    254             }
    255             return;
    256         }
    257         case kAlpha_8_SkColorType:
    258             for (int y = 0; y < bm.height(); ++y) {
    259                 out->write(bm.getAddr8(0, y), bm.width());
    260             }
    261             return;
    262         case kRGB_565_SkColorType:
    263         case kGray_8_SkColorType:
    264             SkDEBUGFAIL("color type has no alpha");
    265             return;
    266         case kARGB_4444_SkColorType:
    267             SkDEBUGFAIL("4444 color type should have been converted to N32");
    268             return;
    269         case kUnknown_SkColorType:
    270         default:
    271             SkDEBUGFAIL("unexpected color type");
    272     }
    273 }
    274 
    275 static void emit_image_xobject(SkWStream* stream,
    276                                const SkImage* image,
    277                                bool alpha,
    278                                const sk_sp<SkPDFObject>& smask,
    279                                const SkPDFObjNumMap& objNumMap) {
    280     SkBitmap bitmap;
    281     if (!SkPDFUtils::ToBitmap(image, &bitmap)) {
    282         // no pixels or wrong size: fill with zeros.
    283         bitmap.setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
    284     }
    285 
    286     // Write to a temporary buffer to get the compressed length.
    287     SkDynamicMemoryWStream buffer;
    288     SkDeflateWStream deflateWStream(&buffer);
    289     if (alpha) {
    290         bitmap_alpha_to_a8(bitmap, &deflateWStream);
    291     } else {
    292         bitmap_to_pdf_pixels(bitmap, &deflateWStream);
    293     }
    294     deflateWStream.finalize();  // call before buffer.bytesWritten().
    295 
    296     SkPDFDict pdfDict("XObject");
    297     pdfDict.insertName("Subtype", "Image");
    298     pdfDict.insertInt("Width", bitmap.width());
    299     pdfDict.insertInt("Height", bitmap.height());
    300     if (alpha) {
    301         pdfDict.insertName("ColorSpace", "DeviceGray");
    302     } else if (1 == pdf_color_component_count(bitmap.colorType())) {
    303         pdfDict.insertName("ColorSpace", "DeviceGray");
    304     } else {
    305         pdfDict.insertName("ColorSpace", "DeviceRGB");
    306     }
    307     if (smask) {
    308         pdfDict.insertObjRef("SMask", smask);
    309     }
    310     pdfDict.insertInt("BitsPerComponent", 8);
    311     pdfDict.insertName("Filter", "FlateDecode");
    312     pdfDict.insertInt("Length", buffer.bytesWritten());
    313     pdfDict.emitObject(stream, objNumMap);
    314 
    315     pdf_stream_begin(stream);
    316     buffer.writeToAndReset(stream);
    317     pdf_stream_end(stream);
    318 }
    319 
    320 ////////////////////////////////////////////////////////////////////////////////
    321 
    322 namespace {
    323 // This SkPDFObject only outputs the alpha layer of the given bitmap.
    324 class PDFAlphaBitmap final : public SkPDFObject {
    325 public:
    326     PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
    327     void emitObject(SkWStream*  stream,
    328                     const SkPDFObjNumMap& objNumMap) const override {
    329         SkASSERT(fImage);
    330         emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
    331     }
    332     void drop() override { fImage = nullptr; }
    333 
    334 private:
    335     sk_sp<SkImage> fImage;
    336 };
    337 
    338 }  // namespace
    339 
    340 ////////////////////////////////////////////////////////////////////////////////
    341 
    342 namespace {
    343 class PDFDefaultBitmap final : public SkPDFObject {
    344 public:
    345     void emitObject(SkWStream* stream,
    346                     const SkPDFObjNumMap& objNumMap) const override {
    347         SkASSERT(fImage);
    348         emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
    349     }
    350     void addResources(SkPDFObjNumMap* catalog) const override {
    351         catalog->addObjectRecursively(fSMask.get());
    352     }
    353     void drop() override { fImage = nullptr; fSMask = nullptr; }
    354     PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
    355         : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); }
    356 
    357 private:
    358     sk_sp<SkImage> fImage;
    359     sk_sp<SkPDFObject> fSMask;
    360 };
    361 }  // namespace
    362 
    363 ////////////////////////////////////////////////////////////////////////////////
    364 
    365 namespace {
    366 /**
    367  *  This PDFObject assumes that its constructor was handed YUV or
    368  *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
    369  *  into a PDF.
    370  */
    371 class PDFJpegBitmap final : public SkPDFObject {
    372 public:
    373     SkISize fSize;
    374     sk_sp<SkData> fData;
    375     bool fIsYUV;
    376     PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
    377         : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
    378     void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
    379     void drop() override { fData = nullptr; }
    380 };
    381 
    382 void PDFJpegBitmap::emitObject(SkWStream* stream,
    383                                const SkPDFObjNumMap& objNumMap) const {
    384     SkASSERT(fData);
    385     SkPDFDict pdfDict("XObject");
    386     pdfDict.insertName("Subtype", "Image");
    387     pdfDict.insertInt("Width", fSize.width());
    388     pdfDict.insertInt("Height", fSize.height());
    389     if (fIsYUV) {
    390         pdfDict.insertName("ColorSpace", "DeviceRGB");
    391     } else {
    392         pdfDict.insertName("ColorSpace", "DeviceGray");
    393     }
    394     pdfDict.insertInt("BitsPerComponent", 8);
    395     pdfDict.insertName("Filter", "DCTDecode");
    396     pdfDict.insertInt("ColorTransform", 0);
    397     pdfDict.insertInt("Length", SkToInt(fData->size()));
    398     pdfDict.emitObject(stream, objNumMap);
    399     pdf_stream_begin(stream);
    400     stream->write(fData->data(), fData->size());
    401     pdf_stream_end(stream);
    402 }
    403 }  // namespace
    404 
    405 ////////////////////////////////////////////////////////////////////////////////
    406 
    407 sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image,
    408                                            SkPixelSerializer* pixelSerializer) {
    409     SkASSERT(image);
    410     sk_sp<SkData> data = image->refEncodedData();
    411     SkJFIFInfo info;
    412     if (data && SkIsJFIF(data.get(), &info) &&
    413         (!pixelSerializer ||
    414          pixelSerializer->useEncodedData(data->data(), data->size()))) {
    415         // If there is a SkPixelSerializer, give it a chance to
    416         // re-encode the JPEG with more compression by returning false
    417         // from useEncodedData.
    418         bool yuv = info.fType == SkJFIFInfo::kYCbCr;
    419         if (info.fSize == image->dimensions()) {  // Sanity check.
    420             // hold on to data, not image.
    421             #ifdef SK_PDF_IMAGE_STATS
    422             gJpegImageObjects.fetch_add(1);
    423             #endif
    424             return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
    425         }
    426     }
    427 
    428     if (pixelSerializer) {
    429         SkBitmap bm;
    430         SkPixmap pmap;
    431         if (SkPDFUtils::ToBitmap(image.get(), &bm) && bm.peekPixels(&pmap)) {
    432             data = pixelSerializer->encodeToData(pmap);
    433             if (data && SkIsJFIF(data.get(), &info)) {
    434                 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
    435                 if (info.fSize == image->dimensions()) {  // Sanity check.
    436                     return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
    437                 }
    438             }
    439         }
    440     }
    441 
    442     sk_sp<SkPDFObject> smask;
    443     if (!image_compute_is_opaque(image.get())) {
    444         smask = sk_make_sp<PDFAlphaBitmap>(image);
    445     }
    446     #ifdef SK_PDF_IMAGE_STATS
    447     gRegularImageObjects.fetch_add(1);
    448     #endif
    449     return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));
    450 }
    451