Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(851)

Unified Diff: third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp

Issue 1403393004: JPEGImageDecoder RGB565 and downsample support and related Skia imagegenerator changes Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Continued decoding fix and downscale combined Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index a77a3f4bff35338403be10a21d71786f4ac15189..3b6045390f61bced1b4968e703a3bd4dabab61ee 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -65,7 +65,7 @@ inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_RGBA; }
#else // Output little-endian BGRA pixels.
inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_BGRA; }
#endif
-inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { return colorSpace == JCS_EXT_RGBA || colorSpace == JCS_EXT_BGRA; }
+inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { return colorSpace == JCS_EXT_RGBA || colorSpace == JCS_EXT_BGRA || colorSpace == JCS_RGB565; }
inline bool colorSpaceHasAlpha(J_COLOR_SPACE colorSpace) { return turboSwizzled(colorSpace); }
#else
inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_RGB; }
@@ -432,6 +432,16 @@ public:
bool decode(bool onlySize)
{
+ if ((m_state == JPEG_DECOMPRESS_SEQUENTIAL || m_state == JPEG_DECOMPRESS_PROGRESSIVE)
+ && m_decoder->hasFramebufferChanged()) {
+ // when previous attempts to decode failed with not all data available,
+ // decoder continues. Once that all data is available (and there is no alpha)
+ // and client calls decode to rgb565 or downsampling, it is needed to restart decompression
+ // FIXME restart decompression without reading header
+ clearBuffer();
+ m_state = JPEG_HEADER;
+ }
+
// We need to do the setjmp here. Otherwise bad things will happen
if (setjmp(m_err.setjmp_buffer))
return m_decoder->setFailed();
@@ -472,6 +482,21 @@ public:
default:
return m_decoder->setFailed();
}
+ if (m_decoder->decodeToRGB565Enabled()) {
+ if (m_info.out_color_space == rgbOutputColorSpace()) {
+ // the rest would need to be converted manually on write
+#if defined (JCS_ALPHA_EXTENSIONS)
+ m_info.out_color_space = JCS_RGB565;
+#endif
+#if USE(QCMSLIB)
+ // if there is colorprofile, use JCS_RGB as QCMS is not supporting RGB565
+ // conversion, RGB->RGB565 happens in outputRows<>()
+ if (!m_decoder->ignoresGammaAndColorProfile())
+ m_info.out_color_space = JCS_RGB;
+#endif
+ }
+ }
+ // FALL THROUGH
m_state = JPEG_START_DECOMPRESS;
@@ -588,6 +613,7 @@ public:
case JPEG_DECOMPRESS_PROGRESSIVE:
if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) {
+
int status = 0;
do {
decoder_error_mgr* err = reinterpret_cast_ptr<decoder_error_mgr*>(m_info.err);
@@ -780,6 +806,8 @@ void term_source(j_decompress_ptr jd)
JPEGImageDecoder::JPEGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes)
: ImageDecoder(alphaOption, colorOptions, maxDecodedBytes)
, m_hasColorProfile(false)
+ , m_decodeColor(ImageFrame::RGBA8888)
+ , m_originalMaxDecodedBytes(maxDecodedBytes)
{
}
@@ -821,7 +849,8 @@ IntSize JPEGImageDecoder::decodedYUVSize(int component, ImageDecoder::SizeType s
unsigned JPEGImageDecoder::desiredScaleNumerator() const
{
- size_t originalBytes = size().width() * size().height() * 4;
+ size_t originalBytes = size().width() * size().height()
+ * (decodeToRGB565Enabled() ? 2 : 4);
if (originalBytes <= m_maxDecodedBytes) {
return scaleDenominator;
}
@@ -841,6 +870,64 @@ bool JPEGImageDecoder::canDecodeToYUV()
return isSizeAvailable() && m_reader->info()->out_color_space == JCS_YCbCr;
}
+void JPEGImageDecoder::getAvailableDecodeAndScale(ImageFrame::ColorType* outType, float* scale, float* lowerScale)
+{
+ if (outType) {
+ if (*outType != ImageFrame::RGBA8888 && *outType != ImageFrame::RGB565)
+ *outType = ImageFrame::RGBA8888;
+ }
+ if (scale) {
+ unsigned upper = static_cast<unsigned>(ceil(*scale * scaleDenominator));
+ upper = (upper > scaleDenominator) ? scaleDenominator : upper;
+ unsigned lower = upper - 1;
+ *scale = static_cast<float>(upper) / static_cast<float>(scaleDenominator);
+
+ if (lowerScale)
+ *lowerScale = static_cast<float>(lower) / static_cast<float>(scaleDenominator);
+ return;
+ }
+ if (lowerScale)
+ *lowerScale = 1.0f;
+}
+
+bool JPEGImageDecoder::activateDecodeAndScale(ImageFrame::ColorType outColor, size_t maxDecodedBytes)
+{
+ ASSERT(m_decodeColor == ImageFrame::RGBA8888);
+ if (outColor == ImageFrame::RGB565) {
+ m_decodeColor = ImageFrame::RGB565;
+ } else {
+ if (outColor != ImageFrame::RGBA8888) {
+ return false;
+ }
+ m_decodeColor = ImageFrame::RGBA8888;
+ }
+ m_originalMaxDecodedBytes = m_maxDecodedBytes;
+ m_maxDecodedBytes = maxDecodedBytes;
+ return true;
+}
+
+void JPEGImageDecoder::disableDecodeAndScale()
+{
+ m_decodeColor = ImageFrame::RGBA8888;
+ m_maxDecodedBytes = m_originalMaxDecodedBytes;
+}
+
+bool JPEGImageDecoder::hasFramebufferChanged() const
+{
+ // for decoding that doesn't restart (e.g. when previous decodings didn't have
+ // all of the data, and meanwhile decoding to different output size was requested
+ if (m_frameBufferCache.isEmpty() || hasImagePlanes()) {
+ return false;
+ }
+ const ImageFrame& buffer = m_frameBufferCache[0];
+ // size is important here, not the decoded color - so use the current one
+ // when checking size change
+ if (buffer.status() != ImageFrame::FrameEmpty && !buffer.hasSize(m_decodedSize, m_decodeColor))
+ return true;
+ return false;
+}
+
+
bool JPEGImageDecoder::decodeToYUV()
{
if (!hasImagePlanes())
@@ -856,18 +943,18 @@ void JPEGImageDecoder::setImagePlanes(PassOwnPtr<ImagePlanes> imagePlanes)
m_imagePlanes = imagePlanes;
}
-template <J_COLOR_SPACE colorSpace> void setPixel(ImageFrame& buffer, ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column)
+template <J_COLOR_SPACE colorSpace, class T> void setPixel(ImageFrame& buffer, T* pixel, JSAMPARRAY samples, int column)
{
ASSERT_NOT_REACHED();
}
-template <> void setPixel<JCS_RGB>(ImageFrame& buffer, ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column)
+template <> void setPixel<JCS_RGB, ImageFrame::PixelData>(ImageFrame& buffer, ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column)
{
JSAMPLE* jsample = *samples + column * 3;
buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255);
}
-template <> void setPixel<JCS_CMYK>(ImageFrame& buffer, ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column)
+template <> void setPixel<JCS_CMYK, ImageFrame::PixelData>(ImageFrame& buffer, ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column)
{
JSAMPLE* jsample = *samples + column * 4;
@@ -884,7 +971,30 @@ template <> void setPixel<JCS_CMYK>(ImageFrame& buffer, ImageFrame::PixelData* p
buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, jsample[2] * k / 255, 255);
}
-template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, ImageFrame& buffer)
+template <> void setPixel<JCS_RGB, ImageFrame::PixelData16>(ImageFrame& buffer, ImageFrame::PixelData16* pixel, JSAMPARRAY samples, int column)
+{
+ JSAMPLE* jsample = *samples + column * 3;
+ buffer.setRGB565(pixel, jsample[0], jsample[1], jsample[2]);
+}
+
+template <> void setPixel<JCS_CMYK, ImageFrame::PixelData16>(ImageFrame& buffer, ImageFrame::PixelData16* pixel, JSAMPARRAY samples, int column)
+{
+ JSAMPLE* jsample = *samples + column * 4;
+
+ // Source is 'Inverted CMYK', output is RGB.
+ // See: http://www.easyrgb.com/math.php?MATH=M12#text12
+ // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
+ // From CMYK to CMY:
+ // X = X * (1 - K ) + K [for X = C, M, or Y]
+ // Thus, from Inverted CMYK to CMY is:
+ // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK
+ // From CMY (0..1) to RGB (0..1):
+ // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar]
+ unsigned k = jsample[3];
+ buffer.setRGB565(pixel, jsample[0] * k / 255, jsample[1] * k / 255, jsample[2] * k / 255);
+}
+
+template <J_COLOR_SPACE colorSpace, class T> bool outputRows(JPEGImageReader* reader, ImageFrame& buffer)
{
JSAMPARRAY samples = reader->samples();
jpeg_decompress_struct* info = reader->info();
@@ -901,9 +1011,9 @@ template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, Ima
if (reader->colorTransform() && colorSpace == JCS_RGB)
qcms_transform_data(reader->colorTransform(), *samples, *samples, width);
#endif
- ImageFrame::PixelData* pixel = buffer.getAddr(0, y);
+ T* pixel = buffer.getAddrT<T>(0, y);
for (int x = 0; x < width; ++pixel, ++x)
- setPixel<colorSpace>(buffer, pixel, samples, x);
+ setPixel<colorSpace, T>(buffer, pixel, samples, x);
}
buffer.setPixelsChanged(true);
@@ -1005,12 +1115,16 @@ bool JPEGImageDecoder::outputScanlines()
ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width()));
ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.height()));
- if (!buffer.setSize(info->output_width, info->output_height))
+ if (!buffer.setSize(info->output_width, info->output_height, decodeToRGB565Enabled()
+ ? ImageFrame::RGB565 : ImageFrame::RGBA8888))
return setFailed();
buffer.setStatus(ImageFrame::FramePartial);
// The buffer is transparent outside the decoded area while the image is
// loading. The image will be marked fully opaque in complete().
- buffer.setHasAlpha(true);
+ // For RGB565 this would just fail, having bitmap opaque during decoding
+ // but, since RGB565 is used only for fully loaded content, this is not a problem
+ if (!decodeToRGB565Enabled())
+ buffer.setHasAlpha(true);
// For JPEGs, the frame always fills the entire image.
buffer.setOriginalFrameRect(IntRect(IntPoint(), size()));
@@ -1019,9 +1133,12 @@ bool JPEGImageDecoder::outputScanlines()
#if defined(TURBO_JPEG_RGB_SWIZZLE)
if (turboSwizzled(info->out_color_space)) {
while (info->output_scanline < info->output_height) {
- unsigned char* row = reinterpret_cast_ptr<unsigned char*>(buffer.getAddr(0, info->output_scanline));
- if (jpeg_read_scanlines(info, &row, 1) != 1)
+ unsigned char* row = decodeToRGB565Enabled()
+ ? reinterpret_cast_ptr<unsigned char*>(buffer.getAddrT<ImageFrame::PixelData16>(0, info->output_scanline))
+ : reinterpret_cast_ptr<unsigned char*>(buffer.getAddr(0, info->output_scanline));
+ if (jpeg_read_scanlines(info, &row, 1) != 1) {
return false;
+ }
#if USE(QCMSLIB)
if (qcms_transform* transform = m_reader->colorTransform())
qcms_transform_data_type(transform, row, row, info->output_width, rgbOutputColorSpace() == JCS_EXT_BGRA ? QCMS_OUTPUT_BGRX : QCMS_OUTPUT_RGBX);
@@ -1034,9 +1151,13 @@ bool JPEGImageDecoder::outputScanlines()
switch (info->out_color_space) {
case JCS_RGB:
- return outputRows<JCS_RGB>(m_reader.get(), buffer);
+ if (decodeToRGB565Enabled())
+ return outputRows<JCS_RGB, ImageFrame::PixelData16>(m_reader.get(), buffer);
+ return outputRows<JCS_RGB, ImageFrame::PixelData>(m_reader.get(), buffer);
case JCS_CMYK:
- return outputRows<JCS_CMYK>(m_reader.get(), buffer);
+ if (decodeToRGB565Enabled())
+ return outputRows<JCS_CMYK, ImageFrame::PixelData16>(m_reader.get(), buffer);
+ return outputRows<JCS_CMYK, ImageFrame::PixelData>(m_reader.get(), buffer);
default:
ASSERT_NOT_REACHED();
}

Powered by Google App Engine
This is Rietveld 408576698