284 lines
8.3 KiB
C++
284 lines
8.3 KiB
C++
/*
|
|
* 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
|