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 "SkFlate.h"
     11 #include "SkImageGenerator.h"
     12 #include "SkJpegInfo.h"
     13 #include "SkPDFBitmap.h"
     14 #include "SkPDFCanon.h"
     15 #include "SkPixelRef.h"
     16 #include "SkStream.h"
     17 #include "SkUnPreMultiply.h"
     18 
     19 ////////////////////////////////////////////////////////////////////////////////
     20 
     21 static void pdf_stream_begin(SkWStream* stream) {
     22     static const char streamBegin[] = " stream\n";
     23     stream->write(streamBegin, strlen(streamBegin));
     24 }
     25 
     26 static void pdf_stream_end(SkWStream* stream) {
     27     static const char streamEnd[] = "\nendstream";
     28     stream->write(streamEnd, strlen(streamEnd));
     29 }
     30 
     31 ////////////////////////////////////////////////////////////////////////////////
     32 
     33 // write a single byte to a stream n times.
     34 static void fill_stream(SkWStream* out, char value, size_t n) {
     35     char buffer[4096];
     36     memset(buffer, value, sizeof(buffer));
     37     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
     38         out->write(buffer, sizeof(buffer));
     39     }
     40     out->write(buffer, n % sizeof(buffer));
     41 }
     42 
     43 // unpremultiply and extract R, G, B components.
     44 static void pmcolor_to_rgb24(SkPMColor pmColor, uint8_t* rgb) {
     45     uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
     46     rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
     47     rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
     48     rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
     49 }
     50 
     51 /* It is necessary to average the color component of transparent
     52    pixels with their surrounding neighbors since the PDF renderer may
     53    separately re-sample the alpha and color channels when the image is
     54    not displayed at its native resolution. Since an alpha of zero
     55    gives no information about the color component, the pathological
     56    case is a white image with sharp transparency bounds - the color
     57    channel goes to black, and the should-be-transparent pixels are
     58    rendered as grey because of the separate soft mask and color
     59    resizing. e.g.: gm/bitmappremul.cpp */
     60 static void get_neighbor_avg_color(const SkBitmap& bm,
     61                                    int xOrig,
     62                                    int yOrig,
     63                                    uint8_t rgb[3]) {
     64     SkASSERT(kN32_SkColorType == bm.colorType());
     65     unsigned a = 0, r = 0, g = 0, b = 0;
     66     // Clamp the range to the edge of the bitmap.
     67     int ymin = SkTMax(0, yOrig - 1);
     68     int ymax = SkTMin(yOrig + 1, bm.height() - 1);
     69     int xmin = SkTMax(0, xOrig - 1);
     70     int xmax = SkTMin(xOrig + 1, bm.width() - 1);
     71     for (int y = ymin; y <= ymax; ++y) {
     72         SkPMColor* scanline = bm.getAddr32(0, y);
     73         for (int x = xmin; x <= xmax; ++x) {
     74             SkPMColor pmColor = scanline[x];
     75             a += SkGetPackedA32(pmColor);
     76             r += SkGetPackedR32(pmColor);
     77             g += SkGetPackedG32(pmColor);
     78             b += SkGetPackedB32(pmColor);
     79         }
     80     }
     81     if (a > 0) {
     82         rgb[0] = SkToU8(255 * r / a);
     83         rgb[1] = SkToU8(255 * g / a);
     84         rgb[2] = SkToU8(255 * b / a);
     85     } else {
     86         rgb[0] = rgb[1] = rgb[2] = 0;
     87     }
     88 }
     89 
     90 static size_t pixel_count(const SkBitmap& bm) {
     91     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
     92 }
     93 
     94 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
     95     if (input.colorType() != kARGB_4444_SkColorType) {
     96         return input;
     97     }
     98     // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
     99     SkAssertResult(input.copyTo(copy, kN32_SkColorType));
    100     copy->setImmutable();
    101     return *copy;
    102 }
    103 
    104 static size_t pdf_color_component_count(SkColorType ct) {
    105     switch (ct) {
    106         case kN32_SkColorType:
    107         case kRGB_565_SkColorType:
    108         case kARGB_4444_SkColorType:
    109             return 3;
    110         case kAlpha_8_SkColorType:
    111         case kIndex_8_SkColorType:
    112         case kGray_8_SkColorType:
    113             return 1;
    114         case kUnknown_SkColorType:
    115         default:
    116             SkDEBUGFAIL("unexpected color type");
    117             return 0;
    118     }
    119 }
    120 
    121 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
    122     if (!bitmap.getPixels()) {
    123         size_t size = pixel_count(bitmap) *
    124                       pdf_color_component_count(bitmap.colorType());
    125         fill_stream(out, '\x00', size);
    126         return;
    127     }
    128     SkBitmap copy;
    129     const SkBitmap& bm = not4444(bitmap, &copy);
    130     SkAutoLockPixels autoLockPixels(bm);
    131     switch (bm.colorType()) {
    132         case kN32_SkColorType: {
    133             SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
    134             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    135             for (int y = 0; y < bm.height(); ++y) {
    136                 const SkPMColor* src = bm.getAddr32(0, y);
    137                 uint8_t* dst = scanline.get();
    138                 for (int x = 0; x < bm.width(); ++x) {
    139                     SkPMColor color = *src++;
    140                     U8CPU alpha = SkGetPackedA32(color);
    141                     if (alpha != SK_AlphaTRANSPARENT) {
    142                         pmcolor_to_rgb24(color, dst);
    143                     } else {
    144                         get_neighbor_avg_color(bm, x, y, dst);
    145                     }
    146                     dst += 3;
    147                 }
    148                 out->write(scanline.get(), 3 * bm.width());
    149             }
    150             return;
    151         }
    152         case kRGB_565_SkColorType: {
    153             SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
    154             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
    155             for (int y = 0; y < bm.height(); ++y) {
    156                 const uint16_t* src = bm.getAddr16(0, y);
    157                 uint8_t* dst = scanline.get();
    158                 for (int x = 0; x < bm.width(); ++x) {
    159                     U16CPU color565 = *src++;
    160                     *dst++ = SkPacked16ToR32(color565);
    161                     *dst++ = SkPacked16ToG32(color565);
    162                     *dst++ = SkPacked16ToB32(color565);
    163                 }
    164                 out->write(scanline.get(), 3 * bm.width());
    165             }
    166             return;
    167         }
    168         case kAlpha_8_SkColorType:
    169             SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
    170             fill_stream(out, '\x00', pixel_count(bm));
    171             return;
    172         case kGray_8_SkColorType:
    173         case kIndex_8_SkColorType:
    174             SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
    175             // these two formats need no transformation to serialize.
    176             for (int y = 0; y < bm.height(); ++y) {
    177                 out->write(bm.getAddr8(0, y), bm.width());
    178             }
    179             return;
    180         case kUnknown_SkColorType:
    181         case kARGB_4444_SkColorType:
    182         default:
    183             SkDEBUGFAIL("unexpected color type");
    184     }
    185 }
    186 
    187 ////////////////////////////////////////////////////////////////////////////////
    188 
    189 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
    190     if (!bitmap.getPixels()) {
    191         fill_stream(out, '\xFF', pixel_count(bitmap));
    192         return;
    193     }
    194     SkBitmap copy;
    195     const SkBitmap& bm = not4444(bitmap, &copy);
    196     SkAutoLockPixels autoLockPixels(bm);
    197     switch (bm.colorType()) {
    198         case kN32_SkColorType: {
    199             SkAutoTMalloc<uint8_t> scanline(bm.width());
    200             for (int y = 0; y < bm.height(); ++y) {
    201                 uint8_t* dst = scanline.get();
    202                 const SkPMColor* src = bm.getAddr32(0, y);
    203                 for (int x = 0; x < bm.width(); ++x) {
    204                     *dst++ = SkGetPackedA32(*src++);
    205                 }
    206                 out->write(scanline.get(), bm.width());
    207             }
    208             return;
    209         }
    210         case kAlpha_8_SkColorType:
    211             for (int y = 0; y < bm.height(); ++y) {
    212                 out->write(bm.getAddr8(0, y), bm.width());
    213             }
    214             return;
    215         case kIndex_8_SkColorType: {
    216             SkColorTable* ct = bm.getColorTable();
    217             SkASSERT(ct);
    218             SkAutoTMalloc<uint8_t> scanline(bm.width());
    219             for (int y = 0; y < bm.height(); ++y) {
    220                 uint8_t* dst = scanline.get();
    221                 const uint8_t* src = bm.getAddr8(0, y);
    222                 for (int x = 0; x < bm.width(); ++x) {
    223                     *dst++ = SkGetPackedA32((*ct)[*src++]);
    224                 }
    225                 out->write(scanline.get(), bm.width());
    226             }
    227             return;
    228         }
    229         case kRGB_565_SkColorType:
    230         case kGray_8_SkColorType:
    231             SkDEBUGFAIL("color type has no alpha");
    232             return;
    233         case kARGB_4444_SkColorType:
    234             SkDEBUGFAIL("4444 color type should have been converted to N32");
    235             return;
    236         case kUnknown_SkColorType:
    237         default:
    238             SkDEBUGFAIL("unexpected color type");
    239     }
    240 }
    241 
    242 ////////////////////////////////////////////////////////////////////////////////
    243 
    244 namespace {
    245 // This SkPDFObject only outputs the alpha layer of the given bitmap.
    246 class PDFAlphaBitmap : public SkPDFObject {
    247 public:
    248     PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
    249     ~PDFAlphaBitmap() {}
    250     void emitObject(SkWStream*,
    251                     const SkPDFObjNumMap&,
    252                     const SkPDFSubstituteMap&) override;
    253 
    254 private:
    255     const SkBitmap fBitmap;
    256 };
    257 
    258 void PDFAlphaBitmap::emitObject(SkWStream* stream,
    259                                 const SkPDFObjNumMap& objNumMap,
    260                                 const SkPDFSubstituteMap& substitutes) {
    261     SkAutoLockPixels autoLockPixels(fBitmap);
    262     SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
    263              fBitmap.getColorTable());
    264 
    265     // Write to a temporary buffer to get the compressed length.
    266     SkDynamicMemoryWStream buffer;
    267     SkDeflateWStream deflateWStream(&buffer);
    268     bitmap_alpha_to_a8(fBitmap, &deflateWStream);
    269     deflateWStream.finalize();  // call before detachAsStream().
    270     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
    271 
    272     SkPDFDict pdfDict("XObject");
    273     pdfDict.insertName("Subtype", "Image");
    274     pdfDict.insertInt("Width", fBitmap.width());
    275     pdfDict.insertInt("Height", fBitmap.height());
    276     pdfDict.insertName("ColorSpace", "DeviceGray");
    277     pdfDict.insertInt("BitsPerComponent", 8);
    278     pdfDict.insertName("Filter", "FlateDecode");
    279     pdfDict.insertInt("Length", asset->getLength());
    280     pdfDict.emitObject(stream, objNumMap, substitutes);
    281 
    282     pdf_stream_begin(stream);
    283     stream->writeStream(asset.get(), asset->getLength());
    284     pdf_stream_end(stream);
    285 }
    286 }  // namespace
    287 
    288 ////////////////////////////////////////////////////////////////////////////////
    289 
    290 namespace {
    291 class PDFDefaultBitmap : public SkPDFBitmap {
    292 public:
    293     const SkAutoTUnref<SkPDFObject> fSMask;
    294     void emitObject(SkWStream*,
    295                     const SkPDFObjNumMap&,
    296                     const SkPDFSubstituteMap&) override;
    297     void addResources(SkPDFObjNumMap*,
    298                       const SkPDFSubstituteMap&) const override;
    299     PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask)
    300         : SkPDFBitmap(bm), fSMask(smask) {}
    301 };
    302 }  // namespace
    303 
    304 void PDFDefaultBitmap::addResources(
    305         SkPDFObjNumMap* catalog,
    306         const SkPDFSubstituteMap& substitutes) const {
    307     if (fSMask.get()) {
    308         SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
    309         SkASSERT(obj);
    310         if (catalog->addObject(obj)) {
    311             obj->addResources(catalog, substitutes);
    312         }
    313     }
    314 }
    315 
    316 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
    317     SkPDFArray* result = SkNEW(SkPDFArray);
    318     result->reserve(4);
    319     result->appendName("Indexed");
    320     result->appendName("DeviceRGB");
    321     SkASSERT(table);
    322     if (table->count() < 1) {
    323         result->appendInt(0);
    324         char shortTableArray[3] = {0, 0, 0};
    325         SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
    326         result->appendString(tableString);
    327         return result;
    328     }
    329     result->appendInt(table->count() - 1);  // maximum color index.
    330 
    331     // Potentially, this could be represented in fewer bytes with a stream.
    332     // Max size as a string is 1.5k.
    333     char tableArray[256 * 3];
    334     SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
    335     uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
    336     const SkPMColor* colors = table->readColors();
    337     for (int i = 0; i < table->count(); i++) {
    338         pmcolor_to_rgb24(colors[i], tablePtr);
    339         tablePtr += 3;
    340     }
    341     SkString tableString(tableArray, 3 * table->count());
    342     result->appendString(tableString);
    343     return result;
    344 }
    345 
    346 void PDFDefaultBitmap::emitObject(SkWStream* stream,
    347                                   const SkPDFObjNumMap& objNumMap,
    348                                   const SkPDFSubstituteMap& substitutes) {
    349     SkAutoLockPixels autoLockPixels(fBitmap);
    350     SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
    351              fBitmap.getColorTable());
    352 
    353     // Write to a temporary buffer to get the compressed length.
    354     SkDynamicMemoryWStream buffer;
    355     SkDeflateWStream deflateWStream(&buffer);
    356     bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
    357     deflateWStream.finalize();  // call before detachAsStream().
    358     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
    359 
    360     SkPDFDict pdfDict("XObject");
    361     pdfDict.insertName("Subtype", "Image");
    362     pdfDict.insertInt("Width", fBitmap.width());
    363     pdfDict.insertInt("Height", fBitmap.height());
    364     if (fBitmap.colorType() == kIndex_8_SkColorType) {
    365         SkASSERT(1 == pdf_color_component_count(fBitmap.colorType()));
    366         pdfDict.insertObject("ColorSpace",
    367                              make_indexed_color_space(fBitmap.getColorTable()));
    368     } else if (1 == pdf_color_component_count(fBitmap.colorType())) {
    369         pdfDict.insertName("ColorSpace", "DeviceGray");
    370     } else {
    371         pdfDict.insertName("ColorSpace", "DeviceRGB");
    372     }
    373     pdfDict.insertInt("BitsPerComponent", 8);
    374     if (fSMask) {
    375         pdfDict.insertObjRef("SMask", SkRef(fSMask.get()));
    376     }
    377     pdfDict.insertName("Filter", "FlateDecode");
    378     pdfDict.insertInt("Length", asset->getLength());
    379     pdfDict.emitObject(stream, objNumMap, substitutes);
    380 
    381     pdf_stream_begin(stream);
    382     stream->writeStream(asset.get(), asset->getLength());
    383     pdf_stream_end(stream);
    384 }
    385 
    386 ////////////////////////////////////////////////////////////////////////////////
    387 
    388 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
    389     if (bm.isImmutable()) {
    390         return bm;
    391     }
    392     bm.copyTo(copy);
    393     copy->setImmutable();
    394     return *copy;
    395 }
    396 
    397 namespace {
    398 /**
    399  *  This PDFObject assumes that its constructor was handed YUV JFIF
    400  *  Jpeg-encoded data that can be directly embedded into a PDF.
    401  */
    402 class PDFJpegBitmap : public SkPDFBitmap {
    403 public:
    404     SkAutoTUnref<SkData> fData;
    405     bool fIsYUV;
    406     PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV)
    407         : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {}
    408     void emitObject(SkWStream*,
    409                     const SkPDFObjNumMap&,
    410                     const SkPDFSubstituteMap&) override;
    411 };
    412 
    413 void PDFJpegBitmap::emitObject(SkWStream* stream,
    414                                const SkPDFObjNumMap& objNumMap,
    415                                const SkPDFSubstituteMap& substituteMap) {
    416     SkPDFDict pdfDict("XObject");
    417     pdfDict.insertName("Subtype", "Image");
    418     pdfDict.insertInt("Width", fBitmap.width());
    419     pdfDict.insertInt("Height", fBitmap.height());
    420     if (fIsYUV) {
    421         pdfDict.insertName("ColorSpace", "DeviceRGB");
    422     } else {
    423         pdfDict.insertName("ColorSpace", "DeviceGray");
    424     }
    425     pdfDict.insertInt("BitsPerComponent", 8);
    426     pdfDict.insertName("Filter", "DCTDecode");
    427     pdfDict.insertInt("ColorTransform", 0);
    428     pdfDict.insertInt("Length", SkToInt(fData->size()));
    429     pdfDict.emitObject(stream, objNumMap, substituteMap);
    430     pdf_stream_begin(stream);
    431     stream->write(fData->data(), fData->size());
    432     pdf_stream_end(stream);
    433 }
    434 }  // namespace
    435 
    436 ////////////////////////////////////////////////////////////////////////////////
    437 
    438 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
    439     SkASSERT(canon);
    440     if (!SkColorTypeIsValid(bitmap.colorType()) ||
    441         kUnknown_SkColorType == bitmap.colorType()) {
    442         return NULL;
    443     }
    444     SkBitmap copy;
    445     const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
    446     if (bm.drawsNothing()) {
    447         return NULL;
    448     }
    449     if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
    450         return SkRef(canonBitmap);
    451     }
    452 
    453     if (bm.pixelRef() && bm.pixelRefOrigin().isZero() &&
    454         bm.dimensions() == bm.pixelRef()->info().dimensions()) {
    455         // Requires the bitmap to be backed by lazy pixels.
    456         SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
    457         SkJFIFInfo info;
    458         if (data && SkIsJFIF(data, &info)) {
    459             bool yuv = info.fType == SkJFIFInfo::kYCbCr;
    460             SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data, yuv));
    461             canon->addBitmap(pdfBitmap);
    462             return pdfBitmap;
    463         }
    464     }
    465 
    466     SkPDFObject* smask = NULL;
    467     if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
    468         smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
    469     }
    470     SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask));
    471     canon->addBitmap(pdfBitmap);
    472     return pdfBitmap;
    473 }
    474