1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/pdf/SkPDFImage.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,635 @@ 1.4 +/* 1.5 + * Copyright 2010 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkPDFImage.h" 1.12 + 1.13 +#include "SkBitmap.h" 1.14 +#include "SkColor.h" 1.15 +#include "SkColorPriv.h" 1.16 +#include "SkData.h" 1.17 +#include "SkFlate.h" 1.18 +#include "SkPDFCatalog.h" 1.19 +#include "SkRect.h" 1.20 +#include "SkStream.h" 1.21 +#include "SkString.h" 1.22 +#include "SkUnPreMultiply.h" 1.23 + 1.24 +static const int kNoColorTransform = 0; 1.25 + 1.26 +static bool skip_compression(SkPDFCatalog* catalog) { 1.27 + return SkToBool(catalog->getDocumentFlags() & 1.28 + SkPDFDocument::kFavorSpeedOverSize_Flags); 1.29 +} 1.30 + 1.31 +static size_t get_uncompressed_size(const SkBitmap& bitmap, 1.32 + const SkIRect& srcRect) { 1.33 + switch (bitmap.config()) { 1.34 + case SkBitmap::kIndex8_Config: 1.35 + return srcRect.width() * srcRect.height(); 1.36 + case SkBitmap::kARGB_4444_Config: 1.37 + return ((srcRect.width() * 3 + 1) / 2) * srcRect.height(); 1.38 + case SkBitmap::kRGB_565_Config: 1.39 + return srcRect.width() * 3 * srcRect.height(); 1.40 + case SkBitmap::kARGB_8888_Config: 1.41 + return srcRect.width() * 3 * srcRect.height(); 1.42 + case SkBitmap::kA8_Config: 1.43 + return 1; 1.44 + default: 1.45 + SkASSERT(false); 1.46 + return 0; 1.47 + } 1.48 +} 1.49 + 1.50 +static SkStream* extract_index8_image(const SkBitmap& bitmap, 1.51 + const SkIRect& srcRect) { 1.52 + const int rowBytes = srcRect.width(); 1.53 + SkStream* stream = SkNEW_ARGS(SkMemoryStream, 1.54 + (get_uncompressed_size(bitmap, srcRect))); 1.55 + uint8_t* dst = (uint8_t*)stream->getMemoryBase(); 1.56 + 1.57 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.58 + memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); 1.59 + dst += rowBytes; 1.60 + } 1.61 + return stream; 1.62 +} 1.63 + 1.64 +static SkStream* extract_argb4444_data(const SkBitmap& bitmap, 1.65 + const SkIRect& srcRect, 1.66 + bool extractAlpha, 1.67 + bool* isOpaque, 1.68 + bool* isTransparent) { 1.69 + SkStream* stream; 1.70 + uint8_t* dst = NULL; 1.71 + if (extractAlpha) { 1.72 + const int alphaRowBytes = (srcRect.width() + 1) / 2; 1.73 + stream = SkNEW_ARGS(SkMemoryStream, 1.74 + (alphaRowBytes * srcRect.height())); 1.75 + } else { 1.76 + stream = SkNEW_ARGS(SkMemoryStream, 1.77 + (get_uncompressed_size(bitmap, srcRect))); 1.78 + } 1.79 + dst = (uint8_t*)stream->getMemoryBase(); 1.80 + 1.81 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.82 + uint16_t* src = bitmap.getAddr16(0, y); 1.83 + int x; 1.84 + for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { 1.85 + if (extractAlpha) { 1.86 + dst[0] = (SkGetPackedA4444(src[x]) << 4) | 1.87 + SkGetPackedA4444(src[x + 1]); 1.88 + *isOpaque &= dst[0] == SK_AlphaOPAQUE; 1.89 + *isTransparent &= dst[0] == SK_AlphaTRANSPARENT; 1.90 + dst++; 1.91 + } else { 1.92 + dst[0] = (SkGetPackedR4444(src[x]) << 4) | 1.93 + SkGetPackedG4444(src[x]); 1.94 + dst[1] = (SkGetPackedB4444(src[x]) << 4) | 1.95 + SkGetPackedR4444(src[x + 1]); 1.96 + dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | 1.97 + SkGetPackedB4444(src[x + 1]); 1.98 + dst += 3; 1.99 + } 1.100 + } 1.101 + if (srcRect.width() & 1) { 1.102 + if (extractAlpha) { 1.103 + dst[0] = (SkGetPackedA4444(src[x]) << 4); 1.104 + *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0); 1.105 + *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0); 1.106 + dst++; 1.107 + 1.108 + } else { 1.109 + dst[0] = (SkGetPackedR4444(src[x]) << 4) | 1.110 + SkGetPackedG4444(src[x]); 1.111 + dst[1] = (SkGetPackedB4444(src[x]) << 4); 1.112 + dst += 2; 1.113 + } 1.114 + } 1.115 + } 1.116 + return stream; 1.117 +} 1.118 + 1.119 +static SkStream* extract_rgb565_image(const SkBitmap& bitmap, 1.120 + const SkIRect& srcRect) { 1.121 + SkStream* stream = SkNEW_ARGS(SkMemoryStream, 1.122 + (get_uncompressed_size(bitmap, 1.123 + srcRect))); 1.124 + uint8_t* dst = (uint8_t*)stream->getMemoryBase(); 1.125 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.126 + uint16_t* src = bitmap.getAddr16(0, y); 1.127 + for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 1.128 + dst[0] = SkGetPackedR16(src[x]); 1.129 + dst[1] = SkGetPackedG16(src[x]); 1.130 + dst[2] = SkGetPackedB16(src[x]); 1.131 + dst += 3; 1.132 + } 1.133 + } 1.134 + return stream; 1.135 +} 1.136 + 1.137 +static SkStream* extract_argb8888_data(const SkBitmap& bitmap, 1.138 + const SkIRect& srcRect, 1.139 + bool extractAlpha, 1.140 + bool* isOpaque, 1.141 + bool* isTransparent) { 1.142 + SkStream* stream; 1.143 + if (extractAlpha) { 1.144 + stream = SkNEW_ARGS(SkMemoryStream, 1.145 + (srcRect.width() * srcRect.height())); 1.146 + } else { 1.147 + stream = SkNEW_ARGS(SkMemoryStream, 1.148 + (get_uncompressed_size(bitmap, srcRect))); 1.149 + } 1.150 + uint8_t* dst = (uint8_t*)stream->getMemoryBase(); 1.151 + 1.152 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.153 + uint32_t* src = bitmap.getAddr32(0, y); 1.154 + for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 1.155 + if (extractAlpha) { 1.156 + dst[0] = SkGetPackedA32(src[x]); 1.157 + *isOpaque &= dst[0] == SK_AlphaOPAQUE; 1.158 + *isTransparent &= dst[0] == SK_AlphaTRANSPARENT; 1.159 + dst++; 1.160 + } else { 1.161 + dst[0] = SkGetPackedR32(src[x]); 1.162 + dst[1] = SkGetPackedG32(src[x]); 1.163 + dst[2] = SkGetPackedB32(src[x]); 1.164 + dst += 3; 1.165 + } 1.166 + } 1.167 + } 1.168 + return stream; 1.169 +} 1.170 + 1.171 +static SkStream* extract_a8_alpha(const SkBitmap& bitmap, 1.172 + const SkIRect& srcRect, 1.173 + bool* isOpaque, 1.174 + bool* isTransparent) { 1.175 + const int alphaRowBytes = srcRect.width(); 1.176 + SkStream* stream = SkNEW_ARGS(SkMemoryStream, 1.177 + (alphaRowBytes * srcRect.height())); 1.178 + uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase(); 1.179 + 1.180 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.181 + uint8_t* src = bitmap.getAddr8(0, y); 1.182 + for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 1.183 + alphaDst[0] = src[x]; 1.184 + *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE; 1.185 + *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT; 1.186 + alphaDst++; 1.187 + } 1.188 + } 1.189 + return stream; 1.190 +} 1.191 + 1.192 +static SkStream* create_black_image() { 1.193 + SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1)); 1.194 + ((uint8_t*)stream->getMemoryBase())[0] = 0; 1.195 + return stream; 1.196 +} 1.197 + 1.198 +/** 1.199 + * Extract either the color or image data from a SkBitmap into a SkStream. 1.200 + * @param bitmap Bitmap to extract data from. 1.201 + * @param srcRect Region in the bitmap to extract. 1.202 + * @param extractAlpha Set to true to extract the alpha data or false to 1.203 + * extract the color data. 1.204 + * @param isTransparent Pointer to a bool to output whether the alpha is 1.205 + * completely transparent. May be NULL. Only valid when 1.206 + * extractAlpha == true. 1.207 + * @return Unencoded image data, or NULL if either data was not 1.208 + * available or alpha data was requested but the image was 1.209 + * entirely transparent or opaque. 1.210 + */ 1.211 +static SkStream* extract_image_data(const SkBitmap& bitmap, 1.212 + const SkIRect& srcRect, 1.213 + bool extractAlpha, bool* isTransparent) { 1.214 + SkBitmap::Config config = bitmap.config(); 1.215 + if (extractAlpha && (config == SkBitmap::kIndex8_Config || 1.216 + config == SkBitmap::kRGB_565_Config)) { 1.217 + if (isTransparent != NULL) { 1.218 + *isTransparent = false; 1.219 + } 1.220 + return NULL; 1.221 + } 1.222 + bool isOpaque = true; 1.223 + bool transparent = extractAlpha; 1.224 + SkStream* stream = NULL; 1.225 + 1.226 + bitmap.lockPixels(); 1.227 + switch (config) { 1.228 + case SkBitmap::kIndex8_Config: 1.229 + if (!extractAlpha) { 1.230 + stream = extract_index8_image(bitmap, srcRect); 1.231 + } 1.232 + break; 1.233 + case SkBitmap::kARGB_4444_Config: 1.234 + stream = extract_argb4444_data(bitmap, srcRect, extractAlpha, 1.235 + &isOpaque, &transparent); 1.236 + break; 1.237 + case SkBitmap::kRGB_565_Config: 1.238 + if (!extractAlpha) { 1.239 + stream = extract_rgb565_image(bitmap, srcRect); 1.240 + } 1.241 + break; 1.242 + case SkBitmap::kARGB_8888_Config: 1.243 + stream = extract_argb8888_data(bitmap, srcRect, extractAlpha, 1.244 + &isOpaque, &transparent); 1.245 + break; 1.246 + case SkBitmap::kA8_Config: 1.247 + if (!extractAlpha) { 1.248 + stream = create_black_image(); 1.249 + } else { 1.250 + stream = extract_a8_alpha(bitmap, srcRect, 1.251 + &isOpaque, &transparent); 1.252 + } 1.253 + break; 1.254 + default: 1.255 + SkASSERT(false); 1.256 + } 1.257 + bitmap.unlockPixels(); 1.258 + 1.259 + if (isTransparent != NULL) { 1.260 + *isTransparent = transparent; 1.261 + } 1.262 + if (extractAlpha && (transparent || isOpaque)) { 1.263 + SkSafeUnref(stream); 1.264 + return NULL; 1.265 + } 1.266 + return stream; 1.267 +} 1.268 + 1.269 +static SkPDFArray* make_indexed_color_space(SkColorTable* table) { 1.270 + SkPDFArray* result = new SkPDFArray(); 1.271 + result->reserve(4); 1.272 + result->appendName("Indexed"); 1.273 + result->appendName("DeviceRGB"); 1.274 + result->appendInt(table->count() - 1); 1.275 + 1.276 + // Potentially, this could be represented in fewer bytes with a stream. 1.277 + // Max size as a string is 1.5k. 1.278 + SkString index; 1.279 + for (int i = 0; i < table->count(); i++) { 1.280 + char buf[3]; 1.281 + SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); 1.282 + buf[0] = SkGetPackedR32(color); 1.283 + buf[1] = SkGetPackedG32(color); 1.284 + buf[2] = SkGetPackedB32(color); 1.285 + index.append(buf, 3); 1.286 + } 1.287 + result->append(new SkPDFString(index))->unref(); 1.288 + return result; 1.289 +} 1.290 + 1.291 +/** 1.292 + * Removes the alpha component of an ARGB color (including unpremultiply) while 1.293 + * keeping the output in the same format as the input. 1.294 + */ 1.295 +static uint32_t remove_alpha_argb8888(uint32_t pmColor) { 1.296 + SkColor color = SkUnPreMultiply::PMColorToColor(pmColor); 1.297 + return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 1.298 + SkColorGetR(color), 1.299 + SkColorGetG(color), 1.300 + SkColorGetB(color)); 1.301 +} 1.302 + 1.303 +static uint16_t remove_alpha_argb4444(uint16_t pmColor) { 1.304 + return SkPixel32ToPixel4444( 1.305 + remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor))); 1.306 +} 1.307 + 1.308 +static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap, 1.309 + int xOrig, int yOrig) { 1.310 + uint8_t count = 0; 1.311 + uint16_t r = 0; 1.312 + uint16_t g = 0; 1.313 + uint16_t b = 0; 1.314 + 1.315 + for (int y = yOrig - 1; y <= yOrig + 1; y++) { 1.316 + if (y < 0 || y >= bitmap.height()) { 1.317 + continue; 1.318 + } 1.319 + uint32_t* src = bitmap.getAddr32(0, y); 1.320 + for (int x = xOrig - 1; x <= xOrig + 1; x++) { 1.321 + if (x < 0 || x >= bitmap.width()) { 1.322 + continue; 1.323 + } 1.324 + if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) { 1.325 + uint32_t color = remove_alpha_argb8888(src[x]); 1.326 + r += SkGetPackedR32(color); 1.327 + g += SkGetPackedG32(color); 1.328 + b += SkGetPackedB32(color); 1.329 + count++; 1.330 + } 1.331 + } 1.332 + } 1.333 + 1.334 + if (count == 0) { 1.335 + return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); 1.336 + } else { 1.337 + return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 1.338 + r / count, g / count, b / count); 1.339 + } 1.340 +} 1.341 + 1.342 +static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap, 1.343 + int xOrig, int yOrig) { 1.344 + uint8_t count = 0; 1.345 + uint8_t r = 0; 1.346 + uint8_t g = 0; 1.347 + uint8_t b = 0; 1.348 + 1.349 + for (int y = yOrig - 1; y <= yOrig + 1; y++) { 1.350 + if (y < 0 || y >= bitmap.height()) { 1.351 + continue; 1.352 + } 1.353 + uint16_t* src = bitmap.getAddr16(0, y); 1.354 + for (int x = xOrig - 1; x <= xOrig + 1; x++) { 1.355 + if (x < 0 || x >= bitmap.width()) { 1.356 + continue; 1.357 + } 1.358 + if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) { 1.359 + uint16_t color = remove_alpha_argb4444(src[x]); 1.360 + r += SkGetPackedR4444(color); 1.361 + g += SkGetPackedG4444(color); 1.362 + b += SkGetPackedB4444(color); 1.363 + count++; 1.364 + } 1.365 + } 1.366 + } 1.367 + 1.368 + if (count == 0) { 1.369 + return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); 1.370 + } else { 1.371 + return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 1.372 + r / count, g / count, b / count); 1.373 + } 1.374 +} 1.375 + 1.376 +static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, 1.377 + const SkIRect& srcRect) { 1.378 + SkBitmap outBitmap; 1.379 + outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height()); 1.380 + outBitmap.allocPixels(); 1.381 + int dstRow = 0; 1.382 + 1.383 + outBitmap.lockPixels(); 1.384 + bitmap.lockPixels(); 1.385 + switch (bitmap.config()) { 1.386 + case SkBitmap::kARGB_4444_Config: { 1.387 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.388 + uint16_t* dst = outBitmap.getAddr16(0, dstRow); 1.389 + uint16_t* src = bitmap.getAddr16(0, y); 1.390 + for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 1.391 + uint8_t a = SkGetPackedA4444(src[x]); 1.392 + // It is necessary to average the color component of 1.393 + // transparent pixels with their surrounding neighbors 1.394 + // since the PDF renderer may separately re-sample the 1.395 + // alpha and color channels when the image is not 1.396 + // displayed at its native resolution. Since an alpha of 1.397 + // zero gives no information about the color component, 1.398 + // the pathological case is a white image with sharp 1.399 + // transparency bounds - the color channel goes to black, 1.400 + // and the should-be-transparent pixels are rendered 1.401 + // as grey because of the separate soft mask and color 1.402 + // resizing. 1.403 + if (a == (SK_AlphaTRANSPARENT & 0x0F)) { 1.404 + *dst = get_argb4444_neighbor_avg_color(bitmap, x, y); 1.405 + } else { 1.406 + *dst = remove_alpha_argb4444(src[x]); 1.407 + } 1.408 + dst++; 1.409 + } 1.410 + dstRow++; 1.411 + } 1.412 + break; 1.413 + } 1.414 + case SkBitmap::kARGB_8888_Config: { 1.415 + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 1.416 + uint32_t* dst = outBitmap.getAddr32(0, dstRow); 1.417 + uint32_t* src = bitmap.getAddr32(0, y); 1.418 + for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 1.419 + uint8_t a = SkGetPackedA32(src[x]); 1.420 + if (a == SK_AlphaTRANSPARENT) { 1.421 + *dst = get_argb8888_neighbor_avg_color(bitmap, x, y); 1.422 + } else { 1.423 + *dst = remove_alpha_argb8888(src[x]); 1.424 + } 1.425 + dst++; 1.426 + } 1.427 + dstRow++; 1.428 + } 1.429 + break; 1.430 + } 1.431 + default: 1.432 + SkASSERT(false); 1.433 + } 1.434 + bitmap.unlockPixels(); 1.435 + outBitmap.unlockPixels(); 1.436 + 1.437 + outBitmap.setImmutable(); 1.438 + 1.439 + return outBitmap; 1.440 +} 1.441 + 1.442 +// static 1.443 +SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 1.444 + const SkIRect& srcRect, 1.445 + SkPicture::EncodeBitmap encoder) { 1.446 + if (bitmap.config() == SkBitmap::kNo_Config) { 1.447 + return NULL; 1.448 + } 1.449 + 1.450 + bool isTransparent = false; 1.451 + SkAutoTUnref<SkStream> alphaData; 1.452 + if (!bitmap.isOpaque()) { 1.453 + // Note that isOpaque is not guaranteed to return false for bitmaps 1.454 + // with alpha support but a completely opaque alpha channel, 1.455 + // so alphaData may still be NULL if we have a completely opaque 1.456 + // (or transparent) bitmap. 1.457 + alphaData.reset( 1.458 + extract_image_data(bitmap, srcRect, true, &isTransparent)); 1.459 + } 1.460 + if (isTransparent) { 1.461 + return NULL; 1.462 + } 1.463 + 1.464 + SkPDFImage* image; 1.465 + SkBitmap::Config config = bitmap.config(); 1.466 + if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config || 1.467 + config == SkBitmap::kARGB_4444_Config)) { 1.468 + SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); 1.469 + image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false, 1.470 + SkIRect::MakeWH(srcRect.width(), srcRect.height()), 1.471 + encoder)); 1.472 + } else { 1.473 + image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); 1.474 + } 1.475 + if (alphaData.get() != NULL) { 1.476 + SkAutoTUnref<SkPDFImage> mask( 1.477 + SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, 1.478 + true, srcRect, NULL))); 1.479 + image->addSMask(mask); 1.480 + } 1.481 + 1.482 + return image; 1.483 +} 1.484 + 1.485 +SkPDFImage::~SkPDFImage() { 1.486 + fResources.unrefAll(); 1.487 +} 1.488 + 1.489 +SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 1.490 + fResources.push(mask); 1.491 + mask->ref(); 1.492 + insert("SMask", new SkPDFObjRef(mask))->unref(); 1.493 + return mask; 1.494 +} 1.495 + 1.496 +void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 1.497 + SkTSet<SkPDFObject*>* newResourceObjects) { 1.498 + GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); 1.499 +} 1.500 + 1.501 +SkPDFImage::SkPDFImage(SkStream* stream, 1.502 + const SkBitmap& bitmap, 1.503 + bool isAlpha, 1.504 + const SkIRect& srcRect, 1.505 + SkPicture::EncodeBitmap encoder) 1.506 + : fIsAlpha(isAlpha), 1.507 + fSrcRect(srcRect), 1.508 + fEncoder(encoder) { 1.509 + 1.510 + if (bitmap.isImmutable()) { 1.511 + fBitmap = bitmap; 1.512 + } else { 1.513 + bitmap.deepCopyTo(&fBitmap); 1.514 + fBitmap.setImmutable(); 1.515 + } 1.516 + 1.517 + if (stream != NULL) { 1.518 + setData(stream); 1.519 + fStreamValid = true; 1.520 + } else { 1.521 + fStreamValid = false; 1.522 + } 1.523 + 1.524 + SkBitmap::Config config = fBitmap.config(); 1.525 + 1.526 + insertName("Type", "XObject"); 1.527 + insertName("Subtype", "Image"); 1.528 + 1.529 + bool alphaOnly = (config == SkBitmap::kA8_Config); 1.530 + 1.531 + if (!isAlpha && alphaOnly) { 1.532 + // For alpha only images, we stretch a single pixel of black for 1.533 + // the color/shape part. 1.534 + SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); 1.535 + insert("Width", one.get()); 1.536 + insert("Height", one.get()); 1.537 + } else { 1.538 + insertInt("Width", fSrcRect.width()); 1.539 + insertInt("Height", fSrcRect.height()); 1.540 + } 1.541 + 1.542 + if (isAlpha || alphaOnly) { 1.543 + insertName("ColorSpace", "DeviceGray"); 1.544 + } else if (config == SkBitmap::kIndex8_Config) { 1.545 + SkAutoLockPixels alp(fBitmap); 1.546 + insert("ColorSpace", 1.547 + make_indexed_color_space(fBitmap.getColorTable()))->unref(); 1.548 + } else { 1.549 + insertName("ColorSpace", "DeviceRGB"); 1.550 + } 1.551 + 1.552 + int bitsPerComp = 8; 1.553 + if (config == SkBitmap::kARGB_4444_Config) { 1.554 + bitsPerComp = 4; 1.555 + } 1.556 + insertInt("BitsPerComponent", bitsPerComp); 1.557 + 1.558 + if (config == SkBitmap::kRGB_565_Config) { 1.559 + SkASSERT(!isAlpha); 1.560 + SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); 1.561 + SkAutoTUnref<SkPDFScalar> scale5Val( 1.562 + new SkPDFScalar(8.2258f)); // 255/2^5-1 1.563 + SkAutoTUnref<SkPDFScalar> scale6Val( 1.564 + new SkPDFScalar(4.0476f)); // 255/2^6-1 1.565 + SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); 1.566 + decodeValue->reserve(6); 1.567 + decodeValue->append(zeroVal.get()); 1.568 + decodeValue->append(scale5Val.get()); 1.569 + decodeValue->append(zeroVal.get()); 1.570 + decodeValue->append(scale6Val.get()); 1.571 + decodeValue->append(zeroVal.get()); 1.572 + decodeValue->append(scale5Val.get()); 1.573 + insert("Decode", decodeValue.get()); 1.574 + } 1.575 +} 1.576 + 1.577 +SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) 1.578 + : SkPDFStream(pdfImage), 1.579 + fBitmap(pdfImage.fBitmap), 1.580 + fIsAlpha(pdfImage.fIsAlpha), 1.581 + fSrcRect(pdfImage.fSrcRect), 1.582 + fEncoder(pdfImage.fEncoder), 1.583 + fStreamValid(pdfImage.fStreamValid) { 1.584 + // Nothing to do here - the image params are already copied in SkPDFStream's 1.585 + // constructor, and the bitmap will be regenerated and encoded in 1.586 + // populate. 1.587 +} 1.588 + 1.589 +bool SkPDFImage::populate(SkPDFCatalog* catalog) { 1.590 + if (getState() == kUnused_State) { 1.591 + // Initializing image data for the first time. 1.592 + SkDynamicMemoryWStream dctCompressedWStream; 1.593 + if (!skip_compression(catalog) && fEncoder && 1.594 + get_uncompressed_size(fBitmap, fSrcRect) > 1) { 1.595 + SkBitmap subset; 1.596 + // Extract subset 1.597 + if (!fBitmap.extractSubset(&subset, fSrcRect)) { 1.598 + // TODO(edisonn) It fails only for kA1_Config, if that is a 1.599 + // major concern we will fix it later, so far it is NYI. 1.600 + return false; 1.601 + } 1.602 + size_t pixelRefOffset = 0; 1.603 + SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset)); 1.604 + if (data.get() && data->size() < get_uncompressed_size(fBitmap, 1.605 + fSrcRect)) { 1.606 + SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, 1.607 + (data))); 1.608 + setData(stream.get()); 1.609 + 1.610 + insertName("Filter", "DCTDecode"); 1.611 + insertInt("ColorTransform", kNoColorTransform); 1.612 + insertInt("Length", getData()->getLength()); 1.613 + setState(kCompressed_State); 1.614 + return true; 1.615 + } 1.616 + } 1.617 + // Fallback method 1.618 + if (!fStreamValid) { 1.619 + SkAutoTUnref<SkStream> stream( 1.620 + extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL)); 1.621 + setData(stream); 1.622 + fStreamValid = true; 1.623 + } 1.624 + return INHERITED::populate(catalog); 1.625 + } else if (getState() == kNoCompression_State && 1.626 + !skip_compression(catalog) && 1.627 + (SkFlate::HaveFlate() || fEncoder)) { 1.628 + // Compression has not been requested when the stream was first created, 1.629 + // but the new catalog wants it compressed. 1.630 + if (!getSubstitute()) { 1.631 + SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); 1.632 + setSubstitute(substitute); 1.633 + catalog->setSubstitute(this, substitute); 1.634 + } 1.635 + return false; 1.636 + } 1.637 + return true; 1.638 +}