1/* $Id: raw2tiff.c 276 2010-06-30 12:18:30Z nijtmans $
2 *
3 * Project:  libtiff tools
4 * Purpose:  Convert raw byte sequences in TIFF images
5 * Author:   Andrey Kiselev, dron@ak4719.spb.edu
6 *
7 ******************************************************************************
8 * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
9 *
10 * Permission to use, copy, modify, distribute, and sell this software and
11 * its documentation for any purpose is hereby granted without fee, provided
12 * that (i) the above copyright notices and this permission notice appear in
13 * all copies of the software and related documentation, and (ii) the names of
14 * Sam Leffler and Silicon Graphics may not be used in any advertising or
15 * publicity relating to the software without the specific, prior written
16 * permission of Sam Leffler and Silicon Graphics.
17 *
18 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
20 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
21 *
22 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
23 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
24 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
25 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
26 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
27 * OF THIS SOFTWARE.
28 */
29
30#include "tif_config.h"
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include <math.h>
38#include <ctype.h>
39
40#ifdef HAVE_UNISTD_H
41# include <unistd.h>
42#endif
43
44#if HAVE_FCNTL_H
45# include <fcntl.h>
46#endif
47
48#if HAVE_SYS_TYPES_H
49# include <sys/types.h>
50#endif
51
52#if HAVE_IO_H
53# include <io.h>
54#endif
55
56#include "tiffio.h"
57
58#ifndef HAVE_GETOPT
59extern int getopt(int, char**, char*);
60#endif
61
62#ifndef O_BINARY
63# define O_BINARY 0
64#endif
65
66typedef enum {
67	PIXEL,
68	BAND
69} InterleavingType;
70
71static	uint16 compression = (uint16) -1;
72static	int jpegcolormode = JPEGCOLORMODE_RGB;
73static	int quality = 75;		/* JPEG quality */
74static	uint16 predictor = 0;
75
76static void swapBytesInScanline(void *, uint32, TIFFDataType);
77static int guessSize(int, TIFFDataType, off_t, uint32, int,
78		     uint32 *, uint32 *);
79static double correlation(void *, void *, uint32, TIFFDataType);
80static void usage(void);
81static	int processCompressOptions(char*);
82
83int
84main(int argc, char* argv[])
85{
86	uint32	width = 0, length = 0, linebytes, bufsize;
87	uint32	nbands = 1;		    /* number of bands in input image*/
88	off_t	hdr_size = 0;		    /* size of the header to skip */
89	TIFFDataType dtype = TIFF_BYTE;
90	int16	depth = 1;		    /* bytes per pixel in input image */
91	int	swab = 0;		    /* byte swapping flag */
92	InterleavingType interleaving = 0;  /* interleaving type flag */
93	uint32  rowsperstrip = (uint32) -1;
94	uint16	photometric = PHOTOMETRIC_MINISBLACK;
95	uint16	config = PLANARCONFIG_CONTIG;
96	uint16	fillorder = FILLORDER_LSB2MSB;
97	int	fd;
98	char	*outfilename = NULL;
99	TIFF	*out;
100
101	uint32 row, col, band;
102	int	c;
103	unsigned char *buf = NULL, *buf1 = NULL;
104	extern int optind;
105	extern char* optarg;
106
107	while ((c = getopt(argc, argv, "c:r:H:w:l:b:d:LMp:si:o:h")) != -1) {
108		switch (c) {
109		case 'c':		/* compression scheme */
110			if (!processCompressOptions(optarg))
111				usage();
112			break;
113		case 'r':		/* rows/strip */
114			rowsperstrip = atoi(optarg);
115			break;
116		case 'H':		/* size of input image file header */
117			hdr_size = atoi(optarg);
118			break;
119		case 'w':		/* input image width */
120			width = atoi(optarg);
121			break;
122		case 'l':		/* input image length */
123			length = atoi(optarg);
124			break;
125		case 'b':		/* number of bands in input image */
126			nbands = atoi(optarg);
127			break;
128		case 'd':		/* type of samples in input image */
129			if (strncmp(optarg, "byte", 4) == 0)
130				dtype = TIFF_BYTE;
131			else if (strncmp(optarg, "short", 5) == 0)
132				dtype = TIFF_SHORT;
133			else if  (strncmp(optarg, "long", 4) == 0)
134				dtype = TIFF_LONG;
135			else if  (strncmp(optarg, "sbyte", 5) == 0)
136				dtype = TIFF_SBYTE;
137			else if  (strncmp(optarg, "sshort", 6) == 0)
138				dtype = TIFF_SSHORT;
139			else if  (strncmp(optarg, "slong", 5) == 0)
140				dtype = TIFF_SLONG;
141			else if  (strncmp(optarg, "float", 5) == 0)
142				dtype = TIFF_FLOAT;
143			else if  (strncmp(optarg, "double", 6) == 0)
144				dtype = TIFF_DOUBLE;
145			else
146				dtype = TIFF_BYTE;
147			depth = TIFFDataWidth(dtype);
148			break;
149		case 'L':		/* input has lsb-to-msb fillorder */
150			fillorder = FILLORDER_LSB2MSB;
151			break;
152		case 'M':		/* input has msb-to-lsb fillorder */
153			fillorder = FILLORDER_MSB2LSB;
154			break;
155		case 'p':		/* photometric interpretation */
156			if (strncmp(optarg, "miniswhite", 10) == 0)
157				photometric = PHOTOMETRIC_MINISWHITE;
158			else if (strncmp(optarg, "minisblack", 10) == 0)
159				photometric = PHOTOMETRIC_MINISBLACK;
160			else if (strncmp(optarg, "rgb", 3) == 0)
161				photometric = PHOTOMETRIC_RGB;
162			else if (strncmp(optarg, "cmyk", 4) == 0)
163				photometric = PHOTOMETRIC_SEPARATED;
164			else if (strncmp(optarg, "ycbcr", 5) == 0)
165				photometric = PHOTOMETRIC_YCBCR;
166			else if (strncmp(optarg, "cielab", 6) == 0)
167				photometric = PHOTOMETRIC_CIELAB;
168			else if (strncmp(optarg, "icclab", 6) == 0)
169				photometric = PHOTOMETRIC_ICCLAB;
170			else if (strncmp(optarg, "itulab", 6) == 0)
171				photometric = PHOTOMETRIC_ITULAB;
172			else
173				photometric = PHOTOMETRIC_MINISBLACK;
174			break;
175		case 's':		/* do we need to swap bytes? */
176			swab = 1;
177			break;
178		case 'i':		/* type of interleaving */
179			if (strncmp(optarg, "pixel", 4) == 0)
180				interleaving = PIXEL;
181			else if  (strncmp(optarg, "band", 6) == 0)
182				interleaving = BAND;
183			else
184				interleaving = 0;
185			break;
186		case 'o':
187			outfilename = optarg;
188			break;
189		case 'h':
190			usage();
191		default:
192			break;
193		}
194        }
195
196        if (argc - optind < 2)
197		usage();
198
199        fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
200	if (fd < 0) {
201		fprintf(stderr, "%s: %s: Cannot open input file.\n",
202			argv[0], argv[optind]);
203		return (-1);
204	}
205
206	if (guessSize(fd, dtype, hdr_size, nbands, swab, &width, &length) < 0)
207		return 1;
208
209	if (outfilename == NULL)
210		outfilename = argv[optind+1];
211	out = TIFFOpen(outfilename, "w");
212	if (out == NULL) {
213		fprintf(stderr, "%s: %s: Cannot open file for output.\n",
214			argv[0], outfilename);
215		return (-1);
216	}
217	TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
218	TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
219	TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
220	TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
221	TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth * 8);
222	TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
223	TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
224	TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
225	switch (dtype) {
226	case TIFF_BYTE:
227	case TIFF_SHORT:
228	case TIFF_LONG:
229		TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
230		break;
231	case TIFF_SBYTE:
232	case TIFF_SSHORT:
233	case TIFF_SLONG:
234		TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
235		break;
236	case TIFF_FLOAT:
237	case TIFF_DOUBLE:
238		TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
239		break;
240	default:
241		TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_VOID);
242		break;
243	}
244	if (compression == (uint16) -1)
245		compression = COMPRESSION_PACKBITS;
246	TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
247	switch (compression) {
248	case COMPRESSION_JPEG:
249		if (photometric == PHOTOMETRIC_RGB
250		    && jpegcolormode == JPEGCOLORMODE_RGB)
251			photometric = PHOTOMETRIC_YCBCR;
252		TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
253		TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
254		break;
255	case COMPRESSION_LZW:
256	case COMPRESSION_DEFLATE:
257		if (predictor != 0)
258			TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
259		break;
260	}
261	switch(interleaving) {
262	case BAND:				/* band interleaved data */
263		linebytes = width * depth;
264		buf = (unsigned char *)_TIFFmalloc(linebytes);
265		break;
266	case PIXEL:				/* pixel interleaved data */
267	default:
268		linebytes = width * nbands * depth;
269		break;
270	}
271	bufsize = width * nbands * depth;
272	buf1 = (unsigned char *)_TIFFmalloc(bufsize);
273
274	rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
275	if (rowsperstrip > length) {
276		rowsperstrip = length;
277	}
278	TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip );
279
280	lseek(fd, hdr_size, SEEK_SET);		/* Skip the file header */
281	for (row = 0; row < length; row++) {
282		switch(interleaving) {
283		case BAND:			/* band interleaved data */
284			for (band = 0; band < nbands; band++) {
285				lseek(fd,
286				      hdr_size + (length*band+row)*linebytes,
287				      SEEK_SET);
288				if (read(fd, buf, linebytes) < 0) {
289					fprintf(stderr,
290					"%s: %s: scanline %lu: Read error.\n",
291					argv[0], argv[optind],
292					(unsigned long) row);
293				break;
294				}
295				if (swab)	/* Swap bytes if needed */
296					swapBytesInScanline(buf, width, dtype);
297				for (col = 0; col < width; col++)
298					memcpy(buf1 + (col*nbands+band)*depth,
299					       buf + col * depth, depth);
300			}
301			break;
302		case PIXEL:			/* pixel interleaved data */
303		default:
304			if (read(fd, buf1, bufsize) < 0) {
305				fprintf(stderr,
306					"%s: %s: scanline %lu: Read error.\n",
307					argv[0], argv[optind],
308					(unsigned long) row);
309				break;
310			}
311			if (swab)		/* Swap bytes if needed */
312				swapBytesInScanline(buf1, width, dtype);
313			break;
314		}
315
316		if (TIFFWriteScanline(out, buf1, row, 0) < 0) {
317			fprintf(stderr,	"%s: %s: scanline %lu: Write error.\n",
318				argv[0], outfilename, (unsigned long) row);
319			break;
320		}
321	}
322	if (buf)
323		_TIFFfree(buf);
324	if (buf1)
325		_TIFFfree(buf1);
326	TIFFClose(out);
327	return (0);
328}
329
330static void
331swapBytesInScanline(void *buf, uint32 width, TIFFDataType dtype)
332{
333	switch (dtype) {
334		case TIFF_SHORT:
335		case TIFF_SSHORT:
336			TIFFSwabArrayOfShort((uint16*)buf,
337                                             (unsigned long)width);
338			break;
339		case TIFF_LONG:
340		case TIFF_SLONG:
341			TIFFSwabArrayOfLong((uint32*)buf,
342                                            (unsigned long)width);
343			break;
344		/* case TIFF_FLOAT: */	/* FIXME */
345		case TIFF_DOUBLE:
346			TIFFSwabArrayOfDouble((double*)buf,
347                                              (unsigned long)width);
348			break;
349		default:
350			break;
351	}
352}
353
354static int
355guessSize(int fd, TIFFDataType dtype, off_t hdr_size, uint32 nbands,
356	  int swab, uint32 *width, uint32 *length)
357{
358	const float longt = 40.0;    /* maximum possible height/width ratio */
359	char	    *buf1, *buf2;
360	struct stat filestat;
361	uint32	    w, h, scanlinesize, imagesize;
362	uint32	    depth = TIFFDataWidth(dtype);
363	float	    cor_coef = 0, tmp;
364
365	fstat(fd, &filestat);
366
367	if (filestat.st_size < hdr_size) {
368		fprintf(stderr, "Too large header size specified.\n");
369		return -1;
370	}
371
372	imagesize = (filestat.st_size - hdr_size) / nbands / depth;
373
374	if (*width != 0 && *length == 0) {
375		fprintf(stderr,	"Image height is not specified.\n");
376
377		*length = imagesize / *width;
378
379		fprintf(stderr, "Height is guessed as %lu.\n",
380			(unsigned long)*length);
381
382		return 1;
383	} else if (*width == 0 && *length != 0) {
384		fprintf(stderr, "Image width is not specified.\n");
385
386		*width = imagesize / *length;
387
388		fprintf(stderr,	"Width is guessed as %lu.\n",
389			(unsigned long)*width);
390
391		return 1;
392	} else if (*width == 0 && *length == 0) {
393		fprintf(stderr,	"Image width and height are not specified.\n");
394
395		for (w = (uint32) sqrt(imagesize / longt);
396		     w < sqrt(imagesize * longt);
397		     w++) {
398			if (imagesize % w == 0) {
399				scanlinesize = w * depth;
400				buf1 = _TIFFmalloc(scanlinesize);
401				buf2 = _TIFFmalloc(scanlinesize);
402				h = imagesize / w;
403				lseek(fd, hdr_size + (int)(h/2)*scanlinesize,
404				      SEEK_SET);
405				read(fd, buf1, scanlinesize);
406				read(fd, buf2, scanlinesize);
407				if (swab) {
408					swapBytesInScanline(buf1, w, dtype);
409					swapBytesInScanline(buf2, w, dtype);
410				}
411				tmp = (float) fabs(correlation(buf1, buf2,
412							       w, dtype));
413				if (tmp > cor_coef) {
414					cor_coef = tmp;
415					*width = w, *length = h;
416				}
417
418				_TIFFfree(buf1);
419				_TIFFfree(buf2);
420			}
421		}
422
423		fprintf(stderr,
424			"Width is guessed as %lu, height is guessed as %lu.\n",
425			(unsigned long)*width, (unsigned long)*length);
426
427		return 1;
428	} else {
429		if (filestat.st_size<(off_t)(hdr_size+(*width)*(*length)*nbands*depth)) {
430			fprintf(stderr, "Input file too small.\n");
431		return -1;
432		}
433	}
434
435	return 1;
436}
437
438/* Calculate correlation coefficient between two numeric vectors */
439static double
440correlation(void *buf1, void *buf2, uint32 n_elem, TIFFDataType dtype)
441{
442	double	X, Y, M1 = 0.0, M2 = 0.0, D1 = 0.0, D2 = 0.0, K = 0.0;
443	uint32	i;
444
445	switch (dtype) {
446		case TIFF_BYTE:
447		default:
448                        for (i = 0; i < n_elem; i++) {
449				X = ((unsigned char *)buf1)[i];
450				Y = ((unsigned char *)buf2)[i];
451				M1 += X, M2 += Y;
452				D1 += X * X, D2 += Y * Y;
453				K += X * Y;
454                        }
455			break;
456		case TIFF_SBYTE:
457                        for (i = 0; i < n_elem; i++) {
458				X = ((signed char *)buf1)[i];
459				Y = ((signed char *)buf2)[i];
460				M1 += X, M2 += Y;
461				D1 += X * X, D2 += Y * Y;
462				K += X * Y;
463                        }
464			break;
465		case TIFF_SHORT:
466                        for (i = 0; i < n_elem; i++) {
467				X = ((uint16 *)buf1)[i];
468				Y = ((uint16 *)buf2)[i];
469				M1 += X, M2 += Y;
470				D1 += X * X, D2 += Y * Y;
471				K += X * Y;
472                        }
473			break;
474		case TIFF_SSHORT:
475                        for (i = 0; i < n_elem; i++) {
476				X = ((int16 *)buf1)[i];
477				Y = ((int16 *)buf2)[i];
478				M1 += X, M2 += Y;
479				D1 += X * X, D2 += Y * Y;
480				K += X * Y;
481                        }
482			break;
483		case TIFF_LONG:
484                        for (i = 0; i < n_elem; i++) {
485				X = ((uint32 *)buf1)[i];
486				Y = ((uint32 *)buf2)[i];
487				M1 += X, M2 += Y;
488				D1 += X * X, D2 += Y * Y;
489				K += X * Y;
490                        }
491			break;
492		case TIFF_SLONG:
493                        for (i = 0; i < n_elem; i++) {
494				X = ((int32 *)buf1)[i];
495				Y = ((int32 *)buf2)[i];
496				M1 += X, M2 += Y;
497				D1 += X * X, D2 += Y * Y;
498				K += X * Y;
499                        }
500			break;
501		case TIFF_FLOAT:
502                        for (i = 0; i < n_elem; i++) {
503				X = ((float *)buf1)[i];
504				Y = ((float *)buf2)[i];
505				M1 += X, M2 += Y;
506				D1 += X * X, D2 += Y * Y;
507				K += X * Y;
508                        }
509			break;
510		case TIFF_DOUBLE:
511                        for (i = 0; i < n_elem; i++) {
512				X = ((double *)buf1)[i];
513				Y = ((double *)buf2)[i];
514				M1 += X, M2 += Y;
515				D1 += X * X, D2 += Y * Y;
516				K += X * Y;
517                        }
518			break;
519	}
520
521	M1 /= n_elem;
522	M2 /= n_elem;
523	D1 -= M1 * M1 * n_elem;
524	D2 -= M2 * M2 * n_elem;
525	K = (K - M1 * M2 * n_elem) / sqrt(D1 * D2);
526
527	return K;
528}
529
530static int
531processCompressOptions(char* opt)
532{
533	if (strcmp(opt, "none") == 0)
534		compression = COMPRESSION_NONE;
535	else if (strcmp(opt, "packbits") == 0)
536		compression = COMPRESSION_PACKBITS;
537	else if (strncmp(opt, "jpeg", 4) == 0) {
538		char* cp = strchr(opt, ':');
539
540                compression = COMPRESSION_JPEG;
541                while( cp )
542                {
543                    if (isdigit((int)cp[1]))
544			quality = atoi(cp+1);
545                    else if (cp[1] == 'r' )
546			jpegcolormode = JPEGCOLORMODE_RAW;
547                    else
548                        usage();
549
550                    cp = strchr(cp+1,':');
551                }
552	} else if (strncmp(opt, "lzw", 3) == 0) {
553		char* cp = strchr(opt, ':');
554		if (cp)
555			predictor = atoi(cp+1);
556		compression = COMPRESSION_LZW;
557	} else if (strncmp(opt, "zip", 3) == 0) {
558		char* cp = strchr(opt, ':');
559		if (cp)
560			predictor = atoi(cp+1);
561		compression = COMPRESSION_DEFLATE;
562	} else
563		return (0);
564	return (1);
565}
566
567static char* stuff[] = {
568"raw2tiff --- tool for converting raw byte sequences in TIFF images",
569"usage: raw2tiff [options] input.raw output.tif",
570"where options are:",
571" -L		input data has LSB2MSB bit order (default)",
572" -M		input data has MSB2LSB bit order",
573" -r #		make each strip have no more than # rows",
574" -H #		size of input image file header in bytes (0 by default)",
575" -w #		width of input image in pixels",
576" -l #		length of input image in lines",
577" -b #		number of bands in input image (1 by default)",
578"",
579" -d data_type	type of samples in input image",
580"where data_type may be:",
581" byte		8-bit unsigned integer (default)",
582" short		16-bit unsigned integer",
583" long		32-bit unsigned integer",
584" sbyte		8-bit signed integer",
585" sshort		16-bit signed integer",
586" slong		32-bit signed integer",
587" float		32-bit IEEE floating point",
588" double		64-bit IEEE floating point",
589"",
590" -p photo	photometric interpretation (color space) of the input image",
591"where photo may be:",
592" miniswhite	white color represented with 0 value",
593" minisblack	black color represented with 0 value (default)",
594" rgb		image has RGB color model",
595" cmyk		image has CMYK (separated) color model",
596" ycbcr		image has YCbCr color model",
597" cielab		image has CIE L*a*b color model",
598" icclab		image has ICC L*a*b color model",
599" itulab		image has ITU L*a*b color model",
600"",
601" -s		swap bytes fetched from input file",
602"",
603" -i config	type of samples interleaving in input image",
604"where config may be:",
605" pixel		pixel interleaved data (default)",
606" band		band interleaved data",
607"",
608" -c lzw[:opts]	compress output with Lempel-Ziv & Welch encoding",
609" -c zip[:opts]	compress output with deflate encoding",
610" -c jpeg[:opts]	compress output with JPEG encoding",
611" -c packbits	compress output with packbits encoding",
612" -c none	use no compression algorithm on output",
613"",
614"JPEG options:",
615" #		set compression quality level (0-100, default 75)",
616" r		output color image as RGB rather than YCbCr",
617"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
618"",
619"LZW and deflate options:",
620" #		set predictor value",
621"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
622" -o out.tif	write output to out.tif",
623" -h		this help message",
624NULL
625};
626
627static void
628usage(void)
629{
630	char buf[BUFSIZ];
631	int i;
632
633	setbuf(stderr, buf);
634        fprintf(stderr, "%s\n\n", TIFFGetVersion());
635	for (i = 0; stuff[i] != NULL; i++)
636		fprintf(stderr, "%s\n", stuff[i]);
637	exit(-1);
638}
639
640/* vim: set ts=8 sts=8 sw=8 noet: */
641/*
642 * Local Variables:
643 * mode: c
644 * c-basic-offset: 8
645 * fill-column: 78
646 * End:
647 */
648