Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: src/pdf/SkPDFImage.cpp

Issue 950633003: PDF: remove last use of SkPDFImage (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-02-21 (Saturday) 10:55:02 EST Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/pdf/SkPDFBitmap.cpp ('K') | « src/pdf/SkPDFImage.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "SkPDFBitmap.h"
16 #include "SkPDFCatalog.h"
17 #include "SkPixelRef.h"
18 #include "SkRect.h"
19 #include "SkStream.h"
20 #include "SkString.h"
21 #include "SkUnPreMultiply.h"
22
23 static size_t get_uncompressed_size(const SkBitmap& bitmap,
24 const SkIRect& srcRect) {
25 switch (bitmap.colorType()) {
26 case kIndex_8_SkColorType:
27 return srcRect.width() * srcRect.height();
28 case kARGB_4444_SkColorType:
29 return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
30 case kRGB_565_SkColorType:
31 return srcRect.width() * 3 * srcRect.height();
32 case kRGBA_8888_SkColorType:
33 case kBGRA_8888_SkColorType:
34 return srcRect.width() * 3 * srcRect.height();
35 case kAlpha_8_SkColorType:
36 return 1;
37 default:
38 SkASSERT(false);
39 return 0;
40 }
41 }
42
43 static SkStream* extract_index8_image(const SkBitmap& bitmap,
44 const SkIRect& srcRect) {
45 const int rowBytes = srcRect.width();
46 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
47 (get_uncompressed_size(bitmap, srcRect)));
48 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
49
50 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
51 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
52 dst += rowBytes;
53 }
54 return stream;
55 }
56
57 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
58 const SkIRect& srcRect,
59 bool extractAlpha,
60 bool* isOpaque,
61 bool* isTransparent) {
62 SkStream* stream;
63 uint8_t* dst = NULL;
64 if (extractAlpha) {
65 const int alphaRowBytes = (srcRect.width() + 1) / 2;
66 stream = SkNEW_ARGS(SkMemoryStream,
67 (alphaRowBytes * srcRect.height()));
68 } else {
69 stream = SkNEW_ARGS(SkMemoryStream,
70 (get_uncompressed_size(bitmap, srcRect)));
71 }
72 dst = (uint8_t*)stream->getMemoryBase();
73
74 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
75 uint16_t* src = bitmap.getAddr16(0, y);
76 int x;
77 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
78 if (extractAlpha) {
79 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
80 SkGetPackedA4444(src[x + 1]);
81 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
82 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
83 dst++;
84 } else {
85 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
86 SkGetPackedG4444(src[x]);
87 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
88 SkGetPackedR4444(src[x + 1]);
89 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
90 SkGetPackedB4444(src[x + 1]);
91 dst += 3;
92 }
93 }
94 if (srcRect.width() & 1) {
95 if (extractAlpha) {
96 dst[0] = (SkGetPackedA4444(src[x]) << 4);
97 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
98 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
99 dst++;
100
101 } else {
102 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
103 SkGetPackedG4444(src[x]);
104 dst[1] = (SkGetPackedB4444(src[x]) << 4);
105 dst += 2;
106 }
107 }
108 }
109 return stream;
110 }
111
112 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
113 const SkIRect& srcRect) {
114 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
115 (get_uncompressed_size(bitmap,
116 srcRect)));
117 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
118 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
119 uint16_t* src = bitmap.getAddr16(0, y);
120 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
121 dst[0] = SkGetPackedR16(src[x]);
122 dst[1] = SkGetPackedG16(src[x]);
123 dst[2] = SkGetPackedB16(src[x]);
124 dst += 3;
125 }
126 }
127 return stream;
128 }
129
130 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
131 int xOrig,
132 int yOrig);
133
134 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
135 const SkIRect& srcRect,
136 bool extractAlpha,
137 bool* isOpaque,
138 bool* isTransparent) {
139 size_t streamSize = extractAlpha ? srcRect.width() * srcRect.height()
140 : get_uncompressed_size(bitmap, srcRect);
141 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (streamSize));
142 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
143
144 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
145
146 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
147 uint32_t* src = bitmap.getAddr32(0, y);
148 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
149 SkPMColor c = src[x];
150 U8CPU alpha = SkGetPackedA32(c);
151 if (extractAlpha) {
152 *isOpaque &= alpha == SK_AlphaOPAQUE;
153 *isTransparent &= alpha == SK_AlphaTRANSPARENT;
154 *dst++ = alpha;
155 } else {
156 if (SK_AlphaTRANSPARENT == alpha) {
157 // It is necessary to average the color component of
158 // transparent pixels with their surrounding neighbors
159 // since the PDF renderer may separately re-sample the
160 // alpha and color channels when the image is not
161 // displayed at its native resolution. Since an alpha of
162 // zero gives no information about the color component,
163 // the pathological case is a white image with sharp
164 // transparency bounds - the color channel goes to black,
165 // and the should-be-transparent pixels are rendered
166 // as grey because of the separate soft mask and color
167 // resizing.
168 c = get_argb8888_neighbor_avg_color(bitmap, x, y);
169 *dst++ = SkGetPackedR32(c);
170 *dst++ = SkGetPackedG32(c);
171 *dst++ = SkGetPackedB32(c);
172 } else {
173 SkUnPreMultiply::Scale s = scaleTable[alpha];
174 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
175 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(c));
176 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
177 }
178 }
179 }
180 }
181 SkASSERT(dst == streamSize + (uint8_t*)stream->getMemoryBase());
182 return stream;
183 }
184
185 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
186 const SkIRect& srcRect,
187 bool* isOpaque,
188 bool* isTransparent) {
189 const int alphaRowBytes = srcRect.width();
190 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
191 (alphaRowBytes * srcRect.height()));
192 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
193
194 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
195 uint8_t* src = bitmap.getAddr8(0, y);
196 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
197 alphaDst[0] = src[x];
198 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
199 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
200 alphaDst++;
201 }
202 }
203 return stream;
204 }
205
206 static SkStream* create_black_image() {
207 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
208 ((uint8_t*)stream->getMemoryBase())[0] = 0;
209 return stream;
210 }
211
212 /**
213 * Extract either the color or image data from a SkBitmap into a SkStream.
214 * @param bitmap Bitmap to extract data from.
215 * @param srcRect Region in the bitmap to extract.
216 * @param extractAlpha Set to true to extract the alpha data or false to
217 * extract the color data.
218 * @param isTransparent Pointer to a bool to output whether the alpha is
219 * completely transparent. May be NULL. Only valid when
220 * extractAlpha == true.
221 * @return Unencoded image data, or NULL if either data was not
222 * available or alpha data was requested but the image was
223 * entirely transparent or opaque.
224 */
225 static SkStream* extract_image_data(const SkBitmap& bitmap,
226 const SkIRect& srcRect,
227 bool extractAlpha, bool* isTransparent) {
228 SkColorType colorType = bitmap.colorType();
229 if (extractAlpha && (kIndex_8_SkColorType == colorType ||
230 kRGB_565_SkColorType == colorType)) {
231 if (isTransparent != NULL) {
232 *isTransparent = false;
233 }
234 return NULL;
235 }
236
237 SkAutoLockPixels lock(bitmap);
238 if (NULL == bitmap.getPixels()) {
239 return NULL;
240 }
241
242 bool isOpaque = true;
243 bool transparent = extractAlpha;
244 SkAutoTDelete<SkStream> stream;
245
246 switch (colorType) {
247 case kIndex_8_SkColorType:
248 if (!extractAlpha) {
249 stream.reset(extract_index8_image(bitmap, srcRect));
250 }
251 break;
252 case kARGB_4444_SkColorType:
253 stream.reset(extract_argb4444_data(bitmap, srcRect, extractAlpha,
254 &isOpaque, &transparent));
255 break;
256 case kRGB_565_SkColorType:
257 if (!extractAlpha) {
258 stream.reset(extract_rgb565_image(bitmap, srcRect));
259 }
260 break;
261 case kN32_SkColorType:
262 stream.reset(extract_argb8888_data(bitmap, srcRect, extractAlpha,
263 &isOpaque, &transparent));
264 break;
265 case kAlpha_8_SkColorType:
266 if (!extractAlpha) {
267 stream.reset(create_black_image());
268 } else {
269 stream.reset(extract_a8_alpha(bitmap, srcRect,
270 &isOpaque, &transparent));
271 }
272 break;
273 default:
274 SkASSERT(false);
275 }
276
277 if (isTransparent != NULL) {
278 *isTransparent = transparent;
279 }
280 if (extractAlpha && (transparent || isOpaque)) {
281 return NULL;
282 }
283 return stream.detach();
284 }
285
286 static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
287 SkPDFArray* result = new SkPDFArray();
288 result->reserve(4);
289 result->appendName("Indexed");
290 result->appendName("DeviceRGB");
291 result->appendInt(table->count() - 1);
292
293 // Potentially, this could be represented in fewer bytes with a stream.
294 // Max size as a string is 1.5k.
295 SkString index;
296 for (int i = 0; i < table->count(); i++) {
297 char buf[3];
298 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
299 buf[0] = SkGetPackedR32(color);
300 buf[1] = SkGetPackedG32(color);
301 buf[2] = SkGetPackedB32(color);
302 index.append(buf, 3);
303 }
304 result->append(new SkPDFString(index))->unref();
305 return result;
306 }
307
308 /**
309 * Removes the alpha component of an ARGB color (including unpremultiply) while
310 * keeping the output in the same format as the input.
311 */
312 static uint32_t remove_alpha_argb8888(uint32_t pmColor) {
313 SkColor color = SkUnPreMultiply::PMColorToColor(pmColor);
314 return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
315 SkColorGetR(color),
316 SkColorGetG(color),
317 SkColorGetB(color));
318 }
319
320 static uint16_t remove_alpha_argb4444(uint16_t pmColor) {
321 return SkPixel32ToPixel4444(
322 remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor)));
323 }
324
325 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
326 int xOrig, int yOrig) {
327 uint8_t count = 0;
328 uint16_t r = 0;
329 uint16_t g = 0;
330 uint16_t b = 0;
331
332 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
333 if (y < 0 || y >= bitmap.height()) {
334 continue;
335 }
336 uint32_t* src = bitmap.getAddr32(0, y);
337 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
338 if (x < 0 || x >= bitmap.width()) {
339 continue;
340 }
341 if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) {
342 uint32_t color = remove_alpha_argb8888(src[x]);
343 r += SkGetPackedR32(color);
344 g += SkGetPackedG32(color);
345 b += SkGetPackedB32(color);
346 count++;
347 }
348 }
349 }
350
351 if (count == 0) {
352 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
353 } else {
354 return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
355 r / count, g / count, b / count);
356 }
357 }
358
359 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap,
360 int xOrig, int yOrig) {
361 uint8_t count = 0;
362 uint8_t r = 0;
363 uint8_t g = 0;
364 uint8_t b = 0;
365
366 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
367 if (y < 0 || y >= bitmap.height()) {
368 continue;
369 }
370 uint16_t* src = bitmap.getAddr16(0, y);
371 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
372 if (x < 0 || x >= bitmap.width()) {
373 continue;
374 }
375 if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) {
376 uint16_t color = remove_alpha_argb4444(src[x]);
377 r += SkGetPackedR4444(color);
378 g += SkGetPackedG4444(color);
379 b += SkGetPackedB4444(color);
380 count++;
381 }
382 }
383 }
384
385 if (count == 0) {
386 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
387 } else {
388 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
389 r / count, g / count, b / count);
390 }
391 }
392
393 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
394 const SkIRect& srcRect) {
395 SkBitmap outBitmap;
396 outBitmap.allocPixels(bitmap.info().makeWH(srcRect.width(), srcRect.height() ));
397 int dstRow = 0;
398
399 SkAutoLockPixels outBitmapPixelLock(outBitmap);
400 SkAutoLockPixels bitmapPixelLock(bitmap);
401 switch (bitmap.colorType()) {
402 case kARGB_4444_SkColorType: {
403 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
404 uint16_t* dst = outBitmap.getAddr16(0, dstRow);
405 uint16_t* src = bitmap.getAddr16(0, y);
406 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
407 uint8_t a = SkGetPackedA4444(src[x]);
408 // It is necessary to average the color component of
409 // transparent pixels with their surrounding neighbors
410 // since the PDF renderer may separately re-sample the
411 // alpha and color channels when the image is not
412 // displayed at its native resolution. Since an alpha of
413 // zero gives no information about the color component,
414 // the pathological case is a white image with sharp
415 // transparency bounds - the color channel goes to black,
416 // and the should-be-transparent pixels are rendered
417 // as grey because of the separate soft mask and color
418 // resizing.
419 if (a == (SK_AlphaTRANSPARENT & 0x0F)) {
420 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y);
421 } else {
422 *dst = remove_alpha_argb4444(src[x]);
423 }
424 dst++;
425 }
426 dstRow++;
427 }
428 break;
429 }
430 case kN32_SkColorType: {
431 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
432 uint32_t* dst = outBitmap.getAddr32(0, dstRow);
433 uint32_t* src = bitmap.getAddr32(0, y);
434 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
435 uint8_t a = SkGetPackedA32(src[x]);
436 if (a == SK_AlphaTRANSPARENT) {
437 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y);
438 } else {
439 *dst = remove_alpha_argb8888(src[x]);
440 }
441 dst++;
442 }
443 dstRow++;
444 }
445 break;
446 }
447 default:
448 SkASSERT(false);
449 }
450
451 outBitmap.setImmutable();
452
453 return outBitmap;
454 }
455
456 // static
457 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
458 const SkIRect& srcRect) {
459 if (bitmap.colorType() == kUnknown_SkColorType) {
460 return NULL;
461 }
462
463 bool isTransparent = false;
464 SkAutoTDelete<SkStream> alphaData;
465 if (!bitmap.isOpaque()) {
466 // Note that isOpaque is not guaranteed to return false for bitmaps
467 // with alpha support but a completely opaque alpha channel,
468 // so alphaData may still be NULL if we have a completely opaque
469 // (or transparent) bitmap.
470 alphaData.reset(
471 extract_image_data(bitmap, srcRect, true, &isTransparent));
472 }
473 if (isTransparent) {
474 return NULL;
475 }
476
477 SkPDFImage* image;
478 SkColorType colorType = bitmap.colorType();
479 if (alphaData.get() != NULL && (kN32_SkColorType == colorType ||
480 kARGB_4444_SkColorType == colorType)) {
481 if (kN32_SkColorType == colorType) {
482 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false,
483 SkIRect::MakeWH(srcRect.width(),
484 srcRect.height())));
485 } else {
486 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
487 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false,
488 SkIRect::MakeWH(srcRect.width(),
489 srcRect.height())));
490 }
491 } else {
492 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect));
493 }
494 if (alphaData.get() != NULL) {
495 SkAutoTUnref<SkPDFImage> mask(
496 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, true, srcRect)) );
497 image->insert("SMask", new SkPDFObjRef(mask))->unref();
498 }
499 return image;
500 }
501
502 SkPDFImage::~SkPDFImage() {}
503
504 SkPDFImage::SkPDFImage(SkStream* stream,
505 const SkBitmap& bitmap,
506 bool isAlpha,
507 const SkIRect& srcRect)
508 : fIsAlpha(isAlpha),
509 fSrcRect(srcRect) {
510
511 if (bitmap.isImmutable()) {
512 fBitmap = bitmap;
513 } else {
514 bitmap.deepCopyTo(&fBitmap);
515 fBitmap.setImmutable();
516 }
517
518 if (stream != NULL) {
519 this->setData(stream);
520 fStreamValid = true;
521 } else {
522 fStreamValid = false;
523 }
524
525 SkColorType colorType = fBitmap.colorType();
526
527 insertName("Type", "XObject");
528 insertName("Subtype", "Image");
529
530 bool alphaOnly = (kAlpha_8_SkColorType == colorType);
531
532 if (!isAlpha && alphaOnly) {
533 // For alpha only images, we stretch a single pixel of black for
534 // the color/shape part.
535 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
536 insert("Width", one.get());
537 insert("Height", one.get());
538 } else {
539 insertInt("Width", fSrcRect.width());
540 insertInt("Height", fSrcRect.height());
541 }
542
543 if (isAlpha || alphaOnly) {
544 insertName("ColorSpace", "DeviceGray");
545 } else if (kIndex_8_SkColorType == colorType) {
546 SkAutoLockPixels alp(fBitmap);
547 insert("ColorSpace",
548 make_indexed_color_space(fBitmap.getColorTable()))->unref();
549 } else {
550 insertName("ColorSpace", "DeviceRGB");
551 }
552
553 int bitsPerComp = 8;
554 if (kARGB_4444_SkColorType == colorType) {
555 bitsPerComp = 4;
556 }
557 insertInt("BitsPerComponent", bitsPerComp);
558
559 if (kRGB_565_SkColorType == colorType) {
560 SkASSERT(!isAlpha);
561 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
562 SkAutoTUnref<SkPDFScalar> scale5Val(
563 new SkPDFScalar(8.2258f)); // 255/2^5-1
564 SkAutoTUnref<SkPDFScalar> scale6Val(
565 new SkPDFScalar(4.0476f)); // 255/2^6-1
566 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
567 decodeValue->reserve(6);
568 decodeValue->append(zeroVal.get());
569 decodeValue->append(scale5Val.get());
570 decodeValue->append(zeroVal.get());
571 decodeValue->append(scale6Val.get());
572 decodeValue->append(zeroVal.get());
573 decodeValue->append(scale5Val.get());
574 insert("Decode", decodeValue.get());
575 }
576 }
577
578 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
579 : SkPDFStream(pdfImage),
580 fBitmap(pdfImage.fBitmap),
581 fIsAlpha(pdfImage.fIsAlpha),
582 fSrcRect(pdfImage.fSrcRect),
583 fStreamValid(pdfImage.fStreamValid) {
584 // Nothing to do here - the image params are already copied in SkPDFStream's
585 // constructor, and the bitmap will be regenerated and encoded in
586 // populate.
587 }
588
589 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
590 if (getState() == kUnused_State) {
591 // Initializing image data for the first time.
592 // Fallback method
593 if (!fStreamValid) {
594 SkAutoTDelete<SkStream> stream(
595 extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
596 this->setData(stream);
597 fStreamValid = true;
598 }
599 return INHERITED::populate(catalog);
600 }
601 #ifndef SK_NO_FLATE
602 else if (getState() == kNoCompression_State) {
603 // Compression has not been requested when the stream was first created,
604 // but the new catalog wants it compressed.
605 if (!getSubstitute()) {
606 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
607 setSubstitute(substitute);
608 catalog->setSubstitute(this, substitute);
609 }
610 return false;
611 }
612 #endif // SK_NO_FLATE
613 return true;
614 }
615
616 #if 0 // reenable when we can figure out the JPEG colorspace
617 namespace {
618 /**
619 * This PDFObject assumes that its constructor was handed
620 * Jpeg-encoded data that can be directly embedded into a PDF.
621 */
622 class PDFJPEGImage : public SkPDFObject {
623 SkAutoTUnref<SkData> fData;
624 int fWidth;
625 int fHeight;
626 public:
627 PDFJPEGImage(SkData* data, int width, int height)
628 : fData(SkRef(data)), fWidth(width), fHeight(height) {}
629 virtual void emitObject(
630 SkWStream* stream,
631 SkPDFCatalog* catalog, bool indirect) SK_OVERRIDE {
632 if (indirect) {
633 this->emitIndirectObject(stream, catalog);
634 return;
635 }
636 SkASSERT(fData.get());
637 const char kPrefaceFormat[] =
638 "<<"
639 "/Type /XObject\n"
640 "/Subtype /Image\n"
641 "/Width %d\n"
642 "/Height %d\n"
643 "/ColorSpace /DeviceRGB\n" // or DeviceGray
644 "/BitsPerComponent 8\n"
645 "/Filter /DCTDecode\n"
646 "/ColorTransform 0\n"
647 "/Length " SK_SIZE_T_SPECIFIER "\n"
648 ">> stream\n";
649 SkString preface(
650 SkStringPrintf(kPrefaceFormat, fWidth, fHeight, fData->size()));
651 const char kPostface[] = "\nendstream";
652 stream->write(preface.c_str(), preface.size());
653 stream->write(fData->data(), fData->size());
654 stream->write(kPostface, sizeof(kPostface));
655 }
656 };
657
658 /**
659 * If the bitmap is not subsetted, return its encoded data, if
660 * availible.
661 */
662 static inline SkData* ref_encoded_data(const SkBitmap& bm) {
663 if ((NULL == bm.pixelRef())
664 || !bm.pixelRefOrigin().isZero()
665 || (bm.info().dimensions() != bm.pixelRef()->info().dimensions())) {
666 return NULL;
667 }
668 return bm.pixelRef()->refEncodedData();
669 }
670
671 /*
672 * This functions may give false negatives but no false positives.
673 */
674 static bool is_jfif_jpeg(SkData* data) {
675 if (!data || (data->size() < 11)) {
676 return false;
677 }
678 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0};
679 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0};
680 // 0 1 2 3 4 5 6 7 8 9 10
681 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ...
682 return ((0 == memcmp(data->bytes(), bytesZeroToThree,
683 sizeof(bytesZeroToThree)))
684 && (0 == memcmp(data->bytes() + 6, bytesSixToTen,
685 sizeof(bytesSixToTen))));
686 }
687 } // namespace
688 #endif
689
690 SkPDFObject* SkPDFCreateImageObject(SkPDFCanon* canon,
691 const SkBitmap& bitmap,
692 const SkIRect& subset) {
693 if (SkPDFObject* pdfBitmap = SkPDFBitmap::Create(canon, bitmap, subset)) {
694 return pdfBitmap;
695 }
696 #if 0 // reenable when we can figure out the JPEG colorspace
697 if (SkIRect::MakeWH(bitmap.width(), bitmap.height()) == subset) {
698 SkAutoTUnref<SkData> encodedData(ref_encoded_data(bitmap));
699 if (is_jfif_jpeg(encodedData)) {
700 return SkNEW_ARGS(PDFJPEGImage,
701 (encodedData, bitmap.width(), bitmap.height()));
702 }
703 }
704 #endif
705 return SkPDFImage::CreateImage(bitmap, subset);
706 }
OLDNEW
« src/pdf/SkPDFBitmap.cpp ('K') | « src/pdf/SkPDFImage.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698