1 /* +-------------------------------------------------------------------+ */
2 /* | This file is derived from | */
3 /* | Xpaint's readJPEG routines, copyrighted | */
4 /* | by David Koblas (koblas@netcom.com) | */
5 /* | | */
6 /* | Permission to use, copy, modify, and to distribute this software | */
7 /* | and its documentation for any purpose is hereby granted without | */
8 /* | fee, provided that the above copyright notice appear in all | */
9 /* | copies and that both that copyright notice and this permission | */
10 /* | notice appear in supporting documentation. There is no | */
11 /* | representations about the suitability of this software for | */
12 /* | any purpose. this software is provided "as is" without express | */
13 /* | or implied warranty. | */
14 /* | | */
15 /* +-------------------------------------------------------------------+ */
16
17 #include <stdio.h>
18 #include <setjmp.h>
19 #include <stdlib.h>
20 #include <jpeglib.h>
21
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24
25 #include "sunclock.h"
26
27 extern Display * dpy;
28 extern Visual * visual;
29 extern Colormap tmp_cmap;
30
31 extern int scr;
32 extern int bigendian;
33 extern int color_depth;
34 extern int color_pad;
35 extern int bytes_per_pixel;
36 extern int color_alloc_failed;
37 extern int verbose;
38 #define RANGE 252
39 extern long lr[RANGE], lg[RANGE], lb[RANGE], lnum[RANGE];
40
41 extern char * salloc();
42 extern void fill_line(char *scan, char* c, int w, int zw, int wp, int dx);
43
44 struct error_mgr {
45 struct jpeg_error_mgr pub; /* "public" fields */
46
47 jmp_buf setjmp_buffer; /* for return to caller */
48 };
49
50 typedef struct error_mgr * error_ptr;
51
52 void
error_exit(j_common_ptr cinfo)53 error_exit (j_common_ptr cinfo)
54 {
55 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
56 error_ptr err = (error_ptr) cinfo->err;
57
58 /* Always display the message. */
59 /* We could postpone this until after returning, if we chose. */
60 (*cinfo->err->output_message) (cinfo);
61
62 /* Return control to the setjmp point */
63 longjmp(err->setjmp_buffer, 1);
64 }
65
66 int
readJPEG(path,Context)67 readJPEG(path, Context)
68 char *path;
69 Sundata * Context;
70 {
71 struct jpeg_decompress_struct cinfo;
72 struct error_mgr jerr;
73 FILE *input_file;
74 double ratio;
75 int i, k, l, m, prev, next, size;
76 JSAMPROW scanline[1];
77 char *scan, *c;
78 char pix[RANGE];
79 XColor xc;
80
81 if ((input_file = fopen(path, "r")) == NULL) return 1;
82
83 cinfo.err = jpeg_std_error(&jerr.pub);
84 jerr.pub.error_exit = error_exit;
85
86 if (setjmp(jerr.setjmp_buffer)) {
87 /* If we get here, the JPEG code has signaled an error.
88 * We need to clean up the JPEG object, close the input file,
89 * and return.
90 */
91 jpeg_destroy_decompress(&cinfo);
92 fclose(input_file);
93 Context->xim = 0;
94 return 2;
95 }
96
97 jpeg_create_decompress(&cinfo);
98 jpeg_stdio_src(&cinfo, input_file);
99 jpeg_read_header(&cinfo, TRUE);
100
101 if (cinfo.jpeg_color_space == JCS_GRAYSCALE) return 3;
102
103 ratio = ((double) cinfo.image_width/(double) Context->zoom.width +
104 (double) cinfo.image_height/(double) Context->zoom.height )/1.8;
105 if (ratio>=8.0)
106 cinfo.scale_denom = 8;
107 else
108 if (ratio>=4.0)
109 cinfo.scale_denom = 4;
110 else
111 if (ratio>=2.0)
112 cinfo.scale_denom = 2;
113 else
114 cinfo.scale_denom = 1;
115
116 jpeg_start_decompress(&cinfo);
117
118 Context->xim = XCreateImage(dpy, visual,
119 DefaultDepth(dpy, scr), ZPixmap, 0, NULL,
120 Context->geom.width, Context->geom.height, color_pad, 0);
121 XFlush(dpy);
122 if (!Context->xim) return 4;
123
124 bytes_per_pixel = (Context->xim->bits_per_pixel/8);
125 size = Context->xim->bytes_per_line * Context->geom.height;
126 Context->xim->data = (char *) salloc(size);
127 scan = (char *) salloc(3 * cinfo.output_width * sizeof(char));
128
129 if (verbose)
130 fprintf(stderr, "Loading %s\n"
131 "Rescaling JPEG data by 1/%d, "
132 "%d %d --> %d %d, %d bytes per pixel\n",
133 path, cinfo.scale_denom,
134 cinfo.image_width, cinfo.image_height,
135 Context->geom.width, Context->geom.height,
136 bytes_per_pixel);
137
138 prev = -1;
139 scanline[0] = (JSAMPROW) scan;
140
141 if (color_depth<=8)
142 for (l=0; l<RANGE; l++) {
143 lr[l] = lg[l] = lb[l] = lnum[l] = 0;
144 }
145
146 while (cinfo.output_scanline < cinfo.output_height) {
147 (void) jpeg_read_scanlines(&cinfo, scanline, (JDIMENSION) 1);
148 next = ((2*cinfo.output_scanline - 1) * Context->zoom.height)/
149 (2*(int)cinfo.output_height) - Context->zoom.dy;
150 if (next>=0) {
151 if (next>=Context->geom.height) {
152 next = Context->geom.height - 1;
153 /* get loop to stop at next iteration ! */
154 cinfo.output_scanline = cinfo.output_height;
155 }
156 for (l = prev+1; l<= next; l++) {
157 c = Context->xim->data + l * Context->xim->bytes_per_line;
158 fill_line(scan, c, Context->geom.width, Context->zoom.width,
159 cinfo.output_width, Context->zoom.dx);
160 }
161 prev = next;
162 }
163 }
164
165 free(scan);
166 jpeg_destroy_decompress(&cinfo);
167
168 fclose(input_file);
169
170 if (jerr.pub.num_warnings > 0) {
171 longjmp(jerr.setjmp_buffer, 1);
172 }
173
174 if (color_depth<=8) {
175 xc.flags = DoRed | DoGreen | DoBlue;
176 k = 0;
177 for (m=0; m<RANGE; m++) if (lnum[m]) {
178 xc.red = (lr[m]/lnum[m])*257;
179 xc.green = (lg[m]/lnum[m])*257;
180 xc.blue = (lb[m]/lnum[m])*257;
181 if (!XAllocColor(dpy, tmp_cmap, &xc))
182 color_alloc_failed = 1;
183 pix[m] = (char) xc.pixel;
184 Context->daypixel[k] = (unsigned char) xc.pixel;
185 ++k;
186 }
187 Context->ncolors = k;
188 for (i=0; i<size; i++)
189 Context->xim->data[i] = pix[(unsigned char)Context->xim->data[i]];
190 }
191
192 return 0;
193 }
194
195 int
testJPEG(char * file)196 testJPEG(char *file)
197 {
198 unsigned char buf[2];
199 FILE *fd = fopen(file, "r");
200 int ret = 0;
201
202 if (fd == NULL)
203 return 0;
204
205 if (2 == fread(buf, sizeof(char), 2, fd)) {
206 if (buf[0] == 0xff && buf[1] == 0xd8)
207 ret = 1;
208 }
209 fclose(fd);
210
211 return ret;
212 }
213