blob: 8d5f5cec4768ed577e87607becd2a871353df848 [file] [log] [blame]
/*
* 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 __ixmaJPEG_h
#include "ximage.h"
#if CXIMAGE_SUPPORT_JPG
#define CXIMAGEJPG_SUPPORT_EXIF 1
extern "C" {
#include "../jpeg/jpeglib.h"
#include "../jpeg/jerror.h"
}
class DLL_EXP CxImageJPG: public CxImage
{
public:
CxImageJPG();
~CxImageJPG();
// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);}
// bool Save(const char * 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
#define MAX_COMMENT 1000
#define MAX_SECTIONS 20
typedef struct tag_ExifInfo {
char Version [5];
char CameraMake [32];
char CameraModel [40];
char DateTime [20];
int Height, Width;
int Orientation;
int IsColor;
int Process;
int FlashUsed;
float FocalLength;
float ExposureTime;
float ApertureFNumber;
float Distance;
float CCDWidth;
float ExposureBias;
int Whitebalance;
int MeteringMode;
int ExposureProgram;
int ISOequivalent;
int CompressionLevel;
float FocalplaneXRes;
float FocalplaneYRes;
float FocalplaneUnits;
float Xresolution;
float Yresolution;
float ResolutionUnit;
float Brightness;
char Comments[MAX_COMMENT];
unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */
unsigned ThumbnailSize; /* Size of thumbnail. */
bool IsExif;
} EXIFINFO;
//--------------------------------------------------------------------------
// 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{
BYTE* Data;
int Type;
unsigned Size;
} Section_t;
public:
EXIFINFO* m_exifinfo;
char m_szLastError[256];
CxExifInfo(EXIFINFO* info = NULL);
~CxExifInfo();
bool DecodeExif(CxFile * hFile, int nReadMode = EXIF_READ_EXIF);
bool EncodeExif(CxFile * hFile);
void DiscardAllButExif();
protected:
bool process_EXIF(unsigned char * CharBuf, unsigned int length);
void process_COM (const BYTE * Data, int length);
void process_SOFn (const BYTE * Data, int marker);
int Get16u(void * Short);
int Get16m(void * Short);
long Get32s(void * Long);
unsigned long Get32u(void * Long);
double ConvertAnyFormat(void * ValuePtr, int Format);
void* FindSection(int SectionType);
bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP);
int ExifImageWidth;
int MotorolaOrder;
Section_t Sections[MAX_SECTIONS];
int SectionsRead;
bool freeinfo;
};
CxExifInfo* m_exif;
EXIFINFO m_exifinfo;
bool DecodeExif(CxFile * hFile);
bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); }
#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 unsigned char[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 > (long)pSource->bytes_in_buffer){
num_bytes -= (long)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;
unsigned char *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
};
int m_nPredictor;
int m_nPointTransform;
int m_nSmoothing;
int m_nQuantize;
J_DITHER_MODE m_nDither;
};
#endif
#endif