/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginPNM.cpp
Line | Count | Source |
1 | | // ========================================================== |
2 | | // PNM (PPM, PGM, PBM) Loader and Writer |
3 | | // |
4 | | // Design and implementation by |
5 | | // - Floris van den Berg (flvdberg@wxs.nl) |
6 | | // - Hervé Drolon (drolon@infonie.fr) |
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 | | // Internal functions |
28 | | // ========================================================== |
29 | | |
30 | | /** |
31 | | Get an integer value from the actual position pointed by handle |
32 | | */ |
33 | | static int |
34 | 0 | GetInt(FreeImageIO *io, fi_handle handle) { |
35 | 0 | char c = 0; |
36 | 0 | BOOL bFirstChar; |
37 | | |
38 | | // skip forward to start of next number |
39 | |
|
40 | 0 | if(!io->read_proc(&c, 1, 1, handle)) { |
41 | 0 | throw FI_MSG_ERROR_PARSING; |
42 | 0 | } |
43 | | |
44 | 0 | while (1) { |
45 | | // eat comments |
46 | |
|
47 | 0 | if (c == '#') { |
48 | | // if we're at a comment, read to end of line |
49 | |
|
50 | 0 | bFirstChar = TRUE; |
51 | |
|
52 | 0 | while (1) { |
53 | 0 | if(!io->read_proc(&c, 1, 1, handle)) { |
54 | 0 | throw FI_MSG_ERROR_PARSING; |
55 | 0 | } |
56 | | |
57 | 0 | if (bFirstChar && c == ' ') { |
58 | | // loop off 1 sp after # |
59 | 0 | bFirstChar = FALSE; |
60 | 0 | } else if (c == '\n') { |
61 | 0 | break; |
62 | 0 | } |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | 0 | if (c >= '0' && c <='9') { |
67 | | // we've found what we were looking for |
68 | 0 | break; |
69 | 0 | } |
70 | | |
71 | 0 | if(!io->read_proc(&c, 1, 1, handle)) { |
72 | 0 | throw FI_MSG_ERROR_PARSING; |
73 | 0 | } |
74 | 0 | } |
75 | | |
76 | | // we're at the start of a number, continue until we hit a non-number |
77 | | |
78 | 0 | int i = 0; |
79 | |
|
80 | 0 | while (1) { |
81 | 0 | i = (i * 10) + (c - '0'); |
82 | |
|
83 | 0 | if(!io->read_proc(&c, 1, 1, handle)) { |
84 | 0 | throw FI_MSG_ERROR_PARSING; |
85 | 0 | } |
86 | | |
87 | 0 | if (c < '0' || c > '9') { |
88 | 0 | break; |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | 0 | return i; |
93 | 0 | } |
94 | | |
95 | | /** |
96 | | Read a WORD value taking into account the endianess issue |
97 | | */ |
98 | | static inline WORD |
99 | 0 | ReadWord(FreeImageIO *io, fi_handle handle) { |
100 | 0 | WORD level = 0; |
101 | 0 | io->read_proc(&level, 2, 1, handle); |
102 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
103 | 0 | SwapShort(&level); // PNM uses the big endian convention |
104 | 0 | #endif |
105 | 0 | return level; |
106 | 0 | } |
107 | | |
108 | | /** |
109 | | Write a WORD value taking into account the endianess issue |
110 | | */ |
111 | | static inline void |
112 | 0 | WriteWord(FreeImageIO *io, fi_handle handle, const WORD value) { |
113 | 0 | WORD level = value; |
114 | 0 | #ifndef FREEIMAGE_BIGENDIAN |
115 | 0 | SwapShort(&level); // PNM uses the big endian convention |
116 | 0 | #endif |
117 | 0 | io->write_proc(&level, 2, 1, handle); |
118 | 0 | } |
119 | | |
120 | | |
121 | | // ========================================================== |
122 | | // Plugin Interface |
123 | | // ========================================================== |
124 | | |
125 | | static int s_format_id; |
126 | | |
127 | | // ========================================================== |
128 | | // Plugin Implementation |
129 | | // ========================================================== |
130 | | |
131 | | static const char * DLL_CALLCONV |
132 | 0 | Format() { |
133 | 0 | return "PNM"; |
134 | 0 | } |
135 | | |
136 | | static const char * DLL_CALLCONV |
137 | 0 | Description() { |
138 | 0 | return "Portable Network Media"; |
139 | 0 | } |
140 | | |
141 | | static const char * DLL_CALLCONV |
142 | 0 | Extension() { |
143 | 0 | return "pbm,pgm,ppm"; |
144 | 0 | } |
145 | | |
146 | | static const char * DLL_CALLCONV |
147 | 0 | RegExpr() { |
148 | 0 | return NULL; |
149 | 0 | } |
150 | | |
151 | | static const char * DLL_CALLCONV |
152 | 0 | MimeType() { |
153 | 0 | return "image/freeimage-pnm"; |
154 | 0 | } |
155 | | |
156 | | static BOOL DLL_CALLCONV |
157 | 138k | Validate(FreeImageIO *io, fi_handle handle) { |
158 | 138k | BYTE pbm_id1[] = { 0x50, 0x31 }; |
159 | 138k | BYTE pbm_id2[] = { 0x50, 0x34 }; |
160 | 138k | BYTE pgm_id1[] = { 0x50, 0x32 }; |
161 | 138k | BYTE pgm_id2[] = { 0x50, 0x35 }; |
162 | 138k | BYTE ppm_id1[] = { 0x50, 0x33 }; |
163 | 138k | BYTE ppm_id2[] = { 0x50, 0x36 }; |
164 | 138k | BYTE signature[2] = { 0, 0 }; |
165 | | |
166 | 138k | io->read_proc(signature, 1, sizeof(pbm_id1), handle); |
167 | | |
168 | 138k | if (memcmp(pbm_id1, signature, sizeof(pbm_id1)) == 0) |
169 | 0 | return TRUE; |
170 | | |
171 | 138k | if (memcmp(pbm_id2, signature, sizeof(pbm_id2)) == 0) |
172 | 0 | return TRUE; |
173 | | |
174 | 138k | if (memcmp(pgm_id1, signature, sizeof(pgm_id1)) == 0) |
175 | 0 | return TRUE; |
176 | | |
177 | 138k | if (memcmp(pgm_id2, signature, sizeof(pgm_id2)) == 0) |
178 | 0 | return TRUE; |
179 | | |
180 | 138k | if (memcmp(ppm_id1, signature, sizeof(ppm_id1)) == 0) |
181 | 0 | return TRUE; |
182 | | |
183 | 138k | if (memcmp(ppm_id2, signature, sizeof(ppm_id2)) == 0) |
184 | 0 | return TRUE; |
185 | | |
186 | 138k | return FALSE; |
187 | 138k | } |
188 | | |
189 | | static BOOL DLL_CALLCONV |
190 | 0 | SupportsExportDepth(int depth) { |
191 | 0 | return ( |
192 | 0 | (depth == 1) || |
193 | 0 | (depth == 8) || |
194 | 0 | (depth == 24) |
195 | 0 | ); |
196 | 0 | } |
197 | | |
198 | | static BOOL DLL_CALLCONV |
199 | 0 | SupportsExportType(FREE_IMAGE_TYPE type) { |
200 | 0 | return ( |
201 | 0 | (type == FIT_BITMAP) || |
202 | 0 | (type == FIT_UINT16) || |
203 | 0 | (type == FIT_RGB16) |
204 | 0 | ); |
205 | 0 | } |
206 | | |
207 | | static BOOL DLL_CALLCONV |
208 | 0 | SupportsNoPixels() { |
209 | 0 | return TRUE; |
210 | 0 | } |
211 | | |
212 | | // ---------------------------------------------------------- |
213 | | |
214 | | static FIBITMAP * DLL_CALLCONV |
215 | 0 | Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
216 | 0 | char id_one = 0, id_two = 0; |
217 | 0 | int x, y; |
218 | 0 | FIBITMAP *dib = NULL; |
219 | 0 | RGBQUAD *pal; // pointer to dib palette |
220 | 0 | int i; |
221 | |
|
222 | 0 | if (!handle) { |
223 | 0 | return NULL; |
224 | 0 | } |
225 | | |
226 | 0 | BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; |
227 | |
|
228 | 0 | try { |
229 | 0 | FREE_IMAGE_TYPE image_type = FIT_BITMAP; // standard image: 1-, 8-, 24-bit |
230 | | |
231 | | // Read the first two bytes of the file to determine the file format |
232 | | // "P1" = ascii bitmap, "P2" = ascii greymap, "P3" = ascii pixmap, |
233 | | // "P4" = raw bitmap, "P5" = raw greymap, "P6" = raw pixmap |
234 | |
|
235 | 0 | io->read_proc(&id_one, 1, 1, handle); |
236 | 0 | io->read_proc(&id_two, 1, 1, handle); |
237 | |
|
238 | 0 | if ((id_one != 'P') || (id_two < '1') || (id_two > '6')) { |
239 | | // signature error |
240 | 0 | throw FI_MSG_ERROR_MAGIC_NUMBER; |
241 | 0 | } |
242 | | |
243 | | // Read the header information: width, height and the 'max' value if any |
244 | | |
245 | 0 | const int width = GetInt(io, handle); |
246 | 0 | const int height = GetInt(io, handle); |
247 | 0 | int maxval = 1; |
248 | |
|
249 | 0 | if (width < 0 || height < 0) { |
250 | 0 | throw FI_MSG_ERROR_PARSING; |
251 | 0 | } |
252 | | |
253 | 0 | if((id_two == '2') || (id_two == '5') || (id_two == '3') || (id_two == '6')) { |
254 | 0 | maxval = GetInt(io, handle); |
255 | 0 | if((maxval <= 0) || (maxval > 65535)) { |
256 | 0 | FreeImage_OutputMessageProc(s_format_id, "Invalid max value : %d", maxval); |
257 | 0 | throw (const char*)NULL; |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | | // Create a new DIB |
262 | | |
263 | 0 | switch (id_two) { |
264 | 0 | case '1': |
265 | 0 | case '4': |
266 | | // 1-bit |
267 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, 1); |
268 | 0 | break; |
269 | | |
270 | 0 | case '2': |
271 | 0 | case '5': |
272 | 0 | if(maxval > 255) { |
273 | | // 16-bit greyscale |
274 | 0 | image_type = FIT_UINT16; |
275 | 0 | dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height); |
276 | 0 | } else { |
277 | | // 8-bit greyscale |
278 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, 8); |
279 | 0 | } |
280 | 0 | break; |
281 | | |
282 | 0 | case '3': |
283 | 0 | case '6': |
284 | 0 | if(maxval > 255) { |
285 | | // 48-bit RGB |
286 | 0 | image_type = FIT_RGB16; |
287 | 0 | dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height); |
288 | 0 | } else { |
289 | | // 24-bit RGB |
290 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
291 | 0 | } |
292 | 0 | break; |
293 | 0 | } |
294 | | |
295 | 0 | if (dib == NULL) { |
296 | 0 | throw FI_MSG_ERROR_DIB_MEMORY; |
297 | 0 | } |
298 | | |
299 | | // Build a greyscale palette if needed |
300 | | |
301 | 0 | if(image_type == FIT_BITMAP) { |
302 | 0 | switch(id_two) { |
303 | 0 | case '1': |
304 | 0 | case '4': |
305 | 0 | pal = FreeImage_GetPalette(dib); |
306 | 0 | pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; |
307 | 0 | pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; |
308 | 0 | break; |
309 | | |
310 | 0 | case '2': |
311 | 0 | case '5': |
312 | 0 | pal = FreeImage_GetPalette(dib); |
313 | 0 | for (i = 0; i < 256; i++) { |
314 | 0 | pal[i].rgbRed = |
315 | 0 | pal[i].rgbGreen = |
316 | 0 | pal[i].rgbBlue = (BYTE)i; |
317 | 0 | } |
318 | 0 | break; |
319 | | |
320 | 0 | default: |
321 | 0 | break; |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | 0 | if(header_only) { |
326 | | // header only mode |
327 | 0 | return dib; |
328 | 0 | } |
329 | | |
330 | | // Read the image... |
331 | | |
332 | 0 | switch(id_two) { |
333 | 0 | case '1': |
334 | 0 | case '4': |
335 | | // write the bitmap data |
336 | |
|
337 | 0 | if (id_two == '1') { // ASCII bitmap |
338 | 0 | for (y = 0; y < height; y++) { |
339 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
340 | |
|
341 | 0 | for (x = 0; x < width; x++) { |
342 | 0 | if (GetInt(io, handle) == 0) |
343 | 0 | bits[x >> 3] |= (0x80 >> (x & 0x7)); |
344 | 0 | else |
345 | 0 | bits[x >> 3] &= (0xFF7F >> (x & 0x7)); |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } else { // Raw bitmap |
349 | 0 | int line = CalculateLine(width, 1); |
350 | |
|
351 | 0 | for (y = 0; y < height; y++) { |
352 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
353 | |
|
354 | 0 | for (x = 0; x < line; x++) { |
355 | 0 | io->read_proc(&bits[x], 1, 1, handle); |
356 | |
|
357 | 0 | bits[x] = ~bits[x]; |
358 | 0 | } |
359 | 0 | } |
360 | 0 | } |
361 | |
|
362 | 0 | return dib; |
363 | | |
364 | 0 | case '2': |
365 | 0 | case '5': |
366 | 0 | if(image_type == FIT_BITMAP) { |
367 | | // write the bitmap data |
368 | |
|
369 | 0 | if(id_two == '2') { // ASCII greymap |
370 | 0 | int level = 0; |
371 | |
|
372 | 0 | for (y = 0; y < height; y++) { |
373 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
374 | |
|
375 | 0 | for (x = 0; x < width; x++) { |
376 | 0 | level = GetInt(io, handle); |
377 | 0 | bits[x] = (BYTE)((255 * level) / maxval); |
378 | 0 | } |
379 | 0 | } |
380 | 0 | } else { // Raw greymap |
381 | 0 | BYTE level = 0; |
382 | |
|
383 | 0 | for (y = 0; y < height; y++) { |
384 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
385 | |
|
386 | 0 | for (x = 0; x < width; x++) { |
387 | 0 | io->read_proc(&level, 1, 1, handle); |
388 | 0 | bits[x] = (BYTE)((255 * (int)level) / maxval); |
389 | 0 | } |
390 | 0 | } |
391 | 0 | } |
392 | 0 | } |
393 | 0 | else if(image_type == FIT_UINT16) { |
394 | | // write the bitmap data |
395 | |
|
396 | 0 | if(id_two == '2') { // ASCII greymap |
397 | 0 | int level = 0; |
398 | |
|
399 | 0 | for (y = 0; y < height; y++) { |
400 | 0 | WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); |
401 | |
|
402 | 0 | for (x = 0; x < width; x++) { |
403 | 0 | level = GetInt(io, handle); |
404 | 0 | bits[x] = (WORD)((65535 * (double)level) / maxval); |
405 | 0 | } |
406 | 0 | } |
407 | 0 | } else { // Raw greymap |
408 | 0 | WORD level = 0; |
409 | |
|
410 | 0 | for (y = 0; y < height; y++) { |
411 | 0 | WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); |
412 | |
|
413 | 0 | for (x = 0; x < width; x++) { |
414 | 0 | level = ReadWord(io, handle); |
415 | 0 | bits[x] = (WORD)((65535 * (double)level) / maxval); |
416 | 0 | } |
417 | 0 | } |
418 | 0 | } |
419 | 0 | } |
420 | |
|
421 | 0 | return dib; |
422 | | |
423 | 0 | case '3': |
424 | 0 | case '6': |
425 | 0 | if(image_type == FIT_BITMAP) { |
426 | | // write the bitmap data |
427 | |
|
428 | 0 | if (id_two == '3') { // ASCII pixmap |
429 | 0 | int level = 0; |
430 | |
|
431 | 0 | for (y = 0; y < height; y++) { |
432 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
433 | |
|
434 | 0 | for (x = 0; x < width; x++) { |
435 | 0 | level = GetInt(io, handle); |
436 | 0 | bits[FI_RGBA_RED] = (BYTE)((255 * level) / maxval); // R |
437 | 0 | level = GetInt(io, handle); |
438 | 0 | bits[FI_RGBA_GREEN] = (BYTE)((255 * level) / maxval); // G |
439 | 0 | level = GetInt(io, handle); |
440 | 0 | bits[FI_RGBA_BLUE] = (BYTE)((255 * level) / maxval); // B |
441 | |
|
442 | 0 | bits += 3; |
443 | 0 | } |
444 | 0 | } |
445 | 0 | } else { // Raw pixmap |
446 | 0 | BYTE level = 0; |
447 | |
|
448 | 0 | for (y = 0; y < height; y++) { |
449 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
450 | |
|
451 | 0 | for (x = 0; x < width; x++) { |
452 | 0 | io->read_proc(&level, 1, 1, handle); |
453 | 0 | bits[FI_RGBA_RED] = (BYTE)((255 * (int)level) / maxval); // R |
454 | |
|
455 | 0 | io->read_proc(&level, 1, 1, handle); |
456 | 0 | bits[FI_RGBA_GREEN] = (BYTE)((255 * (int)level) / maxval); // G |
457 | |
|
458 | 0 | io->read_proc(&level, 1, 1, handle); |
459 | 0 | bits[FI_RGBA_BLUE] = (BYTE)((255 * (int)level) / maxval); // B |
460 | |
|
461 | 0 | bits += 3; |
462 | 0 | } |
463 | 0 | } |
464 | 0 | } |
465 | 0 | } |
466 | 0 | else if(image_type == FIT_RGB16) { |
467 | | // write the bitmap data |
468 | |
|
469 | 0 | if (id_two == '3') { // ASCII pixmap |
470 | 0 | int level = 0; |
471 | |
|
472 | 0 | for (y = 0; y < height; y++) { |
473 | 0 | FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); |
474 | |
|
475 | 0 | for (x = 0; x < width; x++) { |
476 | 0 | level = GetInt(io, handle); |
477 | 0 | bits[x].red = (WORD)((65535 * (double)level) / maxval); // R |
478 | 0 | level = GetInt(io, handle); |
479 | 0 | bits[x].green = (WORD)((65535 * (double)level) / maxval); // G |
480 | 0 | level = GetInt(io, handle); |
481 | 0 | bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B |
482 | 0 | } |
483 | 0 | } |
484 | 0 | } else { // Raw pixmap |
485 | 0 | WORD level = 0; |
486 | |
|
487 | 0 | for (y = 0; y < height; y++) { |
488 | 0 | FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); |
489 | |
|
490 | 0 | for (x = 0; x < width; x++) { |
491 | 0 | level = ReadWord(io, handle); |
492 | 0 | bits[x].red = (WORD)((65535 * (double)level) / maxval); // R |
493 | 0 | level = ReadWord(io, handle); |
494 | 0 | bits[x].green = (WORD)((65535 * (double)level) / maxval); // G |
495 | 0 | level = ReadWord(io, handle); |
496 | 0 | bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B |
497 | 0 | } |
498 | 0 | } |
499 | 0 | } |
500 | 0 | } |
501 | |
|
502 | 0 | return dib; |
503 | 0 | } |
504 | |
|
505 | 0 | } catch (const char *text) { |
506 | 0 | if(dib) FreeImage_Unload(dib); |
507 | |
|
508 | 0 | if(NULL != text) { |
509 | 0 | switch(id_two) { |
510 | 0 | case '1': |
511 | 0 | case '4': |
512 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
513 | 0 | break; |
514 | | |
515 | 0 | case '2': |
516 | 0 | case '5': |
517 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
518 | 0 | break; |
519 | | |
520 | 0 | case '3': |
521 | 0 | case '6': |
522 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
523 | 0 | break; |
524 | 0 | } |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | 0 | return NULL; |
529 | 0 | } |
530 | | |
531 | | static BOOL DLL_CALLCONV |
532 | 0 | Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { |
533 | | // ---------------------------------------------------------- |
534 | | // PNM Saving |
535 | | // ---------------------------------------------------------- |
536 | | // |
537 | | // Output format : |
538 | | // |
539 | | // Bit depth flags file format |
540 | | // ------------- -------------- ----------- |
541 | | // 1-bit / pixel PNM_SAVE_ASCII PBM (P1) |
542 | | // 1-bit / pixel PNM_SAVE_RAW PBM (P4) |
543 | | // 8-bit / pixel PNM_SAVE_ASCII PGM (P2) |
544 | | // 8-bit / pixel PNM_SAVE_RAW PGM (P5) |
545 | | // 24-bit / pixel PNM_SAVE_ASCII PPM (P3) |
546 | | // 24-bit / pixel PNM_SAVE_RAW PPM (P6) |
547 | | // ---------------------------------------------------------- |
548 | |
|
549 | 0 | int x, y; |
550 | |
|
551 | 0 | char buffer[256]; // temporary buffer whose size should be enough for what we need |
552 | |
|
553 | 0 | if(!dib || !handle) return FALSE; |
554 | | |
555 | 0 | FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
556 | |
|
557 | 0 | int bpp = FreeImage_GetBPP(dib); |
558 | 0 | int width = FreeImage_GetWidth(dib); |
559 | 0 | int height = FreeImage_GetHeight(dib); |
560 | | |
561 | | // Find the appropriate magic number for this file type |
562 | |
|
563 | 0 | int magic = 0; |
564 | 0 | int maxval = 255; |
565 | |
|
566 | 0 | switch(image_type) { |
567 | 0 | case FIT_BITMAP: |
568 | 0 | switch (bpp) { |
569 | 0 | case 1 : |
570 | 0 | magic = 1; // PBM file (B & W) |
571 | 0 | break; |
572 | 0 | case 8 : |
573 | 0 | magic = 2; // PGM file (Greyscale) |
574 | 0 | break; |
575 | | |
576 | 0 | case 24 : |
577 | 0 | magic = 3; // PPM file (RGB) |
578 | 0 | break; |
579 | | |
580 | 0 | default: |
581 | 0 | return FALSE; // Invalid bit depth |
582 | 0 | } |
583 | 0 | break; |
584 | | |
585 | 0 | case FIT_UINT16: |
586 | 0 | magic = 2; // PGM file (Greyscale) |
587 | 0 | maxval = 65535; |
588 | 0 | break; |
589 | | |
590 | 0 | case FIT_RGB16: |
591 | 0 | magic = 3; // PPM file (RGB) |
592 | 0 | maxval = 65535; |
593 | 0 | break; |
594 | | |
595 | 0 | default: |
596 | 0 | return FALSE; |
597 | 0 | } |
598 | | |
599 | | |
600 | 0 | if (flags == PNM_SAVE_RAW) |
601 | 0 | magic += 3; |
602 | | |
603 | | // Write the header info |
604 | |
|
605 | 0 | sprintf(buffer, "P%d\n%d %d\n", magic, width, height); |
606 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
607 | |
|
608 | 0 | if (bpp != 1) { |
609 | 0 | sprintf(buffer, "%d\n", maxval); |
610 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
611 | 0 | } |
612 | | |
613 | | // Write the image data |
614 | | /////////////////////// |
615 | |
|
616 | 0 | if(image_type == FIT_BITMAP) { |
617 | 0 | switch(bpp) { |
618 | 0 | case 24 : // 24-bit RGB, 3 bytes per pixel |
619 | 0 | { |
620 | 0 | if (flags == PNM_SAVE_RAW) { |
621 | 0 | for (y = 0; y < height; y++) { |
622 | | // write the scanline to disc |
623 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
624 | |
|
625 | 0 | for (x = 0; x < width; x++) { |
626 | 0 | io->write_proc(&bits[FI_RGBA_RED], 1, 1, handle); // R |
627 | 0 | io->write_proc(&bits[FI_RGBA_GREEN], 1, 1, handle); // G |
628 | 0 | io->write_proc(&bits[FI_RGBA_BLUE], 1, 1, handle); // B |
629 | |
|
630 | 0 | bits += 3; |
631 | 0 | } |
632 | 0 | } |
633 | 0 | } else { |
634 | 0 | int length = 0; |
635 | |
|
636 | 0 | for (y = 0; y < height; y++) { |
637 | | // write the scanline to disc |
638 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
639 | | |
640 | 0 | for (x = 0; x < width; x++) { |
641 | 0 | sprintf(buffer, "%3d %3d %3d ", bits[FI_RGBA_RED], bits[FI_RGBA_GREEN], bits[FI_RGBA_BLUE]); |
642 | |
|
643 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
644 | |
|
645 | 0 | length += 12; |
646 | |
|
647 | 0 | if(length > 58) { |
648 | | // No line should be longer than 70 characters |
649 | 0 | sprintf(buffer, "\n"); |
650 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
651 | 0 | length = 0; |
652 | 0 | } |
653 | |
|
654 | 0 | bits += 3; |
655 | 0 | } |
656 | 0 | } |
657 | |
|
658 | 0 | } |
659 | 0 | } |
660 | 0 | break; |
661 | | |
662 | 0 | case 8: // 8-bit greyscale |
663 | 0 | { |
664 | 0 | if (flags == PNM_SAVE_RAW) { |
665 | 0 | for (y = 0; y < height; y++) { |
666 | | // write the scanline to disc |
667 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
668 | |
|
669 | 0 | for (x = 0; x < width; x++) { |
670 | 0 | io->write_proc(&bits[x], 1, 1, handle); |
671 | 0 | } |
672 | 0 | } |
673 | 0 | } else { |
674 | 0 | int length = 0; |
675 | |
|
676 | 0 | for (y = 0; y < height; y++) { |
677 | | // write the scanline to disc |
678 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
679 | |
|
680 | 0 | for (x = 0; x < width; x++) { |
681 | 0 | sprintf(buffer, "%3d ", bits[x]); |
682 | |
|
683 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
684 | |
|
685 | 0 | length += 4; |
686 | |
|
687 | 0 | if (length > 66) { |
688 | | // No line should be longer than 70 characters |
689 | 0 | sprintf(buffer, "\n"); |
690 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
691 | 0 | length = 0; |
692 | 0 | } |
693 | 0 | } |
694 | 0 | } |
695 | 0 | } |
696 | 0 | } |
697 | 0 | break; |
698 | | |
699 | 0 | case 1: // 1-bit B & W |
700 | 0 | { |
701 | 0 | int color; |
702 | |
|
703 | 0 | if (flags == PNM_SAVE_RAW) { |
704 | 0 | for(y = 0; y < height; y++) { |
705 | | // write the scanline to disc |
706 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
707 | |
|
708 | 0 | for(x = 0; x < (int)FreeImage_GetLine(dib); x++) |
709 | 0 | io->write_proc(&bits[x], 1, 1, handle); |
710 | 0 | } |
711 | 0 | } else { |
712 | 0 | int length = 0; |
713 | |
|
714 | 0 | for (y = 0; y < height; y++) { |
715 | | // write the scanline to disc |
716 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); |
717 | |
|
718 | 0 | for (x = 0; x < (int)FreeImage_GetLine(dib) * 8; x++) { |
719 | 0 | color = (bits[x>>3] & (0x80 >> (x & 0x07))) != 0; |
720 | |
|
721 | 0 | sprintf(buffer, "%c ", color ? '1':'0'); |
722 | |
|
723 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
724 | |
|
725 | 0 | length += 2; |
726 | |
|
727 | 0 | if (length > 68) { |
728 | | // No line should be longer than 70 characters |
729 | 0 | sprintf(buffer, "\n"); |
730 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
731 | 0 | length = 0; |
732 | 0 | } |
733 | 0 | } |
734 | 0 | } |
735 | 0 | } |
736 | 0 | } |
737 | | |
738 | 0 | break; |
739 | 0 | } |
740 | 0 | } // if(FIT_BITMAP) |
741 | | |
742 | 0 | else if(image_type == FIT_UINT16) { // 16-bit greyscale |
743 | 0 | if (flags == PNM_SAVE_RAW) { |
744 | 0 | for (y = 0; y < height; y++) { |
745 | | // write the scanline to disc |
746 | 0 | WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); |
747 | |
|
748 | 0 | for (x = 0; x < width; x++) { |
749 | 0 | WriteWord(io, handle, bits[x]); |
750 | 0 | } |
751 | 0 | } |
752 | 0 | } else { |
753 | 0 | int length = 0; |
754 | |
|
755 | 0 | for (y = 0; y < height; y++) { |
756 | | // write the scanline to disc |
757 | 0 | WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); |
758 | |
|
759 | 0 | for (x = 0; x < width; x++) { |
760 | 0 | sprintf(buffer, "%5d ", bits[x]); |
761 | |
|
762 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
763 | |
|
764 | 0 | length += 6; |
765 | |
|
766 | 0 | if (length > 64) { |
767 | | // No line should be longer than 70 characters |
768 | 0 | sprintf(buffer, "\n"); |
769 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
770 | 0 | length = 0; |
771 | 0 | } |
772 | 0 | } |
773 | 0 | } |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | 0 | else if(image_type == FIT_RGB16) { // 48-bit RGB |
778 | 0 | if (flags == PNM_SAVE_RAW) { |
779 | 0 | for (y = 0; y < height; y++) { |
780 | | // write the scanline to disc |
781 | 0 | FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); |
782 | |
|
783 | 0 | for (x = 0; x < width; x++) { |
784 | 0 | WriteWord(io, handle, bits[x].red); // R |
785 | 0 | WriteWord(io, handle, bits[x].green); // G |
786 | 0 | WriteWord(io, handle, bits[x].blue); // B |
787 | 0 | } |
788 | 0 | } |
789 | 0 | } else { |
790 | 0 | int length = 0; |
791 | |
|
792 | 0 | for (y = 0; y < height; y++) { |
793 | | // write the scanline to disc |
794 | 0 | FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); |
795 | | |
796 | 0 | for (x = 0; x < width; x++) { |
797 | 0 | sprintf(buffer, "%5d %5d %5d ", bits[x].red, bits[x].green, bits[x].blue); |
798 | |
|
799 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
800 | |
|
801 | 0 | length += 18; |
802 | |
|
803 | 0 | if(length > 52) { |
804 | | // No line should be longer than 70 characters |
805 | 0 | sprintf(buffer, "\n"); |
806 | 0 | io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); |
807 | 0 | length = 0; |
808 | 0 | } |
809 | 0 | } |
810 | 0 | } |
811 | |
|
812 | 0 | } |
813 | 0 | } |
814 | | |
815 | 0 | return TRUE; |
816 | 0 | } |
817 | | |
818 | | // ========================================================== |
819 | | // Init |
820 | | // ========================================================== |
821 | | |
822 | | void DLL_CALLCONV |
823 | 12 | InitPNM(Plugin *plugin, int format_id) { |
824 | 12 | s_format_id = format_id; |
825 | | |
826 | 12 | plugin->format_proc = Format; |
827 | 12 | plugin->description_proc = Description; |
828 | 12 | plugin->extension_proc = Extension; |
829 | 12 | plugin->regexpr_proc = RegExpr; |
830 | 12 | plugin->open_proc = NULL; |
831 | 12 | plugin->close_proc = NULL; |
832 | 12 | plugin->pagecount_proc = NULL; |
833 | 12 | plugin->pagecapability_proc = NULL; |
834 | 12 | plugin->load_proc = Load; |
835 | 12 | plugin->save_proc = Save; |
836 | 12 | plugin->validate_proc = Validate; |
837 | 12 | plugin->mime_proc = MimeType; |
838 | 12 | plugin->supports_export_bpp_proc = SupportsExportDepth; |
839 | 12 | plugin->supports_export_type_proc = SupportsExportType; |
840 | | plugin->supports_icc_profiles_proc = NULL; |
841 | 12 | plugin->supports_no_pixels_proc = SupportsNoPixels; |
842 | 12 | } |