1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Herv� Drolon (drolon@infonie.fr)
6 // - Tanner Helland (tannerhelland@users.sf.net)
7 //
8 // This file is part of FreeImage 3
9 //
10 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
11 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
12 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
13 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
14 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
15 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
16 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
17 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
18 // THIS DISCLAIMER.
19 //
20 // Use at your own risk!
21 // ==========================================================
22
23 #include "FreeImage.h"
24 #include "Utilities.h"
25
26 // ----------------------------------------------------------
27
28 /** Convert a greyscale image of type Tsrc to type Tdst.
29 Conversion is done using standard C language casting convention.
30 */
31 template<class Tdst, class Tsrc>
32 class CONVERT_TYPE
33 {
34 public:
35 FIBITMAP* convert(FIBITMAP *src, FREE_IMAGE_TYPE dst_type);
36 };
37
38 template<class Tdst, class Tsrc> FIBITMAP*
convert(FIBITMAP * src,FREE_IMAGE_TYPE dst_type)39 CONVERT_TYPE<Tdst, Tsrc>::convert(FIBITMAP *src, FREE_IMAGE_TYPE dst_type) {
40
41 FIBITMAP *dst = NULL;
42
43 unsigned width = FreeImage_GetWidth(src);
44 unsigned height = FreeImage_GetHeight(src);
45 unsigned bpp = FreeImage_GetBPP(src);
46
47 // allocate dst image
48
49 dst = FreeImage_AllocateT(dst_type, width, height, bpp,
50 FreeImage_GetRedMask(src), FreeImage_GetGreenMask(src), FreeImage_GetBlueMask(src));
51 if(!dst) return NULL;
52
53 // convert from src_type to dst_type
54
55 for(unsigned y = 0; y < height; y++) {
56 const Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y));
57 Tdst *dst_bits = reinterpret_cast<Tdst*>(FreeImage_GetScanLine(dst, y));
58
59 for(unsigned x = 0; x < width; x++) {
60 *dst_bits++ = static_cast<Tdst>(*src_bits++);
61 }
62 }
63
64 return dst;
65 }
66
67
68 /** Convert a greyscale image of type Tsrc to a 8-bit grayscale dib.
69 Conversion is done using either a linear scaling from [min, max] to [0, 255]
70 or a rounding from src_pixel to (BYTE) MIN(255, MAX(0, q)) where int q = int(src_pixel + 0.5);
71 */
72 template<class Tsrc>
73 class CONVERT_TO_BYTE
74 {
75 public:
76 FIBITMAP* convert(FIBITMAP *src, BOOL scale_linear);
77 };
78
79 template<class Tsrc> FIBITMAP*
convert(FIBITMAP * src,BOOL scale_linear)80 CONVERT_TO_BYTE<Tsrc>::convert(FIBITMAP *src, BOOL scale_linear) {
81 FIBITMAP *dst = NULL;
82 unsigned x, y;
83
84 unsigned width = FreeImage_GetWidth(src);
85 unsigned height = FreeImage_GetHeight(src);
86
87 // allocate a 8-bit dib
88
89 dst = FreeImage_AllocateT(FIT_BITMAP, width, height, 8, 0, 0, 0);
90 if(!dst) return NULL;
91
92 // build a greyscale palette
93 RGBQUAD *pal = FreeImage_GetPalette(dst);
94 for(int i = 0; i < 256; i++) {
95 pal[i].rgbRed = (BYTE)i;
96 pal[i].rgbGreen = (BYTE)i;
97 pal[i].rgbBlue = (BYTE)i;
98 }
99
100 // convert the src image to dst
101 // (FIBITMAP are stored upside down)
102 if(scale_linear) {
103 Tsrc max, min;
104 double scale;
105
106 // find the min and max value of the image
107 Tsrc l_min, l_max;
108 min = 255, max = 0;
109 for(y = 0; y < height; y++) {
110 Tsrc *bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y));
111 MAXMIN(bits, width, l_max, l_min);
112 if(l_max > max) max = l_max;
113 if(l_min < min) min = l_min;
114 }
115 if(max == min) {
116 max = 255; min = 0;
117 }
118
119 // compute the scaling factor
120 scale = 255 / (double)(max - min);
121
122 // scale to 8-bit
123 for(y = 0; y < height; y++) {
124 Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y));
125 BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
126 for(x = 0; x < width; x++) {
127 dst_bits[x] = (BYTE)( scale * (src_bits[x] - min) + 0.5);
128 }
129 }
130 } else {
131 for(y = 0; y < height; y++) {
132 Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y));
133 BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
134 for(x = 0; x < width; x++) {
135 // rounding
136 int q = int(src_bits[x] + 0.5);
137 dst_bits[x] = (BYTE) MIN(255, MAX(0, q));
138 }
139 }
140 }
141
142 return dst;
143 }
144
145 /** Convert a greyscale image of type Tsrc to a FICOMPLEX dib.
146 */
147 template<class Tsrc>
148 class CONVERT_TO_COMPLEX
149 {
150 public:
151 FIBITMAP* convert(FIBITMAP *src);
152 };
153
154 template<class Tsrc> FIBITMAP*
convert(FIBITMAP * src)155 CONVERT_TO_COMPLEX<Tsrc>::convert(FIBITMAP *src) {
156 FIBITMAP *dst = NULL;
157
158 unsigned width = FreeImage_GetWidth(src);
159 unsigned height = FreeImage_GetHeight(src);
160
161 // allocate dst image
162
163 dst = FreeImage_AllocateT(FIT_COMPLEX, width, height);
164 if(!dst) return NULL;
165
166 // convert from src_type to FIT_COMPLEX
167
168 for(unsigned y = 0; y < height; y++) {
169 const Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y));
170 FICOMPLEX *dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y);
171
172 for(unsigned x = 0; x < width; x++) {
173 dst_bits[x].r = (double)src_bits[x];
174 dst_bits[x].i = 0;
175 }
176 }
177
178 return dst;
179 }
180
181 // ----------------------------------------------------------
182
183 // Convert from type BYTE to type X
184 CONVERT_TYPE<unsigned short, BYTE> convertByteToUShort;
185 CONVERT_TYPE<short, BYTE> convertByteToShort;
186 CONVERT_TYPE<DWORD, BYTE> convertByteToULong;
187 CONVERT_TYPE<LONG, BYTE> convertByteToLong;
188 CONVERT_TYPE<float, BYTE> convertByteToFloat;
189 CONVERT_TYPE<double, BYTE> convertByteToDouble;
190
191 // Convert from type X to type BYTE
192 CONVERT_TO_BYTE<unsigned short> convertUShortToByte;
193 CONVERT_TO_BYTE<short> convertShortToByte;
194 CONVERT_TO_BYTE<DWORD> convertULongToByte;
195 CONVERT_TO_BYTE<LONG> convertLongToByte;
196 CONVERT_TO_BYTE<float> convertFloatToByte;
197 CONVERT_TO_BYTE<double> convertDoubleToByte;
198
199 // Convert from type X to type float
200 CONVERT_TYPE<float, unsigned short> convertUShortToFloat;
201 CONVERT_TYPE<float, short> convertShortToFloat;
202 CONVERT_TYPE<float, DWORD> convertULongToFloat;
203 CONVERT_TYPE<float, LONG> convertLongToFloat;
204
205 // Convert from type X to type double
206 CONVERT_TYPE<double, unsigned short> convertUShortToDouble;
207 CONVERT_TYPE<double, short> convertShortToDouble;
208 CONVERT_TYPE<double, DWORD> convertULongToDouble;
209 CONVERT_TYPE<double, LONG> convertLongToDouble;
210 CONVERT_TYPE<double, float> convertFloatToDouble;
211
212 // Convert from type X to type FICOMPLEX
213 CONVERT_TO_COMPLEX<BYTE> convertByteToComplex;
214 CONVERT_TO_COMPLEX<unsigned short> convertUShortToComplex;
215 CONVERT_TO_COMPLEX<short> convertShortToComplex;
216 CONVERT_TO_COMPLEX<DWORD> convertULongToComplex;
217 CONVERT_TO_COMPLEX<LONG> convertLongToComplex;
218 CONVERT_TO_COMPLEX<float> convertFloatToComplex;
219 CONVERT_TO_COMPLEX<double> convertDoubleToComplex;
220
221 // ----------------------------------------------------------
222
223 // ----------------------------------------------------------
224 // smart convert X to standard FIBITMAP
225 // ----------------------------------------------------------
226
227 /** Convert image of any type to a standard 8-bit greyscale image.
228 For standard images, a clone of the input image is returned.
229 When the scale_linear parameter is TRUE, conversion is done by scaling linearly
230 each pixel to an integer value between [0..255]. When it is FALSE, conversion is done
231 by rounding each float pixel to an integer between [0..255].
232 For complex images, the magnitude is extracted as a double image, then converted according to the scale parameter.
233 @param image Image to convert
234 @param scale_linear Linear scaling / rounding switch
235 */
236 FIBITMAP* DLL_CALLCONV
FreeImage_ConvertToStandardType(FIBITMAP * src,BOOL scale_linear)237 FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear) {
238 FIBITMAP *dst = NULL;
239
240 if(!src) return NULL;
241
242 // convert from src_type to FIT_BITMAP
243
244 const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);
245
246 switch(src_type) {
247 case FIT_BITMAP: // standard image: 1-, 4-, 8-, 16-, 24-, 32-bit
248 dst = FreeImage_Clone(src);
249 break;
250 case FIT_UINT16: // array of unsigned short: unsigned 16-bit
251 dst = convertUShortToByte.convert(src, scale_linear);
252 break;
253 case FIT_INT16: // array of short: signed 16-bit
254 dst = convertShortToByte.convert(src, scale_linear);
255 break;
256 case FIT_UINT32: // array of unsigned long: unsigned 32-bit
257 dst = convertULongToByte.convert(src, scale_linear);
258 break;
259 case FIT_INT32: // array of long: signed 32-bit
260 dst = convertLongToByte.convert(src, scale_linear);
261 break;
262 case FIT_FLOAT: // array of float: 32-bit
263 dst = convertFloatToByte.convert(src, scale_linear);
264 break;
265 case FIT_DOUBLE: // array of double: 64-bit
266 dst = convertDoubleToByte.convert(src, scale_linear);
267 break;
268 case FIT_COMPLEX: // array of FICOMPLEX: 2 x 64-bit
269 {
270 // Convert to type FIT_DOUBLE
271 FIBITMAP *dib_double = FreeImage_GetComplexChannel(src, FICC_MAG);
272 if(dib_double) {
273 // Convert to a standard bitmap (linear scaling)
274 dst = convertDoubleToByte.convert(dib_double, scale_linear);
275 // Free image of type FIT_DOUBLE
276 FreeImage_Unload(dib_double);
277 }
278 }
279 break;
280 case FIT_RGB16: // 48-bit RGB image: 3 x 16-bit
281 break;
282 case FIT_RGBA16: // 64-bit RGBA image: 4 x 16-bit
283 break;
284 case FIT_RGBF: // 96-bit RGB float image: 3 x 32-bit IEEE floating point
285 break;
286 case FIT_RGBAF: // 128-bit RGBA float image: 4 x 32-bit IEEE floating point
287 break;
288 }
289
290 if(NULL == dst) {
291 FreeImage_OutputMessageProc(FIF_UNKNOWN, "FREE_IMAGE_TYPE: Unable to convert from type %d to type %d.\n No such conversion exists.", src_type, FIT_BITMAP);
292 } else {
293 // copy metadata from src to dst
294 FreeImage_CloneMetadata(dst, src);
295 }
296
297 return dst;
298 }
299
300
301
302 // ----------------------------------------------------------
303 // smart convert X to Y
304 // ----------------------------------------------------------
305
306 FIBITMAP* DLL_CALLCONV
FreeImage_ConvertToType(FIBITMAP * src,FREE_IMAGE_TYPE dst_type,BOOL scale_linear)307 FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear) {
308 FIBITMAP *dst = NULL;
309
310 if(!FreeImage_HasPixels(src)) return NULL;
311
312 // convert from src_type to dst_type
313
314 const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);
315
316 if(src_type == dst_type) {
317 return FreeImage_Clone(src);
318 }
319
320 const unsigned src_bpp = FreeImage_GetBPP(src);
321
322 switch(src_type) {
323 case FIT_BITMAP:
324 switch(dst_type) {
325 case FIT_UINT16:
326 dst = FreeImage_ConvertToUINT16(src);
327 break;
328 case FIT_INT16:
329 dst = (src_bpp == 8) ? convertByteToShort.convert(src, dst_type) : NULL;
330 break;
331 case FIT_UINT32:
332 dst = (src_bpp == 8) ? convertByteToULong.convert(src, dst_type) : NULL;
333 break;
334 case FIT_INT32:
335 dst = (src_bpp == 8) ? convertByteToLong.convert(src, dst_type) : NULL;
336 break;
337 case FIT_FLOAT:
338 dst = FreeImage_ConvertToFloat(src);
339 break;
340 case FIT_DOUBLE:
341 dst = (src_bpp == 8) ? convertByteToDouble.convert(src, dst_type) : NULL;
342 break;
343 case FIT_COMPLEX:
344 dst = (src_bpp == 8) ? convertByteToComplex.convert(src) : NULL;
345 break;
346 case FIT_RGB16:
347 dst = FreeImage_ConvertToRGB16(src);
348 break;
349 case FIT_RGBA16:
350 dst = FreeImage_ConvertToRGBA16(src);
351 break;
352 case FIT_RGBF:
353 dst = FreeImage_ConvertToRGBF(src);
354 break;
355 case FIT_RGBAF:
356 dst = FreeImage_ConvertToRGBAF(src);
357 break;
358 }
359 break;
360 case FIT_UINT16:
361 switch(dst_type) {
362 case FIT_BITMAP:
363 dst = FreeImage_ConvertToStandardType(src, scale_linear);
364 break;
365 case FIT_INT16:
366 break;
367 case FIT_UINT32:
368 break;
369 case FIT_INT32:
370 break;
371 case FIT_FLOAT:
372 dst = FreeImage_ConvertToFloat(src);
373 break;
374 case FIT_DOUBLE:
375 dst = convertUShortToDouble.convert(src, dst_type);
376 break;
377 case FIT_COMPLEX:
378 dst = convertUShortToComplex.convert(src);
379 break;
380 case FIT_RGB16:
381 dst = FreeImage_ConvertToRGB16(src);
382 break;
383 case FIT_RGBA16:
384 dst = FreeImage_ConvertToRGBA16(src);
385 break;
386 case FIT_RGBF:
387 dst = FreeImage_ConvertToRGBF(src);
388 break;
389 case FIT_RGBAF:
390 dst = FreeImage_ConvertToRGBAF(src);
391 break;
392 }
393 break;
394 case FIT_INT16:
395 switch(dst_type) {
396 case FIT_BITMAP:
397 dst = FreeImage_ConvertToStandardType(src, scale_linear);
398 break;
399 case FIT_UINT16:
400 break;
401 case FIT_UINT32:
402 break;
403 case FIT_INT32:
404 break;
405 case FIT_FLOAT:
406 dst = convertShortToFloat.convert(src, dst_type);
407 break;
408 case FIT_DOUBLE:
409 dst = convertShortToDouble.convert(src, dst_type);
410 break;
411 case FIT_COMPLEX:
412 dst = convertShortToComplex.convert(src);
413 break;
414 case FIT_RGB16:
415 break;
416 case FIT_RGBA16:
417 break;
418 case FIT_RGBF:
419 break;
420 case FIT_RGBAF:
421 break;
422 }
423 break;
424 case FIT_UINT32:
425 switch(dst_type) {
426 case FIT_BITMAP:
427 dst = FreeImage_ConvertToStandardType(src, scale_linear);
428 break;
429 case FIT_UINT16:
430 break;
431 case FIT_INT16:
432 break;
433 case FIT_INT32:
434 break;
435 case FIT_FLOAT:
436 dst = convertULongToFloat.convert(src, dst_type);
437 break;
438 case FIT_DOUBLE:
439 dst = convertULongToDouble.convert(src, dst_type);
440 break;
441 case FIT_COMPLEX:
442 dst = convertULongToComplex.convert(src);
443 break;
444 case FIT_RGB16:
445 break;
446 case FIT_RGBA16:
447 break;
448 case FIT_RGBF:
449 break;
450 case FIT_RGBAF:
451 break;
452 }
453 break;
454 case FIT_INT32:
455 switch(dst_type) {
456 case FIT_BITMAP:
457 dst = FreeImage_ConvertToStandardType(src, scale_linear);
458 break;
459 case FIT_UINT16:
460 break;
461 case FIT_INT16:
462 break;
463 case FIT_UINT32:
464 break;
465 case FIT_FLOAT:
466 dst = convertLongToFloat.convert(src, dst_type);
467 break;
468 case FIT_DOUBLE:
469 dst = convertLongToDouble.convert(src, dst_type);
470 break;
471 case FIT_COMPLEX:
472 dst = convertLongToComplex.convert(src);
473 break;
474 case FIT_RGB16:
475 break;
476 case FIT_RGBA16:
477 break;
478 case FIT_RGBF:
479 break;
480 case FIT_RGBAF:
481 break;
482 }
483 break;
484 case FIT_FLOAT:
485 switch(dst_type) {
486 case FIT_BITMAP:
487 dst = FreeImage_ConvertToStandardType(src, scale_linear);
488 break;
489 case FIT_UINT16:
490 break;
491 case FIT_INT16:
492 break;
493 case FIT_UINT32:
494 break;
495 case FIT_INT32:
496 break;
497 case FIT_DOUBLE:
498 dst = convertFloatToDouble.convert(src, dst_type);
499 break;
500 case FIT_COMPLEX:
501 dst = convertFloatToComplex.convert(src);
502 break;
503 case FIT_RGB16:
504 break;
505 case FIT_RGBA16:
506 break;
507 case FIT_RGBF:
508 dst = FreeImage_ConvertToRGBF(src);
509 break;
510 case FIT_RGBAF:
511 dst = FreeImage_ConvertToRGBAF(src);
512 break;
513 }
514 break;
515 case FIT_DOUBLE:
516 switch(dst_type) {
517 case FIT_BITMAP:
518 dst = FreeImage_ConvertToStandardType(src, scale_linear);
519 break;
520 case FIT_UINT16:
521 break;
522 case FIT_INT16:
523 break;
524 case FIT_UINT32:
525 break;
526 case FIT_INT32:
527 break;
528 case FIT_FLOAT:
529 break;
530 case FIT_COMPLEX:
531 dst = convertDoubleToComplex.convert(src);
532 break;
533 case FIT_RGB16:
534 break;
535 case FIT_RGBA16:
536 break;
537 case FIT_RGBF:
538 break;
539 case FIT_RGBAF:
540 break;
541 }
542 break;
543 case FIT_COMPLEX:
544 switch(dst_type) {
545 case FIT_BITMAP:
546 break;
547 case FIT_UINT16:
548 break;
549 case FIT_INT16:
550 break;
551 case FIT_UINT32:
552 break;
553 case FIT_INT32:
554 break;
555 case FIT_FLOAT:
556 break;
557 case FIT_DOUBLE:
558 break;
559 case FIT_RGB16:
560 break;
561 case FIT_RGBA16:
562 break;
563 case FIT_RGBF:
564 break;
565 case FIT_RGBAF:
566 break;
567 }
568 break;
569 case FIT_RGB16:
570 switch(dst_type) {
571 case FIT_BITMAP:
572 dst = FreeImage_ConvertTo24Bits(src);
573 break;
574 case FIT_UINT16:
575 dst = FreeImage_ConvertToUINT16(src);
576 break;
577 case FIT_INT16:
578 break;
579 case FIT_UINT32:
580 break;
581 case FIT_INT32:
582 break;
583 case FIT_FLOAT:
584 dst = FreeImage_ConvertToFloat(src);
585 break;
586 case FIT_DOUBLE:
587 break;
588 case FIT_COMPLEX:
589 break;
590 case FIT_RGBA16:
591 dst = FreeImage_ConvertToRGBA16(src);
592 break;
593 case FIT_RGBF:
594 dst = FreeImage_ConvertToRGBF(src);
595 break;
596 case FIT_RGBAF:
597 dst = FreeImage_ConvertToRGBAF(src);
598 break;
599 }
600 break;
601 case FIT_RGBA16:
602 switch(dst_type) {
603 case FIT_BITMAP:
604 dst = FreeImage_ConvertTo32Bits(src);
605 break;
606 case FIT_UINT16:
607 dst = FreeImage_ConvertToUINT16(src);
608 break;
609 case FIT_INT16:
610 break;
611 case FIT_UINT32:
612 break;
613 case FIT_INT32:
614 break;
615 case FIT_FLOAT:
616 dst = FreeImage_ConvertToFloat(src);
617 break;
618 case FIT_DOUBLE:
619 break;
620 case FIT_COMPLEX:
621 break;
622 case FIT_RGB16:
623 dst = FreeImage_ConvertToRGB16(src);
624 break;
625 case FIT_RGBF:
626 dst = FreeImage_ConvertToRGBF(src);
627 break;
628 case FIT_RGBAF:
629 dst = FreeImage_ConvertToRGBAF(src);
630 break;
631 }
632 break;
633 case FIT_RGBF:
634 switch(dst_type) {
635 case FIT_BITMAP:
636 break;
637 case FIT_UINT16:
638 break;
639 case FIT_INT16:
640 break;
641 case FIT_UINT32:
642 break;
643 case FIT_INT32:
644 break;
645 case FIT_FLOAT:
646 dst = FreeImage_ConvertToFloat(src);
647 break;
648 case FIT_DOUBLE:
649 break;
650 case FIT_COMPLEX:
651 break;
652 case FIT_RGB16:
653 break;
654 case FIT_RGBA16:
655 break;
656 case FIT_RGBAF:
657 dst = FreeImage_ConvertToRGBAF(src);
658 break;
659 }
660 break;
661 case FIT_RGBAF:
662 switch(dst_type) {
663 case FIT_BITMAP:
664 break;
665 case FIT_UINT16:
666 break;
667 case FIT_INT16:
668 break;
669 case FIT_UINT32:
670 break;
671 case FIT_INT32:
672 break;
673 case FIT_FLOAT:
674 dst = FreeImage_ConvertToFloat(src);
675 break;
676 case FIT_DOUBLE:
677 break;
678 case FIT_COMPLEX:
679 break;
680 case FIT_RGB16:
681 break;
682 case FIT_RGBA16:
683 break;
684 case FIT_RGBF:
685 dst = FreeImage_ConvertToRGBF(src);
686 break;
687 }
688 break;
689 }
690
691 if(NULL == dst) {
692 FreeImage_OutputMessageProc(FIF_UNKNOWN, "FREE_IMAGE_TYPE: Unable to convert from type %d to type %d.\n No such conversion exists.", src_type, dst_type);
693 } else {
694 // copy metadata from src to dst
695 FreeImage_CloneMetadata(dst, src);
696 }
697
698 return dst;
699 }
700