/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginPCX.cpp
Line | Count | Source |
1 | | // ========================================================== |
2 | | // PCX Loader |
3 | | // |
4 | | // Design and implementation by |
5 | | // - Floris van den Berg (flvdberg@wxs.nl) |
6 | | // - Jani Kajala (janik@remedy.fi) |
7 | | // - Markus Loibl (markus.loibl@epost.de) |
8 | | // - Hervé Drolon (drolon@infonie.fr) |
9 | | // - Juergen Riecker (j.riecker@gmx.de) |
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 | 0 | #define PCX_IO_BUF_SIZE 2048 |
34 | | |
35 | | // ---------------------------------------------------------- |
36 | | |
37 | | #ifdef _WIN32 |
38 | | #pragma pack(push, 1) |
39 | | #else |
40 | | #pragma pack(1) |
41 | | #endif |
42 | | |
43 | | /** |
44 | | PCX header |
45 | | */ |
46 | | typedef struct tagPCXHEADER { |
47 | | BYTE manufacturer; // Magic number (0x0A = ZSoft Z) |
48 | | BYTE version; // Version 0 == 2.5 |
49 | | // 2 == 2.8 with palette info |
50 | | // 3 == 2.8 without palette info |
51 | | // 5 == 3.0 with palette info |
52 | | BYTE encoding; // Encoding: 0 = uncompressed, 1 = PCX bIsRLE compressed |
53 | | BYTE bpp; // Bits per pixel per plane (only 1 or 8) |
54 | | WORD window[4]; // left, upper, right,lower pixel coord. |
55 | | WORD hdpi; // Horizontal resolution |
56 | | WORD vdpi; // Vertical resolution |
57 | | BYTE color_map[48]; // Colormap for 16-color images |
58 | | BYTE reserved; |
59 | | BYTE planes; // Number of planes (1, 3 or 4) |
60 | | WORD bytes_per_line; // Bytes per row (always even) |
61 | | WORD palette_info; // Palette information (1 = color or b&w; 2 = gray scale) |
62 | | WORD h_screen_size; |
63 | | WORD v_screen_size; |
64 | | BYTE filler[54]; // Reserved filler |
65 | | } PCXHEADER; |
66 | | |
67 | | #ifdef _WIN32 |
68 | | #pragma pack(pop) |
69 | | #else |
70 | | #pragma pack() |
71 | | #endif |
72 | | |
73 | | // ========================================================== |
74 | | // Internal functions |
75 | | // ========================================================== |
76 | | |
77 | | /** |
78 | | Try to validate a PCX signature. |
79 | | Note that a PCX file cannot be trusted by its signature. |
80 | | We use other information from the PCX header to improve the trust we have with this file. |
81 | | @return Returns TRUE if PCX signature is OK, returns FALSE otherwise |
82 | | */ |
83 | | static BOOL |
84 | 12.2k | pcx_validate(FreeImageIO *io, fi_handle handle) { |
85 | 12.2k | BYTE pcx_signature = 0x0A; |
86 | 12.2k | BYTE signature[4] = { 0, 0, 0, 0 }; |
87 | | |
88 | 12.2k | if(io->read_proc(&signature, 1, 4, handle) != 4) { |
89 | 0 | return FALSE; |
90 | 0 | } |
91 | | // magic number (0x0A = ZSoft Z) |
92 | 12.2k | if(signature[0] == pcx_signature) { |
93 | | // version |
94 | 0 | if(signature[1] <= 5) { |
95 | | // encoding |
96 | 0 | if((signature[2] == 0) || (signature[2] == 1)) { |
97 | | // bits per pixel per plane |
98 | 0 | if((signature[3] == 1) || (signature[3] == 8)) { |
99 | 0 | return TRUE; |
100 | 0 | } |
101 | 0 | } |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 12.2k | return FALSE; |
106 | 12.2k | } |
107 | | |
108 | | /** |
109 | | Read either run-length encoded or normal image data |
110 | | |
111 | | THIS IS HOW RUNTIME LENGTH ENCODING WORKS IN PCX: |
112 | | 1) If the upper 2 bits of a byte are set, the lower 6 bits specify the count for the next byte |
113 | | 2) If the upper 2 bits of the byte are clear, the byte is actual data with a count of 1 |
114 | | |
115 | | Note that a scanline always has an even number of bytes |
116 | | |
117 | | @param io FreeImage IO |
118 | | @param handle FreeImage handle |
119 | | @param buffer |
120 | | @param length |
121 | | @param bIsRLE |
122 | | @param ReadBuf |
123 | | @param ReadPos |
124 | | @return |
125 | | */ |
126 | | static unsigned |
127 | 0 | readLine(FreeImageIO *io, fi_handle handle, BYTE *buffer, unsigned length, BOOL bIsRLE, BYTE * ReadBuf, int * ReadPos) { |
128 | 0 | BYTE count = 0; |
129 | 0 | BYTE value = 0; |
130 | 0 | unsigned written = 0; |
131 | |
|
132 | 0 | if (bIsRLE) { |
133 | | // run-length encoded read |
134 | |
|
135 | 0 | while (length--) { |
136 | 0 | if (count == 0) { |
137 | 0 | if (*ReadPos >= PCX_IO_BUF_SIZE - 1 ) { |
138 | 0 | if (*ReadPos == PCX_IO_BUF_SIZE - 1) { |
139 | | // we still have one BYTE, copy it to the start pos |
140 | 0 | *ReadBuf = ReadBuf[PCX_IO_BUF_SIZE - 1]; |
141 | 0 | io->read_proc(ReadBuf + 1, 1, PCX_IO_BUF_SIZE - 1, handle); |
142 | 0 | } else { |
143 | | // read the complete buffer |
144 | 0 | io->read_proc(ReadBuf, 1, PCX_IO_BUF_SIZE, handle); |
145 | 0 | } |
146 | |
|
147 | 0 | *ReadPos = 0; |
148 | 0 | } |
149 | |
|
150 | 0 | value = *(ReadBuf + (*ReadPos)++); |
151 | |
|
152 | 0 | if ((value & 0xC0) == 0xC0) { |
153 | 0 | count = value & 0x3F; |
154 | 0 | value = *(ReadBuf + (*ReadPos)++); |
155 | 0 | } else { |
156 | 0 | count = 1; |
157 | 0 | } |
158 | 0 | } |
159 | |
|
160 | 0 | count--; |
161 | |
|
162 | 0 | *(buffer + written++) = value; |
163 | 0 | } |
164 | |
|
165 | 0 | } else { |
166 | | // normal read |
167 | |
|
168 | 0 | written = io->read_proc(buffer, length, 1, handle); |
169 | 0 | } |
170 | |
|
171 | 0 | return written; |
172 | 0 | } |
173 | | |
174 | | #ifdef FREEIMAGE_BIGENDIAN |
175 | | static void |
176 | | SwapHeader(PCXHEADER *header) { |
177 | | SwapShort(&header->window[0]); |
178 | | SwapShort(&header->window[1]); |
179 | | SwapShort(&header->window[2]); |
180 | | SwapShort(&header->window[3]); |
181 | | SwapShort(&header->hdpi); |
182 | | SwapShort(&header->vdpi); |
183 | | SwapShort(&header->bytes_per_line); |
184 | | SwapShort(&header->palette_info); |
185 | | SwapShort(&header->h_screen_size); |
186 | | SwapShort(&header->v_screen_size); |
187 | | } |
188 | | #endif |
189 | | |
190 | | // ========================================================== |
191 | | // Plugin Interface |
192 | | // ========================================================== |
193 | | |
194 | | static int s_format_id; |
195 | | |
196 | | // ========================================================== |
197 | | // Plugin Implementation |
198 | | // ========================================================== |
199 | | |
200 | | /*! |
201 | | Returns the format string for the plugin. Each plugin, |
202 | | both internal in the DLL and external in a .fip file, must have |
203 | | a unique format string to be addressable. |
204 | | */ |
205 | | |
206 | | static const char * DLL_CALLCONV |
207 | 2 | Format() { |
208 | 2 | return "PCX"; |
209 | 2 | } |
210 | | |
211 | | /*! |
212 | | Returns a description string for the plugin. Though a |
213 | | description is not necessary per-se, |
214 | | it is advised to return an unique string in order to tell the |
215 | | user what type of bitmaps this plugin will read and/or write. |
216 | | */ |
217 | | |
218 | | static const char * DLL_CALLCONV |
219 | 0 | Description() { |
220 | 0 | return "Zsoft Paintbrush"; |
221 | 0 | } |
222 | | |
223 | | /*! |
224 | | Returns a comma separated list of file |
225 | | extensions indicating what files this plugin can open. The |
226 | | list, being used by FreeImage_GetFIFFromFilename, is usually |
227 | | used as a last resort in finding the type of the bitmap we |
228 | | are dealing with. Best is to check the first few bytes on |
229 | | the low-level bits level first and compare them with a known |
230 | | signature . If this fails, FreeImage_GetFIFFromFilename can be |
231 | | used. |
232 | | */ |
233 | | |
234 | | static const char * DLL_CALLCONV |
235 | 0 | Extension() { |
236 | 0 | return "pcx"; |
237 | 0 | } |
238 | | |
239 | | /*! |
240 | | Returns an (optional) regular expression to help |
241 | | software identifying a bitmap type. The |
242 | | expression can be applied to the first few bytes (header) of |
243 | | the bitmap. FreeImage is not capable of processing regular expression itself, |
244 | | but FreeImageQt, the FreeImage Trolltech support library, can. If RegExpr |
245 | | returns NULL, FreeImageQt will automatically bypass Trolltech's regular |
246 | | expression support and use its internal functions to find the bitmap type. |
247 | | */ |
248 | | |
249 | | static const char * DLL_CALLCONV |
250 | 0 | RegExpr() { |
251 | 0 | return NULL; |
252 | 0 | } |
253 | | |
254 | | static const char * DLL_CALLCONV |
255 | 0 | MimeType() { |
256 | 0 | return "image/x-pcx"; |
257 | 0 | } |
258 | | |
259 | | /*! |
260 | | Validates a bitmap by reading the first few bytes |
261 | | and comparing them with a known bitmap signature. |
262 | | TRUE is returned if the bytes match the signature, FALSE otherwise. |
263 | | The Validate function is used by using FreeImage_GetFileType. |
264 | | |
265 | | Note: a plugin can safely read data any data from the bitmap without seeking back |
266 | | to the original entry point; the entry point is stored prior to calling this |
267 | | function and restored after. |
268 | | |
269 | | Note: because of FreeImage's io redirection support, the header for the bitmap |
270 | | must be on the start of the bitmap or at least on a known part in the bitmap. It is |
271 | | forbidden to seek to the end of the bitmap or to a point relative to the end of a bitmap, |
272 | | because the end of the bitmap is not always known. |
273 | | */ |
274 | | |
275 | | static BOOL DLL_CALLCONV |
276 | 12.2k | Validate(FreeImageIO *io, fi_handle handle) { |
277 | 12.2k | return pcx_validate(io, handle); |
278 | 12.2k | } |
279 | | |
280 | | /*! |
281 | | This function is used to 'ask' the plugin if it can write |
282 | | a bitmap in a certain bitdepth. Different bitmap types have different |
283 | | capabilities, for example not all formats allow writing in palettized mode. |
284 | | This function is there provide an uniform interface to the plugin's |
285 | | capabilities. SupportsExportDepth returns TRUE if the plugin support writing |
286 | | in the asked bitdepth, or FALSE if it doesn't. The function also |
287 | | returns FALSE if bitmap saving is not supported by the plugin at all. |
288 | | */ |
289 | | |
290 | | static BOOL DLL_CALLCONV |
291 | 0 | SupportsExportDepth(int depth) { |
292 | 0 | return FALSE; |
293 | 0 | } |
294 | | |
295 | | static BOOL DLL_CALLCONV |
296 | 0 | SupportsExportType(FREE_IMAGE_TYPE type) { |
297 | 0 | return FALSE; |
298 | 0 | } |
299 | | |
300 | | static BOOL DLL_CALLCONV |
301 | 0 | SupportsNoPixels() { |
302 | 0 | return TRUE; |
303 | 0 | } |
304 | | |
305 | | // ---------------------------------------------------------- |
306 | | |
307 | | /*! |
308 | | Loads a bitmap into memory. On entry it is assumed that |
309 | | the bitmap to be loaded is of the correct type. If the bitmap |
310 | | is of an incorrect type, the plugin might not gracefully fail but |
311 | | crash or enter an endless loop. It is also assumed that all |
312 | | the bitmap data is available at one time. If the bitmap is not complete, |
313 | | for example because it is being downloaded while loaded, the plugin |
314 | | might also not gracefully fail. |
315 | | |
316 | | The Load function has the following parameters: |
317 | | |
318 | | The first parameter (FreeImageIO *io) is a structure providing |
319 | | function pointers in order to make use of FreeImage's IO redirection. Using |
320 | | FreeImage's file i/o functions instead of standard ones it is garantueed |
321 | | that all bitmap types, both current and future ones, can be loaded from |
322 | | memory, file cabinets, the internet and more. The second parameter (fi_handle handle) |
323 | | is a companion of FreeImageIO and can be best compared with the standard FILE* type, |
324 | | in a generalized form. |
325 | | |
326 | | The third parameter (int page) indicates wether we will be loading a certain page |
327 | | in the bitmap or if we will load the default one. This parameter is only used if |
328 | | the plugin supports multi-paged bitmaps, e.g. cabinet bitmaps that contain a series |
329 | | of images or pages. If the plugin does support multi-paging, the page parameter |
330 | | can contain either a number higher or equal to 0 to load a certain page, or -1 to |
331 | | load the default page. If the plugin does not support multi-paging, |
332 | | the page parameter is always -1. |
333 | | |
334 | | The fourth parameter (int flags) manipulates the load function to load a bitmap |
335 | | in a certain way. Every plugin has a different flag parameter with different meanings. |
336 | | |
337 | | The last parameter (void *data) can contain a special data block used when |
338 | | the file is read multi-paged. Because not every plugin supports multi-paging |
339 | | not every plugin will use the data parameter and it will be set to NULL.However, |
340 | | when the plugin does support multi-paging the parameter contains a pointer to a |
341 | | block of data allocated by the Open function. |
342 | | */ |
343 | | |
344 | | static FIBITMAP * DLL_CALLCONV |
345 | 0 | Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
346 | 0 | FIBITMAP *dib = NULL; |
347 | 0 | BYTE *bits; // Pointer to dib data |
348 | 0 | RGBQUAD *pal; // Pointer to dib palette |
349 | 0 | BYTE *line = NULL; // PCX raster line |
350 | 0 | BYTE *ReadBuf = NULL; // buffer; |
351 | 0 | BOOL bIsRLE; // True if the file is run-length encoded |
352 | |
|
353 | 0 | if(!handle) { |
354 | 0 | return NULL; |
355 | 0 | } |
356 | | |
357 | 0 | BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; |
358 | |
|
359 | 0 | try { |
360 | | // check PCX identifier |
361 | | // (note: should have been already validated using FreeImage_GetFileType but check again) |
362 | 0 | { |
363 | 0 | long start_pos = io->tell_proc(handle); |
364 | 0 | BOOL bValidated = pcx_validate(io, handle); |
365 | 0 | io->seek_proc(handle, start_pos, SEEK_SET); |
366 | 0 | if(!bValidated) { |
367 | 0 | throw FI_MSG_ERROR_MAGIC_NUMBER; |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | 0 | PCXHEADER header; |
372 | | |
373 | | // process the header |
374 | 0 | if(io->read_proc(&header, sizeof(PCXHEADER), 1, handle) != 1) { |
375 | 0 | throw FI_MSG_ERROR_PARSING; |
376 | 0 | } |
377 | | #ifdef FREEIMAGE_BIGENDIAN |
378 | | SwapHeader(&header); |
379 | | #endif |
380 | | |
381 | | // process the window |
382 | 0 | const WORD *window = header.window; // left, upper, right,lower pixel coord. |
383 | 0 | const int left = window[0]; |
384 | 0 | const int top = window[1]; |
385 | 0 | const int right = window[2]; |
386 | 0 | const int bottom = window[3]; |
387 | | |
388 | | // check image size |
389 | 0 | if((left >= right) || (top >= bottom)) { |
390 | 0 | throw FI_MSG_ERROR_PARSING; |
391 | 0 | } |
392 | | |
393 | 0 | const unsigned width = right - left + 1; |
394 | 0 | const unsigned height = bottom - top + 1; |
395 | 0 | const unsigned bitcount = header.bpp * header.planes; |
396 | | |
397 | | // allocate a new dib |
398 | 0 | switch(bitcount) { |
399 | 0 | case 1: |
400 | 0 | case 4: |
401 | 0 | case 8: |
402 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, bitcount); |
403 | 0 | break; |
404 | 0 | case 24: |
405 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, bitcount, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
406 | 0 | break; |
407 | 0 | default: |
408 | 0 | throw FI_MSG_ERROR_DIB_MEMORY; |
409 | 0 | break; |
410 | 0 | } |
411 | | |
412 | | // if the dib couldn't be allocated, throw an error |
413 | 0 | if (!dib) { |
414 | 0 | throw FI_MSG_ERROR_DIB_MEMORY; |
415 | 0 | } |
416 | | |
417 | | // metrics handling code |
418 | | |
419 | 0 | FreeImage_SetDotsPerMeterX(dib, (unsigned) (((float)header.hdpi) / 0.0254000 + 0.5)); |
420 | 0 | FreeImage_SetDotsPerMeterY(dib, (unsigned) (((float)header.vdpi) / 0.0254000 + 0.5)); |
421 | | |
422 | | // Set up the palette if needed |
423 | | // ---------------------------- |
424 | |
|
425 | 0 | switch(bitcount) { |
426 | 0 | case 1: |
427 | 0 | { |
428 | 0 | pal = FreeImage_GetPalette(dib); |
429 | 0 | pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; |
430 | 0 | pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; |
431 | 0 | break; |
432 | 0 | } |
433 | | |
434 | 0 | case 4: |
435 | 0 | { |
436 | 0 | pal = FreeImage_GetPalette(dib); |
437 | |
|
438 | 0 | BYTE *pColormap = &header.color_map[0]; |
439 | |
|
440 | 0 | for (int i = 0; i < 16; i++) { |
441 | 0 | pal[i].rgbRed = pColormap[0]; |
442 | 0 | pal[i].rgbGreen = pColormap[1]; |
443 | 0 | pal[i].rgbBlue = pColormap[2]; |
444 | 0 | pColormap += 3; |
445 | 0 | } |
446 | |
|
447 | 0 | break; |
448 | 0 | } |
449 | | |
450 | 0 | case 8: |
451 | 0 | { |
452 | 0 | BYTE palette_id; |
453 | |
|
454 | 0 | io->seek_proc(handle, -769L, SEEK_END); |
455 | 0 | io->read_proc(&palette_id, 1, 1, handle); |
456 | |
|
457 | 0 | if (palette_id == 0x0C) { |
458 | 0 | BYTE *cmap = (BYTE*)malloc(768 * sizeof(BYTE)); |
459 | |
|
460 | 0 | if(cmap) { |
461 | 0 | io->read_proc(cmap, 768, 1, handle); |
462 | |
|
463 | 0 | pal = FreeImage_GetPalette(dib); |
464 | 0 | BYTE *pColormap = &cmap[0]; |
465 | |
|
466 | 0 | for(int i = 0; i < 256; i++) { |
467 | 0 | pal[i].rgbRed = pColormap[0]; |
468 | 0 | pal[i].rgbGreen = pColormap[1]; |
469 | 0 | pal[i].rgbBlue = pColormap[2]; |
470 | 0 | pColormap += 3; |
471 | 0 | } |
472 | |
|
473 | 0 | free(cmap); |
474 | 0 | } |
475 | |
|
476 | 0 | } |
477 | | |
478 | | // wrong palette ID, perhaps a gray scale is needed ? |
479 | | |
480 | 0 | else if (header.palette_info == 2) { |
481 | 0 | pal = FreeImage_GetPalette(dib); |
482 | |
|
483 | 0 | for(int i = 0; i < 256; i++) { |
484 | 0 | pal[i].rgbRed = (BYTE)i; |
485 | 0 | pal[i].rgbGreen = (BYTE)i; |
486 | 0 | pal[i].rgbBlue = (BYTE)i; |
487 | 0 | } |
488 | 0 | } |
489 | |
|
490 | 0 | io->seek_proc(handle, (long)sizeof(PCXHEADER), SEEK_SET); |
491 | 0 | } |
492 | 0 | break; |
493 | 0 | } |
494 | | |
495 | 0 | if(header_only) { |
496 | | // header only mode |
497 | 0 | return dib; |
498 | 0 | } |
499 | | |
500 | | // calculate the line length for the PCX and the dib |
501 | | |
502 | | // length of raster line in bytes |
503 | 0 | const unsigned lineLength = header.bytes_per_line * header.planes; |
504 | | // length of dib line (rounded to DWORD) in bytes |
505 | 0 | const unsigned pitch = FreeImage_GetPitch(dib); |
506 | | |
507 | | // run-length encoding ? |
508 | |
|
509 | 0 | bIsRLE = (header.encoding == 1) ? TRUE : FALSE; |
510 | | |
511 | | // load image data |
512 | | // --------------- |
513 | |
|
514 | 0 | line = (BYTE*)malloc(MAX(lineLength, width * header.bpp) * sizeof(BYTE)); //< # header.bytes_per_line might be corrupted (too small) |
515 | 0 | if(!line) { |
516 | 0 | throw FI_MSG_ERROR_MEMORY; |
517 | 0 | } |
518 | | |
519 | 0 | ReadBuf = (BYTE*)malloc(PCX_IO_BUF_SIZE * sizeof(BYTE)); |
520 | 0 | if(!ReadBuf) { |
521 | 0 | throw FI_MSG_ERROR_MEMORY; |
522 | 0 | } |
523 | | |
524 | 0 | bits = FreeImage_GetScanLine(dib, height - 1); |
525 | |
|
526 | 0 | int ReadPos = PCX_IO_BUF_SIZE; |
527 | |
|
528 | 0 | if ((header.planes == 1) && ((header.bpp == 1) || (header.bpp == 8))) { |
529 | 0 | BYTE skip; |
530 | 0 | unsigned written; |
531 | |
|
532 | 0 | for (unsigned y = 0; y < height; y++) { |
533 | | // do a safe copy of the scanline into 'line' |
534 | 0 | written = readLine(io, handle, line, lineLength, bIsRLE, ReadBuf, &ReadPos); |
535 | | // sometimes (already encountered), PCX images can have a lineLength > pitch |
536 | 0 | memcpy(bits, line, MIN(pitch, lineLength)); |
537 | | |
538 | | // skip trailing garbage at the end of the scanline |
539 | |
|
540 | 0 | for (unsigned count = written; count < lineLength; count++) { |
541 | 0 | if (ReadPos < PCX_IO_BUF_SIZE) { |
542 | 0 | ReadPos++; |
543 | 0 | } else { |
544 | 0 | io->read_proc(&skip, sizeof(BYTE), 1, handle); |
545 | 0 | } |
546 | 0 | } |
547 | |
|
548 | 0 | bits -= pitch; |
549 | 0 | } |
550 | 0 | } else if ((header.planes == 4) && (header.bpp == 1)) { |
551 | 0 | BYTE bit, mask, skip; |
552 | 0 | unsigned index; |
553 | 0 | BYTE *buffer; |
554 | |
|
555 | 0 | buffer = (BYTE*)malloc(width * sizeof(BYTE)); |
556 | 0 | if(!buffer) { |
557 | 0 | throw FI_MSG_ERROR_MEMORY; |
558 | 0 | } |
559 | | |
560 | 0 | for (unsigned y = 0; y < height; y++) { |
561 | 0 | unsigned written = readLine(io, handle, line, lineLength, bIsRLE, ReadBuf, &ReadPos); |
562 | | |
563 | | // build a nibble using the 4 planes |
564 | |
|
565 | 0 | memset(buffer, 0, width * sizeof(BYTE)); |
566 | |
|
567 | 0 | for(int plane = 0; plane < 4; plane++) { |
568 | 0 | bit = (BYTE)(1 << plane); |
569 | |
|
570 | 0 | for (unsigned x = 0; x < width; x++) { |
571 | 0 | index = (unsigned)((x / 8) + plane * header.bytes_per_line); |
572 | 0 | mask = (BYTE)(0x80 >> (x & 0x07)); |
573 | 0 | buffer[x] |= (line[index] & mask) ? bit : 0; |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | | // then write the dib row |
578 | |
|
579 | 0 | for (unsigned x = 0; x < width / 2; x++) { |
580 | 0 | bits[x] = (buffer[2*x] << 4) | buffer[2*x+1]; |
581 | 0 | } |
582 | | |
583 | | // skip trailing garbage at the end of the scanline |
584 | |
|
585 | 0 | for (unsigned count = written; count < lineLength; count++) { |
586 | 0 | if (ReadPos < PCX_IO_BUF_SIZE) { |
587 | 0 | ReadPos++; |
588 | 0 | } else { |
589 | 0 | io->read_proc(&skip, sizeof(BYTE), 1, handle); |
590 | 0 | } |
591 | 0 | } |
592 | |
|
593 | 0 | bits -= pitch; |
594 | 0 | } |
595 | |
|
596 | 0 | free(buffer); |
597 | |
|
598 | 0 | } else if((header.planes == 3) && (header.bpp == 8)) { |
599 | 0 | BYTE *pLine; |
600 | |
|
601 | 0 | for (unsigned y = 0; y < height; y++) { |
602 | 0 | readLine(io, handle, line, lineLength, bIsRLE, ReadBuf, &ReadPos); |
603 | | |
604 | | // convert the plane stream to BGR (RRRRGGGGBBBB -> BGRBGRBGRBGR) |
605 | | // well, now with the FI_RGBA_x macros, on BIGENDIAN we convert to RGB |
606 | |
|
607 | 0 | pLine = line; |
608 | 0 | unsigned x; |
609 | |
|
610 | 0 | for (x = 0; x < width; x++) { |
611 | 0 | bits[x * 3 + FI_RGBA_RED] = pLine[x]; |
612 | 0 | } |
613 | 0 | pLine += header.bytes_per_line; |
614 | |
|
615 | 0 | for (x = 0; x < width; x++) { |
616 | 0 | bits[x * 3 + FI_RGBA_GREEN] = pLine[x]; |
617 | 0 | } |
618 | 0 | pLine += header.bytes_per_line; |
619 | |
|
620 | 0 | for (x = 0; x < width; x++) { |
621 | 0 | bits[x * 3 + FI_RGBA_BLUE] = pLine[x]; |
622 | 0 | } |
623 | 0 | pLine += header.bytes_per_line; |
624 | |
|
625 | 0 | bits -= pitch; |
626 | 0 | } |
627 | 0 | } else { |
628 | 0 | throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; |
629 | 0 | } |
630 | | |
631 | 0 | free(line); |
632 | 0 | free(ReadBuf); |
633 | |
|
634 | 0 | return dib; |
635 | |
|
636 | 0 | } catch (const char *text) { |
637 | | // free allocated memory |
638 | |
|
639 | 0 | if (dib != NULL) { |
640 | 0 | FreeImage_Unload(dib); |
641 | 0 | } |
642 | 0 | if (line != NULL) { |
643 | 0 | free(line); |
644 | 0 | } |
645 | 0 | if (ReadBuf != NULL) { |
646 | 0 | free(ReadBuf); |
647 | 0 | } |
648 | |
|
649 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
650 | 0 | } |
651 | | |
652 | 0 | return NULL; |
653 | 0 | } |
654 | | |
655 | | // ========================================================== |
656 | | // Init |
657 | | // ========================================================== |
658 | | |
659 | | /*! |
660 | | Initialises the plugin. The first parameter (Plugin *plugin) |
661 | | contains a pointer to a pre-allocated Plugin structure |
662 | | wherein pointers to the available plugin functions |
663 | | has to be stored. The second parameter (int format_id) is an identification |
664 | | number that the plugin may use to show plugin specific warning messages |
665 | | or other information to the user. The plugin number |
666 | | is generated by FreeImage and can differ everytime the plugin is |
667 | | initialised. |
668 | | |
669 | | If you want to create your own plugin you have to take some |
670 | | rules into account. Plugin functions have to be compiled |
671 | | __stdcall using the multithreaded c runtime libraries. Throwing |
672 | | exceptions in plugin functions is allowed, as long as those exceptions |
673 | | are being caught inside the same plugin. It is forbidden for a plugin |
674 | | function to directly call FreeImage functions or to allocate memory |
675 | | and pass it to the main DLL. Exception to this rule is the special file data |
676 | | block that may be allocated the Open function. Allocating a FIBITMAP inside a |
677 | | plugin can be using the function allocate_proc in the FreeImage structure, |
678 | | which will allocate the memory using the DLL's c runtime library. |
679 | | */ |
680 | | |
681 | | void DLL_CALLCONV |
682 | 2 | InitPCX(Plugin *plugin, int format_id) { |
683 | 2 | s_format_id = format_id; |
684 | | |
685 | 2 | plugin->format_proc = Format; |
686 | 2 | plugin->description_proc = Description; |
687 | 2 | plugin->extension_proc = Extension; |
688 | 2 | plugin->regexpr_proc = RegExpr; |
689 | 2 | plugin->open_proc = NULL; |
690 | 2 | plugin->close_proc = NULL; |
691 | 2 | plugin->pagecount_proc = NULL; |
692 | 2 | plugin->pagecapability_proc = NULL; |
693 | 2 | plugin->load_proc = Load; |
694 | 2 | plugin->save_proc = NULL; |
695 | 2 | plugin->validate_proc = Validate; |
696 | 2 | plugin->mime_proc = MimeType; |
697 | 2 | plugin->supports_export_bpp_proc = SupportsExportDepth; |
698 | 2 | plugin->supports_export_type_proc = SupportsExportType; |
699 | | plugin->supports_icc_profiles_proc = NULL; |
700 | 2 | plugin->supports_no_pixels_proc = SupportsNoPixels; |
701 | 2 | } |