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 "SkStream.h"
     16 #include "SkUnPreMultiply.h"
     17 
     18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
     19     if(as_IB(image)->getROPixels(dst)
     20        && dst->dimensions() == image->dimensions()) {
     21         if (dst->colorType() != kIndex_8_SkColorType) {
     22             return;
     23         }
     24         // We must check to see if the bitmap has a color table.
     25         SkAutoLockPixels autoLockPixels(*dst);
     26         if (!dst->getColorTable()) {
     27             // We can't use an indexed bitmap with no colortable.
     28             dst->reset();
     29         } else {
     30             return;
     31         }
     32     }
     33     // no pixels or wrong size: fill with zeros.
     34     SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
     35     dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at));
     36 }
     37 
     38 bool image_compute_is_opaque(const SkImage* image) {
     39     if (image->isOpaque()) {
     40         return true;
     41     }
     42     // keep output PDF small at cost of possible resource use.
     43     SkBitmap bm;
     44     image_get_ro_pixels(image, &bm);
     45     return SkBitmap::ComputeIsOpaque(bm);
     46 }
     47 
     48 ////////////////////////////////////////////////////////////////////////////////
     49 
     50 static void pdf_stream_begin(SkWStream* stream) {
     51     static const char streamBegin[] = " stream\n";
     52     stream->write(streamBegin, strlen(streamBegin));
     53 }
     54 
     55 static void pdf_stream_end(SkWStream* stream) {
     56     static const char streamEnd[] = "\nendstream";
     57     stream->write(streamEnd, strlen(streamEnd));
     58 }
     59 
     60 ////////////////////////////////////////////////////////////////////////////////
     61 
     62 // write a single byte to a stream n times.
     63 static void fill_stream(SkWStream* out, char value, size_t n) {
     64     char buffer[4096];
     65     memset(buffer, value, sizeof(buffer));
     66     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
     67         out->write(buffer, sizeof(buffer));
     68     }
     69     out->write(buffer, n % sizeof(buffer));
     70 }
     71 
     72 // TODO(reed@): Decide if these five functions belong in SkColorPriv.h
     73 static bool SkIsBGRA(SkColorType ct) {
     74     SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
     75     return kBGRA_8888_SkColorType == ct;
     76 }
     77 
     78 // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
     79 // RGBA_8888) and return the appropriate component.  Each component
     80 // should be interpreted according to the associated SkAlphaType and
     81 // SkColorProfileType.
     82 static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
     83     return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
     84 }
     85 static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
     86     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
     87 }
     88 static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
     89     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
     90 }
     91 static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
     92     return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
     93 }
     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     switch (colorType) {
    187         case kRGBA_8888_SkColorType:
    188         case kBGRA_8888_SkColorType: {
    189             SkASSERT(3 == pdf_color_component_count(colorType));
    190             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    191             for (int y = 0; y < bm.height(); ++y) {
    192                 const uint32_t* src = bm.getAddr32(0, y);
    193                 uint8_t* dst = scanline.get();
    194                 for (int x = 0; x < bm.width(); ++x) {
    195                     uint32_t color = *src++;
    196                     U8CPU alpha = SkGetA32Component(color, colorType);
    197                     if (alpha != SK_AlphaTRANSPARENT) {
    198                         pmcolor_to_rgb24(color, dst, colorType);
    199                     } else {
    200                         get_neighbor_avg_color(bm, x, y, dst, colorType);
    201                     }
    202                     dst += 3;
    203                 }
    204                 out->write(scanline.get(), 3 * bm.width());
    205             }
    206             return;
    207         }
    208         case kRGB_565_SkColorType: {
    209             SkASSERT(3 == pdf_color_component_count(colorType));
    210             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    211             for (int y = 0; y < bm.height(); ++y) {
    212                 const uint16_t* src = bm.getAddr16(0, y);
    213                 uint8_t* dst = scanline.get();
    214                 for (int x = 0; x < bm.width(); ++x) {
    215                     U16CPU color565 = *src++;
    216                     *dst++ = SkPacked16ToR32(color565);
    217                     *dst++ = SkPacked16ToG32(color565);
    218                     *dst++ = SkPacked16ToB32(color565);
    219                 }
    220                 out->write(scanline.get(), 3 * bm.width());
    221             }
    222             return;
    223         }
    224         case kAlpha_8_SkColorType:
    225             SkASSERT(1 == pdf_color_component_count(colorType));
    226             fill_stream(out, '\x00', pixel_count(bm));
    227             return;
    228         case kGray_8_SkColorType:
    229         case kIndex_8_SkColorType:
    230             SkASSERT(1 == pdf_color_component_count(colorType));
    231             // these two formats need no transformation to serialize.
    232             for (int y = 0; y < bm.height(); ++y) {
    233                 out->write(bm.getAddr8(0, y), bm.width());
    234             }
    235             return;
    236         case kUnknown_SkColorType:
    237         case kARGB_4444_SkColorType:
    238         default:
    239             SkDEBUGFAIL("unexpected color type");
    240     }
    241 }
    242 
    243 ////////////////////////////////////////////////////////////////////////////////
    244 
    245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
    246     if (!bitmap.getPixels()) {
    247         fill_stream(out, '\xFF', pixel_count(bitmap));
    248         return;
    249     }
    250     SkBitmap copy;
    251     const SkBitmap& bm = not4444(bitmap, &copy);
    252     SkAutoLockPixels autoLockPixels(bm);
    253     SkColorType colorType = bm.colorType();
    254     switch (colorType) {
    255         case kRGBA_8888_SkColorType:
    256         case kBGRA_8888_SkColorType: {
    257             SkAutoTMalloc<uint8_t> scanline(bm.width());
    258             for (int y = 0; y < bm.height(); ++y) {
    259                 uint8_t* dst = scanline.get();
    260                 const SkPMColor* src = bm.getAddr32(0, y);
    261                 for (int x = 0; x < bm.width(); ++x) {
    262                     *dst++ = SkGetA32Component(*src++, colorType);
    263                 }
    264                 out->write(scanline.get(), bm.width());
    265             }
    266             return;
    267         }
    268         case kAlpha_8_SkColorType:
    269             for (int y = 0; y < bm.height(); ++y) {
    270                 out->write(bm.getAddr8(0, y), bm.width());
    271             }
    272             return;
    273         case kIndex_8_SkColorType: {
    274             SkColorTable* ct = bm.getColorTable();
    275             SkASSERT(ct);
    276             SkAutoTMalloc<uint8_t> scanline(bm.width());
    277             for (int y = 0; y < bm.height(); ++y) {
    278                 uint8_t* dst = scanline.get();
    279                 const uint8_t* src = bm.getAddr8(0, y);
    280                 for (int x = 0; x < bm.width(); ++x) {
    281                     *dst++ = SkGetPackedA32((*ct)[*src++]);
    282                 }
    283                 out->write(scanline.get(), bm.width());
    284             }
    285             return;
    286         }
    287         case kRGB_565_SkColorType:
    288         case kGray_8_SkColorType:
    289             SkDEBUGFAIL("color type has no alpha");
    290             return;
    291         case kARGB_4444_SkColorType:
    292             SkDEBUGFAIL("4444 color type should have been converted to N32");
    293             return;
    294         case kUnknown_SkColorType:
    295         default:
    296             SkDEBUGFAIL("unexpected color type");
    297     }
    298 }
    299 
    300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
    301     SkPDFArray* result = new SkPDFArray;
    302     result->reserve(4);
    303     result->appendName("Indexed");
    304     result->appendName("DeviceRGB");
    305     SkASSERT(table);
    306     if (table->count() < 1) {
    307         result->appendInt(0);
    308         char shortTableArray[3] = {0, 0, 0};
    309         SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
    310         result->appendString(tableString);
    311         return result;
    312     }
    313     result->appendInt(table->count() - 1);  // maximum color index.
    314 
    315     // Potentially, this could be represented in fewer bytes with a stream.
    316     // Max size as a string is 1.5k.
    317     char tableArray[256 * 3];
    318     SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
    319     uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
    320     const SkPMColor* colors = table->readColors();
    321     for (int i = 0; i < table->count(); i++) {
    322         pmcolor_to_rgb24(colors[i], tablePtr, kN32_SkColorType);
    323         tablePtr += 3;
    324     }
    325     SkString tableString(tableArray, 3 * table->count());
    326     result->appendString(tableString);
    327     return result;
    328 }
    329 
    330 static void emit_image_xobject(SkWStream* stream,
    331                                const SkImage* image,
    332                                bool alpha,
    333                                SkPDFObject* smask,
    334                                const SkPDFObjNumMap& objNumMap,
    335                                const SkPDFSubstituteMap& substitutes) {
    336     SkBitmap bitmap;
    337     image_get_ro_pixels(image, &bitmap);      // TODO(halcanary): test
    338     SkAutoLockPixels autoLockPixels(bitmap);  // with malformed images.
    339 
    340     // Write to a temporary buffer to get the compressed length.
    341     SkDynamicMemoryWStream buffer;
    342     SkDeflateWStream deflateWStream(&buffer);
    343     if (alpha) {
    344         bitmap_alpha_to_a8(bitmap, &deflateWStream);
    345     } else {
    346         bitmap_to_pdf_pixels(bitmap, &deflateWStream);
    347     }
    348     deflateWStream.finalize();  // call before detachAsStream().
    349     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
    350 
    351     SkPDFDict pdfDict("XObject");
    352     pdfDict.insertName("Subtype", "Image");
    353     pdfDict.insertInt("Width", bitmap.width());
    354     pdfDict.insertInt("Height", bitmap.height());
    355     if (alpha) {
    356         pdfDict.insertName("ColorSpace", "DeviceGray");
    357     } else if (bitmap.colorType() == kIndex_8_SkColorType) {
    358         SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
    359         pdfDict.insertObject("ColorSpace",
    360                              make_indexed_color_space(bitmap.getColorTable()));
    361     } else if (1 == pdf_color_component_count(bitmap.colorType())) {
    362         pdfDict.insertName("ColorSpace", "DeviceGray");
    363     } else {
    364         pdfDict.insertName("ColorSpace", "DeviceRGB");
    365     }
    366     if (smask) {
    367         pdfDict.insertObjRef("SMask", SkRef(smask));
    368     }
    369     pdfDict.insertInt("BitsPerComponent", 8);
    370     pdfDict.insertName("Filter", "FlateDecode");
    371     pdfDict.insertInt("Length", asset->getLength());
    372     pdfDict.emitObject(stream, objNumMap, substitutes);
    373 
    374     pdf_stream_begin(stream);
    375     stream->writeStream(asset.get(), asset->getLength());
    376     pdf_stream_end(stream);
    377 }
    378 
    379 ////////////////////////////////////////////////////////////////////////////////
    380 
    381 namespace {
    382 // This SkPDFObject only outputs the alpha layer of the given bitmap.
    383 class PDFAlphaBitmap final : public SkPDFObject {
    384 public:
    385     PDFAlphaBitmap(const SkImage* image) : fImage(SkRef(image)) {}
    386     ~PDFAlphaBitmap() {}
    387     void emitObject(SkWStream*  stream,
    388                     const SkPDFObjNumMap& objNumMap,
    389                     const SkPDFSubstituteMap& subs) const override {
    390         emit_image_xobject(stream, fImage, true, nullptr, objNumMap, subs);
    391     }
    392 
    393 private:
    394     SkAutoTUnref<const SkImage> fImage;
    395 };
    396 
    397 }  // namespace
    398 
    399 ////////////////////////////////////////////////////////////////////////////////
    400 
    401 namespace {
    402 class PDFDefaultBitmap final : public SkPDFObject {
    403 public:
    404     void emitObject(SkWStream* stream,
    405                     const SkPDFObjNumMap& objNumMap,
    406                     const SkPDFSubstituteMap& subs) const override {
    407         emit_image_xobject(stream, fImage, false, fSMask, objNumMap, subs);
    408     }
    409     void addResources(SkPDFObjNumMap* catalog,
    410                       const SkPDFSubstituteMap& subs) const override {
    411         if (fSMask.get()) {
    412             SkPDFObject* obj = subs.getSubstitute(fSMask.get());
    413             SkASSERT(obj);
    414             catalog->addObjectRecursively(obj, subs);
    415         }
    416     }
    417     PDFDefaultBitmap(const SkImage* image, SkPDFObject* smask)
    418         : fImage(SkRef(image)), fSMask(smask) {}
    419 
    420 private:
    421     SkAutoTUnref<const SkImage> fImage;
    422     const SkAutoTUnref<SkPDFObject> fSMask;
    423 };
    424 }  // namespace
    425 
    426 ////////////////////////////////////////////////////////////////////////////////
    427 
    428 namespace {
    429 /**
    430  *  This PDFObject assumes that its constructor was handed YUV or
    431  *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
    432  *  into a PDF.
    433  */
    434 class PDFJpegBitmap final : public SkPDFObject {
    435 public:
    436     SkISize fSize;
    437     SkAutoTUnref<SkData> fData;
    438     bool fIsYUV;
    439     PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
    440         : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) {}
    441     void emitObject(SkWStream*,
    442                     const SkPDFObjNumMap&,
    443                     const SkPDFSubstituteMap&) const override;
    444 };
    445 
    446 void PDFJpegBitmap::emitObject(SkWStream* stream,
    447                                const SkPDFObjNumMap& objNumMap,
    448                                const SkPDFSubstituteMap& substituteMap) const {
    449     SkPDFDict pdfDict("XObject");
    450     pdfDict.insertName("Subtype", "Image");
    451     pdfDict.insertInt("Width", fSize.width());
    452     pdfDict.insertInt("Height", fSize.height());
    453     if (fIsYUV) {
    454         pdfDict.insertName("ColorSpace", "DeviceRGB");
    455     } else {
    456         pdfDict.insertName("ColorSpace", "DeviceGray");
    457     }
    458     pdfDict.insertInt("BitsPerComponent", 8);
    459     pdfDict.insertName("Filter", "DCTDecode");
    460     pdfDict.insertInt("ColorTransform", 0);
    461     pdfDict.insertInt("Length", SkToInt(fData->size()));
    462     pdfDict.emitObject(stream, objNumMap, substituteMap);
    463     pdf_stream_begin(stream);
    464     stream->write(fData->data(), fData->size());
    465     pdf_stream_end(stream);
    466 }
    467 }  // namespace
    468 
    469 ////////////////////////////////////////////////////////////////////////////////
    470 
    471 SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image,
    472                                      SkPixelSerializer* pixelSerializer) {
    473     SkAutoTUnref<SkData> data(image->refEncoded());
    474     SkJFIFInfo info;
    475     if (data && SkIsJFIF(data, &info) &&
    476         (!pixelSerializer ||
    477          pixelSerializer->useEncodedData(data->data(), data->size()))) {
    478         // If there is a SkPixelSerializer, give it a chance to
    479         // re-encode the JPEG with more compression by returning false
    480         // from useEncodedData.
    481         bool yuv = info.fType == SkJFIFInfo::kYCbCr;
    482         if (info.fSize == image->dimensions()) {  // Sanity check.
    483             // hold on to data, not image.
    484             #ifdef SK_PDF_IMAGE_STATS
    485             gJpegImageObjects.fetch_add(1);
    486             #endif
    487             return new PDFJpegBitmap(info.fSize, data, yuv);
    488         }
    489     }
    490 
    491     if (pixelSerializer) {
    492         SkBitmap bm;
    493         SkAutoPixmapUnlock apu;
    494         if (as_IB(image)->getROPixels(&bm) && bm.requestLock(&apu)) {
    495             data.reset(pixelSerializer->encode(apu.pixmap()));
    496             if (data && SkIsJFIF(data, &info)) {
    497                 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
    498                 if (info.fSize == image->dimensions()) {  // Sanity check.
    499                     return new PDFJpegBitmap(info.fSize, data, yuv);
    500                 }
    501             }
    502         }
    503     }
    504 
    505     SkPDFObject* smask =
    506             image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image);
    507     #ifdef SK_PDF_IMAGE_STATS
    508     gRegularImageObjects.fetch_add(1);
    509     #endif
    510     return new PDFDefaultBitmap(image, smask);
    511 }
    512