3 * Purpose: JPG Image Class Loader and Writer
5 /* ==========================================================
6 * CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
7 * For conditions of distribution and use, see copyright notice in ximage.h
9 * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
11 * Special thanks to Chris Shearer Cooper for CxFileJpg tips & code
13 * EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
15 * original CImageJPG and CImageIterator implementation are:
16 * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
18 * This software is based in part on the work of the Independent JPEG Group.
19 * Copyright (C) 1991-1998, Thomas G. Lane.
20 * ==========================================================
22 #if !defined(__ximaJPEG_h)
27 #if CXIMAGE_SUPPORT_JPG
29 #define CXIMAGEJPG_SUPPORT_EXIF 1
32 #include "../jpeg/jpeglib.h"
33 #include "../jpeg/jerror.h"
36 class DLL_EXP CxImageJPG: public CxImage
42 // bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);}
43 // bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);}
44 bool Decode(CxFile * hFile);
45 bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
47 #if CXIMAGE_SUPPORT_ENCODE
48 bool Encode(CxFile * hFile);
49 bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
50 #endif // CXIMAGE_SUPPORT_ENCODE
53 * EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
56 #if CXIMAGEJPG_SUPPORT_EXIF
58 #define MAX_COMMENT 1000
59 #define MAX_SECTIONS 20
61 typedef struct tag_ExifInfo {
64 char CameraModel [40];
73 float ApertureFNumber;
84 float FocalplaneUnits;
89 char Comments[MAX_COMMENT];
91 unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */
92 unsigned ThumbnailSize; /* Size of thumbnail. */
97 //--------------------------------------------------------------------------
98 // JPEG markers consist of one or more 0xFF bytes, followed by a marker
99 // code byte (which is not an FF). Here are the marker codes of interest
100 // in this program. (See jdmarker.c for a more complete list.)
101 //--------------------------------------------------------------------------
103 #define M_SOF0 0xC0 // Start Of Frame N
104 #define M_SOF1 0xC1 // N indicates which compression process
105 #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
107 #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
116 #define M_SOI 0xD8 // Start Of Image (beginning of datastream)
117 #define M_EOI 0xD9 // End Of Image (end of datastream)
118 #define M_SOS 0xDA // Start Of Scan (begins compressed data)
119 #define M_JFIF 0xE0 // Jfif marker
120 #define M_EXIF 0xE1 // Exif marker
121 #define M_COM 0xFE // COMment
123 #define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
125 #define EXIF_READ_EXIF 0x01
126 #define EXIF_READ_IMAGE 0x02
127 #define EXIF_READ_ALL 0x03
129 class DLL_EXP CxExifInfo
132 typedef struct tag_Section_t{
139 EXIFINFO* m_exifinfo;
140 char m_szLastError[256];
141 CxExifInfo(EXIFINFO* info = NULL);
143 bool DecodeExif(CxFile * hFile, int nReadMode = EXIF_READ_EXIF);
144 bool EncodeExif(CxFile * hFile);
145 void DiscardAllButExif();
147 bool process_EXIF(unsigned char * CharBuf, unsigned int length);
148 void process_COM (const BYTE * Data, int length);
149 void process_SOFn (const BYTE * Data, int marker);
150 int Get16u(void * Short);
151 int Get16m(void * Short);
152 long Get32s(void * Long);
153 unsigned long Get32u(void * Long);
154 double ConvertAnyFormat(void * ValuePtr, int Format);
155 void* FindSection(int SectionType);
156 bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
157 EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP, int NestingLevel=0);
160 Section_t Sections[MAX_SECTIONS];
167 bool DecodeExif(CxFile * hFile);
168 bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); }
170 #endif //CXIMAGEJPG_SUPPORT_EXIF
172 ////////////////////////////////////////////////////////////////////////////////////////
173 ////////////////////// C x F i l e J p g ////////////////////////////////
174 ////////////////////////////////////////////////////////////////////////////////////////
176 // thanks to Chris Shearer Cooper <cscooper(at)frii(dot)com>
177 class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr
180 enum { eBufSize = 4096 };
182 CxFileJpg(CxFile* pFile)
186 init_destination = InitDestination;
187 empty_output_buffer = EmptyOutputBuffer;
188 term_destination = TermDestination;
190 init_source = InitSource;
191 fill_input_buffer = FillInputBuffer;
192 skip_input_data = SkipInputData;
193 resync_to_restart = jpeg_resync_to_restart; // use default method
194 term_source = TermSource;
195 next_input_byte = NULL; //* => next byte to read from buffer
196 bytes_in_buffer = 0; //* # of bytes remaining in buffer
198 m_pBuffer = new unsigned char[eBufSize];
205 static void InitDestination(j_compress_ptr cinfo)
207 CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
208 pDest->next_output_byte = pDest->m_pBuffer;
209 pDest->free_in_buffer = eBufSize;
212 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
214 CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
215 if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize)
216 ERREXIT(cinfo, JERR_FILE_WRITE);
217 pDest->next_output_byte = pDest->m_pBuffer;
218 pDest->free_in_buffer = eBufSize;
222 static void TermDestination(j_compress_ptr cinfo)
224 CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
225 size_t datacount = eBufSize - pDest->free_in_buffer;
226 /* Write any data remaining in the buffer */
228 if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount))
229 ERREXIT(cinfo, JERR_FILE_WRITE);
231 pDest->m_pFile->Flush();
232 /* Make sure we wrote the output file OK */
233 if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE);
237 static void InitSource(j_decompress_ptr cinfo)
239 CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
240 pSource->m_bStartOfFile = TRUE;
243 static boolean FillInputBuffer(j_decompress_ptr cinfo)
246 CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
247 nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize);
249 if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error
250 ERREXIT(cinfo, JERR_INPUT_EMPTY);
251 WARNMS(cinfo, JWRN_JPEG_EOF);
252 // Insert a fake EOI marker
253 pSource->m_pBuffer[0] = (JOCTET) 0xFF;
254 pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI;
257 pSource->next_input_byte = pSource->m_pBuffer;
258 pSource->bytes_in_buffer = nbytes;
259 pSource->m_bStartOfFile = FALSE;
263 static void SkipInputData(j_decompress_ptr cinfo, long num_bytes)
265 CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
267 while (num_bytes > (long)pSource->bytes_in_buffer){
268 num_bytes -= (long)pSource->bytes_in_buffer;
269 FillInputBuffer(cinfo);
270 // note we assume that fill_input_buffer will never return FALSE,
271 // so suspension need not be handled.
273 pSource->next_input_byte += (size_t) num_bytes;
274 pSource->bytes_in_buffer -= (size_t) num_bytes;
278 static void TermSource(j_decompress_ptr /*cinfo*/)
284 unsigned char *m_pBuffer;
291 ENCODE_BASELINE = 0x1,
292 ENCODE_ARITHMETIC = 0x2,
293 ENCODE_GRAYSCALE = 0x4,
294 ENCODE_OPTIMIZE = 0x8,
295 ENCODE_PROGRESSIVE = 0x10,
296 ENCODE_LOSSLESS = 0x20,
297 ENCODE_SMOOTHING = 0x40,
298 DECODE_GRAYSCALE = 0x80,
299 DECODE_QUANTIZE = 0x100,
300 DECODE_DITHER = 0x200,
301 DECODE_ONEPASS = 0x400,
302 DECODE_NOSMOOTH = 0x800,
303 ENCODE_SUBSAMPLE_422 = 0x1000,
304 ENCODE_SUBSAMPLE_444 = 0x2000
308 int m_nPointTransform;
311 J_DITHER_MODE m_nDither;