Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginRAS.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// Sun rasterfile Loader
3
//
4
// Design and implementation by 
5
// - Hervé Drolon (drolon@infonie.fr)
6
//
7
// This file is part of FreeImage 3
8
//
9
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17
// THIS DISCLAIMER.
18
//
19
// Use at your own risk!
20
// ==========================================================
21
22
#include "FreeImage.h"
23
#include "Utilities.h"
24
25
// ----------------------------------------------------------
26
//   Constants + headers
27
// ----------------------------------------------------------
28
29
#ifdef _WIN32
30
#pragma pack(push, 1)
31
#else
32
#pragma pack(1)
33
#endif
34
35
typedef struct tagSUNHEADER {
36
  DWORD magic;    // Magic number
37
  DWORD width;    // Image width in pixels
38
  DWORD height;   // Image height in pixels
39
  DWORD depth;    // Depth (1, 8, 24 or 32 bits) of each pixel
40
  DWORD length;   // Image length (in bytes)
41
  DWORD type;     // Format of file (see RT_* below)
42
  DWORD maptype;    // Type of colormap (see RMT_* below)
43
  DWORD maplength;  // Length of colormap (in bytes)
44
} SUNHEADER;
45
46
#ifdef _WIN32
47
#pragma pack(pop)
48
#else
49
#pragma pack()
50
#endif
51
52
// ----------------------------------------------------------
53
54
// Following the header is the colormap, for maplength bytes (unless maplength is zero),
55
// then the image. Each row of the image is rounded to 2 bytes.
56
57
0
#define RAS_MAGIC 0x59A66A95 // Magic number for Sun rasterfiles
58
59
// Sun supported type's
60
61
0
#define RT_OLD      0  // Old format (raw image in 68000 byte order)
62
0
#define RT_STANDARD   1  // Raw image in 68000 byte order
63
0
#define RT_BYTE_ENCODED 2  // Run-length encoding of bytes 
64
0
#define RT_FORMAT_RGB 3  // XRGB or RGB instead of XBGR or BGR
65
0
#define RT_FORMAT_TIFF  4  // TIFF <-> standard rasterfile
66
0
#define RT_FORMAT_IFF 5  // IFF (TAAC format) <-> standard rasterfile
67
68
#define RT_EXPERIMENTAL 0xffff  // Reserved for testing
69
70
// These are the possible colormap types.
71
// if it's in RGB format, the map is made up of three byte arrays
72
// (red, green, then blue) that are each 1/3 of the colormap length.
73
74
0
#define RMT_NONE    0  // maplength is expected to be 0
75
0
#define RMT_EQUAL_RGB 1  // red[maplength/3], green[maplength/3], blue[maplength/3]
76
0
#define RMT_RAW     2  // Raw colormap
77
0
#define RESC      128 // Run-length encoding escape character
78
79
// ----- NOTES -----
80
// Each line of the image is rounded out to a multiple of 16 bits.
81
// This corresponds to the rounding convention used by the memory pixrect
82
// package (/usr/include/pixrect/memvar.h) of the SunWindows system.
83
// The ras_encoding field (always set to 0 by Sun's supported software)
84
// was renamed to ras_length in release 2.0.  As a result, rasterfiles
85
// of type 0 generated by the old software claim to have 0 length; for
86
// compatibility, code reading rasterfiles must be prepared to compute the
87
// TRUE length from the width, height, and depth fields.
88
89
// ==========================================================
90
// Internal functions
91
// ==========================================================
92
93
static void
94
0
ReadData(FreeImageIO *io, fi_handle handle, BYTE *buf, DWORD length, BOOL rle) {
95
  // Read either Run-Length Encoded or normal image data
96
97
0
  static BYTE repchar, remaining= 0;
98
99
0
  if (rle) {
100
    // Run-length encoded read
101
102
0
    while(length--) {
103
0
      if (remaining) {
104
0
        remaining--;
105
0
        *(buf++)= repchar;
106
0
      } else {
107
0
        io->read_proc(&repchar, 1, 1, handle);
108
109
0
        if (repchar == RESC) {
110
0
          io->read_proc(&remaining, 1, 1, handle);
111
112
0
          if (remaining == 0) {
113
0
            *(buf++)= RESC;
114
0
          } else {
115
0
            io->read_proc(&repchar, 1, 1, handle);
116
117
0
            *(buf++)= repchar;
118
0
          }
119
0
        } else {
120
0
          *(buf++)= repchar;
121
0
        }
122
0
      }
123
0
    }
124
0
  } else {
125
    // Normal read
126
  
127
0
    io->read_proc(buf, length, 1, handle);
128
0
  }
129
0
}
130
131
// ==========================================================
132
// Plugin Interface
133
// ==========================================================
134
135
static int s_format_id;
136
137
// ==========================================================
138
// Plugin Implementation
139
// ==========================================================
140
141
static const char * DLL_CALLCONV
142
2
Format() {
143
2
  return "RAS";
144
2
}
145
146
static const char * DLL_CALLCONV
147
0
Description() {
148
0
  return "Sun Raster Image";
149
0
}
150
151
static const char * DLL_CALLCONV
152
0
Extension() {
153
0
  return "ras";
154
0
}
155
156
static const char * DLL_CALLCONV
157
0
RegExpr() {
158
0
  return NULL;
159
0
}
160
161
static const char * DLL_CALLCONV
162
0
MimeType() {
163
0
  return "image/x-cmu-raster";
164
0
}
165
166
static BOOL DLL_CALLCONV
167
29.9k
Validate(FreeImageIO *io, fi_handle handle) {
168
29.9k
  BYTE ras_signature[] = { 0x59, 0xA6, 0x6A, 0x95 };
169
29.9k
  BYTE signature[4] = { 0, 0, 0, 0 };
170
171
29.9k
  io->read_proc(signature, 1, sizeof(ras_signature), handle);
172
173
29.9k
  return (memcmp(ras_signature, signature, sizeof(ras_signature)) == 0);
174
29.9k
}
175
176
static BOOL DLL_CALLCONV
177
0
SupportsExportDepth(int depth) {
178
0
  return FALSE;
179
0
}
180
181
static BOOL DLL_CALLCONV 
182
0
SupportsExportType(FREE_IMAGE_TYPE type) {
183
0
  return FALSE;
184
0
}
185
186
static BOOL DLL_CALLCONV
187
0
SupportsNoPixels() {
188
0
  return TRUE;
189
0
}
190
191
// ----------------------------------------------------------
192
193
static FIBITMAP * DLL_CALLCONV
194
0
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
195
0
  SUNHEADER header; // Sun file header
196
0
  WORD linelength;  // Length of raster line in bytes
197
0
  WORD fill;      // Number of fill bytes per raster line
198
0
  BOOL rle;     // TRUE if RLE file
199
0
  BOOL isRGB;     // TRUE if file type is RT_FORMAT_RGB
200
0
  BYTE fillchar;
201
202
0
  FIBITMAP *dib = NULL;
203
0
  BYTE *bits;     // Pointer to dib data
204
0
  WORD x, y;
205
206
0
  if(!handle) {
207
0
    return NULL;
208
0
  }
209
210
0
  BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
211
212
0
  try {
213
    // Read SUN raster header
214
215
0
    io->read_proc(&header, sizeof(SUNHEADER), 1, handle);
216
217
0
#ifndef FREEIMAGE_BIGENDIAN
218
    // SUN rasterfiles are big endian only
219
220
0
    SwapLong(&header.magic);
221
0
    SwapLong(&header.width);
222
0
    SwapLong(&header.height);
223
0
    SwapLong(&header.depth);
224
0
    SwapLong(&header.length);
225
0
    SwapLong(&header.type);
226
0
    SwapLong(&header.maptype);
227
0
    SwapLong(&header.maplength);
228
0
#endif
229
230
    // Verify SUN identifier
231
232
0
    if (header.magic != RAS_MAGIC) {
233
0
      throw FI_MSG_ERROR_MAGIC_NUMBER;
234
0
    }
235
236
    // Allocate a new DIB
237
238
0
    switch(header.depth) {
239
0
      case 1:
240
0
      case 8:
241
0
        dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth);
242
0
        break;
243
244
0
      case 24:
245
0
        dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
246
0
        break;
247
248
0
      case 32:
249
0
        dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
250
0
        break;
251
0
    }
252
253
0
    if (dib == NULL) {
254
0
      throw FI_MSG_ERROR_DIB_MEMORY;
255
0
    }
256
257
    // Check the file format
258
259
0
    rle = FALSE;
260
0
    isRGB = FALSE;
261
262
0
    switch(header.type) {
263
0
      case RT_OLD:
264
0
      case RT_STANDARD:
265
0
      case RT_FORMAT_TIFF: // I don't even know what these format are...
266
0
      case RT_FORMAT_IFF: //The TIFF and IFF format types indicate that the raster
267
        //file was originally converted from either of these file formats.
268
        //so lets at least try to process them as RT_STANDARD
269
0
        break;
270
271
0
      case RT_BYTE_ENCODED:
272
0
        rle = TRUE;
273
0
        break;
274
275
0
      case RT_FORMAT_RGB:
276
0
        isRGB = TRUE;
277
0
        break;
278
279
0
      default:
280
0
        throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
281
0
    }
282
283
    // set up the colormap if needed
284
285
0
    switch(header.maptype) {
286
0
      case RMT_NONE :
287
0
      {       
288
0
        if (header.depth < 24) {
289
          // Create linear color ramp
290
291
0
          RGBQUAD *pal = FreeImage_GetPalette(dib);
292
293
0
          int numcolors = 1 << header.depth;
294
295
0
          for (int i = 0; i < numcolors; i++) {
296
0
            pal[i].rgbRed = (BYTE)((255 * i) / (numcolors - 1));
297
0
            pal[i].rgbGreen = (BYTE)((255 * i) / (numcolors - 1));
298
0
            pal[i].rgbBlue  = (BYTE)((255 * i) / (numcolors - 1));
299
0
          }
300
0
        }
301
302
0
        break;
303
0
      }
304
305
0
      case RMT_EQUAL_RGB:
306
0
      {
307
0
        BYTE *r, *g, *b;
308
309
        // Read SUN raster colormap
310
311
0
        int numcolors = 1 << header.depth;
312
0
        if((DWORD)(3 * numcolors) > header.maplength) {
313
          // some RAS may have less colors than the full palette
314
0
          numcolors = header.maplength / 3;
315
0
        } else {
316
0
          throw "Invalid palette";
317
0
        }
318
319
0
        r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE));
320
0
        g = r + numcolors;
321
0
        b = g + numcolors;
322
323
0
        RGBQUAD *pal = FreeImage_GetPalette(dib);
324
325
0
        io->read_proc(r, 3 * numcolors, 1, handle);
326
327
0
        for (int i = 0; i < numcolors; i++) {
328
0
          pal[i].rgbRed = r[i];
329
0
          pal[i].rgbGreen = g[i];
330
0
          pal[i].rgbBlue  = b[i];
331
0
        }
332
333
0
        free(r);
334
0
        break;
335
0
      }
336
337
0
      case RMT_RAW:
338
0
      {
339
0
        BYTE *colormap;
340
341
        // Read (skip) SUN raster colormap.
342
343
0
        colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE));
344
345
0
        io->read_proc(colormap, header.maplength, 1, handle);
346
347
0
        free(colormap);
348
0
        break;
349
0
      }
350
0
    }
351
352
0
    if(header_only) {
353
      // header only mode
354
0
      return dib;
355
0
    }
356
357
    // Calculate the line + pitch
358
    // Each row is multiple of 16 bits (2 bytes).
359
360
0
    if (header.depth == 1) {
361
0
      linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0));
362
0
    } else {
363
0
      linelength = (WORD)header.width;
364
0
    }
365
366
0
    fill = (linelength % 2) ? 1 : 0;
367
368
0
    unsigned pitch = FreeImage_GetPitch(dib);
369
370
    // Read the image data
371
    
372
0
    switch(header.depth) {
373
0
      case 1:
374
0
      case 8:
375
0
      {
376
0
        bits = FreeImage_GetBits(dib) + (header.height - 1) * pitch;
377
378
0
        for (y = 0; y < header.height; y++) {
379
0
          ReadData(io, handle, bits, linelength, rle);
380
381
0
          bits -= pitch;
382
383
0
          if (fill) {
384
0
            ReadData(io, handle, &fillchar, fill, rle);
385
0
          }
386
0
        }
387
388
0
        break;
389
0
      }
390
391
0
      case 24:
392
0
      {
393
0
        BYTE *buf, *bp;
394
395
0
        buf = (BYTE*)malloc(header.width * 3);
396
397
0
        for (y = 0; y < header.height; y++) {
398
0
          bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
399
400
0
          ReadData(io, handle, buf, header.width * 3, rle);
401
402
0
          bp = buf;
403
404
0
          if (isRGB) {
405
0
            for (x = 0; x < header.width; x++) {
406
0
              bits[FI_RGBA_RED] = *(bp++);  // red
407
0
              bits[FI_RGBA_GREEN] = *(bp++);  // green
408
0
              bits[FI_RGBA_BLUE] = *(bp++);  // blue
409
410
0
              bits += 3;
411
0
            }
412
0
          } else {
413
0
            for (x = 0; x < header.width; x++) {
414
0
              bits[FI_RGBA_RED] = *(bp + 2);  // red
415
0
              bits[FI_RGBA_GREEN] = *(bp + 1);// green
416
0
              bits[FI_RGBA_BLUE] = *bp;       // blue
417
418
0
              bits += 3; bp += 3;
419
0
            }
420
0
          }
421
422
0
          if (fill) {
423
0
            ReadData(io, handle, &fillchar, fill, rle);
424
0
          }
425
0
        }
426
427
0
        free(buf);
428
0
        break;
429
0
      }
430
431
0
      case 32:
432
0
      {
433
0
        BYTE *buf, *bp;
434
435
0
        buf = (BYTE*)malloc(header.width * 4);
436
437
0
        for (y = 0; y < header.height; y++) {
438
0
          bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
439
440
0
          ReadData(io, handle, buf, header.width * 4, rle);
441
442
0
          bp = buf;
443
444
0
          if (isRGB) {
445
0
            for (x = 0; x < header.width; x++) {
446
0
              bits[FI_RGBA_ALPHA] = *(bp++);  // alpha
447
0
              bits[FI_RGBA_RED] = *(bp++);  // red
448
0
              bits[FI_RGBA_GREEN] = *(bp++);  // green
449
0
              bits[FI_RGBA_BLUE] = *(bp++);  // blue
450
451
0
              bits += 4;
452
0
            }
453
0
          }
454
0
          else {
455
0
            for (x = 0; x < header.width; x++) {
456
0
              bits[FI_RGBA_RED] = *(bp + 3);  // red
457
0
              bits[FI_RGBA_GREEN] = *(bp + 2); // green
458
0
              bits[FI_RGBA_BLUE] = *(bp + 1);  // blue
459
0
              bits[FI_RGBA_ALPHA] = *bp;    // alpha
460
461
0
              bits += 4;
462
0
              bp += 4;
463
0
            }
464
0
          }
465
466
0
          if (fill) {
467
0
            ReadData(io, handle, &fillchar, fill, rle);
468
0
          }
469
0
        }
470
471
0
        free(buf);
472
0
        break;
473
0
      }
474
0
    }
475
    
476
0
    return dib;
477
478
0
  } catch (const char *text) {
479
0
    if(dib) {
480
0
      FreeImage_Unload(dib);
481
0
    }
482
0
    FreeImage_OutputMessageProc(s_format_id, text);
483
0
  }
484
485
0
  return NULL;
486
0
}
487
488
// ==========================================================
489
//   Init
490
// ==========================================================
491
492
void DLL_CALLCONV
493
2
InitRAS(Plugin *plugin, int format_id) {
494
2
  s_format_id = format_id;
495
496
2
  plugin->format_proc = Format;
497
2
  plugin->description_proc = Description;
498
2
  plugin->extension_proc = Extension;
499
2
  plugin->regexpr_proc = RegExpr;
500
2
  plugin->open_proc = NULL;
501
2
  plugin->close_proc = NULL;
502
2
  plugin->pagecount_proc = NULL;
503
2
  plugin->pagecapability_proc = NULL;
504
2
  plugin->load_proc = Load;
505
2
  plugin->save_proc = NULL;
506
2
  plugin->validate_proc = Validate;
507
2
  plugin->mime_proc = MimeType;
508
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
509
2
  plugin->supports_export_type_proc = SupportsExportType;
510
2
  plugin->supports_icc_profiles_proc = NULL;
511
2
  plugin->supports_no_pixels_proc = SupportsNoPixels;
512
2
}