PageRenderTime 26ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/tiff/contrib/dbs/xtiff/xtiff.c

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