Coverage Report

Created: 2025-10-10 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}