/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginIFF.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // ========================================================== |
2 | | // Deluxe Paint Loader |
3 | | // |
4 | | // Design and implementation by |
5 | | // - Floris van den Berg (flvdberg@wxs.nl) |
6 | | // - Mark Sibly (marksibly@blitzbasic.com) |
7 | | // - Aaron Shumate (trek@startreker.com) |
8 | | // - Hervé Drolon (drolon@infonie.fr) |
9 | | // |
10 | | // This file is part of FreeImage 3 |
11 | | // |
12 | | // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
13 | | // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
14 | | // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
15 | | // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
16 | | // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
17 | | // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
18 | | // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
19 | | // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
20 | | // THIS DISCLAIMER. |
21 | | // |
22 | | // Use at your own risk! |
23 | | // ========================================================== |
24 | | |
25 | | #include "FreeImage.h" |
26 | | #include "Utilities.h" |
27 | | |
28 | | // ---------------------------------------------------------- |
29 | | // Internal typedefs and structures |
30 | | // ---------------------------------------------------------- |
31 | | |
32 | | #ifdef _WIN32 |
33 | | #pragma pack(push, 1) |
34 | | #else |
35 | | #pragma pack(1) |
36 | | #endif |
37 | | |
38 | | typedef struct { |
39 | | WORD w, h; /* raster width & height in pixels */ |
40 | | WORD x, y; /* position for this image */ |
41 | | BYTE nPlanes; /* # source bitplanes */ |
42 | | BYTE masking; /* masking technique */ |
43 | | BYTE compression; /* compression algorithm */ |
44 | | BYTE pad1; /* UNUSED. For consistency, put 0 here.*/ |
45 | | WORD transparentColor; /* transparent "color number" */ |
46 | | BYTE xAspect, yAspect; /* aspect ratio, a rational number x/y */ |
47 | | WORD pageWidth, pageHeight; /* source "page" size in pixels */ |
48 | | } BMHD; |
49 | | |
50 | | #ifdef _WIN32 |
51 | | #pragma pack(pop) |
52 | | #else |
53 | | #pragma pack() |
54 | | #endif |
55 | | |
56 | | #ifndef FREEIMAGE_BIGENDIAN |
57 | | static void |
58 | 0 | SwapHeader(BMHD *header) { |
59 | 0 | SwapShort(&header->w); |
60 | 0 | SwapShort(&header->h); |
61 | 0 | SwapShort(&header->x); |
62 | 0 | SwapShort(&header->y); |
63 | 0 | SwapShort(&header->transparentColor); |
64 | 0 | SwapShort(&header->pageWidth); |
65 | 0 | SwapShort(&header->pageHeight); |
66 | 0 | } |
67 | | #endif |
68 | | |
69 | | // ---------------------------------------------------------- |
70 | | |
71 | | /* IFF chunk IDs */ |
72 | | |
73 | | typedef DWORD IFF_ID; |
74 | | |
75 | 23.1k | #define MAKE_ID(a, b, c, d) ((IFF_ID)(a)<<24 | (IFF_ID)(b)<<16 | (IFF_ID)(c)<<8 | (IFF_ID)(d)) |
76 | | |
77 | 23.1k | #define ID_FORM MAKE_ID('F', 'O', 'R', 'M') /* EA IFF 85 group identifier */ |
78 | | #define ID_CAT MAKE_ID('C', 'A', 'T', ' ') /* EA IFF 85 group identifier */ |
79 | | #define ID_LIST MAKE_ID('L', 'I', 'S', 'T') /* EA IFF 85 group identifier */ |
80 | | #define ID_PROP MAKE_ID('P', 'R', 'O', 'P') /* EA IFF 85 group identifier */ |
81 | | #define ID_END MAKE_ID('E', 'N', 'D', ' ') /* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3 page 376) */ |
82 | | |
83 | 3 | #define ID_ILBM MAKE_ID('I', 'L', 'B', 'M') /* EA IFF 85 raster bitmap form */ |
84 | | #define ID_DEEP MAKE_ID('D', 'E', 'E', 'P') /* Chunky pixel image files (Used in TV Paint) */ |
85 | | #define ID_RGB8 MAKE_ID('R', 'G', 'B', '8') /* RGB image forms, Turbo Silver (Impulse) */ |
86 | | #define ID_RGBN MAKE_ID('R', 'G', 'B', 'N') /* RGB image forms, Turbo Silver (Impulse) */ |
87 | 3 | #define ID_PBM MAKE_ID('P', 'B', 'M', ' ') /* 256-color chunky format (DPaint 2 ?) */ |
88 | | #define ID_ACBM MAKE_ID('A', 'C', 'B', 'M') /* Amiga Contiguous Bitmap (AmigaBasic) */ |
89 | | /* generic */ |
90 | | #define ID_FVER MAKE_ID('F', 'V', 'E', 'R') /* AmigaOS version string */ |
91 | | #define ID_JUNK MAKE_ID('J', 'U', 'N', 'K') /* always ignore this chunk */ |
92 | | #define ID_ANNO MAKE_ID('A', 'N', 'N', 'O') /* EA IFF 85 Generic Annotation chunk */ |
93 | | #define ID_AUTH MAKE_ID('A', 'U', 'T', 'H') /* EA IFF 85 Generic Author chunk */ |
94 | | #define ID_CHRS MAKE_ID('C', 'H', 'R', 'S') /* EA IFF 85 Generic character string chunk */ |
95 | | #define ID_NAME MAKE_ID('N', 'A', 'M', 'E') /* EA IFF 85 Generic Name of art, music, etc. chunk */ |
96 | | #define ID_TEXT MAKE_ID('T', 'E', 'X', 'T') /* EA IFF 85 Generic unformatted ASCII text chunk */ |
97 | | #define ID_copy MAKE_ID('(', 'c', ')', ' ') /* EA IFF 85 Generic Copyright text chunk */ |
98 | | /* ILBM chunks */ |
99 | 0 | #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* ILBM BitmapHeader */ |
100 | 0 | #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* ILBM 8bit RGB colormap */ |
101 | | #define ID_GRAB MAKE_ID('G', 'R', 'A', 'B') /* ILBM "hotspot" coordiantes */ |
102 | | #define ID_DEST MAKE_ID('D', 'E', 'S', 'T') /* ILBM destination image info */ |
103 | | #define ID_SPRT MAKE_ID('S', 'P', 'R', 'T') /* ILBM sprite identifier */ |
104 | | #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* Amiga viewportmodes */ |
105 | 0 | #define ID_BODY MAKE_ID('B', 'O', 'D', 'Y') /* ILBM image data */ |
106 | | #define ID_CRNG MAKE_ID('C', 'R', 'N', 'G') /* color cycling */ |
107 | | #define ID_CCRT MAKE_ID('C', 'C', 'R', 'T') /* color cycling */ |
108 | | #define ID_CLUT MAKE_ID('C', 'L', 'U', 'T') /* Color Lookup Table chunk */ |
109 | | #define ID_DPI MAKE_ID('D', 'P', 'I', ' ') /* Dots per inch chunk */ |
110 | | #define ID_DPPV MAKE_ID('D', 'P', 'P', 'V') /* DPaint perspective chunk (EA) */ |
111 | | #define ID_DRNG MAKE_ID('D', 'R', 'N', 'G') /* DPaint IV enhanced color cycle chunk (EA) */ |
112 | | #define ID_EPSF MAKE_ID('E', 'P', 'S', 'F') /* Encapsulated Postscript chunk */ |
113 | | #define ID_CMYK MAKE_ID('C', 'M', 'Y', 'K') /* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */ |
114 | | #define ID_CNAM MAKE_ID('C', 'N', 'A', 'M') /* Color naming chunk (Soft-Logik) */ |
115 | | #define ID_PCHG MAKE_ID('P', 'C', 'H', 'G') /* Line by line palette control information (Sebastiano Vigna) */ |
116 | | #define ID_PRVW MAKE_ID('P', 'R', 'V', 'W') /* A mini duplicate ILBM used for preview (Gary Bonham) */ |
117 | | #define ID_XBMI MAKE_ID('X', 'B', 'M', 'I') /* eXtended BitMap Information (Soft-Logik) */ |
118 | | #define ID_CTBL MAKE_ID('C', 'T', 'B', 'L') /* Newtek Dynamic Ham color chunk */ |
119 | | #define ID_DYCP MAKE_ID('D', 'Y', 'C', 'P') /* Newtek Dynamic Ham chunk */ |
120 | | #define ID_SHAM MAKE_ID('S', 'H', 'A', 'M') /* Sliced HAM color chunk */ |
121 | | #define ID_ABIT MAKE_ID('A', 'B', 'I', 'T') /* ACBM body chunk */ |
122 | | #define ID_DCOL MAKE_ID('D', 'C', 'O', 'L') /* unofficial direct color */ |
123 | | |
124 | | // ========================================================== |
125 | | // Plugin Interface |
126 | | // ========================================================== |
127 | | |
128 | | static int s_format_id; |
129 | | |
130 | | // ========================================================== |
131 | | // Plugin Implementation |
132 | | // ========================================================== |
133 | | |
134 | | static const char * DLL_CALLCONV |
135 | 2 | Format() { |
136 | 2 | return "IFF"; |
137 | 2 | } |
138 | | |
139 | | static const char * DLL_CALLCONV |
140 | 0 | Description() { |
141 | 0 | return "IFF Interleaved Bitmap"; |
142 | 0 | } |
143 | | |
144 | | static const char * DLL_CALLCONV |
145 | 0 | Extension() { |
146 | 0 | return "iff,lbm"; |
147 | 0 | } |
148 | | |
149 | | static const char * DLL_CALLCONV |
150 | 0 | RegExpr() { |
151 | 0 | return NULL; |
152 | 0 | } |
153 | | |
154 | | static const char * DLL_CALLCONV |
155 | 0 | MimeType() { |
156 | 0 | return "image/x-iff"; |
157 | 0 | } |
158 | | |
159 | | static BOOL DLL_CALLCONV |
160 | 23.1k | Validate(FreeImageIO *io, fi_handle handle) { |
161 | 23.1k | DWORD type = 0; |
162 | | |
163 | | // read chunk type |
164 | 23.1k | io->read_proc(&type, 4, 1, handle); |
165 | 23.1k | #ifndef FREEIMAGE_BIGENDIAN |
166 | 23.1k | SwapLong(&type); |
167 | 23.1k | #endif |
168 | | |
169 | 23.1k | if(type != ID_FORM) |
170 | 23.1k | return FALSE; |
171 | | |
172 | | // skip 4 bytes |
173 | 3 | io->read_proc(&type, 4, 1, handle); |
174 | | |
175 | | // read chunk type |
176 | 3 | io->read_proc(&type, 4, 1, handle); |
177 | 3 | #ifndef FREEIMAGE_BIGENDIAN |
178 | 3 | SwapLong(&type); |
179 | 3 | #endif |
180 | | |
181 | | // File format : ID_PBM = Packed Bitmap, ID_ILBM = Interleaved Bitmap |
182 | 3 | return (type == ID_ILBM) || (type == ID_PBM); |
183 | 23.1k | } |
184 | | |
185 | | |
186 | | static BOOL DLL_CALLCONV |
187 | 0 | SupportsExportDepth(int depth) { |
188 | 0 | return FALSE; |
189 | 0 | } |
190 | | |
191 | | static BOOL DLL_CALLCONV |
192 | 0 | SupportsExportType(FREE_IMAGE_TYPE type) { |
193 | 0 | return FALSE; |
194 | 0 | } |
195 | | |
196 | | // ---------------------------------------------------------- |
197 | | |
198 | | static FIBITMAP * DLL_CALLCONV |
199 | 0 | Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
200 | 0 | if (handle != NULL) { |
201 | 0 | FIBITMAP *dib = NULL; |
202 | |
|
203 | 0 | DWORD type, size; |
204 | |
|
205 | 0 | io->read_proc(&type, 4, 1, handle); |
206 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
207 | 0 | SwapLong(&type); |
208 | 0 | #endif |
209 | |
|
210 | 0 | if(type != ID_FORM) |
211 | 0 | return NULL; |
212 | | |
213 | 0 | io->read_proc(&size, 4, 1, handle); |
214 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
215 | 0 | SwapLong(&size); |
216 | 0 | #endif |
217 | |
|
218 | 0 | io->read_proc(&type, 4, 1, handle); |
219 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
220 | 0 | SwapLong(&type); |
221 | 0 | #endif |
222 | |
|
223 | 0 | if((type != ID_ILBM) && (type != ID_PBM)) |
224 | 0 | return NULL; |
225 | | |
226 | 0 | size -= 4; |
227 | |
|
228 | 0 | unsigned width = 0, height = 0, planes = 0, depth = 0, comp = 0; |
229 | |
|
230 | 0 | while (size) { |
231 | 0 | DWORD ch_type,ch_size; |
232 | |
|
233 | 0 | io->read_proc(&ch_type, 4, 1, handle); |
234 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
235 | 0 | SwapLong(&ch_type); |
236 | 0 | #endif |
237 | |
|
238 | 0 | io->read_proc(&ch_size,4,1,handle ); |
239 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
240 | 0 | SwapLong(&ch_size); |
241 | 0 | #endif |
242 | |
|
243 | 0 | unsigned ch_end = io->tell_proc(handle) + ch_size; |
244 | |
|
245 | 0 | if (ch_type == ID_BMHD) { // Bitmap Header |
246 | 0 | if (dib) |
247 | 0 | FreeImage_Unload(dib); |
248 | |
|
249 | 0 | BMHD bmhd; |
250 | |
|
251 | 0 | io->read_proc(&bmhd, sizeof(bmhd), 1, handle); |
252 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
253 | 0 | SwapHeader(&bmhd); |
254 | 0 | #endif |
255 | |
|
256 | 0 | width = bmhd.w; |
257 | 0 | height = bmhd.h; |
258 | 0 | planes = bmhd.nPlanes; |
259 | 0 | comp = bmhd.compression; |
260 | |
|
261 | 0 | if(bmhd.masking & 1) |
262 | 0 | planes++; // there is a mask ( 'stencil' ) |
263 | |
|
264 | 0 | if (planes > 8 && planes != 24) |
265 | 0 | return NULL; |
266 | | |
267 | 0 | depth = planes > 8 ? 24 : 8; |
268 | |
|
269 | 0 | if( depth == 24 ) { |
270 | 0 | dib = FreeImage_Allocate(width, height, depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
271 | 0 | } else { |
272 | 0 | dib = FreeImage_Allocate(width, height, depth); |
273 | 0 | } |
274 | 0 | } else if (ch_type == ID_CMAP) { // Palette (Color Map) |
275 | 0 | if (!dib) |
276 | 0 | return NULL; |
277 | | |
278 | 0 | RGBQUAD *pal = FreeImage_GetPalette(dib); |
279 | 0 | if(pal != NULL) { |
280 | 0 | unsigned palette_entries = MIN((unsigned)ch_size / 3, FreeImage_GetColorsUsed(dib)); |
281 | 0 | for (unsigned k = 0; k < palette_entries; k++) { |
282 | 0 | io->read_proc(&pal[k].rgbRed, 1, 1, handle ); |
283 | 0 | io->read_proc(&pal[k].rgbGreen, 1, 1, handle ); |
284 | 0 | io->read_proc(&pal[k].rgbBlue, 1, 1, handle ); |
285 | 0 | } |
286 | 0 | } |
287 | 0 | } else if (ch_type == ID_BODY) { |
288 | 0 | if (!dib) |
289 | 0 | return NULL; |
290 | | |
291 | 0 | if (type == ID_PBM) { |
292 | | // NON INTERLACED (LBM) |
293 | |
|
294 | 0 | unsigned line = FreeImage_GetLine(dib) + 1 & ~1; |
295 | | |
296 | 0 | for (unsigned i = 0; i < FreeImage_GetHeight(dib); i++) { |
297 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1); |
298 | |
|
299 | 0 | if (comp == 1) { |
300 | | // use RLE compression |
301 | |
|
302 | 0 | DWORD number_of_bytes_written = 0; |
303 | 0 | BYTE rle_count; |
304 | 0 | BYTE byte; |
305 | |
|
306 | 0 | while (number_of_bytes_written < line) { |
307 | 0 | io->read_proc(&rle_count, 1, 1, handle); |
308 | |
|
309 | 0 | if (rle_count < 128) { |
310 | 0 | for (int k = 0; k < rle_count + 1; k++) { |
311 | 0 | io->read_proc(&byte, 1, 1, handle); |
312 | |
|
313 | 0 | bits[number_of_bytes_written++] += byte; |
314 | 0 | } |
315 | 0 | } else if (rle_count > 128) { |
316 | 0 | io->read_proc(&byte, 1, 1, handle); |
317 | |
|
318 | 0 | for (int k = 0; k < 257 - rle_count; k++) { |
319 | 0 | bits[number_of_bytes_written++] += byte; |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } else { |
324 | | // don't use compression |
325 | |
|
326 | 0 | io->read_proc(bits, line, 1, handle); |
327 | 0 | } |
328 | 0 | } |
329 | |
|
330 | 0 | return dib; |
331 | 0 | } else { |
332 | | // INTERLACED (ILBM) |
333 | |
|
334 | 0 | unsigned pixel_size = depth/8; |
335 | 0 | unsigned n_width=(width+15)&~15; |
336 | 0 | unsigned plane_size = n_width/8; |
337 | 0 | unsigned src_size = plane_size * planes; |
338 | 0 | BYTE *src = (BYTE*)malloc(src_size); |
339 | 0 | BYTE *dest = FreeImage_GetBits(dib); |
340 | |
|
341 | 0 | dest += FreeImage_GetPitch(dib) * height; |
342 | |
|
343 | 0 | for (unsigned y = 0; y < height; y++) { |
344 | 0 | dest -= FreeImage_GetPitch(dib); |
345 | | |
346 | | // read all planes in one hit, |
347 | | // 'coz PSP compresses across planes... |
348 | |
|
349 | 0 | if (comp) { |
350 | | // unpacker algorithm |
351 | |
|
352 | 0 | for(unsigned x = 0; x < src_size;) { |
353 | | // read the next source byte into t |
354 | 0 | signed char t = 0; |
355 | 0 | io->read_proc(&t, 1, 1, handle); |
356 | | |
357 | 0 | if (t >= 0) { |
358 | | // t = [0..127] => copy the next t+1 bytes literally |
359 | 0 | unsigned size_to_read = t + 1; |
360 | |
|
361 | 0 | if((size_to_read + x) > src_size) { |
362 | | // sanity check for buffer overruns |
363 | 0 | size_to_read = src_size - x; |
364 | 0 | io->read_proc(src + x, size_to_read, 1, handle); |
365 | 0 | x += (t + 1); |
366 | 0 | } else { |
367 | 0 | io->read_proc(src + x, size_to_read, 1, handle); |
368 | 0 | x += size_to_read; |
369 | 0 | } |
370 | 0 | } else if (t != -128) { |
371 | | // t = [-1..-127] => replicate the next byte -t+1 times |
372 | 0 | BYTE b = 0; |
373 | 0 | io->read_proc(&b, 1, 1, handle); |
374 | 0 | unsigned size_to_copy = (unsigned)(-(int)t + 1); |
375 | |
|
376 | 0 | if((size_to_copy + x) > src_size) { |
377 | | // sanity check for buffer overruns |
378 | 0 | size_to_copy = src_size - x; |
379 | 0 | memset(src + x, b, size_to_copy); |
380 | 0 | x += (unsigned)(-(int)t + 1); |
381 | 0 | } else { |
382 | 0 | memset(src + x, b, size_to_copy); |
383 | 0 | x += size_to_copy; |
384 | 0 | } |
385 | 0 | } |
386 | | // t = -128 => noop |
387 | 0 | } |
388 | 0 | } else { |
389 | 0 | io->read_proc(src, src_size, 1, handle); |
390 | 0 | } |
391 | | |
392 | | // lazy planar->chunky... |
393 | |
|
394 | 0 | for (unsigned x = 0; x < width; x++) { |
395 | 0 | for (unsigned n = 0; n < planes; n++) { |
396 | 0 | BYTE bit = (BYTE)( src[n * plane_size + (x / 8)] >> ((x^7) & 7) ); |
397 | |
|
398 | 0 | dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7); |
399 | 0 | } |
400 | 0 | } |
401 | |
|
402 | 0 | #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR |
403 | 0 | if (depth == 24) { |
404 | 0 | for (unsigned x = 0; x < width; ++x){ |
405 | 0 | INPLACESWAP(dest[x * 3], dest[x * 3 + 2]); |
406 | 0 | } |
407 | 0 | } |
408 | 0 | #endif |
409 | 0 | } |
410 | |
|
411 | 0 | free(src); |
412 | |
|
413 | 0 | return dib; |
414 | 0 | } |
415 | 0 | } |
416 | | |
417 | | // Every odd-length chunk is followed by a 0 pad byte. This pad |
418 | | // byte is not counted in ch_size. |
419 | 0 | if (ch_size & 1) { |
420 | 0 | ch_size++; |
421 | 0 | ch_end++; |
422 | 0 | } |
423 | |
|
424 | 0 | io->seek_proc(handle, ch_end - io->tell_proc(handle), SEEK_CUR); |
425 | |
|
426 | 0 | size -= ch_size + 8; |
427 | 0 | } |
428 | | |
429 | 0 | if (dib) |
430 | 0 | FreeImage_Unload(dib); |
431 | 0 | } |
432 | | |
433 | 0 | return 0; |
434 | 0 | } |
435 | | |
436 | | // ========================================================== |
437 | | // Init |
438 | | // ========================================================== |
439 | | |
440 | | void DLL_CALLCONV |
441 | 2 | InitIFF(Plugin *plugin, int format_id) { |
442 | 2 | s_format_id = format_id; |
443 | | |
444 | 2 | plugin->format_proc = Format; |
445 | 2 | plugin->description_proc = Description; |
446 | 2 | plugin->extension_proc = Extension; |
447 | 2 | plugin->regexpr_proc = RegExpr; |
448 | 2 | plugin->open_proc = NULL; |
449 | 2 | plugin->close_proc = NULL; |
450 | 2 | plugin->pagecount_proc = NULL; |
451 | 2 | plugin->pagecapability_proc = NULL; |
452 | 2 | plugin->load_proc = Load; |
453 | 2 | plugin->save_proc = NULL; |
454 | 2 | plugin->validate_proc = Validate; |
455 | 2 | plugin->mime_proc = MimeType; |
456 | 2 | plugin->supports_export_bpp_proc = SupportsExportDepth; |
457 | 2 | plugin->supports_export_type_proc = SupportsExportType; |
458 | 2 | plugin->supports_icc_profiles_proc = NULL; |
459 | 2 | } |