/***************************************************************** * fltiff.c: FBM Release 1.2 24-Mar-93 Michael Mauldin * * Copyright (C) 1993 by Michael Mauldin. Permission is granted * to use this file in whole or in part for any purpose, educational, * recreational or commercial, provided that this copyright notice * is retained unchanged. This software is available to all free of * charge by anonymous FTP and in the UUNET archives. * * fltiff.c: * * CONTENTS * read_tiff (image, fname) * write_tiff (image, wfile, graybits) * * EDITLOG * LastEditDate = Mon Jun 25 00:18:04 1990 - Michael Mauldin * LastFileName = /usr2/mlm/src/misc/fbm/fltiff.c * * HISTORY * 24-Mar-93 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon * Created from flsun.c and tiff2fbm.c, fbm2tiff.c *****************************************************************/ # include # include # include # include # include # ifdef BYTE # undef BYTE # endif # include # include # include # include # include "fbm.h" # define RED 0 # define GRN 1 # define BLU 2 # ifdef __STDC__ # define FIELD(tif,f) TIFFFieldSet(tif, FIELD_ ## f) # else /* The following macro is taken from tiff_print.c */ # define FIELD(tif,f) TIFFFieldSet(tif, FIELD_/**/f) # endif #ifndef howmany # define howmany(x, y) (((x)+((y)-1))/(y)) #endif #define SCALE(x) (((x)*((1L<<16)-1))/256) /**************************************************************** * fbmid: ****************************************************************/ #ifndef lint static char *fbmid = "$FBM fltiff.c <1.2> 24-Mar-93 (C) 1993 by Michael Mauldin, source \ code available free from MLM@CS.CMU.EDU and from UUNET archives$"; #endif /**************************************************************** * write_tiff (image, fname, graybit) ****************************************************************/ write_tiff (image, fname, graybit) FBM *image; char *fname; int graybit; { int width, height, rowlen, planes, plnlen, k; int failed = 0; u_short config = PLANARCONFIG_CONTIG; u_short compression = COMPRESSION_NONE; u_short rowsperstrip = 0; u_char *bmp, *obm, *scanbuf; int row, linebytes; TIFF *out; /* Check for bad argument to reduced resolution argument */ switch (graybit) { case 1: case 2: case 4: /* These are standard values */ break; case 0: case 8: /* These mean no reduced resolution */ graybit = 0; break; default: fprintf (stderr, "Error: graybit value must be 0, 1, 2, or 4\n"); return (0); } width = image->hdr.cols; height = image->hdr.rows; rowlen = image->hdr.rowlen; planes = image->hdr.planes; plnlen = image->hdr.plnlen; /*-Start of Tiff writing code-------------------------------------*/ if (!(out = TIFFOpen (fname, "w"))) { return (0); } TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, height); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, graybit ? 1:image->hdr.planes); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, graybit ? graybit:image->hdr.bits); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); if (image->hdr.clrlen > 0 && !graybit) { register u_short *red; register int i, j; int mapsize, cbytes, nclrs; mapsize = 1<hdr.bits; if (image->hdr.clrlen > mapsize*3) { fprintf(stderr, "stdin: Huh, %d colormap entries, should be %d?\n", image->hdr.clrlen, mapsize*3); exit(-7); } cbytes = mapsize * 3 * sizeof (u_short); nclrs = image->hdr.clrlen/3; if ((red = (u_short *) malloc(cbytes)) == NULL) { perror ("colormap"); exit (-8); } /* XXX -- set pointers up before we step through arrays */ TIFFSetField(out, TIFFTAG_COLORMAP, red, red + mapsize, red + 2*mapsize); bmp = image->cm; for (j = 0; j < 3; j++) { for (i=0; i < nclrs; i++) *red++ = SCALE(*bmp++); for (; ihdr.planes == 3) && !graybit ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK); } TIFFSetField(out, TIFFTAG_COMPRESSION, compression); linebytes = (((image->hdr.bits * width+15) >> 3) &~ 1) * planes; if (TIFFScanlineSize(out) < linebytes) scanbuf = (u_char *)malloc(linebytes); else scanbuf = (u_char *)malloc(TIFFScanlineSize(out)); if (scanbuf == NULL) { perror ("mallocing scanbuf"); exit (1); } if (rowsperstrip != (u_short)-1) rowsperstrip = (8*1024)/linebytes; TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip == 0 ? 1 : rowsperstrip); /* Handle bitmaps first */ if (image->hdr.bits == 1 && image->hdr.physbits == 8) { int byte = 0, i; u_char *obm; for (row = 0; row < height; row++) { byte = 0; bmp = &image->bm[row*rowlen]; obm = scanbuf; /* Write out each group of 8 bytes as one byte */ for (i=0; ihdr.bits == 8) { int byte, mask, spb, shift, i; /* spb: Samples per byte mask */ u_char *obm; switch (graybit) { case 1: mask = 0x80; spb = 7; shift = 7; break; case 2: mask = 0xc0; spb = 3; shift = 6; break; case 4: mask = 0xf0; spb = 1; shift = 4; break; } for (row = 0; row < height; row++) { byte = 0; bmp = &image->bm[row*rowlen]; obm = scanbuf; /* Write out each group of 8 bytes as one byte */ for (i=0; i> shift); if ((++i & spb) == 0) { *obm++ = byte; byte=0; } } /* Handle stragglers if width not multiple of 8 */ if (i&spb) { while (i++ & spb) { byte <<= graybit; } *obm = byte; } if (TIFFWriteScanline(out, scanbuf, row, 0) < 0) { failed++; break; } } } /* Catch cases we cant handle */ else if (image->hdr.physbits != 8) { fprintf (stderr, "Error: cannot handle %d physical bits per pixel\n", image->hdr.physbits); (void) TIFFClose(out); return (0); } /* Handle 8bit grayscale or 24bit rgb */ else { fprintf (stderr, "Writing %d bit output, height %d, width %d, ", planes * image->hdr.physbits, height, width); fprintf (stderr, "planes %d, linebytes %d. plnlen %d, rowlen %d\n", planes, linebytes, plnlen, rowlen); for (row = 0; row < height; row++) { for (k=0; k= linebytes) { fprintf (stderr, "Overran scanbuf...\n"); abort(); } scanbuf[oi] = image->bm[k*plnlen + row*rowlen + i]; } } if (TIFFWriteScanline(out, scanbuf, row, 0) < 0) { failed++; break; } } } (void) TIFFClose(out); if (failed) { fprintf (stderr, "Could not write tiff file\n"); return (0); } return (1); } /**************************************************************** * read_tiff (image, rfile) ****************************************************************/ read_tiff (image, fname) FBM *image; char *fname; { int userdir = 1, fw, fh, rowlen, plnlen, clrlen=0, colors=0; double aspect = 0.0; char *title = NULL, *credits = NULL; TIFF *tif; TIFFDirectory *td; u_char *scanbuf, *tail; register u_char *pp, *obm, *tmp; int bitspersample, scanline, samplesperbyte; register unsigned int mask; register int shift, nib; register int poff, k, planes; int i, j, w, h, dirnum = 0; /* Clear the memory pointers so alloc_fbm won't be confused */ image->cm = image->bm = (unsigned char *) NULL; /* Now read in the TIFF format image */ if ((tif = TIFFOpen(fname, "r")) == NULL) { return (0); } do { ++dirnum; if (userdir != dirnum) continue; td = &tif->tif_dir; bitspersample = td->td_bitspersample; planes = td->td_samplesperpixel; if (td->td_planarconfig == PLANARCONFIG_CONTIG) { bitspersample *= planes; } scanline = howmany (bitspersample * td->td_imagewidth, 8); scanbuf = (u_char *) malloc (scanline); if (scanbuf == NULL) { printf ("No space for scanline buffer\n"); continue; } w = td->td_imagewidth; h = td->td_imagelength; switch (bitspersample) { case 1: samplesperbyte = 8; break; case 2: samplesperbyte = 4; break; case 4: samplesperbyte = 2; break; case 8: samplesperbyte = 1; break; case 24: samplesperbyte = 1; break; default: fprintf (stderr, "I can't handle %d bits per sample\n", bitspersample); if (tif) TIFFClose (tif); return (0); } /* Now build FBM image header */ if (bitspersample == 1) { rowlen = 16 * ((w+15)/16); } else { rowlen = 2 * ((w+1)/2); } plnlen = rowlen * h; /* Build header */ image->hdr.title[0] = image->hdr.credits[0] = '\0'; image->hdr.rows = h; image->hdr.cols = w; image->hdr.planes = planes; image->hdr.bits = bitspersample / planes; image->hdr.physbits = 8; image->hdr.rowlen = rowlen; image->hdr.plnlen = plnlen; colors = FIELD (tif,COLORMAP) ? (1 << td->td_bitspersample) : 0; image->hdr.clrlen = colors * 3; /* Determine aspect from X and Y resolution */ if (FIELD (tif,RESOLUTION) && td->td_yresolution != 0) { image->hdr.aspect = td->td_xresolution / td->td_yresolution; } else { image->hdr.aspect = 1.0; } /* Extract Title and Credit information */ if (FIELD (tif,DOCUMENTNAME)) { strcpy (image->hdr.title, td->td_documentname); } else if (FIELD (tif,IMAGEDESCRIPTION)) { strcpy (image->hdr.title, td->td_imagedescription); } else { strcpy (image->hdr.title, fname); } if (FIELD (tif,ARTIST)) { strcpy (image->hdr.credits, td->td_artist); } else if (FIELD (tif,SOFTWARE)) { strcpy (image->hdr.credits, td->td_software); } else if (FIELD (tif,MAKE)) { strcpy (image->hdr.credits, td->td_make); if (FIELD (tif,MODEL)) { strcat (image->hdr.credits, ", "); strcat (image->hdr.credits, td->td_model); } } fprintf (stderr, "Reading \"%s\" [%dx%d], %d bits, directory %d\n", image->hdr.title, w, h, bitspersample, userdir); alloc_fbm (image); /* Read colormap: Note TIFF colors are 16 bit, FBM colors 8 bit */ if (FIELD (tif,COLORMAP)) { for (i=0; icm[i] = td->td_colormap[0][i] >> 8; image->cm[i + colors] = td->td_colormap[1][i] >> 8; image->cm[i + colors + colors] = td->td_colormap[2][i] >> 8; } } /* Check for multiplane images */ if (td->td_planarconfig == PLANARCONFIG_SEPARATE && planes > 1) { fprintf (stderr, "Multiplane images (%d) not yet implemented\n", planes); if (tif) TIFFClose (tif); return (0); } else { /* * Read single plane images (for RGB color, values are stored in * successive bytes) */ /* Precompute mask and shift parameters */ switch (samplesperbyte) { case 8: mask = 0x01; shift = 1; break; case 4: mask = 0x03; shift = 2; break; case 2: mask = 0x0f; shift = 4; break; case 1: mask = 0xff; shift = 8; break; } fprintf (stderr, "Samples per byte %d, mask %02x, shift %d, planes %d, scanline %d\n", samplesperbyte, mask, shift, planes, scanline); /* Each loop does one scan line */ for (j=0; jtd_photometric == PHOTOMETRIC_MINISWHITE) { for (pp = scanbuf, i=scanline; --i >= 0; pp++) { *pp = ~ *pp; } } pp = scanbuf; obm = &image->bm[j * rowlen]; tmp = obm; tail = obm + w; nib = 8 - shift; if (samplesperbyte > 1) { nib = 8 - shift; for (; obm < tail; obm++) { for (k=0, poff=0; k> nib) & mask; # ifdef DEBUG if (j< 10 && (obm-tmp)< 18) { fprintf (stderr, "<%2d,%2d> obm[%d] = %d, nib %d, mask %d, pp %08x\n", (obm-tmp), j, poff, obm[poff], nib, mask, pp); } # endif if ((nib -= shift) < 0) { pp++; nib = 8 - shift; } } } } else { for (; obm < tail; obm++) { for (k=0, poff=0; k dirnum) { if (dirnum > 0) { fprintf (stderr, "File %s has only %d directories, %d out of range\n", fname, dirnum, userdir); } else { fprintf (stderr, "File %s has no directories\n", fname); } return (0); } return (1); }