Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rletopaint.c
Go to the documentation of this file.
1 /*
2  * This software is copyrighted as noted below. It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is". Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  */
18 /*
19  * rletopaint.c - Convert an RLE file to macpaint format, using dithering.
20  *
21  * Author: John W. Peterson
22  * Computer Science Dept.
23  * University of Utah
24  * Date: Thu Oct 16 1986
25  * Copyright (c) 1986, John W. Peterson
26  *
27  * Byte compression code (compress_line) by Jim Schimpf.
28  *
29  * Usage is:
30  * rle2paint [-l] [-i] [-g [gamma]] [-o outfile.paint] [infile.rle]
31  *
32  * -l Uses a linear color map in converting the RLE image
33  * -r Invert the bits in the MacPaint output.
34  * -g [gamma] Use a gamma map of [gamma] in converting the output
35  * (default is 2.0)
36  * infile.rle If specified, the input RLE file. Default stdin.
37  * -o outfile If specified, the MacPaint file will be written here.
38  * Default stdout.
39  *
40  * Note that the image should be flipped vertically (by rleflip, e.g.),
41  * as the two formats number their scanlines oppositely.
42  */
43 static char rcsid[] = "$Header: /tmp_mnt/n/itn/hendrix/u/spencer/RCS/rletopaint.c,v 3.0.1.3 1992/04/30 14:00:05 spencer Exp spencer $";
44 /*
45 rletopaint() Tag the file.
46 */
47 
48 
49 #include <stdio.h>
50 #include "rle.h"
51 #include <math.h>
52 
53 #define MIN(x,y) ( (x) < (y) ? (x) : (y) )
54 
55 /* Scanline storage & RLE row pointers */
56 rle_hdr hdr;
58 
59 int gammamap[256];
60 unsigned char rawbits[73]; /* Uncompressed MacPaint pixels */
61 unsigned char squishedbits[74]; /* Compressed data */
62 int inverse_flag = 0; /* If true then invert image */
63 
64 /* Gray scale dither table */
65 int dmgray[8][8] = { 0 ,128 , 32 ,160 , 8 ,136 , 40 ,168 ,
66  192 , 64 ,224 , 96 ,200 , 72 ,232 ,104 ,
67  48 ,176 , 16 ,144 , 56 ,184 , 24 ,152 ,
68  240 ,112 ,208 , 80 ,248 ,120 ,216 , 88 ,
69  12 ,140 , 44 ,172 , 4 ,132 , 36 ,164 ,
70  204 , 76 ,236 ,108 ,196 , 68 ,228 ,100 ,
71  60 ,188 , 28 ,156 , 52 ,220 , 20 ,148 ,
72  252 ,124 ,220 , 92 ,244 ,116 ,212 ,84 } ;
73 
74 int compress_line();
75 void write_paint_line(), bytes_to_bits();
76 
77 void
79 int argc;
80 char *argv[];
81 {
82  int i;
83  int databytes;
84  float gam = 2.0; /* Default gamma */
85  int gamma_flag = 0, oflag = 0;
86  int linear_flag = 1;
87  char * fname = NULL, * out_fname = NULL;
88  FILE * out_fp;
89 
90  if ( scanargs( argc, argv, "% r%- l%- g%-gamma%f o%-outfile!s infile%s",
91  &inverse_flag, &linear_flag,
92  &gamma_flag, &gam, &oflag, &out_fname, &fname ) == 0)
93  exit(-1);
94 
95  if (gamma_flag) linear_flag = 0;
96  /* Initialize header. */
97  hdr = *rle_hdr_init( (rle_hdr *)NULL );
98  rle_names( &hdr, cmd_name( argv ), fname, 0 );
99 
101  rle_get_setup_ok( &hdr, NULL, NULL );
102 
103  out_fp = rle_open_f(hdr.cmd, out_fname, "w");
104 
105  /* set up rows to point to our copy of the scanline */
106  if (rle_row_alloc( &hdr, &rows ))
107  {
108  fprintf(stderr,"%s: malloc failed\n", hdr.cmd);
109  exit(-2);
110  }
111 
112  /* Compute a gamma correction map and tables */
113  for ( i = 0; i < 256; i++ )
114  {
115  if (linear_flag)
116  gammamap[i] = i;
117  else
118  gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gam ));
119  }
120 
121  /* Output MacPaint header */
122  for (i = 0; i < 512; i++)
123  putc('\0', out_fp); /* Null tells MacPaint to ignore header */
124 
125  for (i = 0; i < 72; i++) /* Kludge - pad bottom with blank lines */
126  rawbits[i] = 0;
127 
128  /* If the picture doesn't start at the bottom, output blank lines
129  * to fill the space */
130 
131  databytes = compress_line(); /* Blank compressed data */
132  for (i = 0; i < hdr.ymin; i++)
133  write_paint_line(databytes, out_fp);
134 
135  for (i = hdr.ymin; i <= MIN( hdr.ymax, 719 ); i++)
136  {
138  bytes_to_bits( i );
139  write_paint_line(compress_line(), out_fp);
140  }
141 
142  /* Finish up unused picture space */
143  if (hdr.ymax < 719)
144  {
145  for (i = 0; i < 72; i++) /* Kludge - pad bottom with blank lines */
146  rawbits[i] = 0;
147 
148  databytes = compress_line(); /* Blank compressed data */
149  for (i = hdr.ymax+1; i < 720; i++)
150  write_paint_line(databytes, out_fp);
151  }
152 }
153 
154 
155 /* Write a scanline to the macpaint file. */
156 void
157 write_paint_line(num, fp)
158 int num;
159 FILE *fp;
160 {
161  int j;
162  for (j = 0; j < num; j++)
163  putc(squishedbits[j], fp);
164 }
165 
166 /*
167  * Map a 24 bit scanline through to get dithered black and white, generating
168  * a row of bits in rawbits.
169  */
170 void
171 bytes_to_bits( y )
172 int y;
173 {
174  register unsigned char *r, *g, *b;
175  register int i, col, row;
176  int pixel;
177  int n = MIN(hdr.xmax, 576);
178  int B = 0, W = 1;
179 
180  if (inverse_flag)
181  {
182  B = 1; W = 0; /* Swap meaning of Black and White */
183  }
184  for (i = 0; i < 72; i++)
185  rawbits[i] = 0;
186 
187  r = g = b = rows[0];
188  if ( hdr.ncolors > 1 )
189  g = rows[1];
190  if ( hdr.ncolors > 2 )
191  b = rows[2];
192  for ( row = y % 8, col = 0, i = 0;
193  i < n;
194  i++, r++, g++, b++, col = ((col + 1) & 7) )
195  {
196  /* Conver to BW (uses YIQ/percentage xformation) */
197  if ( hdr.ncolors > 2 )
198  pixel = (35*gammamap[*r] + 55*gammamap[*g] + 10*gammamap[*b]) / 100;
199  else if ( hdr.ncolors == 2 )
200  pixel = (gammamap[*r] + gammamap[*g]) / 2;
201  else
202  pixel = gammamap[*r];
203  if (pixel < 0) pixel += 256;
204 
205  /* Use dither to convert to zero/one */
206  pixel = ((pixel > dmgray[col][row]) ? W : B);
207 
208  /* Compress scanline bytes to unencoded macpaint bits */
209  rawbits[(i / 8)] |= pixel << (7-(i % 8));
210  }
211 }
212 
213 /*
214  * Compress the bits in rawbits to run-length encoded bytes in squishedbits.
215  *
216  * Compression is as follows:
217  *
218  * <CNT><Byte><Byte>... If <CNT> < 0x80 i.e. <CNT> different bytes
219  * <CNT><Byte> If <CNT> > 0x80 i.e. <CNT> repeated bytes
220  *
221  */
222 
223 int
224 compress_line()
225 {
226  int i,j,k = 0,cntpsn,count = 0;
227  int flag;
228  unsigned char pixel;
229 #define SAME 1
230 #define NOTSAME 0
231 
232  i = 0;
233  j = 2;
234  if( rawbits[0] == rawbits[1] )
235  {
236  flag = SAME;
237  cntpsn = 0;
238  squishedbits[1] = rawbits[0];
239  }
240  else
241  {
242  flag = NOTSAME;
243  cntpsn = 0;
244  squishedbits[1] = rawbits[0];
245  }
246 
247  while( i < 72 )
248  {
249  switch( flag )
250  {
251 
252  /* Same case see how far the run goes then update stuff */
253 
254  case SAME:
255  count = 0;
256  for( k=i; k<72; k++ )
257  {
258  if( squishedbits[j-1] != rawbits[k] )
259  break;
260  else
261  count++;
262  }
263 
264  /* If count is zero then just skip all this stuff and try again
265  * with the flag the other way
266  */
267  if( count != 0 )
268  {
269 
270  /* Ok update the count and save the byte in the output line
271  * NOTE: Count is just 2's compliment of the value
272  */
273  pixel = -1 * (count-1);
274  squishedbits[cntpsn] = 0xff & pixel;
275 
276  /* Set the flag for the other & advance j to next frame */
277 
278  flag = NOTSAME;
279  }
280  else
281  flag = NOTSAME;
282  break;
283 
284  /* Not the same, look for a run of something if found quit */
285 
286  case NOTSAME:
287  count = 0;
288  for( k=i+1; k<72; k++ )
289  {
290  if( squishedbits[j-1] == rawbits[k] )
291  break;
292  else
293  {
294  count++;
295  squishedbits[j++] = rawbits[k];
296  }
297  }
298  /* If count is zero then skip all the updating stuff and just try
299  * the other method
300  */
301  if( count != 0 )
302  {
303  if ( k == 72 )
304  squishedbits[cntpsn] = count;
305  else
306  {
307  squishedbits[cntpsn] = count - 1;
308 
309  /* Set the flag for the other and back up the psn
310  * to get the start of the run.
311  */
312 
313  k = k - 1;
314  j--;
315  flag = SAME;
316  }
317  }
318  else
319  flag = SAME;
320  break;
321  }
322 
323 
324  /* End of loop update the positions of the count save lcn and
325  * next character to look at
326  *
327  * Only do update on non zero counts
328  */
329 
330  if( count != 0 )
331  {
332  /* Sometimes 'compression' doesn't. Check for this. */
333  if ( j > k + 1 )
334  {
335  squishedbits[0] = k - 1;
336  for ( j = 0; j < k; j++ )
337  squishedbits[j + 1] = rawbits[j];
338  j++;
339  }
340  cntpsn = j;
341  squishedbits[++j] = rawbits[k];
342  j++;
343  i = k;
344  }
345  }
346 
347  return( j-2 );
348 }
FILE * rle_open_f(char *prog_name, char *file_name, char *mode)
Definition: rle_open_f.c:216
#define MIN(x, y)
Definition: rletopaint.c:53
rle_hdr hdr
Definition: getx10.c:84
unsigned char rawbits[73]
Definition: rletopaint.c:60
void rle_names(rle_hdr *the_hdr, const char *pgmname, const char *fname, int img_num)
Definition: rle_hdr.c:48
#define NOTSAME
char * cmd_name(char **argv)
Definition: cmd_name.c:31
void main(int argc, char **argv)
Definition: aliastorle.c:121
int rle_row_alloc(rle_hdr *the_hdr, rle_pixel ***scanp)
Definition: rle_row_alc.c:56
int rle_getrow(rle_hdr *the_hdr, scanline)
Definition: rle_getrow.c:333
int ymin
Definition: rle.h:100
static char rcsid[]
Definition: rletopaint.c:43
int scanargs(int argc, char **argv, const char *format,...)
Definition: scanargs.c:94
const char * cmd
Definition: rle.h:133
int dmgray[8][8]
Definition: rletopaint.c:65
int xmax
Definition: rle.h:100
#define SAME
void rle_get_setup_ok(rle_hdr *the_hdr, const char *prog_name, const char *file_name)
Definition: rle_getrow.c:254
int inverse_flag
Definition: getap.c:82
int ymax
Definition: rle.h:100
unsigned char squishedbits[74]
Definition: rletopaint.c:61
unsigned char rle_pixel
Definition: rle.h:56
int gammamap[256]
Definition: getx10.c:68
rle_hdr * rle_hdr_init(rle_hdr *the_hdr)
Definition: rle_hdr.c:267
unsigned char * rows[4]
Definition: getbob.c:52
FILE * rle_file
Definition: rle.h:114
int ncolors
Definition: rle.h:100