#include #include #include #include #include #include #include "readers.h" #include "viewer.h" #include "sane.h" #include "ida.h" #include #include #include #include #include extern int sane_res; /* ---------------------------------------------------------------------- */ static void build_menu(Widget widget, XtPointer clientdata, XtPointer call_data) { WidgetList children,wlist; Cardinal nchildren; const SANE_Device **list; Widget push; XmString str; char action[256]; int rc,i; /* del old */ XtVaGetValues(widget, XtNchildren,&children, XtNnumChildren,&nchildren, NULL); wlist = malloc(sizeof(Widget*)*nchildren); memcpy(list,children,sizeof(Widget*)*nchildren); for (i = 0; i < nchildren; i++) XtDestroyWidget(wlist[i]); free(wlist); /* create new */ if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto done; } sane_get_devices(&list,0); if (NULL == list[0]) goto done; for (i = 0; list[i] != NULL; i++) { if (debug) fprintf(stderr,"sane dev: %s | %s | %s | %s\n", list[i]->name, list[i]->vendor, list[i]->model, list[i]->type); str = XmStringGenerate((char*)list[i]->model, NULL, XmMULTIBYTE_TEXT, NULL); push = XtVaCreateManagedWidget(list[i]->name, xmPushButtonWidgetClass,widget, XmNlabelString,str, NULL); XmStringFree(str); sprintf(action,"Scan(%s)",list[i]->name); XtAddCallback(push,XmNactivateCallback,action_cb,strdup(action)); } done: sane_exit(); } void sane_menu(Widget menu) { Widget submenu; int rc; if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto done; } submenu = XmCreatePulldownMenu(menu,"scanM",NULL,0); XtVaCreateManagedWidget("scan",xmCascadeButtonWidgetClass,menu, XmNsubMenuId,submenu,NULL); XtAddCallback(submenu, XmNmapCallback, build_menu, NULL); done: sane_exit(); } /* ---------------------------------------------------------------------- */ /* load */ #define BUF_LINES 16 /* read bigger chunks to reduce overhead */ struct sane_state { SANE_Handle sane; SANE_Parameters parm; SANE_Byte *buf; int started; }; static void dump_desc(SANE_Handle h, int nr, const SANE_Option_Descriptor *opt) { SANE_Bool b; SANE_Int i,flags; fprintf(stderr,"sane opt: name=%s title=%s type=%d unit=%d cap=%d\n", opt->name, opt->title, opt->type, opt->unit, opt->cap); switch (opt->type) { case SANE_TYPE_BOOL: sane_control_option(h, nr, SANE_ACTION_GET_VALUE, &b, &flags); fprintf(stderr," value=%s [bool]\n",b ? "true" : "false"); break; case SANE_TYPE_INT: sane_control_option(h, nr, SANE_ACTION_GET_VALUE, &i, &flags); fprintf(stderr," value=%d [int]\n",i); break; case SANE_TYPE_FIXED: case SANE_TYPE_STRING: case SANE_TYPE_BUTTON: case SANE_TYPE_GROUP: break; } switch (opt->constraint_type) { case SANE_CONSTRAINT_NONE: break; case SANE_CONSTRAINT_RANGE: fprintf(stderr," range=%d-%d\n", opt->constraint.range->min, opt->constraint.range->max); break; case SANE_CONSTRAINT_WORD_LIST: fprintf(stderr," constraint word_list:"); for (i = 1; i <= opt->constraint.word_list[0]; i++) fprintf(stderr," %d",opt->constraint.word_list[i]); fprintf(stderr,"\n"); break; case SANE_CONSTRAINT_STRING_LIST: fprintf(stderr," constraint string_list:"); for (i = 0; opt->constraint.string_list[i] != NULL; i++) fprintf(stderr," %s",opt->constraint.string_list[i]); fprintf(stderr,"\n"); break; }; } static void* sane_idainit(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info, int thumbnail) { const SANE_Option_Descriptor *opt; SANE_Int flags, count; struct sane_state *h; int rc,i,value,dpi = 0; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto oops; } if (SANE_STATUS_GOOD != (rc = sane_open(filename,&h->sane))) { fprintf(stderr,"sane_open: %s\n",sane_strstatus(rc)); goto oops; } /* set options */ opt = sane_get_option_descriptor(h->sane,0); rc = sane_control_option(h->sane, 0, SANE_ACTION_GET_VALUE, &count, &flags); for (i = 1; i < count; i++) { opt = sane_get_option_descriptor(h->sane,i); if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_X)) { value = opt->constraint.range->min; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_Y)) { value = opt->constraint.range->min; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_X)) { value = opt->constraint.range->max; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_Y)) { value = opt->constraint.range->max; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_PREVIEW)) { value = SANE_FALSE; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->cap & SANE_CAP_AUTOMATIC) sane_control_option(h->sane, i, SANE_ACTION_SET_AUTO, NULL, &flags); if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_RESOLUTION)) { if (sane_res) { dpi = sane_res; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &dpi, &flags); } sane_control_option(h->sane, i, SANE_ACTION_GET_VALUE, &dpi, &flags); } if (debug) dump_desc(h->sane,i,opt); } if (SANE_STATUS_GOOD != (rc = sane_start(h->sane))) { fprintf(stderr,"sane_start: %s\n",sane_strstatus(rc)); goto oops; } h->started = 1; if (SANE_STATUS_GOOD != (rc = sane_get_parameters(h->sane,&h->parm))) { fprintf(stderr,"sane_get_parameters: %s\n",sane_strstatus(rc)); goto oops; } if (h->parm.format != SANE_FRAME_GRAY && h->parm.format != SANE_FRAME_RGB) { fprintf(stderr,"sane: unsupported frame format (%d)\n",h->parm.format); goto oops; } if (h->parm.depth != 8) { fprintf(stderr,"sane: unsupported color depth (%d)\n",h->parm.depth); goto oops; } if (-1 == h->parm.lines) { fprintf(stderr,"sane: can't handle unknown image size\n"); goto oops; } info->width = h->parm.pixels_per_line; info->height = h->parm.lines; if (dpi) info->dpi = dpi; h->buf = malloc(h->parm.bytes_per_line * BUF_LINES); if (debug) fprintf(stderr,"sane: scanning %dx%d %s\n",info->width,info->height, (h->parm.format == SANE_FRAME_GRAY) ? "gray" : "color"); return h; oops: if (h->buf) free(h->buf); if (h->started) sane_cancel(h->sane); if (h->sane) sane_close(h->sane); sane_exit(); free(h); return NULL; } static void sane_idaread(unsigned char *dst, unsigned int line, void *data) { struct sane_state *h = data; unsigned int lines, total, offset, len; int rc, i; SANE_Byte *row; if (0 == (line % BUF_LINES)) { lines = BUF_LINES; if (lines > h->parm.lines - line) lines = h->parm.lines - line; total = h->parm.bytes_per_line * lines; offset = 0; while (offset < total) { rc = sane_read(h->sane, h->buf + offset, total - offset, &len); if (rc != SANE_STATUS_GOOD) return; offset += len; } } row = h->buf + (line % BUF_LINES) * h->parm.bytes_per_line; switch (h->parm.format) { case SANE_FRAME_GRAY: for (i = 0; i < h->parm.pixels_per_line; i++) { dst[3*i+0] = row[i]; dst[3*i+1] = row[i]; dst[3*i+2] = row[i]; } break; case SANE_FRAME_RGB: memcpy(dst,row,h->parm.pixels_per_line*3); break; default: fprintf(stderr,"sane: read: internal error\n"); exit(1); } } static void sane_idadone(void *data) { struct sane_state *h = data; sane_cancel(h->sane); sane_close(h->sane); sane_exit(); free(h->buf); free(h); } struct ida_loader sane_loader = { name: "sane interface", init: sane_idainit, read: sane_idaread, done: sane_idadone, }; static void __init init_rd(void) { load_register(&sane_loader); }