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 #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
pcx_validate(FreeImageIO * io,fi_handle handle)84 pcx_validate(FreeImageIO *io, fi_handle handle) {
85 	BYTE pcx_signature = 0x0A;
86 	BYTE signature[4] = { 0, 0, 0, 0 };
87 
88 	if(io->read_proc(&signature, 1, 4, handle) != 4) {
89 		return FALSE;
90 	}
91 	// magic number (0x0A = ZSoft Z)
92 	if(signature[0] == pcx_signature) {
93 		// version
94 		if(signature[1] <= 5) {
95 			// encoding
96 			if((signature[2] == 0) || (signature[2] == 1)) {
97 				// bits per pixel per plane
98 				if((signature[3] == 1) || (signature[3] == 8)) {
99 					return TRUE;
100 				}
101 			}
102 		}
103 	}
104 
105 	return FALSE;
106 }
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
readLine(FreeImageIO * io,fi_handle handle,BYTE * buffer,unsigned length,BOOL bIsRLE,BYTE * ReadBuf,int * ReadPos)127 readLine(FreeImageIO *io, fi_handle handle, BYTE *buffer, unsigned length, BOOL bIsRLE, BYTE * ReadBuf, int * ReadPos) {
128 	BYTE count = 0;
129 	BYTE value = 0;
130 	unsigned written = 0;
131 
132 	if (bIsRLE) {
133 		// run-length encoded read
134 
135 		while (length--) {
136 			if (count == 0) {
137 				if (*ReadPos >= PCX_IO_BUF_SIZE - 1 ) {
138 					if (*ReadPos == PCX_IO_BUF_SIZE - 1) {
139 						// we still have one BYTE, copy it to the start pos
140 						*ReadBuf = ReadBuf[PCX_IO_BUF_SIZE - 1];
141 						io->read_proc(ReadBuf + 1, 1, PCX_IO_BUF_SIZE - 1, handle);
142 					} else {
143 						// read the complete buffer
144 						io->read_proc(ReadBuf, 1, PCX_IO_BUF_SIZE, handle);
145 					}
146 
147 					*ReadPos = 0;
148 				}
149 
150 				value = *(ReadBuf + (*ReadPos)++);
151 
152 				if ((value & 0xC0) == 0xC0) {
153 					count = value & 0x3F;
154 					value = *(ReadBuf + (*ReadPos)++);
155 				} else {
156 					count = 1;
157 				}
158 			}
159 
160 			count--;
161 
162 			*(buffer + written++) = value;
163 		}
164 
165 	} else {
166 		// normal read
167 
168 		written = io->read_proc(buffer, length, 1, handle);
169 	}
170 
171 	return written;
172 }
173 
174 #ifdef FREEIMAGE_BIGENDIAN
175 static void
SwapHeader(PCXHEADER * header)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
Format()207 Format() {
208 	return "PCX";
209 }
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
Description()219 Description() {
220 	return "Zsoft Paintbrush";
221 }
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
Extension()235 Extension() {
236 	return "pcx";
237 }
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
RegExpr()250 RegExpr() {
251 	return NULL;
252 }
253 
254 static const char * DLL_CALLCONV
MimeType()255 MimeType() {
256 	return "image/x-pcx";
257 }
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
Validate(FreeImageIO * io,fi_handle handle)276 Validate(FreeImageIO *io, fi_handle handle) {
277 	return pcx_validate(io, handle);
278 }
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
SupportsExportDepth(int depth)291 SupportsExportDepth(int depth) {
292 	return FALSE;
293 }
294 
295 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)296 SupportsExportType(FREE_IMAGE_TYPE type) {
297 	return FALSE;
298 }
299 
300 static BOOL DLL_CALLCONV
SupportsNoPixels()301 SupportsNoPixels() {
302 	return TRUE;
303 }
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
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)345 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
346 	FIBITMAP *dib = NULL;
347 	BYTE *bits;			  // Pointer to dib data
348 	RGBQUAD *pal;		  // Pointer to dib palette
349 	BYTE *line = NULL;	  // PCX raster line
350 	BYTE *ReadBuf = NULL; // buffer;
351 	BOOL bIsRLE;		  // True if the file is run-length encoded
352 
353 	if(!handle) {
354 		return NULL;
355 	}
356 
357 	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
358 
359 	try {
360 		// check PCX identifier
361 		// (note: should have been already validated using FreeImage_GetFileType but check again)
362 		{
363 			long start_pos = io->tell_proc(handle);
364 			BOOL bValidated = pcx_validate(io, handle);
365 			io->seek_proc(handle, start_pos, SEEK_SET);
366 			if(!bValidated) {
367 				throw FI_MSG_ERROR_MAGIC_NUMBER;
368 			}
369 		}
370 
371 		PCXHEADER header;
372 
373 		// process the header
374 		if(io->read_proc(&header, sizeof(PCXHEADER), 1, handle) != 1) {
375 			throw FI_MSG_ERROR_PARSING;
376 		}
377 #ifdef FREEIMAGE_BIGENDIAN
378 		SwapHeader(&header);
379 #endif
380 
381 		// process the window
382 		const WORD *window = header.window;	// left, upper, right,lower pixel coord.
383 		const int left		= window[0];
384 		const int top		= window[1];
385 		const int right		= window[2];
386 		const int bottom	= window[3];
387 
388 		// check image size
389 		if((left >= right) || (top >= bottom)) {
390 			throw FI_MSG_ERROR_PARSING;
391 		}
392 
393 		const unsigned width = right - left + 1;
394 		const unsigned height = bottom - top + 1;
395 		const unsigned bitcount = header.bpp * header.planes;
396 
397 		// allocate a new dib
398 		switch(bitcount) {
399 			case 1:
400 			case 4:
401 			case 8:
402 				dib = FreeImage_AllocateHeader(header_only, width, height, bitcount);
403 				break;
404 			case 24:
405 				dib = FreeImage_AllocateHeader(header_only, width, height, bitcount, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
406 				break;
407 			default:
408 				throw FI_MSG_ERROR_DIB_MEMORY;
409 				break;
410 		}
411 
412 		// if the dib couldn't be allocated, throw an error
413 		if (!dib) {
414 			throw FI_MSG_ERROR_DIB_MEMORY;
415 		}
416 
417 		// metrics handling code
418 
419 		FreeImage_SetDotsPerMeterX(dib, (unsigned) (((float)header.hdpi) / 0.0254000 + 0.5));
420 		FreeImage_SetDotsPerMeterY(dib, (unsigned) (((float)header.vdpi) / 0.0254000 + 0.5));
421 
422 		// Set up the palette if needed
423 		// ----------------------------
424 
425 		switch(bitcount) {
426 			case 1:
427 			{
428 				pal = FreeImage_GetPalette(dib);
429 				pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
430 				pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
431 				break;
432 			}
433 
434 			case 4:
435 			{
436 				pal = FreeImage_GetPalette(dib);
437 
438 				BYTE *pColormap = &header.color_map[0];
439 
440 				for (int i = 0; i < 16; i++) {
441 					pal[i].rgbRed   = pColormap[0];
442 					pal[i].rgbGreen = pColormap[1];
443 					pal[i].rgbBlue  = pColormap[2];
444 					pColormap += 3;
445 				}
446 
447 				break;
448 			}
449 
450 			case 8:
451 			{
452 				BYTE palette_id;
453 
454 				io->seek_proc(handle, -769L, SEEK_END);
455 				io->read_proc(&palette_id, 1, 1, handle);
456 
457 				if (palette_id == 0x0C) {
458 					BYTE *cmap = (BYTE*)malloc(768 * sizeof(BYTE));
459 
460 					if(cmap) {
461 						io->read_proc(cmap, 768, 1, handle);
462 
463 						pal = FreeImage_GetPalette(dib);
464 						BYTE *pColormap = &cmap[0];
465 
466 						for(int i = 0; i < 256; i++) {
467 							pal[i].rgbRed   = pColormap[0];
468 							pal[i].rgbGreen = pColormap[1];
469 							pal[i].rgbBlue  = pColormap[2];
470 							pColormap += 3;
471 						}
472 
473 						free(cmap);
474 					}
475 
476 				}
477 
478 				// wrong palette ID, perhaps a gray scale is needed ?
479 
480 				else if (header.palette_info == 2) {
481 					pal = FreeImage_GetPalette(dib);
482 
483 					for(int i = 0; i < 256; i++) {
484 						pal[i].rgbRed   = (BYTE)i;
485 						pal[i].rgbGreen = (BYTE)i;
486 						pal[i].rgbBlue  = (BYTE)i;
487 					}
488 				}
489 
490 				io->seek_proc(handle, (long)sizeof(PCXHEADER), SEEK_SET);
491 			}
492 			break;
493 		}
494 
495 		if(header_only) {
496 			// header only mode
497 			return dib;
498 		}
499 
500 		// calculate the line length for the PCX and the dib
501 
502 		// length of raster line in bytes
503 		const unsigned lineLength = header.bytes_per_line * header.planes;
504 		// length of dib line (rounded to DWORD) in bytes
505 		const unsigned pitch = FreeImage_GetPitch(dib);
506 
507 		// run-length encoding ?
508 
509 		bIsRLE = (header.encoding == 1) ? TRUE : FALSE;
510 
511 		// load image data
512 		// ---------------
513 
514 		line = (BYTE*)malloc(lineLength * sizeof(BYTE));
515 		if(!line) {
516 			throw FI_MSG_ERROR_MEMORY;
517 		}
518 
519 		ReadBuf = (BYTE*)malloc(PCX_IO_BUF_SIZE * sizeof(BYTE));
520 		if(!ReadBuf) {
521 			throw FI_MSG_ERROR_MEMORY;
522 		}
523 
524 		bits = FreeImage_GetScanLine(dib, height - 1);
525 
526 		int ReadPos = PCX_IO_BUF_SIZE;
527 
528 		if ((header.planes == 1) && ((header.bpp == 1) || (header.bpp == 8))) {
529 			BYTE skip;
530 			unsigned written;
531 
532 			for (unsigned y = 0; y < height; y++) {
533 				// do a safe copy of the scanline into 'line'
534 				written = readLine(io, handle, line, lineLength, bIsRLE, ReadBuf, &ReadPos);
535 				// sometimes (already encountered), PCX images can have a lineLength > pitch
536 				memcpy(bits, line, MIN(pitch, lineLength));
537 
538 				// skip trailing garbage at the end of the scanline
539 
540 				for (unsigned count = written; count < lineLength; count++) {
541 					if (ReadPos < PCX_IO_BUF_SIZE) {
542 						ReadPos++;
543 					} else {
544 						io->read_proc(&skip, sizeof(BYTE), 1, handle);
545 					}
546 				}
547 
548 				bits -= pitch;
549 			}
550 		} else if ((header.planes == 4) && (header.bpp == 1)) {
551 			BYTE bit,  mask, skip;
552 			unsigned index;
553 			BYTE *buffer;
554 
555 			buffer = (BYTE*)malloc(width * sizeof(BYTE));
556 			if(!buffer) {
557 				throw FI_MSG_ERROR_MEMORY;
558 			}
559 
560 			for (unsigned y = 0; y < height; y++) {
561 				unsigned written = readLine(io, handle, line, lineLength, bIsRLE, ReadBuf, &ReadPos);
562 
563 				// build a nibble using the 4 planes
564 
565 				memset(buffer, 0, width * sizeof(BYTE));
566 
567 				for(int plane = 0; plane < 4; plane++) {
568 					bit = (BYTE)(1 << plane);
569 
570 					for (unsigned x = 0; x < width; x++) {
571 						index = (unsigned)((x / 8) + plane * header.bytes_per_line);
572 						mask = (BYTE)(0x80 >> (x & 0x07));
573 						buffer[x] |= (line[index] & mask) ? bit : 0;
574 					}
575 				}
576 
577 				// then write the dib row
578 
579 				for (unsigned x = 0; x < width / 2; x++) {
580 					bits[x] = (buffer[2*x] << 4) | buffer[2*x+1];
581 				}
582 
583 				// skip trailing garbage at the end of the scanline
584 
585 				for (unsigned count = written; count < lineLength; count++) {
586 					if (ReadPos < PCX_IO_BUF_SIZE) {
587 						ReadPos++;
588 					} else {
589 						io->read_proc(&skip, sizeof(BYTE), 1, handle);
590 					}
591 				}
592 
593 				bits -= pitch;
594 			}
595 
596 			free(buffer);
597 
598 		} else if((header.planes == 3) && (header.bpp == 8)) {
599 			BYTE *pLine;
600 
601 			for (unsigned y = 0; y < height; y++) {
602 				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 				pLine = line;
608 				unsigned x;
609 
610 				for (x = 0; x < width; x++) {
611 					bits[x * 3 + FI_RGBA_RED] = pLine[x];
612 				}
613 				pLine += header.bytes_per_line;
614 
615 				for (x = 0; x < width; x++) {
616 					bits[x * 3 + FI_RGBA_GREEN] = pLine[x];
617 				}
618 				pLine += header.bytes_per_line;
619 
620 				for (x = 0; x < width; x++) {
621 					bits[x * 3 + FI_RGBA_BLUE] = pLine[x];
622 				}
623 				pLine += header.bytes_per_line;
624 
625 				bits -= pitch;
626 			}
627 		} else {
628 			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
629 		}
630 
631 		free(line);
632 		free(ReadBuf);
633 
634 		return dib;
635 
636 	} catch (const char *text) {
637 		// free allocated memory
638 
639 		if (dib != NULL) {
640 			FreeImage_Unload(dib);
641 		}
642 		if (line != NULL) {
643 			free(line);
644 		}
645 		if (ReadBuf != NULL) {
646 			free(ReadBuf);
647 		}
648 
649 		FreeImage_OutputMessageProc(s_format_id, text);
650 	}
651 
652 	return NULL;
653 }
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
InitPCX(Plugin * plugin,int format_id)682 InitPCX(Plugin *plugin, int format_id) {
683 	s_format_id = format_id;
684 
685 	plugin->format_proc = Format;
686 	plugin->description_proc = Description;
687 	plugin->extension_proc = Extension;
688 	plugin->regexpr_proc = RegExpr;
689 	plugin->open_proc = NULL;
690 	plugin->close_proc = NULL;
691 	plugin->pagecount_proc = NULL;
692 	plugin->pagecapability_proc = NULL;
693 	plugin->load_proc = Load;
694 	plugin->save_proc = NULL;
695 	plugin->validate_proc = Validate;
696 	plugin->mime_proc = MimeType;
697 	plugin->supports_export_bpp_proc = SupportsExportDepth;
698 	plugin->supports_export_type_proc = SupportsExportType;
699 	plugin->supports_icc_profiles_proc = NULL;
700 	plugin->supports_no_pixels_proc = SupportsNoPixels;
701 }
702