/* * $Id: tiffflip.c,v 1.2 1995/10/13 14:18:49 alberto Exp alberto $ * * Flips 1 bit/pixel TIFF files, writes out TIFF G4 compressed files. * Only planar configuration files are supported. * Compile with Sam Leffler's libtiff available at * ftp://ftp.sgi.com/graphics/tiff. * * This program is part of the NASA Astrophysics Data System * article service data reduction/conversion software. * * Copyright (C): 1994, 1995 Smithsonian Astrophysical Observatory. * You may do anything you like with this file except remove * this copyright. The Smithsonian Astrophysical Observatory * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. It may not be incorporated into * commercial products without permission of the Smithsonian * Astrophysical Observatory. * * Written by Alberto Accomazzi * http://cfa-www.harvard.edu/~alberto/ * * * $Log: tiffflip.c,v $ * Revision 1.2 1995/10/13 14:18:49 alberto * Merged I/O and bit manipulation routines with main program to * distribute with libtiff. * * Revision 1.1 1995/09/29 21:28:21 alberto * Initial revision * * */ #include #include #include #include /* prototypes */ int tiffread (char*, unsigned char**, int*, int*, char*); int tiffwrite (char*, unsigned char*, int, int, int, char*); int bitflipr90 (unsigned char*, int, int); int bitflipr180 (unsigned char*, int, int); int bitflipr270 (unsigned char*, int, int); int bitfliplr (unsigned char*, int, int); int bitfliptb (unsigned char*, int, int); static void usage(void); #define max(x,y) (((x)>(y))?(x):(y)) #define min(x,y) (((x)<(y))?(x):(y)) #define match(string, option, lmin) \ ( strncmp((string), (option), max((lmin),strlen(string))) == 0 ) enum { NONE, LR, TB, R90, R180, R270 }; static const char *usage_msg[] = { " This program will read 1 bit/pixel TIFF files from infile,", " flip the bitmaps as specified by the command line flags,", " and write out TIFF G4 files.", " Output file names are generated by appending \".flip\" to the", " input file names.", " Rotation operations currently supported are:", " -tb flip top-to-bottom", " -lr flip left-to-right", " -r90 rotate by 90 degrees clockwise", " -r180 rotate by 180 degrees", " -r270 rotate by 270 degrees clockwise", NULL }; char *progname; int debug = 0; static void usage(void) { char **c; fprintf(stderr, "Usage: %s [-debug] -tb|-lr|-r90|-r180|-r270 infile [...]\n", progname); for (c = (char **)usage_msg; *c; c++) fprintf(stderr, "%s\n", *c); exit (1); } int main(int argc, char *argv[]) { int argn = 1, iwidth, iheight, dpi = 0, flip = NONE; char title[BUFSIZ], imfile[BUFSIZ]; unsigned char *buffer; progname = strrchr(argv[0], '/'); if (progname) progname++; else progname = argv[0]; buffer = NULL; while (argn < argc && argv[argn][0] == '-') { if (match(argv[argn], "-debug", 3)) debug = 1; else if (match(argv[argn], "-tb", 3)) flip = TB; else if (match(argv[argn], "-lr", 3)) flip = LR; else if (match(argv[argn], "-r90", 4)) flip = R90; else if (match(argv[argn], "-r180", 5)) flip = R180; else if (match(argv[argn], "-r270", 5)) flip = R270; else usage(); argn++; } if (flip == NONE || argn == argc) usage(); while (argn < argc) { sprintf(imfile, "%s.flip", argv[argn]); printf("%s -> ", argv[argn]); if (debug) fprintf(stderr, "%s: reading input file %s...", progname, argv[argn]); if (!(dpi = tiffread(argv[argn], &buffer, &iwidth, &iheight, title))) { fprintf(stderr, "%s: error reading input file %s\n", progname, argv[argn]); continue; } if (debug) fprintf(stderr, "done. Dimensions are %dx%d.\n", iwidth, iheight); if (debug) fprintf(stderr, "%s: flipping image with mode %d...", progname, flip); if (flip == TB) { if (bitfliptb(buffer, iwidth, iheight)) { fprintf(stderr, "%s: error flipping file %s\n", progname, argv[argn]); continue; } } else if (flip == LR) { if (bitfliplr(buffer, iwidth, iheight)) { fprintf(stderr, "%s: error flipping file %s\n", progname, argv[argn]); continue; } } else if (flip == R180) { if (bitflipr180(buffer, iwidth, iheight)) { fprintf(stderr, "%s: error flipping file %s\n", progname, argv[argn]); continue; } } else if (flip == R90) { int tmp = iwidth; if (bitflipr90(buffer, iwidth, iheight)) { fprintf(stderr, "%s: error flipping file %s\n", progname, argv[argn]); continue; } iwidth = iheight; iheight = tmp; } else if (flip == R270) { int tmp = iwidth; if (bitflipr270(buffer, iwidth, iheight)) { fprintf(stderr, "%s: error flipping file %s\n", progname, argv[argn]); continue; } iwidth = iheight; iheight = tmp; } else { fprintf(stderr, "%s: error: flip mode %d not implemented yet (sorry).\n", progname, flip); continue; } if (debug) fprintf(stderr, "done.\n"); if (debug) fprintf(stderr, "%s: writing output file...", progname); if (tiffwrite(imfile, buffer, iwidth, iheight, dpi, title)) { fprintf(stderr, "%s: error writing output file %s!\n", progname, imfile); continue; } if (debug) fprintf(stderr, "done.\n"); printf("%s\n", imfile); argn++; } exit(0); } #include "tiffio.h" /* letter page sizes used to figure out image resolution */ #define PGSIZEX 8.5 #define PGSIZEY 11 /* * Reads TIFF file with planar configuration of single image plane, * returns resolution (dots/inch), or 0 in case of error. * If the flag rotation is set and the orientation of the image as * specified in the TIFF header is landscape, the image will be rotated. */ int tiffread(char *file, unsigned char **image, int *x, int *y, char *title) { TIFF *tif; char *dtitle; float xres, yres; int xdpi = 0, ydpi = 0, resolution = 0; uint16 config, bitspersample, samplesperpixel, bitsperpixel, bytesperrow; uint32 row, w, h, rowsperstrip = (uint32)-1; static uint32 buffersize = 0; tsize_t scanline; unsigned char *buf; if (NULL == (tif = TIFFOpen(file, "r"))) { fprintf(stderr, "tiffread: error: cannot open file %s for reading!\n", file); return(0); } scanline = TIFFScanlineSize(tif); if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h)) { fprintf(stderr, "tiffread: error: cannot get imagelength!\n"); return(0); } if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w)) { fprintf(stderr, "tiffread: error: cannot get imagelength!\n"); return(0); } if (!TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip)) { fprintf(stderr, "tiffread: error: cannot get rowsperstrip count!\n"); return(0); } if (TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config) && config != PLANARCONFIG_CONTIG) { fprintf(stderr, "tiffread: error: cannot deal with TIFF file with non-planar configuration!\n"); return(0); } if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample)) bitspersample = 1; if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel)) samplesperpixel = 1; bitsperpixel = bitspersample * samplesperpixel; if (!TIFFGetField(tif, TIFFTAG_DOCUMENTNAME, &dtitle)) title[0] = '\0'; else strcpy(title, dtitle); /* calculate resolution (assume it's a multiple of 75 dpi) */ if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)) { for (xdpi = 75; ((double)w/(double)xdpi) > PGSIZEX; xdpi *= 2) {} xres = 0; } if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)) { for (ydpi = 75; ((double)h/(double)ydpi) > PGSIZEY; ydpi *= 2) {} yres = 0; } if (xres == 0 && yres == 0) resolution = max(xdpi,ydpi); else if (xres != yres) { fprintf(stderr, "tiffread: error: file %s: xres (%f) is different from yres (%f)!\n", file, xres, yres); return(0); } else resolution = max(xres,yres); bytesperrow = (w / 8) * bitsperpixel; if (*image == NULL) { buffersize = (h + 8) * bytesperrow; *image = (unsigned char *) malloc (buffersize); } else if (buffersize < (h + 8) * bytesperrow) { if (debug) fprintf(stderr, "tiffread: increasing output buffer size from %ld to %ld\n", buffersize, (long)((h + 8) * bytesperrow)); buffersize = (h + 8) * bytesperrow; *image = (unsigned char *) realloc ((void *) (*image), buffersize); } if (*image == NULL) { fprintf(stderr, "tiffread: error: cannot allocate %ld-byte buffer for tiff image\n", h * bytesperrow); return(0); } for (row = 0, buf = *image; row < h; row += rowsperstrip, buf += rowsperstrip*scanline) { uint32 nrow = (row+rowsperstrip > h ? h-row : rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) { fprintf(stderr, "tiffread: error reading strip\n"); return(0); } } *x = w; *y = h; TIFFClose(tif); return(resolution); } /* * Writes a TIFF file out to disk with the following characteristics: * Resolution: a multiple of 75dpi if not specified * Dynamic range: 1 bit/pixel, 1 bit/sample * Compression: CCITT Group 4 facsimile encoding * Photometric Interpretation: min-is-white * Planar Configuration: single image plane * Returns 1 iff a write error occurs. */ int tiffwrite(char *file, unsigned char *image, int x, int y, int res, char *title) { uint32 row; double resolution = res; unsigned char *buf; TIFF *tif; if (NULL == (tif = TIFFOpen(file, "w"))) { fprintf(stderr, "tiffwrite: error opening file %s for writing!\n", file); return(1); } TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) x); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) y); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4); /* causes data to be in single huge strip */ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32) y); TIFFSetField(tif, TIFFTAG_XPOSITION, 0.0); TIFFSetField(tif, TIFFTAG_YPOSITION, 0.0); if (title && title[0]) TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, title); /* figure out resolution based on image dimensions; * assumption is that it is a multiple of 75dpi and * that the image should fit nicely on letter size media */ if (!resolution) for (resolution = 75; (y/resolution) > PGSIZEY; resolution *= 2) {} if (resolution >= 75 && resolution <= 600) { TIFFSetField(tif, TIFFTAG_XRESOLUTION, resolution); TIFFSetField(tif, TIFFTAG_YRESOLUTION, resolution); TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); } for (row = 0, buf = image; row < y; row++, buf += x/8) if (TIFFWriteScanline(tif, buf, row, 0) < 0) break; if (row != y) { fprintf(stderr, "tiffwrite: error writing bitmap data to file %s!\n", file); return(1); } TIFFClose(tif); return(0); } #define flipbits(a,b)\ (b) = ((a) >> 7) & 0x01;\ (b) |= ((a) >> 5) & 0x02;\ (b) |= ((a) >> 3) & 0x04;\ (b) |= ((a) >> 1) & 0x08;\ (b) |= ((a) << 1) & 0x10;\ (b) |= ((a) << 3) & 0x20;\ (b) |= ((a) << 5) & 0x40;\ (b) |= ((a) << 7) & 0x80 /* Flips a bitmap in place by rotating it 180 degrees */ int bitflipr180 (unsigned char *i, int x, int y) { unsigned char *b, *t, tmp; x /= 8; t = i; b = i + x * y - 1; if (x <= 0 || y <= 1) return(1); while (b > t) { tmp = *t; flipbits(*b,*t); flipbits(tmp,*b); t++; b--; } return(0); } static void rotate8x8(unsigned char*, int, unsigned char*, int, int); /* Flips a bitmap in place by rotating it 90 degrees clockwise */ int bitflipr90 (unsigned char *i, int x, int y) { unsigned char *f, *t, *tmpbuf = (unsigned char *) malloc((x*y)/8); register int k, n; x /= 8; f = tmpbuf; y /= 8; if (x <= 0 || y <= 1 || tmpbuf == NULL) return(1); memcpy(tmpbuf, i, x*y*8); for (k = 0; k < y; k++, f += 7 * x) for (n = 0, t = i + y - k; n < x; n++, t += 8 * y, f++) rotate8x8(f, x, t, y, 1); free(tmpbuf); return(0); } /* Flips a bitmap in place by rotating it 270 degrees clockwise */ int bitflipr270 (unsigned char *i, int x, int y) { unsigned char *f, *t, *tmpbuf = (unsigned char *) malloc((x*y)/8); register int k, n; x /= 8; f = tmpbuf + x * (y - 8) - 1; y /= 8; if (x <= 0 || y <= 1 || tmpbuf == NULL) return(1); memcpy(tmpbuf, i, x*y*8); for (k = 0; k < y; k++, f -= 7 * x) for (n = 0, t = i + y - k; n < x; n++, t += 8 * y, f--) rotate8x8(f, x, t, y, 0); free(tmpbuf); return(0); } /* Flips a bitmap in place left to right */ int bitfliplr (unsigned char *i, int x, int y) { unsigned char *l, *r, *b, tmp, *ei; x /= 8; ei = i + x * y; if (x <= 0 || y <= 1) return(1); for (b = i; b < ei; b += x) { l = b; r = b + x - 1; while (r > l) { tmp = *l; flipbits(*r,*l); flipbits(tmp,*r); l++; r--; } } return(0); } /* Flips a bitmap in place transposing top and bottom rows */ int bitfliptb (unsigned char *i, int x, int y) { unsigned char *b, *t, tmp, *p; register int n; x /= 8; p = i + x * (y - 1); if (x <= 0 || y <= 1) return(1); for (t = i; t < p; p -= x) { n = 0; b = p; while (n++ < x) { tmp = *t; *t++ = *b; *b++ = tmp; } } return(0); } #undef flipbits /* ** Rotate an 8x8 tile clockwise by table lookup ** and write to destination directly. ** Large bitmaps can be rotated an 8x8 tile at a time. ** The extraction is done a nybble at a time to reduce the ** size of the tables. ** ** Input parameters: ** src starting address of source 8x8 tile ** srcstep difference in byte address between ** adjacent rows in source bitmap ** dst starting address of destination 8x8 tile ** dststep difference in byte address between ** adjacent rows in destination bitmap ** ** Ken Yap (Centre for Spatial Information Systems, CSIRO DIT, Australia) ** after an idea suggested by Alan Paeth (U of Waterloo). */ typedef long bit32; #define table(name,n)\ static bit32 name[16] =\ {\ 0x00000000<> 4;\ low |= t[lownyb]; hi |= t[hinyb]; d += pstep #define unpack(d,w)\ *d = w & 0xff; d += pstep;\ *d = (w >> 8) & 0xff; d += pstep;\ *d = (w >> 16) & 0xff; d += pstep;\ *d = (w >> 24) & 0xff #define flipbits(a)\ tmp = ((a) >> 7) & 0x01;\ tmp |= ((a) >> 5) & 0x02;\ tmp |= ((a) >> 3) & 0x04;\ tmp |= ((a) >> 1) & 0x08;\ tmp |= ((a) << 1) & 0x10;\ tmp |= ((a) << 3) & 0x20;\ tmp |= ((a) << 5) & 0x40;\ tmp |= ((a) << 7) & 0x80;\ (a) = tmp static void rotate8x8(unsigned char *src, int srcstep, unsigned char *dst, int dststep, int flip) { register unsigned char *p, tmp = 0; register int pstep, lownyb, hinyb; register bit32 low, hi; low = hi = 0; p = src; pstep = srcstep; if (flip) { flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p = src; } extract(p,ltab0); extract(p,ltab1); extract(p,ltab2); extract(p,ltab3); extract(p,ltab4); extract(p,ltab5); extract(p,ltab6); extract(p,ltab7); p = dst; pstep = dststep; unpack(p,low); p += pstep; unpack(p,hi); if (flip) { p = dst; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); p += pstep; flipbits(*p); } }