Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PCX.CPP
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: PCX.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  PCX image file loader
13 */
14 
15 
16 #include "MemDebug.h"
17 #include "PCX.h"
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 // +--------------------------------------------------------------------+
24 
25 #define MAX_SIZE (4*1024*1024)
26 
27 enum { BYTEMODE, RUNMODE };
28 
29 // +--------------------------------------------------------------------+
30 
32 : width(0), height(0), bitmap(0), himap(0), imagebytes(0)
33 { }
34 
35 PcxImage::PcxImage(short w, short h, unsigned char* bits, unsigned char* colors)
36 : bitmap(0), himap(0)
37 {
38  hdr.manufacturer = 10; // Always set to 10
39  hdr.version = 5; // Always 5 for 256-color files
40  hdr.encoding = 1; // Always set to 1
41  hdr.bits_per_pixel = 8; // Should be 8 for 256-color files
42  hdr.xmin = 0;
43  hdr.xmax = w-1;
44  hdr.ymin = 0;
45  hdr.ymax = h-1;
46  hdr.hres = 0x48;
47  hdr.vres = 0x48;
48 
49  hdr.palette16[ 0] = (unsigned char) 0x00;
50  hdr.palette16[ 1] = (unsigned char) 0x00;
51  hdr.palette16[ 2] = (unsigned char) 0x00;
52  hdr.palette16[ 3] = (unsigned char) 0x80;
53  hdr.palette16[ 4] = (unsigned char) 0x00;
54  hdr.palette16[ 5] = (unsigned char) 0x00;
55  hdr.palette16[ 6] = (unsigned char) 0x00;
56  hdr.palette16[ 7] = (unsigned char) 0x80;
57  hdr.palette16[ 8] = (unsigned char) 0x00;
58  hdr.palette16[ 9] = (unsigned char) 0x80;
59  hdr.palette16[10] = (unsigned char) 0x80;
60  hdr.palette16[11] = (unsigned char) 0x00;
61  hdr.palette16[12] = (unsigned char) 0x00;
62  hdr.palette16[13] = (unsigned char) 0x00;
63  hdr.palette16[14] = (unsigned char) 0x80;
64  hdr.palette16[15] = (unsigned char) 0x80;
65 
66  hdr.palette16[16] = (unsigned char) 0x00;
67  hdr.palette16[17] = (unsigned char) 0x80;
68  hdr.palette16[18] = (unsigned char) 0x00;
69  hdr.palette16[19] = (unsigned char) 0x80;
70  hdr.palette16[20] = (unsigned char) 0x80;
71  hdr.palette16[21] = (unsigned char) 0xC0;
72  hdr.palette16[22] = (unsigned char) 0xC0;
73  hdr.palette16[23] = (unsigned char) 0xC0;
74  hdr.palette16[24] = (unsigned char) 0xC0;
75  hdr.palette16[25] = (unsigned char) 0xDC;
76  hdr.palette16[26] = (unsigned char) 0xC0;
77  hdr.palette16[27] = (unsigned char) 0xA6;
78  hdr.palette16[28] = (unsigned char) 0xCA;
79  hdr.palette16[29] = (unsigned char) 0xF0;
80  hdr.palette16[30] = (unsigned char) 0x33;
81  hdr.palette16[31] = (unsigned char) 0x2B;
82 
83  hdr.palette16[32] = (unsigned char) 0x1F;
84  hdr.palette16[33] = (unsigned char) 0x2B;
85  hdr.palette16[34] = (unsigned char) 0x23;
86  hdr.palette16[35] = (unsigned char) 0x1B;
87  hdr.palette16[36] = (unsigned char) 0x5F;
88  hdr.palette16[37] = (unsigned char) 0x5F;
89  hdr.palette16[38] = (unsigned char) 0x5F;
90  hdr.palette16[39] = (unsigned char) 0x2F;
91  hdr.palette16[40] = (unsigned char) 0x2F;
92  hdr.palette16[41] = (unsigned char) 0x2F;
93  hdr.palette16[42] = (unsigned char) 0x27;
94  hdr.palette16[43] = (unsigned char) 0x27;
95  hdr.palette16[44] = (unsigned char) 0x27;
96  hdr.palette16[45] = (unsigned char) 0x1F;
97  hdr.palette16[46] = (unsigned char) 0x1F;
98  hdr.palette16[47] = (unsigned char) 0x1F;
99 
100  hdr.reserved = 0; // Reserved for future use
101  hdr.color_planes = 1; // Color planes
102  hdr.bytes_per_line = w; // Number of bytes in 1 line of pixels
103  hdr.palette_type = 1; // Should be 1 for color palette
104 
105  for (unsigned int i = 0; i < 58; i++)
106  hdr.filler[i] = 0;
107 
108  width = w;
109  height = h;
110  imagebytes = width * height;
111 
112  bitmap = new(__FILE__,__LINE__) unsigned char [imagebytes];
113 
114  if (bitmap) {
115  for (unsigned long i = 0; i < imagebytes; i++)
116  bitmap[i] = bits[i];
117 
118  unsigned char* p = pal;
119  for (int i = 0; i < 256; i++) {
120  *p++ = *colors++;
121  *p++ = *colors++;
122  *p++ = *colors++;
123  colors++;
124  }
125  }
126 }
127 
128 PcxImage::PcxImage(short w, short h, unsigned long* hibits)
129 : bitmap(0), himap(0)
130 {
131  hdr.manufacturer = 10; // Always set to 10
132  hdr.version = 5; // Always 5 for true color files
133  hdr.encoding = 1; // Always set to 1
134  hdr.bits_per_pixel = 8; // Should be 8 for true color files
135  hdr.xmin = 0;
136  hdr.xmax = w-1;
137  hdr.ymin = 0;
138  hdr.ymax = h-1;
139  hdr.hres = 0x48;
140  hdr.vres = 0x48;
141 
142  hdr.palette16[ 0] = (unsigned char) 0x00;
143  hdr.palette16[ 1] = (unsigned char) 0x00;
144  hdr.palette16[ 2] = (unsigned char) 0x00;
145  hdr.palette16[ 3] = (unsigned char) 0x80;
146  hdr.palette16[ 4] = (unsigned char) 0x00;
147  hdr.palette16[ 5] = (unsigned char) 0x00;
148  hdr.palette16[ 6] = (unsigned char) 0x00;
149  hdr.palette16[ 7] = (unsigned char) 0x80;
150  hdr.palette16[ 8] = (unsigned char) 0x00;
151  hdr.palette16[ 9] = (unsigned char) 0x80;
152  hdr.palette16[10] = (unsigned char) 0x80;
153  hdr.palette16[11] = (unsigned char) 0x00;
154  hdr.palette16[12] = (unsigned char) 0x00;
155  hdr.palette16[13] = (unsigned char) 0x00;
156  hdr.palette16[14] = (unsigned char) 0x80;
157  hdr.palette16[15] = (unsigned char) 0x80;
158 
159  hdr.palette16[16] = (unsigned char) 0x00;
160  hdr.palette16[17] = (unsigned char) 0x80;
161  hdr.palette16[18] = (unsigned char) 0x00;
162  hdr.palette16[19] = (unsigned char) 0x80;
163  hdr.palette16[20] = (unsigned char) 0x80;
164  hdr.palette16[21] = (unsigned char) 0xC0;
165  hdr.palette16[22] = (unsigned char) 0xC0;
166  hdr.palette16[23] = (unsigned char) 0xC0;
167  hdr.palette16[24] = (unsigned char) 0xC0;
168  hdr.palette16[25] = (unsigned char) 0xDC;
169  hdr.palette16[26] = (unsigned char) 0xC0;
170  hdr.palette16[27] = (unsigned char) 0xA6;
171  hdr.palette16[28] = (unsigned char) 0xCA;
172  hdr.palette16[29] = (unsigned char) 0xF0;
173  hdr.palette16[30] = (unsigned char) 0x33;
174  hdr.palette16[31] = (unsigned char) 0x2B;
175 
176  hdr.palette16[32] = (unsigned char) 0x1F;
177  hdr.palette16[33] = (unsigned char) 0x2B;
178  hdr.palette16[34] = (unsigned char) 0x23;
179  hdr.palette16[35] = (unsigned char) 0x1B;
180  hdr.palette16[36] = (unsigned char) 0x5F;
181  hdr.palette16[37] = (unsigned char) 0x5F;
182  hdr.palette16[38] = (unsigned char) 0x5F;
183  hdr.palette16[39] = (unsigned char) 0x2F;
184  hdr.palette16[40] = (unsigned char) 0x2F;
185  hdr.palette16[41] = (unsigned char) 0x2F;
186  hdr.palette16[42] = (unsigned char) 0x27;
187  hdr.palette16[43] = (unsigned char) 0x27;
188  hdr.palette16[44] = (unsigned char) 0x27;
189  hdr.palette16[45] = (unsigned char) 0x1F;
190  hdr.palette16[46] = (unsigned char) 0x1F;
191  hdr.palette16[47] = (unsigned char) 0x1F;
192 
193  hdr.reserved = 0; // Reserved for future use
194  hdr.color_planes = 3; // Color planes
195  hdr.bytes_per_line = w; // Number of bytes in 1 line of pixels
196  hdr.palette_type = 1; // Should be 1 for color palette
197 
198  for (unsigned int i = 0; i < 58; i++)
199  hdr.filler[i] = 0;
200 
201  width = w;
202  height = h;
203  imagebytes = width * height;
204 
205  himap = new(__FILE__,__LINE__) unsigned long [imagebytes];
206 
207  if (himap) {
208  for (unsigned long i = 0; i < imagebytes; i++)
209  himap[i] = hibits[i];
210  }
211 }
212 
214 {
215  delete [] bitmap;
216  delete [] himap;
217 }
218 
219 // +--------------------------------------------------------------------+
220 
221 int PcxImage::Load(char *filename)
222 {
223  unsigned long i;
224  short mode=BYTEMODE, bytecount;
225  unsigned char abyte, *p;
226  FILE *f;
227 
228  fopen_s(&f, filename,"rb");
229  if (f == NULL)
230  return PCX_NOFILE;
231 
232  fread(&hdr, sizeof(PcxHeader), 1, f);
233 
234  // read 256 color PCX file
235  if (hdr.color_planes == 1) {
236  width = 1 + hdr.xmax - hdr.xmin;
237  height = 1 + hdr.ymax - hdr.ymin;
238  imagebytes = width * height;
239 
240  if (imagebytes > MAX_SIZE)
241  return PCX_TOOBIG;
242 
243  // get palette from pcx file
244  fseek(f,-768L,SEEK_END);
245  fread(pal,768,1,f);
246 
247  // now go back and read the pixel data:
248  fseek(f,sizeof(PcxHeader),SEEK_SET);
249 
250  delete [] himap; himap = 0;
251  delete [] bitmap; bitmap = 0;
252 
253  himap = new(__FILE__,__LINE__) unsigned long [imagebytes];
254  if (himap == NULL)
255  return PCX_NOMEM;
256 
257  // force alpha channel to 255
258  memset(himap, 0xff, imagebytes*4);
259 
260  unsigned long* pix = himap;
261  for (i=0; i<imagebytes; i++) {
262  if (mode == BYTEMODE) {
263  abyte = fgetc(f);
264 
265  if (abyte > 0xbf) {
266  bytecount = abyte & 0x3f;
267  abyte = fgetc(f);
268  if (--bytecount > 0)
269  mode = RUNMODE;
270  }
271  }
272  else if (--bytecount == 0) {
273  mode = BYTEMODE;
274  }
275 
276  *pix++ = 0xff000000 | (pal[3*abyte] << 16) | (pal[3*abyte+1] << 8) | (pal[3*abyte+2]);
277  }
278  }
279 
280  // read 24-bit (true COLOR) PCX file
281  else {
282  width = 1 + hdr.xmax - hdr.xmin;
283  height = 1 + hdr.ymax - hdr.ymin;
284  imagebytes = width * height;
285 
286  if (imagebytes > MAX_SIZE)
287  return PCX_TOOBIG;
288 
289  delete [] himap; himap = 0;
290  delete [] bitmap; bitmap = 0;
291 
292  himap = new(__FILE__,__LINE__) unsigned long [imagebytes];
293  if (himap == NULL)
294  return PCX_NOMEM;
295 
296  // force alpha channel to 255
297  memset(himap, 0xff, imagebytes*4);
298 
299  for (int row = 0; row < height; row++) {
300  // RED, GREEN, BLUE
301  for (int plane = 2; plane >= 0; plane--) {
302  p = ((unsigned char*) himap) + width*row*4 + plane;
303  for (int col = 0; col < width; col++) {
304  if (mode == BYTEMODE) {
305  abyte = fgetc(f);
306 
307  if (abyte > 0xbf) {
308  bytecount = abyte & 0x3f;
309  abyte = fgetc(f);
310  if (--bytecount > 0)
311  mode = RUNMODE;
312  }
313  }
314  else if (--bytecount == 0) {
315  mode = BYTEMODE;
316  }
317 
318  *p = abyte;
319  p += 4;
320  }
321  }
322  }
323  }
324 
325  fclose(f);
326  return PCX_OK;
327 }
328 
329 // +--------------------------------------------------------------------+
330 
331 int PcxImage::LoadBuffer(unsigned char* buf, int len)
332 {
333  unsigned long i;
334  short mode=BYTEMODE, bytecount;
335  unsigned char abyte, *p;
336  unsigned char* fp;
337 
338  if (buf == NULL)
339  return PCX_NOFILE;
340 
341  fp = buf;
342  memcpy(&hdr, buf, sizeof(PcxHeader));
343  fp += sizeof(PcxHeader);
344 
345  // read 256 color PCX file
346  if (hdr.color_planes == 1) {
347  width = 1 + hdr.xmax - hdr.xmin;
348  height = 1 + hdr.ymax - hdr.ymin;
349  imagebytes = width * height;
350 
351  if (imagebytes > MAX_SIZE)
352  return PCX_TOOBIG;
353 
354  // get palette from end of pcx file
355  memcpy(pal,buf+len-768,768);
356 
357  delete [] himap; himap = 0;
358  delete [] bitmap; bitmap = 0;
359 
360  himap = new(__FILE__,__LINE__) unsigned long [imagebytes];
361  if (himap == NULL)
362  return PCX_NOMEM;
363 
364  memset(himap, 0, imagebytes*4);
365 
366  unsigned long* pix = himap;
367  for (i=0; i<imagebytes; i++) {
368  if (mode == BYTEMODE) {
369  abyte = *fp++;
370 
371  if (abyte > 0xbf) {
372  bytecount = abyte & 0x3f;
373  abyte = *fp++;
374  if (--bytecount > 0)
375  mode = RUNMODE;
376  }
377  }
378  else if (--bytecount == 0) {
379  mode = BYTEMODE;
380  }
381 
382  *pix++ = 0xff000000 | (pal[3*abyte] << 16) | (pal[3*abyte+1] << 8) | (pal[3*abyte+2]);
383  }
384  }
385 
386  // read 24-bit (true COLOR) PCX file
387  else {
388  width = 1 + hdr.xmax - hdr.xmin;
389  height = 1 + hdr.ymax - hdr.ymin;
390  imagebytes = width * height;
391 
392  if (imagebytes > MAX_SIZE)
393  return PCX_TOOBIG;
394 
395  delete [] himap; himap = 0;
396  delete [] bitmap; bitmap = 0;
397 
398  himap = new(__FILE__,__LINE__) unsigned long [imagebytes];
399  if (himap == NULL)
400  return PCX_NOMEM;
401 
402  memset(himap, 0, imagebytes*4);
403 
404  for (int row = 0; row < height; row++) {
405  // RED, GREEN, BLUE
406  for (int plane = 2; plane >= 0; plane--) {
407  p = ((unsigned char*) himap) + width*row*4 + plane;
408  for (int col = 0; col < width; col++) {
409  if (mode == BYTEMODE) {
410  abyte = *fp++;
411 
412  if (abyte > 0xbf) {
413  bytecount = abyte & 0x3f;
414  abyte = *fp++;
415  if (--bytecount > 0)
416  mode = RUNMODE;
417  }
418  }
419  else if (--bytecount == 0) {
420  mode = BYTEMODE;
421  }
422 
423  *p = abyte;
424  p += 4;
425  }
426  }
427  }
428  }
429 
430  return PCX_OK;
431 }
432 
433 // +--------------------------------------------------------------------+
434 
435 int PcxImage::Save(char *filename)
436 {
437  short mode=BYTEMODE;
438  FILE *f;
439 
440  fopen_s(&f, filename,"wb");
441  if (f == NULL)
442  return PCX_NOFILE;
443 
444  fwrite(&hdr, sizeof(PcxHeader), 1, f);
445 
446  if (hdr.color_planes == 1) {
447  unsigned char *p = bitmap;
448  unsigned long total = imagebytes;
449  unsigned long row = 0;
450  unsigned char palette_marker = 12;
451 
452  while (total) {
453  unsigned char* start = p;
454  unsigned char count = 0;
455 
456  while (*start == *p && count < 0x3f && row < width) {
457  p++;
458  count++;
459  row++;
460  }
461 
462  if (count > 1 || *start > 0xbf) {
463  unsigned char b[2];
464  b[0] = 0xc0 | count;
465  b[1] = *start;
466  fwrite(b, 2, 1, f);
467  }
468  else {
469  fwrite(start, 1, 1, f);
470  }
471 
472  total -= count;
473 
474  if (row == width)
475  row = 0;
476  }
477 
478  fwrite(&palette_marker,1,1,f);
479  fwrite(pal,768,1,f);
480  }
481 
482  // write 24-bit (TRUE COLOR) PCX file
483  else {
484  for (int row = 0; row < height; row++) {
485  for (int plane = 2; plane >= 0; plane--) {
486  unsigned long col = 0;
487  unsigned char* p = ((unsigned char*) himap) + width*row*4 + plane;
488 
489  while (col < width) {
490  unsigned char* start = p;
491  unsigned char count = 0;
492 
493  while (*start == *p && count < 0x3f && col < width) {
494  p += 4;
495  count++;
496  col++;
497  }
498 
499  if (count > 1 || *start > 0xbf) {
500  unsigned char b[2];
501  b[0] = 0xc0 | count;
502  b[1] = *start;
503  fwrite(b, 2, 1, f);
504  }
505  else {
506  fwrite(start, 1, 1, f);
507  }
508  }
509  }
510  }
511  }
512 
513  fclose(f);
514  return PCX_OK; // return success
515 }
516