/* $Id: raw2tiff.c,v 1.16 2004-10-28 14:35:50 dron Exp $ * * Project: libtiff tools * Purpose: Convert raw byte sequences in TIFF images * Author: Andrey Kiselev, dron@remotesensing.org * ****************************************************************************** * Copyright (c) 2002, Andrey Kiselev * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include "tif_config.h" #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #if HAVE_FCNTL_H # include #endif #if HAVE_SYS_TYPES_H # include #endif #if HAVE_IO_H # include #endif #include "tiffio.h" #ifndef O_BINARY # define O_BINARY 0 #endif typedef enum { PIXEL, BAND } InterleavingType; static uint16 compression = (uint16) -1; static int jpegcolormode = JPEGCOLORMODE_RGB; static int quality = 75; /* JPEG quality */ static uint16 predictor = 0; static void swapBytesInScanline(void *, uint32, TIFFDataType); static int guessSize(int, TIFFDataType, off_t, uint32, int, uint32 *, uint32 *); static double correlation(void *, void *, uint32, TIFFDataType); static void usage(void); static int processCompressOptions(char*); int main(int argc, char* argv[]) { uint32 width = 0, length = 0, linebytes, bufsize; uint32 nbands = 1; /* number of bands in input image*/ off_t hdr_size = 0; /* size of the header to skip */ TIFFDataType dtype = TIFF_BYTE; int16 depth = 1; /* bytes per pixel in input image */ int swab = 0; /* byte swapping flag */ InterleavingType interleaving = 0; /* interleaving type flag */ uint32 rowsperstrip = (uint32) -1; uint16 photometric = PHOTOMETRIC_MINISBLACK; uint16 config = PLANARCONFIG_CONTIG; uint16 fillorder = FILLORDER_LSB2MSB; int fd; char *outfilename = NULL; TIFF *out; uint32 row, col, band; int c; unsigned char *buf = NULL, *buf1 = NULL; extern int optind; extern char* optarg; while ((c = getopt(argc, argv, "c:r:H:w:l:b:d:LMp:si:o:h")) != -1) { switch (c) { case 'c': /* compression scheme */ if (!processCompressOptions(optarg)) usage(); break; case 'r': /* rows/strip */ rowsperstrip = atoi(optarg); break; case 'H': /* size of input image file header */ hdr_size = atoi(optarg); break; case 'w': /* input image width */ width = atoi(optarg); break; case 'l': /* input image length */ length = atoi(optarg); break; case 'b': /* number of bands in input image */ nbands = atoi(optarg); break; case 'd': /* type of samples in input image */ if (strncmp(optarg, "byte", 4) == 0) dtype = TIFF_BYTE; else if (strncmp(optarg, "short", 5) == 0) dtype = TIFF_SHORT; else if (strncmp(optarg, "long", 4) == 0) dtype = TIFF_LONG; else if (strncmp(optarg, "sbyte", 5) == 0) dtype = TIFF_SBYTE; else if (strncmp(optarg, "sshort", 6) == 0) dtype = TIFF_SSHORT; else if (strncmp(optarg, "slong", 5) == 0) dtype = TIFF_SLONG; else if (strncmp(optarg, "float", 5) == 0) dtype = TIFF_FLOAT; else if (strncmp(optarg, "double", 6) == 0) dtype = TIFF_DOUBLE; else dtype = TIFF_BYTE; depth = TIFFDataWidth(dtype); break; case 'L': /* input has lsb-to-msb fillorder */ fillorder = FILLORDER_LSB2MSB; break; case 'M': /* input has msb-to-lsb fillorder */ fillorder = FILLORDER_MSB2LSB; break; case 'p': /* photometric interpretation */ if (strncmp(optarg, "miniswhite", 10) == 0) photometric = PHOTOMETRIC_MINISWHITE; else if (strncmp(optarg, "minisblack", 10) == 0) photometric = PHOTOMETRIC_MINISBLACK; else if (strncmp(optarg, "rgb", 3) == 0) photometric = PHOTOMETRIC_RGB; else if (strncmp(optarg, "cmyk", 4) == 0) photometric = PHOTOMETRIC_SEPARATED; else if (strncmp(optarg, "ycbcr", 5) == 0) photometric = PHOTOMETRIC_YCBCR; else if (strncmp(optarg, "cielab", 6) == 0) photometric = PHOTOMETRIC_CIELAB; else if (strncmp(optarg, "icclab", 6) == 0) photometric = PHOTOMETRIC_ICCLAB; else if (strncmp(optarg, "itulab", 6) == 0) photometric = PHOTOMETRIC_ITULAB; else photometric = PHOTOMETRIC_MINISBLACK; break; case 's': /* do we need to swap bytes? */ swab = 1; break; case 'i': /* type of interleaving */ if (strncmp(optarg, "pixel", 4) == 0) interleaving = PIXEL; else if (strncmp(optarg, "band", 6) == 0) interleaving = BAND; else interleaving = 0; break; case 'o': outfilename = optarg; break; case 'h': usage(); default: break; } } if (argc - optind < 2) usage(); fd = open(argv[optind], O_RDONLY|O_BINARY, 0); if (fd < 0) { fprintf(stderr, "%s: %s: Cannot open input file.\n", argv[0], argv[optind]); return (-1); } if (guessSize(fd, dtype, hdr_size, nbands, swab, &width, &length) < 0) return 1; if (outfilename == NULL) outfilename = argv[optind+1]; out = TIFFOpen(outfilename, "w"); if (out == NULL) { fprintf(stderr, "%s: %s: Cannot open file for output.\n", argv[0], outfilename); return (-1); } TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, length); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth * 8); TIFFSetField(out, TIFFTAG_FILLORDER, fillorder); TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); switch (dtype) { case TIFF_BYTE: case TIFF_SHORT: case TIFF_LONG: TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); break; case TIFF_SBYTE: case TIFF_SSHORT: case TIFF_SLONG: TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); break; case TIFF_FLOAT: case TIFF_DOUBLE: TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); break; default: TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_VOID); break; } if (compression == (uint16) -1) compression = COMPRESSION_PACKBITS; TIFFSetField(out, TIFFTAG_COMPRESSION, compression); switch (compression) { case COMPRESSION_JPEG: if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR; TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); break; case COMPRESSION_LZW: case COMPRESSION_DEFLATE: if (predictor != 0) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); break; } switch(interleaving) { case BAND: /* band interleaved data */ linebytes = width * depth; buf = (unsigned char *)_TIFFmalloc(linebytes); break; case PIXEL: /* pixel interleaved data */ default: linebytes = width * nbands * depth; break; } bufsize = width * nbands * depth; buf1 = (unsigned char *)_TIFFmalloc(bufsize); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, rowsperstrip)); lseek(fd, hdr_size, SEEK_SET); /* Skip the file header */ for (row = 0; row < length; row++) { switch(interleaving) { case BAND: /* band interleaved data */ for (band = 0; band < nbands; band++) { lseek(fd, hdr_size + (length*band+row)*linebytes, SEEK_SET); if (read(fd, buf, linebytes) != linebytes) { fprintf(stderr, "%s: %s: scanline %lu: Read error.\n", argv[0], argv[optind], (unsigned long) row); break; } if (swab) /* Swap bytes if needed */ swapBytesInScanline(buf, width, dtype); for (col = 0; col < width; col++) memcpy(buf1 + (col*nbands+band)*depth, buf + col * depth, depth); } break; case PIXEL: /* pixel interleaved data */ default: if (read(fd, buf1, bufsize) != bufsize) { fprintf(stderr, "%s: %s: scanline %lu: Read error.\n", argv[0], argv[optind], (unsigned long) row); break; } if (swab) /* Swap bytes if needed */ swapBytesInScanline(buf1, width, dtype); break; } if (TIFFWriteScanline(out, buf1, row, 0) < 0) { fprintf(stderr, "%s: %s: scanline %lu: Write error.\n", argv[0], outfilename, (unsigned long) row); break; } } if (buf) _TIFFfree(buf); if (buf1) _TIFFfree(buf1); TIFFClose(out); return (0); } static void swapBytesInScanline(void *buf, uint32 width, TIFFDataType dtype) { switch (dtype) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((uint16*)buf, (unsigned long)width); break; case TIFF_LONG: case TIFF_SLONG: TIFFSwabArrayOfLong((uint32*)buf, (unsigned long)width); break; /* case TIFF_FLOAT: */ /* FIXME */ case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*)buf, (unsigned long)width); break; default: break; } } static int guessSize(int fd, TIFFDataType dtype, off_t hdr_size, uint32 nbands, int swab, uint32 *width, uint32 *length) { const float longt = 40.0; /* maximum possible height/width ratio */ char *buf1, *buf2; struct stat filestat; uint32 w, h, scanlinesize, imagesize; uint32 depth = TIFFDataWidth(dtype); float cor_coef = 0, tmp; fstat(fd, &filestat); if (filestat.st_size < hdr_size) { fprintf(stderr, "Too large header size specified.\n"); return -1; } imagesize = (filestat.st_size - hdr_size) / nbands / depth; if (*width != 0 && *length == 0) { fprintf(stderr, "Image height is not specified.\n"); *length = imagesize / *width; fprintf(stderr, "Height is guessed as %lu.\n", *length); return 1; } else if (*width == 0 && *length != 0) { fprintf(stderr, "Image width is not specified.\n"); *width = imagesize / *length; fprintf(stderr, "Width is guessed as %lu.\n", *width); return 1; } else if (*width == 0 && *length == 0) { fprintf(stderr, "Image width and height are not specified.\n"); for (w = (uint32) sqrt(imagesize / longt); w < sqrt(imagesize * longt); w++) { if (imagesize % w == 0) { scanlinesize = w * depth; buf1 = _TIFFmalloc(scanlinesize); buf2 = _TIFFmalloc(scanlinesize); h = imagesize / w; lseek(fd, hdr_size + (int)(h/2)*scanlinesize, SEEK_SET); read(fd, buf1, scanlinesize); read(fd, buf2, scanlinesize); if (swab) { swapBytesInScanline(buf1, w, dtype); swapBytesInScanline(buf2, w, dtype); } tmp = (float) fabs(correlation(buf1, buf2, w, dtype)); if (tmp > cor_coef) { cor_coef = tmp; *width = w, *length = h; } _TIFFfree(buf1); _TIFFfree(buf2); } } fprintf(stderr, "Width is guessed as %lu, height is guessed as %lu.\n", *width, *length); return 1; } else { if (filestat.st_size