/[projet1]/public/pc/shared_libraries/freeimage/v3.12.0/Source/FreeImage/PluginBMP.cpp
Defence Force logotype

Contents of /public/pc/shared_libraries/freeimage/v3.12.0/Source/FreeImage/PluginBMP.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 126 - (show annotations)
Mon Jul 13 12:20:10 2009 UTC (10 years, 7 months ago) by dbug
File size: 36935 byte(s)
Added some shared libraries (UnitTest++, and FreeImage) to avoid having every single project brings its own libraries.
Ideally people should add them in a way we can upgrade versions without breaking things:
-> public/pc/shared_libraries/library_name/library_version/actuall_content
1 // ==========================================================
2 // BMP Loader and Writer
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Markus Loibl (markus.loibl@epost.de)
7 // - Martin Weber (martweb@gmx.net)
8 // - Hervé Drolon (drolon@infonie.fr)
9 // - Michal Novotny (michal@etc.cz)
10 //
11 // This file is part of FreeImage 3
12 //
13 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
14 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
15 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
16 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
17 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
18 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
19 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
20 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
21 // THIS DISCLAIMER.
22 //
23 // Use at your own risk!
24 // ==========================================================
25
26 #include "FreeImage.h"
27 #include "Utilities.h"
28
29 // ----------------------------------------------------------
30 // Constants + headers
31 // ----------------------------------------------------------
32
33 static const BYTE RLE_COMMAND = 0;
34 static const BYTE RLE_ENDOFLINE = 0;
35 static const BYTE RLE_ENDOFBITMAP = 1;
36 static const BYTE RLE_DELTA = 2;
37
38 #ifndef __MINGW32__ // prevents a bug in mingw32
39
40 static const BYTE BI_RGB = 0;
41 static const BYTE BI_RLE8 = 1;
42 static const BYTE BI_RLE4 = 2;
43 static const BYTE BI_BITFIELDS = 3;
44
45 #endif // __MINGW32__
46
47 // ----------------------------------------------------------
48
49 #ifdef _WIN32
50 #pragma pack(push, 1)
51 #else
52 #pragma pack(1)
53 #endif
54
55 #ifndef __MINGW32__
56 typedef struct tagBITMAPCOREHEADER {
57 DWORD bcSize;
58 WORD bcWidth;
59 WORD bcHeight;
60 WORD bcPlanes;
61 WORD bcBitCnt;
62 } BITMAPCOREHEADER, *PBITMAPCOREHEADER;
63 #endif //__MINGW32__
64
65 typedef struct tagBITMAPINFOOS2_1X_HEADER {
66 DWORD biSize;
67 WORD biWidth;
68 WORD biHeight;
69 WORD biPlanes;
70 WORD biBitCount;
71 } BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER;
72
73 #ifndef __MINGW32__
74 typedef struct tagBITMAPFILEHEADER {
75 WORD bfType;
76 DWORD bfSize;
77 WORD bfReserved1;
78 WORD bfReserved2;
79 DWORD bfOffBits;
80 } BITMAPFILEHEADER, *PBITMAPFILEHEADER;
81 #endif //__MINGW32__
82
83 #ifdef _WIN32
84 #pragma pack(pop)
85 #else
86 #pragma pack()
87 #endif
88
89 // ==========================================================
90 // Plugin Interface
91 // ==========================================================
92
93 static int s_format_id;
94
95 // ==========================================================
96 // Internal functions
97 // ==========================================================
98
99 #ifdef FREEIMAGE_BIGENDIAN
100 static void
101 SwapInfoHeader(BITMAPINFOHEADER *header) {
102 SwapLong(&header->biSize);
103 SwapLong((DWORD *)&header->biWidth);
104 SwapLong((DWORD *)&header->biHeight);
105 SwapShort(&header->biPlanes);
106 SwapShort(&header->biBitCount);
107 SwapLong(&header->biCompression);
108 SwapLong(&header->biSizeImage);
109 SwapLong((DWORD *)&header->biXPelsPerMeter);
110 SwapLong((DWORD *)&header->biYPelsPerMeter);
111 SwapLong(&header->biClrUsed);
112 SwapLong(&header->biClrImportant);
113 }
114
115 static void
116 SwapCoreHeader(BITMAPCOREHEADER *header) {
117 SwapLong(&header->bcSize);
118 SwapShort(&header->bcWidth);
119 SwapShort(&header->bcHeight);
120 SwapShort(&header->bcPlanes);
121 SwapShort(&header->bcBitCnt);
122 }
123
124 static void
125 SwapOS21XHeader(BITMAPINFOOS2_1X_HEADER *header) {
126 SwapLong(&header->biSize);
127 SwapShort(&header->biWidth);
128 SwapShort(&header->biHeight);
129 SwapShort(&header->biPlanes);
130 SwapShort(&header->biBitCount);
131 }
132
133 static void
134 SwapFileHeader(BITMAPFILEHEADER *header) {
135 SwapShort(&header->bfType);
136 SwapLong(&header->bfSize);
137 SwapShort(&header->bfReserved1);
138 SwapShort(&header->bfReserved2);
139 SwapLong(&header->bfOffBits);
140 }
141 #endif
142
143 // --------------------------------------------------------------------------
144
145 /**
146 Load uncompressed image pixels for 1-, 4-, 8-, 16-, 24- and 32-bit dib
147 @param io FreeImage IO
148 @param handle FreeImage IO handle
149 @param dib Image to be loaded
150 @param height Image height
151 @param pitch Image pitch
152 @param bit_count Image bit-depth (1-, 4-, 8-, 16-, 24- or 32-bit)
153 */
154 static void
155 LoadPixelData(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int height, int pitch, int bit_count) {
156 // Load pixel data
157 // NB: height can be < 0 for BMP data
158 if (height > 0) {
159 io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle);
160 } else {
161 int positiveHeight = abs(height);
162 for (int c = 0; c < positiveHeight; ++c) {
163 io->read_proc((void *)FreeImage_GetScanLine(dib, positiveHeight - c - 1), pitch, 1, handle);
164 }
165 }
166
167 // swap as needed
168 #ifdef FREEIMAGE_BIGENDIAN
169 if (bit_count == 16) {
170 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
171 WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y);
172 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
173 SwapShort(pixel);
174 pixel++;
175 }
176 }
177 }
178 #endif
179 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
180 if (bit_count == 24 || bit_count == 32) {
181 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
182 BYTE *pixel = FreeImage_GetScanLine(dib, y);
183 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
184 INPLACESWAP(pixel[0], pixel[2]);
185 pixel += (bit_count >> 3);
186 }
187 }
188 }
189 #endif
190 }
191
192 /**
193 Load image pixels for 4-bit RLE compressed dib
194 @param io FreeImage IO
195 @param handle FreeImage IO handle
196 @param width Image width
197 @param height Image height
198 @param dib Image to be loaded
199 @return Returns TRUE if successful, returns FALSE otherwise
200 */
201 static BOOL
202 LoadPixelDataRLE4(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
203 int status_byte = 0;
204 BYTE second_byte = 0;
205 int bits = 0;
206
207 BYTE *pixels = NULL; // temporary 8-bit buffer
208
209 try {
210 height = abs(height);
211
212 pixels = (BYTE*)malloc(width * height * sizeof(BYTE));
213 if(!pixels) throw(1);
214 memset(pixels, 0, width * height * sizeof(BYTE));
215
216 BYTE *q = pixels;
217 BYTE *end = pixels + height * width;
218
219 for (int scanline = 0; scanline < height; ) {
220 if (q < pixels || q >= end) {
221 break;
222 }
223 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
224 throw(1);
225 }
226 if (status_byte != 0) {
227 status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
228 // Encoded mode
229 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
230 throw(1);
231 }
232 for (int i = 0; i < status_byte; i++) {
233 *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
234 }
235 bits += status_byte;
236 }
237 else {
238 // Escape mode
239 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
240 throw(1);
241 }
242 switch (status_byte) {
243 case RLE_ENDOFLINE:
244 {
245 // End of line
246 bits = 0;
247 scanline++;
248 q = pixels + scanline*width;
249 }
250 break;
251
252 case RLE_ENDOFBITMAP:
253 // End of bitmap
254 q = end;
255 break;
256
257 case RLE_DELTA:
258 {
259 // read the delta values
260
261 BYTE delta_x = 0;
262 BYTE delta_y = 0;
263
264 if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
265 throw(1);
266 }
267 if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
268 throw(1);
269 }
270
271 // apply them
272
273 bits += delta_x;
274 scanline += delta_y;
275 q = pixels + scanline*width+bits;
276 }
277 break;
278
279 default:
280 {
281 // Absolute mode
282 status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
283 for (int i = 0; i < status_byte; i++) {
284 if ((i & 0x01) == 0) {
285 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
286 throw(1);
287 }
288 }
289 *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
290 }
291 bits += status_byte;
292 // Read pad byte
293 if (((status_byte & 0x03) == 1) || ((status_byte & 0x03) == 2)) {
294 BYTE padding = 0;
295 if(io->read_proc(&padding, sizeof(BYTE), 1, handle) != 1) {
296 throw(1);
297 }
298 }
299 }
300 break;
301 }
302 }
303 }
304
305 {
306 // Convert to 4-bit
307 for(int y = 0; y < height; y++) {
308 const BYTE *src = (BYTE*)pixels + y * width;
309 BYTE *dst = FreeImage_GetScanLine(dib, y);
310
311 BOOL hinibble = TRUE;
312
313 for (int cols = 0; cols < width; cols++){
314 if (hinibble) {
315 dst[cols >> 1] = (src[cols] << 4);
316 } else {
317 dst[cols >> 1] |= src[cols];
318 }
319
320 hinibble = !hinibble;
321 }
322 }
323 }
324
325 free(pixels);
326
327 return TRUE;
328
329 } catch(int) {
330 if(pixels) free(pixels);
331 return FALSE;
332 }
333 }
334
335 /**
336 Load image pixels for 8-bit RLE compressed dib
337 @param io FreeImage IO
338 @param handle FreeImage IO handle
339 @param width Image width
340 @param height Image height
341 @param dib Image to be loaded
342 @return Returns TRUE if successful, returns FALSE otherwise
343 */
344 static BOOL
345 LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
346 BYTE status_byte = 0;
347 BYTE second_byte = 0;
348 int scanline = 0;
349 int bits = 0;
350
351 for (;;) {
352 if( io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
353 return FALSE;
354 }
355
356 switch (status_byte) {
357 case RLE_COMMAND :
358 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
359 return FALSE;
360 }
361
362 switch (status_byte) {
363 case RLE_ENDOFLINE :
364 bits = 0;
365 scanline++;
366 break;
367
368 case RLE_ENDOFBITMAP :
369 return TRUE;
370
371 case RLE_DELTA :
372 {
373 // read the delta values
374
375 BYTE delta_x = 0;
376 BYTE delta_y = 0;
377
378 if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
379 return FALSE;
380 }
381 if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
382 return FALSE;
383 }
384
385 // apply them
386
387 bits += delta_x;
388 scanline += delta_y;
389
390 break;
391 }
392
393 default :
394 {
395 if(scanline >= abs(height)) {
396 return TRUE;
397 }
398
399 int count = MIN((int)status_byte, width - bits);
400
401 BYTE *sline = FreeImage_GetScanLine(dib, scanline);
402
403 if(io->read_proc((void *)(sline + bits), sizeof(BYTE) * count, 1, handle) != 1) {
404 return FALSE;
405 }
406
407 // align run length to even number of bytes
408
409 if ((status_byte & 1) == 1) {
410 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
411 return FALSE;
412 }
413 }
414
415 bits += status_byte;
416
417 break;
418 }
419 }
420
421 break;
422
423 default :
424 {
425 if(scanline >= abs(height)) {
426 return TRUE;
427 }
428
429 int count = MIN((int)status_byte, width - bits);
430
431 BYTE *sline = FreeImage_GetScanLine(dib, scanline);
432
433 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
434 return FALSE;
435 }
436
437 for (int i = 0; i < count; i++) {
438 *(sline + bits) = second_byte;
439
440 bits++;
441 }
442
443 break;
444 }
445 }
446 }
447 }
448
449 // --------------------------------------------------------------------------
450
451 static FIBITMAP *
452 LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
453 FIBITMAP *dib = NULL;
454
455 try {
456 // load the info header
457
458 BITMAPINFOHEADER bih;
459
460 io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
461 #ifdef FREEIMAGE_BIGENDIAN
462 SwapInfoHeader(&bih);
463 #endif
464
465 // keep some general information about the bitmap
466
467 int used_colors = bih.biClrUsed;
468 int width = bih.biWidth;
469 int height = bih.biHeight; // WARNING: height can be < 0 => check each call using 'height' as a parameter
470 int bit_count = bih.biBitCount;
471 int compression = bih.biCompression;
472 int pitch = CalculatePitch(CalculateLine(width, bit_count));
473
474 switch (bit_count) {
475 case 1 :
476 case 4 :
477 case 8 :
478 {
479 if ((used_colors <= 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
480 used_colors = CalculateUsedPaletteEntries(bit_count);
481
482 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
483
484 dib = FreeImage_Allocate(width, height, bit_count);
485
486 if (dib == NULL)
487 throw "DIB allocation failed";
488
489 // set resolution information
490 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
491 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
492
493 // load the palette
494
495 io->read_proc(FreeImage_GetPalette(dib), used_colors * sizeof(RGBQUAD), 1, handle);
496 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
497 RGBQUAD *pal = FreeImage_GetPalette(dib);
498 for(int i = 0; i < used_colors; i++) {
499 INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue);
500 }
501 #endif
502
503 // seek to the actual pixel data.
504 // this is needed because sometimes the palette is larger than the entries it contains predicts
505
506 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * sizeof(RGBQUAD))))
507 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
508
509 // read the pixel data
510
511 switch (compression) {
512 case BI_RGB :
513 LoadPixelData(io, handle, dib, height, pitch, bit_count);
514 return dib;
515
516 case BI_RLE4 :
517 if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
518 return dib;
519 } else {
520 throw "Error encountered while decoding RLE4 BMP data";
521 }
522 break;
523
524 case BI_RLE8 :
525 if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
526 return dib;
527 } else {
528 throw "Error encountered while decoding RLE8 BMP data";
529 }
530 break;
531
532 default :
533 throw "compression type not supported";
534 }
535 }
536 break; // 1-, 4-, 8-bit
537
538 case 16 :
539 {
540 if (bih.biCompression == BI_BITFIELDS) {
541 DWORD bitfields[3];
542
543 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
544
545 dib = FreeImage_Allocate(width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
546 } else {
547 dib = FreeImage_Allocate(width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
548 }
549
550 if (dib == NULL)
551 throw "DIB allocation failed";
552
553 // set resolution information
554 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
555 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
556
557 // load pixel data and swap as needed if OS is Big Endian
558 LoadPixelData(io, handle, dib, height, pitch, bit_count);
559
560 return dib;
561 }
562 break; // 16-bit
563
564 case 24 :
565 case 32 :
566 {
567 if (bih.biCompression == BI_BITFIELDS) {
568 DWORD bitfields[3];
569
570 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
571
572 dib = FreeImage_Allocate(width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
573 } else {
574 if( bit_count == 32 ) {
575 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
576 } else {
577 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
578 }
579 }
580
581 if (dib == NULL)
582 throw "DIB allocation failed";
583
584 // set resolution information
585 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
586 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
587
588 // Skip over the optional palette
589 // A 24 or 32 bit DIB may contain a palette for faster color reduction
590
591 if (FreeImage_GetColorsUsed(dib) > 0) {
592 io->seek_proc(handle, FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD), SEEK_CUR);
593 } else if ((bih.biCompression != BI_BITFIELDS) && (bitmap_bits_offset > sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) {
594 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
595 }
596
597 // read in the bitmap bits
598 // load pixel data and swap as needed if OS is Big Endian
599 LoadPixelData(io, handle, dib, height, pitch, bit_count);
600
601 // check if the bitmap contains transparency, if so enable it in the header
602
603 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
604
605 return dib;
606 }
607 break; // 24-, 32-bit
608 }
609 } catch(const char *message) {
610 if(dib) {
611 FreeImage_Unload(dib);
612 }
613 if(message) {
614 FreeImage_OutputMessageProc(s_format_id, message);
615 }
616 }
617
618 return NULL;
619 }
620
621 // --------------------------------------------------------------------------
622
623 static FIBITMAP *
624 LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
625 FIBITMAP *dib = NULL;
626
627 try {
628 // load the info header
629
630 BITMAPINFOHEADER bih;
631
632 io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
633 #ifdef FREEIMAGE_BIGENDIAN
634 SwapInfoHeader(&bih);
635 #endif
636
637 // keep some general information about the bitmap
638
639 int used_colors = bih.biClrUsed;
640 int width = bih.biWidth;
641 int height = bih.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
642 int bit_count = bih.biBitCount;
643 int compression = bih.biCompression;
644 int pitch = CalculatePitch(CalculateLine(width, bit_count));
645
646 switch (bit_count) {
647 case 1 :
648 case 4 :
649 case 8 :
650 {
651 if ((used_colors <= 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
652 used_colors = CalculateUsedPaletteEntries(bit_count);
653
654 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
655
656 dib = FreeImage_Allocate(width, height, bit_count);
657
658 if (dib == NULL)
659 throw "DIB allocation failed";
660
661 // set resolution information
662 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
663 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
664
665 // load the palette
666
667 io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET);
668
669 RGBQUAD *pal = FreeImage_GetPalette(dib);
670
671 for (int count = 0; count < used_colors; count++) {
672 FILE_BGR bgr;
673
674 io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
675
676 pal[count].rgbRed = bgr.r;
677 pal[count].rgbGreen = bgr.g;
678 pal[count].rgbBlue = bgr.b;
679 }
680
681 // seek to the actual pixel data.
682 // this is needed because sometimes the palette is larger than the entries it contains predicts
683
684 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
685 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
686
687 // read the pixel data
688
689 switch (compression) {
690 case BI_RGB :
691 // load pixel data
692 LoadPixelData(io, handle, dib, height, pitch, bit_count);
693 return dib;
694
695 case BI_RLE4 :
696 if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
697 return dib;
698 } else {
699 throw "Error encountered while decoding RLE4 BMP data";
700 }
701 break;
702
703 case BI_RLE8 :
704 if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
705 return dib;
706 } else {
707 throw "Error encountered while decoding RLE8 BMP data";
708 }
709 break;
710
711 default :
712 throw "compression type not supported";
713 }
714 }
715
716 case 16 :
717 {
718 if (bih.biCompression == 3) {
719 DWORD bitfields[3];
720
721 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
722
723 dib = FreeImage_Allocate(width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
724 } else {
725 dib = FreeImage_Allocate(width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
726 }
727
728 if (dib == NULL)
729 throw "DIB allocation failed";
730
731 // set resolution information
732 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
733 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
734
735 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
736 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
737 }
738
739 // load pixel data and swap as needed if OS is Big Endian
740 LoadPixelData(io, handle, dib, height, pitch, bit_count);
741
742 return dib;
743 }
744
745 case 24 :
746 case 32 :
747 {
748 if( bit_count == 32 ) {
749 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
750 } else {
751 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
752 }
753
754 if (dib == NULL)
755 throw "DIB allocation failed";
756
757 // set resolution information
758 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
759 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
760
761 // Skip over the optional palette
762 // A 24 or 32 bit DIB may contain a palette for faster color reduction
763
764 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
765 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
766
767 // read in the bitmap bits
768 // load pixel data and swap as needed if OS is Big Endian
769 LoadPixelData(io, handle, dib, height, pitch, bit_count);
770
771 // check if the bitmap contains transparency, if so enable it in the header
772
773 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
774
775 return dib;
776 }
777 }
778 } catch(const char *message) {
779 if(dib)
780 FreeImage_Unload(dib);
781
782 FreeImage_OutputMessageProc(s_format_id, message);
783 }
784
785 return NULL;
786 }
787
788 // --------------------------------------------------------------------------
789
790 static FIBITMAP *
791 LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
792 FIBITMAP *dib = NULL;
793
794 try {
795 BITMAPINFOOS2_1X_HEADER bios2_1x;
796
797 io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle);
798 #ifdef FREEIMAGE_BIGENDIAN
799 SwapOS21XHeader(&bios2_1x);
800 #endif
801 // keep some general information about the bitmap
802
803 int used_colors = 0;
804 int width = bios2_1x.biWidth;
805 int height = bios2_1x.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
806 int bit_count = bios2_1x.biBitCount;
807 int pitch = CalculatePitch(CalculateLine(width, bit_count));
808
809 switch (bit_count) {
810 case 1 :
811 case 4 :
812 case 8 :
813 {
814 used_colors = CalculateUsedPaletteEntries(bit_count);
815
816 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
817
818 dib = FreeImage_Allocate(width, height, bit_count);
819
820 if (dib == NULL)
821 throw "DIB allocation failed";
822
823 // set resolution information to default values (72 dpi in english units)
824 FreeImage_SetDotsPerMeterX(dib, 2835);
825 FreeImage_SetDotsPerMeterY(dib, 2835);
826
827 // load the palette
828
829 RGBQUAD *pal = FreeImage_GetPalette(dib);
830
831 for (int count = 0; count < used_colors; count++) {
832 FILE_BGR bgr;
833
834 io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
835
836 pal[count].rgbRed = bgr.r;
837 pal[count].rgbGreen = bgr.g;
838 pal[count].rgbBlue = bgr.b;
839 }
840
841 // Skip over the optional palette
842 // A 24 or 32 bit DIB may contain a palette for faster color reduction
843
844 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
845
846 // read the pixel data
847
848 // load pixel data
849 LoadPixelData(io, handle, dib, height, pitch, bit_count);
850
851 return dib;
852 }
853
854 case 16 :
855 {
856 dib = FreeImage_Allocate(width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
857
858 if (dib == NULL)
859 throw "DIB allocation failed";
860
861 // set resolution information to default values (72 dpi in english units)
862 FreeImage_SetDotsPerMeterX(dib, 2835);
863 FreeImage_SetDotsPerMeterY(dib, 2835);
864
865 // load pixel data and swap as needed if OS is Big Endian
866 LoadPixelData(io, handle, dib, height, pitch, bit_count);
867
868 return dib;
869 }
870
871 case 24 :
872 case 32 :
873 {
874 if( bit_count == 32 ) {
875 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
876 } else {
877 dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
878 }
879
880 if (dib == NULL)
881 throw "DIB allocation failed";
882
883 // set resolution information to default values (72 dpi in english units)
884 FreeImage_SetDotsPerMeterX(dib, 2835);
885 FreeImage_SetDotsPerMeterY(dib, 2835);
886
887 // Skip over the optional palette
888 // A 24 or 32 bit DIB may contain a palette for faster color reduction
889
890 // load pixel data and swap as needed if OS is Big Endian
891 LoadPixelData(io, handle, dib, height, pitch, bit_count);
892
893 // check if the bitmap contains transparency, if so enable it in the header
894
895 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
896
897 return dib;
898 }
899 }
900 } catch(const char *message) {
901 if(dib)
902 FreeImage_Unload(dib);
903
904 FreeImage_OutputMessageProc(s_format_id, message);
905 }
906
907 return NULL;
908 }
909
910 // ==========================================================
911 // Plugin Implementation
912 // ==========================================================
913
914 static const char * DLL_CALLCONV
915 Format() {
916 return "BMP";
917 }
918
919 static const char * DLL_CALLCONV
920 Description() {
921 return "Windows or OS/2 Bitmap";
922 }
923
924 static const char * DLL_CALLCONV
925 Extension() {
926 return "bmp";
927 }
928
929 static const char * DLL_CALLCONV
930 RegExpr() {
931 return "^BM";
932 }
933
934 static const char * DLL_CALLCONV
935 MimeType() {
936 return "image/bmp";
937 }
938
939 static BOOL DLL_CALLCONV
940 Validate(FreeImageIO *io, fi_handle handle) {
941 BYTE bmp_signature1[] = { 0x42, 0x4D };
942 BYTE bmp_signature2[] = { 0x42, 0x41 };
943 BYTE signature[2] = { 0, 0 };
944
945 io->read_proc(signature, 1, sizeof(bmp_signature1), handle);
946
947 if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0)
948 return TRUE;
949
950 if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0)
951 return TRUE;
952
953 return FALSE;
954 }
955
956 static BOOL DLL_CALLCONV
957 SupportsExportDepth(int depth) {
958 return (
959 (depth == 1) ||
960 (depth == 4) ||
961 (depth == 8) ||
962 (depth == 16) ||
963 (depth == 24) ||
964 (depth == 32)
965 );
966 }
967
968 static BOOL DLL_CALLCONV
969 SupportsExportType(FREE_IMAGE_TYPE type) {
970 return (type == FIT_BITMAP) ? TRUE : FALSE;
971 }
972
973 // ----------------------------------------------------------
974
975 static FIBITMAP * DLL_CALLCONV
976 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
977 if (handle != NULL) {
978 BITMAPFILEHEADER bitmapfileheader;
979 DWORD type = 0;
980 BYTE magic[2];
981
982 // we use this offset value to make seemingly absolute seeks relative in the file
983
984 long offset_in_file = io->tell_proc(handle);
985
986 // read the magic
987
988 io->read_proc(&magic, sizeof(magic), 1, handle);
989
990 // compare the magic with the number we know
991
992 // somebody put a comment here explaining the purpose of this loop
993 while (memcmp(&magic, "BA", 2) == 0) {
994 io->read_proc(&bitmapfileheader.bfSize, sizeof(DWORD), 1, handle);
995 io->read_proc(&bitmapfileheader.bfReserved1, sizeof(WORD), 1, handle);
996 io->read_proc(&bitmapfileheader.bfReserved2, sizeof(WORD), 1, handle);
997 io->read_proc(&bitmapfileheader.bfOffBits, sizeof(DWORD), 1, handle);
998 io->read_proc(&magic, sizeof(magic), 1, handle);
999 }
1000
1001 // read the fileheader
1002
1003 io->seek_proc(handle, 0 - sizeof(magic), SEEK_CUR);
1004 io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle);
1005 #ifdef FREEIMAGE_BIGENDIAN
1006 SwapFileHeader(&bitmapfileheader);
1007 #endif
1008
1009 // read the first byte of the infoheader
1010
1011 io->read_proc(&type, sizeof(DWORD), 1, handle);
1012 io->seek_proc(handle, 0 - sizeof(DWORD), SEEK_CUR);
1013 #ifdef FREEIMAGE_BIGENDIAN
1014 SwapLong(&type);
1015 #endif
1016
1017 // call the appropriate load function for the found bitmap type
1018
1019 if (type == 40)
1020 return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
1021
1022 if (type == 12)
1023 return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
1024
1025 if (type <= 64)
1026 return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
1027
1028 FreeImage_OutputMessageProc(s_format_id, "unknown bmp subtype with id %d", type);
1029 }
1030
1031 return NULL;
1032 }
1033
1034 // ----------------------------------------------------------
1035
1036 /**
1037 Encode a 8-bit source buffer into a 8-bit target buffer using a RLE compression algorithm.
1038 The size of the target buffer must be equal to the size of the source buffer.
1039 On return, the function will return the real size of the target buffer, which should be less that or equal to the source buffer size.
1040 @param target 8-bit Target buffer
1041 @param source 8-bit Source buffer
1042 @param size Source/Target input buffer size
1043 @return Returns the target buffer size
1044 */
1045 static int
1046 RLEEncodeLine(BYTE *target, BYTE *source, int size) {
1047 BYTE buffer[256];
1048 int buffer_size = 0;
1049 int target_pos = 0;
1050
1051 for (int i = 0; i < size; ++i) {
1052 if ((i < size - 1) && (source[i] == source[i + 1])) {
1053 // find a solid block of same bytes
1054
1055 int j = i + 1;
1056 int jmax = 254 + i;
1057
1058 while ((j < size - 1) && (j < jmax) && (source[j] == source[j + 1]))
1059 ++j;
1060
1061 // if the block is larger than 3 bytes, use it
1062 // else put the data into the larger pool
1063
1064 if (((j - i) + 1) > 3) {
1065 // don't forget to write what we already have in the buffer
1066
1067 switch(buffer_size) {
1068 case 0 :
1069 break;
1070
1071 case RLE_DELTA :
1072 target[target_pos++] = 1;
1073 target[target_pos++] = buffer[0];
1074 target[target_pos++] = 1;
1075 target[target_pos++] = buffer[1];
1076 break;
1077
1078 case RLE_ENDOFBITMAP :
1079 target[target_pos++] = (BYTE)buffer_size;
1080 target[target_pos++] = buffer[0];
1081 break;
1082
1083 default :
1084 target[target_pos++] = RLE_COMMAND;
1085 target[target_pos++] = (BYTE)buffer_size;
1086 memcpy(target + target_pos, buffer, buffer_size);
1087
1088 // prepare for next run
1089
1090 target_pos += buffer_size;
1091
1092 if ((buffer_size & 1) == 1)
1093 target_pos++;
1094
1095 break;
1096 }
1097
1098 // write the continuous data
1099
1100 target[target_pos++] = (BYTE)((j - i) + 1);
1101 target[target_pos++] = source[i];
1102
1103 buffer_size = 0;
1104 } else {
1105 for (int k = 0; k < (j - i) + 1; ++k) {
1106 buffer[buffer_size++] = source[i + k];
1107
1108 if (buffer_size == 254) {
1109 // write what we have
1110
1111 target[target_pos++] = RLE_COMMAND;
1112 target[target_pos++] = (BYTE)buffer_size;
1113 memcpy(target + target_pos, buffer, buffer_size);
1114
1115 // prepare for next run
1116
1117 target_pos += buffer_size;
1118 buffer_size = 0;
1119 }
1120 }
1121 }
1122
1123 i = j;
1124 } else {
1125 buffer[buffer_size++] = source[i];
1126 }
1127
1128 // write the buffer if it's full
1129
1130 if (buffer_size == 254) {
1131 target[target_pos++] = RLE_COMMAND;
1132 target[target_pos++] = (BYTE)buffer_size;
1133 memcpy(target + target_pos, buffer, buffer_size);
1134
1135 // prepare for next run
1136
1137 target_pos += buffer_size;
1138 buffer_size = 0;
1139 }
1140 }
1141
1142 // write the last bytes
1143
1144 switch(buffer_size) {
1145 case 0 :
1146 break;
1147
1148 case RLE_DELTA :
1149 target[target_pos++] = 1;
1150 target[target_pos++] = buffer[0];
1151 target[target_pos++] = 1;
1152 target[target_pos++] = buffer[1];
1153 break;
1154
1155 case RLE_ENDOFBITMAP :
1156 target[target_pos++] = (BYTE)buffer_size;
1157 target[target_pos++] = buffer[0];
1158 break;
1159
1160 default :
1161 target[target_pos++] = RLE_COMMAND;
1162 target[target_pos++] = (BYTE)buffer_size;
1163 memcpy(target + target_pos, buffer, buffer_size);
1164
1165 // prepare for next run
1166
1167 target_pos += buffer_size;
1168
1169 if ((buffer_size & 1) == 1)
1170 target_pos++;
1171
1172 break;
1173 }
1174
1175 // write the END_OF_LINE marker
1176
1177 target[target_pos++] = RLE_COMMAND;
1178 target[target_pos++] = RLE_ENDOFLINE;
1179
1180 // return the written size
1181
1182 return target_pos;
1183 }
1184
1185 static BOOL DLL_CALLCONV
1186 Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
1187 if ((dib != NULL) && (handle != NULL)) {
1188 // write the file header
1189
1190 BITMAPFILEHEADER bitmapfileheader;
1191 bitmapfileheader.bfType = 0x4D42;
1192 bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD);
1193 bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib);
1194 bitmapfileheader.bfReserved1 = 0;
1195 bitmapfileheader.bfReserved2 = 0;
1196
1197 // take care of the bit fields data of any
1198
1199 bool bit_fields = (FreeImage_GetBPP(dib) == 16);
1200
1201 if (bit_fields) {
1202 bitmapfileheader.bfSize += 3 * sizeof(DWORD);
1203 bitmapfileheader.bfOffBits += 3 * sizeof(DWORD);
1204 }
1205
1206 #ifdef FREEIMAGE_BIGENDIAN
1207 SwapFileHeader(&bitmapfileheader);
1208 #endif
1209 if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1)
1210 return FALSE;
1211
1212 // update the bitmap info header
1213
1214 BITMAPINFOHEADER bih;
1215 memcpy(&bih, FreeImage_GetInfoHeader(dib), sizeof(BITMAPINFOHEADER));
1216
1217 if (bit_fields)
1218 bih.biCompression = BI_BITFIELDS;
1219 else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE))
1220 bih.biCompression = BI_RLE8;
1221 else
1222 bih.biCompression = BI_RGB;
1223
1224 // write the bitmap info header
1225
1226 #ifdef FREEIMAGE_BIGENDIAN
1227 SwapInfoHeader(&bih);
1228 #endif
1229 if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1)
1230 return FALSE;
1231
1232 // write the bit fields when we are dealing with a 16 bit BMP
1233
1234 if (bit_fields) {
1235 DWORD d;
1236
1237 d = FreeImage_GetRedMask(dib);
1238
1239 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
1240 return FALSE;
1241
1242 d = FreeImage_GetGreenMask(dib);
1243
1244 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
1245 return FALSE;
1246
1247 d = FreeImage_GetBlueMask(dib);
1248
1249 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
1250 return FALSE;
1251 }
1252
1253 // write the palette
1254
1255 if (FreeImage_GetPalette(dib) != NULL) {
1256 RGBQUAD *pal = FreeImage_GetPalette(dib);
1257 FILE_BGRA bgra;
1258 for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) {
1259 bgra.b = pal[i].rgbBlue;
1260 bgra.g = pal[i].rgbGreen;
1261 bgra.r = pal[i].rgbRed;
1262 bgra.a = pal[i].rgbReserved;
1263 if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
1264 return FALSE;
1265 }
1266 }
1267
1268 // write the bitmap data... if RLE compression is enable, use it
1269
1270 unsigned bpp = FreeImage_GetBPP(dib);
1271 if ((bpp == 8) && (flags & BMP_SAVE_RLE)) {
1272 BYTE *buffer = new BYTE[FreeImage_GetPitch(dib) * 2];
1273
1274 for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) {
1275 int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib));
1276
1277 if (io->write_proc(buffer, size, 1, handle) != 1) {
1278 delete [] buffer;
1279 return FALSE;
1280 }
1281 }
1282
1283 buffer[0] = RLE_COMMAND;
1284 buffer[1] = RLE_ENDOFBITMAP;
1285
1286 if (io->write_proc(buffer, 2, 1, handle) != 1) {
1287 delete [] buffer;
1288 return FALSE;
1289 }
1290
1291 delete [] buffer;
1292 #ifdef FREEIMAGE_BIGENDIAN
1293 } else if (bpp == 16) {
1294 int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(WORD);
1295 WORD pad = 0;
1296 WORD pixel;
1297 for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
1298 BYTE *line = FreeImage_GetScanLine(dib, y);
1299 for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
1300 pixel = ((WORD *)line)[x];
1301 SwapShort(&pixel);
1302 if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1)
1303 return FALSE;
1304 }
1305 if(padding != 0) {
1306 if(io->write_proc(&pad, padding, 1, handle) != 1) {
1307 return FALSE;
1308 }
1309 }
1310 }
1311 #endif
1312 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
1313 } else if (bpp == 24) {
1314 int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(FILE_BGR);
1315 DWORD pad = 0;
1316 FILE_BGR bgr;
1317 for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
1318 BYTE *line = FreeImage_GetScanLine(dib, y);
1319 for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
1320 RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x;
1321 bgr.b = triple->rgbtBlue;
1322 bgr.g = triple->rgbtGreen;
1323 bgr.r = triple->rgbtRed;
1324 if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1)
1325 return FALSE;
1326 }
1327 if(padding != 0) {
1328 if(io->write_proc(&pad, padding, 1, handle) != 1) {
1329 return FALSE;
1330 }
1331 }
1332 }
1333 } else if (bpp == 32) {
1334 FILE_BGRA bgra;
1335 for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
1336 BYTE *line = FreeImage_GetScanLine(dib, y);
1337 for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
1338 RGBQUAD *quad = ((RGBQUAD *)line)+x;
1339 bgra.b = quad->rgbBlue;
1340 bgra.g = quad->rgbGreen;
1341 bgra.r = quad->rgbRed;
1342 bgra.a = quad->rgbReserved;
1343 if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
1344 return FALSE;
1345 }
1346 }
1347 #endif
1348 } else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) {
1349 return FALSE;
1350 }
1351
1352 return TRUE;
1353 } else {
1354 return FALSE;
1355 }
1356 }
1357
1358 // ==========================================================
1359 // Init
1360 // ==========================================================
1361
1362 void DLL_CALLCONV
1363 InitBMP(Plugin *plugin, int format_id) {
1364 s_format_id = format_id;
1365
1366 plugin->format_proc = Format;
1367 plugin->description_proc = Description;
1368 plugin->extension_proc = Extension;
1369 plugin->regexpr_proc = RegExpr;
1370 plugin->open_proc = NULL;
1371 plugin->close_proc = NULL;
1372 plugin->pagecount_proc = NULL;
1373 plugin->pagecapability_proc = NULL;
1374 plugin->load_proc = Load;
1375 plugin->save_proc = Save;
1376 plugin->validate_proc = Validate;
1377 plugin->mime_proc = MimeType;
1378 plugin->supports_export_bpp_proc = SupportsExportDepth;
1379 plugin->supports_export_type_proc = SupportsExportType;
1380 plugin->supports_icc_profiles_proc = NULL; // not implemented yet;
1381 }

  ViewVC Help
Powered by ViewVC 1.1.26