]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/contrib/dbs/xtiff/xtiff.c
Define __VISUALC__ for ICC under Windows again.
[wxWidgets.git] / src / tiff / contrib / dbs / xtiff / xtiff.c
1 /*
2 *
3 * xtiff - view a TIFF file in an X window
4 *
5 * Dan Sears
6 * Chris Sears
7 *
8 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
9 *
10 * All Rights Reserved
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation, and that the name of Digital not be
17 * used in advertising or publicity pertaining to distribution of the
18 * software without specific, written prior permission.
19 *
20 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 * SOFTWARE.
27 *
28 * Revision 1.0 90/05/07
29 * Initial release.
30 * Revision 2.0 90/12/20
31 * Converted to use the Athena Widgets and the Xt Intrinsics.
32 *
33 * Notes:
34 *
35 * According to the TIFF 5.0 Specification, it is possible to have
36 * both a TIFFTAG_COLORMAP and a TIFFTAG_COLORRESPONSECURVE. This
37 * doesn't make sense since a TIFFTAG_COLORMAP is 16 bits wide and
38 * a TIFFTAG_COLORRESPONSECURVE is tfBitsPerSample bits wide for each
39 * channel. This is probably a bug in the specification.
40 * In this case, TIFFTAG_COLORRESPONSECURVE is ignored.
41 * This might make sense if TIFFTAG_COLORMAP was 8 bits wide.
42 *
43 * TIFFTAG_COLORMAP is often incorrectly written as ranging from
44 * 0 to 255 rather than from 0 to 65535. CheckAndCorrectColormap()
45 * takes care of this.
46 *
47 * Only ORIENTATION_TOPLEFT is supported correctly. This is the
48 * default TIFF and X orientation. Other orientations will be
49 * displayed incorrectly.
50 *
51 * There is no support for or use of 3/3/2 DirectColor visuals.
52 * TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE are not supported.
53 *
54 * Only TIFFTAG_BITSPERSAMPLE values that are 1, 2, 4 or 8 are supported.
55 */
56 #include <math.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <tiffio.h>
60 #include <X11/Xatom.h>
61 #include <X11/Intrinsic.h>
62 #include <X11/StringDefs.h>
63 #include <X11/Xproto.h>
64 #include <X11/Shell.h>
65 #include <X11/Xaw/Form.h>
66 #include <X11/Xaw/List.h>
67 #include <X11/Xaw/Label.h>
68 #include <X11/cursorfont.h>
69 #define XK_MISCELLANY
70 #include <X11/keysymdef.h>
71 #include "xtifficon.h"
72
73 #define TIFF_GAMMA "2.2" /* default gamma from the TIFF 5.0 spec */
74 #define ROUND(x) (uint16) ((x) + 0.5)
75 #define SCALE(x, s) (((x) * 65535L) / (s))
76 #define MCHECK(m) if (!m) { fprintf(stderr, "malloc failed\n"); exit(0); }
77 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
78 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
79 #define VIEWPORT_WIDTH 700
80 #define VIEWPORT_HEIGHT 500
81 #define KEY_TRANSLATE 20
82
83 #ifdef __STDC__
84 #define PP(args) args
85 #else
86 #define PP(args) ()
87 #endif
88
89 int main PP((int argc, char **argv));
90 void OpenTIFFFile PP((void));
91 void GetTIFFHeader PP((void));
92 void SetNameLabel PP((void));
93 void CheckAndCorrectColormap PP((void));
94 void SimpleGammaCorrection PP((void));
95 void GetVisual PP((void));
96 Boolean SearchVisualList PP((int image_depth,
97 int visual_class, Visual **visual));
98 void GetTIFFImage PP((void));
99 void CreateXImage PP((void));
100 XtCallbackProc SelectProc PP((Widget w, caddr_t unused_1, caddr_t unused_2));
101 void QuitProc PP((void));
102 void NextProc PP((void));
103 void PreviousProc PP((void));
104 void PageProc PP((int direction));
105 void EventProc PP((Widget widget, caddr_t unused, XEvent *event));
106 void ResizeProc PP((void));
107 int XTiffErrorHandler PP((Display *display, XErrorEvent *error_event));
108 void Usage PP((void));
109
110 int xtVersion = XtSpecificationRelease; /* xtiff depends on R4 or higher */
111
112 /*
113 * Xt data structures
114 */
115 Widget shellWidget, formWidget, listWidget, labelWidget, imageWidget;
116
117 enum { ButtonQuit = 0, ButtonPreviousPage = 1, ButtonNextPage = 2 };
118
119 String buttonStrings[] = { "Quit", "Previous", "Next" };
120
121 static XrmOptionDescRec shellOptions[] = {
122 { "-help", "*help", XrmoptionNoArg, (caddr_t) "True" },
123 { "-gamma", "*gamma", XrmoptionSepArg, NULL },
124 { "-usePixmap", "*usePixmap", XrmoptionSepArg, NULL },
125 { "-viewportWidth", "*viewportWidth", XrmoptionSepArg, NULL },
126 { "-viewportHeight", "*viewportHeight", XrmoptionSepArg, NULL },
127 { "-translate", "*translate", XrmoptionSepArg, NULL },
128 { "-verbose", "*verbose", XrmoptionSepArg, NULL }
129 };
130
131 typedef struct {
132 Boolean help;
133 float gamma;
134 Boolean usePixmap;
135 uint32 viewportWidth;
136 uint32 viewportHeight;
137 int translate;
138 Boolean verbose;
139 } AppData, *AppDataPtr;
140
141 AppData appData;
142
143 XtResource clientResources[] = {
144 {
145 "help", XtCBoolean, XtRBoolean, sizeof(Boolean),
146 XtOffset(AppDataPtr, help), XtRImmediate, (XtPointer) False
147 }, {
148 "gamma", "Gamma", XtRFloat, sizeof(float),
149 XtOffset(AppDataPtr, gamma), XtRString, (XtPointer) TIFF_GAMMA
150 }, {
151 "usePixmap", "UsePixmap", XtRBoolean, sizeof(Boolean),
152 XtOffset(AppDataPtr, usePixmap), XtRImmediate, (XtPointer) True
153 }, {
154 "viewportWidth", "ViewportWidth", XtRInt, sizeof(int),
155 XtOffset(AppDataPtr, viewportWidth), XtRImmediate,
156 (XtPointer) VIEWPORT_WIDTH
157 }, {
158 "viewportHeight", "ViewportHeight", XtRInt, sizeof(int),
159 XtOffset(AppDataPtr, viewportHeight), XtRImmediate,
160 (XtPointer) VIEWPORT_HEIGHT
161 }, {
162 "translate", "Translate", XtRInt, sizeof(int),
163 XtOffset(AppDataPtr, translate), XtRImmediate, (XtPointer) KEY_TRANSLATE
164 }, {
165 "verbose", "Verbose", XtRBoolean, sizeof(Boolean),
166 XtOffset(AppDataPtr, verbose), XtRImmediate, (XtPointer) True
167 }
168 };
169
170 Arg formArgs[] = {
171 { XtNresizable, True }
172 };
173
174 Arg listArgs[] = {
175 { XtNresizable, False },
176 { XtNborderWidth, 0 },
177 { XtNdefaultColumns, 3 },
178 { XtNforceColumns, True },
179 { XtNlist, (int) buttonStrings },
180 { XtNnumberStrings, XtNumber(buttonStrings) },
181 { XtNtop, XtChainTop },
182 { XtNleft, XtChainLeft },
183 { XtNbottom, XtChainTop },
184 { XtNright, XtChainLeft }
185 };
186
187 Arg labelArgs[] = {
188 { XtNresizable, False },
189 { XtNwidth, 200 },
190 { XtNborderWidth, 0 },
191 { XtNjustify, XtJustifyLeft },
192 { XtNtop, XtChainTop },
193 { XtNleft, XtChainLeft },
194 { XtNbottom, XtChainTop },
195 { XtNright, XtChainLeft }
196 };
197
198 Arg imageArgs[] = {
199 { XtNresizable, True },
200 { XtNborderWidth, 0 },
201 { XtNtop, XtChainTop },
202 { XtNleft, XtChainLeft },
203 { XtNbottom, XtChainTop },
204 { XtNright, XtChainLeft }
205 };
206
207 XtActionsRec actionsTable[] = {
208 { "quit", QuitProc },
209 { "next", NextProc },
210 { "previous", PreviousProc },
211 { "notifyresize", ResizeProc }
212 };
213
214 char translationsTable[] = "<Key>q: quit() \n \
215 <Key>Q: quit() \n \
216 <Message>WM_PROTOCOLS: quit()\n \
217 <Key>p: previous() \n \
218 <Key>P: previous() \n \
219 <Key>n: next() \n \
220 <Key>N: next() \n \
221 <Configure>: notifyresize()";
222
223 /*
224 * X data structures
225 */
226 Colormap xColormap;
227 Display * xDisplay;
228 Pixmap xImagePixmap;
229 Visual * xVisual;
230 XImage * xImage;
231 GC xWinGc;
232 int xImageDepth, xScreen, xRedMask, xGreenMask, xBlueMask,
233 xOffset = 0, yOffset = 0, grabX = -1, grabY = -1;
234 unsigned char basePixel = 0;
235
236 /*
237 * TIFF data structures
238 */
239 TIFF * tfFile = NULL;
240 uint32 tfImageWidth, tfImageHeight;
241 uint16 tfBitsPerSample, tfSamplesPerPixel, tfPlanarConfiguration,
242 tfPhotometricInterpretation, tfGrayResponseUnit,
243 tfImageDepth, tfBytesPerRow;
244 int tfDirectory = 0, tfMultiPage = False;
245 double tfUnitMap, tfGrayResponseUnitMap[] = {
246 -1, -10, -100, -1000, -10000, -100000
247 };
248
249 /*
250 * display data structures
251 */
252 double *dRed, *dGreen, *dBlue;
253
254 /*
255 * shared data structures
256 */
257 uint16 * redMap = NULL, *greenMap = NULL, *blueMap = NULL,
258 *grayMap = NULL, colormapSize;
259 char * imageMemory;
260 char * fileName;
261
262 int
263 main(int argc, char **argv)
264 {
265 XSetWindowAttributes window_attributes;
266 Widget widget_list[3];
267 Arg args[5];
268
269 setbuf(stdout, NULL); setbuf(stderr, NULL);
270
271 shellWidget = XtInitialize(argv[0], "XTiff", shellOptions,
272 XtNumber(shellOptions), &argc, argv);
273
274 XSetErrorHandler(XTiffErrorHandler);
275
276 XtGetApplicationResources(shellWidget, &appData,
277 (XtResourceList) clientResources, (Cardinal) XtNumber(clientResources),
278 (ArgList) NULL, (Cardinal) 0);
279
280 if ((argc <= 1) || (argc > 2) || appData.help)
281 Usage();
282
283 if (appData.verbose == False) {
284 TIFFSetErrorHandler(0);
285 TIFFSetWarningHandler(0);
286 }
287
288 fileName = argv[1];
289
290 xDisplay = XtDisplay(shellWidget);
291 xScreen = DefaultScreen(xDisplay);
292
293 OpenTIFFFile();
294 GetTIFFHeader();
295 SimpleGammaCorrection();
296 GetVisual();
297 GetTIFFImage();
298
299 /*
300 * Send visual, colormap, depth and iconPixmap to shellWidget.
301 * Sending the visual to the shell is only possible with the advent of R4.
302 */
303 XtSetArg(args[0], XtNvisual, xVisual);
304 XtSetArg(args[1], XtNcolormap, xColormap);
305 XtSetArg(args[2], XtNdepth,
306 xImageDepth == 1 ? DefaultDepth(xDisplay, xScreen) : xImageDepth);
307 XtSetArg(args[3], XtNiconPixmap,
308 XCreateBitmapFromData(xDisplay, RootWindow(xDisplay, xScreen),
309 xtifficon_bits, xtifficon_width, xtifficon_height));
310 XtSetArg(args[4], XtNallowShellResize, True);
311 XtSetValues(shellWidget, args, 5);
312
313 /*
314 * widget instance hierarchy
315 */
316 formWidget = XtCreateManagedWidget("form", formWidgetClass,
317 shellWidget, formArgs, XtNumber(formArgs));
318
319 widget_list[0] = listWidget = XtCreateWidget("list",
320 listWidgetClass, formWidget, listArgs, XtNumber(listArgs));
321
322 widget_list[1] = labelWidget = XtCreateWidget("label",
323 labelWidgetClass, formWidget, labelArgs, XtNumber(labelArgs));
324
325 widget_list[2] = imageWidget = XtCreateWidget("image",
326 widgetClass, formWidget, imageArgs, XtNumber(imageArgs));
327
328 XtManageChildren(widget_list, XtNumber(widget_list));
329
330 /*
331 * initial widget sizes - for small images let xtiff size itself
332 */
333 if (tfImageWidth >= appData.viewportWidth) {
334 XtSetArg(args[0], XtNwidth, appData.viewportWidth);
335 XtSetValues(shellWidget, args, 1);
336 }
337 if (tfImageHeight >= appData.viewportHeight) {
338 XtSetArg(args[0], XtNheight, appData.viewportHeight);
339 XtSetValues(shellWidget, args, 1);
340 }
341
342 XtSetArg(args[0], XtNwidth, tfImageWidth);
343 XtSetArg(args[1], XtNheight, tfImageHeight);
344 XtSetValues(imageWidget, args, 2);
345
346 /*
347 * formWidget uses these constraints but they are stored in the children.
348 */
349 XtSetArg(args[0], XtNfromVert, listWidget);
350 XtSetValues(imageWidget, args, 1);
351 XtSetArg(args[0], XtNfromHoriz, listWidget);
352 XtSetValues(labelWidget, args, 1);
353
354 SetNameLabel();
355
356 XtAddCallback(listWidget, XtNcallback, (XtCallbackProc) SelectProc,
357 (XtPointer) NULL);
358
359 XtAddActions(actionsTable, XtNumber(actionsTable));
360 XtSetArg(args[0], XtNtranslations,
361 XtParseTranslationTable(translationsTable));
362 XtSetValues(formWidget, &args[0], 1);
363 XtSetValues(imageWidget, &args[0], 1);
364
365 /*
366 * This is intended to be a little faster than going through
367 * the translation manager.
368 */
369 XtAddEventHandler(imageWidget, ExposureMask | ButtonPressMask
370 | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
371 False, EventProc, NULL);
372
373 XtRealizeWidget(shellWidget);
374
375 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_fleur);
376 XChangeWindowAttributes(xDisplay, XtWindow(imageWidget),
377 CWCursor, &window_attributes);
378
379 CreateXImage();
380
381 XtMainLoop();
382
383 return 0;
384 }
385
386 void
387 OpenTIFFFile()
388 {
389 if (tfFile != NULL)
390 TIFFClose(tfFile);
391
392 if ((tfFile = TIFFOpen(fileName, "r")) == NULL) {
393 fprintf(appData.verbose ? stderr : stdout,
394 "xtiff: can't open %s as a TIFF file\n", fileName);
395 exit(0);
396 }
397
398 tfMultiPage = (TIFFLastDirectory(tfFile) ? False : True);
399 }
400
401 void
402 GetTIFFHeader()
403 {
404 register int i;
405
406 if (!TIFFSetDirectory(tfFile, tfDirectory)) {
407 fprintf(stderr, "xtiff: can't seek to directory %d in %s\n",
408 tfDirectory, fileName);
409 exit(0);
410 }
411
412 TIFFGetField(tfFile, TIFFTAG_IMAGEWIDTH, &tfImageWidth);
413 TIFFGetField(tfFile, TIFFTAG_IMAGELENGTH, &tfImageHeight);
414
415 /*
416 * If the following tags aren't present then use the TIFF defaults.
417 */
418 TIFFGetFieldDefaulted(tfFile, TIFFTAG_BITSPERSAMPLE, &tfBitsPerSample);
419 TIFFGetFieldDefaulted(tfFile, TIFFTAG_SAMPLESPERPIXEL, &tfSamplesPerPixel);
420 TIFFGetFieldDefaulted(tfFile, TIFFTAG_PLANARCONFIG, &tfPlanarConfiguration);
421 TIFFGetFieldDefaulted(tfFile, TIFFTAG_GRAYRESPONSEUNIT, &tfGrayResponseUnit);
422
423 tfUnitMap = tfGrayResponseUnitMap[tfGrayResponseUnit];
424 colormapSize = 1 << tfBitsPerSample;
425 tfImageDepth = tfBitsPerSample * tfSamplesPerPixel;
426
427 dRed = (double *) malloc(colormapSize * sizeof(double));
428 dGreen = (double *) malloc(colormapSize * sizeof(double));
429 dBlue = (double *) malloc(colormapSize * sizeof(double));
430 MCHECK(dRed); MCHECK(dGreen); MCHECK(dBlue);
431
432 /*
433 * If TIFFTAG_PHOTOMETRIC is not present then assign a reasonable default.
434 * The TIFF 5.0 specification doesn't give a default.
435 */
436 if (!TIFFGetField(tfFile, TIFFTAG_PHOTOMETRIC,
437 &tfPhotometricInterpretation)) {
438 if (tfSamplesPerPixel != 1)
439 tfPhotometricInterpretation = PHOTOMETRIC_RGB;
440 else if (tfBitsPerSample == 1)
441 tfPhotometricInterpretation = PHOTOMETRIC_MINISBLACK;
442 else if (TIFFGetField(tfFile, TIFFTAG_COLORMAP,
443 &redMap, &greenMap, &blueMap)) {
444 tfPhotometricInterpretation = PHOTOMETRIC_PALETTE;
445 redMap = greenMap = blueMap = NULL;
446 } else
447 tfPhotometricInterpretation = PHOTOMETRIC_MINISBLACK;
448 }
449
450 /*
451 * Given TIFFTAG_PHOTOMETRIC extract or create the response curves.
452 */
453 switch (tfPhotometricInterpretation) {
454 case PHOTOMETRIC_RGB:
455 redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
456 greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
457 blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
458 MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
459 for (i = 0; i < colormapSize; i++)
460 dRed[i] = dGreen[i] = dBlue[i]
461 = (double) SCALE(i, colormapSize - 1);
462 break;
463 case PHOTOMETRIC_PALETTE:
464 if (!TIFFGetField(tfFile, TIFFTAG_COLORMAP,
465 &redMap, &greenMap, &blueMap)) {
466 redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
467 greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
468 blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
469 MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
470 for (i = 0; i < colormapSize; i++)
471 dRed[i] = dGreen[i] = dBlue[i]
472 = (double) SCALE(i, colormapSize - 1);
473 } else {
474 CheckAndCorrectColormap();
475 for (i = 0; i < colormapSize; i++) {
476 dRed[i] = (double) redMap[i];
477 dGreen[i] = (double) greenMap[i];
478 dBlue[i] = (double) blueMap[i];
479 }
480 }
481 break;
482 case PHOTOMETRIC_MINISWHITE:
483 redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
484 greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
485 blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
486 MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
487 for (i = 0; i < colormapSize; i++)
488 dRed[i] = dGreen[i] = dBlue[i] = (double)
489 SCALE(colormapSize-1-i, colormapSize-1);
490 break;
491 case PHOTOMETRIC_MINISBLACK:
492 redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
493 greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
494 blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
495 MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
496 for (i = 0; i < colormapSize; i++)
497 dRed[i] = dGreen[i] = dBlue[i] = (double) SCALE(i, colormapSize-1);
498 break;
499 default:
500 fprintf(stderr,
501 "xtiff: can't display photometric interpretation type %d\n",
502 tfPhotometricInterpretation);
503 exit(0);
504 }
505 }
506
507 void
508 SetNameLabel()
509 {
510 char buffer[BUFSIZ];
511 Arg args[1];
512
513 if (tfMultiPage)
514 sprintf(buffer, "%s - page %d", fileName, tfDirectory);
515 else
516 strcpy(buffer, fileName);
517 XtSetArg(args[0], XtNlabel, buffer);
518 XtSetValues(labelWidget, args, 1);
519 }
520
521 /*
522 * Many programs get TIFF colormaps wrong. They use 8-bit colormaps instead of
523 * 16-bit colormaps. This function is a heuristic to detect and correct this.
524 */
525 void
526 CheckAndCorrectColormap()
527 {
528 register int i;
529
530 for (i = 0; i < colormapSize; i++)
531 if ((redMap[i] > 255) || (greenMap[i] > 255) || (blueMap[i] > 255))
532 return;
533
534 for (i = 0; i < colormapSize; i++) {
535 redMap[i] = SCALE(redMap[i], 255);
536 greenMap[i] = SCALE(greenMap[i], 255);
537 blueMap[i] = SCALE(blueMap[i], 255);
538 }
539 TIFFWarning(fileName, "Assuming 8-bit colormap");
540 }
541
542 void
543 SimpleGammaCorrection()
544 {
545 register int i;
546 register double i_gamma = 1.0 / appData.gamma;
547
548 for (i = 0; i < colormapSize; i++) {
549 if (((tfPhotometricInterpretation == PHOTOMETRIC_MINISWHITE)
550 && (i == colormapSize - 1))
551 || ((tfPhotometricInterpretation == PHOTOMETRIC_MINISBLACK)
552 && (i == 0)))
553 redMap[i] = greenMap[i] = blueMap[i] = 0;
554 else {
555 redMap[i] = ROUND((pow(dRed[i] / 65535.0, i_gamma) * 65535.0));
556 greenMap[i] = ROUND((pow(dGreen[i] / 65535.0, i_gamma) * 65535.0));
557 blueMap[i] = ROUND((pow(dBlue[i] / 65535.0, i_gamma) * 65535.0));
558 }
559 }
560
561 free(dRed); free(dGreen); free(dBlue);
562 }
563
564 static char* classNames[] = {
565 "StaticGray",
566 "GrayScale",
567 "StaticColor",
568 "PseudoColor",
569 "TrueColor",
570 "DirectColor"
571 };
572
573 /*
574 * Current limitation: the visual is set initially by the first file.
575 * It cannot be changed.
576 */
577 void
578 GetVisual()
579 {
580 XColor *colors = NULL;
581 unsigned long *pixels = NULL;
582 unsigned long i;
583
584 switch (tfImageDepth) {
585 /*
586 * X really wants a 32-bit image with the fourth channel unused,
587 * but the visual structure thinks it's 24-bit. bitmap_unit is 32.
588 */
589 case 32:
590 case 24:
591 if (SearchVisualList(24, DirectColor, &xVisual) == False) {
592 fprintf(stderr, "xtiff: 24-bit DirectColor visual not available\n");
593 exit(0);
594 }
595
596 colors = (XColor *) malloc(3 * colormapSize * sizeof(XColor));
597 MCHECK(colors);
598
599 for (i = 0; i < colormapSize; i++) {
600 colors[i].pixel = (i << 16) + (i << 8) + i;
601 colors[i].red = redMap[i];
602 colors[i].green = greenMap[i];
603 colors[i].blue = blueMap[i];
604 colors[i].flags = DoRed | DoGreen | DoBlue;
605 }
606
607 xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
608 xVisual, AllocAll);
609 XStoreColors(xDisplay, xColormap, colors, colormapSize);
610 break;
611 case 8:
612 case 4:
613 case 2:
614 /*
615 * We assume that systems with 24-bit visuals also have 8-bit visuals.
616 * We don't promote from 8-bit PseudoColor to 24/32 bit DirectColor.
617 */
618 switch (tfPhotometricInterpretation) {
619 case PHOTOMETRIC_MINISWHITE:
620 case PHOTOMETRIC_MINISBLACK:
621 if (SearchVisualList((int) tfImageDepth, GrayScale, &xVisual) == True)
622 break;
623 case PHOTOMETRIC_PALETTE:
624 if (SearchVisualList((int) tfImageDepth, PseudoColor, &xVisual) == True)
625 break;
626 default:
627 fprintf(stderr, "xtiff: Unsupported TIFF/X configuration\n");
628 exit(0);
629 }
630
631 colors = (XColor *) malloc(colormapSize * sizeof(XColor));
632 MCHECK(colors);
633
634 for (i = 0; i < colormapSize; i++) {
635 colors[i].pixel = i;
636 colors[i].red = redMap[i];
637 colors[i].green = greenMap[i];
638 colors[i].blue = blueMap[i];
639 colors[i].flags = DoRed | DoGreen | DoBlue;
640 }
641
642 /*
643 * xtiff's colormap allocation is private. It does not attempt
644 * to detect whether any existing colormap entries are suitable
645 * for its use. This will cause colormap flashing. Furthermore,
646 * background and foreground are taken from the environment.
647 * For example, the foreground color may be red when the visual
648 * is GrayScale. If the colormap is completely populated,
649 * Xt will not be able to allocate fg and bg.
650 */
651 if (tfImageDepth == 8)
652 xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
653 xVisual, AllocAll);
654 else {
655 xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
656 xVisual, AllocNone);
657 pixels = (unsigned long *)
658 malloc(colormapSize * sizeof(unsigned long));
659 MCHECK(pixels);
660 (void) XAllocColorCells(xDisplay, xColormap, True,
661 NULL, 0, pixels, colormapSize);
662 basePixel = (unsigned char) pixels[0];
663 free(pixels);
664 }
665 XStoreColors(xDisplay, xColormap, colors, colormapSize);
666 break;
667 case 1:
668 xImageDepth = 1;
669 xVisual = DefaultVisual(xDisplay, xScreen);
670 xColormap = DefaultColormap(xDisplay, xScreen);
671 break;
672 default:
673 fprintf(stderr, "xtiff: unsupported image depth %d\n", tfImageDepth);
674 exit(0);
675 }
676
677 if (appData.verbose == True)
678 fprintf(stderr, "%s: Using %d-bit %s visual.\n",
679 fileName, xImageDepth, classNames[xVisual->class]);
680
681 if (colors != NULL)
682 free(colors);
683 if (grayMap != NULL)
684 free(grayMap);
685 if (redMap != NULL)
686 free(redMap);
687 if (greenMap != NULL)
688 free(greenMap);
689 if (blueMap != NULL)
690 free(blueMap);
691
692 colors = NULL; grayMap = redMap = greenMap = blueMap = NULL;
693 }
694
695 /*
696 * Search for an appropriate visual. Promote where necessary.
697 * Check to make sure that ENOUGH colormap entries are writeable.
698 * basePixel was determined when XAllocColorCells() contiguously
699 * allocated enough entries. basePixel is used below in GetTIFFImage.
700 */
701 Boolean
702 SearchVisualList(image_depth, visual_class, visual)
703 int image_depth, visual_class;
704 Visual **visual;
705 {
706 XVisualInfo template_visual, *visual_list, *vl;
707 int i, n_visuals;
708
709 template_visual.screen = xScreen;
710 vl = visual_list = XGetVisualInfo(xDisplay, VisualScreenMask,
711 &template_visual, &n_visuals);
712
713 if (n_visuals == 0) {
714 fprintf(stderr, "xtiff: visual list not available\n");
715 exit(0);
716 }
717
718 for (i = 0; i < n_visuals; vl++, i++) {
719 if ((vl->class == visual_class) && (vl->depth >= image_depth)
720 && (vl->visual->map_entries >= (1 << vl->depth))) {
721 *visual = vl->visual;
722 xImageDepth = vl->depth;
723 xRedMask = vl->red_mask;
724 xGreenMask = vl->green_mask;
725 xBlueMask = vl->blue_mask;
726 XFree((char *) visual_list);
727 return True;
728 }
729 }
730
731 XFree((char *) visual_list);
732 return False;
733 }
734
735 void
736 GetTIFFImage()
737 {
738 int pixel_map[3], red_shift, green_shift, blue_shift;
739 char *scan_line, *output_p, *input_p;
740 uint32 i, j;
741 uint16 s;
742
743 scan_line = (char *) malloc(tfBytesPerRow = TIFFScanlineSize(tfFile));
744 MCHECK(scan_line);
745
746 if ((tfImageDepth == 32) || (tfImageDepth == 24)) {
747 output_p = imageMemory = (char *)
748 malloc(tfImageWidth * tfImageHeight * 4);
749 MCHECK(imageMemory);
750
751 /*
752 * Handle different color masks for different frame buffers.
753 */
754 if (ImageByteOrder(xDisplay) == LSBFirst) { /* DECstation 5000 */
755 red_shift = pixel_map[0] = xRedMask == 0xFF000000 ? 3
756 : (xRedMask == 0xFF0000 ? 2 : (xRedMask == 0xFF00 ? 1 : 0));
757 green_shift = pixel_map[1] = xGreenMask == 0xFF000000 ? 3
758 : (xGreenMask == 0xFF0000 ? 2 : (xGreenMask == 0xFF00 ? 1 : 0));
759 blue_shift = pixel_map[2] = xBlueMask == 0xFF000000 ? 3
760 : (xBlueMask == 0xFF0000 ? 2 : (xBlueMask == 0xFF00 ? 1 : 0));
761 } else { /* Ardent */
762 red_shift = pixel_map[0] = xRedMask == 0xFF000000 ? 0
763 : (xRedMask == 0xFF0000 ? 1 : (xRedMask == 0xFF00 ? 2 : 3));
764 green_shift = pixel_map[0] = xGreenMask == 0xFF000000 ? 0
765 : (xGreenMask == 0xFF0000 ? 1 : (xGreenMask == 0xFF00 ? 2 : 3));
766 blue_shift = pixel_map[0] = xBlueMask == 0xFF000000 ? 0
767 : (xBlueMask == 0xFF0000 ? 1 : (xBlueMask == 0xFF00 ? 2 : 3));
768 }
769
770 if (tfPlanarConfiguration == PLANARCONFIG_CONTIG) {
771 for (i = 0; i < tfImageHeight; i++) {
772 if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
773 break;
774 for (input_p = scan_line, j = 0; j < tfImageWidth; j++) {
775 *(output_p + red_shift) = *input_p++;
776 *(output_p + green_shift) = *input_p++;
777 *(output_p + blue_shift) = *input_p++;
778 output_p += 4;
779 if (tfSamplesPerPixel == 4) /* skip the fourth channel */
780 input_p++;
781 }
782 }
783 } else {
784 for (s = 0; s < tfSamplesPerPixel; s++) {
785 if (s == 3) /* skip the fourth channel */
786 continue;
787 for (i = 0; i < tfImageHeight; i++) {
788 if (TIFFReadScanline(tfFile, scan_line, i, s) < 0)
789 break;
790 input_p = scan_line;
791 output_p = imageMemory + (i*tfImageWidth*4) + pixel_map[s];
792 for (j = 0; j < tfImageWidth; j++, output_p += 4)
793 *output_p = *input_p++;
794 }
795 }
796 }
797 } else {
798 if (xImageDepth == tfImageDepth) {
799 output_p = imageMemory = (char *)
800 malloc(tfBytesPerRow * tfImageHeight);
801 MCHECK(imageMemory);
802
803 for (i = 0; i < tfImageHeight; i++, output_p += tfBytesPerRow)
804 if (TIFFReadScanline(tfFile, output_p, i, 0) < 0)
805 break;
806 } else if ((xImageDepth == 8) && (tfImageDepth == 4)) {
807 output_p = imageMemory = (char *)
808 malloc(tfBytesPerRow * 2 * tfImageHeight + 2);
809 MCHECK(imageMemory);
810
811 /*
812 * If a scanline is of odd size the inner loop below will overshoot.
813 * This is handled very simply by recalculating the start point at
814 * each scanline and padding imageMemory a little at the end.
815 */
816 for (i = 0; i < tfImageHeight; i++) {
817 if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
818 break;
819 output_p = &imageMemory[i * tfImageWidth];
820 input_p = scan_line;
821 for (j = 0; j < tfImageWidth; j += 2, input_p++) {
822 *output_p++ = (*input_p >> 4) + basePixel;
823 *output_p++ = (*input_p & 0xf) + basePixel;
824 }
825 }
826 } else if ((xImageDepth == 8) && (tfImageDepth == 2)) {
827 output_p = imageMemory = (char *)
828 malloc(tfBytesPerRow * 4 * tfImageHeight + 4);
829 MCHECK(imageMemory);
830
831 for (i = 0; i < tfImageHeight; i++) {
832 if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
833 break;
834 output_p = &imageMemory[i * tfImageWidth];
835 input_p = scan_line;
836 for (j = 0; j < tfImageWidth; j += 4, input_p++) {
837 *output_p++ = (*input_p >> 6) + basePixel;
838 *output_p++ = ((*input_p >> 4) & 3) + basePixel;
839 *output_p++ = ((*input_p >> 2) & 3) + basePixel;
840 *output_p++ = (*input_p & 3) + basePixel;
841 }
842 }
843 } else if ((xImageDepth == 4) && (tfImageDepth == 2)) {
844 output_p = imageMemory = (char *)
845 malloc(tfBytesPerRow * 2 * tfImageHeight + 2);
846 MCHECK(imageMemory);
847
848 for (i = 0; i < tfImageHeight; i++) {
849 if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
850 break;
851 output_p = &imageMemory[i * tfBytesPerRow * 2];
852 input_p = scan_line;
853 for (j = 0; j < tfImageWidth; j += 4, input_p++) {
854 *output_p++ = (((*input_p>>6) << 4)
855 | ((*input_p >> 4) & 3)) + basePixel;
856 *output_p++ = ((((*input_p>>2) & 3) << 4)
857 | (*input_p & 3)) + basePixel;
858 }
859 }
860 } else {
861 fprintf(stderr,
862 "xtiff: can't handle %d-bit TIFF file on an %d-bit display\n",
863 tfImageDepth, xImageDepth);
864 exit(0);
865 }
866 }
867
868 free(scan_line);
869 }
870
871 void
872 CreateXImage()
873 {
874 XGCValues gc_values;
875 GC bitmap_gc;
876
877 xOffset = yOffset = 0;
878 grabX = grabY = -1;
879
880 xImage = XCreateImage(xDisplay, xVisual, xImageDepth,
881 xImageDepth == 1 ? XYBitmap : ZPixmap, /* offset */ 0,
882 (char *) imageMemory, tfImageWidth, tfImageHeight,
883 /* bitmap_pad */ 8, /* bytes_per_line */ 0);
884
885 /*
886 * libtiff converts LSB data into MSB but doesn't change the FillOrder tag.
887 */
888 if (xImageDepth == 1)
889 xImage->bitmap_bit_order = MSBFirst;
890 if (xImageDepth <= 8)
891 xImage->byte_order = MSBFirst;
892
893 /*
894 * create an appropriate GC
895 */
896 gc_values.function = GXcopy;
897 gc_values.plane_mask = AllPlanes;
898 if (tfPhotometricInterpretation == PHOTOMETRIC_MINISBLACK) {
899 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
900 gc_values.background = XBlackPixel(xDisplay, xScreen);
901 } else {
902 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
903 gc_values.background = XWhitePixel(xDisplay, xScreen);
904 }
905 xWinGc = XCreateGC(xDisplay, XtWindow(shellWidget),
906 GCFunction | GCPlaneMask | GCForeground | GCBackground, &gc_values);
907
908 /*
909 * create the pixmap and load the image
910 */
911 if (appData.usePixmap == True) {
912 xImagePixmap = XCreatePixmap(xDisplay, RootWindow(xDisplay, xScreen),
913 xImage->width, xImage->height, xImageDepth);
914
915 /*
916 * According to the O'Reilly X Protocol Reference Manual, page 53,
917 * "A pixmap depth of one is always supported and listed, but windows
918 * of depth one might not be supported." Therefore we create a pixmap
919 * of depth one and use XCopyPlane(). This is idiomatic.
920 */
921 if (xImageDepth == 1) { /* just pass the bits through */
922 gc_values.foreground = 1; /* foreground describes set bits */
923 gc_values.background = 0; /* background describes clear bits */
924 bitmap_gc = XCreateGC(xDisplay, xImagePixmap,
925 GCForeground | GCBackground, &gc_values);
926 XPutImage(xDisplay, xImagePixmap, bitmap_gc, xImage,
927 0, 0, 0, 0, xImage->width, xImage->height);
928 } else
929 XPutImage(xDisplay, xImagePixmap, xWinGc, xImage,
930 0, 0, 0, 0, xImage->width, xImage->height);
931 XDestroyImage(xImage);
932 free(imageMemory);
933 }
934 }
935
936 XtCallbackProc
937 SelectProc(w, unused_1, unused_2)
938 Widget w;
939 caddr_t unused_1;
940 caddr_t unused_2;
941 {
942 XawListReturnStruct *list_return;
943
944 list_return = XawListShowCurrent(w);
945
946 switch (list_return->list_index) {
947 case ButtonQuit:
948 QuitProc();
949 break;
950 case ButtonPreviousPage:
951 PreviousProc();
952 break;
953 case ButtonNextPage:
954 NextProc();
955 break;
956 default:
957 fprintf(stderr, "error in SelectProc\n");
958 exit(0);
959 }
960 XawListUnhighlight(w);
961 }
962
963 void
964 QuitProc(void)
965 {
966 exit(0);
967 }
968
969 void
970 NextProc()
971 {
972 PageProc(ButtonNextPage);
973 }
974
975 void
976 PreviousProc()
977 {
978 PageProc(ButtonPreviousPage);
979 }
980
981 void
982 PageProc(direction)
983 int direction;
984 {
985 XEvent fake_event;
986 Arg args[4];
987
988 switch (direction) {
989 case ButtonPreviousPage:
990 if (tfDirectory > 0)
991 TIFFSetDirectory(tfFile, --tfDirectory);
992 else
993 return;
994 break;
995 case ButtonNextPage:
996 if (TIFFReadDirectory(tfFile) == True)
997 tfDirectory++;
998 else
999 return;
1000 break;
1001 default:
1002 fprintf(stderr, "error in PageProc\n");
1003 exit(0);
1004 }
1005
1006 xOffset = yOffset = 0;
1007 grabX = grabY = -1;
1008
1009 GetTIFFHeader();
1010 SetNameLabel();
1011 GetTIFFImage();
1012
1013 if (appData.usePixmap == True)
1014 XFreePixmap(xDisplay, xImagePixmap);
1015 else
1016 XDestroyImage(xImage);
1017
1018 CreateXImage();
1019
1020 /*
1021 * Using XtSetValues() to set the widget size causes a resize.
1022 * This resize gets propagated up to the parent shell.
1023 * In order to disable this visually disconcerting effect,
1024 * shell resizing is temporarily disabled.
1025 */
1026 XtSetArg(args[0], XtNallowShellResize, False);
1027 XtSetValues(shellWidget, args, 1);
1028
1029 XtSetArg(args[0], XtNwidth, tfImageWidth);
1030 XtSetArg(args[1], XtNheight, tfImageHeight);
1031 XtSetValues(imageWidget, args, 2);
1032
1033 XtSetArg(args[0], XtNallowShellResize, True);
1034 XtSetValues(shellWidget, args, 1);
1035
1036 XClearWindow(xDisplay, XtWindow(imageWidget));
1037
1038 fake_event.type = Expose;
1039 fake_event.xexpose.x = fake_event.xexpose.y = 0;
1040 fake_event.xexpose.width = tfImageWidth; /* the window will clip */
1041 fake_event.xexpose.height = tfImageHeight;
1042 EventProc(imageWidget, NULL, &fake_event);
1043 }
1044
1045 void
1046 EventProc(widget, unused, event)
1047 Widget widget;
1048 caddr_t unused;
1049 XEvent *event;
1050 {
1051 int ih, iw, ww, wh, sx, sy, w, h, dx, dy;
1052 Dimension w_width, w_height;
1053 XEvent next_event;
1054 Arg args[2];
1055
1056 if (event->type == MappingNotify) {
1057 XRefreshKeyboardMapping((XMappingEvent *) event);
1058 return;
1059 }
1060
1061 if (!XtIsRealized(widget))
1062 return;
1063
1064 if ((event->type == ButtonPress) || (event->type == ButtonRelease))
1065 if (event->xbutton.button != Button1)
1066 return;
1067
1068 iw = tfImageWidth; /* avoid sign problems */
1069 ih = tfImageHeight;
1070
1071 /*
1072 * The grabX and grabY variables record where the user grabbed the image.
1073 * They also record whether the mouse button is down or not.
1074 */
1075 if (event->type == ButtonPress) {
1076 grabX = event->xbutton.x;
1077 grabY = event->xbutton.y;
1078 return;
1079 }
1080
1081 /*
1082 * imageWidget is a Core widget and doesn't get resized.
1083 * So we calculate the size of its viewport here.
1084 */
1085 XtSetArg(args[0], XtNwidth, &w_width);
1086 XtSetArg(args[1], XtNheight, &w_height);
1087 XtGetValues(shellWidget, args, 2);
1088 ww = w_width;
1089 wh = w_height;
1090 XtGetValues(listWidget, args, 2);
1091 wh -= w_height;
1092
1093 switch (event->type) {
1094 case Expose:
1095 dx = event->xexpose.x;
1096 dy = event->xexpose.y;
1097 sx = dx + xOffset;
1098 sy = dy + yOffset;
1099 w = MIN(event->xexpose.width, iw);
1100 h = MIN(event->xexpose.height, ih);
1101 break;
1102 case KeyPress:
1103 if ((grabX >= 0) || (grabY >= 0)) /* Mouse button is still down */
1104 return;
1105 switch (XLookupKeysym((XKeyEvent *) event, /* KeySyms index */ 0)) {
1106 case XK_Up:
1107 if (ih < wh) /* Don't scroll if the window fits the image. */
1108 return;
1109 sy = yOffset + appData.translate;
1110 sy = MIN(ih - wh, sy);
1111 if (sy == yOffset) /* Filter redundant stationary refreshes. */
1112 return;
1113 yOffset = sy;
1114 sx = xOffset;
1115 dx = dy = 0;
1116 w = ww; h = wh;
1117 break;
1118 case XK_Down:
1119 if (ih < wh)
1120 return;
1121 sy = yOffset - appData.translate;
1122 sy = MAX(sy, 0);
1123 if (sy == yOffset)
1124 return;
1125 yOffset = sy;
1126 sx = xOffset;
1127 dx = dy = 0;
1128 w = ww; h = wh;
1129 break;
1130 case XK_Left:
1131 if (iw < ww)
1132 return;
1133 sx = xOffset + appData.translate;
1134 sx = MIN(iw - ww, sx);
1135 if (sx == xOffset)
1136 return;
1137 xOffset = sx;
1138 sy = yOffset;
1139 dx = dy = 0;
1140 w = ww; h = wh;
1141 break;
1142 case XK_Right:
1143 if (iw < ww)
1144 return;
1145 sx = xOffset - appData.translate;
1146 sx = MAX(sx, 0);
1147 if (sx == xOffset)
1148 return;
1149 xOffset = sx;
1150 sy = yOffset;
1151 dx = dy = 0;
1152 w = ww; h = wh;
1153 break;
1154 default:
1155 return;
1156 }
1157 break;
1158 case MotionNotify:
1159 /*
1160 * MotionEvent compression. Ignore multiple motion events.
1161 * Ignore motion events if the mouse button is up.
1162 */
1163 if (XPending(xDisplay)) /* Xlib doesn't flush the output buffer */
1164 if (XtPeekEvent(&next_event))
1165 if (next_event.type == MotionNotify)
1166 return;
1167 if ((grabX < 0) || (grabY < 0))
1168 return;
1169 sx = xOffset + grabX - (int) event->xmotion.x;
1170 if (sx >= (iw - ww)) /* clamp x motion but allow y motion */
1171 sx = iw - ww;
1172 sx = MAX(sx, 0);
1173 sy = yOffset + grabY - (int) event->xmotion.y;
1174 if (sy >= (ih - wh)) /* clamp y motion but allow x motion */
1175 sy = ih - wh;
1176 sy = MAX(sy, 0);
1177 if ((sx == xOffset) && (sy == yOffset))
1178 return;
1179 dx = dy = 0;
1180 w = ww; h = wh;
1181 break;
1182 case ButtonRelease:
1183 xOffset = xOffset + grabX - (int) event->xbutton.x;
1184 xOffset = MIN(iw - ww, xOffset);
1185 xOffset = MAX(xOffset, 0);
1186 yOffset = yOffset + grabY - (int) event->xbutton.y;
1187 yOffset = MIN(ih - wh, yOffset);
1188 yOffset = MAX(yOffset, 0);
1189 grabX = grabY = -1;
1190 default:
1191 return;
1192 }
1193
1194 if (appData.usePixmap == True) {
1195 if (xImageDepth == 1)
1196 XCopyPlane(xDisplay, xImagePixmap, XtWindow(widget),
1197 xWinGc, sx, sy, w, h, dx, dy, 1);
1198 else
1199 XCopyArea(xDisplay, xImagePixmap, XtWindow(widget),
1200 xWinGc, sx, sy, w, h, dx, dy);
1201 } else
1202 XPutImage(xDisplay, XtWindow(widget), xWinGc, xImage,
1203 sx, sy, dx, dy, w, h);
1204 }
1205
1206 void
1207 ResizeProc()
1208 {
1209 Dimension w_width, w_height;
1210 int xo, yo, ww, wh;
1211 XEvent fake_event;
1212 Arg args[2];
1213
1214 if ((xOffset == 0) && (yOffset == 0))
1215 return;
1216
1217 XtSetArg(args[0], XtNwidth, &w_width);
1218 XtSetArg(args[1], XtNheight, &w_height);
1219 XtGetValues(shellWidget, args, 2);
1220 ww = w_width;
1221 wh = w_height;
1222 XtGetValues(listWidget, args, 2);
1223 wh -= w_height;
1224
1225 xo = xOffset; yo = yOffset;
1226
1227 if ((xOffset + ww) >= tfImageWidth)
1228 xOffset = MAX((int) tfImageWidth - ww, 0);
1229 if ((yOffset + wh) >= tfImageHeight)
1230 yOffset = MAX((int) tfImageHeight - wh, 0);
1231
1232 /*
1233 * Send an ExposeEvent if the origin changed.
1234 * We have to do this because of the use and semantics of bit gravity.
1235 */
1236 if ((xo != xOffset) || (yo != yOffset)) {
1237 fake_event.type = Expose;
1238 fake_event.xexpose.x = fake_event.xexpose.y = 0;
1239 fake_event.xexpose.width = tfImageWidth;
1240 fake_event.xexpose.height = tfImageHeight;
1241 EventProc(imageWidget, NULL, &fake_event);
1242 }
1243 }
1244
1245 int
1246 XTiffErrorHandler(display, error_event)
1247 Display *display;
1248 XErrorEvent *error_event;
1249 {
1250 char message[80];
1251
1252 /*
1253 * Some X servers limit the size of pixmaps.
1254 */
1255 if ((error_event->error_code == BadAlloc)
1256 && (error_event->request_code == X_CreatePixmap))
1257 fprintf(stderr, "xtiff: requested pixmap too big for display\n");
1258 else {
1259 XGetErrorText(display, error_event->error_code, message, 80);
1260 fprintf(stderr, "xtiff: error code %s\n", message);
1261 }
1262
1263 exit(0);
1264 }
1265
1266 void
1267 Usage()
1268 {
1269 fprintf(stderr, "Usage xtiff: [options] tiff-file\n");
1270 fprintf(stderr, "\tstandard Xt options\n");
1271 fprintf(stderr, "\t[-help]\n");
1272 fprintf(stderr, "\t[-gamma gamma]\n");
1273 fprintf(stderr, "\t[-usePixmap (True | False)]\n");
1274 fprintf(stderr, "\t[-viewportWidth pixels]\n");
1275 fprintf(stderr, "\t[-viewportHeight pixels]\n");
1276 fprintf(stderr, "\t[-translate pixels]\n");
1277 fprintf(stderr, "\t[-verbose (True | False)]\n");
1278 exit(0);
1279 }
1280
1281 /* vim: set ts=8 sts=8 sw=8 noet: */
1282
1283 /*
1284 * Local Variables:
1285 * mode: c
1286 * c-basic-offset: 8
1287 * fill-column: 78
1288 * End:
1289 */