diff options
author | Hal Canary <halcanary@google.com> | 2018-04-05 16:58:41 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-07 14:25:30 +0000 |
commit | 83e0f1b1bb111c99d2f11d382b31caef0af5de10 (patch) | |
tree | 8ed18a789d4f8b72525ccd308af2a08e9ea409ef /src | |
parent | c7695ff269a6ec7c4420d571d9077f2895166083 (diff) |
SkPDF: smarter Jpeg when libjpeg-turbo is present
The fallback code does not parse the color type for EXIF-only jpegs.
Since these exist in the wild, we need to find out if they are really
standard YUV or greyscale Jpegs and embed them in PDFs if they are.
BUG=chromium:801430
Change-Id: I93eaf8b8fc22b7169b2fce9520e022b72ad0bf81
Reviewed-on: https://skia-review.googlesource.com/118992
Commit-Queue: Hal Canary <halcanary@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/codec/SkJpegCodec.cpp | 45 | ||||
-rw-r--r-- | src/pdf/SkJpegInfo.cpp | 35 | ||||
-rw-r--r-- | src/pdf/SkJpegInfo.h | 26 | ||||
-rw-r--r-- | src/pdf/SkPDFBitmap.cpp | 44 |
4 files changed, 101 insertions, 49 deletions
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 4f48886be2..2cc7921277 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -5,11 +5,13 @@ * found in the LICENSE file. */ -#include "SkCodec.h" #include "SkJpegCodec.h" -#include "SkJpegDecoderMgr.h" + +#include "SkCodec.h" #include "SkCodecPriv.h" #include "SkColorData.h" +#include "SkJpegDecoderMgr.h" +#include "SkJpegInfo.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkTypes.h" @@ -968,3 +970,42 @@ SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void return kSuccess; } + +// This function is declared in SkJpegInfo.h, used by SkPDF. +bool SkGetJpegInfo(const void* data, size_t len, + SkISize* size, + SkEncodedInfo::Color* colorType, + SkEncodedOrigin* orientation) { + if (!SkJpegCodec::IsJpeg(data, len)) { + return false; + } + + SkMemoryStream stream(data, len); + JpegDecoderMgr decoderMgr(&stream); + // libjpeg errors will be caught and reported here + skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr.errorMgr()); + if (setjmp(jmp)) { + return false; + } + decoderMgr.init(); + jpeg_decompress_struct* dinfo = decoderMgr.dinfo(); + jpeg_save_markers(dinfo, kExifMarker, 0xFFFF); + jpeg_save_markers(dinfo, kICCMarker, 0xFFFF); + if (JPEG_HEADER_OK != jpeg_read_header(dinfo, true)) { + return false; + } + SkEncodedInfo::Color encodedColorType; + if (!decoderMgr.getEncodedColor(&encodedColorType)) { + return false; // Unable to interpret the color channels as colors. + } + if (colorType) { + *colorType = encodedColorType; + } + if (orientation) { + *orientation = get_exif_orientation(dinfo); + } + if (size) { + *size = {SkToS32(dinfo->image_width), SkToS32(dinfo->image_height)}; + } + return true; +} diff --git a/src/pdf/SkJpegInfo.cpp b/src/pdf/SkJpegInfo.cpp index 5e5ec792ea..df99de4e93 100644 --- a/src/pdf/SkJpegInfo.cpp +++ b/src/pdf/SkJpegInfo.cpp @@ -5,15 +5,16 @@ * found in the LICENSE file. */ -#include "SkData.h" #include "SkJpegInfo.h" +#ifndef SK_HAS_JPEG_LIBRARY + namespace { class JpegSegment { public: - JpegSegment(const SkData* skdata) - : fData(static_cast<const char*>(skdata->data())) - , fSize(skdata->size()) + JpegSegment(const void* data, size_t size) + : fData(static_cast<const char*>(data)) + , fSize(size) , fOffset(0) , fLength(0) {} bool read() { @@ -75,10 +76,13 @@ private: }; } // namespace -bool SkIsJFIF(const SkData* skdata, SkJFIFInfo* info) { +bool SkGetJpegInfo(const void* data, size_t len, + SkISize* size, + SkEncodedInfo::Color* colorType, + SkEncodedOrigin* orientation) { static const uint16_t kSOI = 0xFFD8; static const uint16_t kAPP0 = 0xFFE0; - JpegSegment segment(skdata); + JpegSegment segment(data, len); if (!segment.read() || segment.marker() != kSOI) { return false; // not a JPEG } @@ -106,14 +110,17 @@ bool SkIsJFIF(const SkData* skdata, SkJFIFInfo* info) { if (numberOfComponents != 1 && numberOfComponents != 3) { return false; // Invalid JFIF } - if (info) { - info->fSize.set(JpegSegment::GetBigendianUint16(&segment.data()[3]), - JpegSegment::GetBigendianUint16(&segment.data()[1])); - if (numberOfComponents == 3) { - info->fType = SkJFIFInfo::kYCbCr; - } else { - info->fType = SkJFIFInfo::kGrayscale; - } + if (size) { + *size = {JpegSegment::GetBigendianUint16(&segment.data()[3]), + JpegSegment::GetBigendianUint16(&segment.data()[1])}; + } + if (colorType) { + *colorType = numberOfComponents == 3 ? SkEncodedInfo::kYUV_Color + : SkEncodedInfo::kGray_Color; + } + if (orientation) { + *orientation = kTopLeft_SkEncodedOrigin; } return true; } +#endif // SK_HAS_JPEG_LIBRARY diff --git a/src/pdf/SkJpegInfo.h b/src/pdf/SkJpegInfo.h index 39de99455a..2f0eb6f54a 100644 --- a/src/pdf/SkJpegInfo.h +++ b/src/pdf/SkJpegInfo.h @@ -7,25 +7,19 @@ #ifndef SkJpegInfo_DEFINED #define SkJpegInfo_DEFINED +#include "SkEncodedInfo.h" +#include "SkEncodedOrigin.h" #include "SkSize.h" -class SkData; +/** Returns true if the data seems to be a valid JPEG image with a known colorType. -struct SkJFIFInfo { - SkISize fSize; - enum Type { - kGrayscale, - kYCbCr, - } fType; -}; - -/** Returns true iff the data seems to be a valid JFIF JPEG image. - If so and if info is not nullptr, populate info. - - JPEG/JFIF References: - http://www.w3.org/Graphics/JPEG/itu-t81.pdf - http://www.w3.org/Graphics/JPEG/jfif3.pdf + @param [out] size Image size in pixels + @param [out] colorType Encoded color type (kGray_Color, kYUV_Color, several others). + @param [out] orientation EXIF Orientation of the image. */ -bool SkIsJFIF(const SkData* skdata, SkJFIFInfo* info); +bool SkGetJpegInfo(const void* data, size_t len, + SkISize* size, + SkEncodedInfo::Color* colorType, + SkEncodedOrigin* orientation); #endif // SkJpegInfo_DEFINED diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp index faae47ef63..b575d16430 100644 --- a/src/pdf/SkPDFBitmap.cpp +++ b/src/pdf/SkPDFBitmap.cpp @@ -376,8 +376,8 @@ public: SkISize fSize; sk_sp<SkData> fData; bool fIsYUV; - PDFJpegBitmap(SkISize size, SkData* data, bool isYUV) - : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); } + PDFJpegBitmap(SkISize size, sk_sp<SkData> data, bool isYUV) + : fSize(size), fData(std::move(data)), fIsYUV(isYUV) { SkASSERT(fData); } void emitObject(SkWStream*, const SkPDFObjNumMap&) const override; void drop() override { fData = nullptr; } }; @@ -406,32 +406,42 @@ void PDFJpegBitmap::emitObject(SkWStream* stream, } // namespace //////////////////////////////////////////////////////////////////////////////// - -sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, int encodingQuality) { - SkASSERT(image); - SkASSERT(encodingQuality >= 0); - sk_sp<SkData> data = image->refEncodedData(); - SkJFIFInfo info; - if (data && SkIsJFIF(data.get(), &info)) { - bool yuv = info.fType == SkJFIFInfo::kYCbCr; - if (info.fSize == image->dimensions()) { // Sanity check. +sk_sp<PDFJpegBitmap> make_jpeg_bitmap(sk_sp<SkData> data, SkISize size) { + SkISize jpegSize; + SkEncodedInfo::Color jpegColorType; + SkEncodedOrigin exifOrientation; + if (data && SkGetJpegInfo(data->data(), data->size(), &jpegSize, + &jpegColorType, &exifOrientation)) { + bool yuv = jpegColorType == SkEncodedInfo::kYUV_Color; + bool goodColorType = yuv || jpegColorType == SkEncodedInfo::kGray_Color; + if (jpegSize == size // Sanity check. + && goodColorType + && kTopLeft_SkEncodedOrigin == exifOrientation) { // hold on to data, not image. #ifdef SK_PDF_IMAGE_STATS gJpegImageObjects.fetch_add(1); #endif - return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv); + return sk_make_sp<PDFJpegBitmap>(jpegSize, std::move(data), yuv); } } + return nullptr; +} + +sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, int encodingQuality) { + SkASSERT(image); + SkASSERT(encodingQuality >= 0); + SkISize dimensions = image->dimensions(); + sk_sp<SkData> data = image->refEncodedData(); + if (auto jpeg = make_jpeg_bitmap(std::move(data), dimensions)) { + return jpeg; + } const bool isOpaque = image_compute_is_opaque(image.get()); if (encodingQuality <= 100 && isOpaque) { data = image->encodeToData(SkEncodedImageFormat::kJPEG, encodingQuality); - if (data && SkIsJFIF(data.get(), &info)) { - bool yuv = info.fType == SkJFIFInfo::kYCbCr; - if (info.fSize == image->dimensions()) { // Sanity check. - return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv); - } + if (auto jpeg = make_jpeg_bitmap(std::move(data), dimensions)) { + return jpeg; } } |