aboutsummaryrefslogtreecommitdiff
path: root/image/jpeg.cpp
diff options
context:
space:
mode:
authorBastien Bouclet2019-01-22 15:02:05 +0100
committerBastien Bouclet2019-04-28 07:59:14 +0200
commit0d5d04ca3a5473f24f45112bb40a009679024acc (patch)
treedb509988aed8e0ef0f51052ca5154f771de8edb9 /image/jpeg.cpp
parent5196ae1cd49b879f0497c5ad863dfa6dfebe61c7 (diff)
downloadscummvm-rg350-0d5d04ca3a5473f24f45112bb40a009679024acc.tar.gz
scummvm-rg350-0d5d04ca3a5473f24f45112bb40a009679024acc.tar.bz2
scummvm-rg350-0d5d04ca3a5473f24f45112bb40a009679024acc.zip
IMAGE: Allow setting the output pixel format to the JPEG decoder
Diffstat (limited to 'image/jpeg.cpp')
-rw-r--r--image/jpeg.cpp114
1 files changed, 78 insertions, 36 deletions
diff --git a/image/jpeg.cpp b/image/jpeg.cpp
index 1ce45f2539..5cc348fdfe 100644
--- a/image/jpeg.cpp
+++ b/image/jpeg.cpp
@@ -30,6 +30,7 @@
#include "common/endian.h"
#include "common/stream.h"
#include "common/textconsole.h"
+#include "common/util.h"
#include "graphics/pixelformat.h"
#ifdef USE_JPEG
@@ -44,13 +45,24 @@ extern "C" {
namespace Image {
-JPEGDecoder::JPEGDecoder() : _surface(), _colorSpace(kColorSpaceRGBA) {
+JPEGDecoder::JPEGDecoder() :
+ _surface(),
+ _colorSpace(kColorSpaceRGB),
+ _requestedPixelFormat(getByteOrderRgbPixelFormat()) {
}
JPEGDecoder::~JPEGDecoder() {
destroy();
}
+Graphics::PixelFormat JPEGDecoder::getByteOrderRgbPixelFormat() const {
+#ifdef SCUMM_BIG_ENDIAN
+ return Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0);
+#else
+ return Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0);
+#endif
+}
+
const Graphics::Surface *JPEGDecoder::getSurface() const {
return &_surface;
}
@@ -171,6 +183,44 @@ void outputMessage(j_common_ptr cinfo) {
debug(3, "libjpeg: %s", buffer);
}
+J_COLOR_SPACE fromScummvmPixelFormat(const Graphics::PixelFormat &format) {
+ struct PixelFormatMapping {
+ Graphics::PixelFormat pixelFormat;
+ J_COLOR_SPACE bigEndianColorSpace;
+ J_COLOR_SPACE littleEndianColorSpace;
+ };
+
+ static const PixelFormatMapping mappings[] = {
+#ifdef JCS_EXTENSIONS
+ { Graphics::PixelFormat(4, 8, 8, 8, 0, 24, 16, 8, 0), JCS_EXT_RGBX, JCS_EXT_XBGR },
+ { Graphics::PixelFormat(4, 8, 8, 8, 0, 0, 8, 16, 24), JCS_EXT_XBGR, JCS_EXT_RGBX },
+ { Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24), JCS_EXT_XRGB, JCS_EXT_BGRX },
+ { Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0), JCS_EXT_BGRX, JCS_EXT_XRGB },
+ { Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), JCS_EXT_RGB, JCS_EXT_BGR },
+ { Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), JCS_EXT_BGR, JCS_EXT_RGB },
+#endif
+#ifdef JCS_ALPHA_EXTENSIONS
+ { Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), JCS_EXT_RGBA, JCS_EXT_ABGR },
+ { Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), JCS_EXT_ABGR, JCS_EXT_RGBA },
+ { Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), JCS_EXT_ARGB, JCS_EXT_BGRA },
+ { Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), JCS_EXT_BGRA, JCS_EXT_ARGB },
+#endif
+ { Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), JCS_RGB565, JCS_RGB565 }
+ };
+
+ for (uint i = 0; i < ARRAYSIZE(mappings); i++) {
+ if (mappings[i].pixelFormat == format) {
+#ifdef SCUMM_BIG_ENDIAN
+ return mappings[i].bigEndianColorSpace;
+#else
+ return mappings[i].littleEndianColorSpace;
+#endif
+ }
+ }
+
+ return JCS_UNKNOWN;
+}
+
} // End of anonymous namespace
#endif
@@ -198,10 +248,19 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
// We can request YUV output because Groovie requires it
switch (_colorSpace) {
- case kColorSpaceRGBA:
- cinfo.out_color_space = JCS_RGB;
- break;
+ case kColorSpaceRGB: {
+ J_COLOR_SPACE colorSpace = fromScummvmPixelFormat(_requestedPixelFormat);
+
+ if (colorSpace == JCS_UNKNOWN) {
+ // When libjpeg-turbo is not available or an unhandled pixel
+ // format was requested, ask libjpeg to decode to byte order RGB
+ // as it's always available.
+ colorSpace = JCS_RGB;
+ }
+ cinfo.out_color_space = colorSpace;
+ break;
+ }
case kColorSpaceYUV:
cinfo.out_color_space = JCS_YCbCr;
break;
@@ -212,11 +271,16 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
// Allocate buffers for the output data
switch (_colorSpace) {
- case kColorSpaceRGBA:
- // We use RGBA8888 in this scenario
- _surface.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat(4, 8, 8, 8, 0, 24, 16, 8, 0));
+ case kColorSpaceRGB: {
+ Graphics::PixelFormat outputPixelFormat;
+ if (cinfo.out_color_space == JCS_RGB) {
+ outputPixelFormat = getByteOrderRgbPixelFormat();
+ } else {
+ outputPixelFormat = _requestedPixelFormat;
+ }
+ _surface.create(cinfo.output_width, cinfo.output_height, outputPixelFormat);
break;
-
+ }
case kColorSpaceYUV:
// We use YUV with 3 bytes per pixel otherwise.
// This is pretty ugly since our PixelFormat cannot express YUV...
@@ -225,8 +289,7 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
}
// Allocate buffer for one scanline
- assert(cinfo.output_components == 3);
- JDIMENSION pitch = cinfo.output_width * cinfo.output_components;
+ JDIMENSION pitch = cinfo.output_width * _surface.format.bytesPerPixel;
assert(_surface.pitch >= pitch);
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, pitch, 1);
@@ -236,38 +299,17 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
jpeg_read_scanlines(&cinfo, buffer, 1);
- const byte *src = buffer[0];
- switch (_colorSpace) {
- case kColorSpaceRGBA: {
- for (int remaining = cinfo.output_width; remaining > 0; --remaining) {
- byte r = *src++;
- byte g = *src++;
- byte b = *src++;
- // We need to insert a alpha value of 255 (opaque) here.
-#ifdef SCUMM_BIG_ENDIAN
- *dst++ = r;
- *dst++ = g;
- *dst++ = b;
- *dst++ = 0xFF;
-#else
- *dst++ = 0xFF;
- *dst++ = b;
- *dst++ = g;
- *dst++ = r;
-#endif
- }
- } break;
-
- case kColorSpaceYUV:
- memcpy(dst, src, pitch);
- break;
- }
+ memcpy(dst, buffer[0], pitch);
}
// We are done with decompressing, thus free all the data
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
+ if (_colorSpace == kColorSpaceRGB && _surface.format != _requestedPixelFormat) {
+ _surface.convertToInPlace(_requestedPixelFormat); // Slow path
+ }
+
return true;
#else
return false;