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