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 "SkFlate.h" | 10 #include "SkFlate.h" |
11 #include "SkImageGenerator.h" | 11 #include "SkImageGenerator.h" |
| 12 #include "SkJpegInfo.h" |
12 #include "SkPDFBitmap.h" | 13 #include "SkPDFBitmap.h" |
13 #include "SkPDFCanon.h" | 14 #include "SkPDFCanon.h" |
14 #include "SkPixelRef.h" | 15 #include "SkPixelRef.h" |
15 #include "SkStream.h" | 16 #include "SkStream.h" |
16 #include "SkUnPreMultiply.h" | 17 #include "SkUnPreMultiply.h" |
17 | 18 |
18 //////////////////////////////////////////////////////////////////////////////// | 19 //////////////////////////////////////////////////////////////////////////////// |
19 | 20 |
20 static void pdf_stream_begin(SkWStream* stream) { | 21 static void pdf_stream_begin(SkWStream* stream) { |
21 static const char streamBegin[] = " stream\n"; | 22 static const char streamBegin[] = " stream\n"; |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 } | 395 } |
395 | 396 |
396 namespace { | 397 namespace { |
397 /** | 398 /** |
398 * This PDFObject assumes that its constructor was handed YUV JFIF | 399 * This PDFObject assumes that its constructor was handed YUV JFIF |
399 * Jpeg-encoded data that can be directly embedded into a PDF. | 400 * Jpeg-encoded data that can be directly embedded into a PDF. |
400 */ | 401 */ |
401 class PDFJpegBitmap : public SkPDFBitmap { | 402 class PDFJpegBitmap : public SkPDFBitmap { |
402 public: | 403 public: |
403 SkAutoTUnref<SkData> fData; | 404 SkAutoTUnref<SkData> fData; |
404 PDFJpegBitmap(const SkBitmap& bm, SkData* data) | 405 bool fIsYUV; |
405 : SkPDFBitmap(bm), fData(SkRef(data)) {} | 406 PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV) |
| 407 : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {} |
406 void emitObject(SkWStream*, | 408 void emitObject(SkWStream*, |
407 const SkPDFObjNumMap&, | 409 const SkPDFObjNumMap&, |
408 const SkPDFSubstituteMap&) override; | 410 const SkPDFSubstituteMap&) override; |
409 }; | 411 }; |
410 | 412 |
411 void PDFJpegBitmap::emitObject(SkWStream* stream, | 413 void PDFJpegBitmap::emitObject(SkWStream* stream, |
412 const SkPDFObjNumMap& objNumMap, | 414 const SkPDFObjNumMap& objNumMap, |
413 const SkPDFSubstituteMap& substituteMap) { | 415 const SkPDFSubstituteMap& substituteMap) { |
414 SkPDFDict pdfDict("XObject"); | 416 SkPDFDict pdfDict("XObject"); |
415 pdfDict.insertName("Subtype", "Image"); | 417 pdfDict.insertName("Subtype", "Image"); |
416 pdfDict.insertInt("Width", fBitmap.width()); | 418 pdfDict.insertInt("Width", fBitmap.width()); |
417 pdfDict.insertInt("Height", fBitmap.height()); | 419 pdfDict.insertInt("Height", fBitmap.height()); |
418 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 420 if (fIsYUV) { |
| 421 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| 422 } else { |
| 423 pdfDict.insertName("ColorSpace", "DeviceGray"); |
| 424 } |
419 pdfDict.insertInt("BitsPerComponent", 8); | 425 pdfDict.insertInt("BitsPerComponent", 8); |
420 pdfDict.insertName("Filter", "DCTDecode"); | 426 pdfDict.insertName("Filter", "DCTDecode"); |
421 pdfDict.insertInt("ColorTransform", 0); | 427 pdfDict.insertInt("ColorTransform", 0); |
422 pdfDict.insertInt("Length", SkToInt(fData->size())); | 428 pdfDict.insertInt("Length", SkToInt(fData->size())); |
423 pdfDict.emitObject(stream, objNumMap, substituteMap); | 429 pdfDict.emitObject(stream, objNumMap, substituteMap); |
424 pdf_stream_begin(stream); | 430 pdf_stream_begin(stream); |
425 stream->write(fData->data(), fData->size()); | 431 stream->write(fData->data(), fData->size()); |
426 pdf_stream_end(stream); | 432 pdf_stream_end(stream); |
427 } | 433 } |
428 } // namespace | 434 } // namespace |
429 | 435 |
430 //////////////////////////////////////////////////////////////////////////////// | 436 //////////////////////////////////////////////////////////////////////////////// |
431 | 437 |
432 static bool is_jfif_yuv_jpeg(SkData* data) { | |
433 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0}; | |
434 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0}; | |
435 // 0 1 2 3 4 5 6 7 8 9 10 | |
436 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ... | |
437 if (data->size() < 11 || | |
438 0 != memcmp(data->bytes(), bytesZeroToThree, | |
439 sizeof(bytesZeroToThree)) || | |
440 0 != memcmp(data->bytes() + 6, bytesSixToTen, sizeof(bytesSixToTen))) { | |
441 return false; | |
442 } | |
443 SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromData(data)); | |
444 SkISize sizes[3]; | |
445 // Only YUV JPEG allows access to YUV planes. | |
446 return gen && gen->getYUV8Planes(sizes, NULL, NULL, NULL); | |
447 } | |
448 | |
449 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { | 438 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { |
450 SkASSERT(canon); | 439 SkASSERT(canon); |
451 if (!SkColorTypeIsValid(bitmap.colorType()) || | 440 if (!SkColorTypeIsValid(bitmap.colorType()) || |
452 kUnknown_SkColorType == bitmap.colorType()) { | 441 kUnknown_SkColorType == bitmap.colorType()) { |
453 return NULL; | 442 return NULL; |
454 } | 443 } |
455 SkBitmap copy; | 444 SkBitmap copy; |
456 const SkBitmap& bm = immutable_bitmap(bitmap, ©); | 445 const SkBitmap& bm = immutable_bitmap(bitmap, ©); |
457 if (bm.drawsNothing()) { | 446 if (bm.drawsNothing()) { |
458 return NULL; | 447 return NULL; |
459 } | 448 } |
460 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { | 449 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { |
461 return SkRef(canonBitmap); | 450 return SkRef(canonBitmap); |
462 } | 451 } |
463 | 452 |
464 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() && | 453 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() && |
465 bm.dimensions() == bm.pixelRef()->info().dimensions()) { | 454 bm.dimensions() == bm.pixelRef()->info().dimensions()) { |
466 // Requires the bitmap to be backed by lazy pixels. | 455 // Requires the bitmap to be backed by lazy pixels. |
467 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); | 456 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
468 if (data && is_jfif_yuv_jpeg(data)) { | 457 SkJFIFInfo info; |
469 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data)); | 458 if (data && SkIsJFIF(data, &info)) { |
| 459 bool yuv = info.fType == SkJFIFInfo::kYCbCr; |
| 460 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data, yuv)); |
470 canon->addBitmap(pdfBitmap); | 461 canon->addBitmap(pdfBitmap); |
471 return pdfBitmap; | 462 return pdfBitmap; |
472 } | 463 } |
473 } | 464 } |
474 | 465 |
475 SkPDFObject* smask = NULL; | 466 SkPDFObject* smask = NULL; |
476 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { | 467 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { |
477 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); | 468 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); |
478 } | 469 } |
479 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask)); | 470 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask)); |
480 canon->addBitmap(pdfBitmap); | 471 canon->addBitmap(pdfBitmap); |
481 return pdfBitmap; | 472 return pdfBitmap; |
482 } | 473 } |
OLD | NEW |