1 /* spctoppm.c - read a compressed Spectrum file and produce a portable pixmap
2 **
3 ** Copyright (C) 1991 by Steve Belczyk and Jef Poskanzer
4 **
5 ** Permission to use, copy, modify, and distribute this software and its
6 ** documentation for any purpose and without fee is hereby granted, provided
7 ** that the above copyright notice appear in all copies and that both that
8 ** copyright notice and this permission notice appear in supporting
9 ** documentation. This software is provided "as is" without express or
10 ** implied warranty.
11 */
12
13 #include "ppm.h"
14
15 #define ROWS 200
16 #define COLS 320
17 #define MAXVAL 7
18
19 static void DoBitmap ARGS(( FILE* ifp ));
20 static void DoChar ARGS(( int n, char c ));
21 static void DoColormap ARGS(( FILE* ifp ));
22
23 static char screen[ROWS*COLS/2];
24 static short sscreen[ROWS*COLS/4];
25 static pixel pal[ROWS][48];
26 static long colormap_length, bitmap_length;
27
28 int
main(argc,argv)29 main( argc, argv )
30 int argc;
31 char* argv[];
32 {
33 FILE* ifp;
34 char c1, c2;
35 pixel* pixelrow;
36 register pixel* pP;
37 int row, col;
38
39
40 ppm_init( &argc, argv );
41
42 /* Check args. */
43 if ( argc > 2 )
44 pm_usage( "[spcfile]" );
45
46 if ( argc == 2 )
47 ifp = pm_openr( argv[1] );
48 else
49 ifp = stdin;
50
51 /* Check SPC file header. */
52 c1 = getc( ifp );
53 c2 = getc( ifp );
54
55 if ( ( c1 != 'S' ) || ( c2 != 'P' ) )
56 pm_error( "not a Spectrum picture" );
57
58 /* Skip reserved bytes. */
59 getc( ifp );
60 getc( ifp );
61
62 /* Get length of bitmap data. */
63 (void) pm_readbiglong( ifp, &bitmap_length );
64
65 /* and colormap */
66 (void) pm_readbiglong( ifp, &colormap_length );
67
68 /* Process bitmap. */
69 DoBitmap( ifp );
70
71 /* Process colormap. */
72 DoColormap( ifp );
73
74 pm_close( ifp );
75
76 /* Write the PPM file. */
77 ppm_writeppminit( stdout, COLS, ROWS, (pixval) MAXVAL, 0 );
78 pixelrow = ppm_allocrow( COLS );
79
80 for ( row = 0; row < ROWS; ++row )
81 {
82 for ( col = 0, pP = pixelrow; col < COLS; ++col, ++pP )
83 {
84 int c, ind, b, plane, x1;
85
86 /* Compute pixel value. */
87 ind = ( 80 * row ) + ( ( col >> 4 ) << 2 );
88 b = 0x8000 >> (col & 0xf);
89 c = 0;
90 for ( plane = 0; plane < 4; ++plane )
91 if ( b & sscreen[ind+plane] )
92 c |= (1 << plane);
93
94 /* Compute palette index. */
95 x1 = 10 * c;
96 if ( c & 1 )
97 x1 -= 5;
98 else
99 ++x1;
100 if ( ( col >= x1 ) && ( col < ( x1 + 160 ) ) )
101 c += 16;
102 if ( col >= ( x1 + 160 ) )
103 c += 32;
104
105 /* Store the proper color. */
106 *pP = pal[row][c];
107 }
108 ppm_writeppmrow( stdout, pixelrow, COLS, (pixval) MAXVAL, 0 );
109 }
110
111 pm_close( stdout );
112
113 exit( 0 );
114 }
115
116 static void
DoBitmap(ifp)117 DoBitmap( ifp )
118 FILE* ifp;
119 {
120 int i;
121 long count, data;
122 signed char h, c;
123
124 /* Zero out first scan line. */
125 for ( i = 0; i < 160; ++i )
126 screen[i] = 0;
127
128 /* 'count' counts number of input bytes. */
129 count = 0;
130
131 /* 'data' counts just data bytes. */
132 data = 0;
133
134 while ( count < bitmap_length )
135 {
136 /* Get next record header. */
137 h = getc( ifp );
138 ++count;
139
140 if ( ( h >= 0 ) && ( count < bitmap_length ) )
141 {
142 for ( i = 0; i <= h; ++i )
143 {
144 c = getc( ifp );
145 ++count;
146 DoChar( data, c );
147 ++data;
148 }
149 }
150 else if ( ( h < 0 ) && ( count < bitmap_length ) )
151 {
152 c = getc( ifp );
153 ++count;
154
155 for ( i = 0; i < ( 2 - h ); ++i )
156 {
157 DoChar( data, c );
158 ++data;
159 }
160 }
161 }
162
163 /* Convert the char version of the screen to short. */
164 for ( i = 0; i < ROWS*COLS/4; ++i )
165 sscreen[i] = ( screen[i<<1] << 8 ) + ( 0xff & screen[(i<<1)+1] );
166 }
167
168 static void
DoChar(int n,char c)169 DoChar( int n, char c )
170 {
171 int i;
172
173 /* Compute screen index. */
174 i = 160 + 2 * ( n / 7960 ) + 8 * ( ( n % 7960 ) / 2 ) + ( n & 1 );
175 screen[i] = c;
176 }
177
178 static void
DoColormap(ifp)179 DoColormap( ifp )
180 FILE* ifp;
181 {
182 int i, j, b;
183 short mask;
184
185 /* Clear first three palettes. */
186 for ( j = 0; j < 48; ++j )
187 PPM_ASSIGN( pal[0][j], 0, 0, 0 );
188
189 /* Read the palettes. */
190 for ( i = 1; i < ROWS; ++i )
191 for ( j = 0; j < 3; ++j )
192 {
193 (void) pm_readbigshort( ifp, &mask );
194 for ( b = 0; b < 15; ++b )
195 if ( mask & ( 1 << b ) )
196 {
197 short k;
198 (void) pm_readbigshort( ifp, &k );
199 PPM_ASSIGN( pal[i][(j*16)+b],
200 ( k & 0x700 ) >> 8,
201 ( k & 0x070 ) >> 4,
202 ( k & 0x007 ) );
203 }
204 }
205 }
206