xtiff.c 41 KB

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