Initial commit
This commit is contained in:
208
Torque/SDK/engine/dgl/bitmapJpeg.cc
Normal file
208
Torque/SDK/engine/dgl/bitmapJpeg.cc
Normal file
@@ -0,0 +1,208 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "core/stream.h"
|
||||
#include "core/fileStream.h"
|
||||
#include "core/memstream.h"
|
||||
#include "dgl/gPalette.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
|
||||
#include "jpeglib.h"
|
||||
|
||||
U32 gJpegQuality = 90;
|
||||
|
||||
|
||||
//-------------------------------------- Replacement I/O for standard LIBjpeg
|
||||
// functions. we don't wanna use
|
||||
// FILE*'s...
|
||||
static int jpegReadDataFn(void *client_data, unsigned char *data, int length)
|
||||
{
|
||||
Stream *stream = (Stream*)client_data;
|
||||
AssertFatal(stream != NULL, "jpegReadDataFn::No stream.");
|
||||
int pos = stream->getPosition();
|
||||
if (stream->read(length, data))
|
||||
return length;
|
||||
|
||||
if (stream->getStatus() == Stream::EOS)
|
||||
return (stream->getPosition()-pos);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
static int jpegWriteDataFn(void *client_data, unsigned char *data, int length)
|
||||
{
|
||||
Stream *stream = (Stream*)client_data;
|
||||
AssertFatal(stream != NULL, "jpegWriteDataFn::No stream.");
|
||||
if (stream->write(length, data))
|
||||
return length;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
static int jpegFlushDataFn(void *)
|
||||
{
|
||||
// do nothing since we can't flush the stream object
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
static int jpegErrorFn(void *client_data)
|
||||
{
|
||||
Stream *stream = (Stream*)client_data;
|
||||
AssertFatal(stream != NULL, "jpegErrorFn::No stream.");
|
||||
return (stream->getStatus() != Stream::Ok);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool GBitmap::readJPEG(Stream &stream)
|
||||
{
|
||||
JFREAD = jpegReadDataFn;
|
||||
JFERROR = jpegErrorFn;
|
||||
|
||||
jpeg_decompress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
// We set up the normal JPEG error routines, then override error_exit.
|
||||
//cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
//jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
// if (setjmp(jerr.setjmp_buffer))
|
||||
// {
|
||||
// // If we get here, the JPEG code has signaled an error.
|
||||
// // We need to clean up the JPEG object, close the input file, and return.
|
||||
// jpeg_destroy_decompress(&cinfo);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
|
||||
cinfo.client_data = (void*)&stream; // set the stream into the client_data
|
||||
|
||||
// Now we can initialize the JPEG decompression object.
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
jpeg_stdio_src(&cinfo);
|
||||
|
||||
// Read file header, set default decompression parameters
|
||||
jpeg_read_header(&cinfo, true);
|
||||
|
||||
BitmapFormat format;
|
||||
switch (cinfo.out_color_space)
|
||||
{
|
||||
case JCS_GRAYSCALE: format = Alpha; break;
|
||||
case JCS_RGB: format = RGB; break;
|
||||
default:
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start decompressor
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
// allocate the bitmap space and init internal variables...
|
||||
allocateBitmap(cinfo.output_width, cinfo.output_height, false, format);
|
||||
|
||||
// Set up the row pointers...
|
||||
U32 rowBytes = cinfo.output_width * cinfo.output_components;
|
||||
|
||||
U8* pBase = (U8*)getBits();
|
||||
for (U32 i = 0; i < height; i++)
|
||||
{
|
||||
JSAMPROW rowPointer = pBase + (i * rowBytes);
|
||||
jpeg_read_scanlines(&cinfo, &rowPointer, 1);
|
||||
}
|
||||
|
||||
// Finish decompression
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
// Release JPEG decompression object
|
||||
// This is an important step since it will release a good deal of memory.
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GBitmap::writeJPEG(Stream& stream) const
|
||||
{
|
||||
// JPEG format has no support for transparancy so any image
|
||||
// in Alpha format should be saved as a grayscale which coincides
|
||||
// with how the readJPEG function will read-in a JPEG. So the
|
||||
// only formats supported are RGB and Alpha, not RGBA.
|
||||
AssertFatal(getFormat() == RGB || getFormat() == Alpha,
|
||||
"GBitmap::writeJPEG: ONLY RGB bitmap writing supported at this time.");
|
||||
if (internalFormat != RGB && internalFormat != Alpha)
|
||||
return false;
|
||||
|
||||
// maximum image size allowed
|
||||
#define MAX_HEIGHT 4096
|
||||
if (height >= MAX_HEIGHT)
|
||||
return false;
|
||||
|
||||
// Bind our own stream writing, error, and memory flush functions
|
||||
// to the jpeg library interface
|
||||
JFWRITE = jpegWriteDataFn;
|
||||
JFFLUSH = jpegFlushDataFn;
|
||||
JFERROR = jpegErrorFn;
|
||||
|
||||
// Allocate and initialize our jpeg compression structure and error manager
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
|
||||
cinfo.client_data = (void*)&stream; // set the stream into the client_data
|
||||
jpeg_create_compress(&cinfo); // allocates a small amount of memory
|
||||
|
||||
// specify the destination for the compressed data(our stream)
|
||||
jpeg_stdio_dest(&cinfo);
|
||||
|
||||
// set the image properties
|
||||
cinfo.image_width = getWidth(); // image width
|
||||
cinfo.image_height = getHeight(); // image height
|
||||
cinfo.input_components = bytesPerPixel; // samples per pixel(RGB:3, Alpha:1)
|
||||
switch (internalFormat)
|
||||
{
|
||||
case Alpha: // no alpha support in JPEG format, so turn it into a grayscale
|
||||
cinfo.in_color_space = JCS_GRAYSCALE;
|
||||
break;
|
||||
case RGB: // otherwise we are writing in RGB format
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
break;
|
||||
}
|
||||
// use default compression params(75% compression)
|
||||
jpeg_set_defaults(&cinfo);
|
||||
jpeg_set_quality(&cinfo, gJpegQuality, false);
|
||||
|
||||
// begin JPEG compression cycle
|
||||
jpeg_start_compress(&cinfo, true);
|
||||
|
||||
// Set up the row pointers...
|
||||
U32 rowBytes = cinfo.image_width * cinfo.input_components;
|
||||
|
||||
U8* pBase = (U8*)getBits();
|
||||
for (U32 i = 0; i < height; i++)
|
||||
{
|
||||
// write the image data
|
||||
JSAMPROW rowPointer = pBase + (i * rowBytes);
|
||||
jpeg_write_scanlines(&cinfo, &rowPointer, 1);
|
||||
}
|
||||
|
||||
// complete the compression cycle
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
// release the JPEG compression object
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
// return success
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user