/*
* File: ximajpg.h
* Purpose: JPG Image Class Loader and Writer
*/
/* ==========================================================
* CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
* For conditions of distribution and use, see copyright notice in ximage.h
*
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
*
* Special thanks to Chris Shearer Cooper for CxFileJpg tips & code
*
* EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*
* original CImageJPG and CImageIterator implementation are:
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
*
* This software is based in part on the work of the Independent JPEG Group.
* Copyright (C) 1991-1998, Thomas G. Lane.
* ==========================================================
*/
#if !defined(__ximaJPEG_h)
#define __ximaJPEG_h
#include "ximage.h"
#if CXIMAGE_SUPPORT_JPG
#define CXIMAGEJPG_SUPPORT_EXIF CXIMAGE_SUPPORT_EXIF
extern "C" {
#ifdef _LINUX
#include <jpeglib.h>
#include <jerror.h>
#else
#include "jpeg/jpeglib.h"
#include "jpeg/jerror.h"
#endif
}
class DLL_EXP CxImageJPG: public CxImage
{
public:
CxImageJPG();
~CxImageJPG();
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);}
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);}
bool Decode(CxFile * hFile);
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
#if CXIMAGE_SUPPORT_ENCODE
bool Encode(CxFile * hFile);
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
#endif // CXIMAGE_SUPPORT_ENCODE
/*
* EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*/
#if CXIMAGEJPG_SUPPORT_EXIF
//--------------------------------------------------------------------------
// JPEG markers consist of one or more 0xFF bytes, followed by a marker
// code byte (which is not an FF). Here are the marker codes of interest
// in this program. (See jdmarker.c for a more complete list.)
//--------------------------------------------------------------------------
#define M_SOF0 0xC0 // Start Of Frame N
#define M_SOF1 0xC1 // N indicates which compression process
#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
#define M_SOF3 0xC3
#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
#define M_SOF6 0xC6
#define M_SOF7 0xC7
#define M_SOF9 0xC9
#define M_SOF10 0xCA
#define M_SOF11 0xCB
#define M_SOF13 0xCD
#define M_SOF14 0xCE
#define M_SOF15 0xCF
#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
#define M_EOI 0xD9 // End Of Image (end of datastream)
#define M_SOS 0xDA // Start Of Scan (begins compressed data)
#define M_JFIF 0xE0 // Jfif marker
#define M_EXIF 0xE1 // Exif marker
#define M_COM 0xFE // COMment
#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
#define EXIF_READ_EXIF 0x01
#define EXIF_READ_IMAGE 0x02
#define EXIF_READ_ALL 0x03
class DLL_EXP CxExifInfo
{
typedef struct tag_Section_t{
uint8_t* Data;
int32_t Type;
unsigned Size;
} Section_t;
public:
EXIFINFO* m_exifinfo;
char m_szLastError[256];
CxExifInfo(EXIFINFO* info = NULL);
~CxExifInfo();
bool DecodeExif(CxFile * hFile, int32_t nReadMode = EXIF_READ_EXIF);
bool EncodeExif(CxFile * hFile);
void DiscardAllButExif();
protected:
bool process_EXIF(uint8_t * CharBuf, uint32_t length);
void process_COM (const uint8_t * Data, int32_t length);
void process_SOFn (const uint8_t * Data, int32_t marker);
int32_t Get16u(void * Short);
int32_t Get16m(void * Short);
int32_t Get32s(void * Long);
uint32_t Get32u(void * Long);
double ConvertAnyFormat(void * ValuePtr, int32_t Format);
void* FindSection(int32_t SectionType);
bool ProcessExifDir(uint8_t * DirStart, uint8_t * OffsetBase, unsigned ExifLength,
EXIFINFO * const pInfo, uint8_t ** const LastExifRefdP, int32_t NestingLevel=0);
int32_t ExifImageWidth;
int32_t MotorolaOrder;
Section_t Sections[MAX_SECTIONS];
int32_t SectionsRead;
bool freeinfo;
};
CxExifInfo* m_exif;
bool DecodeExif(CxFile * hFile);
bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); }
bool GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type);
#endif //CXIMAGEJPG_SUPPORT_EXIF
////////////////////////////////////////////////////////////////////////////////////////
////////////////////// C x F i l e J p g ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// thanks to Chris Shearer Cooper <cscooper(at)frii(dot)com>
class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr
{
public:
enum { eBufSize = 4096 };
CxFileJpg(CxFile* pFile)
{
m_pFile = pFile;
init_destination = InitDestination;
empty_output_buffer = EmptyOutputBuffer;
term_destination = TermDestination;
init_source = InitSource;
fill_input_buffer = FillInputBuffer;
skip_input_data = SkipInputData;
resync_to_restart = jpeg_resync_to_restart; // use default method
term_source = TermSource;
next_input_byte = NULL; //* => next byte to read from buffer
bytes_in_buffer = 0; //* # of bytes remaining in buffer
m_pBuffer = new uint8_t[eBufSize];
}
~CxFileJpg()
{
delete [] m_pBuffer;
}
static void InitDestination(j_compress_ptr cinfo)
{
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
pDest->next_output_byte = pDest->m_pBuffer;
pDest->free_in_buffer = eBufSize;
}
static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
{
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize)
ERREXIT(cinfo, JERR_FILE_WRITE);
pDest->next_output_byte = pDest->m_pBuffer;
pDest->free_in_buffer = eBufSize;
return TRUE;
}
static void TermDestination(j_compress_ptr cinfo)
{
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
size_t datacount = eBufSize - pDest->free_in_buffer;
/* Write any data remaining in the buffer */
if (datacount > 0) {
if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount))
ERREXIT(cinfo, JERR_FILE_WRITE);
}
pDest->m_pFile->Flush();
/* Make sure we wrote the output file OK */
if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE);
return;
}
static void InitSource(j_decompress_ptr cinfo)
{
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
pSource->m_bStartOfFile = TRUE;
}
static boolean FillInputBuffer(j_decompress_ptr cinfo)
{
size_t nbytes;
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize);
if (nbytes <= 0){
if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error
ERREXIT(cinfo, JERR_INPUT_EMPTY);
WARNMS(cinfo, JWRN_JPEG_EOF);
// Insert a fake EOI marker
pSource->m_pBuffer[0] = (JOCTET) 0xFF;
pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI;
nbytes = 2;
}
pSource->next_input_byte = pSource->m_pBuffer;
pSource->bytes_in_buffer = nbytes;
pSource->m_bStartOfFile = FALSE;
return TRUE;
}
static void SkipInputData(j_decompress_ptr cinfo, long num_bytes)
{
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
if (num_bytes > 0){
while (num_bytes > (int32_t)pSource->bytes_in_buffer){
num_bytes -= (int32_t)pSource->bytes_in_buffer;
FillInputBuffer(cinfo);
// note we assume that fill_input_buffer will never return FALSE,
// so suspension need not be handled.
}
pSource->next_input_byte += (size_t) num_bytes;
pSource->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void TermSource(j_decompress_ptr /*cinfo*/)
{
return;
}
protected:
CxFile *m_pFile;
uint8_t *m_pBuffer;
bool m_bStartOfFile;
};
public:
enum CODEC_OPTION
{
ENCODE_BASELINE = 0x1,
ENCODE_ARITHMETIC = 0x2,
ENCODE_GRAYSCALE = 0x4,
ENCODE_OPTIMIZE = 0x8,
ENCODE_PROGRESSIVE = 0x10,
ENCODE_LOSSLESS = 0x20,
ENCODE_SMOOTHING = 0x40,
DECODE_GRAYSCALE = 0x80,
DECODE_QUANTIZE = 0x100,
DECODE_DITHER = 0x200,
DECODE_ONEPASS = 0x400,
DECODE_NOSMOOTH = 0x800,
ENCODE_SUBSAMPLE_422 = 0x1000,
ENCODE_SUBSAMPLE_444 = 0x2000
};
int32_t m_nPredictor;
int32_t m_nPointTransform;
int32_t m_nSmoothing;
int32_t m_nQuantize;
J_DITHER_MODE m_nDither;
};
#endif
#endif