1 // ==========================================================
2 // fipImage class implementation
3 //
4 // Design and implementation by
5 // - Herv� Drolon (drolon@infonie.fr)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21 
22 #include "FreeImagePlus.h"
23 
24 ///////////////////////////////////////////////////////////////////
25 // Protected functions
26 
replace(FIBITMAP * new_dib)27 BOOL fipImage::replace(FIBITMAP *new_dib) {
28 	if (new_dib == NULL) {
29 		return FALSE;
30 	}
31 	if (_dib) {
32 		FreeImage_Unload(_dib);
33 	}
34 	_dib = new_dib;
35 	_bHasChanged = TRUE;
36 	return TRUE;
37 }
38 
39 ///////////////////////////////////////////////////////////////////
40 // Creation & Destruction
41 
fipImage(FREE_IMAGE_TYPE image_type,unsigned width,unsigned height,unsigned bpp)42 fipImage::fipImage(FREE_IMAGE_TYPE image_type, unsigned width, unsigned height, unsigned bpp) {
43 	_dib = NULL;
44 	_fif = FIF_UNKNOWN;
45 	_bHasChanged = FALSE;
46 	if(width && height && bpp) {
47 		setSize(image_type, width, height, bpp);
48 	}
49 }
50 
~fipImage()51 fipImage::~fipImage() {
52 	if(_dib) {
53 		FreeImage_Unload(_dib);
54 		_dib = NULL;
55 	}
56 }
57 
setSize(FREE_IMAGE_TYPE image_type,unsigned width,unsigned height,unsigned bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)58 BOOL fipImage::setSize(FREE_IMAGE_TYPE image_type, unsigned width, unsigned height, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
59 	if(_dib) {
60 		FreeImage_Unload(_dib);
61 	}
62 	if((_dib = FreeImage_AllocateT(image_type, width, height, bpp, red_mask, green_mask, blue_mask)) == NULL) {
63 		return FALSE;
64 	}
65 
66 	if(image_type == FIT_BITMAP) {
67 		// Create palette if needed
68 		switch(bpp)	{
69 			case 1:
70 			case 4:
71 			case 8:
72 				RGBQUAD *pal = FreeImage_GetPalette(_dib);
73 				for(unsigned i = 0; i < FreeImage_GetColorsUsed(_dib); i++) {
74 					pal[i].rgbRed = i;
75 					pal[i].rgbGreen = i;
76 					pal[i].rgbBlue = i;
77 				}
78 				break;
79 		}
80 	}
81 
82 	_bHasChanged = TRUE;
83 
84 	return TRUE;
85 }
86 
clear()87 void fipImage::clear() {
88 	if(_dib) {
89 		FreeImage_Unload(_dib);
90 		_dib = NULL;
91 	}
92 	_bHasChanged = TRUE;
93 }
94 
95 ///////////////////////////////////////////////////////////////////
96 // Copying
97 
fipImage(const fipImage & Image)98 fipImage::fipImage(const fipImage& Image) {
99 	_dib = NULL;
100 	FIBITMAP *clone = FreeImage_Clone((FIBITMAP*)Image._dib);
101 	replace(clone);
102 	_fif = Image._fif;
103 }
104 
operator =(const fipImage & Image)105 fipImage& fipImage::operator=(const fipImage& Image) {
106 	if(this != &Image) {
107 		FIBITMAP *clone = FreeImage_Clone((FIBITMAP*)Image._dib);
108 		replace(clone);
109 		_fif = Image._fif;
110 	}
111 	return *this;
112 }
113 
operator =(FIBITMAP * dib)114 fipImage& fipImage::operator=(FIBITMAP *dib) {
115 	if(_dib != dib) {
116 		replace(dib);
117 		_fif = FIF_UNKNOWN;
118 	}
119 	return *this;
120 }
121 
copySubImage(fipImage & dst,int left,int top,int right,int bottom) const122 BOOL fipImage::copySubImage(fipImage& dst, int left, int top, int right, int bottom) const {
123 	if(_dib) {
124 		dst = FreeImage_Copy(_dib, left, top, right, bottom);
125 		return dst.isValid();
126 	}
127 	return FALSE;
128 }
129 
pasteSubImage(fipImage & src,int left,int top,int alpha)130 BOOL fipImage::pasteSubImage(fipImage& src, int left, int top, int alpha) {
131 	if(_dib) {
132 		BOOL bResult = FreeImage_Paste(_dib, src._dib, left, top, alpha);
133 		_bHasChanged = TRUE;
134 		return bResult;
135 	}
136 	return FALSE;
137 }
138 
crop(int left,int top,int right,int bottom)139 BOOL fipImage::crop(int left, int top, int right, int bottom) {
140 	if(_dib) {
141 		FIBITMAP *dst = FreeImage_Copy(_dib, left, top, right, bottom);
142 		return replace(dst);
143 	}
144 	return FALSE;
145 }
146 
createView(fipImage & dynamicView,unsigned left,unsigned top,unsigned right,unsigned bottom)147 BOOL fipImage::createView(fipImage& dynamicView, unsigned left, unsigned top, unsigned right, unsigned bottom) {
148 	dynamicView = FreeImage_CreateView(_dib, left, top, right, bottom);
149 	return dynamicView.isValid();
150 }
151 
152 ///////////////////////////////////////////////////////////////////
153 // Information functions
154 
getImageType() const155 FREE_IMAGE_TYPE fipImage::getImageType() const {
156 	return FreeImage_GetImageType(_dib);
157 }
158 
getFIF() const159 FREE_IMAGE_FORMAT fipImage::getFIF() const {
160 	return _fif;
161 }
162 
getWidth() const163 unsigned fipImage::getWidth() const {
164 	return FreeImage_GetWidth(_dib);
165 }
166 
getHeight() const167 unsigned fipImage::getHeight() const {
168 	return FreeImage_GetHeight(_dib);
169 }
170 
getScanWidth() const171 unsigned fipImage::getScanWidth() const {
172 	return FreeImage_GetPitch(_dib);
173 }
174 
isValid() const175 BOOL fipImage::isValid() const {
176 	return (_dib != NULL) ? TRUE:FALSE;
177 }
178 
getInfo() const179 const BITMAPINFO* fipImage::getInfo() const {
180 	return FreeImage_GetInfo(_dib);
181 }
182 
getInfoHeader() const183 const BITMAPINFOHEADER* fipImage::getInfoHeader() const {
184 	return FreeImage_GetInfoHeader(_dib);
185 }
186 
getImageSize() const187 unsigned fipImage::getImageSize() const {
188 	return FreeImage_GetDIBSize(_dib);
189 }
190 
getImageMemorySize() const191 unsigned fipImage::getImageMemorySize() const {
192 	return FreeImage_GetMemorySize(_dib);
193 }
194 
getBitsPerPixel() const195 unsigned fipImage::getBitsPerPixel() const {
196 	return FreeImage_GetBPP(_dib);
197 }
198 
getLine() const199 unsigned fipImage::getLine() const {
200 	return FreeImage_GetLine(_dib);
201 }
202 
getHorizontalResolution() const203 double fipImage::getHorizontalResolution() const {
204 	return (FreeImage_GetDotsPerMeterX(_dib) / (double)100);
205 }
206 
getVerticalResolution() const207 double fipImage::getVerticalResolution() const {
208 	return (FreeImage_GetDotsPerMeterY(_dib) / (double)100);
209 }
210 
setHorizontalResolution(double value)211 void fipImage::setHorizontalResolution(double value) {
212 	FreeImage_SetDotsPerMeterX(_dib, (unsigned)(value * 100 + 0.5));
213 }
214 
setVerticalResolution(double value)215 void fipImage::setVerticalResolution(double value) {
216 	FreeImage_SetDotsPerMeterY(_dib, (unsigned)(value * 100 + 0.5));
217 }
218 
219 
220 ///////////////////////////////////////////////////////////////////
221 // Palette operations
222 
getPalette() const223 RGBQUAD* fipImage::getPalette() const {
224 	return FreeImage_GetPalette(_dib);
225 }
226 
getPaletteSize() const227 unsigned fipImage::getPaletteSize() const {
228 	return FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
229 }
230 
getColorsUsed() const231 unsigned fipImage::getColorsUsed() const {
232 	return FreeImage_GetColorsUsed(_dib);
233 }
234 
getColorType() const235 FREE_IMAGE_COLOR_TYPE fipImage::getColorType() const {
236 	return FreeImage_GetColorType(_dib);
237 }
238 
isGrayscale() const239 BOOL fipImage::isGrayscale() const {
240 	return ((FreeImage_GetBPP(_dib) == 8) && (FreeImage_GetColorType(_dib) != FIC_PALETTE));
241 }
242 
243 ///////////////////////////////////////////////////////////////////
244 // Thumbnail access
245 
getThumbnail(fipImage & image) const246 BOOL fipImage::getThumbnail(fipImage& image) const {
247 	image = FreeImage_Clone( FreeImage_GetThumbnail(_dib) );
248 	return image.isValid();
249 }
250 
setThumbnail(const fipImage & image)251 BOOL fipImage::setThumbnail(const fipImage& image) {
252 	return FreeImage_SetThumbnail(_dib, (FIBITMAP*)image._dib);
253 }
254 
hasThumbnail() const255 BOOL fipImage::hasThumbnail() const {
256 	return (FreeImage_GetThumbnail(_dib) != NULL);
257 }
258 
clearThumbnail()259 BOOL fipImage::clearThumbnail() {
260 	return FreeImage_SetThumbnail(_dib, NULL);
261 }
262 
263 
264 ///////////////////////////////////////////////////////////////////
265 // Pixel access
266 
accessPixels() const267 BYTE* fipImage::accessPixels() const {
268 	return FreeImage_GetBits(_dib);
269 }
270 
getScanLine(unsigned scanline) const271 BYTE* fipImage::getScanLine(unsigned scanline) const {
272 	if(scanline < FreeImage_GetHeight(_dib)) {
273 		return FreeImage_GetScanLine(_dib, scanline);
274 	}
275 	return NULL;
276 }
277 
getPixelIndex(unsigned x,unsigned y,BYTE * value) const278 BOOL fipImage::getPixelIndex(unsigned x, unsigned y, BYTE *value) const {
279 	return FreeImage_GetPixelIndex(_dib, x, y, value);
280 }
281 
getPixelColor(unsigned x,unsigned y,RGBQUAD * value) const282 BOOL fipImage::getPixelColor(unsigned x, unsigned y, RGBQUAD *value) const {
283 	return FreeImage_GetPixelColor(_dib, x, y, value);
284 }
285 
setPixelIndex(unsigned x,unsigned y,BYTE * value)286 BOOL fipImage::setPixelIndex(unsigned x, unsigned y, BYTE *value) {
287 	_bHasChanged = TRUE;
288 	return FreeImage_SetPixelIndex(_dib, x, y, value);
289 }
290 
setPixelColor(unsigned x,unsigned y,RGBQUAD * value)291 BOOL fipImage::setPixelColor(unsigned x, unsigned y, RGBQUAD *value) {
292 	_bHasChanged = TRUE;
293 	return FreeImage_SetPixelColor(_dib, x, y, value);
294 }
295 
296 ///////////////////////////////////////////////////////////////////
297 // File type identification
298 
identifyFIF(const char * lpszPathName)299 FREE_IMAGE_FORMAT fipImage::identifyFIF(const char* lpszPathName) {
300 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
301 
302 	// check the file signature and get its format
303 	// (the second argument is currently not used by FreeImage)
304 	fif = FreeImage_GetFileType(lpszPathName, 0);
305 	if(fif == FIF_UNKNOWN) {
306 		// no signature ?
307 		// try to guess the file format from the file extension
308 		fif = FreeImage_GetFIFFromFilename(lpszPathName);
309 	}
310 
311 	return fif;
312 }
313 
identifyFIFU(const wchar_t * lpszPathName)314 FREE_IMAGE_FORMAT fipImage::identifyFIFU(const wchar_t* lpszPathName) {
315 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
316 
317 	// check the file signature and get its format
318 	// (the second argument is currently not used by FreeImage)
319 	fif = FreeImage_GetFileTypeU(lpszPathName, 0);
320 	if(fif == FIF_UNKNOWN) {
321 		// no signature ?
322 		// try to guess the file format from the file extension
323 		fif = FreeImage_GetFIFFromFilenameU(lpszPathName);
324 	}
325 
326 	return fif;
327 }
328 
identifyFIFFromHandle(FreeImageIO * io,fi_handle handle)329 FREE_IMAGE_FORMAT fipImage::identifyFIFFromHandle(FreeImageIO *io, fi_handle handle) {
330 	if(io && handle) {
331 		// check the file signature and get its format
332 		return FreeImage_GetFileTypeFromHandle(io, handle);
333 	}
334 	return FIF_UNKNOWN;
335 }
336 
identifyFIFFromMemory(FIMEMORY * hmem)337 FREE_IMAGE_FORMAT fipImage::identifyFIFFromMemory(FIMEMORY *hmem) {
338 	if(hmem != NULL) {
339 		return FreeImage_GetFileTypeFromMemory(hmem, 0);
340 	}
341 	return FIF_UNKNOWN;
342 }
343 
344 
345 ///////////////////////////////////////////////////////////////////
346 // Loading & Saving
347 
load(FREE_IMAGE_FORMAT fif,const char * lpszPathName,int flag)348 BOOL fipImage::load(FREE_IMAGE_FORMAT fif, const char* lpszPathName, int flag) {
349 	// free the previous dib
350 	if (_dib) {
351 		FreeImage_Unload(_dib);
352 	}
353 	// load the file
354 	_dib = FreeImage_Load(fif, lpszPathName, flag);
355 	_fif = fif;
356 	_bHasChanged = TRUE;
357 
358 	return (_dib == NULL) ? FALSE : TRUE;
359 }
360 
load(const char * lpszPathName,int flag)361 BOOL fipImage::load(const char* lpszPathName, int flag) {
362 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
363 
364 	// check the file signature and get its format
365 	// (the second argument is currently not used by FreeImage)
366 	fif = FreeImage_GetFileType(lpszPathName, 0);
367 	if(fif == FIF_UNKNOWN) {
368 		// no signature ?
369 		// try to guess the file format from the file extension
370 		fif = FreeImage_GetFIFFromFilename(lpszPathName);
371 	}
372 	// check that the plugin has reading capabilities ...
373 	if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
374 		return load(fif, lpszPathName, flag);
375 	}
376 
377 	return FALSE;
378 }
379 
loadU(FREE_IMAGE_FORMAT fif,const wchar_t * lpszPathName,int flag)380 BOOL fipImage::loadU(FREE_IMAGE_FORMAT fif, const wchar_t* lpszPathName, int flag) {
381 	// free the previous dib
382 	if (_dib) {
383 		FreeImage_Unload(_dib);
384 	}
385 	// load the file
386 	_dib = FreeImage_LoadU(fif, lpszPathName, flag);
387 	_fif = fif;
388 	_bHasChanged = TRUE;
389 
390 	return (_dib == NULL) ? FALSE : TRUE;
391 }
392 
loadU(const wchar_t * lpszPathName,int flag)393 BOOL fipImage::loadU(const wchar_t* lpszPathName, int flag) {
394 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
395 
396 	// check the file signature and get its format
397 	// (the second argument is currently not used by FreeImage)
398 	fif = FreeImage_GetFileTypeU(lpszPathName, 0);
399 	if(fif == FIF_UNKNOWN) {
400 		// no signature ?
401 		// try to guess the file format from the file extension
402 		fif = FreeImage_GetFIFFromFilenameU(lpszPathName);
403 	}
404 	// check that the plugin has reading capabilities ...
405 	if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
406 		return loadU(fif, lpszPathName, flag);
407 	}
408 
409 	return FALSE;
410 }
411 
loadFromHandle(FreeImageIO * io,fi_handle handle,int flag)412 BOOL fipImage::loadFromHandle(FreeImageIO *io, fi_handle handle, int flag) {
413 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
414 
415 	// check the file signature and get its format
416 	fif = FreeImage_GetFileTypeFromHandle(io, handle);
417 	if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
418 		// Free the previous dib
419 		if(_dib) {
420 			FreeImage_Unload(_dib);
421 		}
422 		// Load the file
423 		_dib = FreeImage_LoadFromHandle(fif, io, handle, flag);
424 		_fif = fif;
425 		_bHasChanged = TRUE;
426 
427 		return (_dib == NULL) ? FALSE : TRUE;
428 	}
429 	return FALSE;
430 }
431 
loadFromMemory(fipMemoryIO & memIO,int flag)432 BOOL fipImage::loadFromMemory(fipMemoryIO& memIO, int flag) {
433 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
434 
435 	// check the file signature and get its format
436 	fif = memIO.getFileType();
437 	if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
438 		// Free the previous dib
439 		if(_dib) {
440 			FreeImage_Unload(_dib);
441 		}
442 		// Load the file
443 		_dib = memIO.load(fif, flag);
444 		_fif = fif;
445 		_bHasChanged = TRUE;
446 
447 		return (_dib == NULL) ? FALSE : TRUE;
448 	}
449 	return FALSE;
450 }
451 
loadFromMemory(FREE_IMAGE_FORMAT fif,fipMemoryIO & memIO,int flag)452 BOOL fipImage::loadFromMemory(FREE_IMAGE_FORMAT fif, fipMemoryIO& memIO, int flag) {
453 	if (fif != FIF_UNKNOWN) {
454 		// Free the previous dib
455 		if (_dib) {
456 			FreeImage_Unload(_dib);
457 		}
458 		// Load the file
459 		_dib = memIO.load(fif, flag);
460 		_fif = fif;
461 		_bHasChanged = TRUE;
462 
463 		return (_dib == NULL) ? FALSE : TRUE;
464 	}
465 	return FALSE;
466 }
467 
save(FREE_IMAGE_FORMAT fif,const char * lpszPathName,int flag)468 BOOL  fipImage::save(FREE_IMAGE_FORMAT fif, const char* lpszPathName, int flag) {
469 	BOOL bSuccess = FreeImage_Save(fif, _dib, lpszPathName, flag);
470 	_fif = fif;
471 	return bSuccess;
472 }
473 
save(const char * lpszPathName,int flag)474 BOOL fipImage::save(const char* lpszPathName, int flag) {
475 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
476 	BOOL bSuccess = FALSE;
477 
478 	// Try to guess the file format from the file extension
479 	fif = FreeImage_GetFIFFromFilename(lpszPathName);
480 	if(fif != FIF_UNKNOWN ) {
481 		// Check that the dib can be saved in this format
482 		BOOL bCanSave;
483 
484 		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
485 		if(image_type == FIT_BITMAP) {
486 			// standard bitmap type
487 			WORD bpp = FreeImage_GetBPP(_dib);
488 			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
489 		} else {
490 			// special bitmap type
491 			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
492 		}
493 
494 		if(bCanSave) {
495 			bSuccess = FreeImage_Save(fif, _dib, lpszPathName, flag);
496 			_fif = fif;
497 			return bSuccess;
498 		}
499 	}
500 	return bSuccess;
501 }
502 
saveU(FREE_IMAGE_FORMAT fif,const wchar_t * lpszPathName,int flag)503 BOOL  fipImage::saveU(FREE_IMAGE_FORMAT fif, const wchar_t* lpszPathName, int flag) {
504 	BOOL bSuccess = FreeImage_SaveU(fif, _dib, lpszPathName, flag);
505 	_fif = fif;
506 	return bSuccess;
507 }
508 
saveU(const wchar_t * lpszPathName,int flag)509 BOOL fipImage::saveU(const wchar_t* lpszPathName, int flag) {
510 	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
511 	BOOL bSuccess = FALSE;
512 
513 	// Try to guess the file format from the file extension
514 	fif = FreeImage_GetFIFFromFilenameU(lpszPathName);
515 	if(fif != FIF_UNKNOWN ) {
516 		// Check that the dib can be saved in this format
517 		BOOL bCanSave;
518 
519 		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
520 		if(image_type == FIT_BITMAP) {
521 			// standard bitmap type
522 			WORD bpp = FreeImage_GetBPP(_dib);
523 			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
524 		} else {
525 			// special bitmap type
526 			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
527 		}
528 
529 		if(bCanSave) {
530 			bSuccess = FreeImage_SaveU(fif, _dib, lpszPathName, flag);
531 			_fif = fif;
532 			return bSuccess;
533 		}
534 	}
535 	return bSuccess;
536 }
537 
saveToHandle(FREE_IMAGE_FORMAT fif,FreeImageIO * io,fi_handle handle,int flag)538 BOOL fipImage::saveToHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flag) {
539 	BOOL bSuccess = FALSE;
540 
541 	if(fif != FIF_UNKNOWN ) {
542 		// Check that the dib can be saved in this format
543 		BOOL bCanSave;
544 
545 		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
546 		if(image_type == FIT_BITMAP) {
547 			// standard bitmap type
548 			WORD bpp = FreeImage_GetBPP(_dib);
549 			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
550 		} else {
551 			// special bitmap type
552 			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
553 		}
554 
555 		if(bCanSave) {
556 			bSuccess = FreeImage_SaveToHandle(fif, _dib, io, handle, flag);
557 			_fif = fif;
558 			return bSuccess;
559 		}
560 	}
561 	return bSuccess;
562 }
563 
saveToMemory(FREE_IMAGE_FORMAT fif,fipMemoryIO & memIO,int flag)564 BOOL fipImage::saveToMemory(FREE_IMAGE_FORMAT fif, fipMemoryIO& memIO, int flag) {
565 	BOOL bSuccess = FALSE;
566 
567 	if(fif != FIF_UNKNOWN ) {
568 		// Check that the dib can be saved in this format
569 		BOOL bCanSave;
570 
571 		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
572 		if(image_type == FIT_BITMAP) {
573 			// standard bitmap type
574 			WORD bpp = FreeImage_GetBPP(_dib);
575 			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
576 		} else {
577 			// special bitmap type
578 			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
579 		}
580 
581 		if(bCanSave) {
582 			bSuccess = memIO.save(fif, _dib, flag);
583 			_fif = fif;
584 			return bSuccess;
585 		}
586 	}
587 	return bSuccess;
588 }
589 
590 ///////////////////////////////////////////////////////////////////
591 // Conversion routines
592 
convertToType(FREE_IMAGE_TYPE image_type,BOOL scale_linear)593 BOOL fipImage::convertToType(FREE_IMAGE_TYPE image_type, BOOL scale_linear) {
594 	if(_dib) {
595 		FIBITMAP *dib = FreeImage_ConvertToType(_dib, image_type, scale_linear);
596 		return replace(dib);
597 	}
598 	return FALSE;
599 }
600 
threshold(BYTE T)601 BOOL fipImage::threshold(BYTE T) {
602 	if(_dib) {
603 		FIBITMAP *dib1 = FreeImage_Threshold(_dib, T);
604 		return replace(dib1);
605 	}
606 	return FALSE;
607 }
608 
convertTo4Bits()609 BOOL fipImage::convertTo4Bits() {
610 	if(_dib) {
611 		FIBITMAP *dib4 = FreeImage_ConvertTo4Bits(_dib);
612 		return replace(dib4);
613 	}
614 	return FALSE;
615 }
616 
convertTo8Bits()617 BOOL fipImage::convertTo8Bits() {
618 	if(_dib) {
619 		FIBITMAP *dib8 = FreeImage_ConvertTo8Bits(_dib);
620 		return replace(dib8);
621 	}
622 	return FALSE;
623 }
624 
convertTo16Bits555()625 BOOL fipImage::convertTo16Bits555() {
626 	if(_dib) {
627 		FIBITMAP *dib16_555 = FreeImage_ConvertTo16Bits555(_dib);
628 		return replace(dib16_555);
629 	}
630 	return FALSE;
631 }
632 
convertTo16Bits565()633 BOOL fipImage::convertTo16Bits565() {
634 	if(_dib) {
635 		FIBITMAP *dib16_565 = FreeImage_ConvertTo16Bits565(_dib);
636 		return replace(dib16_565);
637 	}
638 	return FALSE;
639 }
640 
convertTo24Bits()641 BOOL fipImage::convertTo24Bits() {
642 	if(_dib) {
643 		FIBITMAP *dibRGB = FreeImage_ConvertTo24Bits(_dib);
644 		return replace(dibRGB);
645 	}
646 	return FALSE;
647 }
648 
convertTo32Bits()649 BOOL fipImage::convertTo32Bits() {
650 	if(_dib) {
651 		FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(_dib);
652 		return replace(dib32);
653 	}
654 	return FALSE;
655 }
656 
convertToGrayscale()657 BOOL fipImage::convertToGrayscale() {
658 	if(_dib) {
659 		FIBITMAP *dib8 = FreeImage_ConvertToGreyscale(_dib);
660 		return replace(dib8);
661 	}
662 	return FALSE;
663 }
664 
colorQuantize(FREE_IMAGE_QUANTIZE algorithm)665 BOOL fipImage::colorQuantize(FREE_IMAGE_QUANTIZE algorithm) {
666 	if(_dib) {
667 		FIBITMAP *dib8 = FreeImage_ColorQuantize(_dib, algorithm);
668 		return replace(dib8);
669 	}
670 	return FALSE;
671 }
672 
dither(FREE_IMAGE_DITHER algorithm)673 BOOL fipImage::dither(FREE_IMAGE_DITHER algorithm) {
674 	if(_dib) {
675 		FIBITMAP *dib = FreeImage_Dither(_dib, algorithm);
676 		return replace(dib);
677 	}
678 	return FALSE;
679 }
680 
convertToFloat()681 BOOL fipImage::convertToFloat() {
682 	if(_dib) {
683 		FIBITMAP *dib = FreeImage_ConvertToFloat(_dib);
684 		return replace(dib);
685 	}
686 	return FALSE;
687 }
688 
convertToRGBF()689 BOOL fipImage::convertToRGBF() {
690 	if(_dib) {
691 		FIBITMAP *dib = FreeImage_ConvertToRGBF(_dib);
692 		return replace(dib);
693 	}
694 	return FALSE;
695 }
696 
convertToRGBAF()697 BOOL fipImage::convertToRGBAF() {
698 	if(_dib) {
699 		FIBITMAP *dib = FreeImage_ConvertToRGBAF(_dib);
700 		return replace(dib);
701 	}
702 	return FALSE;
703 }
704 
convertToUINT16()705 BOOL fipImage::convertToUINT16() {
706 	if(_dib) {
707 		FIBITMAP *dib = FreeImage_ConvertToUINT16(_dib);
708 		return replace(dib);
709 	}
710 	return FALSE;
711 }
712 
convertToRGB16()713 BOOL fipImage::convertToRGB16() {
714 	if(_dib) {
715 		FIBITMAP *dib = FreeImage_ConvertToRGB16(_dib);
716 		return replace(dib);
717 	}
718 	return FALSE;
719 }
720 
convertToRGBA16()721 BOOL fipImage::convertToRGBA16() {
722 	if(_dib) {
723 		FIBITMAP *dib = FreeImage_ConvertToRGBA16(_dib);
724 		return replace(dib);
725 	}
726 	return FALSE;
727 }
728 
toneMapping(FREE_IMAGE_TMO tmo,double first_param,double second_param,double third_param,double fourth_param)729 BOOL fipImage::toneMapping(FREE_IMAGE_TMO tmo, double first_param, double second_param, double third_param, double fourth_param) {
730 	if(_dib) {
731 		FIBITMAP *dst = NULL;
732 		// Apply a tone mapping algorithm and convert to 24-bit
733 		switch(tmo) {
734 			case FITMO_REINHARD05:
735 				dst = FreeImage_TmoReinhard05Ex(_dib, first_param, second_param, third_param, fourth_param);
736 				break;
737 			default:
738 				dst = FreeImage_ToneMapping(_dib, tmo, first_param, second_param);
739 				break;
740 		}
741 
742 		return replace(dst);
743 	}
744 	return FALSE;
745 }
746 
747 ///////////////////////////////////////////////////////////////////
748 // Transparency support: background colour and alpha channel
749 
isTransparent() const750 BOOL fipImage::isTransparent() const {
751 	return FreeImage_IsTransparent(_dib);
752 }
753 
getTransparencyCount() const754 unsigned fipImage::getTransparencyCount() const {
755 	return FreeImage_GetTransparencyCount(_dib);
756 }
757 
getTransparencyTable() const758 BYTE* fipImage::getTransparencyTable() const {
759 	return FreeImage_GetTransparencyTable(_dib);
760 }
761 
setTransparencyTable(BYTE * table,int count)762 void fipImage::setTransparencyTable(BYTE *table, int count) {
763 	FreeImage_SetTransparencyTable(_dib, table, count);
764 	_bHasChanged = TRUE;
765 }
766 
hasFileBkColor() const767 BOOL fipImage::hasFileBkColor() const {
768 	return FreeImage_HasBackgroundColor(_dib);
769 }
770 
getFileBkColor(RGBQUAD * bkcolor) const771 BOOL fipImage::getFileBkColor(RGBQUAD *bkcolor) const {
772 	return FreeImage_GetBackgroundColor(_dib, bkcolor);
773 }
774 
setFileBkColor(RGBQUAD * bkcolor)775 BOOL fipImage::setFileBkColor(RGBQUAD *bkcolor) {
776 	_bHasChanged = TRUE;
777 	return FreeImage_SetBackgroundColor(_dib, bkcolor);
778 }
779 
780 ///////////////////////////////////////////////////////////////////
781 // Channel processing support
782 
getChannel(fipImage & image,FREE_IMAGE_COLOR_CHANNEL channel) const783 BOOL fipImage::getChannel(fipImage& image, FREE_IMAGE_COLOR_CHANNEL channel) const {
784 	if(_dib) {
785 		image = FreeImage_GetChannel(_dib, channel);
786 		return image.isValid();
787 	}
788 	return FALSE;
789 }
790 
setChannel(fipImage & image,FREE_IMAGE_COLOR_CHANNEL channel)791 BOOL fipImage::setChannel(fipImage& image, FREE_IMAGE_COLOR_CHANNEL channel) {
792 	if(_dib) {
793 		_bHasChanged = TRUE;
794 		return FreeImage_SetChannel(_dib, image._dib, channel);
795 	}
796 	return FALSE;
797 }
798 
splitChannels(fipImage & RedChannel,fipImage & GreenChannel,fipImage & BlueChannel)799 BOOL fipImage::splitChannels(fipImage& RedChannel, fipImage& GreenChannel, fipImage& BlueChannel) {
800 	if(_dib) {
801 		RedChannel = FreeImage_GetChannel(_dib, FICC_RED);
802 		GreenChannel = FreeImage_GetChannel(_dib, FICC_GREEN);
803 		BlueChannel = FreeImage_GetChannel(_dib, FICC_BLUE);
804 
805 		return (RedChannel.isValid() && GreenChannel.isValid() && BlueChannel.isValid());
806 	}
807 	return FALSE;
808 }
809 
combineChannels(fipImage & red,fipImage & green,fipImage & blue)810 BOOL fipImage::combineChannels(fipImage& red, fipImage& green, fipImage& blue) {
811 	if(!_dib) {
812 		int width = red.getWidth();
813 		int height = red.getHeight();
814 		_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
815 	}
816 
817 	if(_dib) {
818 		BOOL bResult = TRUE;
819 		bResult &= FreeImage_SetChannel(_dib, red._dib, FICC_RED);
820 		bResult &= FreeImage_SetChannel(_dib, green._dib, FICC_GREEN);
821 		bResult &= FreeImage_SetChannel(_dib, blue._dib, FICC_BLUE);
822 
823 		_bHasChanged = TRUE;
824 
825 		return bResult;
826 	}
827 	return FALSE;
828 }
829 
830 ///////////////////////////////////////////////////////////////////
831 // Rotation and flipping
832 
rotateEx(double angle,double x_shift,double y_shift,double x_origin,double y_origin,BOOL use_mask)833 BOOL fipImage::rotateEx(double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask) {
834 	if(_dib) {
835 		if(FreeImage_GetBPP(_dib) >= 8) {
836 			FIBITMAP *rotated = FreeImage_RotateEx(_dib, angle, x_shift, y_shift, x_origin, y_origin, use_mask);
837 			return replace(rotated);
838 		}
839 	}
840 	return FALSE;
841 }
842 
rotate(double angle,const void * bkcolor)843 BOOL fipImage::rotate(double angle, const void *bkcolor) {
844 	if(_dib) {
845 		switch(FreeImage_GetImageType(_dib)) {
846 			case FIT_BITMAP:
847 				switch(FreeImage_GetBPP(_dib)) {
848 					case 1:
849 					case 8:
850 					case 24:
851 					case 32:
852 						break;
853 					default:
854 						return FALSE;
855 				}
856 				break;
857 
858 			case FIT_UINT16:
859 			case FIT_RGB16:
860 			case FIT_RGBA16:
861 			case FIT_FLOAT:
862 			case FIT_RGBF:
863 			case FIT_RGBAF:
864 				break;
865 			default:
866 				return FALSE;
867 				break;
868 		}
869 
870 		FIBITMAP *rotated = FreeImage_Rotate(_dib, angle, bkcolor);
871 		return replace(rotated);
872 
873 	}
874 	return FALSE;
875 }
876 
flipVertical()877 BOOL fipImage::flipVertical() {
878 	if(_dib) {
879 		_bHasChanged = TRUE;
880 
881 		return FreeImage_FlipVertical(_dib);
882 	}
883 	return FALSE;
884 }
885 
flipHorizontal()886 BOOL fipImage::flipHorizontal() {
887 	if(_dib) {
888 		_bHasChanged = TRUE;
889 
890 		return FreeImage_FlipHorizontal(_dib);
891 	}
892 	return FALSE;
893 }
894 
895 ///////////////////////////////////////////////////////////////////
896 // Color manipulation routines
897 
invert()898 BOOL fipImage::invert() {
899 	if(_dib) {
900 		_bHasChanged = TRUE;
901 
902 		return FreeImage_Invert(_dib);
903 	}
904 	return FALSE;
905 }
906 
adjustCurve(BYTE * LUT,FREE_IMAGE_COLOR_CHANNEL channel)907 BOOL fipImage::adjustCurve(BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel) {
908 	if(_dib) {
909 		_bHasChanged = TRUE;
910 
911 		return FreeImage_AdjustCurve(_dib, LUT, channel);
912 	}
913 	return FALSE;
914 }
915 
adjustGamma(double gamma)916 BOOL fipImage::adjustGamma(double gamma) {
917 	if(_dib) {
918 		_bHasChanged = TRUE;
919 
920 		return FreeImage_AdjustGamma(_dib, gamma);
921 	}
922 	return FALSE;
923 }
924 
adjustBrightness(double percentage)925 BOOL fipImage::adjustBrightness(double percentage) {
926 	if(_dib) {
927 		_bHasChanged = TRUE;
928 
929 		return FreeImage_AdjustBrightness(_dib, percentage);
930 	}
931 	return FALSE;
932 }
933 
adjustContrast(double percentage)934 BOOL fipImage::adjustContrast(double percentage) {
935 	if(_dib) {
936 		_bHasChanged = TRUE;
937 
938 		return FreeImage_AdjustContrast(_dib, percentage);
939 	}
940 	return FALSE;
941 }
942 
adjustBrightnessContrastGamma(double brightness,double contrast,double gamma)943 BOOL fipImage::adjustBrightnessContrastGamma(double brightness, double contrast, double gamma) {
944 	if(_dib) {
945 		_bHasChanged = TRUE;
946 
947 		return FreeImage_AdjustColors(_dib, brightness, contrast, gamma, FALSE);
948 	}
949 	return FALSE;
950 }
951 
getHistogram(DWORD * histo,FREE_IMAGE_COLOR_CHANNEL channel) const952 BOOL fipImage::getHistogram(DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel) const {
953 	if(_dib) {
954 		return FreeImage_GetHistogram(_dib, histo, channel);
955 	}
956 	return FALSE;
957 }
958 
959 ///////////////////////////////////////////////////////////////////
960 // Upsampling / downsampling routine
961 
rescale(unsigned new_width,unsigned new_height,FREE_IMAGE_FILTER filter)962 BOOL fipImage::rescale(unsigned new_width, unsigned new_height, FREE_IMAGE_FILTER filter) {
963 	if(_dib) {
964 		switch(FreeImage_GetImageType(_dib)) {
965 			case FIT_BITMAP:
966 			case FIT_UINT16:
967 			case FIT_RGB16:
968 			case FIT_RGBA16:
969 			case FIT_FLOAT:
970 			case FIT_RGBF:
971 			case FIT_RGBAF:
972 				break;
973 			default:
974 				return FALSE;
975 				break;
976 		}
977 
978 		// Perform upsampling / downsampling
979 		FIBITMAP *dst = FreeImage_Rescale(_dib, new_width, new_height, filter);
980 		return replace(dst);
981 	}
982 	return FALSE;
983 }
984 
makeThumbnail(unsigned max_size,BOOL convert)985 BOOL fipImage::makeThumbnail(unsigned max_size, BOOL convert) {
986 	if(_dib) {
987 		switch(FreeImage_GetImageType(_dib)) {
988 			case FIT_BITMAP:
989 			case FIT_UINT16:
990 			case FIT_RGB16:
991 			case FIT_RGBA16:
992 			case FIT_FLOAT:
993 			case FIT_RGBF:
994 			case FIT_RGBAF:
995 				break;
996 			default:
997 				return FALSE;
998 				break;
999 		}
1000 
1001 		// Perform downsampling
1002 		FIBITMAP *dst = FreeImage_MakeThumbnail(_dib, max_size, convert);
1003 		return replace(dst);
1004 	}
1005 	return FALSE;
1006 }
1007 
1008 ///////////////////////////////////////////////////////////////////
1009 // Metadata
1010 
getMetadataCount(FREE_IMAGE_MDMODEL model) const1011 unsigned fipImage::getMetadataCount(FREE_IMAGE_MDMODEL model) const {
1012 	return FreeImage_GetMetadataCount(model, _dib);
1013 }
1014 
getMetadata(FREE_IMAGE_MDMODEL model,const char * key,fipTag & tag) const1015 BOOL fipImage::getMetadata(FREE_IMAGE_MDMODEL model, const char *key, fipTag& tag) const {
1016 	FITAG *searchedTag = NULL;
1017 	FreeImage_GetMetadata(model, _dib, key, &searchedTag);
1018 	if(searchedTag != NULL) {
1019 		tag = FreeImage_CloneTag(searchedTag);
1020 		return TRUE;
1021 	} else {
1022 		// clear the tag
1023 		tag = (FITAG*)NULL;
1024 	}
1025 	return FALSE;
1026 }
1027 
setMetadata(FREE_IMAGE_MDMODEL model,const char * key,fipTag & tag)1028 BOOL fipImage::setMetadata(FREE_IMAGE_MDMODEL model, const char *key, fipTag& tag) {
1029 	return FreeImage_SetMetadata(model, _dib, key, tag);
1030 }
1031 
clearMetadata()1032 void fipImage::clearMetadata() {
1033 	// clear all metadata attached to the dib
1034 	FreeImage_SetMetadata(FIMD_COMMENTS, _dib, NULL, NULL);			// single comment or keywords
1035 	FreeImage_SetMetadata(FIMD_EXIF_MAIN, _dib, NULL, NULL);		// Exif-TIFF metadata
1036 	FreeImage_SetMetadata(FIMD_EXIF_EXIF, _dib, NULL, NULL);		// Exif-specific metadata
1037 	FreeImage_SetMetadata(FIMD_EXIF_GPS, _dib, NULL, NULL);			// Exif GPS metadata
1038 	FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, _dib, NULL, NULL);	// Exif maker note metadata
1039 	FreeImage_SetMetadata(FIMD_EXIF_INTEROP, _dib, NULL, NULL);		// Exif interoperability metadata
1040 	FreeImage_SetMetadata(FIMD_IPTC, _dib, NULL, NULL);				// IPTC/NAA metadata
1041 	FreeImage_SetMetadata(FIMD_XMP, _dib, NULL, NULL);				// Abobe XMP metadata
1042 	FreeImage_SetMetadata(FIMD_GEOTIFF, _dib, NULL, NULL);			// GeoTIFF metadata
1043 	FreeImage_SetMetadata(FIMD_ANIMATION, _dib, NULL, NULL);		// Animation metadata
1044 	FreeImage_SetMetadata(FIMD_CUSTOM, _dib, NULL, NULL);			// Used to attach other metadata types to a dib
1045 	FreeImage_SetMetadata(FIMD_EXIF_RAW, _dib, NULL, NULL);			// Exif metadata as a raw buffer
1046 }
1047 
1048