Logo Search packages:      
Sourcecode: fbi version File versions  Download package

sane.c

#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);
}

Generated by  Doxygen 1.6.0   Back to index