PCX.C 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. #pragma off (unreferenced)
  14. static char rcsid[] = "$Id: pcx.c 1.19 1996/09/18 16:38:07 jeremy Exp $";
  15. #pragma on (unreferenced)
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include "pa_enabl.h" //$$POLY_ACC
  20. #include "gr.h"
  21. #include "grdef.h"
  22. #include "mem.h"
  23. #include "pcx.h"
  24. #include "cfile.h"
  25. #include "byteswap.h"
  26. #if defined(POLY_ACC)
  27. #include "poly_acc.h"
  28. #endif
  29. /* PCX Header data type */
  30. typedef struct {
  31. ubyte Manufacturer;
  32. ubyte Version;
  33. ubyte Encoding;
  34. ubyte BitsPerPixel;
  35. short Xmin;
  36. short Ymin;
  37. short Xmax;
  38. short Ymax;
  39. short Hdpi;
  40. short Vdpi;
  41. ubyte ColorMap[16][3];
  42. ubyte Reserved;
  43. ubyte Nplanes;
  44. short BytesPerLine;
  45. ubyte filler[60];
  46. } PCXHeader;
  47. int pcx_get_dimensions( char *filename, int *width, int *height)
  48. {
  49. CFILE *PCXfile;
  50. PCXHeader header;
  51. PCXfile = cfopen(filename, "rb");
  52. if (!PCXfile) return PCX_ERROR_OPENING;
  53. if (cfread(&header, sizeof(PCXHeader), 1, PCXfile) != 1) {
  54. cfclose(PCXfile);
  55. return PCX_ERROR_NO_HEADER;
  56. }
  57. cfclose(PCXfile);
  58. *width = header.Xmax - header.Xmin+1;
  59. *height = header.Ymax - header.Ymin+1;
  60. return PCX_ERROR_NONE;
  61. }
  62. #ifdef MACINTOSH
  63. int pcx_read_bitmap_palette( char *filename, ubyte *palette)
  64. {
  65. PCXHeader header;
  66. CFILE * PCXfile;
  67. ubyte data;
  68. int i;
  69. PCXfile = cfopen( filename , "rb" );
  70. if ( !PCXfile )
  71. return PCX_ERROR_OPENING;
  72. // read 128 char PCX header
  73. if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
  74. cfclose( PCXfile );
  75. return PCX_ERROR_NO_HEADER;
  76. }
  77. // Is it a 256 color PCX file?
  78. if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
  79. cfclose( PCXfile );
  80. return PCX_ERROR_WRONG_VERSION;
  81. }
  82. // Read the extended palette at the end of PCX file
  83. // Read in a character which should be 12 to be extended palette file
  84. if (palette != NULL) {
  85. cfseek( PCXfile, -768, SEEK_END );
  86. cfread( palette, 3, 256, PCXfile );
  87. cfseek( PCXfile, sizeof(PCXHeader), SEEK_SET );
  88. for (i=0; i<768; i++ )
  89. palette[i] >>= 2;
  90. #ifdef MACINTOSH
  91. for (i = 0; i < 3; i++) {
  92. data = palette[i];
  93. palette[i] = palette[765+i];
  94. palette[765+i] = data;
  95. }
  96. #endif
  97. }
  98. }
  99. #endif
  100. //#ifndef MACINTOSH
  101. int pcx_read_bitmap( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette )
  102. {
  103. PCXHeader header;
  104. CFILE * PCXfile;
  105. int i, row, col, count, xsize, ysize;
  106. ubyte data, *pixdata;
  107. #if defined(POLY_ACC)
  108. unsigned char local_pal[768];
  109. pa_flush();
  110. #endif
  111. PCXfile = cfopen( filename , "rb" );
  112. if ( !PCXfile )
  113. return PCX_ERROR_OPENING;
  114. // read 128 char PCX header
  115. if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
  116. cfclose( PCXfile );
  117. return PCX_ERROR_NO_HEADER;
  118. }
  119. // Is it a 256 color PCX file?
  120. if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
  121. cfclose( PCXfile );
  122. return PCX_ERROR_WRONG_VERSION;
  123. }
  124. #ifdef MACINTOSH
  125. header.Xmin = SWAPSHORT(header.Xmin);
  126. header.Xmax = SWAPSHORT(header.Xmax);
  127. header.Ymin = SWAPSHORT(header.Ymin);
  128. header.Ymax = SWAPSHORT(header.Ymax);
  129. #endif
  130. // Find the size of the image
  131. xsize = header.Xmax - header.Xmin + 1;
  132. ysize = header.Ymax - header.Ymin + 1;
  133. #if defined(POLY_ACC)
  134. // Read the extended palette at the end of PCX file
  135. if(bitmap_type == BM_LINEAR15) // need palette for conversion from 8bit pcx to 15bit.
  136. {
  137. cfseek( PCXfile, -768, SEEK_END );
  138. cfread( local_pal, 3, 256, PCXfile );
  139. cfseek( PCXfile, sizeof(PCXHeader), SEEK_SET );
  140. for (i=0; i<768; i++ )
  141. local_pal[i] >>= 2;
  142. pa_save_clut();
  143. pa_update_clut(local_pal, 0, 256, 0);
  144. }
  145. #endif
  146. if ( bitmap_type == BM_LINEAR ) {
  147. if ( bmp->bm_data == NULL ) {
  148. memset( bmp, 0, sizeof( grs_bitmap ) );
  149. bmp->bm_data = malloc( xsize * ysize );
  150. if ( bmp->bm_data == NULL ) {
  151. cfclose( PCXfile );
  152. return PCX_ERROR_MEMORY;
  153. }
  154. bmp->bm_w = bmp->bm_rowsize = xsize;
  155. bmp->bm_h = ysize;
  156. bmp->bm_type = bitmap_type;
  157. }
  158. }
  159. if ( bmp->bm_type == BM_LINEAR ) {
  160. for (row=0; row< ysize ; row++) {
  161. pixdata = &bmp->bm_data[bmp->bm_rowsize*row];
  162. for (col=0; col< xsize ; ) {
  163. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  164. cfclose( PCXfile );
  165. return PCX_ERROR_READING;
  166. }
  167. if ((data & 0xC0) == 0xC0) {
  168. count = data & 0x3F;
  169. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  170. cfclose( PCXfile );
  171. return PCX_ERROR_READING;
  172. }
  173. #ifdef MACINTOSH
  174. if (data == 0)
  175. data = 255;
  176. else if (data == 255)
  177. data = 0;
  178. #endif
  179. memset( pixdata, data, count );
  180. pixdata += count;
  181. col += count;
  182. } else {
  183. #ifdef MACINTOSH
  184. if (data == 0)
  185. data = 255;
  186. else if (data == 255)
  187. data = 0;
  188. #endif
  189. *pixdata++ = data;
  190. col++;
  191. }
  192. }
  193. }
  194. #if defined(POLY_ACC)
  195. } else if( bmp->bm_type == BM_LINEAR15 ) {
  196. ushort *pixdata2, pix15;
  197. PA_DFX (pa_set_backbuffer_current());
  198. PA_DFX (pa_set_write_mode(0));
  199. for (row=0; row< ysize ; row++) {
  200. pixdata2 = (ushort *)&bmp->bm_data[bmp->bm_rowsize*row];
  201. for (col=0; col< xsize ; ) {
  202. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  203. cfclose( PCXfile );
  204. return PCX_ERROR_READING;
  205. }
  206. if ((data & 0xC0) == 0xC0) {
  207. count = data & 0x3F;
  208. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  209. cfclose( PCXfile );
  210. return PCX_ERROR_READING;
  211. }
  212. pix15 = pa_clut[data];
  213. for(i = 0; i != count; ++i) pixdata2[i] = pix15;
  214. pixdata2 += count;
  215. col += count;
  216. } else {
  217. *pixdata2++ = pa_clut[data];
  218. col++;
  219. }
  220. }
  221. }
  222. pa_restore_clut();
  223. PA_DFX (pa_swap_buffer());
  224. PA_DFX (pa_set_frontbuffer_current());
  225. #endif
  226. } else {
  227. for (row=0; row< ysize ; row++) {
  228. for (col=0; col< xsize ; ) {
  229. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  230. cfclose( PCXfile );
  231. return PCX_ERROR_READING;
  232. }
  233. if ((data & 0xC0) == 0xC0) {
  234. count = data & 0x3F;
  235. if (cfread( &data, 1, 1, PCXfile )!=1 ) {
  236. cfclose( PCXfile );
  237. return PCX_ERROR_READING;
  238. }
  239. for (i=0;i<count;i++)
  240. gr_bm_pixel( bmp, col+i, row, data );
  241. col += count;
  242. } else {
  243. gr_bm_pixel( bmp, col, row, data );
  244. col++;
  245. }
  246. }
  247. }
  248. }
  249. // Read the extended palette at the end of PCX file
  250. if ( palette != NULL ) {
  251. // Read in a character which should be 12 to be extended palette file
  252. if (cfread( &data, 1, 1, PCXfile )==1) {
  253. if ( data == 12 ) {
  254. if (cfread(palette,768, 1, PCXfile)!=1) {
  255. cfclose( PCXfile );
  256. return PCX_ERROR_READING;
  257. }
  258. for (i=0; i<768; i++ )
  259. palette[i] >>= 2;
  260. #ifdef MACINTOSH
  261. for (i = 0; i < 3; i++) {
  262. data = palette[i];
  263. palette[i] = palette[765+i];
  264. palette[765+i] = data;
  265. }
  266. #endif
  267. }
  268. } else {
  269. cfclose( PCXfile );
  270. return PCX_ERROR_NO_PALETTE;
  271. }
  272. }
  273. cfclose(PCXfile);
  274. return PCX_ERROR_NONE;
  275. }
  276. //#endif
  277. #if 0 // used to be #ifdef MACINTOSH -- using poly_acc code above now.
  278. //special fast version for Mac - doesn't support SVGA, poly acc, etc.
  279. int pcx_read_bitmap( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette )
  280. {
  281. PCXHeader header;
  282. CFILE * PCXfile;
  283. int i, row, col, count, xsize, ysize;
  284. ubyte data, c;
  285. ubyte row_data[640], *row_ptr, cdata;
  286. int buffer_size, buffer_pos;
  287. ubyte buffer[1024];
  288. ushort colors[256];
  289. PCXfile = cfopen( filename , "rb" );
  290. if ( !PCXfile )
  291. return PCX_ERROR_OPENING;
  292. // read 128 char PCX header
  293. if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
  294. cfclose( PCXfile );
  295. return PCX_ERROR_NO_HEADER;
  296. }
  297. // Is it a 256 color PCX file?
  298. if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
  299. cfclose( PCXfile );
  300. return PCX_ERROR_WRONG_VERSION;
  301. }
  302. #if defined(MACINTOSH)
  303. header.Xmin= swapshort(header.Xmin);
  304. header.Xmax = swapshort(header.Xmax);
  305. header.Ymin = swapshort(header.Ymin);
  306. header.Ymax = swapshort(header.Ymax);
  307. #endif
  308. // Find the size of the image
  309. xsize = header.Xmax - header.Xmin + 1;
  310. ysize = header.Ymax - header.Ymin + 1;
  311. if ( bmp->bm_data == NULL ) {
  312. memset( bmp, 0, sizeof( grs_bitmap ) );
  313. bmp->bm_data = malloc( xsize * ysize );
  314. if ( bmp->bm_data == NULL ) {
  315. cfclose( PCXfile );
  316. return PCX_ERROR_MEMORY;
  317. }
  318. bmp->bm_w = bmp->bm_rowsize = xsize;
  319. bmp->bm_h = ysize;
  320. bmp->bm_type = bitmap_type;
  321. }
  322. // Read the extended palette at the end of PCX file
  323. // Read in a character which should be 12 to be extended palette file
  324. if (palette != NULL) {
  325. cfseek( PCXfile, -768, SEEK_END );
  326. cfread( palette, 3, 256, PCXfile );
  327. cfseek( PCXfile, sizeof(PCXHeader), SEEK_SET );
  328. for (i=0; i<768; i++ )
  329. palette[i] >>= 2;
  330. #ifdef MACINTOSH
  331. for (i = 0; i < 3; i++) {
  332. data = palette[i];
  333. palette[i] = palette[765+i];
  334. palette[765+i] = data;
  335. }
  336. #endif
  337. }
  338. buffer_size = 1024;
  339. buffer_pos = 0;
  340. buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
  341. for (row=0; row< ysize ; row++) {
  342. row_ptr = row_data;
  343. for (col=0; col< xsize ; ) {
  344. data = buffer[buffer_pos++];
  345. if ( buffer_pos == buffer_size ) {
  346. buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
  347. buffer_pos = 0;
  348. }
  349. //cfread( &data, 1, 1, PCXfile )!=1 ) {
  350. if ((data & 0xC0) == 0xC0) {
  351. count = data & 0x3F;
  352. //cfread( &data, 1, 1, PCXfile );
  353. data = buffer[buffer_pos++];
  354. #ifdef MACINTOSH
  355. if (data == 0)
  356. data = 255;
  357. else if (data == 255)
  358. data = 0;
  359. #endif
  360. if ( buffer_pos == buffer_size ) {
  361. buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
  362. buffer_pos = 0;
  363. }
  364. for (i = 0; i<count;i++)
  365. *row_ptr++ = data;
  366. col += count;
  367. } else {
  368. #ifdef MACINTOSH
  369. if (data == 0)
  370. data = 255;
  371. else if (data == 255)
  372. data = 0;
  373. #endif
  374. *row_ptr++ = data;
  375. col++;
  376. }
  377. }
  378. gr_linear_movsd(row_data, &(bmp->bm_data[row * bmp->bm_rowsize]), bmp->bm_w );
  379. }
  380. cfclose(PCXfile);
  381. return PCX_ERROR_NONE;
  382. }
  383. #endif
  384. int pcx_write_bitmap( char * filename, grs_bitmap * bmp, ubyte * palette )
  385. {
  386. int retval;
  387. int i;
  388. ubyte data;
  389. PCXHeader header;
  390. FILE * PCXfile;
  391. memset( &header, 0, sizeof( PCXHeader ) );
  392. header.Manufacturer = 10;
  393. header.Encoding = 1;
  394. header.Nplanes = 1;
  395. header.BitsPerPixel = 8;
  396. header.Version = 5;
  397. header.Xmax = bmp->bm_w-1;
  398. header.Ymax = bmp->bm_h-1;
  399. header.BytesPerLine = bmp->bm_w;
  400. PCXfile = fopen( filename , "wb" );
  401. if ( !PCXfile )
  402. return PCX_ERROR_OPENING;
  403. if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 ) {
  404. fclose( PCXfile );
  405. return PCX_ERROR_WRITING;
  406. }
  407. for (i=0; i<bmp->bm_h; i++ ) {
  408. if (!pcx_encode_line( &bmp->bm_data[bmp->bm_rowsize*i], bmp->bm_w, PCXfile )) {
  409. fclose( PCXfile );
  410. return PCX_ERROR_WRITING;
  411. }
  412. }
  413. // Mark an extended palette
  414. data = 12;
  415. if (fwrite( &data, 1, 1, PCXfile )!=1) {
  416. fclose( PCXfile );
  417. return PCX_ERROR_WRITING;
  418. }
  419. // Write the extended palette
  420. for (i=0; i<768; i++ )
  421. palette[i] <<= 2;
  422. retval = fwrite( palette, 768, 1, PCXfile );
  423. for (i=0; i<768; i++ )
  424. palette[i] >>= 2;
  425. if (retval !=1) {
  426. fclose( PCXfile );
  427. return PCX_ERROR_WRITING;
  428. }
  429. fclose( PCXfile );
  430. return PCX_ERROR_NONE;
  431. }
  432. // subroutine for writing an encoded byte pair
  433. // returns count of bytes written, 0 if error
  434. int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid)
  435. {
  436. if (cnt) {
  437. if ( (cnt==1) && (0xc0 != (0xc0 & byt)) ) {
  438. if(EOF == putc((int)byt, fid))
  439. return 0; // disk write error (probably full)
  440. return 1;
  441. } else {
  442. if(EOF == putc((int)0xC0 | cnt, fid))
  443. return 0; // disk write error
  444. if(EOF == putc((int)byt, fid))
  445. return 0; // disk write error
  446. return 2;
  447. }
  448. }
  449. return 0;
  450. }
  451. // returns number of bytes written into outBuff, 0 if failed
  452. int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
  453. {
  454. ubyte this, last;
  455. int srcIndex, i;
  456. register int total;
  457. register ubyte runCount; // max single runlength is 63
  458. total = 0;
  459. last = *(inBuff);
  460. runCount = 1;
  461. for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
  462. this = *(++inBuff);
  463. if (this == last) {
  464. runCount++; // it encodes
  465. if (runCount == 63) {
  466. if (!(i=pcx_encode_byte(last, runCount, fp)))
  467. return(0);
  468. total += i;
  469. runCount = 0;
  470. }
  471. } else { // this != last
  472. if (runCount) {
  473. if (!(i=pcx_encode_byte(last, runCount, fp)))
  474. return(0);
  475. total += i;
  476. }
  477. last = this;
  478. runCount = 1;
  479. }
  480. }
  481. if (runCount) { // finish up
  482. if (!(i=pcx_encode_byte(last, runCount, fp)))
  483. return 0;
  484. return total + i;
  485. }
  486. return total;
  487. }
  488. //text for error messges
  489. char pcx_error_messages[] = {
  490. "No error.\0"
  491. "Error opening file.\0"
  492. "Couldn't read PCX header.\0"
  493. "Unsupported PCX version.\0"
  494. "Error reading data.\0"
  495. "Couldn't find palette information.\0"
  496. "Error writing data.\0"
  497. };
  498. //function to return pointer to error message
  499. char *pcx_errormsg(int error_number)
  500. {
  501. char *p = pcx_error_messages;
  502. while (error_number--) {
  503. if (!p) return NULL;
  504. p += strlen(p)+1;
  505. }
  506. return p;
  507. }