1/* $Id: ras2tiff.c 276 2010-06-30 12:18:30Z nijtmans $ */ 2 3/* 4 * Copyright (c) 1988-1997 Sam Leffler 5 * Copyright (c) 1991-1997 Silicon Graphics, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and 8 * its documentation for any purpose is hereby granted without fee, provided 9 * that (i) the above copyright notices and this permission notice appear in 10 * all copies of the software and related documentation, and (ii) the names of 11 * Sam Leffler and Silicon Graphics may not be used in any advertising or 12 * publicity relating to the software without the specific, prior written 13 * permission of Sam Leffler and Silicon Graphics. 14 * 15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 */ 26 27#include "tif_config.h" 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <ctype.h> 33 34#ifdef HAVE_UNISTD_H 35# include <unistd.h> 36#endif 37 38#include "rasterfile.h" 39#include "tiffio.h" 40 41#ifndef howmany 42#define howmany(x, y) (((x)+((y)-1))/(y)) 43#endif 44#define streq(a,b) (strcmp(a,b) == 0) 45#define strneq(a,b,n) (strncmp(a,b,n) == 0) 46 47static uint16 compression = (uint16) -1; 48static int jpegcolormode = JPEGCOLORMODE_RGB; 49static int quality = 75; /* JPEG quality */ 50static uint16 predictor = 0; 51 52static void usage(void); 53static int processCompressOptions(char*); 54 55int 56main(int argc, char* argv[]) 57{ 58 unsigned char* buf; 59 long row; 60 tsize_t linebytes, scanline; 61 TIFF *out; 62 FILE *in; 63 struct rasterfile h; 64 uint16 photometric; 65 uint16 config = PLANARCONFIG_CONTIG; 66 uint32 rowsperstrip = (uint32) -1; 67 int c; 68 extern int optind; 69 extern char* optarg; 70 71 while ((c = getopt(argc, argv, "c:r:h")) != -1) 72 switch (c) { 73 case 'c': /* compression scheme */ 74 if (!processCompressOptions(optarg)) 75 usage(); 76 break; 77 case 'r': /* rows/strip */ 78 rowsperstrip = atoi(optarg); 79 break; 80 case 'h': 81 usage(); 82 /*NOTREACHED*/ 83 } 84 if (argc - optind != 2) 85 usage(); 86 in = fopen(argv[optind], "rb"); 87 if (in == NULL) { 88 fprintf(stderr, "%s: Can not open.\n", argv[optind]); 89 return (-1); 90 } 91 if (fread(&h, sizeof (h), 1, in) != 1) { 92 fprintf(stderr, "%s: Can not read header.\n", argv[optind]); 93 return (-2); 94 } 95 if (strcmp(h.ras_magic, RAS_MAGIC) == 0) { 96#ifndef WORDS_BIGENDIAN 97 TIFFSwabLong((uint32 *)&h.ras_width); 98 TIFFSwabLong((uint32 *)&h.ras_height); 99 TIFFSwabLong((uint32 *)&h.ras_depth); 100 TIFFSwabLong((uint32 *)&h.ras_length); 101 TIFFSwabLong((uint32 *)&h.ras_type); 102 TIFFSwabLong((uint32 *)&h.ras_maptype); 103 TIFFSwabLong((uint32 *)&h.ras_maplength); 104#endif 105 } else if (strcmp(h.ras_magic, RAS_MAGIC_INV) == 0) { 106#ifdef WORDS_BIGENDIAN 107 TIFFSwabLong((uint32 *)&h.ras_width); 108 TIFFSwabLong((uint32 *)&h.ras_height); 109 TIFFSwabLong((uint32 *)&h.ras_depth); 110 TIFFSwabLong((uint32 *)&h.ras_length); 111 TIFFSwabLong((uint32 *)&h.ras_type); 112 TIFFSwabLong((uint32 *)&h.ras_maptype); 113 TIFFSwabLong((uint32 *)&h.ras_maplength); 114#endif 115 } else { 116 fprintf(stderr, "%s: Not a rasterfile.\n", argv[optind]); 117 return (-3); 118 } 119 out = TIFFOpen(argv[optind+1], "w"); 120 if (out == NULL) 121 return (-4); 122 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) h.ras_width); 123 TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h.ras_height); 124 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); 125 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, h.ras_depth > 8 ? 3 : 1); 126 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, h.ras_depth > 1 ? 8 : 1); 127 TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); 128 if (h.ras_maptype != RMT_NONE) { 129 uint16* red; 130 register uint16* map; 131 register int i, j; 132 int mapsize; 133 134 buf = (unsigned char *)_TIFFmalloc(h.ras_maplength); 135 if (buf == NULL) { 136 fprintf(stderr, "No space to read in colormap.\n"); 137 return (-5); 138 } 139 if (fread(buf, h.ras_maplength, 1, in) != 1) { 140 fprintf(stderr, "%s: Read error on colormap.\n", 141 argv[optind]); 142 return (-6); 143 } 144 mapsize = 1<<h.ras_depth; 145 if (h.ras_maplength > mapsize*3) { 146 fprintf(stderr, 147 "%s: Huh, %ld colormap entries, should be %d?\n", 148 argv[optind], h.ras_maplength, mapsize*3); 149 return (-7); 150 } 151 red = (uint16*)_TIFFmalloc(mapsize * 3 * sizeof (uint16)); 152 if (red == NULL) { 153 fprintf(stderr, "No space for colormap.\n"); 154 return (-8); 155 } 156 map = red; 157 for (j = 0; j < 3; j++) { 158#define SCALE(x) (((x)*((1L<<16)-1))/255) 159 for (i = h.ras_maplength/3; i-- > 0;) 160 *map++ = SCALE(*buf++); 161 if ((i = h.ras_maplength/3) < mapsize) { 162 i = mapsize - i; 163 _TIFFmemset(map, 0, i*sizeof (uint16)); 164 map += i; 165 } 166 } 167 TIFFSetField(out, TIFFTAG_COLORMAP, 168 red, red + mapsize, red + 2*mapsize); 169 photometric = PHOTOMETRIC_PALETTE; 170 if (compression == (uint16) -1) 171 compression = COMPRESSION_PACKBITS; 172 TIFFSetField(out, TIFFTAG_COMPRESSION, compression); 173 } else { 174 /* XXX this is bogus... */ 175 photometric = h.ras_depth == 24 ? 176 PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; 177 if (compression == (uint16) -1) 178 compression = COMPRESSION_LZW; 179 TIFFSetField(out, TIFFTAG_COMPRESSION, compression); 180 } 181 switch (compression) { 182 case COMPRESSION_JPEG: 183 if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB) 184 photometric = PHOTOMETRIC_YCBCR; 185 TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); 186 TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); 187 break; 188 case COMPRESSION_LZW: 189 case COMPRESSION_DEFLATE: 190 if (predictor != 0) 191 TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); 192 break; 193 } 194 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); 195 linebytes = ((h.ras_depth*h.ras_width+15) >> 3) &~ 1; 196 scanline = TIFFScanlineSize(out); 197 if (scanline > linebytes) { 198 buf = (unsigned char *)_TIFFmalloc(scanline); 199 _TIFFmemset(buf+linebytes, 0, scanline-linebytes); 200 } else 201 buf = (unsigned char *)_TIFFmalloc(linebytes); 202 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 203 TIFFDefaultStripSize(out, rowsperstrip)); 204 for (row = 0; row < h.ras_height; row++) { 205 if (fread(buf, linebytes, 1, in) != 1) { 206 fprintf(stderr, "%s: scanline %ld: Read error.\n", 207 argv[optind], row); 208 break; 209 } 210 if (h.ras_type == RT_STANDARD && h.ras_depth == 24) { 211 tsize_t cc = h.ras_width; 212 unsigned char* cp = buf; 213#define SWAP(a,b) { unsigned char t = (a); (a) = (b); (b) = t; } 214 do { 215 SWAP(cp[0], cp[2]); 216 cp += 3; 217 } while (--cc); 218 } 219 if (TIFFWriteScanline(out, buf, row, 0) < 0) 220 break; 221 } 222 (void) TIFFClose(out); 223 return (0); 224} 225 226static int 227processCompressOptions(char* opt) 228{ 229 if (streq(opt, "none")) 230 compression = COMPRESSION_NONE; 231 else if (streq(opt, "packbits")) 232 compression = COMPRESSION_PACKBITS; 233 else if (strneq(opt, "jpeg", 4)) { 234 char* cp = strchr(opt, ':'); 235 236 compression = COMPRESSION_JPEG; 237 while( cp ) 238 { 239 if (isdigit((int)cp[1])) 240 quality = atoi(cp+1); 241 else if (cp[1] == 'r' ) 242 jpegcolormode = JPEGCOLORMODE_RAW; 243 else 244 usage(); 245 246 cp = strchr(cp+1,':'); 247 } 248 } else if (strneq(opt, "lzw", 3)) { 249 char* cp = strchr(opt, ':'); 250 if (cp) 251 predictor = atoi(cp+1); 252 compression = COMPRESSION_LZW; 253 } else if (strneq(opt, "zip", 3)) { 254 char* cp = strchr(opt, ':'); 255 if (cp) 256 predictor = atoi(cp+1); 257 compression = COMPRESSION_DEFLATE; 258 } else 259 return (0); 260 return (1); 261} 262 263char* stuff[] = { 264"usage: ras2tiff [options] input.ras output.tif", 265"where options are:", 266" -r # make each strip have no more than # rows", 267"", 268" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", 269" -c zip[:opts] compress output with deflate encoding", 270" -c jpeg[:opts] compress output with JPEG encoding", 271" -c packbits compress output with packbits encoding", 272" -c none use no compression algorithm on output", 273"", 274"JPEG options:", 275" # set compression quality level (0-100, default 75)", 276" r output color image as RGB rather than YCbCr", 277"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality", 278"", 279"LZW and deflate options:", 280" # set predictor value", 281"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", 282" -h this help message", 283NULL 284}; 285 286static void 287usage(void) 288{ 289 char buf[BUFSIZ]; 290 int i; 291 292 setbuf(stderr, buf); 293 fprintf(stderr, "%s\n\n", TIFFGetVersion()); 294 for (i = 0; stuff[i] != NULL; i++) 295 fprintf(stderr, "%s\n", stuff[i]); 296 exit(-1); 297} 298 299/* vim: set ts=8 sts=8 sw=8 noet: */ 300/* 301 * Local Variables: 302 * mode: c 303 * c-basic-offset: 8 304 * fill-column: 78 305 * End: 306 */ 307