Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright 2010 The Android Open Source Project
      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 "SkPDFImage.h"
      9 
     10 #include "SkBitmap.h"
     11 #include "SkColor.h"
     12 #include "SkColorPriv.h"
     13 #include "SkData.h"
     14 #include "SkFlate.h"
     15 #include "SkPDFCatalog.h"
     16 #include "SkRect.h"
     17 #include "SkStream.h"
     18 #include "SkString.h"
     19 #include "SkUnPreMultiply.h"
     20 
     21 static const int kNoColorTransform = 0;
     22 
     23 static bool skip_compression(SkPDFCatalog* catalog) {
     24     return SkToBool(catalog->getDocumentFlags() &
     25                     SkPDFDocument::kFavorSpeedOverSize_Flags);
     26 }
     27 
     28 static size_t get_uncompressed_size(const SkBitmap& bitmap,
     29                                     const SkIRect& srcRect) {
     30     switch (bitmap.colorType()) {
     31         case kIndex_8_SkColorType:
     32             return srcRect.width() * srcRect.height();
     33         case kARGB_4444_SkColorType:
     34             return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
     35         case kRGB_565_SkColorType:
     36             return srcRect.width() * 3 * srcRect.height();
     37         case kRGBA_8888_SkColorType:
     38         case kBGRA_8888_SkColorType:
     39             return srcRect.width() * 3 * srcRect.height();
     40         case kAlpha_8_SkColorType:
     41             return 1;
     42         default:
     43             SkASSERT(false);
     44             return 0;
     45     }
     46 }
     47 
     48 static SkStream* extract_index8_image(const SkBitmap& bitmap,
     49                                       const SkIRect& srcRect) {
     50     const int rowBytes = srcRect.width();
     51     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
     52                                   (get_uncompressed_size(bitmap, srcRect)));
     53     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
     54 
     55     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
     56         memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
     57         dst += rowBytes;
     58     }
     59     return stream;
     60 }
     61 
     62 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
     63                                        const SkIRect& srcRect,
     64                                        bool extractAlpha,
     65                                        bool* isOpaque,
     66                                        bool* isTransparent) {
     67     SkStream* stream;
     68     uint8_t* dst = NULL;
     69     if (extractAlpha) {
     70         const int alphaRowBytes = (srcRect.width() + 1) / 2;
     71         stream = SkNEW_ARGS(SkMemoryStream,
     72                             (alphaRowBytes * srcRect.height()));
     73     } else {
     74         stream = SkNEW_ARGS(SkMemoryStream,
     75                             (get_uncompressed_size(bitmap, srcRect)));
     76     }
     77     dst = (uint8_t*)stream->getMemoryBase();
     78 
     79     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
     80         uint16_t* src = bitmap.getAddr16(0, y);
     81         int x;
     82         for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
     83             if (extractAlpha) {
     84                 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
     85                     SkGetPackedA4444(src[x + 1]);
     86                 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
     87                 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
     88                 dst++;
     89             } else {
     90                 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
     91                     SkGetPackedG4444(src[x]);
     92                 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
     93                     SkGetPackedR4444(src[x + 1]);
     94                 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
     95                     SkGetPackedB4444(src[x + 1]);
     96                 dst += 3;
     97             }
     98         }
     99         if (srcRect.width() & 1) {
    100             if (extractAlpha) {
    101                 dst[0] = (SkGetPackedA4444(src[x]) << 4);
    102                 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
    103                 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
    104                 dst++;
    105 
    106             } else {
    107                 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
    108                     SkGetPackedG4444(src[x]);
    109                 dst[1] = (SkGetPackedB4444(src[x]) << 4);
    110                 dst += 2;
    111             }
    112         }
    113     }
    114     return stream;
    115 }
    116 
    117 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
    118                                       const SkIRect& srcRect) {
    119     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
    120                                   (get_uncompressed_size(bitmap,
    121                                                      srcRect)));
    122     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
    123     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    124         uint16_t* src = bitmap.getAddr16(0, y);
    125         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    126             dst[0] = SkGetPackedR16(src[x]);
    127             dst[1] = SkGetPackedG16(src[x]);
    128             dst[2] = SkGetPackedB16(src[x]);
    129             dst += 3;
    130         }
    131     }
    132     return stream;
    133 }
    134 
    135 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
    136                                        const SkIRect& srcRect,
    137                                        bool extractAlpha,
    138                                        bool* isOpaque,
    139                                        bool* isTransparent) {
    140     SkStream* stream;
    141     if (extractAlpha) {
    142         stream = SkNEW_ARGS(SkMemoryStream,
    143                             (srcRect.width() * srcRect.height()));
    144     } else {
    145         stream = SkNEW_ARGS(SkMemoryStream,
    146                             (get_uncompressed_size(bitmap, srcRect)));
    147     }
    148     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
    149 
    150     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    151         uint32_t* src = bitmap.getAddr32(0, y);
    152         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    153             if (extractAlpha) {
    154                 dst[0] = SkGetPackedA32(src[x]);
    155                 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
    156                 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
    157                 dst++;
    158             } else {
    159                 dst[0] = SkGetPackedR32(src[x]);
    160                 dst[1] = SkGetPackedG32(src[x]);
    161                 dst[2] = SkGetPackedB32(src[x]);
    162                 dst += 3;
    163             }
    164         }
    165     }
    166     return stream;
    167 }
    168 
    169 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
    170                                   const SkIRect& srcRect,
    171                                   bool* isOpaque,
    172                                   bool* isTransparent) {
    173     const int alphaRowBytes = srcRect.width();
    174     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
    175                                   (alphaRowBytes * srcRect.height()));
    176     uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
    177 
    178     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    179         uint8_t* src = bitmap.getAddr8(0, y);
    180         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    181             alphaDst[0] = src[x];
    182             *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
    183             *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
    184             alphaDst++;
    185         }
    186     }
    187     return stream;
    188 }
    189 
    190 static SkStream* create_black_image() {
    191     SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
    192     ((uint8_t*)stream->getMemoryBase())[0] = 0;
    193     return stream;
    194 }
    195 
    196 /**
    197  * Extract either the color or image data from a SkBitmap into a SkStream.
    198  * @param bitmap        Bitmap to extract data from.
    199  * @param srcRect       Region in the bitmap to extract.
    200  * @param extractAlpha  Set to true to extract the alpha data or false to
    201  *                      extract the color data.
    202  * @param isTransparent Pointer to a bool to output whether the alpha is
    203  *                      completely transparent. May be NULL. Only valid when
    204  *                      extractAlpha == true.
    205  * @return              Unencoded image data, or NULL if either data was not
    206  *                      available or alpha data was requested but the image was
    207  *                      entirely transparent or opaque.
    208  */
    209 static SkStream* extract_image_data(const SkBitmap& bitmap,
    210                                     const SkIRect& srcRect,
    211                                     bool extractAlpha, bool* isTransparent) {
    212     SkColorType colorType = bitmap.colorType();
    213     if (extractAlpha && (kIndex_8_SkColorType == colorType ||
    214                          kRGB_565_SkColorType == colorType)) {
    215         if (isTransparent != NULL) {
    216             *isTransparent = false;
    217         }
    218         return NULL;
    219     }
    220     bool isOpaque = true;
    221     bool transparent = extractAlpha;
    222     SkStream* stream = NULL;
    223 
    224     bitmap.lockPixels();
    225     switch (colorType) {
    226         case kIndex_8_SkColorType:
    227             if (!extractAlpha) {
    228                 stream = extract_index8_image(bitmap, srcRect);
    229             }
    230             break;
    231         case kARGB_4444_SkColorType:
    232             stream = extract_argb4444_data(bitmap, srcRect, extractAlpha,
    233                                            &isOpaque, &transparent);
    234             break;
    235         case kRGB_565_SkColorType:
    236             if (!extractAlpha) {
    237                 stream = extract_rgb565_image(bitmap, srcRect);
    238             }
    239             break;
    240         case kN32_SkColorType:
    241             stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
    242                                            &isOpaque, &transparent);
    243             break;
    244         case kAlpha_8_SkColorType:
    245             if (!extractAlpha) {
    246                 stream = create_black_image();
    247             } else {
    248                 stream = extract_a8_alpha(bitmap, srcRect,
    249                                           &isOpaque, &transparent);
    250             }
    251             break;
    252         default:
    253             SkASSERT(false);
    254     }
    255     bitmap.unlockPixels();
    256 
    257     if (isTransparent != NULL) {
    258         *isTransparent = transparent;
    259     }
    260     if (extractAlpha && (transparent || isOpaque)) {
    261         SkSafeUnref(stream);
    262         return NULL;
    263     }
    264     return stream;
    265 }
    266 
    267 static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
    268     SkPDFArray* result = new SkPDFArray();
    269     result->reserve(4);
    270     result->appendName("Indexed");
    271     result->appendName("DeviceRGB");
    272     result->appendInt(table->count() - 1);
    273 
    274     // Potentially, this could be represented in fewer bytes with a stream.
    275     // Max size as a string is 1.5k.
    276     SkString index;
    277     for (int i = 0; i < table->count(); i++) {
    278         char buf[3];
    279         SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
    280         buf[0] = SkGetPackedR32(color);
    281         buf[1] = SkGetPackedG32(color);
    282         buf[2] = SkGetPackedB32(color);
    283         index.append(buf, 3);
    284     }
    285     result->append(new SkPDFString(index))->unref();
    286     return result;
    287 }
    288 
    289 /**
    290  * Removes the alpha component of an ARGB color (including unpremultiply) while
    291  * keeping the output in the same format as the input.
    292  */
    293 static uint32_t remove_alpha_argb8888(uint32_t pmColor) {
    294     SkColor color = SkUnPreMultiply::PMColorToColor(pmColor);
    295     return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
    296                                SkColorGetR(color),
    297                                SkColorGetG(color),
    298                                SkColorGetB(color));
    299 }
    300 
    301 static uint16_t remove_alpha_argb4444(uint16_t pmColor) {
    302     return SkPixel32ToPixel4444(
    303             remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor)));
    304 }
    305 
    306 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
    307                                                 int xOrig, int yOrig) {
    308     uint8_t count = 0;
    309     uint16_t r = 0;
    310     uint16_t g = 0;
    311     uint16_t b = 0;
    312 
    313     for (int y = yOrig - 1; y <= yOrig + 1; y++) {
    314         if (y < 0 || y >= bitmap.height()) {
    315             continue;
    316         }
    317         uint32_t* src = bitmap.getAddr32(0, y);
    318         for (int x = xOrig - 1; x <= xOrig + 1; x++) {
    319             if (x < 0 || x >= bitmap.width()) {
    320                 continue;
    321             }
    322             if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) {
    323                 uint32_t color = remove_alpha_argb8888(src[x]);
    324                 r += SkGetPackedR32(color);
    325                 g += SkGetPackedG32(color);
    326                 b += SkGetPackedB32(color);
    327                 count++;
    328             }
    329         }
    330     }
    331 
    332     if (count == 0) {
    333         return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
    334     } else {
    335         return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
    336                                    r / count, g / count, b / count);
    337     }
    338 }
    339 
    340 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap,
    341                                                 int xOrig, int yOrig) {
    342     uint8_t count = 0;
    343     uint8_t r = 0;
    344     uint8_t g = 0;
    345     uint8_t b = 0;
    346 
    347     for (int y = yOrig - 1; y <= yOrig + 1; y++) {
    348         if (y < 0 || y >= bitmap.height()) {
    349             continue;
    350         }
    351         uint16_t* src = bitmap.getAddr16(0, y);
    352         for (int x = xOrig - 1; x <= xOrig + 1; x++) {
    353             if (x < 0 || x >= bitmap.width()) {
    354                 continue;
    355             }
    356             if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) {
    357                 uint16_t color = remove_alpha_argb4444(src[x]);
    358                 r += SkGetPackedR4444(color);
    359                 g += SkGetPackedG4444(color);
    360                 b += SkGetPackedB4444(color);
    361                 count++;
    362             }
    363         }
    364     }
    365 
    366     if (count == 0) {
    367         return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
    368     } else {
    369         return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
    370                                    r / count, g / count, b / count);
    371     }
    372 }
    373 
    374 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
    375                                      const SkIRect& srcRect) {
    376     SkBitmap outBitmap;
    377     outBitmap.allocPixels(bitmap.info().makeWH(srcRect.width(), srcRect.height()));
    378     int dstRow = 0;
    379 
    380     outBitmap.lockPixels();
    381     bitmap.lockPixels();
    382     switch (bitmap.colorType()) {
    383         case kARGB_4444_SkColorType: {
    384             for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    385                 uint16_t* dst = outBitmap.getAddr16(0, dstRow);
    386                 uint16_t* src = bitmap.getAddr16(0, y);
    387                 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    388                     uint8_t a = SkGetPackedA4444(src[x]);
    389                     // It is necessary to average the color component of
    390                     // transparent pixels with their surrounding neighbors
    391                     // since the PDF renderer may separately re-sample the
    392                     // alpha and color channels when the image is not
    393                     // displayed at its native resolution. Since an alpha of
    394                     // zero gives no information about the color component,
    395                     // the pathological case is a white image with sharp
    396                     // transparency bounds - the color channel goes to black,
    397                     // and the should-be-transparent pixels are rendered
    398                     // as grey because of the separate soft mask and color
    399                     // resizing.
    400                     if (a == (SK_AlphaTRANSPARENT & 0x0F)) {
    401                         *dst = get_argb4444_neighbor_avg_color(bitmap, x, y);
    402                     } else {
    403                         *dst = remove_alpha_argb4444(src[x]);
    404                     }
    405                     dst++;
    406                 }
    407                 dstRow++;
    408             }
    409             break;
    410         }
    411         case kN32_SkColorType: {
    412             for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    413                 uint32_t* dst = outBitmap.getAddr32(0, dstRow);
    414                 uint32_t* src = bitmap.getAddr32(0, y);
    415                 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    416                     uint8_t a = SkGetPackedA32(src[x]);
    417                     if (a == SK_AlphaTRANSPARENT) {
    418                         *dst = get_argb8888_neighbor_avg_color(bitmap, x, y);
    419                     } else {
    420                         *dst = remove_alpha_argb8888(src[x]);
    421                     }
    422                     dst++;
    423                 }
    424                 dstRow++;
    425             }
    426             break;
    427         }
    428         default:
    429             SkASSERT(false);
    430     }
    431     bitmap.unlockPixels();
    432     outBitmap.unlockPixels();
    433 
    434     outBitmap.setImmutable();
    435 
    436     return outBitmap;
    437 }
    438 
    439 // static
    440 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
    441                                     const SkIRect& srcRect,
    442                                     SkPicture::EncodeBitmap encoder) {
    443     if (bitmap.colorType() == kUnknown_SkColorType) {
    444         return NULL;
    445     }
    446 
    447     bool isTransparent = false;
    448     SkAutoTUnref<SkStream> alphaData;
    449     if (!bitmap.isOpaque()) {
    450         // Note that isOpaque is not guaranteed to return false for bitmaps
    451         // with alpha support but a completely opaque alpha channel,
    452         // so alphaData may still be NULL if we have a completely opaque
    453         // (or transparent) bitmap.
    454         alphaData.reset(
    455                 extract_image_data(bitmap, srcRect, true, &isTransparent));
    456     }
    457     if (isTransparent) {
    458         return NULL;
    459     }
    460 
    461     SkPDFImage* image;
    462     SkColorType colorType = bitmap.colorType();
    463     if (alphaData.get() != NULL && (kN32_SkColorType == colorType ||
    464                                     kARGB_4444_SkColorType == colorType)) {
    465         SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
    466         image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false,
    467                            SkIRect::MakeWH(srcRect.width(), srcRect.height()),
    468                            encoder));
    469     } else {
    470         image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder));
    471     }
    472     if (alphaData.get() != NULL) {
    473         SkAutoTUnref<SkPDFImage> mask(
    474                 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap,
    475                                         true, srcRect, NULL)));
    476         image->addSMask(mask);
    477     }
    478 
    479     return image;
    480 }
    481 
    482 SkPDFImage::~SkPDFImage() {
    483     fResources.unrefAll();
    484 }
    485 
    486 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
    487     fResources.push(mask);
    488     mask->ref();
    489     insert("SMask", new SkPDFObjRef(mask))->unref();
    490     return mask;
    491 }
    492 
    493 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
    494                               SkTSet<SkPDFObject*>* newResourceObjects) {
    495     GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
    496 }
    497 
    498 SkPDFImage::SkPDFImage(SkStream* stream,
    499                        const SkBitmap& bitmap,
    500                        bool isAlpha,
    501                        const SkIRect& srcRect,
    502                        SkPicture::EncodeBitmap encoder)
    503     : fIsAlpha(isAlpha),
    504       fSrcRect(srcRect),
    505       fEncoder(encoder) {
    506 
    507     if (bitmap.isImmutable()) {
    508         fBitmap = bitmap;
    509     } else {
    510         bitmap.deepCopyTo(&fBitmap);
    511         fBitmap.setImmutable();
    512     }
    513 
    514     if (stream != NULL) {
    515         setData(stream);
    516         fStreamValid = true;
    517     } else {
    518         fStreamValid = false;
    519     }
    520 
    521     SkColorType colorType = fBitmap.colorType();
    522 
    523     insertName("Type", "XObject");
    524     insertName("Subtype", "Image");
    525 
    526     bool alphaOnly = (kAlpha_8_SkColorType == colorType);
    527 
    528     if (!isAlpha && alphaOnly) {
    529         // For alpha only images, we stretch a single pixel of black for
    530         // the color/shape part.
    531         SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
    532         insert("Width", one.get());
    533         insert("Height", one.get());
    534     } else {
    535         insertInt("Width", fSrcRect.width());
    536         insertInt("Height", fSrcRect.height());
    537     }
    538 
    539     if (isAlpha || alphaOnly) {
    540         insertName("ColorSpace", "DeviceGray");
    541     } else if (kIndex_8_SkColorType == colorType) {
    542         SkAutoLockPixels alp(fBitmap);
    543         insert("ColorSpace",
    544                make_indexed_color_space(fBitmap.getColorTable()))->unref();
    545     } else {
    546         insertName("ColorSpace", "DeviceRGB");
    547     }
    548 
    549     int bitsPerComp = 8;
    550     if (kARGB_4444_SkColorType == colorType) {
    551         bitsPerComp = 4;
    552     }
    553     insertInt("BitsPerComponent", bitsPerComp);
    554 
    555     if (kRGB_565_SkColorType == colorType) {
    556         SkASSERT(!isAlpha);
    557         SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
    558         SkAutoTUnref<SkPDFScalar> scale5Val(
    559                 new SkPDFScalar(8.2258f));  // 255/2^5-1
    560         SkAutoTUnref<SkPDFScalar> scale6Val(
    561                 new SkPDFScalar(4.0476f));  // 255/2^6-1
    562         SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
    563         decodeValue->reserve(6);
    564         decodeValue->append(zeroVal.get());
    565         decodeValue->append(scale5Val.get());
    566         decodeValue->append(zeroVal.get());
    567         decodeValue->append(scale6Val.get());
    568         decodeValue->append(zeroVal.get());
    569         decodeValue->append(scale5Val.get());
    570         insert("Decode", decodeValue.get());
    571     }
    572 }
    573 
    574 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
    575     : SkPDFStream(pdfImage),
    576       fBitmap(pdfImage.fBitmap),
    577       fIsAlpha(pdfImage.fIsAlpha),
    578       fSrcRect(pdfImage.fSrcRect),
    579       fEncoder(pdfImage.fEncoder),
    580       fStreamValid(pdfImage.fStreamValid) {
    581     // Nothing to do here - the image params are already copied in SkPDFStream's
    582     // constructor, and the bitmap will be regenerated and encoded in
    583     // populate.
    584 }
    585 
    586 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
    587     if (getState() == kUnused_State) {
    588         // Initializing image data for the first time.
    589         SkDynamicMemoryWStream dctCompressedWStream;
    590         if (!skip_compression(catalog) && fEncoder &&
    591                 get_uncompressed_size(fBitmap, fSrcRect) > 1) {
    592             SkBitmap subset;
    593             // Extract subset
    594             if (!fBitmap.extractSubset(&subset, fSrcRect)) {
    595                 return false;
    596             }
    597             size_t pixelRefOffset = 0;
    598             SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset));
    599             if (data.get() && data->size() < get_uncompressed_size(fBitmap,
    600                                                                    fSrcRect)) {
    601                 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream,
    602                                                          (data)));
    603                 setData(stream.get());
    604 
    605                 insertName("Filter", "DCTDecode");
    606                 insertInt("ColorTransform", kNoColorTransform);
    607                 insertInt("Length", getData()->getLength());
    608                 setState(kCompressed_State);
    609                 return true;
    610             }
    611         }
    612         // Fallback method
    613         if (!fStreamValid) {
    614             SkAutoTUnref<SkStream> stream(
    615                     extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
    616             setData(stream);
    617             fStreamValid = true;
    618         }
    619         return INHERITED::populate(catalog);
    620     } else if (getState() == kNoCompression_State &&
    621             !skip_compression(catalog) &&
    622             (SkFlate::HaveFlate() || fEncoder)) {
    623         // Compression has not been requested when the stream was first created,
    624         // but the new catalog wants it compressed.
    625         if (!getSubstitute()) {
    626             SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
    627             setSubstitute(substitute);
    628             catalog->setSubstitute(this, substitute);
    629         }
    630         return false;
    631     }
    632     return true;
    633 }
    634