From e9e9684117719204929821028ba9dbb7915ea119 Mon Sep 17 00:00:00 2001 From: kraxel Date: Sun, 28 Mar 2004 11:31:57 +0000 Subject: Initial revision --- sane.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 sane.c (limited to 'sane.c') diff --git a/sane.c b/sane.c new file mode 100644 index 0000000..585ac1c --- /dev/null +++ b/sane.c @@ -0,0 +1,324 @@ +#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); +} -- cgit