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