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