summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp')
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp124
1 files changed, 86 insertions, 38 deletions
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 38d90bd..ae09586 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -6,6 +6,8 @@
* Other contributors:
* Stuart Parmenter <stuart@mozilla.com>
*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -38,17 +40,21 @@
#include "config.h"
#include "JPEGImageDecoder.h"
#include <assert.h>
-#include <stdio.h>
+#include <stdio.h> // Needed by jpeglib.h for FILE.
+
+#if PLATFORM(WINCE)
+// Remove warning: 'FAR' macro redefinition
+#undef FAR
+
+// jmorecfg.h in libjpeg checks for XMD_H with the comment: "X11/xmd.h correctly defines INT32"
+// fix INT32 redefinition error by pretending we are X11/xmd.h
+#define XMD_H
+#endif
extern "C" {
#include "jpeglib.h"
}
-#if COMPILER(MSVC)
-// Remove warnings from warning level 4.
-#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
-#endif // COMPILER(MSVC)
-
#include <setjmp.h>
namespace WebCore {
@@ -188,6 +194,10 @@ public:
break;
case JCS_CMYK:
case JCS_YCCK:
+ // jpeglib cannot convert these to rgb, but it can
+ // convert ycck to cmyk
+ m_info.out_color_space = JCS_CMYK;
+ break;
default:
m_state = JPEG_ERROR;
return false;
@@ -219,7 +229,10 @@ public:
m_state = JPEG_START_DECOMPRESS;
// We can fill in the size now that the header is available.
- m_decoder->setSize(m_info.image_width, m_info.image_height);
+ if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) {
+ m_state = JPEG_ERROR;
+ return false;
+ }
if (m_decodingSizeOnly) {
// We can stop here.
@@ -411,19 +424,12 @@ void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
}
// Whether or not the size information has been decoded yet.
-bool JPEGImageDecoder::isSizeAvailable() const
+bool JPEGImageDecoder::isSizeAvailable()
{
- // If we have pending data to decode, send it to the JPEG reader now.
- if (!m_sizeAvailable && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the
- // size is encountered.
- decode(true);
- }
+ if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
+ decode(true);
- return m_sizeAvailable;
+ return ImageDecoder::isSizeAvailable();
}
RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
@@ -442,7 +448,7 @@ RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
}
// Feed data to the JPEG reader.
-void JPEGImageDecoder::decode(bool sizeOnly) const
+void JPEGImageDecoder::decode(bool sizeOnly)
{
if (m_failed)
return;
@@ -455,45 +461,87 @@ void JPEGImageDecoder::decode(bool sizeOnly) const
}
}
+static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info)
+{
+ ASSERT(info->out_color_space == JCS_CMYK);
+
+ for (unsigned x = 0; x < info->output_width; ++x) {
+ unsigned c = *src++;
+ unsigned m = *src++;
+ unsigned y = *src++;
+ unsigned k = *src++;
+
+ // 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
+ // C = C * ( 1 - K ) + K
+ // M = M * ( 1 - K ) + K
+ // Y = Y * ( 1 - K ) + K
+
+ // From Inverted CMYK to CMY is thus:
+ // C = (1-iC) * (1 - (1-iK)) + (1-iK) => 1 - iC*iK
+ // Same for M and Y
+
+ // Convert from CMY (0..1) to RGB (0..1)
+ // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
+ // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
+ // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
+
+ // read_scanlines has increased the scanline counter, so we
+ // actually mean the previous one.
+ dest.setRGBA(x, info->output_scanline - 1, c * k / 255, m * k / 255, y * k / 255, 0xFF);
+ }
+}
+
+static void convertRGBToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info)
+{
+ ASSERT(info->out_color_space == JCS_RGB);
+
+ for (unsigned x = 0; x < info->output_width; ++x) {
+ unsigned r = *src++;
+ unsigned g = *src++;
+ unsigned b = *src++;
+ // read_scanlines has increased the scanline counter, so we
+ // actually mean the previous one.
+ dest.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF);
+ }
+}
+
bool JPEGImageDecoder::outputScanlines()
{
if (m_frameBufferCache.isEmpty())
return false;
- // Resize to the width and height of the image.
+ // Initialize the framebuffer if needed.
RGBA32Buffer& buffer = m_frameBufferCache[0];
if (buffer.status() == RGBA32Buffer::FrameEmpty) {
- // Let's resize our buffer now to the correct width/height.
- RGBA32Array& bytes = buffer.bytes();
- bytes.resize(size().width() * size().height());
-
- // Update our status to be partially complete.
+ if (!buffer.setSize(size().width(), size().height())) {
+ m_failed = true;
+ return false;
+ }
buffer.setStatus(RGBA32Buffer::FramePartial);
+ buffer.setHasAlpha(false);
// For JPEGs, the frame always fills the entire image.
- buffer.setRect(IntRect(0, 0, m_size.width(), m_size.height()));
-
- // We don't have alpha (this is the default when the buffer is constructed).
+ buffer.setRect(IntRect(IntPoint(), size()));
}
jpeg_decompress_struct* info = m_reader->info();
JSAMPARRAY samples = m_reader->samples();
- unsigned* dst = buffer.bytes().data() + info->output_scanline * m_size.width();
-
while (info->output_scanline < info->output_height) {
/* Request one scanline. Returns 0 or 1 scanlines. */
if (jpeg_read_scanlines(info, samples, 1) != 1)
return false;
- JSAMPLE *j1 = samples[0];
- for (unsigned x = 0; x < info->output_width; ++x) {
- unsigned r = *j1++;
- unsigned g = *j1++;
- unsigned b = *j1++;
- RGBA32Buffer::setRGBA(*dst++, r, g, b, 0xFF);
- }
- buffer.ensureHeight(info->output_scanline);
+ if (info->out_color_space == JCS_RGB)
+ convertRGBToRGBA(buffer, *samples, info);
+ else if (info->out_color_space == JCS_CMYK)
+ convertCMYKToRGBA(buffer, *samples, info);
+ else
+ return false;
}
return true;