gfx/skia/trunk/src/pdf/SkPDFImage.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial