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