GRAPHICS: Make JPEGDecoder request RGB output from libjpeg by default.

This fixes loading of JPEG files which contain RGB color space instead of YUV.
It is a pretty odd extension of JPEG files by Adobe which is indicated by this:
http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe

To still support Groovie's need for YUV data I added some possibility to
request direct YUV output.
This commit is contained in:
Johannes Schickel 2013-08-12 00:53:34 +02:00
parent ac66cc9219
commit 4809294b43
3 changed files with 94 additions and 59 deletions

View file

@ -25,7 +25,6 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "graphics/pixelformat.h"
#include "graphics/yuv_to_rgb.h"
#include "graphics/decoders/jpeg.h"
#include "common/debug.h"
@ -45,7 +44,7 @@ extern "C" {
namespace Graphics {
JPEGDecoder::JPEGDecoder() : ImageDecoder(), _rgbSurface(nullptr) {
JPEGDecoder::JPEGDecoder() : ImageDecoder(), _surface(), _colorSpace(kColorSpaceRGBA) {
}
JPEGDecoder::~JPEGDecoder() {
@ -53,31 +52,11 @@ JPEGDecoder::~JPEGDecoder() {
}
const Surface *JPEGDecoder::getSurface() const {
// Make sure we have loaded data
if (!_yComponent.getPixels())
return 0;
if (_rgbSurface)
return _rgbSurface;
// Create an RGBA8888 surface
_rgbSurface = new Graphics::Surface();
_rgbSurface->create(_yComponent.w, _yComponent.h, Graphics::PixelFormat(4, 8, 8, 8, 0, 24, 16, 8, 0));
YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (const byte *)_yComponent.getPixels(), (const byte *)_uComponent.getPixels(), (const byte *)_vComponent.getPixels(), _yComponent.w, _yComponent.h, _yComponent.pitch, _uComponent.pitch);
return _rgbSurface;
return &_surface;
}
void JPEGDecoder::destroy() {
if (_rgbSurface) {
_rgbSurface->free();
delete _rgbSurface;
}
_yComponent.free();
_uComponent.free();
_vComponent.free();
_surface.free();
}
#ifdef USE_JPEG
@ -206,16 +185,33 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
// Read the file header
jpeg_read_header(&cinfo, TRUE);
// We request YUV output because Groovie requires it
cinfo.out_color_space = JCS_YCbCr;
// We can request YUV output because Groovie requires it
switch (_colorSpace) {
case kColorSpaceRGBA:
cinfo.out_color_space = JCS_RGB;
break;
case kColorSpaceYUV:
cinfo.out_color_space = JCS_YCbCr;
break;
}
// Actually start decompressing the image
jpeg_start_decompress(&cinfo);
// Allocate buffers for the YUV components
_yComponent.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat::createFormatCLUT8());
_uComponent.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat::createFormatCLUT8());
_vComponent.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat::createFormatCLUT8());
// 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));
break;
case kColorSpaceYUV:
// We use YUV with 3 bytes per pixel otherwise.
// This is pretty ugly since our PixelFormat cannot express YUV...
_surface.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat(3, 0, 0, 0, 0, 0, 0, 0, 0));
break;
}
// Allocate buffer for one scanline
JDIMENSION pitch = cinfo.output_width * cinfo.output_components;
@ -223,17 +219,35 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) {
// Go through the image data scanline by scanline
while (cinfo.output_scanline < cinfo.output_height) {
byte *yPtr = (byte *)_yComponent.getBasePtr(0, cinfo.output_scanline);
byte *uPtr = (byte *)_uComponent.getBasePtr(0, cinfo.output_scanline);
byte *vPtr = (byte *)_vComponent.getBasePtr(0, cinfo.output_scanline);
byte *dst = (byte *)_surface.getBasePtr(0, cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, buffer, 1);
const byte *src = buffer[0];
for (int remaining = cinfo.output_width; remaining > 0; --remaining) {
*yPtr++ = *src++;
*uPtr++ = *src++;
*vPtr++ = *src++;
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, _surface.pitch);
break;
}
}