OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
9 #include "SkData.h" | 9 #include "SkData.h" |
10 #include "SkDeflate.h" | 10 #include "SkDeflate.h" |
11 #include "SkImage_Base.h" | 11 #include "SkImage_Base.h" |
12 #include "SkJpegInfo.h" | 12 #include "SkJpegInfo.h" |
13 #include "SkPDFBitmap.h" | 13 #include "SkPDFBitmap.h" |
14 #include "SkPDFCanon.h" | 14 #include "SkPDFCanon.h" |
15 #include "SkStream.h" | 15 #include "SkStream.h" |
16 #include "SkUnPreMultiply.h" | 16 #include "SkUnPreMultiply.h" |
| 17 #include "SkPngPredictors.h" |
17 | 18 |
18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { | 19 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { |
19 if(as_IB(image)->getROPixels(dst) | 20 if(as_IB(image)->getROPixels(dst) |
20 && dst->dimensions() == image->dimensions()) { | 21 && dst->dimensions() == image->dimensions()) { |
21 if (dst->colorType() != kIndex_8_SkColorType) { | 22 if (dst->colorType() != kIndex_8_SkColorType) { |
22 return; | 23 return; |
23 } | 24 } |
24 // We must check to see if the bitmap has a color table. | 25 // We must check to see if the bitmap has a color table. |
25 SkAutoLockPixels autoLockPixels(*dst); | 26 SkAutoLockPixels autoLockPixels(*dst); |
26 if (!dst->getColorTable()) { | 27 if (!dst->getColorTable()) { |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 case kIndex_8_SkColorType: | 166 case kIndex_8_SkColorType: |
166 case kGray_8_SkColorType: | 167 case kGray_8_SkColorType: |
167 return 1; | 168 return 1; |
168 case kUnknown_SkColorType: | 169 case kUnknown_SkColorType: |
169 default: | 170 default: |
170 SkDEBUGFAIL("unexpected color type"); | 171 SkDEBUGFAIL("unexpected color type"); |
171 return 0; | 172 return 0; |
172 } | 173 } |
173 } | 174 } |
174 | 175 |
175 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { | 176 namespace { |
| 177 template<int COMPONENT_COUNT, void(*FN)(int, const uint8_t*, const uint8_t*, uin
t8_t*)> |
| 178 class PngPredictor { |
| 179 public: |
| 180 PngPredictor(int widthInPixels) |
| 181 : fBuffer(2 * (COMPONENT_COUNT * widthInPixels + 1)) |
| 182 , fWidth(widthInPixels) |
| 183 , fFirstline(true) { |
| 184 fScanline = fBuffer.get(); |
| 185 fPrevScanline = &fScanline[COMPONENT_COUNT * widthInPixels + 1]; |
| 186 } |
| 187 uint8_t* scanline() { return &fScanline[1]; } |
| 188 void write(SkWStream* out) { |
| 189 fPrevScanline[0] = 4; |
| 190 FN(fWidth, fFirstline ? nullptr : &fPrevScanline[1], &fScanline[1], &fPr
evScanline[1]); |
| 191 out->write(fPrevScanline, COMPONENT_COUNT * fWidth + 1); |
| 192 SkTSwap(fScanline, fPrevScanline); |
| 193 fFirstline = false; |
| 194 } |
| 195 private: |
| 196 SkAutoTMalloc<uint8_t> fBuffer; |
| 197 uint8_t* fScanline; |
| 198 uint8_t* fPrevScanline; |
| 199 int fWidth; |
| 200 bool fFirstline; |
| 201 }; |
| 202 } // namespace |
| 203 |
| 204 static bool bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { |
176 if (!bitmap.getPixels()) { | 205 if (!bitmap.getPixels()) { |
177 size_t size = pixel_count(bitmap) * | 206 size_t size = pixel_count(bitmap) * |
178 pdf_color_component_count(bitmap.colorType()); | 207 pdf_color_component_count(bitmap.colorType()); |
179 fill_stream(out, '\x00', size); | 208 fill_stream(out, '\x00', size); |
180 return; | 209 return false; |
181 } | 210 } |
182 SkBitmap copy; | 211 SkBitmap copy; |
183 const SkBitmap& bm = not4444(bitmap, ©); | 212 const SkBitmap& bm = not4444(bitmap, ©); |
184 SkAutoLockPixels autoLockPixels(bm); | 213 SkAutoLockPixels autoLockPixels(bm); |
185 SkColorType colorType = bm.colorType(); | 214 SkColorType colorType = bm.colorType(); |
186 switch (colorType) { | 215 switch (colorType) { |
187 case kRGBA_8888_SkColorType: | 216 case kRGBA_8888_SkColorType: |
188 case kBGRA_8888_SkColorType: { | 217 case kBGRA_8888_SkColorType: { |
189 SkASSERT(3 == pdf_color_component_count(colorType)); | 218 SkASSERT(3 == pdf_color_component_count(colorType)); |
190 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 219 PngPredictor<3, SkPaethEncode3> paether(bm.width()); |
191 for (int y = 0; y < bm.height(); ++y) { | 220 for (int y = 0; y < bm.height(); ++y) { |
192 const uint32_t* src = bm.getAddr32(0, y); | 221 const uint32_t* src = bm.getAddr32(0, y); |
193 uint8_t* dst = scanline.get(); | 222 uint8_t* dst = paether.scanline(); |
194 for (int x = 0; x < bm.width(); ++x) { | 223 for (int x = 0; x < bm.width(); ++x) { |
195 uint32_t color = *src++; | 224 uint32_t color = *src++; |
196 U8CPU alpha = SkGetA32Component(color, colorType); | 225 U8CPU alpha = SkGetA32Component(color, colorType); |
197 if (alpha != SK_AlphaTRANSPARENT) { | 226 if (alpha != SK_AlphaTRANSPARENT) { |
198 pmcolor_to_rgb24(color, dst, colorType); | 227 pmcolor_to_rgb24(color, dst, colorType); |
199 } else { | 228 } else { |
200 get_neighbor_avg_color(bm, x, y, dst, colorType); | 229 get_neighbor_avg_color(bm, x, y, dst, colorType); |
201 } | 230 } |
202 dst += 3; | 231 dst += 3; |
203 } | 232 } |
204 out->write(scanline.get(), 3 * bm.width()); | 233 paether.write(out); |
205 } | 234 } |
206 return; | 235 return true; |
207 } | 236 } |
208 case kRGB_565_SkColorType: { | 237 case kRGB_565_SkColorType: { |
209 SkASSERT(3 == pdf_color_component_count(colorType)); | 238 SkASSERT(3 == pdf_color_component_count(colorType)); |
210 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 239 PngPredictor<3, SkPaethEncode3> paether(bm.width()); |
211 for (int y = 0; y < bm.height(); ++y) { | 240 for (int y = 0; y < bm.height(); ++y) { |
212 const uint16_t* src = bm.getAddr16(0, y); | 241 const uint16_t* src = bm.getAddr16(0, y); |
213 uint8_t* dst = scanline.get(); | 242 uint8_t* dst = paether.scanline(); |
214 for (int x = 0; x < bm.width(); ++x) { | 243 for (int x = 0; x < bm.width(); ++x) { |
215 U16CPU color565 = *src++; | 244 U16CPU color565 = *src++; |
216 *dst++ = SkPacked16ToR32(color565); | 245 *dst++ = SkPacked16ToR32(color565); |
217 *dst++ = SkPacked16ToG32(color565); | 246 *dst++ = SkPacked16ToG32(color565); |
218 *dst++ = SkPacked16ToB32(color565); | 247 *dst++ = SkPacked16ToB32(color565); |
219 } | 248 } |
220 out->write(scanline.get(), 3 * bm.width()); | 249 paether.write(out); |
221 } | 250 } |
222 return; | 251 return true; |
223 } | 252 } |
224 case kAlpha_8_SkColorType: | 253 case kAlpha_8_SkColorType: |
225 SkASSERT(1 == pdf_color_component_count(colorType)); | 254 SkASSERT(1 == pdf_color_component_count(colorType)); |
226 fill_stream(out, '\x00', pixel_count(bm)); | 255 fill_stream(out, '\x00', pixel_count(bm)); |
227 return; | 256 return false; |
228 case kGray_8_SkColorType: | 257 case kGray_8_SkColorType: |
229 case kIndex_8_SkColorType: | 258 case kIndex_8_SkColorType: |
230 SkASSERT(1 == pdf_color_component_count(colorType)); | 259 SkASSERT(1 == pdf_color_component_count(colorType)); |
231 // these two formats need no transformation to serialize. | 260 // these two formats need no transformation to serialize. |
232 for (int y = 0; y < bm.height(); ++y) { | 261 for (int y = 0; y < bm.height(); ++y) { |
233 out->write(bm.getAddr8(0, y), bm.width()); | 262 out->write(bm.getAddr8(0, y), bm.width()); |
234 } | 263 } |
235 return; | 264 return false; |
236 case kUnknown_SkColorType: | 265 case kUnknown_SkColorType: |
237 case kARGB_4444_SkColorType: | 266 case kARGB_4444_SkColorType: |
238 default: | 267 default: |
239 SkDEBUGFAIL("unexpected color type"); | 268 SkDEBUGFAIL("unexpected color type"); |
| 269 return false; |
240 } | 270 } |
241 } | 271 } |
242 | 272 |
243 //////////////////////////////////////////////////////////////////////////////// | 273 //////////////////////////////////////////////////////////////////////////////// |
244 | 274 |
245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { | 275 static bool bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { |
246 if (!bitmap.getPixels()) { | 276 if (!bitmap.getPixels()) { |
247 fill_stream(out, '\xFF', pixel_count(bitmap)); | 277 fill_stream(out, '\xFF', pixel_count(bitmap)); |
248 return; | 278 return false; |
249 } | 279 } |
250 SkBitmap copy; | 280 SkBitmap copy; |
251 const SkBitmap& bm = not4444(bitmap, ©); | 281 const SkBitmap& bm = not4444(bitmap, ©); |
252 SkAutoLockPixels autoLockPixels(bm); | 282 SkAutoLockPixels autoLockPixels(bm); |
253 SkColorType colorType = bm.colorType(); | 283 SkColorType colorType = bm.colorType(); |
254 switch (colorType) { | 284 switch (colorType) { |
255 case kRGBA_8888_SkColorType: | 285 case kRGBA_8888_SkColorType: |
256 case kBGRA_8888_SkColorType: { | 286 case kBGRA_8888_SkColorType: { |
257 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 287 PngPredictor<1, SkPaethEncode1> paether(bm.width()); |
258 for (int y = 0; y < bm.height(); ++y) { | 288 for (int y = 0; y < bm.height(); ++y) { |
259 uint8_t* dst = scanline.get(); | 289 uint8_t* dst = paether.scanline(); |
260 const SkPMColor* src = bm.getAddr32(0, y); | 290 const SkPMColor* src = bm.getAddr32(0, y); |
261 for (int x = 0; x < bm.width(); ++x) { | 291 for (int x = 0; x < bm.width(); ++x) { |
262 *dst++ = SkGetA32Component(*src++, colorType); | 292 *dst++ = SkGetA32Component(*src++, colorType); |
263 } | 293 } |
264 out->write(scanline.get(), bm.width()); | 294 paether.write(out); |
265 } | 295 } |
266 return; | 296 return true; |
267 } | 297 } |
268 case kAlpha_8_SkColorType: | 298 case kAlpha_8_SkColorType: |
269 for (int y = 0; y < bm.height(); ++y) { | 299 for (int y = 0; y < bm.height(); ++y) { |
270 out->write(bm.getAddr8(0, y), bm.width()); | 300 out->write(bm.getAddr8(0, y), bm.width()); |
271 } | 301 } |
272 return; | 302 return false; |
273 case kIndex_8_SkColorType: { | 303 case kIndex_8_SkColorType: { |
274 SkColorTable* ct = bm.getColorTable(); | 304 SkColorTable* ct = bm.getColorTable(); |
275 SkASSERT(ct); | 305 SkASSERT(ct); |
276 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 306 SkAutoTMalloc<uint8_t> scanline(bm.width()); |
277 for (int y = 0; y < bm.height(); ++y) { | 307 for (int y = 0; y < bm.height(); ++y) { |
278 uint8_t* dst = scanline.get(); | 308 uint8_t* dst = scanline.get(); |
279 const uint8_t* src = bm.getAddr8(0, y); | 309 const uint8_t* src = bm.getAddr8(0, y); |
280 for (int x = 0; x < bm.width(); ++x) { | 310 for (int x = 0; x < bm.width(); ++x) { |
281 *dst++ = SkGetPackedA32((*ct)[*src++]); | 311 *dst++ = SkGetPackedA32((*ct)[*src++]); |
282 } | 312 } |
283 out->write(scanline.get(), bm.width()); | 313 out->write(scanline.get(), bm.width()); |
284 } | 314 } |
285 return; | 315 return false; |
286 } | 316 } |
287 case kRGB_565_SkColorType: | 317 case kRGB_565_SkColorType: |
288 case kGray_8_SkColorType: | 318 case kGray_8_SkColorType: |
289 SkDEBUGFAIL("color type has no alpha"); | 319 SkDEBUGFAIL("color type has no alpha"); |
290 return; | 320 return false; |
291 case kARGB_4444_SkColorType: | 321 case kARGB_4444_SkColorType: |
292 SkDEBUGFAIL("4444 color type should have been converted to N32"); | 322 SkDEBUGFAIL("4444 color type should have been converted to N32"); |
293 return; | 323 return false; |
294 case kUnknown_SkColorType: | 324 case kUnknown_SkColorType: |
295 default: | 325 default: |
296 SkDEBUGFAIL("unexpected color type"); | 326 SkDEBUGFAIL("unexpected color type"); |
| 327 return false; |
297 } | 328 } |
298 } | 329 } |
299 | 330 |
300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { | 331 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
301 SkPDFArray* result = new SkPDFArray; | 332 SkPDFArray* result = new SkPDFArray; |
302 result->reserve(4); | 333 result->reserve(4); |
303 result->appendName("Indexed"); | 334 result->appendName("Indexed"); |
304 result->appendName("DeviceRGB"); | 335 result->appendName("DeviceRGB"); |
305 SkASSERT(table); | 336 SkASSERT(table); |
306 if (table->count() < 1) { | 337 if (table->count() < 1) { |
(...skipping 26 matching lines...) Expand all Loading... |
333 SkPDFObject* smask, | 364 SkPDFObject* smask, |
334 const SkPDFObjNumMap& objNumMap, | 365 const SkPDFObjNumMap& objNumMap, |
335 const SkPDFSubstituteMap& substitutes) { | 366 const SkPDFSubstituteMap& substitutes) { |
336 SkBitmap bitmap; | 367 SkBitmap bitmap; |
337 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test | 368 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test |
338 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. | 369 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. |
339 | 370 |
340 // Write to a temporary buffer to get the compressed length. | 371 // Write to a temporary buffer to get the compressed length. |
341 SkDynamicMemoryWStream buffer; | 372 SkDynamicMemoryWStream buffer; |
342 SkDeflateWStream deflateWStream(&buffer); | 373 SkDeflateWStream deflateWStream(&buffer); |
| 374 bool paethPredictor = false; |
343 if (alpha) { | 375 if (alpha) { |
344 bitmap_alpha_to_a8(bitmap, &deflateWStream); | 376 paethPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream); |
345 } else { | 377 } else { |
346 bitmap_to_pdf_pixels(bitmap, &deflateWStream); | 378 paethPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
347 } | 379 } |
348 deflateWStream.finalize(); // call before detachAsStream(). | 380 deflateWStream.finalize(); // call before detachAsStream(). |
349 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 381 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
350 | 382 |
351 SkPDFDict pdfDict("XObject"); | 383 SkPDFDict pdfDict("XObject"); |
352 pdfDict.insertName("Subtype", "Image"); | 384 pdfDict.insertName("Subtype", "Image"); |
353 pdfDict.insertInt("Width", bitmap.width()); | 385 pdfDict.insertInt("Width", bitmap.width()); |
354 pdfDict.insertInt("Height", bitmap.height()); | 386 pdfDict.insertInt("Height", bitmap.height()); |
355 if (alpha) { | 387 if (alpha) { |
356 pdfDict.insertName("ColorSpace", "DeviceGray"); | 388 pdfDict.insertName("ColorSpace", "DeviceGray"); |
357 } else if (bitmap.colorType() == kIndex_8_SkColorType) { | 389 } else if (bitmap.colorType() == kIndex_8_SkColorType) { |
358 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); | 390 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
359 pdfDict.insertObject("ColorSpace", | 391 pdfDict.insertObject("ColorSpace", |
360 make_indexed_color_space(bitmap.getColorTable())); | 392 make_indexed_color_space(bitmap.getColorTable())); |
361 } else if (1 == pdf_color_component_count(bitmap.colorType())) { | 393 } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
362 pdfDict.insertName("ColorSpace", "DeviceGray"); | 394 pdfDict.insertName("ColorSpace", "DeviceGray"); |
363 } else { | 395 } else { |
364 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 396 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
365 } | 397 } |
366 if (smask) { | 398 if (smask) { |
367 pdfDict.insertObjRef("SMask", SkRef(smask)); | 399 pdfDict.insertObjRef("SMask", SkRef(smask)); |
368 } | 400 } |
369 pdfDict.insertInt("BitsPerComponent", 8); | 401 pdfDict.insertInt("BitsPerComponent", 8); |
370 pdfDict.insertName("Filter", "FlateDecode"); | 402 pdfDict.insertName("Filter", "FlateDecode"); |
| 403 if (paethPredictor) { |
| 404 SkAutoTUnref<SkPDFDict> params(new SkPDFDict); |
| 405 params->insertInt("BitsPerComponent", 8); |
| 406 params->insertInt("Predictor", 15); |
| 407 params->insertInt("Colors", alpha ? 1 : 3); |
| 408 params->insertInt("Columns", bitmap.width()); |
| 409 pdfDict.insertObject("DecodeParms", params.detach()); |
| 410 } |
371 pdfDict.insertInt("Length", asset->getLength()); | 411 pdfDict.insertInt("Length", asset->getLength()); |
372 pdfDict.emitObject(stream, objNumMap, substitutes); | 412 pdfDict.emitObject(stream, objNumMap, substitutes); |
373 | 413 |
374 pdf_stream_begin(stream); | 414 pdf_stream_begin(stream); |
375 stream->writeStream(asset.get(), asset->getLength()); | 415 stream->writeStream(asset.get(), asset->getLength()); |
376 pdf_stream_end(stream); | 416 pdf_stream_end(stream); |
377 } | 417 } |
378 | 418 |
379 //////////////////////////////////////////////////////////////////////////////// | 419 //////////////////////////////////////////////////////////////////////////////// |
380 | 420 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 } | 537 } |
498 } | 538 } |
499 | 539 |
500 SkPDFObject* smask = | 540 SkPDFObject* smask = |
501 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; | 541 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; |
502 #ifdef SK_PDF_IMAGE_STATS | 542 #ifdef SK_PDF_IMAGE_STATS |
503 gRegularImageObjects.fetch_add(1); | 543 gRegularImageObjects.fetch_add(1); |
504 #endif | 544 #endif |
505 return new PDFDefaultBitmap(image, smask); | 545 return new PDFDefaultBitmap(image, smask); |
506 } | 546 } |
OLD | NEW |