~ctwm/ctwm/trunk

479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
1
/*
2
 * JPEG image handling functions
3
 */
4
5
#include "ctwm.h"
6
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <string.h>
492.2.122 by Matthew Fuller
We're now aiming strongly at C99, so just use stdint.h in place of
10
#include <stdint.h>
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
11
12
#include "screen.h"
479.1.5 by Matthew Fuller
Switch to single central reportfilenotfound in the "to move to
13
#include "image.h"
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
14
#include "image_jpeg.h"
15
16
/* Bits needed for libjpeg and interaction */
17
#include <setjmp.h>
18
#include <jpeglib.h>
19
#include <jerror.h>
20
21
#include <X11/Xlib.h>
22
480.1.14 by Matthew Fuller
Rearrange and comment image_jpeg to put the public func first, and
23
24
/* Various internal bits */
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
25
static Image *LoadJpegImage(const char *name);
26
static Image *LoadJpegImageCp(const char *name, ColorPair cp);
480.1.14 by Matthew Fuller
Rearrange and comment image_jpeg to put the public func first, and
27
static void convert_for_16(int w, int x, int y, int r, int g, int b);
28
static void convert_for_32(int w, int x, int y, int r, int g, int b);
29
static void jpeg_error_exit(j_common_ptr cinfo);
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
30
31
struct jpeg_error {
32
	struct jpeg_error_mgr pub;
33
	sigjmp_buf setjmp_buffer;
34
};
35
36
typedef struct jpeg_error *jerr_ptr;
37
38
static uint16_t *buffer_16bpp;
39
static uint32_t *buffer_32bpp;
40
480.1.14 by Matthew Fuller
Rearrange and comment image_jpeg to put the public func first, and
41
42
/*
43
 * External entry point
44
 */
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
45
Image *
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
46
GetJpegImage(const char *name)
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
47
{
496.1.4 by Matthew Fuller
Use a dummy temp var here instead of an inline literal; astyle doesn't
48
	ColorPair dummy = {0};
49
480.1.15 by Matthew Fuller
Change GetJpegImage() to use the common func for loading animations.
50
	/* Non-animated */
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
51
	if(! strchr(name, '%')) {
52
		return (LoadJpegImage(name));
53
	}
480.1.15 by Matthew Fuller
Change GetJpegImage() to use the common func for loading animations.
54
55
	/* Animated */
496.1.4 by Matthew Fuller
Use a dummy temp var here instead of an inline literal; astyle doesn't
56
	return get_image_anim_cp(name, dummy, LoadJpegImageCp);
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
57
}
58
480.1.14 by Matthew Fuller
Rearrange and comment image_jpeg to put the public func first, and
59
60
/*
61
 * Internal backend func
62
 */
480.1.15 by Matthew Fuller
Change GetJpegImage() to use the common func for loading animations.
63
64
/* Trivial thunk for get_image_anim_cp() callback */
65
static Image *
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
66
LoadJpegImageCp(const char *name, ColorPair cp)
480.1.15 by Matthew Fuller
Change GetJpegImage() to use the common func for loading animations.
67
{
68
	return LoadJpegImage(name);
69
}
70
71
/* The actual loader */
479.1.29 by Matthew Fuller
Split the rest of the image* function definitions, and make indent.
72
static Image *
480.1.17 by Matthew Fuller
const-ify all these image names we pass through this process.
73
LoadJpegImage(const char *name)
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
74
{
75
	char   *fullname;
76
	XImage *ximage;
77
	FILE   *infile;
78
	Image  *image;
79
	Pixmap pixret;
80
	void (*store_data)(int w, int x, int y, int r, int g, int b);
81
	struct jpeg_decompress_struct cinfo;
82
	struct jpeg_error jerr;
83
	JSAMPARRAY buffer;
84
	int width, height;
85
	int row_stride;
86
	int g, i, a;
87
	int bpix;
88
	GC  gc;
89
90
	fullname = ExpandPixmapPath(name);
91
	if(! fullname) {
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
92
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
93
	}
94
480.1.19 by Matthew Fuller
Add an AllocImage() to ensure new Image's are initialized properly,
95
	image = AllocImage();
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
96
	if(image == NULL) {
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
97
		free(fullname);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
98
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
99
	}
100
101
	if((infile = fopen(fullname, "rb")) == NULL) {
479.1.3 by Matthew Fuller
Stop jumping hoops on these reportfilenotfound's and just make them
102
		if(reportfilenotfound) {
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
103
			fprintf(stderr, "unable to locate %s\n", fullname);
104
		}
105
		fflush(stdout);
106
		free(image);
107
		free(fullname);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
108
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
109
	}
110
	free(fullname);
111
	cinfo.err = jpeg_std_error(&jerr.pub);
112
	jerr.pub.error_exit = jpeg_error_exit;
113
114
	if(sigsetjmp(jerr.setjmp_buffer, 1)) {
115
		jpeg_destroy_decompress(&cinfo);
116
		free(image);
117
		fclose(infile);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
118
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
119
	}
120
	jpeg_create_decompress(&cinfo);
121
	jpeg_stdio_src(&cinfo, infile);
122
	jpeg_read_header(&cinfo, FALSE);
123
	cinfo.do_fancy_upsampling = FALSE;
124
	cinfo.do_block_smoothing = FALSE;
125
	jpeg_start_decompress(&cinfo);
126
	width  = cinfo.output_width;
127
	height = cinfo.output_height;
128
129
	if(Scr->d_depth == 16) {
130
		store_data = &convert_for_16;
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
131
		buffer_16bpp = malloc((width) * (height) * 2);
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
132
		ximage = XCreateImage(dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
133
		                      (char *) buffer_16bpp, width, height, 16, width * 2);
134
	}
135
	else if(Scr->d_depth == 24 || Scr->d_depth == 32) {
136
		store_data = &convert_for_32;
137
		buffer_32bpp = malloc(width * height * 4);
138
		ximage = XCreateImage(dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
139
		                      (char *) buffer_32bpp, width, height, 32, width * 4);
140
	}
141
	else {
142
		fprintf(stderr, "Image %s unsupported depth : %d\n", name, Scr->d_depth);
143
		free(image);
144
		fclose(infile);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
145
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
146
	}
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
147
	if(ximage == NULL) {
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
148
		fprintf(stderr, "cannot create image for %s\n", name);
149
		free(image);
150
		fclose(infile);
501.1.9 by Matthew Fuller
Convert pointer values from None -> NULL in image*.
151
		return NULL;
479.1.1 by Matthew Fuller
Start breaking up util.c by pulling out the JPEG-related functions
152
	}
153
	g = 0;
154
	row_stride = cinfo.output_width * cinfo.output_components;
155
	buffer = (*cinfo.mem->alloc_sarray)
156
	         ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
157
158
	bpix = cinfo.output_components;
159
	while(cinfo.output_scanline < cinfo.output_height) {
160
		jpeg_read_scanlines(&cinfo, buffer, 1);
161
		a = 0;
162
		for(i = 0; i < bpix * cinfo.output_width; i += bpix) {
163
			(*store_data)(width, a, g, buffer[0][i],  buffer[0][i + 1], buffer[0][i + 2]);
164
			a++;
165
		}
166
		g++;
167
	}
168
	jpeg_finish_decompress(&cinfo);
169
	jpeg_destroy_decompress(&cinfo);
170
	fclose(infile);
171
172
	gc = DefaultGC(dpy, Scr->screen);
173
	if((width > (Scr->rootw / 2)) || (height > (Scr->rooth / 2))) {
174
		int x, y;
175
176
		pixret = XCreatePixmap(dpy, Scr->Root, Scr->rootw, Scr->rooth, Scr->d_depth);
177
		x = (Scr->rootw  -  width) / 2;
178
		y = (Scr->rooth  - height) / 2;
179
		XFillRectangle(dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
180
		XPutImage(dpy, pixret, gc, ximage, 0, 0, x, y, width, height);
181
		image->width  = Scr->rootw;
182
		image->height = Scr->rooth;
183
	}
184
	else {
185
		pixret = XCreatePixmap(dpy, Scr->Root, width, height, Scr->d_depth);
186
		XPutImage(dpy, pixret, gc, ximage, 0, 0, 0, 0, width, height);
187
		image->width  = width;
188
		image->height = height;
189
	}
190
	if(ximage) {
191
		XDestroyImage(ximage);
192
	}
193
	image->pixmap = pixret;
194
195
	return image;
196
}
480.1.14 by Matthew Fuller
Rearrange and comment image_jpeg to put the public func first, and
197
198
199
200
/*
201
 * Utils
202
 */
203
static void
204
convert_for_16(int w, int x, int y, int r, int g, int b)
205
{
206
	buffer_16bpp [y * w + x] = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
207
}
208
209
static void
210
convert_for_32(int w, int x, int y, int r, int g, int b)
211
{
212
	buffer_32bpp [y * w + x] = ((r << 16) + (g << 8) + b) & 0xFFFFFFFF;
213
}
214
215
static void
216
jpeg_error_exit(j_common_ptr cinfo)
217
{
218
	jerr_ptr errmgr = (jerr_ptr) cinfo->err;
219
	cinfo->err->output_message(cinfo);
220
	siglongjmp(errmgr->setjmp_buffer, 1);
221
	return;
222
}