1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sane/sane.h>
7 #include <sane/saneopts.h>
8 
9 #include "readers.h"
10 #include "viewer.h"
11 #include "sane.h"
12 #include "ida.h"
13 
14 #include <X11/Intrinsic.h>
15 #include <Xm/Xm.h>
16 #include <Xm/PushB.h>
17 #include <Xm/CascadeB.h>
18 #include <Xm/RowColumn.h>
19 
20 extern int sane_res;
21 
22 /* ---------------------------------------------------------------------- */
23 
24 static void
build_menu(Widget widget,XtPointer clientdata,XtPointer call_data)25 build_menu(Widget widget, XtPointer clientdata, XtPointer call_data)
26 {
27     WidgetList children,wlist;
28     Cardinal nchildren;
29     const SANE_Device **list;
30     Widget push;
31     XmString str;
32     char action[256];
33     int rc,i;
34 
35     /* del old */
36     XtVaGetValues(widget,
37 		  XtNchildren,&children,
38 		  XtNnumChildren,&nchildren,
39 		  NULL);
40     wlist = malloc(sizeof(Widget*)*nchildren);
41     memcpy(wlist,children,sizeof(Widget*)*nchildren);
42     for (i = 0; i < nchildren; i++)
43         XtDestroyWidget(wlist[i]);
44     free(wlist);
45 
46     /* create new */
47     if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) {
48 	fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc));
49 	goto done;
50     }
51     sane_get_devices(&list,0);
52     if (NULL == list[0])
53 	goto done;
54 
55     for (i = 0; list[i] != NULL; i++) {
56 	if (debug)
57 	    fprintf(stderr,"sane dev: %s | %s | %s | %s\n",
58 		    list[i]->name, list[i]->vendor,
59 		    list[i]->model, list[i]->type);
60 	str = XmStringGenerate((char*)list[i]->model,
61 			       NULL, XmMULTIBYTE_TEXT, NULL);
62 	push = XtVaCreateManagedWidget(list[i]->name,
63 				       xmPushButtonWidgetClass,widget,
64 				       XmNlabelString,str,
65 				       NULL);
66 	XmStringFree(str);
67 	sprintf(action,"Scan(%s)",list[i]->name);
68 	XtAddCallback(push,XmNactivateCallback,action_cb,strdup(action));
69     }
70 
71  done:
72     sane_exit();
73 }
74 
75 void
sane_menu(Widget menu)76 sane_menu(Widget menu)
77 {
78     Widget submenu;
79     int rc;
80 
81     if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) {
82 	fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc));
83 	goto done;
84     }
85     submenu = XmCreatePulldownMenu(menu,"scanM",NULL,0);
86     XtVaCreateManagedWidget("scan",xmCascadeButtonWidgetClass,menu,
87 			    XmNsubMenuId,submenu,NULL);
88     XtAddCallback(submenu, XmNmapCallback, build_menu, NULL);
89 
90  done:
91     sane_exit();
92 }
93 
94 /* ---------------------------------------------------------------------- */
95 /* load                                                                   */
96 
97 #define BUF_LINES 16   /* read bigger chunks to reduce overhead */
98 
99 struct sane_state {
100     SANE_Handle sane;
101     SANE_Parameters parm;
102     SANE_Byte *buf;
103     int started;
104 };
105 
dump_desc(SANE_Handle h,int nr,const SANE_Option_Descriptor * opt)106 static void dump_desc(SANE_Handle h, int nr, const SANE_Option_Descriptor *opt)
107 {
108     SANE_Bool b;
109     SANE_Int i,flags;
110 
111     fprintf(stderr,"sane opt: name=%s title=%s type=%d unit=%d cap=%d\n",
112 	    opt->name, opt->title, opt->type, opt->unit, opt->cap);
113     switch (opt->type) {
114     case SANE_TYPE_BOOL:
115 	sane_control_option(h, nr, SANE_ACTION_GET_VALUE,
116 			    &b, &flags);
117 	fprintf(stderr,"  value=%s [bool]\n",b ? "true" : "false");
118 	break;
119     case SANE_TYPE_INT:
120 	sane_control_option(h, nr, SANE_ACTION_GET_VALUE,
121 			    &i, &flags);
122 	fprintf(stderr,"  value=%d [int]\n",i);
123 	break;
124     case SANE_TYPE_FIXED:
125     case SANE_TYPE_STRING:
126     case SANE_TYPE_BUTTON:
127     case SANE_TYPE_GROUP:
128 	break;
129     }
130     switch (opt->constraint_type) {
131     case SANE_CONSTRAINT_NONE:
132 	break;
133     case SANE_CONSTRAINT_RANGE:
134 	fprintf(stderr,"  range=%d-%d\n",
135 		opt->constraint.range->min,
136 		opt->constraint.range->max);
137 	break;
138     case SANE_CONSTRAINT_WORD_LIST:
139 	fprintf(stderr,"  constraint word_list:");
140 	for (i = 1; i <= opt->constraint.word_list[0]; i++)
141 	    fprintf(stderr," %d",opt->constraint.word_list[i]);
142 	fprintf(stderr,"\n");
143 	break;
144     case SANE_CONSTRAINT_STRING_LIST:
145 	fprintf(stderr,"  constraint string_list:");
146 	for (i = 0; opt->constraint.string_list[i] != NULL; i++)
147 	    fprintf(stderr," %s",opt->constraint.string_list[i]);
148 	fprintf(stderr,"\n");
149 	break;
150     };
151 }
152 
153 static void*
sane_idainit(FILE * fp,char * filename,unsigned int page,struct ida_image_info * info,int thumbnail)154 sane_idainit(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info,
155 	     int thumbnail)
156 {
157     const SANE_Option_Descriptor *opt;
158     SANE_Int flags, count;
159     struct sane_state *h;
160     int rc,i,value,dpi = 0;
161 
162     h = malloc(sizeof(*h));
163     memset(h,0,sizeof(*h));
164 
165     if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) {
166 	fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc));
167 	goto oops;
168     }
169     if (SANE_STATUS_GOOD != (rc = sane_open(filename,&h->sane))) {
170 	fprintf(stderr,"sane_open: %s\n",sane_strstatus(rc));
171 	goto oops;
172     }
173 
174     /* set options */
175     opt = sane_get_option_descriptor(h->sane,0);
176     rc = sane_control_option(h->sane, 0, SANE_ACTION_GET_VALUE,
177 			     &count, &flags);
178     for (i = 1; i < count; i++) {
179 	opt = sane_get_option_descriptor(h->sane,i);
180 	if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_X)) {
181 	    value = opt->constraint.range->min;
182 	    sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
183 				&value, &flags);
184 	} else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_Y)) {
185 	    value = opt->constraint.range->min;
186 	    sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
187 				&value, &flags);
188 	} else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_X)) {
189 	    value = opt->constraint.range->max;
190 	    sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
191 				&value, &flags);
192 	} else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_Y)) {
193 	    value = opt->constraint.range->max;
194 	    sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
195 				&value, &flags);
196 	} else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_PREVIEW)) {
197 	    value = SANE_FALSE;
198 	    sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
199 				&value, &flags);
200 	} else if (opt->cap & SANE_CAP_AUTOMATIC)
201 	    sane_control_option(h->sane, i, SANE_ACTION_SET_AUTO,
202 				NULL, &flags);
203 	if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_RESOLUTION)) {
204 	    if (sane_res) {
205 		dpi = sane_res;
206 		sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE,
207 				    &dpi, &flags);
208 	    }
209 	    sane_control_option(h->sane, i, SANE_ACTION_GET_VALUE,
210 				&dpi, &flags);
211 	}
212 	if (debug)
213 	    dump_desc(h->sane,i,opt);
214     }
215 
216     if (SANE_STATUS_GOOD != (rc = sane_start(h->sane))) {
217 	fprintf(stderr,"sane_start: %s\n",sane_strstatus(rc));
218 	goto oops;
219     }
220     h->started = 1;
221 
222     if (SANE_STATUS_GOOD != (rc = sane_get_parameters(h->sane,&h->parm))) {
223 	fprintf(stderr,"sane_get_parameters: %s\n",sane_strstatus(rc));
224 	goto oops;
225     }
226 
227     if (h->parm.format != SANE_FRAME_GRAY &&
228 	h->parm.format != SANE_FRAME_RGB) {
229 	fprintf(stderr,"sane: unsupported frame format (%d)\n",h->parm.format);
230 	goto oops;
231     }
232     if (h->parm.depth != 8) {
233 	fprintf(stderr,"sane: unsupported color depth (%d)\n",h->parm.depth);
234 	goto oops;
235     }
236     if (-1 == h->parm.lines) {
237 	fprintf(stderr,"sane: can't handle unknown image size\n");
238 	goto oops;
239     }
240 
241     info->width  = h->parm.pixels_per_line;
242     info->height = h->parm.lines;
243     if (dpi)
244 	info->dpi  = dpi;
245     h->buf = malloc(h->parm.bytes_per_line * BUF_LINES);
246     if (debug)
247 	fprintf(stderr,"sane: scanning %ux%u %s\n",info->width,info->height,
248 		(h->parm.format == SANE_FRAME_GRAY) ? "gray" : "color");
249 
250     return h;
251 
252  oops:
253     if (h->buf)
254 	free(h->buf);
255     if (h->started)
256 	sane_cancel(h->sane);
257     if (h->sane)
258 	sane_close(h->sane);
259     sane_exit();
260     free(h);
261     return NULL;
262 }
263 
264 static void
sane_idaread(unsigned char * dst,unsigned int line,void * data)265 sane_idaread(unsigned char *dst, unsigned int line, void *data)
266 {
267     struct sane_state *h = data;
268     unsigned int lines, total, offset, len;
269     int rc, i;
270     SANE_Byte *row;
271 
272     if (0 == (line % BUF_LINES)) {
273 	lines = BUF_LINES;
274 	if (lines > h->parm.lines - line)
275 	    lines = h->parm.lines - line;
276 	total  = h->parm.bytes_per_line * lines;
277 	offset = 0;
278 	while (offset < total) {
279 	    rc = sane_read(h->sane, h->buf + offset, total - offset, &len);
280 	    if (rc != SANE_STATUS_GOOD)
281 		return;
282 	    offset += len;
283 	}
284     }
285     row = h->buf + (line % BUF_LINES) * h->parm.bytes_per_line;
286     switch (h->parm.format) {
287     case SANE_FRAME_GRAY:
288 	for (i = 0; i < h->parm.pixels_per_line; i++) {
289 	    dst[3*i+0] = row[i];
290 	    dst[3*i+1] = row[i];
291 	    dst[3*i+2] = row[i];
292 	}
293 	break;
294     case SANE_FRAME_RGB:
295 	memcpy(dst,row,h->parm.pixels_per_line*3);
296 	break;
297     default:
298 	fprintf(stderr,"sane: read: internal error\n");
299 	exit(1);
300     }
301 }
302 
303 static void
sane_idadone(void * data)304 sane_idadone(void *data)
305 {
306     struct sane_state *h = data;
307 
308     sane_cancel(h->sane);
309     sane_close(h->sane);
310     sane_exit();
311     free(h->buf);
312     free(h);
313 }
314 
315 struct ida_loader sane_loader = {
316     name:  "sane interface",
317     init:  sane_idainit,
318     read:  sane_idaread,
319     done:  sane_idadone,
320 };
321 
init_rd(void)322 static void __init init_rd(void)
323 {
324     load_register(&sane_loader);
325 }
326