~ctwm/ctwm/trunk

479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
1
/*
2
 * XWD image handling
3
 */
4
5
#include "ctwm.h"
6
7
#include <stdio.h>
8
#include <stdlib.h>
9
10
#include <X11/XWDFile.h>
11
12
#include "screen.h"
481.1.5 by Matthew Fuller
Pull the animation funcs/vars out into their own file.
13
#include "animate.h"
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
14
15
#include "image.h"
16
#include "image_xwd.h"
17
18
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
19
static Image *LoadXwdImage(const char *filename, ColorPair cp);
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
20
static void compress(XImage *image, XColor *colors, int *ncolors);
21
static void swapshort(char *bp, unsigned n);
22
static void swaplong(char *bp, unsigned n);
23
24
25
26
/*
27
 * External entry
28
 */
29
Image *
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
30
GetXwdImage(const char *name, ColorPair cp)
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
31
{
480.1.13 by Matthew Fuller
Swap the Bitmap and Xwd image types over to using get_image_anim_cp()
32
	/* Non-animated */
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
33
	if(! strchr(name, '%')) {
34
		return (LoadXwdImage(name, cp));
35
	}
480.1.13 by Matthew Fuller
Swap the Bitmap and Xwd image types over to using get_image_anim_cp()
36
37
	/* Animated */
38
	return get_image_anim_cp(name, cp, LoadXwdImage);
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
39
}
40
41
42
/*
43
 * Internal backend
44
 */
45
static Image *
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
46
LoadXwdImage(const char *filename, ColorPair cp)
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
47
{
48
	FILE        *file;
49
	char        *fullname;
50
	XColor      colors [256];
51
	XWDColor    xwdcolors [256];
52
	unsigned    buffer_size;
53
	XImage      *image;
54
	unsigned char *imagedata;
55
	Pixmap      pixret;
56
	Visual      *visual;
57
	char        win_name [256];
58
	int         win_name_size;
59
	int         ispipe;
60
	int         i, len;
61
	int         w, h, depth, ncolors;
62
	int         scrn;
63
	Colormap    cmap;
64
	Colormap    stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
65
	GC          gc;
66
	XGCValues   gcvalues;
67
	XWDFileHeader header;
68
	Image       *ret;
69
	unsigned long swaptest = 1;
70
71
	ispipe = 0;
72
	if(filename [0] == '|') {
73
		file = (FILE *) popen(filename + 1, "r");
74
		if(file == NULL) {
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
75
			return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
76
		}
77
		ispipe = 1;
480.1.24 by Matthew Fuller
This var is actually unneeded.
78
		if(AnimationActive) {
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
79
			StopAnimation();
80
		}
81
		goto file_opened;
82
	}
83
	fullname = ExpandPixmapPath(filename);
84
	if(! fullname) {
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
85
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
86
	}
87
	file = fopen(fullname, "r");
88
	free(fullname);
89
	if(file == NULL) {
90
		if(reportfilenotfound) {
91
			fprintf(stderr, "unable to locate %s\n", filename);
92
		}
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
93
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
94
	}
95
file_opened:
96
	len = fread((char *) &header, sizeof(header), 1, file);
97
	if(len != 1) {
98
		fprintf(stderr, "ctwm: cannot read %s\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
99
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
100
	}
101
	if(*(char *) &swaptest) {
102
		swaplong((char *) &header, sizeof(header));
103
	}
104
	if(header.file_version != XWD_FILE_VERSION) {
105
		fprintf(stderr, "ctwm: XWD file format version mismatch : %s\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
106
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
107
	}
108
	win_name_size = header.header_size - sizeof(header);
109
	len = fread(win_name, win_name_size, 1, file);
110
	if(len != 1) {
111
		fprintf(stderr, "file %s has not the correct format\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
112
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
113
	}
114
115
	if(header.pixmap_format == XYPixmap) {
116
		fprintf(stderr, "ctwm: XYPixmap XWD file not supported : %s\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
117
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
118
	}
119
	w       = header.pixmap_width;
120
	h       = header.pixmap_height;
121
	depth   = header.pixmap_depth;
122
	ncolors = header.ncolors;
123
	len = fread((char *) xwdcolors, sizeof(XWDColor), ncolors, file);
124
	if(len != ncolors) {
125
		fprintf(stderr, "file %s has not the correct format\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
126
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
127
	}
128
	if(*(char *) &swaptest) {
129
		for(i = 0; i < ncolors; i++) {
130
			swaplong((char *) &xwdcolors [i].pixel, 4);
131
			swapshort((char *) &xwdcolors [i].red, 3 * 2);
132
		}
133
	}
134
	for(i = 0; i < ncolors; i++) {
135
		colors [i].pixel = xwdcolors [i].pixel;
136
		colors [i].red   = xwdcolors [i].red;
137
		colors [i].green = xwdcolors [i].green;
138
		colors [i].blue  = xwdcolors [i].blue;
139
		colors [i].flags = xwdcolors [i].flags;
140
		colors [i].pad   = xwdcolors [i].pad;
141
	}
142
143
	scrn    = Scr->screen;
144
	cmap    = AlternateCmap ? AlternateCmap : stdcmap;
145
	visual  = Scr->d_visual;
146
	gc      = DefaultGC(dpy, scrn);
147
148
	buffer_size = header.bytes_per_line * h;
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
149
	imagedata = malloc(buffer_size);
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
150
	if(! imagedata) {
151
		fprintf(stderr, "cannot allocate memory for image %s\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
152
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
153
	}
154
	len = fread(imagedata, (int) buffer_size, 1, file);
155
	if(len != 1) {
156
		free(imagedata);
157
		fprintf(stderr, "file %s has not the correct format\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
158
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
159
	}
160
	if(ispipe) {
161
		pclose(file);
162
	}
163
	else {
164
		fclose(file);
165
	}
166
167
	image = XCreateImage(dpy, visual,  depth, header.pixmap_format,
168
	                     0, (char *) imagedata, w, h,
169
	                     header.bitmap_pad, header.bytes_per_line);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
170
	if(image == NULL) {
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
171
		free(imagedata);
172
		fprintf(stderr, "cannot create image for %s\n", filename);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
173
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
174
	}
175
	if(header.pixmap_format == ZPixmap) {
176
		compress(image, colors, &ncolors);
177
	}
178
	if(header.pixmap_format != XYBitmap) {
179
		for(i = 0; i < ncolors; i++) {
180
			XAllocColor(dpy, cmap, &(colors [i]));
181
		}
182
		for(i = 0; i < buffer_size; i++) {
183
			imagedata [i] = (unsigned char) colors [imagedata [i]].pixel;
184
		}
185
	}
186
	if(w > Scr->rootw) {
187
		w = Scr->rootw;
188
	}
189
	if(h > Scr->rooth) {
190
		h = Scr->rooth;
191
	}
192
480.1.19 by Matthew Fuller
Add an AllocImage() to ensure new Image's are initialized properly,
193
	ret = AllocImage();
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
194
	if(! ret) {
195
		fprintf(stderr, "unable to allocate memory for image : %s\n", filename);
196
		free(image);
197
		free(imagedata);
198
		for(i = 0; i < ncolors; i++) {
199
			XFreeColors(dpy, cmap, &(colors [i].pixel), 1, 0L);
200
		}
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
201
		return NULL;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
202
	}
203
	if(header.pixmap_format == XYBitmap) {
204
		gcvalues.foreground = cp.fore;
205
		gcvalues.background = cp.back;
206
		XChangeGC(dpy, gc, GCForeground | GCBackground, &gcvalues);
207
	}
208
	if((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) {
209
		int x, y;
210
211
		pixret = XCreatePixmap(dpy, Scr->Root, Scr->rootw,
212
		                       Scr->rooth, Scr->d_depth);
213
		x = (Scr->rootw  - w) / 2;
214
		y = (Scr->rooth - h) / 2;
215
		XFillRectangle(dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
216
		XPutImage(dpy, pixret, gc, image, 0, 0, x, y, w, h);
217
		ret->width  = Scr->rootw;
218
		ret->height = Scr->rooth;
219
	}
220
	else {
221
		pixret = XCreatePixmap(dpy, Scr->Root, w, h, depth);
222
		XPutImage(dpy, pixret, gc, image, 0, 0, 0, 0, w, h);
223
		ret->width  = w;
224
		ret->height = h;
225
	}
226
	XDestroyImage(image);
227
228
	ret->pixmap = pixret;
229
	ret->mask   = None;
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
230
	ret->next   = NULL;
231
	return ret;
479.1.22 by Matthew Fuller
Pull the XWD bits out into their own file.
232
}
233
234
235
/*
236
 * Utils
237
 */
238
static void
239
compress(XImage *image, XColor *colors, int *ncolors)
240
{
241
	unsigned char ind  [256];
242
	unsigned int  used [256];
243
	int           i, j, size, nused;
244
	unsigned char color;
245
	XColor        newcolors [256];
246
	unsigned char *imagedata;
247
248
	for(i = 0; i < 256; i++) {
249
		used [i] = 0;
250
		ind  [i] = 0;
251
	}
252
	nused = 0;
253
	size  = image->bytes_per_line * image->height;
254
	imagedata = (unsigned char *) image->data;
255
	for(i = 0; i < size; i++) {
256
		if((i % image->bytes_per_line) > image->width) {
257
			continue;
258
		}
259
		color = imagedata [i];
260
		if(used [color] == 0) {
261
			for(j = 0; j < nused; j++) {
262
				if((colors [color].red   == newcolors [j].red)   &&
263
				                (colors [color].green == newcolors [j].green) &&
264
				                (colors [color].blue  == newcolors [j].blue)) {
265
					break;
266
				}
267
			}
268
			ind  [color] = j;
269
			used [color] = 1;
270
			if(j == nused) {
271
				newcolors [j].red   = colors [color].red;
272
				newcolors [j].green = colors [color].green;
273
				newcolors [j].blue  = colors [color].blue;
274
				nused++;
275
			}
276
		}
277
	}
278
	for(i = 0; i < size; i++) {
279
		imagedata [i] = ind [imagedata [i]];
280
	}
281
	for(i = 0; i < nused; i++) {
282
		colors [i] = newcolors [i];
283
	}
284
	*ncolors = nused;
285
}
286
287
288
static void
289
swapshort(char *bp, unsigned n)
290
{
291
	char c;
292
	char *ep = bp + n;
293
294
	while(bp < ep) {
295
		c = *bp;
296
		*bp = *(bp + 1);
297
		bp++;
298
		*bp++ = c;
299
	}
300
}
301
302
303
static void
304
swaplong(char *bp, unsigned n)
305
{
306
	char c;
307
	char *ep = bp + n;
308
	char *sp;
309
310
	while(bp < ep) {
311
		sp = bp + 3;
312
		c = *sp;
313
		*sp = *bp;
314
		*bp++ = c;
315
		sp = bp + 1;
316
		c = *sp;
317
		*sp = *bp;
318
		*bp++ = c;
319
		bp += 2;
320
	}
321
}