| 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 |