1 /*
2 ACfax - Fax reception with X11-interface for amateur radio
3 Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 andreas.czechanowski@ins.uni-stuttgart.de
20 */
21
22 /*
23 * x_image.c - XImage and colormap allocation functions
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 /*
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #include <X11/Intrinsic.h>
32 */
33 #include "x_image.h"
34
35 unsigned long coltab[256]; /* mapping table grayscale->pixel-value */
36 char cused[256]; /* table indicating used pixel-values */
37 Display *dpy = NULL; /* X-display used */
38 Screen *scrn = NULL; /* Screen of display */
39 Visual *visl = NULL; /* Visual of screen to use */
40 int depth = -1; /* depth of screen (# of planes) */
41 Colormap icmap; /* the colormap to use */
42 XImage *horimag = NULL; /* intermediate-storage for horizontal scan */
43 XImage *verimag = NULL; /* intermediate-storage for vertical scan */
44 XVisualInfo visinfo; /* Visual-info-structure (from Xutil.h) */
45 unsigned long r_mask; /* bit mask bits (truecolor) for red */
46 unsigned long g_mask; /* bit mask bits (truecolor) for green */
47 unsigned long b_mask; /* bit mask bits (truecolor) for blue */
48 int r_shift; /* position of LSB in r_mask */
49 int g_shift; /* position of LSB in g_mask */
50 int b_shift; /* position of LSB in b_mask */
51 int r_bits; /* count of significant bits in r_mask */
52 int g_bits; /* count of significant bits in g_mask */
53 int b_bits; /* count of significant bits in b_mask */
54
55 /*
56 * get some global X11-variables and resources from the passed Widget
57 */
get_globals(Widget toplevel)58 void get_globals(Widget toplevel)
59 {
60 if (!dpy)
61 dpy = XtDisplay(toplevel);
62 if (!scrn)
63 scrn = XtScreen(toplevel);
64 if (depth < 0)
65 depth = DefaultDepthOfScreen(scrn);
66 if (!visl) {
67 visl = DefaultVisualOfScreen(scrn);
68 #if 0
69 if (!(XMatchVisualInfo(dpy, XScreenNumberOfScreen(scrn), depth,
70 PseudoColor, &visinfo))) {
71 fprintf(stderr, "cannot get PseudoColor-visual with depth %d !\n", depth);
72 exit(1);
73 }
74 visl = visinfo.visual;
75 #endif
76 }
77 }
78
79 /*
80 * create two XImages as "transportation storage" between the raw-resulution
81 * picture and the canvas-widget's pixmap (one horizontal stripe with
82 * DEFHEIGHT lines, and one vertical stripe with DEFWIDTH columns).
83 * If called more than once, the old
84 * XImages are Destroyes and new ones are created with the given size.
85 */
create_images(Widget toplevel,Dimension wid,Dimension hei)86 void create_images(Widget toplevel, Dimension wid, Dimension hei)
87 {
88 get_globals(toplevel);
89 fprintf(stderr, "creating XImage for %d x %d pixels\n", wid, hei);
90 /* delete old images and their data (when image is resized) */
91 if (horimag)
92 XDestroyImage(horimag);
93 if (verimag)
94 XDestroyImage(verimag);
95 horimag = XCreateImage(dpy, visl, depth, ZPixmap, 0, NULL,
96 wid, DEFHEIGHT, 32, 0);
97 verimag = XCreateImage(dpy, visl, depth, ZPixmap, 0, NULL,
98 DEFWIDTH, hei, 32, 0);
99 if (!(horimag) || !(verimag)) {
100 fprintf(stderr,"cannot allocate Ximages !\n");
101 exit(1);
102 }
103 /* allocate data for the XImages (not done by XCreateImage !) */
104 horimag->data = (char *)XtMalloc(DEFHEIGHT * horimag->bytes_per_line);
105 verimag->data = (char *)XtMalloc(hei * verimag->bytes_per_line);
106 if (!(horimag->data) || !(verimag->data)) {
107 fprintf(stderr,"cannot allocate space for Ximage !\n");
108 exit(1);
109 }
110 }
111
112 /*
113 * free the space allocated by the two XImages
114 */
destroy_images(void)115 void destroy_images(void)
116 {
117 if (horimag)
118 XDestroyImage(horimag);
119 if (verimag)
120 XDestroyImage(verimag);
121 }
122
123 /*
124 * allocate a new colormap. This is needed for PseudoColor visuals
125 * of depth 8. For truecolor displays, nothing is to be done here.
126 */
alloc_cmap(Widget toplevel,Pixel * respix,unsigned nrespix)127 void alloc_cmap(Widget toplevel, Pixel *respix, unsigned nrespix)
128 {
129 Colormap rootcmap;
130 XColor col;
131 static int cmap_created = 0;
132 int i;
133 XVisualInfo vTemplate;
134 XVisualInfo *visuals;
135 int nvisuals;
136 unsigned long tmpmask;
137
138 get_globals(toplevel);
139 switch(visl->class)
140 {
141 case PseudoColor:
142 case StaticColor:
143 rootcmap = DefaultColormapOfScreen(scrn);
144 if (!(cmap_created))
145 icmap = XCreateColormap(dpy, XtWindow(toplevel), visl, AllocAll);
146 cmap_created = 1;
147 /* XAllocColorCells(dpy, icmap, True, planes, 0, pixels, 216); */
148 /* copy the first 16 colors from the root-colormap, and also copy
149 the colors needed for our widgets */
150 for (i=0; i<(1 << depth); i++)
151 cused[i] = 0;
152 for (i=0; i<nrespix; i++)
153 {
154 /*
155 fprintf(stderr, "respix[%d] = %u\n", i, (unsigned) respix[i]);
156 */
157 if (respix[i] > ((1 << depth) - 1)) respix[i] = 0;
158 col.pixel = respix[i];
159 cused[respix[i]] = 1;
160 XQueryColor(dpy, rootcmap, &col);
161 XStoreColor(dpy, icmap, &col);
162 }
163 /* now, we can use the rest of the colors for the
164 grayscale or 6x6x6 colormap, but this is done
165 in fill_cmap_col and fill_cmap_gray */
166 break;
167 case TrueColor:
168 case DirectColor:
169 /* we want a visual with the depth of our screen : */
170 vTemplate.screen = XScreenNumberOfScreen(scrn);
171 vTemplate.depth = DefaultDepth(dpy, vTemplate.screen);
172 nvisuals = 0;
173 visuals = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask,
174 &vTemplate, &nvisuals);
175 if (nvisuals < 1)
176 {
177 fprintf(stderr, "cannot find visual matching default depth %d\n",
178 vTemplate.depth);
179 exit(1);
180 }
181 /* copy first visual info to own location */
182 visinfo = visuals[0];
183 /* discard the array from XGetVisualInfo() */
184 XFree(visuals);
185
186 /* determine the bit positions and count of significant bits
187 * for red, green and blue, store it in *_shift and *_bits */
188 r_mask = visinfo.red_mask;
189 g_mask = visinfo.green_mask;
190 b_mask = visinfo.blue_mask;
191 if (r_mask == 0 || g_mask == 0 || b_mask == 0)
192 {
193 fprintf(stderr, "one of the color masks is zero : %08lx %08lx %08lx\n",
194 r_mask, g_mask, b_mask);
195 exit(1);
196 }
197
198 /* determine number of bits and position of mask for every color */
199 r_shift = g_shift = b_shift = 0;
200 r_bits = g_bits = b_bits = 0;
201
202 tmpmask = r_mask;
203 while ((tmpmask & 1) == 0)
204 {
205 tmpmask >>= 1;
206 r_shift++;
207 }
208 while ((tmpmask & 1) == 1)
209 {
210 tmpmask >>= 1;
211 r_bits++;
212 }
213
214 tmpmask = g_mask;
215 while ((tmpmask & 1) == 0)
216 {
217 tmpmask >>= 1;
218 g_shift++;
219 }
220 while ((tmpmask & 1) == 1)
221 {
222 tmpmask >>= 1;
223 g_bits++;
224 }
225
226 tmpmask = b_mask;
227 while ((tmpmask & 1) == 0)
228 {
229 tmpmask >>= 1;
230 b_shift++;
231 }
232 while ((tmpmask & 1) == 1)
233 {
234 tmpmask >>= 1;
235 b_bits++;
236 }
237 break;
238 case StaticGray:
239 fprintf (stderr, "Cannot handle StaticGray visual - abort\n");
240 exit(1);
241 /*NOTREACHED*/
242 case GrayScale:
243 fprintf (stderr, "Cannot handle GrayScale visual - abort\n");
244 exit(1);
245 /*NOTREACHED*/
246 default:
247 fprintf (stderr, "unknown visual type %x - abort\n", visl->class);
248 exit(1);
249 /*NOTREACHED*/
250 }
251 }
252
253 /*
254 * fill the colormap with a 6x6x6 color-cube.
255 * when flip is set, the green and blue indexing is exchanged, and rotate
256 * defines the order in which the colors are indexed.
257 * The array coltab is filled with a lookup-table color_value -> pixel_index.
258 */
fill_cmap_col(int invert,int flip,int rotate)259 void fill_cmap_col(int invert, int flip, int rotate)
260 {
261 int cm[3];
262 unsigned ixr, ixg, ixb;
263 XColor col;
264 int i = 0;
265
266 fprintf(stderr, "filling colormap with 6x6x6 cube\n");
267 col.flags = DoRed | DoGreen | DoBlue;
268 switch(rotate) {
269 case 1:
270 ixr = 1;
271 ixg = (flip) ? 0 : 2;
272 ixb = (flip) ? 2 : 0;
273 break;
274 case 2:
275 ixr = 2;
276 ixg = (flip) ? 1 : 0;
277 ixb = (flip) ? 0 : 1;
278 break;
279 case 0:
280 default:
281 ixr = 0;
282 ixg = (flip) ? 2 : 1;
283 ixb = (flip) ? 1 : 2;
284 break;
285 }
286 for (cm[0]=0; cm[0]<6; cm[0]++)
287 for (cm[1]=0; cm[1]<6; cm[1]++)
288 for (cm[2]=0; cm[2]<6; cm[2]++) {
289 while ((cused[i]) && i < 256) i++;
290 if (i == 256) {
291 fprintf(stderr,"cannot assign all required colors !\n");
292 break;
293 }
294 col.pixel = i;
295 if (invert) {
296 col.red = 65535 - 9362 * (cm[ixr] + 1);
297 col.green = 65535 - 9362 * (cm[ixg] + 1);
298 col.blue = 65535 - 9362 * (cm[ixb] + 1);
299 } else {
300 col.red = 9362 * (cm[ixr] + 1);
301 col.green = 9362 * (cm[ixg] + 1);
302 col.blue = 9362 * (cm[ixb] + 1);
303 }
304 XStoreColor(dpy, icmap, &col);
305 coltab[cm[0]+6*cm[1]+36*cm[2]] = i;
306 i++;
307 }
308 }
309
310 /*
311 * fill the colormap with a grayscale of 64 steps (should be good enough).
312 * The array coltab is filled with a lookup-table gray_value -> pixel_index.
313 */
fill_cmap_gray(int invert)314 void fill_cmap_gray(int invert)
315 {
316 int g, yv;
317 XColor col;
318 int i = 0;
319 unsigned long cval;
320
321 fprintf(stderr, "filling colormap with grayscale\n");
322 switch (visl->class)
323 {
324 case StaticColor:
325 case PseudoColor:
326 col.flags = DoRed | DoGreen | DoBlue;
327 for (g=0; g<64; g++)
328 {
329 while ((cused[i]) && i < 256) i++;
330 if (i == 256)
331 {
332 fprintf(stderr,"cannot assign all required grayscales !\n");
333 break;
334 }
335 col.pixel = i;
336 yv = (invert) ? 63 - g : g;
337 col.red = col.green = col.blue = 1040.2 * yv;
338 XStoreColor(dpy, icmap, &col);
339 coltab[g] = i;
340 i++;
341 }
342 break;
343 case TrueColor:
344 case DirectColor:
345 /* allocate a translation table grayscale -> truecolor_value */
346 for (g=0; g<64; g++)
347 {
348 yv = (invert) ? 63 - g : g;
349 cval = (((1 << r_bits) - 1) * yv / 63) << r_shift;
350 cval += (((1 << g_bits) - 1) * yv / 63) << g_shift;
351 cval += (((1 << b_bits) - 1) * yv / 63) << b_shift;
352 coltab[g] = cval;
353 }
354 break;
355 }
356 }
357