1 /*-
2  * tif2ras.c - Converts from a Tagged Image File Format image to a Sun Raster.
3  *
4  * Copyright (c) 1990 by Sun Microsystems, Inc.
5  *
6  * Author: Patrick J. Naughton
7  * naughton@wind.sun.com
8  *
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * Comments and additions should be sent to the author:
22  *
23  *                     Patrick J. Naughton
24  *                     Sun Microsystems
25  *                     2550 Garcia Ave, MS 14-40
26  *                     Mountain View, CA 94043
27  *                     (415) 336-1080
28  *
29  * Revision History:
30  * 10-Jan-89: Created.
31  * 06-Mar-90: Change to byte encoded rasterfiles.
32  *	      fix bug in call to ReadScanline().
33  *	      fix bug in CVT() macro.
34  *	      fix assignment of td, (missing &).
35  *
36  * Description:
37  *   This program takes a MicroSoft/Aldus "Tagged Image File Format" image or
38  * "TIFF" file as input and writes a Sun Rasterfile [see rasterfile(5)].  The
39  * output file may be standard output, but the input TIFF file must be a real
40  * file since seek(2) is used.
41  */
42 
43 #include <stdio.h>
44 #include <pixrect/pixrect_hs.h>
45 #include "tiffio.h"
46 
47 typedef int boolean;
48 #define True (1)
49 #define False (0)
50 #define	CVT(x)		(((x) * 255) / ((1L<<16)-1))
51 
52 boolean     Verbose = False;
53 char       *pname;		/* program name (used for error messages) */
54 
55 void
error(s1,s2)56 error(s1, s2)
57     char       *s1,
58                *s2;
59 {
60     fprintf(stderr, s1, pname, s2);
61     exit(1);
62 }
63 
64 void
usage()65 usage()
66 {
67     error("usage: %s -[vq] TIFFfile [rasterfile]\n", NULL);
68 }
69 
70 
main(argc,argv)71 main(argc, argv)
72     int         argc;
73     char       *argv[];
74 {
75     char       *inf = NULL;
76     char       *outf = NULL;
77     FILE       *fp;
78     long        width,
79                 height;
80     int         depth,
81                 numcolors;
82     register TIFF *tif;
83     TIFFDirectory *td;
84     register u_char *inp,
85                *outp;
86     register int col,
87                 i;
88     register long row;
89     u_char     *Map = NULL;
90     u_char     *buf;
91     short	bitspersample;
92     short	samplesperpixel;
93     short	photometric;
94     u_short    *redcolormap,
95 	       *bluecolormap,
96 	       *greencolormap;
97 
98     Pixrect    *pix;		/* The Sun Pixrect */
99     colormap_t  Colormap;	/* The Pixrect Colormap */
100     u_char      red[256],
101                 green[256],
102                 blue[256];
103 
104     setbuf(stderr, NULL);
105     pname = argv[0];
106 
107     while (--argc) {
108 	if ((++argv)[0][0] == '-')
109 	    switch (argv[0][1]) {
110 	    case 'v':
111 		Verbose = True;
112 		break;
113 	    case 'q':
114 		usage();
115 		break;
116 	    default:
117 		fprintf(stderr, "%s: illegal option -%c.\n", pname,
118 			argv[0][1]);
119 		exit(1);
120 	    }
121 	else if (inf == NULL)
122 	    inf = argv[0];
123 	else if (outf == NULL)
124 	    outf = argv[0];
125 	else
126 	    usage();
127 
128     }
129 
130     if (inf == NULL)
131 	error("%s: can't read input file from a stream.\n", NULL);
132 
133     if (Verbose)
134 	fprintf(stderr, "Reading %s...", inf);
135 
136     tif = TIFFOpen(inf, "r");
137 
138     if (tif == NULL)
139 	error("%s: error opening TIFF file %s", inf);
140 
141     if (Verbose)
142 	TIFFPrintDirectory(tif, stderr, True, False, False);
143     TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
144     if (bitspersample > 8)
145 	error("%s: can't handle more than 8-bits per sample\n", NULL);
146 
147     TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
148     switch (samplesperpixel) {
149     case 1:
150 	if (bitspersample == 1)
151 	    depth = 1;
152 	else
153 	    depth = 8;
154 	break;
155     case 3:
156     case 4:
157 	depth = 24;
158 	break;
159     default:
160 	error("%s: only handle 1-channel gray scale or 3-channel color\n");
161     }
162 
163     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
164     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
165 
166     if (Verbose)
167 	fprintf(stderr, "%dx%dx%d image, ", width, height, depth);
168     if (Verbose)
169 	fprintf(stderr, "%d bits/sample, %d samples/pixel, ",
170 		bitspersample, samplesperpixel);
171 
172     pix = mem_create(width, height, depth);
173     if (pix == (Pixrect *) NULL)
174 	error("%s: can't allocate memory for output pixrect...\n", NULL);
175 
176     numcolors = (1 << bitspersample);
177 
178     TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
179     if (numcolors == 2) {
180 	if (Verbose)
181 	    fprintf(stderr, "monochrome ");
182 	Colormap.type = RMT_NONE;
183 	Colormap.length = 0;
184 	Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = NULL;
185     } else {
186 	switch (photometric) {
187 	case PHOTOMETRIC_MINISBLACK:
188 	    if (Verbose)
189 		fprintf(stderr, "%d graylevels (min=black), ", numcolors);
190 	    Map = (u_char *) malloc(numcolors * sizeof(u_char));
191 	    for (i = 0; i < numcolors; i++)
192 		Map[i] = (255 * i) / numcolors;
193 	    Colormap.type = RMT_EQUAL_RGB;
194 	    Colormap.length = numcolors;
195 	    Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = Map;
196 	    break;
197 	case PHOTOMETRIC_MINISWHITE:
198 	    if (Verbose)
199 		fprintf(stderr, "%d graylevels (min=white), ", numcolors);
200 	    Map = (u_char *) malloc(numcolors * sizeof(u_char));
201 	    for (i = 0; i < numcolors; i++)
202 		Map[i] = 255 - ((255 * i) / numcolors);
203 	    Colormap.type = RMT_EQUAL_RGB;
204 	    Colormap.length = numcolors;
205 	    Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = Map;
206 	    break;
207 	case PHOTOMETRIC_RGB:
208 	    if (Verbose)
209 		fprintf(stderr, "truecolor ");
210 	    Colormap.type = RMT_NONE;
211 	    Colormap.length = 0;
212 	    Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = NULL;
213 	    break;
214 	case PHOTOMETRIC_PALETTE:
215 	    if (Verbose)
216 		fprintf(stderr, "colormapped ");
217 	    Colormap.type = RMT_EQUAL_RGB;
218 	    Colormap.length = numcolors;
219 	    memset(red, 0, sizeof(red));
220 	    memset(green, 0, sizeof(green));
221 	    memset(blue, 0, sizeof(blue));
222 	    TIFFGetField(tif, TIFFTAG_COLORMAP,
223 		&redcolormap, &greencolormap, &bluecolormap);
224 	    for (i = 0; i < numcolors; i++) {
225 		red[i] = (u_char) CVT(redcolormap[i]);
226 		green[i] = (u_char) CVT(greencolormap[i]);
227 		blue[i] = (u_char) CVT(bluecolormap[i]);
228 	    }
229 	    Colormap.map[0] = red;
230 	    Colormap.map[1] = green;
231 	    Colormap.map[2] = blue;
232 	    break;
233 	case PHOTOMETRIC_MASK:
234 	    error("%s: Don't know how to handle PHOTOMETRIC_MASK\n");
235 	    break;
236 	case PHOTOMETRIC_DEPTH:
237 	    error("%s: Don't know how to handle PHOTOMETRIC_DEPTH\n");
238 	    break;
239 	default:
240 	    error("%s: unknown photometric (cmap): %d\n", photometric);
241 	}
242     }
243 
244     buf = (u_char *) malloc(TIFFScanlineSize(tif));
245     if (buf == NULL)
246 	error("%s: can't allocate memory for scanline buffer...\n", NULL);
247 
248     for (row = 0; row < height; row++) {
249 	if (TIFFReadScanline(tif, buf, row, 0) < 0)
250 	    error("%s: bad data read on line: %d\n", row);
251 	inp = buf;
252 	outp = (u_char *) mprd_addr(mpr_d(pix), 0, row);
253 	switch (photometric) {
254 	case PHOTOMETRIC_RGB:
255 	    if (samplesperpixel == 4)
256 		for (col = 0; col < width; col++) {
257 		    *outp++ = *inp++;	/* Blue */
258 		    *outp++ = *inp++;	/* Green */
259 		    *outp++ = *inp++;	/* Red */
260 		    inp++;	/* skip alpha channel */
261 		}
262 	    else
263 		for (col = 0; col < width; col++) {
264 		    *outp++ = *inp++;	/* Blue */
265 		    *outp++ = *inp++;	/* Green */
266 		    *outp++ = *inp++;	/* Red */
267 		}
268 	    break;
269 	case PHOTOMETRIC_MINISWHITE:
270 	case PHOTOMETRIC_MINISBLACK:
271 	    switch (bitspersample) {
272 	    case 1:
273 		for (col = 0; col < ((width + 7) / 8); col++)
274 		    *outp++ = *inp++;
275 		break;
276 	    case 2:
277 		for (col = 0; col < ((width + 3) / 4); col++) {
278 		    *outp++ = (*inp >> 6) & 3;
279 		    *outp++ = (*inp >> 4) & 3;
280 		    *outp++ = (*inp >> 2) & 3;
281 		    *outp++ = *inp++ & 3;
282 		}
283 		break;
284 	    case 4:
285 		for (col = 0; col < width / 2; col++) {
286 		    *outp++ = *inp >> 4;
287 		    *outp++ = *inp++ & 0xf;
288 		}
289 		break;
290 	    case 8:
291 		for (col = 0; col < width; col++)
292 		    *outp++ = *inp++;
293 		break;
294 	    default:
295 		error("%s: bad bits/sample: %d\n", bitspersample);
296 	    }
297 	    break;
298 	case PHOTOMETRIC_PALETTE:
299 	    memcpy(outp, inp, width);
300 	    break;
301 	default:
302 	    error("%s: unknown photometric (write): %d\n", photometric);
303 	}
304     }
305 
306     free((char *) buf);
307 
308     if (Verbose)
309 	fprintf(stderr, "done.\n");
310 
311     if (outf == NULL || strcmp(outf, "Standard Output") == 0) {
312 	outf = "Standard Output";
313 	fp = stdout;
314     } else {
315 	if (!(fp = fopen(outf, "w")))
316 	    error("%s: %s couldn't be opened for writing.\n", outf);
317     }
318 
319     if (Verbose)
320 	fprintf(stderr, "Writing rasterfile in %s...", outf);
321 
322     if (pr_dump(pix, fp, &Colormap, RT_BYTE_ENCODED, 0) == PIX_ERR)
323 	error("%s: error writing Sun Rasterfile: %s\n", outf);
324 
325     if (Verbose)
326 	fprintf(stderr, "done.\n");
327 
328     pr_destroy(pix);
329 
330     if (fp != stdout)
331 	fclose(fp);
332 
333     exit(0);
334 }
335 /*
336  * Local Variables:
337  * mode: c
338  * c-basic-offset: 8
339  * fill-column: 78
340  * End:
341  */
342