blob: 19ad79e4a5d6a9a04a30f08eb9ebf3b9ee248850 [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 The Android Open Source Project
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00006 */
7
8#include "SkPDFImage.h"
9
10#include "SkBitmap.h"
11#include "SkColor.h"
12#include "SkColorPriv.h"
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +000013#include "SkData.h"
14#include "SkFlate.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000015#include "SkPDFCatalog.h"
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +000016#include "SkRect.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000017#include "SkStream.h"
18#include "SkString.h"
19#include "SkUnPreMultiply.h"
20
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +000021static const int kNoColorTransform = 0;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000022
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +000023static bool skip_compression(SkPDFCatalog* catalog) {
24 return SkToBool(catalog->getDocumentFlags() &
25 SkPDFDocument::kFavorSpeedOverSize_Flags);
26}
27
28static size_t get_uncompressed_size(const SkBitmap& bitmap,
29 const SkIRect& srcRect) {
30 switch (bitmap.getConfig()) {
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::kA1_Config:
40 case SkBitmap::kA8_Config:
41 return 1;
42 default:
43 SkASSERT(false);
44 return 0;
45 }
46}
47
48static SkStream* extract_index8_image(const SkBitmap& bitmap,
49 const SkIRect& srcRect) {
50 const int rowBytes = srcRect.width();
51 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
52 (get_uncompressed_size(bitmap, srcRect)));
53 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
54
55 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
56 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
57 dst += rowBytes;
58 }
59 return stream;
60}
61
62static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
63 const SkIRect& srcRect,
64 bool extractAlpha,
65 bool* isOpaque,
66 bool* isTransparent) {
67 SkStream* stream;
68 uint8_t* dst = NULL;
69 if (extractAlpha) {
70 const int alphaRowBytes = (srcRect.width() + 1) / 2;
71 stream = SkNEW_ARGS(SkMemoryStream,
72 (alphaRowBytes * srcRect.height()));
73 } else {
74 stream = SkNEW_ARGS(SkMemoryStream,
75 (get_uncompressed_size(bitmap, srcRect)));
76 }
77 dst = (uint8_t*)stream->getMemoryBase();
78
79 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
80 uint16_t* src = bitmap.getAddr16(0, y);
81 int x;
82 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
83 if (extractAlpha) {
84 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
85 SkGetPackedA4444(src[x + 1]);
86 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
87 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
88 dst++;
89 } else {
90 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
91 SkGetPackedG4444(src[x]);
92 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
93 SkGetPackedR4444(src[x + 1]);
94 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
95 SkGetPackedB4444(src[x + 1]);
96 dst += 3;
97 }
98 }
99 if (srcRect.width() & 1) {
100 if (extractAlpha) {
101 dst[0] = (SkGetPackedA4444(src[x]) << 4);
102 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
103 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
104 dst++;
105
106 } else {
107 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
108 SkGetPackedG4444(src[x]);
109 dst[1] = (SkGetPackedB4444(src[x]) << 4);
110 dst += 2;
111 }
112 }
113 }
114 return stream;
115}
116
117static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
118 const SkIRect& srcRect) {
119 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
120 (get_uncompressed_size(bitmap,
121 srcRect)));
122 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
123 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
124 uint16_t* src = bitmap.getAddr16(0, y);
125 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
126 dst[0] = SkGetPackedR16(src[x]);
127 dst[1] = SkGetPackedG16(src[x]);
128 dst[2] = SkGetPackedB16(src[x]);
129 dst += 3;
130 }
131 }
132 return stream;
133}
134
135static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
136 const SkIRect& srcRect,
137 bool extractAlpha,
138 bool* isOpaque,
139 bool* isTransparent) {
140 SkStream* stream;
141 if (extractAlpha) {
142 stream = SkNEW_ARGS(SkMemoryStream,
143 (srcRect.width() * srcRect.height()));
144 } else {
145 stream = SkNEW_ARGS(SkMemoryStream,
146 (get_uncompressed_size(bitmap, srcRect)));
147 }
148 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
149
150 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
151 uint32_t* src = bitmap.getAddr32(0, y);
152 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
153 if (extractAlpha) {
154 dst[0] = SkGetPackedA32(src[x]);
155 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
156 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
157 dst++;
158 } else {
159 dst[0] = SkGetPackedR32(src[x]);
160 dst[1] = SkGetPackedG32(src[x]);
161 dst[2] = SkGetPackedB32(src[x]);
162 dst += 3;
163 }
164 }
165 }
166 return stream;
167}
168
169static SkStream* extract_a1_alpha(const SkBitmap& bitmap,
170 const SkIRect& srcRect,
171 bool* isOpaque,
172 bool* isTransparent) {
173 const int alphaRowBytes = (srcRect.width() + 7) / 8;
174 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
175 (alphaRowBytes * srcRect.height()));
176 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
177
178 int offset1 = srcRect.fLeft % 8;
179 int offset2 = 8 - offset1;
180
181 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
182 uint8_t* src = bitmap.getAddr1(0, y);
183 // This may read up to one byte after src, but the
184 // potentially invalid bits are never used for computation.
185 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
186 if (offset1) {
187 alphaDst[0] = src[x / 8] << offset1 |
188 src[x / 8 + 1] >> offset2;
189 } else {
190 alphaDst[0] = src[x / 8];
191 }
192 if (x + 7 < srcRect.fRight) {
193 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
194 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
195 }
196 alphaDst++;
197 }
198 // Calculate the mask of bits we're interested in within the
199 // last byte of alphaDst.
200 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
201 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
202 if (srcRect.width() % 8) {
203 *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask);
204 *isTransparent &=
205 (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask);
206 }
207 }
208 return stream;
209}
210
211static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
212 const SkIRect& srcRect,
213 bool* isOpaque,
214 bool* isTransparent) {
215 const int alphaRowBytes = srcRect.width();
216 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
217 (alphaRowBytes * srcRect.height()));
218 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
219
220 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
221 uint8_t* src = bitmap.getAddr8(0, y);
222 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
223 alphaDst[0] = src[x];
224 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
225 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
226 alphaDst++;
227 }
228 }
229 return stream;
230}
231
232static SkStream* create_black_image() {
233 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
234 ((uint8_t*)stream->getMemoryBase())[0] = 0;
235 return stream;
236}
237
238/**
239 * Extract either the color or image data from a SkBitmap into a SkStream.
240 * @param bitmap Bitmap to extract data from.
241 * @param srcRect Region in the bitmap to extract.
242 * @param extractAlpha Set to true to extract the alpha data or false to
243 * extract the color data.
244 * @param isTransparent Pointer to a bool to output whether the alpha is
245 * completely transparent. May be NULL. Only valid when
246 * extractAlpha == true.
247 * @return Unencoded image data, or NULL if either data was not
248 * available or alpha data was requested but the image was
249 * entirely transparent or opaque.
250 */
251static SkStream* extract_image_data(const SkBitmap& bitmap,
252 const SkIRect& srcRect,
253 bool extractAlpha, bool* isTransparent) {
254 SkBitmap::Config config = bitmap.config();
255 if (extractAlpha && (config == SkBitmap::kIndex8_Config ||
256 config == SkBitmap::kRGB_565_Config)) {
257 if (isTransparent != NULL) {
258 *isTransparent = false;
259 }
260 return NULL;
261 }
262 bool isOpaque = true;
263 bool transparent = extractAlpha;
264 SkStream* stream = NULL;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000265
vandebo@chromium.orgad114952010-10-26 19:43:14 +0000266 bitmap.lockPixels();
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000267 switch (config) {
268 case SkBitmap::kIndex8_Config:
269 if (!extractAlpha) {
270 stream = extract_index8_image(bitmap, srcRect);
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000271 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000272 break;
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000273 case SkBitmap::kARGB_4444_Config:
274 stream = extract_argb4444_data(bitmap, srcRect, extractAlpha,
275 &isOpaque, &transparent);
276 break;
277 case SkBitmap::kRGB_565_Config:
278 if (!extractAlpha) {
279 stream = extract_rgb565_image(bitmap, srcRect);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000280 }
281 break;
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000282 case SkBitmap::kARGB_8888_Config:
283 stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
284 &isOpaque, &transparent);
285 break;
286 case SkBitmap::kA1_Config:
287 if (!extractAlpha) {
288 stream = create_black_image();
289 } else {
290 stream = extract_a1_alpha(bitmap, srcRect,
291 &isOpaque, &transparent);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000292 }
293 break;
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000294 case SkBitmap::kA8_Config:
295 if (!extractAlpha) {
296 stream = create_black_image();
297 } else {
298 stream = extract_a8_alpha(bitmap, srcRect,
299 &isOpaque, &transparent);
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000300 }
301 break;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000302 default:
303 SkASSERT(false);
304 }
vandebo@chromium.orgad114952010-10-26 19:43:14 +0000305 bitmap.unlockPixels();
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000306
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000307 if (isTransparent != NULL) {
308 *isTransparent = transparent;
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000309 }
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000310 if (extractAlpha && (transparent || isOpaque)) {
311 SkSafeUnref(stream);
312 return NULL;
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000313 }
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000314 return stream;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000315}
316
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000317static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000318 SkPDFArray* result = new SkPDFArray();
319 result->reserve(4);
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000320 result->appendName("Indexed");
321 result->appendName("DeviceRGB");
322 result->appendInt(table->count() - 1);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000323
324 // Potentially, this could be represented in fewer bytes with a stream.
325 // Max size as a string is 1.5k.
326 SkString index;
327 for (int i = 0; i < table->count(); i++) {
328 char buf[3];
329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
330 buf[0] = SkGetPackedR32(color);
331 buf[1] = SkGetPackedG32(color);
332 buf[2] = SkGetPackedB32(color);
333 index.append(buf, 3);
334 }
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000335 result->append(new SkPDFString(index))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000336 return result;
337}
338
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000339// static
340SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000341 const SkIRect& srcRect,
commit-bot@chromium.org608ea652013-10-03 19:29:21 +0000342 SkPicture::EncodeBitmap encoder) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000343 if (bitmap.getConfig() == SkBitmap::kNo_Config) {
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000344 return NULL;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000345 }
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000346
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000347 bool isTransparent = false;
348 SkAutoTUnref<SkStream> alphaData;
349 if (!bitmap.isOpaque()) {
350 // Note that isOpaque is not guaranteed to return false for bitmaps
351 // with alpha support but a completely opaque alpha channel,
352 // so alphaData may still be NULL if we have a completely opaque
353 // (or transparent) bitmap.
354 alphaData.reset(
355 extract_image_data(bitmap, srcRect, true, &isTransparent));
356 }
357 if (isTransparent) {
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000358 return NULL;
359 }
360
robertphillips@google.com69b13022013-08-25 11:20:54 +0000361 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap,
362 false, srcRect, encoder));
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000363 if (alphaData.get() != NULL) {
364 SkAutoTUnref<SkPDFImage> mask(
365 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap,
366 true, srcRect, NULL)));
367 image->addSMask(mask);
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000368 }
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000369
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000370 return image;
371}
372
373SkPDFImage::~SkPDFImage() {
374 fResources.unrefAll();
375}
376
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000377SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000378 fResources.push(mask);
379 mask->ref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000380 insert("SMask", new SkPDFObjRef(mask))->unref();
381 return mask;
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000382}
383
edisonn@google.com6addb192013-04-02 15:33:08 +0000384void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
385 SkTSet<SkPDFObject*>* newResourceObjects) {
386 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000387}
388
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000389SkPDFImage::SkPDFImage(SkStream* stream,
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000390 const SkBitmap& bitmap,
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000391 bool isAlpha,
edisonn@google.comd9dfa182013-04-24 13:01:01 +0000392 const SkIRect& srcRect,
commit-bot@chromium.org608ea652013-10-03 19:29:21 +0000393 SkPicture::EncodeBitmap encoder)
commit-bot@chromium.org06822ea2013-08-29 20:26:41 +0000394 : fIsAlpha(isAlpha),
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000395 fSrcRect(srcRect),
396 fEncoder(encoder) {
397
commit-bot@chromium.org06822ea2013-08-29 20:26:41 +0000398 if (bitmap.isImmutable()) {
399 fBitmap = bitmap;
400 } else {
401 bitmap.deepCopyTo(&fBitmap, bitmap.config());
402 fBitmap.setImmutable();
403 }
404
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000405 if (stream != NULL) {
406 setData(stream);
407 fStreamValid = true;
408 } else {
409 fStreamValid = false;
410 }
411
412 SkBitmap::Config config = fBitmap.getConfig();
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000413
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000414 insertName("Type", "XObject");
415 insertName("Subtype", "Image");
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000416
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000417 bool alphaOnly = (config == SkBitmap::kA1_Config ||
418 config == SkBitmap::kA8_Config);
419
420 if (!isAlpha && alphaOnly) {
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000421 // For alpha only images, we stretch a single pixel of black for
422 // the color/shape part.
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000423 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000424 insert("Width", one.get());
425 insert("Height", one.get());
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000426 } else {
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000427 insertInt("Width", fSrcRect.width());
428 insertInt("Height", fSrcRect.height());
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000429 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000430
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000431 if (isAlpha || alphaOnly) {
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000432 insertName("ColorSpace", "DeviceGray");
reed@google.com2cb14802013-06-26 14:35:02 +0000433 } else if (config == SkBitmap::kIndex8_Config) {
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000434 SkAutoLockPixels alp(fBitmap);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000435 insert("ColorSpace",
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000436 make_indexed_color_space(fBitmap.getColorTable()))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000437 } else {
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000438 insertName("ColorSpace", "DeviceRGB");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000439 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000440
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000441 int bitsPerComp = 8;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000442 if (config == SkBitmap::kARGB_4444_Config) {
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000443 bitsPerComp = 4;
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000444 } else if (isAlpha && config == SkBitmap::kA1_Config) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000445 bitsPerComp = 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000446 }
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000447 insertInt("BitsPerComponent", bitsPerComp);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000448
449 if (config == SkBitmap::kRGB_565_Config) {
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000450 SkASSERT(!isAlpha);
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000451 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
452 SkAutoTUnref<SkPDFScalar> scale5Val(
453 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1
454 SkAutoTUnref<SkPDFScalar> scale6Val(
455 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1
456 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000457 decodeValue->reserve(6);
458 decodeValue->append(zeroVal.get());
459 decodeValue->append(scale5Val.get());
460 decodeValue->append(zeroVal.get());
461 decodeValue->append(scale6Val.get());
462 decodeValue->append(zeroVal.get());
463 decodeValue->append(scale5Val.get());
464 insert("Decode", decodeValue.get());
465 }
466}
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000467
468SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
469 : SkPDFStream(pdfImage),
470 fBitmap(pdfImage.fBitmap),
471 fIsAlpha(pdfImage.fIsAlpha),
472 fSrcRect(pdfImage.fSrcRect),
473 fEncoder(pdfImage.fEncoder),
474 fStreamValid(pdfImage.fStreamValid) {
475 // Nothing to do here - the image params are already copied in SkPDFStream's
476 // constructor, and the bitmap will be regenerated and encoded in
477 // populate.
478}
479
480bool SkPDFImage::populate(SkPDFCatalog* catalog) {
481 if (getState() == kUnused_State) {
482 // Initializing image data for the first time.
483 SkDynamicMemoryWStream dctCompressedWStream;
484 if (!skip_compression(catalog) && fEncoder &&
commit-bot@chromium.org608ea652013-10-03 19:29:21 +0000485 get_uncompressed_size(fBitmap, fSrcRect) > 1) {
486 SkBitmap subset;
487 // Extract subset
488 if (!fBitmap.extractSubset(&subset, fSrcRect)) {
489 // TODO(edisonn) It fails only for kA1_Config, if that is a
490 // major concern we will fix it later, so far it is NYI.
491 return false;
492 }
493 size_t pixelRefOffset = 0;
494 SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset));
495 if (data.get() && data->size() < get_uncompressed_size(fBitmap,
496 fSrcRect)) {
497 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream,
498 (data)));
499 setData(stream.get());
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000500
commit-bot@chromium.org608ea652013-10-03 19:29:21 +0000501 insertName("Filter", "DCTDecode");
502 insertInt("ColorTransform", kNoColorTransform);
503 insertInt("Length", getData()->getLength());
504 setState(kCompressed_State);
505 return true;
506 }
commit-bot@chromium.org181fcb42013-08-23 19:06:53 +0000507 }
508 // Fallback method
509 if (!fStreamValid) {
510 SkAutoTUnref<SkStream> stream(
511 extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
512 setData(stream);
513 fStreamValid = true;
514 }
515 return INHERITED::populate(catalog);
516 } else if (getState() == kNoCompression_State &&
517 !skip_compression(catalog) &&
518 (SkFlate::HaveFlate() || fEncoder)) {
519 // Compression has not been requested when the stream was first created,
520 // but the new catalog wants it compressed.
521 if (!getSubstitute()) {
522 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
523 setSubstitute(substitute);
524 catalog->setSubstitute(this, substitute);
525 }
526 return false;
527 }
528 return true;
529}