aboutsummaryrefslogtreecommitdiffstats
path: root/sane.c
diff options
context:
space:
mode:
Diffstat (limited to 'sane.c')
-rw-r--r--sane.c324
1 files changed, 324 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sane/sane.h>
+#include <sane/saneopts.h>
+
+#include "readers.h"
+#include "viewer.h"
+#include "sane.h"
+#include "ida.h"
+
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+#include <Xm/PushB.h>
+#include <Xm/CascadeB.h>
+#include <Xm/RowColumn.h>
+
+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);
+}