1 /*
2  * xvtiffwr.c - write routine for TIFF pictures
3  *
4  * WriteTIFF(fp,pic,w,h,r,g,b,numcols,style,raw,fname,comment)
5  */
6 
7 #define NEEDSARGS
8 #include "xv.h"
9 
10 #ifdef HAVE_TIFF
11 
12 #include <tiffio.h>    /* has to be after xv.h, as it needs varargs/stdarg */
13 
14 
15 #define ALLOW_JPEG 0  /* set to '1' to allow 'JPEG' choice in dialog box */
16 
17 
18 static void setupColormap   PARM((TIFF *, byte *, byte *, byte *));
19 static int  WriteTIFF       PARM((FILE *, byte *, int, int, int,
20 				  byte *, byte *, byte *, int, int,
21 				  char *, int, char *));
22 
23 
24 
25 /*********************************************/
setupColormap(tif,rmap,gmap,bmap)26 static void setupColormap(tif, rmap, gmap, bmap)
27      TIFF *tif;
28      byte *rmap, *gmap, *bmap;
29 {
30   short red[256], green[256], blue[256];
31   int i;
32 
33   /* convert 8-bit colormap to 16-bit */
34   for (i=0; i<256; i++) {
35 #define	SCALE(x)	((((int)x)*((1L<<16)-1))/255)
36     red[i] = SCALE(rmap[i]);
37     green[i] = SCALE(gmap[i]);
38     blue[i] = SCALE(bmap[i]);
39   }
40   TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
41 }
42 
43 
44 
45 /*******************************************/
46 /* Returns '0' if successful. */
WriteTIFF(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,fname,comp,comment)47 static int WriteTIFF(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
48 		     fname,comp,comment)
49      FILE *fp;
50      byte *pic;
51      int   ptype,w,h,comp;
52      byte *rmap, *gmap, *bmap;
53      int   numcols, colorstyle;
54      char *fname, *comment;
55 {
56   TIFF *tif;
57   byte *pix;
58   int   i,j;
59   int   npixels = w*h;
60 
61   if (w <= 0 || h <= 0 || npixels/w != h) {
62     SetISTR(ISTR_WARNING, "%s: image dimensions too large", fname);
63     /* TIFFError(fname, "Image dimensions too large"); */
64     return -1;
65   }
66 
67 #ifndef VMS
68   tif = TIFFOpen(fname, "w");
69 #else
70   tif = TIFFFdOpen(dup(fileno(fp)), fname, "w");
71 #endif
72 
73   if (!tif) return -1;   /* GRR:  was 0 */
74 
75   WaitCursor();
76 
77   TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
78   TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
79   TIFFSetField(tif, TIFFTAG_COMPRESSION, comp);
80 
81   if (comment && strlen(comment) > (size_t) 0) {
82     TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, comment);
83   }
84 
85   if (comp == COMPRESSION_CCITTFAX3)
86       TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
87 	  GROUP3OPT_2DENCODING+GROUP3OPT_FILLBITS);
88 
89   if (comp == COMPRESSION_LZW)
90       TIFFSetField(tif, TIFFTAG_PREDICTOR, 2);
91 
92   TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
93   TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
94   TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
95   TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
96 
97   TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (int)2);
98   TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float) 72.0);
99   TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float) 72.0);
100 
101 
102   /* write the image data */
103 
104   if (ptype == PIC24) {  /* only have to deal with FULLCOLOR or GREYSCALE */
105     if (colorstyle == F_FULLCOLOR) {
106       int count = 3*npixels;
107 
108       if (count/3 != npixels) {  /* already know w, h, npixels > 0 */
109         /* SetISTR(ISTR_WARNING, "%s: image dimensions too large", fname); */
110         TIFFError(fname, "Image dimensions too large");
111         return -1;
112       }
113 
114       TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
115       TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8);
116       TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,     PHOTOMETRIC_RGB);
117 
118       TIFFWriteEncodedStrip(tif, 0, pic, count);
119     }
120 
121     else {  /* colorstyle == F_GREYSCALE */
122       byte *tpic, *tp, *sp;
123 
124       TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
125       TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8);
126       TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,    PHOTOMETRIC_MINISBLACK);
127 
128       tpic = (byte *) malloc((size_t) npixels);
129       if (!tpic) FatalError("unable to malloc in WriteTIFF()");
130 
131       for (i=0, tp=tpic, sp=pic; i<npixels; i++, sp+=3)
132 	*tp++ = MONO(sp[0],sp[1],sp[2]);
133 
134       TIFFWriteEncodedStrip(tif, 0, tpic, npixels);
135 
136       free(tpic);
137     }
138   }
139 
140   else {  /* PIC8 */
141     if (colorstyle == F_FULLCOLOR) {                  /* 8bit Palette RGB */
142       TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
143       TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
144       setupColormap(tif, rmap, gmap, bmap);
145       TIFFWriteEncodedStrip(tif, 0, pic, npixels);
146     }
147 
148     else if (colorstyle == F_GREYSCALE) {             /* 8-bit greyscale */
149       byte rgb[256];
150       byte *tpic = (byte *) malloc((size_t) npixels);
151       byte *tp = tpic;
152       TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
153       TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
154       for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
155       for (i=0, pix=pic; i<npixels; i++,pix++) {
156 	if ((i&0x7fff)==0) WaitCursor();
157 	*tp++ = rgb[*pix];
158       }
159       TIFFWriteEncodedStrip(tif, 0, tpic, npixels);
160       free(tpic);
161     }
162 
163     else if (colorstyle == F_BWDITHER) {             /* 1-bit B/W stipple */
164       int bit,k,flipbw;
165       byte *tpic, *tp;
166       tsize_t stripsize;  /* signed */
167 
168       flipbw = (MONO(rmap[0],gmap[0],bmap[0]) > MONO(rmap[1],gmap[1],bmap[1]));
169       TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
170       TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
171       stripsize = TIFFStripSize(tif);
172       if (stripsize <= 0) {
173         TIFFError(fname, "Image dimensions too large");
174         return -1;
175       }
176       tpic = (byte *) malloc((size_t) stripsize);
177       if (tpic == 0) {
178         TIFFError(fname, "No space for strip buffer");
179         return -1;
180       }
181       tp = tpic;
182       for (i=0, pix=pic; i<h; i++) {
183 	if ((i&15)==0) WaitCursor();
184 	for (j=0, bit=0, k=0; j<w; j++, pix++) {
185 	  k = (k << 1) | *pix;
186 	  bit++;
187 	  if (bit==8) {
188 	    if (flipbw) k = ~k;
189 	    *tp++ = (byte) (k&0xff);
190 	    bit = k = 0;
191 	  }
192 	} /* j */
193 	if (bit) {
194 	  k = k << (8-bit);
195 	  if (flipbw) k = ~k;
196 	  *tp++ = (byte) (k & 0xff);
197 	}
198       }
199       TIFFWriteEncodedStrip(tif, 0, tpic, stripsize);
200       free(tpic);
201     }
202   }
203 
204 
205   TIFFClose(tif);
206 
207   return 0;
208 }
209 
210 
211 
212 
213 /**** Stuff for TIFFDialog box ****/
214 
215 #define TWIDE 280
216 #define THIGH 160
217 #define T_NBUTTS 2
218 #define T_BOK    0
219 #define T_BCANC  1
220 #define BUTTH    24
221 
222 static void drawTD    PARM((int, int, int, int));
223 static void clickTD   PARM((int, int));
224 static void doCmd     PARM((int));
225 static void writeTIFF PARM((void));
226 
227 
228 /* local variables */
229 static char *filename;
230 static int   colorType;
231 static BUTT  tbut[T_NBUTTS];
232 static RBUTT *compRB;
233 
234 
235 
236 /***************************************************/
CreateTIFFW()237 void CreateTIFFW()
238 {
239   int	     y;
240 
241   tiffW = CreateWindow("xv tiff", "XVtiff", NULL,
242 		       TWIDE, THIGH, infofg, infobg, 0);
243   if (!tiffW) FatalError("can't create tiff window!");
244 
245   XSelectInput(theDisp, tiffW, ExposureMask | ButtonPressMask | KeyPressMask);
246 
247   BTCreate(&tbut[T_BOK], tiffW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
248 	   "Ok", infofg, infobg, hicol, locol);
249 
250   BTCreate(&tbut[T_BCANC], tiffW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
251 	   "Cancel", infofg, infobg, hicol, locol);
252 
253   y = 55;
254   compRB = RBCreate(NULL, tiffW, 36, y,   "None", infofg, infobg,hicol,locol);
255   RBCreate(compRB, tiffW, 36, y+18,       "LZW", infofg, infobg,hicol,locol);
256   RBCreate(compRB, tiffW, 36, y+36,       "PackBits", infofg, infobg,
257            hicol, locol);
258   RBCreate(compRB, tiffW, TWIDE/2, y,     "CCITT Group3", infofg, infobg,
259 	   hicol, locol);
260   RBCreate(compRB, tiffW, TWIDE/2, y+18,  "CCITT Group4", infofg, infobg,
261 	   hicol, locol);
262   if (ALLOW_JPEG) {
263     RBCreate(compRB, tiffW, TWIDE/2, y+36,  "JPEG", infofg, infobg,
264 	     hicol, locol);
265   }
266 
267   XMapSubwindows(theDisp, tiffW);
268 }
269 
270 
271 /***************************************************/
TIFFDialog(vis)272 void TIFFDialog(vis)
273 int vis;
274 {
275   if (vis) {
276     CenterMapWindow(tiffW, tbut[T_BOK].x + (int) tbut[T_BOK].w/2,
277 		    tbut[T_BOK].y + (int) tbut[T_BOK].h/2, TWIDE, THIGH);
278   }
279   else     XUnmapWindow(theDisp, tiffW);
280   tiffUp = vis;
281 }
282 
283 
284 /***************************************************/
TIFFCheckEvent(xev)285 int TIFFCheckEvent(xev)
286 XEvent *xev;
287 {
288   /* check event to see if it's for one of our subwindows.  If it is,
289      deal accordingly, and return '1'.  Otherwise, return '0' */
290 
291   int rv;
292   rv = 1;
293 
294   if (!tiffUp) return 0;
295 
296   if (xev->type == Expose) {
297     int x,y,w,h;
298     XExposeEvent *e = (XExposeEvent *) xev;
299     x = e->x;  y = e->y;  w = e->width;  h = e->height;
300 
301     if (e->window == tiffW)       drawTD(x, y, w, h);
302     else rv = 0;
303   }
304 
305   else if (xev->type == ButtonPress) {
306     XButtonEvent *e = (XButtonEvent *) xev;
307     int x,y;
308     x = e->x;  y = e->y;
309 
310     if (e->button == Button1) {
311       if      (e->window == tiffW)     clickTD(x,y);
312       else rv = 0;
313     }  /* button1 */
314     else rv = 0;
315   }  /* button press */
316 
317 
318   else if (xev->type == KeyPress) {
319     XKeyEvent *e = (XKeyEvent *) xev;
320     char buf[128];  KeySym ks;  XComposeStatus status;
321     int stlen;
322 
323     stlen = XLookupString(e,buf,128,&ks,&status);
324     buf[stlen] = '\0';
325 
326     RemapKeyCheck(ks, buf, &stlen);
327 
328     if (e->window == tiffW) {
329       if (stlen) {
330 	if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
331 	  FakeButtonPress(&tbut[T_BOK]);
332 	}
333 	else if (buf[0] == '\033') {            /* ESC */
334 	  FakeButtonPress(&tbut[T_BCANC]);
335 	}
336       }
337     }
338     else rv = 0;
339   }
340   else rv = 0;
341 
342   if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
343     XBell(theDisp, 50);
344     rv = 1;   /* eat it */
345   }
346 
347   return rv;
348 }
349 
350 
351 /***************************************************/
TIFFSaveParams(fname,col)352 void TIFFSaveParams(fname, col)
353 char *fname;
354 int col;
355 {
356   int cur;
357   cur = RBWhich(compRB);
358 
359   filename = fname;
360   colorType = col;
361   if (colorType == F_BWDITHER) {
362     RBSetActive(compRB,3,1);
363     RBSetActive(compRB,4,1);
364     if (ALLOW_JPEG) {
365       RBSetActive(compRB,5,0);
366       if (cur == 5) RBSelect(compRB,3);
367     }
368   }
369   else {
370     RBSetActive(compRB,3,0);
371     RBSetActive(compRB,4,0);
372     if (ALLOW_JPEG) RBSetActive(compRB,5,1);
373     if (cur == 3 || cur == 4) RBSelect(compRB,0);
374   }
375 }
376 
377 
378 /***************************************************/
drawTD(x,y,w,h)379 static void drawTD(x,y,w,h)
380 int x,y,w,h;
381 {
382   const char *title  = "Save TIFF file...";
383   int  i;
384   XRectangle xr;
385 
386   xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
387   XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
388 
389   XSetForeground(theDisp, theGC, infofg);
390   XSetBackground(theDisp, theGC, infobg);
391 
392   for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]);
393 
394   ULineString(tiffW, compRB->x-16, compRB->y-3-DESCENT, "Compression");
395   RBRedraw(compRB, -1);
396 
397   DrawString(tiffW, 20, 29, title);
398 
399   XSetClipMask(theDisp, theGC, None);
400 }
401 
402 
403 /***************************************************/
clickTD(x,y)404 static void clickTD(x,y)
405 int x,y;
406 {
407   int i;
408   BUTT *bp;
409 
410   /* check BUTTs */
411 
412   /* check the RBUTTS first, since they don't DO anything */
413   if ( (i=RBClick(compRB, x,y)) >= 0) {
414     (void) RBTrack(compRB, i);
415     return;
416   }
417 
418 
419   for (i=0; i<T_NBUTTS; i++) {
420     bp = &tbut[i];
421     if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
422   }
423 
424   if (i<T_NBUTTS) {  /* found one */
425     if (BTTrack(bp)) doCmd(i);
426   }
427 }
428 
429 
430 
431 /***************************************************/
doCmd(cmd)432 static void doCmd(cmd)
433 int cmd;
434 {
435   switch (cmd) {
436   case T_BOK: {
437     char *fullname;
438 
439     writeTIFF();
440     TIFFDialog(0);
441 
442     fullname = GetDirFullName();
443     if (!ISPIPE(fullname[0])) {
444       XVCreatedFile(fullname);
445       StickInCtrlList(0);
446     }
447   }
448     break;
449 
450   case T_BCANC:	TIFFDialog(0);   break;
451 
452   default:	break;
453   }
454 }
455 
456 
457 /*******************************************/
writeTIFF()458 static void writeTIFF()
459 {
460   FILE *fp;
461   int   w, h, nc, rv, comp, ptype, pfree;
462   byte *inpix, *rmap, *gmap, *bmap;
463 
464 
465   /* see if we can open the output file before proceeding */
466   fp = OpenOutFile(filename);
467   if (!fp) return;
468 
469   WaitCursor();
470   inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
471 
472   if (colorType == F_REDUCED) colorType = F_FULLCOLOR;
473 
474   switch (RBWhich(compRB)) {
475   case 0: comp = COMPRESSION_NONE;      break;
476   case 1: comp = COMPRESSION_LZW;       break;
477   case 2: comp = COMPRESSION_PACKBITS;  break;
478   case 3: comp = COMPRESSION_CCITTFAX3; break;
479   case 4: comp = COMPRESSION_CCITTFAX4; break;
480   case 5: comp = COMPRESSION_JPEG;      break;
481   default: comp = COMPRESSION_NONE;     break;
482   }
483 
484   rv = WriteTIFF(fp, inpix, ptype, w, h,
485 		 rmap, gmap, bmap, nc, colorType, filename, comp, picComments);
486 
487   SetCursors(-1);
488 
489   if (CloseOutFile(fp, filename, rv) == 0) DirBox(0);
490 
491   if (pfree) free(inpix);
492 }
493 
494 
495 #endif /* HAVE_TIFF */
496