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 //#define SK_PDF_USE_BEST_PNG_PREDICTOR |
| 177 //#define SK_PDF_USE_PAETH_PNG_PREDICTOR |
| 178 namespace { |
| 179 #if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) || defined(SK_PDF_USE_PAETH_PNG_PREDI
CTOR) |
| 180 template<int BPP> |
| 181 class PngPredictor { |
| 182 public: |
| 183 PngPredictor(int widthInPixels) |
| 184 : fBuffer(2 * (BPP * widthInPixels + 1)) |
| 185 , fWidth(widthInPixels) |
| 186 , fFirstline(true) { |
| 187 fScanline = fBuffer.get(); |
| 188 fPrevScanline = &fScanline[BPP * widthInPixels + 1]; |
| 189 } |
| 190 bool predicts() { return true; } |
| 191 uint8_t* scanline() { return &fScanline[1]; } |
| 192 void write(SkWStream* out) { |
| 193 static_assert(3 == BPP || 1 == BPP, ""); |
| 194 #if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) // smaller |
| 195 auto encode = (3 == BPP) ? &SkPngEncode3 : &SkPngEncode1; |
| 196 #elif defined(SK_PDF_USE_PAETH_PNG_PREDICTOR) // faster |
| 197 auto encode = (3 == BPP) ? &SkPaethEncode3 : &SkPaethEncode1; |
| 198 #endif |
| 199 fPrevScanline[0] = encode( |
| 200 fWidth, fFirstline ? nullptr : &fPrevScanline[1], |
| 201 &fScanline[1], &fPrevScanline[1]); |
| 202 out->write(fPrevScanline, BPP * fWidth + 1); |
| 203 SkTSwap(fScanline, fPrevScanline); |
| 204 fFirstline = false; |
| 205 } |
| 206 private: |
| 207 SkAutoTMalloc<uint8_t> fBuffer; |
| 208 uint8_t* fScanline; |
| 209 uint8_t* fPrevScanline; |
| 210 uint8_t* fScratch; |
| 211 int fWidth; |
| 212 bool fFirstline; |
| 213 }; |
| 214 #else |
| 215 template<int BPP> |
| 216 class PngPredictor { |
| 217 public: |
| 218 PngPredictor(int widthInPixels) |
| 219 : fBuffer(BPP * widthInPixels) |
| 220 , fWidthInBytes(BPP * widthInPixels) { |
| 221 } |
| 222 bool predicts() { return false; } |
| 223 uint8_t* scanline() { return fBuffer.get(); } |
| 224 void write(SkWStream* out) { |
| 225 out->write(fBuffer.get(), fWidthInBytes); |
| 226 } |
| 227 private: |
| 228 SkAutoTMalloc<uint8_t> fBuffer; |
| 229 int fWidthInBytes; |
| 230 }; |
| 231 #endif |
| 232 } // namespace |
| 233 |
| 234 static bool bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { |
176 if (!bitmap.getPixels()) { | 235 if (!bitmap.getPixels()) { |
177 size_t size = pixel_count(bitmap) * | 236 size_t size = pixel_count(bitmap) * |
178 pdf_color_component_count(bitmap.colorType()); | 237 pdf_color_component_count(bitmap.colorType()); |
179 fill_stream(out, '\x00', size); | 238 fill_stream(out, '\x00', size); |
180 return; | 239 return false; |
181 } | 240 } |
182 SkBitmap copy; | 241 SkBitmap copy; |
183 const SkBitmap& bm = not4444(bitmap, ©); | 242 const SkBitmap& bm = not4444(bitmap, ©); |
184 SkAutoLockPixels autoLockPixels(bm); | 243 SkAutoLockPixels autoLockPixels(bm); |
185 SkColorType colorType = bm.colorType(); | 244 SkColorType colorType = bm.colorType(); |
186 switch (colorType) { | 245 switch (colorType) { |
187 case kRGBA_8888_SkColorType: | 246 case kRGBA_8888_SkColorType: |
188 case kBGRA_8888_SkColorType: { | 247 case kBGRA_8888_SkColorType: { |
189 SkASSERT(3 == pdf_color_component_count(colorType)); | 248 SkASSERT(3 == pdf_color_component_count(colorType)); |
190 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 249 PngPredictor<3> pngPredictorFilter(bm.width()); |
191 for (int y = 0; y < bm.height(); ++y) { | 250 for (int y = 0; y < bm.height(); ++y) { |
192 const uint32_t* src = bm.getAddr32(0, y); | 251 const uint32_t* src = bm.getAddr32(0, y); |
193 uint8_t* dst = scanline.get(); | 252 uint8_t* dst = pngPredictorFilter.scanline(); |
194 for (int x = 0; x < bm.width(); ++x) { | 253 for (int x = 0; x < bm.width(); ++x) { |
195 uint32_t color = *src++; | 254 uint32_t color = *src++; |
196 U8CPU alpha = SkGetA32Component(color, colorType); | 255 U8CPU alpha = SkGetA32Component(color, colorType); |
197 if (alpha != SK_AlphaTRANSPARENT) { | 256 if (alpha != SK_AlphaTRANSPARENT) { |
198 pmcolor_to_rgb24(color, dst, colorType); | 257 pmcolor_to_rgb24(color, dst, colorType); |
199 } else { | 258 } else { |
200 get_neighbor_avg_color(bm, x, y, dst, colorType); | 259 get_neighbor_avg_color(bm, x, y, dst, colorType); |
201 } | 260 } |
202 dst += 3; | 261 dst += 3; |
203 } | 262 } |
204 out->write(scanline.get(), 3 * bm.width()); | 263 pngPredictorFilter.write(out); |
205 } | 264 } |
206 return; | 265 return pngPredictorFilter.predicts(); |
207 } | 266 } |
208 case kRGB_565_SkColorType: { | 267 case kRGB_565_SkColorType: { |
209 SkASSERT(3 == pdf_color_component_count(colorType)); | 268 SkASSERT(3 == pdf_color_component_count(colorType)); |
210 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 269 PngPredictor<3> pngPredictorFilter(bm.width()); |
211 for (int y = 0; y < bm.height(); ++y) { | 270 for (int y = 0; y < bm.height(); ++y) { |
212 const uint16_t* src = bm.getAddr16(0, y); | 271 const uint16_t* src = bm.getAddr16(0, y); |
213 uint8_t* dst = scanline.get(); | 272 uint8_t* dst = pngPredictorFilter.scanline(); |
214 for (int x = 0; x < bm.width(); ++x) { | 273 for (int x = 0; x < bm.width(); ++x) { |
215 U16CPU color565 = *src++; | 274 U16CPU color565 = *src++; |
216 *dst++ = SkPacked16ToR32(color565); | 275 *dst++ = SkPacked16ToR32(color565); |
217 *dst++ = SkPacked16ToG32(color565); | 276 *dst++ = SkPacked16ToG32(color565); |
218 *dst++ = SkPacked16ToB32(color565); | 277 *dst++ = SkPacked16ToB32(color565); |
219 } | 278 } |
220 out->write(scanline.get(), 3 * bm.width()); | 279 pngPredictorFilter.write(out); |
221 } | 280 } |
222 return; | 281 return pngPredictorFilter.predicts(); |
223 } | 282 } |
224 case kAlpha_8_SkColorType: | 283 case kAlpha_8_SkColorType: |
225 SkASSERT(1 == pdf_color_component_count(colorType)); | 284 SkASSERT(1 == pdf_color_component_count(colorType)); |
226 fill_stream(out, '\x00', pixel_count(bm)); | 285 fill_stream(out, '\x00', pixel_count(bm)); |
227 return; | 286 return false; |
228 case kGray_8_SkColorType: | 287 case kGray_8_SkColorType: |
229 case kIndex_8_SkColorType: | 288 case kIndex_8_SkColorType: |
230 SkASSERT(1 == pdf_color_component_count(colorType)); | 289 SkASSERT(1 == pdf_color_component_count(colorType)); |
231 // these two formats need no transformation to serialize. | 290 // these two formats need no transformation to serialize. |
232 for (int y = 0; y < bm.height(); ++y) { | 291 for (int y = 0; y < bm.height(); ++y) { |
233 out->write(bm.getAddr8(0, y), bm.width()); | 292 out->write(bm.getAddr8(0, y), bm.width()); |
234 } | 293 } |
235 return; | 294 return false; |
236 case kUnknown_SkColorType: | 295 case kUnknown_SkColorType: |
237 case kARGB_4444_SkColorType: | 296 case kARGB_4444_SkColorType: |
238 default: | 297 default: |
239 SkDEBUGFAIL("unexpected color type"); | 298 SkDEBUGFAIL("unexpected color type"); |
| 299 return false; |
240 } | 300 } |
241 } | 301 } |
242 | 302 |
243 //////////////////////////////////////////////////////////////////////////////// | 303 //////////////////////////////////////////////////////////////////////////////// |
244 | 304 |
245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { | 305 static bool bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { |
246 if (!bitmap.getPixels()) { | 306 if (!bitmap.getPixels()) { |
247 fill_stream(out, '\xFF', pixel_count(bitmap)); | 307 fill_stream(out, '\xFF', pixel_count(bitmap)); |
248 return; | 308 return false; |
249 } | 309 } |
250 SkBitmap copy; | 310 SkBitmap copy; |
251 const SkBitmap& bm = not4444(bitmap, ©); | 311 const SkBitmap& bm = not4444(bitmap, ©); |
252 SkAutoLockPixels autoLockPixels(bm); | 312 SkAutoLockPixels autoLockPixels(bm); |
253 SkColorType colorType = bm.colorType(); | 313 SkColorType colorType = bm.colorType(); |
254 switch (colorType) { | 314 switch (colorType) { |
255 case kRGBA_8888_SkColorType: | 315 case kRGBA_8888_SkColorType: |
256 case kBGRA_8888_SkColorType: { | 316 case kBGRA_8888_SkColorType: { |
257 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 317 PngPredictor<1> pngPredictorFilter(bm.width()); |
258 for (int y = 0; y < bm.height(); ++y) { | 318 for (int y = 0; y < bm.height(); ++y) { |
259 uint8_t* dst = scanline.get(); | 319 uint8_t* dst = pngPredictorFilter.scanline(); |
260 const SkPMColor* src = bm.getAddr32(0, y); | 320 const SkPMColor* src = bm.getAddr32(0, y); |
261 for (int x = 0; x < bm.width(); ++x) { | 321 for (int x = 0; x < bm.width(); ++x) { |
262 *dst++ = SkGetA32Component(*src++, colorType); | 322 *dst++ = SkGetA32Component(*src++, colorType); |
263 } | 323 } |
264 out->write(scanline.get(), bm.width()); | 324 pngPredictorFilter.write(out); |
265 } | 325 } |
266 return; | 326 return pngPredictorFilter.predicts(); |
267 } | 327 } |
268 case kAlpha_8_SkColorType: | 328 case kAlpha_8_SkColorType: |
269 for (int y = 0; y < bm.height(); ++y) { | 329 for (int y = 0; y < bm.height(); ++y) { |
270 out->write(bm.getAddr8(0, y), bm.width()); | 330 out->write(bm.getAddr8(0, y), bm.width()); |
271 } | 331 } |
272 return; | 332 return false; |
273 case kIndex_8_SkColorType: { | 333 case kIndex_8_SkColorType: { |
274 SkColorTable* ct = bm.getColorTable(); | 334 SkColorTable* ct = bm.getColorTable(); |
275 SkASSERT(ct); | 335 SkASSERT(ct); |
276 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 336 SkAutoTMalloc<uint8_t> scanline(bm.width()); |
277 for (int y = 0; y < bm.height(); ++y) { | 337 for (int y = 0; y < bm.height(); ++y) { |
278 uint8_t* dst = scanline.get(); | 338 uint8_t* dst = scanline.get(); |
279 const uint8_t* src = bm.getAddr8(0, y); | 339 const uint8_t* src = bm.getAddr8(0, y); |
280 for (int x = 0; x < bm.width(); ++x) { | 340 for (int x = 0; x < bm.width(); ++x) { |
281 *dst++ = SkGetPackedA32((*ct)[*src++]); | 341 *dst++ = SkGetPackedA32((*ct)[*src++]); |
282 } | 342 } |
283 out->write(scanline.get(), bm.width()); | 343 out->write(scanline.get(), bm.width()); |
284 } | 344 } |
285 return; | 345 return false; |
286 } | 346 } |
287 case kRGB_565_SkColorType: | 347 case kRGB_565_SkColorType: |
288 case kGray_8_SkColorType: | 348 case kGray_8_SkColorType: |
289 SkDEBUGFAIL("color type has no alpha"); | 349 SkDEBUGFAIL("color type has no alpha"); |
290 return; | 350 return false; |
291 case kARGB_4444_SkColorType: | 351 case kARGB_4444_SkColorType: |
292 SkDEBUGFAIL("4444 color type should have been converted to N32"); | 352 SkDEBUGFAIL("4444 color type should have been converted to N32"); |
293 return; | 353 return false; |
294 case kUnknown_SkColorType: | 354 case kUnknown_SkColorType: |
295 default: | 355 default: |
296 SkDEBUGFAIL("unexpected color type"); | 356 SkDEBUGFAIL("unexpected color type"); |
| 357 return false; |
297 } | 358 } |
298 } | 359 } |
299 | 360 |
300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { | 361 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
301 SkPDFArray* result = new SkPDFArray; | 362 SkPDFArray* result = new SkPDFArray; |
302 result->reserve(4); | 363 result->reserve(4); |
303 result->appendName("Indexed"); | 364 result->appendName("Indexed"); |
304 result->appendName("DeviceRGB"); | 365 result->appendName("DeviceRGB"); |
305 SkASSERT(table); | 366 SkASSERT(table); |
306 if (table->count() < 1) { | 367 if (table->count() < 1) { |
(...skipping 26 matching lines...) Expand all Loading... |
333 SkPDFObject* smask, | 394 SkPDFObject* smask, |
334 const SkPDFObjNumMap& objNumMap, | 395 const SkPDFObjNumMap& objNumMap, |
335 const SkPDFSubstituteMap& substitutes) { | 396 const SkPDFSubstituteMap& substitutes) { |
336 SkBitmap bitmap; | 397 SkBitmap bitmap; |
337 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test | 398 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test |
338 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. | 399 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. |
339 | 400 |
340 // Write to a temporary buffer to get the compressed length. | 401 // Write to a temporary buffer to get the compressed length. |
341 SkDynamicMemoryWStream buffer; | 402 SkDynamicMemoryWStream buffer; |
342 SkDeflateWStream deflateWStream(&buffer); | 403 SkDeflateWStream deflateWStream(&buffer); |
| 404 bool usePngPredictor = false; |
343 if (alpha) { | 405 if (alpha) { |
344 bitmap_alpha_to_a8(bitmap, &deflateWStream); | 406 usePngPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream); |
345 } else { | 407 } else { |
346 bitmap_to_pdf_pixels(bitmap, &deflateWStream); | 408 usePngPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
347 } | 409 } |
348 deflateWStream.finalize(); // call before detachAsStream(). | 410 deflateWStream.finalize(); // call before detachAsStream(). |
349 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 411 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
350 | 412 |
351 SkPDFDict pdfDict("XObject"); | 413 SkPDFDict pdfDict("XObject"); |
352 pdfDict.insertName("Subtype", "Image"); | 414 pdfDict.insertName("Subtype", "Image"); |
353 pdfDict.insertInt("Width", bitmap.width()); | 415 pdfDict.insertInt("Width", bitmap.width()); |
354 pdfDict.insertInt("Height", bitmap.height()); | 416 pdfDict.insertInt("Height", bitmap.height()); |
355 if (alpha) { | 417 if (alpha) { |
356 pdfDict.insertName("ColorSpace", "DeviceGray"); | 418 pdfDict.insertName("ColorSpace", "DeviceGray"); |
357 } else if (bitmap.colorType() == kIndex_8_SkColorType) { | 419 } else if (bitmap.colorType() == kIndex_8_SkColorType) { |
358 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); | 420 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
359 pdfDict.insertObject("ColorSpace", | 421 pdfDict.insertObject("ColorSpace", |
360 make_indexed_color_space(bitmap.getColorTable())); | 422 make_indexed_color_space(bitmap.getColorTable())); |
361 } else if (1 == pdf_color_component_count(bitmap.colorType())) { | 423 } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
362 pdfDict.insertName("ColorSpace", "DeviceGray"); | 424 pdfDict.insertName("ColorSpace", "DeviceGray"); |
363 } else { | 425 } else { |
364 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 426 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
365 } | 427 } |
366 if (smask) { | 428 if (smask) { |
367 pdfDict.insertObjRef("SMask", SkRef(smask)); | 429 pdfDict.insertObjRef("SMask", SkRef(smask)); |
368 } | 430 } |
369 pdfDict.insertInt("BitsPerComponent", 8); | 431 pdfDict.insertInt("BitsPerComponent", 8); |
370 pdfDict.insertName("Filter", "FlateDecode"); | 432 pdfDict.insertName("Filter", "FlateDecode"); |
| 433 if (usePngPredictor) { |
| 434 SkAutoTUnref<SkPDFDict> params(new SkPDFDict); |
| 435 params->insertInt("BitsPerComponent", 8); |
| 436 params->insertInt("Predictor", 15); |
| 437 params->insertInt("Colors", alpha ? 1 : 3); |
| 438 params->insertInt("Columns", bitmap.width()); |
| 439 pdfDict.insertObject("DecodeParms", params.detach()); |
| 440 } |
371 pdfDict.insertInt("Length", asset->getLength()); | 441 pdfDict.insertInt("Length", asset->getLength()); |
372 pdfDict.emitObject(stream, objNumMap, substitutes); | 442 pdfDict.emitObject(stream, objNumMap, substitutes); |
373 | 443 |
374 pdf_stream_begin(stream); | 444 pdf_stream_begin(stream); |
375 stream->writeStream(asset.get(), asset->getLength()); | 445 stream->writeStream(asset.get(), asset->getLength()); |
376 pdf_stream_end(stream); | 446 pdf_stream_end(stream); |
377 } | 447 } |
378 | 448 |
379 //////////////////////////////////////////////////////////////////////////////// | 449 //////////////////////////////////////////////////////////////////////////////// |
380 | 450 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 } | 567 } |
498 } | 568 } |
499 | 569 |
500 SkPDFObject* smask = | 570 SkPDFObject* smask = |
501 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; | 571 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; |
502 #ifdef SK_PDF_IMAGE_STATS | 572 #ifdef SK_PDF_IMAGE_STATS |
503 gRegularImageObjects.fetch_add(1); | 573 gRegularImageObjects.fetch_add(1); |
504 #endif | 574 #endif |
505 return new PDFDefaultBitmap(image, smask); | 575 return new PDFDefaultBitmap(image, smask); |
506 } | 576 } |
OLD | NEW |