1/* $Id: ppm2tiff.c 276 2010-06-30 12:18:30Z nijtmans $ */ 2 3/* 4 * Copyright (c) 1991-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#ifdef HAVE_FCNTL_H 39# include <fcntl.h> 40#endif 41 42#ifdef HAVE_IO_H 43# include <io.h> 44#endif 45 46#include "tiffio.h" 47 48#ifndef HAVE_GETOPT 49extern int getopt(int, char**, char*); 50#endif 51 52#define streq(a,b) (strcmp(a,b) == 0) 53#define strneq(a,b,n) (strncmp(a,b,n) == 0) 54 55static uint16 compression = COMPRESSION_PACKBITS; 56static uint16 predictor = 0; 57static int quality = 75; /* JPEG quality */ 58static int jpegcolormode = JPEGCOLORMODE_RGB; 59static uint32 g3opts; 60 61static void usage(void); 62static int processCompressOptions(char*); 63 64static void 65BadPPM(char* file) 66{ 67 fprintf(stderr, "%s: Not a PPM file.\n", file); 68 exit(-2); 69} 70 71int 72main(int argc, char* argv[]) 73{ 74 uint16 photometric = 0; 75 uint32 rowsperstrip = (uint32) -1; 76 double resolution = -1; 77 unsigned char *buf = NULL; 78 tsize_t linebytes = 0; 79 uint16 spp = 1; 80 uint16 bpp = 8; 81 TIFF *out; 82 FILE *in; 83 unsigned int w, h, prec, row; 84 char *infile; 85 int c; 86 extern int optind; 87 extern char* optarg; 88 89 if (argc < 2) { 90 fprintf(stderr, "%s: Too few arguments\n", argv[0]); 91 usage(); 92 } 93 while ((c = getopt(argc, argv, "c:r:R:")) != -1) 94 switch (c) { 95 case 'c': /* compression scheme */ 96 if (!processCompressOptions(optarg)) 97 usage(); 98 break; 99 case 'r': /* rows/strip */ 100 rowsperstrip = atoi(optarg); 101 break; 102 case 'R': /* resolution */ 103 resolution = atof(optarg); 104 break; 105 case '?': 106 usage(); 107 /*NOTREACHED*/ 108 } 109 110 if (optind + 2 < argc) { 111 fprintf(stderr, "%s: Too many arguments\n", argv[0]); 112 usage(); 113 } 114 115 /* 116 * If only one file is specified, read input from 117 * stdin; otherwise usage is: ppm2tiff input output. 118 */ 119 if (argc - optind > 1) { 120 infile = argv[optind++]; 121 in = fopen(infile, "rb"); 122 if (in == NULL) { 123 fprintf(stderr, "%s: Can not open.\n", infile); 124 return (-1); 125 } 126 } else { 127 infile = "<stdin>"; 128 in = stdin; 129#if defined(HAVE_SETMODE) && defined(O_BINARY) 130 setmode(fileno(stdin), O_BINARY); 131#endif 132 } 133 134 if (fgetc(in) != 'P') 135 BadPPM(infile); 136 switch (fgetc(in)) { 137 case '4': /* it's a PBM file */ 138 bpp = 1; 139 spp = 1; 140 photometric = PHOTOMETRIC_MINISWHITE; 141 break; 142 case '5': /* it's a PGM file */ 143 bpp = 8; 144 spp = 1; 145 photometric = PHOTOMETRIC_MINISBLACK; 146 break; 147 case '6': /* it's a PPM file */ 148 bpp = 8; 149 spp = 3; 150 photometric = PHOTOMETRIC_RGB; 151 if (compression == COMPRESSION_JPEG && 152 jpegcolormode == JPEGCOLORMODE_RGB) 153 photometric = PHOTOMETRIC_YCBCR; 154 break; 155 default: 156 BadPPM(infile); 157 } 158 159 /* Parse header */ 160 while(1) { 161 if (feof(in)) 162 BadPPM(infile); 163 c = fgetc(in); 164 /* Skip whitespaces (blanks, TABs, CRs, LFs) */ 165 if (strchr(" \t\r\n", c)) 166 continue; 167 168 /* Check for comment line */ 169 if (c == '#') { 170 do { 171 c = fgetc(in); 172 } while(!(strchr("\r\n", c) || feof(in))); 173 continue; 174 } 175 176 ungetc(c, in); 177 break; 178 } 179 switch (bpp) { 180 case 1: 181 if (fscanf(in, " %u %u", &w, &h) != 2) 182 BadPPM(infile); 183 if (fgetc(in) != '\n') 184 BadPPM(infile); 185 break; 186 case 8: 187 if (fscanf(in, " %u %u %u", &w, &h, &prec) != 3) 188 BadPPM(infile); 189 if (fgetc(in) != '\n' || prec != 255) 190 BadPPM(infile); 191 break; 192 } 193 out = TIFFOpen(argv[optind], "w"); 194 if (out == NULL) 195 return (-4); 196 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) w); 197 TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h); 198 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); 199 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp); 200 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp); 201 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); 202 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); 203 TIFFSetField(out, TIFFTAG_COMPRESSION, compression); 204 switch (compression) { 205 case COMPRESSION_JPEG: 206 TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); 207 TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); 208 break; 209 case COMPRESSION_LZW: 210 case COMPRESSION_DEFLATE: 211 if (predictor != 0) 212 TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); 213 break; 214 case COMPRESSION_CCITTFAX3: 215 TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts); 216 break; 217 } 218 switch (bpp) { 219 case 1: 220 linebytes = (spp * w + (8 - 1)) / 8; 221 if (rowsperstrip == (uint32) -1) { 222 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, h); 223 } else { 224 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 225 TIFFDefaultStripSize(out, rowsperstrip)); 226 } 227 break; 228 case 8: 229 linebytes = spp * w; 230 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 231 TIFFDefaultStripSize(out, rowsperstrip)); 232 break; 233 } 234 if (TIFFScanlineSize(out) > linebytes) 235 buf = (unsigned char *)_TIFFmalloc(linebytes); 236 else 237 buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); 238 if (resolution > 0) { 239 TIFFSetField(out, TIFFTAG_XRESOLUTION, resolution); 240 TIFFSetField(out, TIFFTAG_YRESOLUTION, resolution); 241 TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); 242 } 243 for (row = 0; row < h; row++) { 244 if (fread(buf, linebytes, 1, in) != 1) { 245 fprintf(stderr, "%s: scanline %lu: Read error.\n", 246 infile, (unsigned long) row); 247 break; 248 } 249 if (TIFFWriteScanline(out, buf, row, 0) < 0) 250 break; 251 } 252 (void) TIFFClose(out); 253 if (buf) 254 _TIFFfree(buf); 255 return (0); 256} 257 258static void 259processG3Options(char* cp) 260{ 261 g3opts = 0; 262 if( (cp = strchr(cp, ':')) ) { 263 do { 264 cp++; 265 if (strneq(cp, "1d", 2)) 266 g3opts &= ~GROUP3OPT_2DENCODING; 267 else if (strneq(cp, "2d", 2)) 268 g3opts |= GROUP3OPT_2DENCODING; 269 else if (strneq(cp, "fill", 4)) 270 g3opts |= GROUP3OPT_FILLBITS; 271 else 272 usage(); 273 } while( (cp = strchr(cp, ':')) ); 274 } 275} 276 277static int 278processCompressOptions(char* opt) 279{ 280 if (streq(opt, "none")) 281 compression = COMPRESSION_NONE; 282 else if (streq(opt, "packbits")) 283 compression = COMPRESSION_PACKBITS; 284 else if (strneq(opt, "jpeg", 4)) { 285 char* cp = strchr(opt, ':'); 286 287 compression = COMPRESSION_JPEG; 288 while (cp) 289 { 290 if (isdigit((int)cp[1])) 291 quality = atoi(cp+1); 292 else if (cp[1] == 'r' ) 293 jpegcolormode = JPEGCOLORMODE_RAW; 294 else 295 usage(); 296 297 cp = strchr(cp+1,':'); 298 } 299 } else if (strneq(opt, "g3", 2)) { 300 processG3Options(opt); 301 compression = COMPRESSION_CCITTFAX3; 302 } else if (streq(opt, "g4")) { 303 compression = COMPRESSION_CCITTFAX4; 304 } else if (strneq(opt, "lzw", 3)) { 305 char* cp = strchr(opt, ':'); 306 if (cp) 307 predictor = atoi(cp+1); 308 compression = COMPRESSION_LZW; 309 } else if (strneq(opt, "zip", 3)) { 310 char* cp = strchr(opt, ':'); 311 if (cp) 312 predictor = atoi(cp+1); 313 compression = COMPRESSION_DEFLATE; 314 } else 315 return (0); 316 return (1); 317} 318 319char* stuff[] = { 320"usage: ppm2tiff [options] input.ppm output.tif", 321"where options are:", 322" -r # make each strip have no more than # rows", 323" -R # set x&y resolution (dpi)", 324"", 325" -c jpeg[:opts] compress output with JPEG encoding", 326" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", 327" -c zip[:opts] compress output with deflate encoding", 328" -c packbits compress output with packbits encoding (the default)", 329" -c g3[:opts] compress output with CCITT Group 3 encoding", 330" -c g4 compress output with CCITT Group 4 encoding", 331" -c none use no compression algorithm on output", 332"", 333"JPEG options:", 334" # set compression quality level (0-100, default 75)", 335" r output color image as RGB rather than YCbCr", 336"LZW and deflate options:", 337" # set predictor value", 338"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", 339NULL 340}; 341 342static void 343usage(void) 344{ 345 char buf[BUFSIZ]; 346 int i; 347 348 setbuf(stderr, buf); 349 fprintf(stderr, "%s\n\n", TIFFGetVersion()); 350 for (i = 0; stuff[i] != NULL; i++) 351 fprintf(stderr, "%s\n", stuff[i]); 352 exit(-1); 353} 354 355/* vim: set ts=8 sts=8 sw=8 noet: */ 356/* 357 * Local Variables: 358 * mode: c 359 * c-basic-offset: 8 360 * fill-column: 78 361 * End: 362 */ 363