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 "SkImageGenerator.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 "SkPixelRef.h" | |
16 #include "SkStream.h" | 15 #include "SkStream.h" |
17 #include "SkUnPreMultiply.h" | 16 #include "SkUnPreMultiply.h" |
18 | 17 |
18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { | |
19 if(as_IB(image)->getROPixels(dst) | |
20 && dst->dimensions() == image->dimensions()) { | |
21 return; | |
22 } | |
23 // no pixels or wrong size: fill with zeros. | |
24 SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaTy pe; | |
25 dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at)); | |
26 } | |
27 | |
19 //////////////////////////////////////////////////////////////////////////////// | 28 //////////////////////////////////////////////////////////////////////////////// |
20 | 29 |
21 static void pdf_stream_begin(SkWStream* stream) { | 30 static void pdf_stream_begin(SkWStream* stream) { |
22 static const char streamBegin[] = " stream\n"; | 31 static const char streamBegin[] = " stream\n"; |
23 stream->write(streamBegin, strlen(streamBegin)); | 32 stream->write(streamBegin, strlen(streamBegin)); |
24 } | 33 } |
25 | 34 |
26 static void pdf_stream_end(SkWStream* stream) { | 35 static void pdf_stream_end(SkWStream* stream) { |
27 static const char streamEnd[] = "\nendstream"; | 36 static const char streamEnd[] = "\nendstream"; |
28 stream->write(streamEnd, strlen(streamEnd)); | 37 stream->write(streamEnd, strlen(streamEnd)); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 SkDEBUGFAIL("unexpected color type"); | 247 SkDEBUGFAIL("unexpected color type"); |
239 } | 248 } |
240 } | 249 } |
241 | 250 |
242 //////////////////////////////////////////////////////////////////////////////// | 251 //////////////////////////////////////////////////////////////////////////////// |
243 | 252 |
244 namespace { | 253 namespace { |
245 // This SkPDFObject only outputs the alpha layer of the given bitmap. | 254 // This SkPDFObject only outputs the alpha layer of the given bitmap. |
246 class PDFAlphaBitmap : public SkPDFObject { | 255 class PDFAlphaBitmap : public SkPDFObject { |
247 public: | 256 public: |
248 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {} | 257 PDFAlphaBitmap(const SkImage* image) : fImage(SkRef(image)) {} |
249 ~PDFAlphaBitmap() {} | 258 ~PDFAlphaBitmap() {} |
250 void emitObject(SkWStream*, | 259 void emitObject(SkWStream*, |
251 const SkPDFObjNumMap&, | 260 const SkPDFObjNumMap&, |
252 const SkPDFSubstituteMap&) const override; | 261 const SkPDFSubstituteMap&) const override; |
253 | 262 |
254 private: | 263 private: |
255 const SkBitmap fBitmap; | 264 SkAutoTUnref<const SkImage> fImage; |
256 }; | 265 }; |
257 | 266 |
258 void PDFAlphaBitmap::emitObject(SkWStream* stream, | 267 void PDFAlphaBitmap::emitObject(SkWStream* stream, |
259 const SkPDFObjNumMap& objNumMap, | 268 const SkPDFObjNumMap& objNumMap, |
260 const SkPDFSubstituteMap& substitutes) const { | 269 const SkPDFSubstituteMap& substitutes) const { |
261 SkAutoLockPixels autoLockPixels(fBitmap); | 270 SkBitmap bitmap; |
262 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || | 271 image_get_ro_pixels(fImage, &bitmap); |
263 fBitmap.getColorTable()); | 272 SkAutoLockPixels autoLockPixels(bitmap); |
273 SkASSERT(bitmap.colorType() != kIndex_8_SkColorType || | |
274 bitmap.getColorTable()); | |
264 | 275 |
265 // Write to a temporary buffer to get the compressed length. | 276 // Write to a temporary buffer to get the compressed length. |
266 SkDynamicMemoryWStream buffer; | 277 SkDynamicMemoryWStream buffer; |
267 SkDeflateWStream deflateWStream(&buffer); | 278 SkDeflateWStream deflateWStream(&buffer); |
268 bitmap_alpha_to_a8(fBitmap, &deflateWStream); | 279 bitmap_alpha_to_a8(bitmap, &deflateWStream); |
269 deflateWStream.finalize(); // call before detachAsStream(). | 280 deflateWStream.finalize(); // call before detachAsStream(). |
270 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 281 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
271 | 282 |
272 SkPDFDict pdfDict("XObject"); | 283 SkPDFDict pdfDict("XObject"); |
273 pdfDict.insertName("Subtype", "Image"); | 284 pdfDict.insertName("Subtype", "Image"); |
274 pdfDict.insertInt("Width", fBitmap.width()); | 285 pdfDict.insertInt("Width", bitmap.width()); |
275 pdfDict.insertInt("Height", fBitmap.height()); | 286 pdfDict.insertInt("Height", bitmap.height()); |
276 pdfDict.insertName("ColorSpace", "DeviceGray"); | 287 pdfDict.insertName("ColorSpace", "DeviceGray"); |
277 pdfDict.insertInt("BitsPerComponent", 8); | 288 pdfDict.insertInt("BitsPerComponent", 8); |
278 pdfDict.insertName("Filter", "FlateDecode"); | 289 pdfDict.insertName("Filter", "FlateDecode"); |
279 pdfDict.insertInt("Length", asset->getLength()); | 290 pdfDict.insertInt("Length", asset->getLength()); |
280 pdfDict.emitObject(stream, objNumMap, substitutes); | 291 pdfDict.emitObject(stream, objNumMap, substitutes); |
281 | 292 |
282 pdf_stream_begin(stream); | 293 pdf_stream_begin(stream); |
283 stream->writeStream(asset.get(), asset->getLength()); | 294 stream->writeStream(asset.get(), asset->getLength()); |
284 pdf_stream_end(stream); | 295 pdf_stream_end(stream); |
285 } | 296 } |
286 } // namespace | 297 } // namespace |
287 | 298 |
288 //////////////////////////////////////////////////////////////////////////////// | 299 //////////////////////////////////////////////////////////////////////////////// |
289 | 300 |
290 namespace { | 301 namespace { |
291 class PDFDefaultBitmap : public SkPDFBitmap { | 302 class PDFDefaultBitmap : public SkPDFObject { |
292 public: | 303 public: |
293 const SkAutoTUnref<SkPDFObject> fSMask; | |
294 void emitObject(SkWStream*, | 304 void emitObject(SkWStream*, |
295 const SkPDFObjNumMap&, | 305 const SkPDFObjNumMap&, |
296 const SkPDFSubstituteMap&) const override; | 306 const SkPDFSubstituteMap&) const override; |
297 void addResources(SkPDFObjNumMap*, | 307 void addResources(SkPDFObjNumMap*, |
298 const SkPDFSubstituteMap&) const override; | 308 const SkPDFSubstituteMap&) const override; |
299 PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask) | 309 PDFDefaultBitmap(const SkImage* image, SkPDFObject* smask) |
300 : SkPDFBitmap(bm), fSMask(smask) {} | 310 : fImage(SkRef(image)), fSMask(smask) {} |
311 | |
312 private: | |
313 SkAutoTUnref<const SkImage> fImage; | |
314 const SkAutoTUnref<SkPDFObject> fSMask; | |
301 }; | 315 }; |
302 } // namespace | 316 } // namespace |
303 | 317 |
304 void PDFDefaultBitmap::addResources( | 318 void PDFDefaultBitmap::addResources( |
305 SkPDFObjNumMap* catalog, | 319 SkPDFObjNumMap* catalog, |
306 const SkPDFSubstituteMap& substitutes) const { | 320 const SkPDFSubstituteMap& substitutes) const { |
307 if (fSMask.get()) { | 321 if (fSMask.get()) { |
308 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get()); | 322 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get()); |
309 SkASSERT(obj); | 323 SkASSERT(obj); |
310 if (catalog->addObject(obj)) { | 324 if (catalog->addObject(obj)) { |
(...skipping 25 matching lines...) Expand all Loading... | |
336 const SkPMColor* colors = table->readColors(); | 350 const SkPMColor* colors = table->readColors(); |
337 for (int i = 0; i < table->count(); i++) { | 351 for (int i = 0; i < table->count(); i++) { |
338 pmcolor_to_rgb24(colors[i], tablePtr); | 352 pmcolor_to_rgb24(colors[i], tablePtr); |
339 tablePtr += 3; | 353 tablePtr += 3; |
340 } | 354 } |
341 SkString tableString(tableArray, 3 * table->count()); | 355 SkString tableString(tableArray, 3 * table->count()); |
342 result->appendString(tableString); | 356 result->appendString(tableString); |
343 return result; | 357 return result; |
344 } | 358 } |
345 | 359 |
346 void PDFDefaultBitmap::emitObject(SkWStream* stream, | 360 void PDFDefaultBitmap::emitObject(SkWStream* stream, |
tomhudson
2015/09/30 16:10:29
There's a lot of redundancy between this and PDFAl
hal.canary
2015/10/01 01:24:55
Done.
| |
347 const SkPDFObjNumMap& objNumMap, | 361 const SkPDFObjNumMap& objNumMap, |
348 const SkPDFSubstituteMap& substitutes) const { | 362 const SkPDFSubstituteMap& substitutes) const { |
349 SkAutoLockPixels autoLockPixels(fBitmap); | 363 SkBitmap bitmap; |
350 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || | 364 image_get_ro_pixels(fImage, &bitmap); // TODO(halcanary): test |
tomhudson
2015/09/30 16:10:29
note TODO?
hal.canary
2015/10/01 01:24:55
Acknowledged.
| |
351 fBitmap.getColorTable()); | 365 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images? |
366 SkASSERT(bitmap.colorType() != kIndex_8_SkColorType || | |
367 bitmap.getColorTable()); | |
352 | 368 |
353 // Write to a temporary buffer to get the compressed length. | 369 // Write to a temporary buffer to get the compressed length. |
354 SkDynamicMemoryWStream buffer; | 370 SkDynamicMemoryWStream buffer; |
355 SkDeflateWStream deflateWStream(&buffer); | 371 SkDeflateWStream deflateWStream(&buffer); |
356 bitmap_to_pdf_pixels(fBitmap, &deflateWStream); | 372 bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
357 deflateWStream.finalize(); // call before detachAsStream(). | 373 deflateWStream.finalize(); // call before detachAsStream(). |
358 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 374 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
359 | 375 |
360 SkPDFDict pdfDict("XObject"); | 376 SkPDFDict pdfDict("XObject"); |
361 pdfDict.insertName("Subtype", "Image"); | 377 pdfDict.insertName("Subtype", "Image"); |
362 pdfDict.insertInt("Width", fBitmap.width()); | 378 pdfDict.insertInt("Width", bitmap.width()); |
363 pdfDict.insertInt("Height", fBitmap.height()); | 379 pdfDict.insertInt("Height", bitmap.height()); |
364 if (fBitmap.colorType() == kIndex_8_SkColorType) { | 380 if (bitmap.colorType() == kIndex_8_SkColorType) { |
365 SkASSERT(1 == pdf_color_component_count(fBitmap.colorType())); | 381 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
366 pdfDict.insertObject("ColorSpace", | 382 pdfDict.insertObject("ColorSpace", |
367 make_indexed_color_space(fBitmap.getColorTable())); | 383 make_indexed_color_space(bitmap.getColorTable())); |
368 } else if (1 == pdf_color_component_count(fBitmap.colorType())) { | 384 } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
369 pdfDict.insertName("ColorSpace", "DeviceGray"); | 385 pdfDict.insertName("ColorSpace", "DeviceGray"); |
370 } else { | 386 } else { |
371 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 387 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
372 } | 388 } |
373 pdfDict.insertInt("BitsPerComponent", 8); | 389 pdfDict.insertInt("BitsPerComponent", 8); |
374 if (fSMask) { | 390 if (fSMask) { |
375 pdfDict.insertObjRef("SMask", SkRef(fSMask.get())); | 391 pdfDict.insertObjRef("SMask", SkRef(fSMask.get())); |
376 } | 392 } |
377 pdfDict.insertName("Filter", "FlateDecode"); | 393 pdfDict.insertName("Filter", "FlateDecode"); |
378 pdfDict.insertInt("Length", asset->getLength()); | 394 pdfDict.insertInt("Length", asset->getLength()); |
379 pdfDict.emitObject(stream, objNumMap, substitutes); | 395 pdfDict.emitObject(stream, objNumMap, substitutes); |
380 | 396 |
381 pdf_stream_begin(stream); | 397 pdf_stream_begin(stream); |
382 stream->writeStream(asset.get(), asset->getLength()); | 398 stream->writeStream(asset.get(), asset->getLength()); |
383 pdf_stream_end(stream); | 399 pdf_stream_end(stream); |
384 } | 400 } |
385 | 401 |
386 //////////////////////////////////////////////////////////////////////////////// | 402 //////////////////////////////////////////////////////////////////////////////// |
387 | 403 |
388 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) { | |
389 if (bm.isImmutable()) { | |
390 return bm; | |
391 } | |
392 bm.copyTo(copy); | |
393 copy->setImmutable(); | |
394 return *copy; | |
395 } | |
396 | |
397 namespace { | 404 namespace { |
398 /** | 405 /** |
399 * This PDFObject assumes that its constructor was handed YUV JFIF | 406 * This PDFObject assumes that its constructor was handed YUV or |
400 * Jpeg-encoded data that can be directly embedded into a PDF. | 407 * Grayscale JFIF Jpeg-encoded data that can be directly embedded |
408 * into a PDF. | |
401 */ | 409 */ |
402 class PDFJpegBitmap : public SkPDFBitmap { | 410 class PDFJpegBitmap : public SkPDFObject { |
403 public: | 411 public: |
412 SkISize fSize; | |
404 SkAutoTUnref<SkData> fData; | 413 SkAutoTUnref<SkData> fData; |
405 bool fIsYUV; | 414 bool fIsYUV; |
406 PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV) | 415 PDFJpegBitmap(SkISize size, SkData* data, bool isYUV) |
407 : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {} | 416 : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) {} |
408 void emitObject(SkWStream*, | 417 void emitObject(SkWStream*, |
409 const SkPDFObjNumMap&, | 418 const SkPDFObjNumMap&, |
410 const SkPDFSubstituteMap&) const override; | 419 const SkPDFSubstituteMap&) const override; |
411 }; | 420 }; |
412 | 421 |
413 void PDFJpegBitmap::emitObject(SkWStream* stream, | 422 void PDFJpegBitmap::emitObject(SkWStream* stream, |
414 const SkPDFObjNumMap& objNumMap, | 423 const SkPDFObjNumMap& objNumMap, |
415 const SkPDFSubstituteMap& substituteMap) const { | 424 const SkPDFSubstituteMap& substituteMap) const { |
416 SkPDFDict pdfDict("XObject"); | 425 SkPDFDict pdfDict("XObject"); |
417 pdfDict.insertName("Subtype", "Image"); | 426 pdfDict.insertName("Subtype", "Image"); |
418 pdfDict.insertInt("Width", fBitmap.width()); | 427 pdfDict.insertInt("Width", fSize.width()); |
419 pdfDict.insertInt("Height", fBitmap.height()); | 428 pdfDict.insertInt("Height", fSize.height()); |
420 if (fIsYUV) { | 429 if (fIsYUV) { |
421 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 430 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
422 } else { | 431 } else { |
423 pdfDict.insertName("ColorSpace", "DeviceGray"); | 432 pdfDict.insertName("ColorSpace", "DeviceGray"); |
424 } | 433 } |
425 pdfDict.insertInt("BitsPerComponent", 8); | 434 pdfDict.insertInt("BitsPerComponent", 8); |
426 pdfDict.insertName("Filter", "DCTDecode"); | 435 pdfDict.insertName("Filter", "DCTDecode"); |
427 pdfDict.insertInt("ColorTransform", 0); | 436 pdfDict.insertInt("ColorTransform", 0); |
428 pdfDict.insertInt("Length", SkToInt(fData->size())); | 437 pdfDict.insertInt("Length", SkToInt(fData->size())); |
429 pdfDict.emitObject(stream, objNumMap, substituteMap); | 438 pdfDict.emitObject(stream, objNumMap, substituteMap); |
430 pdf_stream_begin(stream); | 439 pdf_stream_begin(stream); |
431 stream->write(fData->data(), fData->size()); | 440 stream->write(fData->data(), fData->size()); |
432 pdf_stream_end(stream); | 441 pdf_stream_end(stream); |
433 } | 442 } |
434 } // namespace | 443 } // namespace |
435 | 444 |
436 //////////////////////////////////////////////////////////////////////////////// | 445 //////////////////////////////////////////////////////////////////////////////// |
437 | 446 |
438 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { | 447 SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) { |
439 SkASSERT(canon); | 448 SkAutoTUnref<SkData> data(image->refEncoded()); |
440 if (!SkColorTypeIsValid(bitmap.colorType()) || | 449 SkJFIFInfo info; |
441 kUnknown_SkColorType == bitmap.colorType()) { | 450 if (data && SkIsJFIF(data, &info)) { |
442 return nullptr; | 451 bool yuv = info.fType == SkJFIFInfo::kYCbCr; |
443 } | 452 if (info.fSize == image->dimensions()) { // Sanity check. |
444 SkBitmap copy; | 453 // hold on to data, not image. |
445 const SkBitmap& bm = immutable_bitmap(bitmap, ©); | 454 #ifdef SK_PDF_IMAGE_STATS |
446 if (bm.drawsNothing()) { | 455 gJpegImageObjects.fetch_add(1); |
447 return nullptr; | 456 #endif |
448 } | 457 return new PDFJpegBitmap(info.fSize, data, yuv); |
449 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { | |
450 return SkRef(canonBitmap); | |
451 } | |
452 | |
453 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() && | |
454 bm.dimensions() == bm.pixelRef()->info().dimensions()) { | |
455 // Requires the bitmap to be backed by lazy pixels. | |
456 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); | |
457 SkJFIFInfo info; | |
458 if (data && SkIsJFIF(data, &info)) { | |
459 bool yuv = info.fType == SkJFIFInfo::kYCbCr; | |
460 SkPDFBitmap* pdfBitmap = new PDFJpegBitmap(bm, data, yuv); | |
461 canon->addBitmap(pdfBitmap); | |
462 return pdfBitmap; | |
463 } | 458 } |
464 } | 459 } |
465 | 460 SkPDFObject* smask = |
466 SkPDFObject* smask = nullptr; | 461 image->isOpaque() ? nullptr : new PDFAlphaBitmap(image); |
467 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { | 462 #ifdef SK_PDF_IMAGE_STATS |
468 smask = new PDFAlphaBitmap(bm); | 463 gRegularImageObjects.fetch_add(1); |
469 } | 464 #endif |
470 SkPDFBitmap* pdfBitmap = new PDFDefaultBitmap(bm, smask); | 465 return new PDFDefaultBitmap(image, smask); |
471 canon->addBitmap(pdfBitmap); | |
472 return pdfBitmap; | |
473 } | 466 } |
OLD | NEW |