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.config()) {
     31         case SkBitmap::kIndex8_Config:
     32             return srcRect.width() * srcRect.height();
     33         case SkBitmap::kARGB_4444_Config:
     34             return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
     35         case SkBitmap::kRGB_565_Config:
     36             return srcRect.width() * 3 * srcRect.height();
     37         case SkBitmap::kARGB_8888_Config:
     38             return srcRect.width() * 3 * srcRect.height();
     39         case SkBitmap::kA8_Config:
     40             return 1;
     41         default:
     42             SkASSERT(false);
     43             return 0;
     44     }
     45 }
     46 
     47 static SkStream* extract_index8_image(const SkBitmap& bitmap,
     48                                       const SkIRect& srcRect) {
     49     const int rowBytes = srcRect.width();
     50     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
     51                                   (get_uncompressed_size(bitmap, srcRect)));
     52     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
     53 
     54     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
     55         memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
     56         dst += rowBytes;
     57     }
     58     return stream;
     59 }
     60 
     61 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
     62                                        const SkIRect& srcRect,
     63                                        bool extractAlpha,
     64                                        bool* isOpaque,
     65                                        bool* isTransparent) {
     66     SkStream* stream;
     67     uint8_t* dst = NULL;
     68     if (extractAlpha) {
     69         const int alphaRowBytes = (srcRect.width() + 1) / 2;
     70         stream = SkNEW_ARGS(SkMemoryStream,
     71                             (alphaRowBytes * srcRect.height()));
     72     } else {
     73         stream = SkNEW_ARGS(SkMemoryStream,
     74                             (get_uncompressed_size(bitmap, srcRect)));
     75     }
     76     dst = (uint8_t*)stream->getMemoryBase();
     77 
     78     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
     79         uint16_t* src = bitmap.getAddr16(0, y);
     80         int x;
     81         for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
     82             if (extractAlpha) {
     83                 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
     84                     SkGetPackedA4444(src[x + 1]);
     85                 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
     86                 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
     87                 dst++;
     88             } else {
     89                 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
     90                     SkGetPackedG4444(src[x]);
     91                 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
     92                     SkGetPackedR4444(src[x + 1]);
     93                 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
     94                     SkGetPackedB4444(src[x + 1]);
     95                 dst += 3;
     96             }
     97         }
     98         if (srcRect.width() & 1) {
     99             if (extractAlpha) {
    100                 dst[0] = (SkGetPackedA4444(src[x]) << 4);
    101                 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
    102                 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
    103                 dst++;
    104 
    105             } else {
    106                 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
    107                     SkGetPackedG4444(src[x]);
    108                 dst[1] = (SkGetPackedB4444(src[x]) << 4);
    109                 dst += 2;
    110             }
    111         }
    112     }
    113     return stream;
    114 }
    115 
    116 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
    117                                       const SkIRect& srcRect) {
    118     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
    119                                   (get_uncompressed_size(bitmap,
    120                                                      srcRect)));
    121     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
    122     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    123         uint16_t* src = bitmap.getAddr16(0, y);
    124         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    125             dst[0] = SkGetPackedR16(src[x]);
    126             dst[1] = SkGetPackedG16(src[x]);
    127             dst[2] = SkGetPackedB16(src[x]);
    128             dst += 3;
    129         }
    130     }
    131     return stream;
    132 }
    133 
    134 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
    135                                        const SkIRect& srcRect,
    136                                        bool extractAlpha,
    137                                        bool* isOpaque,
    138                                        bool* isTransparent) {
    139     SkStream* stream;
    140     if (extractAlpha) {
    141         stream = SkNEW_ARGS(SkMemoryStream,
    142                             (srcRect.width() * srcRect.height()));
    143     } else {
    144         stream = SkNEW_ARGS(SkMemoryStream,
    145                             (get_uncompressed_size(bitmap, srcRect)));
    146     }
    147     uint8_t* dst = (uint8_t*)stream->getMemoryBase();
    148 
    149     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    150         uint32_t* src = bitmap.getAddr32(0, y);
    151         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    152             if (extractAlpha) {
    153                 dst[0] = SkGetPackedA32(src[x]);
    154                 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
    155                 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
    156                 dst++;
    157             } else {
    158                 dst[0] = SkGetPackedR32(src[x]);
    159                 dst[1] = SkGetPackedG32(src[x]);
    160                 dst[2] = SkGetPackedB32(src[x]);
    161                 dst += 3;
    162             }
    163         }
    164     }
    165     return stream;
    166 }
    167 
    168 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
    169                                   const SkIRect& srcRect,
    170                                   bool* isOpaque,
    171                                   bool* isTransparent) {
    172     const int alphaRowBytes = srcRect.width();
    173     SkStream* stream = SkNEW_ARGS(SkMemoryStream,
    174                                   (alphaRowBytes * srcRect.height()));
    175     uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
    176 
    177     for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
    178         uint8_t* src = bitmap.getAddr8(0, y);
    179         for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
    180             alphaDst[0] = src[x];
    181             *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
    182             *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
    183             alphaDst++;
    184         }
    185     }
    186     return stream;
    187 }
    188 
    189 static SkStream* create_black_image() {
    190     SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
    191     ((uint8_t*)stream->getMemoryBase())[0] = 0;
    192     return stream;
    193 }
    194 
    195 /**
    196  * Extract either the color or image data from a SkBitmap into a SkStream.
    197  * @param bitmap        Bitmap to extract data from.
    198  * @param srcRect       Region in the bitmap to extract.
    199  * @param extractAlpha  Set to true to extract the alpha data or false to
    200  *                      extract the color data.
    201  * @param isTransparent Pointer to a bool to output whether the alpha is
    202  *                      completely transparent. May be NULL. Only valid when
    203  *                      extractAlpha == true.
    204  * @return              Unencoded image data, or NULL if either data was not
    205  *                      available or alpha data was requested but the image was
    206  *                      entirely transparent or opaque.
    207  */
    208 static SkStream* extract_image_data(const SkBitmap& bitmap,
    209                                     const SkIRect& srcRect,
    210                                     bool extractAlpha, bool* isTransparent) {
    211     SkBitmap::Config config = bitmap.config();
    212     if (extractAlpha && (config == SkBitmap::kIndex8_Config ||
    213             config == SkBitmap::kRGB_565_Config)) {
    214         if (isTransparent != NULL) {
    215             *isTransparent = false;
    216         }
    217         return NULL;
    218     }
    219     bool isOpaque = true;
    220     bool transparent = extractAlpha;
    221     SkStream* stream = NULL;
    222 
    223     bitmap.lockPixels();
    224     switch (config) {
    225         case SkBitmap::kIndex8_Config:
    226             if (!extractAlpha) {
    227                 stream = extract_index8_image(bitmap, srcRect);
    228             }
    229             break;
    230         case SkBitmap::kARGB_4444_Config:
    231             stream = extract_argb4444_data(bitmap, srcRect, extractAlpha,
    232                                            &isOpaque, &transparent);
    233             break;
    234         case SkBitmap::kRGB_565_Config:
    235             if (!extractAlpha) {
    236                 stream = extract_rgb565_image(bitmap, srcRect);
    237             }
    238             break;
    239         case SkBitmap::kARGB_8888_Config:
    240             stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
    241                                            &isOpaque, &transparent);
    242             break;
    243         case SkBitmap::kA8_Config:
    244             if (!extractAlpha) {
    245                 stream = create_black_image();
    246             } else {
    247                 stream = extract_a8_alpha(bitmap, srcRect,
    248                                           &isOpaque, &transparent);
    249             }
    250             break;
    251         default:
    252             SkASSERT(false);
    253     }
    254     bitmap.unlockPixels();
    255 
    256     if (isTransparent != NULL) {
    257         *isTransparent = transparent;
    258     }
    259     if (extractAlpha && (transparent || isOpaque)) {
    260         SkSafeUnref(stream);
    261         return NULL;
    262     }
    263     return stream;
    264 }
    265 
    266 static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
    267     SkPDFArray* result = new SkPDFArray();
    268     result->reserve(4);
    269     result->appendName("Indexed");
    270     result->appendName("DeviceRGB");
    271     result->appendInt(table->count() - 1);
    272 
    273     // Potentially, this could be represented in fewer bytes with a stream.
    274     // Max size as a string is 1.5k.
    275     SkString index;
    276     for (int i = 0; i < table->count(); i++) {
    277         char buf[3];
    278         SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
    279         buf[0] = SkGetPackedR32(color);
    280         buf[1] = SkGetPackedG32(color);
    281         buf[2] = SkGetPackedB32(color);
    282         index.append(buf, 3);
    283     }
    284     result->append(new SkPDFString(index))->unref();
    285     return result;
    286 }
    287 
    288 /**
    289  * Removes the alpha component of an ARGB color (including unpremultiply) while
    290  * keeping the output in the same format as the input.
    291  */
    292 static uint32_t remove_alpha_argb8888(uint32_t pmColor) {
    293     SkColor color = SkUnPreMultiply::PMColorToColor(pmColor);
    294     return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
    295                                SkColorGetR(color),
    296                                SkColorGetG(color),
    297                                SkColorGetB(color));
    298 }
    299 
    300 static uint16_t remove_alpha_argb4444(uint16_t pmColor) {
    301     return SkPixel32ToPixel4444(
    302             remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor)));
    303 }
    304 
    305 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
    306                                                 int xOrig, int yOrig) {
    307     uint8_t count = 0;
    308     uint16_t r = 0;
    309     uint16_t g = 0;
    310     uint16_t b = 0;
    311 
    312     for (int y = yOrig - 1; y <= yOrig + 1; y++) {
    313         if (y < 0 || y >= bitmap.height()) {
    314             continue;
    315         }
    316         uint32_t* src = bitmap.getAddr32(0, y);
    317         for (int x = xOrig - 1; x <= xOrig + 1; x++) {
    318             if (x < 0 || x >= bitmap.width()) {
    319                 continue;
    320             }
    321             if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) {
    322                 uint32_t color = remove_alpha_argb8888(src[x]);
    323                 r += SkGetPackedR32(color);
    324                 g += SkGetPackedG32(color);
    325                 b += SkGetPackedB32(color);
    326                 count++;
    327             }
    328         }
    329     }
    330 
    331     if (count == 0) {
    332         return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
    333     } else {
    334         return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
    335                                    r / count, g / count, b / count);
    336     }
    337 }
    338 
    339 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap,
    340                                                 int xOrig, int yOrig) {
    341     uint8_t count = 0;
    342     uint8_t r = 0;
    343     uint8_t g = 0;
    344     uint8_t b = 0;
    345 
    346     for (int y = yOrig - 1; y <= yOrig + 1; y++) {
    347         if (y < 0 || y >= bitmap.height()) {
    348             continue;
    349         }
    350         uint16_t* src = bitmap.getAddr16(0, y);
    351         for (int x = xOrig - 1; x <= xOrig + 1; x++) {
    352             if (x < 0 || x >= bitmap.width()) {
    353                 continue;
    354             }
    355             if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) {
    356                 uint16_t color = remove_alpha_argb4444(src[x]);
    357                 r += SkGetPackedR4444(color);
    358                 g += SkGetPackedG4444(color);
    359                 b += SkGetPackedB4444(color);
    360                 count++;
    361             }
    362         }
    363     }
    364 
    365     if (count == 0) {
    366         return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
    367     } else {
    368         return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
    369                                    r / count, g / count, b / count);
    370     }
    371 }
    372 
    373 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
    374                                      const SkIRect& srcRect) {
    375     SkBitmap outBitmap;
    376     outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height());
    377     outBitmap.allocPixels();
    378     int dstRow = 0;
    379 
    380     outBitmap.lockPixels();
    381     bitmap.lockPixels();
    382     switch (bitmap.config()) {
    383         case SkBitmap::kARGB_4444_Config: {
    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 SkBitmap::kARGB_8888_Config: {
    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.config() == SkBitmap::kNo_Config) {
    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     SkBitmap::Config config = bitmap.config();
    463     if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config ||
    464             config == SkBitmap::kARGB_4444_Config)) {
    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, bitmap.config());
    511         fBitmap.setImmutable();
    512     }
    513 
    514     if (stream != NULL) {
    515         setData(stream);
    516         fStreamValid = true;
    517     } else {
    518         fStreamValid = false;
    519     }
    520 
    521     SkBitmap::Config config = fBitmap.config();
    522 
    523     insertName("Type", "XObject");
    524     insertName("Subtype", "Image");
    525 
    526     bool alphaOnly = (config == SkBitmap::kA8_Config);
    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 (config == SkBitmap::kIndex8_Config) {
    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 (config == SkBitmap::kARGB_4444_Config) {
    551         bitsPerComp = 4;
    552     }
    553     insertInt("BitsPerComponent", bitsPerComp);
    554 
    555     if (config == SkBitmap::kRGB_565_Config) {
    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                 // TODO(edisonn) It fails only for kA1_Config, if that is a
    596                 // major concern we will fix it later, so far it is NYI.
    597                 return false;
    598             }
    599             size_t pixelRefOffset = 0;
    600             SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset));
    601             if (data.get() && data->size() < get_uncompressed_size(fBitmap,
    602                                                                    fSrcRect)) {
    603                 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream,
    604                                                          (data)));
    605                 setData(stream.get());
    606 
    607                 insertName("Filter", "DCTDecode");
    608                 insertInt("ColorTransform", kNoColorTransform);
    609                 insertInt("Length", getData()->getLength());
    610                 setState(kCompressed_State);
    611                 return true;
    612             }
    613         }
    614         // Fallback method
    615         if (!fStreamValid) {
    616             SkAutoTUnref<SkStream> stream(
    617                     extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
    618             setData(stream);
    619             fStreamValid = true;
    620         }
    621         return INHERITED::populate(catalog);
    622     } else if (getState() == kNoCompression_State &&
    623             !skip_compression(catalog) &&
    624             (SkFlate::HaveFlate() || fEncoder)) {
    625         // Compression has not been requested when the stream was first created,
    626         // but the new catalog wants it compressed.
    627         if (!getSubstitute()) {
    628             SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
    629             setSubstitute(substitute);
    630             catalog->setSubstitute(this, substitute);
    631         }
    632         return false;
    633     }
    634     return true;
    635 }
    636