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 "SkColorPriv.h"
      9 #include "SkData.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"
     16 #include "SkStream.h"
     17 #include "SkUnPreMultiply.h"
     18 
     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) {
     24             return;
     25         }
     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.
     30             dst->reset();
     31         } else {
     32             return;
     33         }
     34     }
     35     // no pixels or wrong size: fill with zeros.
     36     dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
     37 }
     38 
     39 bool image_compute_is_opaque(const SkImage* image) {
     40     if (image->isOpaque()) {
     41         return true;
     42     }
     43     // keep output PDF small at cost of possible resource use.
     44     SkBitmap bm;
     45     image_get_ro_pixels(image, &bm);
     46     return SkBitmap::ComputeIsOpaque(bm);
     47 }
     48 
     49 ////////////////////////////////////////////////////////////////////////////////
     50 
     51 static void pdf_stream_begin(SkWStream* stream) {
     52     static const char streamBegin[] = " stream\n";
     53     stream->write(streamBegin, strlen(streamBegin));
     54 }
     55 
     56 static void pdf_stream_end(SkWStream* stream) {
     57     static const char streamEnd[] = "\nendstream";
     58     stream->write(streamEnd, strlen(streamEnd));
     59 }
     60 
     61 ////////////////////////////////////////////////////////////////////////////////
     62 
     63 // write a single byte to a stream n times.
     64 static void fill_stream(SkWStream* out, char value, size_t n) {
     65     char buffer[4096];
     66     memset(buffer, value, sizeof(buffer));
     67     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
     68         out->write(buffer, sizeof(buffer));
     69     }
     70     out->write(buffer, n % sizeof(buffer));
     71 }
     72 
     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;
     77 }
     78 
     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;
     85 }
     86 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
     87     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
     88 }
     89 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
     90     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
     91 }
     92 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
     93     return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
     94 }
     95 
     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));
    102 }
    103 
    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,
    114                                    int xOrig,
    115                                    int yOrig,
    116                                    uint8_t rgb[3],
    117                                    SkColorType ct) {
    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);
    132         }
    133     }
    134     if (a > 0) {
    135         rgb[0] = SkToU8(255 * r / a);
    136         rgb[1] = SkToU8(255 * g / a);
    137         rgb[2] = SkToU8(255 * b / a);
    138     } else {
    139         rgb[0] = rgb[1] = rgb[2] = 0;
    140     }
    141 }
    142 
    143 static size_t pixel_count(const SkBitmap& bm) {
    144     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
    145 }
    146 
    147 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
    148     if (input.colorType() != kARGB_4444_SkColorType) {
    149         return input;
    150     }
    151     // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
    152     SkAssertResult(input.copyTo(copy, kN32_SkColorType));
    153     copy->setImmutable();
    154     return *copy;
    155 }
    156 
    157 static size_t pdf_color_component_count(SkColorType ct) {
    158     switch (ct) {
    159         case kRGB_565_SkColorType:
    160         case kARGB_4444_SkColorType:
    161         case kRGBA_8888_SkColorType:
    162         case kBGRA_8888_SkColorType:
    163             return 3;
    164         case kAlpha_8_SkColorType:
    165         case kIndex_8_SkColorType:
    166         case kGray_8_SkColorType:
    167             return 1;
    168         case kUnknown_SkColorType:
    169         default:
    170             SkDEBUGFAIL("unexpected color type");
    171             return 0;
    172     }
    173 }
    174 
    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);
    180         return;
    181     }
    182     SkBitmap copy;
    183     const SkBitmap& bm = not4444(bitmap, &copy);
    184     SkAutoLockPixels autoLockPixels(bm);
    185     SkColorType colorType = bm.colorType();
    186     SkAlphaType alphaType = bm.alphaType();
    187     switch (colorType) {
    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);
    201                         } else {
    202                             get_neighbor_avg_color(bm, x, y, dst, colorType);
    203                         }
    204                         dst += 3;
    205                     } else {
    206                         uint32_t color = *src++;
    207                         *dst++ = SkGetR32Component(color, colorType);
    208                         *dst++ = SkGetG32Component(color, colorType);
    209                         *dst++ = SkGetB32Component(color, colorType);
    210                     }
    211                 }
    212                 out->write(scanline.get(), 3 * bm.width());
    213             }
    214             return;
    215         }
    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);
    227                 }
    228                 out->write(scanline.get(), 3 * bm.width());
    229             }
    230             return;
    231         }
    232         case kAlpha_8_SkColorType:
    233             SkASSERT(1 == pdf_color_component_count(colorType));
    234             fill_stream(out, '\x00', pixel_count(bm));
    235             return;
    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());
    242             }
    243             return;
    244         case kUnknown_SkColorType:
    245         case kARGB_4444_SkColorType:
    246         default:
    247             SkDEBUGFAIL("unexpected color type");
    248     }
    249 }
    250 
    251 ////////////////////////////////////////////////////////////////////////////////
    252 
    253 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
    254     if (!bitmap.getPixels()) {
    255         fill_stream(out, '\xFF', pixel_count(bitmap));
    256         return;
    257     }
    258     SkBitmap copy;
    259     const SkBitmap& bm = not4444(bitmap, &copy);
    260     SkAutoLockPixels autoLockPixels(bm);
    261     SkColorType colorType = bm.colorType();
    262     switch (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);
    271                 }
    272                 out->write(scanline.get(), bm.width());
    273             }
    274             return;
    275         }
    276         case kAlpha_8_SkColorType:
    277             for (int y = 0; y < bm.height(); ++y) {
    278                 out->write(bm.getAddr8(0, y), bm.width());
    279             }
    280             return;
    281         case kIndex_8_SkColorType: {
    282             SkColorTable* ct = bm.getColorTable();
    283             SkASSERT(ct);
    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++]);
    290                 }
    291                 out->write(scanline.get(), bm.width());
    292             }
    293             return;
    294         }
    295         case kRGB_565_SkColorType:
    296         case kGray_8_SkColorType:
    297             SkDEBUGFAIL("color type has no alpha");
    298             return;
    299         case kARGB_4444_SkColorType:
    300             SkDEBUGFAIL("4444 color type should have been converted to N32");
    301             return;
    302         case kUnknown_SkColorType:
    303         default:
    304             SkDEBUGFAIL("unexpected color type");
    305     }
    306 }
    307 
    308 static sk_sp<SkPDFArray> make_indexed_color_space(
    309         const SkColorTable* table,
    310         SkAlphaType alphaType) {
    311     auto result = sk_make_sp<SkPDFArray>();
    312     result->reserve(4);
    313     result->appendName("Indexed");
    314     result->appendName("DeviceRGB");
    315     SkASSERT(table);
    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);
    321         return result;
    322     }
    323     result->appendInt(table->count() - 1);  // maximum color index.
    324 
    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);
    334             tablePtr += 3;
    335         } else {
    336             *tablePtr++ = SkGetR32Component(colors[i], kN32_SkColorType);
    337             *tablePtr++ = SkGetG32Component(colors[i], kN32_SkColorType);
    338             *tablePtr++ = SkGetB32Component(colors[i], kN32_SkColorType);
    339         }
    340     }
    341     SkString tableString(tableArray, 3 * table->count());
    342     result->appendString(tableString);
    343     return result;
    344 }
    345 
    346 static void emit_image_xobject(SkWStream* stream,
    347                                const SkImage* image,
    348                                bool alpha,
    349                                const sk_sp<SkPDFObject>& smask,
    350                                const SkPDFObjNumMap& objNumMap) {
    351     SkBitmap bitmap;
    352     image_get_ro_pixels(image, &bitmap);      // TODO(halcanary): test
    353     SkAutoLockPixels autoLockPixels(bitmap);  // with malformed images.
    354 
    355     // Write to a temporary buffer to get the compressed length.
    356     SkDynamicMemoryWStream buffer;
    357     SkDeflateWStream deflateWStream(&buffer);
    358     if (alpha) {
    359         bitmap_alpha_to_a8(bitmap, &deflateWStream);
    360     } else {
    361         bitmap_to_pdf_pixels(bitmap, &deflateWStream);
    362     }
    363     deflateWStream.finalize();  // call before detachAsStream().
    364     std::unique_ptr<SkStreamAsset> asset(buffer.detachAsStream());
    365 
    366     SkPDFDict pdfDict("XObject");
    367     pdfDict.insertName("Subtype", "Image");
    368     pdfDict.insertInt("Width", bitmap.width());
    369     pdfDict.insertInt("Height", bitmap.height());
    370     if (alpha) {
    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");
    379     } else {
    380         pdfDict.insertName("ColorSpace", "DeviceRGB");
    381     }
    382     if (smask) {
    383         pdfDict.insertObjRef("SMask", smask);
    384     }
    385     pdfDict.insertInt("BitsPerComponent", 8);
    386     pdfDict.insertName("Filter", "FlateDecode");
    387     pdfDict.insertInt("Length", asset->getLength());
    388     pdfDict.emitObject(stream, objNumMap);
    389 
    390     pdf_stream_begin(stream);
    391     stream->writeStream(asset.get(), asset->getLength());
    392     pdf_stream_end(stream);
    393 }
    394 
    395 ////////////////////////////////////////////////////////////////////////////////
    396 
    397 namespace {
    398 // This SkPDFObject only outputs the alpha layer of the given bitmap.
    399 class PDFAlphaBitmap final : public SkPDFObject {
    400 public:
    401     PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
    402     void emitObject(SkWStream*  stream,
    403                     const SkPDFObjNumMap& objNumMap) const override {
    404         SkASSERT(fImage);
    405         emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
    406     }
    407     void drop() override { fImage = nullptr; }
    408 
    409 private:
    410     sk_sp<SkImage> fImage;
    411 };
    412 
    413 }  // namespace
    414 
    415 ////////////////////////////////////////////////////////////////////////////////
    416 
    417 namespace {
    418 class PDFDefaultBitmap final : public SkPDFObject {
    419 public:
    420     void emitObject(SkWStream* stream,
    421                     const SkPDFObjNumMap& objNumMap) const override {
    422         SkASSERT(fImage);
    423         emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
    424     }
    425     void addResources(SkPDFObjNumMap* catalog) const override {
    426         catalog->addObjectRecursively(fSMask.get());
    427     }
    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); }
    431 
    432 private:
    433     sk_sp<SkImage> fImage;
    434     sk_sp<SkPDFObject> fSMask;
    435 };
    436 }  // namespace
    437 
    438 ////////////////////////////////////////////////////////////////////////////////
    439 
    440 namespace {
    441 /**
    442  *  This PDFObject assumes that its constructor was handed YUV or
    443  *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
    444  *  into a PDF.
    445  */
    446 class PDFJpegBitmap final : public SkPDFObject {
    447 public:
    448     SkISize fSize;
    449     sk_sp<SkData> fData;
    450     bool fIsYUV;
    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; }
    455 };
    456 
    457 void PDFJpegBitmap::emitObject(SkWStream* stream,
    458                                const SkPDFObjNumMap& objNumMap) const {
    459     SkASSERT(fData);
    460     SkPDFDict pdfDict("XObject");
    461     pdfDict.insertName("Subtype", "Image");
    462     pdfDict.insertInt("Width", fSize.width());
    463     pdfDict.insertInt("Height", fSize.height());
    464     if (fIsYUV) {
    465         pdfDict.insertName("ColorSpace", "DeviceRGB");
    466     } else {
    467         pdfDict.insertName("ColorSpace", "DeviceGray");
    468     }
    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);
    477 }
    478 }  // namespace
    479 
    480 ////////////////////////////////////////////////////////////////////////////////
    481 
    482 sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image,
    483                                            SkPixelSerializer* pixelSerializer) {
    484     SkASSERT(image);
    485     sk_sp<SkData> data(image->refEncoded());
    486     SkJFIFInfo info;
    487     if (data && SkIsJFIF(data.get(), &info) &&
    488         (!pixelSerializer ||
    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);
    498             #endif
    499             return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
    500         }
    501     }
    502 
    503     if (pixelSerializer) {
    504         SkBitmap bm;
    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);
    514                 }
    515             }
    516         }
    517     }
    518 
    519     sk_sp<SkPDFObject> smask;
    520     if (!image_compute_is_opaque(image.get())) {
    521         smask = sk_make_sp<PDFAlphaBitmap>(image);
    522     }
    523     #ifdef SK_PDF_IMAGE_STATS
    524     gRegularImageObjects.fetch_add(1);
    525     #endif
    526     return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));
    527 }
    528