Example #1
0
static PyObject *
SaneDev_get_option(SaneDevObject *self, PyObject *args)
{
  SANE_Status st;
  const SANE_Option_Descriptor *d;
  PyObject *value=NULL;
  int n;
  void *v;
  
  if (!PyArg_ParseTuple(args, "i", &n))
    {
      return NULL;
    }
  if (self->h==NULL)
    {
      PyErr_SetString(ErrorObject, "SaneDev object is closed");
      return NULL;
    }
  d=sane_get_option_descriptor(self->h, n);
  v=malloc(d->size+1);
  st=sane_control_option(self->h, n, SANE_ACTION_GET_VALUE,
			 v, NULL);

  if (st) 
    {
      free(v); 
      return PySane_Error(st);
    }
  
  switch(d->type)
    {
    case(SANE_TYPE_BOOL):
    case(SANE_TYPE_INT):
      value=Py_BuildValue("i", *( (SANE_Int*)v) );
      break;
    case(SANE_TYPE_FIXED):
      value=Py_BuildValue("d", SANE_UNFIX((*((SANE_Fixed*)v))) );
      break;
    case(SANE_TYPE_STRING):
      value=Py_BuildValue("s", v);
      break;
    case(SANE_TYPE_BUTTON):
    case(SANE_TYPE_GROUP):
      value=Py_BuildValue("O", Py_None);
      break;
    }
  
  free(v);
  return value;
}
Example #2
0
static PyObject *getOption (_ScanDevice * self, PyObject * args)
{
    SANE_Status st;
    const SANE_Option_Descriptor *d;
    PyObject *value = NULL;
    int n;
    void *v;

    if (!PyArg_ParseTuple (args, "i", &n))
        raiseError("Invalid arguments.");

    if (self->h == NULL)
        return raiseDeviceClosedError();

    d = sane_get_option_descriptor (self->h, n);
    v = malloc (d->size + 1);
    st = sane_control_option (self->h, n, SANE_ACTION_GET_VALUE, v, NULL);

    if (st != SANE_STATUS_GOOD)
    {
        free (v);
        return raiseSaneError(st);
    }

    switch (d->type)
    {
        case (SANE_TYPE_BOOL):
        case (SANE_TYPE_INT):
            value = Py_BuildValue ("i", *((SANE_Int *) v));
            break;

        case (SANE_TYPE_FIXED):
            value = Py_BuildValue ("d", SANE_UNFIX ((*((SANE_Fixed *) v))));
            break;

        case (SANE_TYPE_STRING):
            value = Py_BuildValue ("s", v);
            break;

        case (SANE_TYPE_BUTTON):
        case (SANE_TYPE_GROUP):
            value = Py_BuildValue ("O", Py_None);
            break;
    }

    free (v);
    return value;
}
Example #3
0
static PyObject *setAutoOption (_ScanDevice * self, PyObject * args)
{
    SANE_Status st;
    const SANE_Option_Descriptor *d;
    SANE_Int i;
    int n;

    if (!PyArg_ParseTuple (args, "i", &n))
        raiseError("Invalid arguments.");

    if (self->h == NULL)
        return raiseDeviceClosedError();

    d = sane_get_option_descriptor (self->h, n);
    st = sane_control_option (self->h, n, SANE_ACTION_SET_AUTO, NULL, &i);

    if (st != SANE_STATUS_GOOD)
        return raiseSaneError (st);

    return Py_BuildValue ("i", i);
}
Example #4
0
static PyObject *
SaneDev_set_auto_option(SaneDevObject *self, PyObject *args)
{
  SANE_Status st;
  const SANE_Option_Descriptor *d;
  SANE_Int i;
  int n;
  
  if (!PyArg_ParseTuple(args, "i", &n))
    return NULL;
  if (self->h==NULL)
    {
      PyErr_SetString(ErrorObject, "SaneDev object is closed");
      return NULL;
    }
  d=sane_get_option_descriptor(self->h, n);
  st=sane_control_option(self->h, n, SANE_ACTION_SET_AUTO,
			 NULL, &i);
  if (st) {return PySane_Error(st);}
  
  return Py_BuildValue("i", i);
 }
Example #5
0
bool KSaneWidget::openDevice(const QString &deviceName)
{
    int                            i = 0;
    const SANE_Option_Descriptor  *optDesc;
    SANE_Status                    status;
    SANE_Word                      numSaneOptions;
    SANE_Int                       res;
    KPasswordDialog               *dlg;
    KWallet::Wallet               *saneWallet;
    QString                        myFolderName = QStringLiteral("ksane");
    QMap<QString, QString>         wallet_entry;

    if (d->m_saneHandle != 0) {
        // this KSaneWidget already has an open device
        return false;
    }

    // don't bother trying to open if the device string is empty
    if (deviceName.isEmpty()) {
        return false;
    }
    // save the device name
    d->m_devName = deviceName;

    // Try to open the device
    status = sane_open(deviceName.toLatin1().constData(), &d->m_saneHandle);

    bool password_dialog_ok = true;

    // prepare wallet for authentication and create password dialog
    if (status == SANE_STATUS_ACCESS_DENIED) {
        saneWallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), winId());

        if (saneWallet) {
            dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword);
            if (!saneWallet->hasFolder(myFolderName)) {
                saneWallet->createFolder(myFolderName);
            }
            saneWallet->setFolder(myFolderName);
            saneWallet->readMap(deviceName, wallet_entry);
            if (!wallet_entry.empty() || true) {
                dlg->setUsername(wallet_entry[QStringLiteral("username")]);
                dlg->setPassword(wallet_entry[QStringLiteral("password")]);
                dlg->setKeepPassword(true);
            }
        } else {
            dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine);
        }
        dlg->setPrompt(i18n("Authentication required for resource: %1", deviceName));

    }

    // sane_open failed due to insufficient authorization
    // retry opening device with user provided data assisted with kwallet records
    while (status == SANE_STATUS_ACCESS_DENIED) {

        password_dialog_ok = dlg->exec();
        if (!password_dialog_ok) {
            delete dlg;
            d->m_devName.clear();
            return false; //the user canceled
        }

        // add/update the device user-name and password for authentication
        d->m_auth->setDeviceAuth(d->m_devName, dlg->username(), dlg->password());

        status = sane_open(deviceName.toLatin1().constData(), &d->m_saneHandle);

        // store password in wallet on successful authentication
        if (dlg->keepPassword() && status != SANE_STATUS_ACCESS_DENIED) {
            QMap<QString, QString> entry;
            entry[QStringLiteral("username")] = dlg->username();
            entry[QStringLiteral("password")] = dlg->password();
            if (saneWallet) {
                saneWallet->writeMap(deviceName, entry);
            }
        }
    }

    if (status != SANE_STATUS_GOOD) {
        qDebug() << "sane_open(\"" << deviceName << "\", &handle) failed! status = " << sane_strstatus(status);
        d->m_auth->clearDeviceAuth(d->m_devName);
        d->m_devName.clear();
        return false;
    }

    // update the device list if needed to get the vendor and model info
    if (d->m_findDevThread->devicesList().size() == 0) {
        d->m_findDevThread->start();
    } else {
        // use the "old" existing list
        d->devListUpdated();
        // if m_vendor is not updated it means that the list needs to be updated.
        if (d->m_vendor.isEmpty()) {
            d->m_findDevThread->start();
        }
    }

    // Read the options (start with option 0 the number of parameters)
    optDesc = sane_get_option_descriptor(d->m_saneHandle, 0);
    if (optDesc == 0) {
        d->m_auth->clearDeviceAuth(d->m_devName);
        d->m_devName.clear();
        return false;
    }
    QVarLengthArray<char> data(optDesc->size);
    status = sane_control_option(d->m_saneHandle, 0, SANE_ACTION_GET_VALUE, data.data(), &res);
    if (status != SANE_STATUS_GOOD) {
        d->m_auth->clearDeviceAuth(d->m_devName);
        d->m_devName.clear();
        return false;
    }
    numSaneOptions = *reinterpret_cast<SANE_Word *>(data.data());

    // read the rest of the options
    for (i = 1; i < numSaneOptions; ++i) {
        switch (KSaneOption::optionType(sane_get_option_descriptor(d->m_saneHandle, i))) {
        case KSaneOption::TYPE_DETECT_FAIL:
            d->m_optList.append(new KSaneOption(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_CHECKBOX:
            d->m_optList.append(new KSaneOptCheckBox(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_SLIDER:
            d->m_optList.append(new KSaneOptSlider(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_F_SLIDER:
            d->m_optList.append(new KSaneOptFSlider(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_COMBO:
            d->m_optList.append(new KSaneOptCombo(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_ENTRY:
            d->m_optList.append(new KSaneOptEntry(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_GAMMA:
            d->m_optList.append(new KSaneOptGamma(d->m_saneHandle, i));
            break;
        case KSaneOption::TYPE_BUTTON:
            d->m_optList.append(new KSaneOptButton(d->m_saneHandle, i));
            break;
        }
    }

    // do the connections of the option parameters
    for (i = 1; i < d->m_optList.size(); ++i) {
        //qDebug() << d->m_optList.at(i)->name();
        connect(d->m_optList.at(i), SIGNAL(optsNeedReload()), d, SLOT(optReload()));
        connect(d->m_optList.at(i), SIGNAL(valsNeedReload()), d, SLOT(scheduleValReload()));

        if (d->m_optList.at(i)->needsPolling()) {
            //qDebug() << d->m_optList.at(i)->name() << " needs polling";
            d->m_pollList.append(d->m_optList.at(i));
            KSaneOptCheckBox *buttonOption = qobject_cast<KSaneOptCheckBox *>(d->m_optList.at(i));
            if (buttonOption) {
                connect(buttonOption, SIGNAL(buttonPressed(QString,QString,bool)),
                        this, SIGNAL(buttonPressed(QString,QString,bool)));
            }
        }
    }
Example #6
0
File: _sane.c Project: Bouke/Pillow
static PyObject *
SaneDev_get_options(SaneDevObject *self, PyObject *args)
{
  const SANE_Option_Descriptor *d;
  PyObject *list, *value;
  int i=1;
  
  if (!PyArg_ParseTuple(args, ""))
    return NULL;
  if (self->h==NULL)
    {
      PyErr_SetString(ErrorObject, "SaneDev object is closed");
      return NULL;
    }
  if (!(list = PyList_New(0)))
	    return NULL;

  do 
    {
      d=sane_get_option_descriptor(self->h, i);
      if (d!=NULL) 
	{
	  PyObject *constraint=NULL;
	  int j;
	  
	  switch (d->constraint_type)
	    {
	    case(SANE_CONSTRAINT_NONE): 
	      Py_INCREF(Py_None); constraint=Py_None; break;
	    case(SANE_CONSTRAINT_RANGE): 
	      if (d->type == SANE_TYPE_INT)
		constraint=Py_BuildValue("iii", d->constraint.range->min, 
					 d->constraint.range->max, 
					 d->constraint.range->quant);
	      else
		constraint=Py_BuildValue("ddd", 
					 SANE_UNFIX(d->constraint.range->min), 
					 SANE_UNFIX(d->constraint.range->max), 
					 SANE_UNFIX(d->constraint.range->quant));
	      break;
	    case(SANE_CONSTRAINT_WORD_LIST): 
	      constraint=PyList_New(d->constraint.word_list[0]);
	      if (d->type == SANE_TYPE_INT)
		for (j=1; j<=d->constraint.word_list[0]; j++)
		  PyList_SetItem(constraint, j-1, 
				 PyInt_FromLong(d->constraint.word_list[j]));
	      else
		for (j=1; j<=d->constraint.word_list[0]; j++)
		  PyList_SetItem(constraint, j-1, 
				 PyFloat_FromDouble(SANE_UNFIX(d->constraint.word_list[j])));
	      break;
	    case(SANE_CONSTRAINT_STRING_LIST): 
	      constraint=PyList_New(0);
	      for(j=0; d->constraint.string_list[j]!=NULL; j++)
		PyList_Append(constraint, 
#if PY_MAJOR_VERSION >= 3
			      PyUnicode_DecodeLatin1(d->constraint.string_list[j], strlen(d->constraint.string_list[j]), NULL));
#else
			      PyString_FromString(d->constraint.string_list[j]));
#endif
	      break;
	    }
	  value=Py_BuildValue("isssiiiiO", i, d->name, d->title, d->desc, 
			      d->type, d->unit, d->size, d->cap, constraint);
	  PyList_Append(list, value);
	}
      i++;
    } while (d!=NULL);
Example #7
0
static PyObject *
SaneDev_set_option(SaneDevObject *self, PyObject *args)
{
  SANE_Status st;
  const SANE_Option_Descriptor *d;
  SANE_Int i;
  PyObject *value;
  int n;
  void *v;
  
  if (!PyArg_ParseTuple(args, "iO", &n, &value))
    return NULL;
  if (self->h==NULL)
    {
      PyErr_SetString(ErrorObject, "SaneDev object is closed");
      return NULL;
    }
  d=sane_get_option_descriptor(self->h, n);
  v=malloc(d->size+1);

  switch(d->type)
    {
    case(SANE_TYPE_BOOL):
      if (!PyInt_Check(value)) 
	{
	  PyErr_SetString(PyExc_TypeError, "SANE_BOOL requires an integer");
	  free(v);
	  return NULL;
	}
	/* fall through */
    case(SANE_TYPE_INT):
      if (!PyInt_Check(value)) 
	{
	  PyErr_SetString(PyExc_TypeError, "SANE_INT requires an integer");
	  free(v);
	  return NULL;
	}
      *( (SANE_Int*)v) = PyInt_AsLong(value);
      break;
    case(SANE_TYPE_FIXED):
      if (!PyFloat_Check(value)) 
	{
	  PyErr_SetString(PyExc_TypeError, "SANE_FIXED requires a floating point number");
	  free(v);
	  return NULL;
	}
      *( (SANE_Fixed*)v) = SANE_FIX(PyFloat_AsDouble(value));
      break;
    case(SANE_TYPE_STRING):
      if (!PyString_Check(value)) 
	{
	  PyErr_SetString(PyExc_TypeError, "SANE_STRING requires a string");
	  free(v);
	  return NULL;
	}
      strncpy(v, PyString_AsString(value), d->size-1);
      ((char*)v)[d->size-1] = 0;
      break;
    case(SANE_TYPE_BUTTON): 
    case(SANE_TYPE_GROUP):
      break;
    }
  
  st=sane_control_option(self->h, n, SANE_ACTION_SET_VALUE,
			 v, &i);
  if (st) {free(v); return PySane_Error(st);}
  
  free(v);
  return Py_BuildValue("i", i);
}
Example #8
0
// --------------------------------------------------------------
void ControlsWindow::MessageReceived
	(
	BMessage *	msg
	)
{
	switch (msg->what)
		{
		case SET_DEVICE_MSG:
			{
			ssize_t 			data_size;
			SANE_Status			status;
			const SANE_Device *	device_info;
			
			if ( msg->FindData("device", B_RAW_TYPE, (const void **) &device_info, &data_size) != B_OK )
				break;
					
			m_device_info = device_info;
					
			if ( m_device )
				sane_close(m_device);
			m_device 		= NULL;
			
			ScannerOptionView * option;
			BView *	child;

			child = m_panel->ChildAt(0);
			while ( child )
				{
				option = dynamic_cast<ScannerOptionView *>(child);
				if ( option )
					option->RemoveSelf();
			
				child = child->NextSibling();
				};
				
			status = sane_open(m_device_info->name, &m_device);
			if ( status != SANE_STATUS_GOOD )
				{
			 	fprintf (stderr, "sane_open: %s\n", sane_strstatus (status));

				BAlert * alert = new BAlert("sane_open", sane_strstatus(status), "Argh");
				alert->Go();
				break;
				};


			const SANE_Option_Descriptor *	desc;
			
			// m_options_lv->MakeEmpty();
			printf("Options for device %s:\n", m_device_info->name);
			int opt = 1;	// skip first option (option 0 = number of options)
			BRect r = m_panel->Bounds();
			r.top = 80;
			r.InsetBy(8, 8);

			while ( (desc = sane_get_option_descriptor(m_device, opt)) != NULL )
				{
				if (desc->type != SANE_TYPE_GROUP)
					{
					ScannerOptionView * ov = new ScannerOptionView(r, desc->name, B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT, 0,
																m_device, opt);
					if ( ov->Build() == B_OK )
						{
						m_panel->AddChild(ov);
						r.top += ov->Bounds().Height();
						m_tooltip->SetText(ov, desc->desc);
						}
					else
						delete ov;
					};

				BString label;
				if (desc->type == SANE_TYPE_GROUP)
					label << "-- ";
				label << desc->title;
				if (desc->type == SANE_TYPE_GROUP)
					label << " --";

				printf("  %d: name = %s\n"
				       "      title = %s\n"
				       "      desc = %s\n"
				       "      type = %d\n"
				       "      unit = %s\n"
					   "      size = %d\n"
				       "      cap  = 0x%0x\n", opt, desc->name, desc->title, desc->desc,
						desc->type, get_unit2(desc->unit), desc->size, desc->cap);


				// m_options_lv->AddItem(new BStringItem(label.String()));

				opt++;
				};

			BMessage * msg;
		
			msg = new BMessage(MainWindow::DEVICE_CHANGED_MSG);
			msg->AddString("device_name", m_device_info->name);
			
			m_parent_window->PostMessage(msg);
			delete msg;
			break;
			};
			
		case SCAN_MSG:
			{
			SANE_Handle		device;
			
			device = Device();
						
			if ( ! device )
				break;
				
			if ( m_scan_thread_id != -1 )
				{
				// already launched...
				m_cancel_scan = true;
				break;
				};
			
			m_cancel_scan = false;

			m_scan_thread_id = spawn_thread(_ScanThread, "scan", B_NORMAL_PRIORITY, this);
			resume_thread(m_scan_thread_id);
			break;
			};	
		
		default:	
			inherited::MessageReceived(msg);
	}
}
Example #9
0
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;
}
Example #10
0
extern char *internalGetScannerDetails(char *device, char *lang) {

  char *answer = NULL;
  SANE_Status status;
  char *deviceList = o_strdup("");; 
  int hlp = 0, resolution = 300, minRes=50, maxRes=50, phashAvailable=0;
  char *resolution_s, *maxRes_s, *minRes_s;
  SANE_Handle *openDeviceHandle;

  o_log(DEBUGM, "sane_open of \"%s\"", device);
  status = sane_open (device, (SANE_Handle)&openDeviceHandle);
  if(status != SANE_STATUS_GOOD) {
    o_log(ERROR, "Could not open: '%s' with error: %s", device, sane_strstatus(status));
    free(deviceList);
    return NULL;
  }


  //
  // Find resolution ranges
  //
  for (hlp = 0; hlp < 9999; hlp++) {

    const SANE_Option_Descriptor *sod;

    sod = sane_get_option_descriptor (openDeviceHandle, hlp);
    if (sod == NULL)
      break;

    // Just a placeholder
    if (sod->type == SANE_TYPE_GROUP
    || sod->name == NULL
    || hlp == 0)
      continue;

    if ( 0 == strcmp(sod->name, SANE_NAME_SCAN_RESOLUTION) ) {

      // Some kind of sliding range
      if (sod->constraint_type == SANE_CONSTRAINT_RANGE) {
        o_log(DEBUGM, "Resolution setting detected as 'range'");

        // Fixed resolution
        if (sod->type == SANE_TYPE_FIXED)
          maxRes = (int)SANE_UNFIX (sod->constraint.range->max);
        else
          maxRes = sod->constraint.range->max;
      }

      // A fixed list of options
      else if (sod->constraint_type == SANE_CONSTRAINT_WORD_LIST) {
        int lastIndex = sod->constraint.word_list[0];
        o_log(DEBUGM, "Resolution setting detected as 'word list': lastIndex = %d",lastIndex);

        // maxRes = sod->constraint.word_list[lastIndex];
        // resolution list cannot be treated as low to high ordered list 
        // remark: impl capability to select scan resolution in webInterface
        int n=0;
        maxRes = 0;
        for (n=1; n<=lastIndex; n++ ) {
          o_log(DEBUGM, "index results %d --> %d", n ,(int)sod->constraint.word_list[n]);
          if ( maxRes < sod->constraint.word_list[n] ) {
            maxRes=sod->constraint.word_list[n];
          }
        }

      }

      break; // we've found our resolution - no need to search more
    }
  }
  o_log(DEBUGM, "Determined max resultion to be %d", maxRes);


  // Define a default
  if(resolution >= maxRes)
    resolution = maxRes;
  if(resolution <= minRes)
    resolution = minRes;

  o_log(DEBUGM, "sane_cancel");
  sane_cancel(openDeviceHandle);

  o_log(DEBUGM, "sane_close");
  sane_close(openDeviceHandle);



  //
  // What languages can we OCR for?
  //
  char *availableLangs = o_strdup("");
#ifdef CAN_OCR
  struct simpleLinkedList *languages = getOCRAvailableLanguages();
  while (languages != NULL ) {
    if ( checkOCRLanguage( languages->data ) == 0 ) {
      o_concatf(&availableLangs, "<lang>%s</lang>", languages->data);
    }
    languages = sll_getNext(languages);
  }
  sll_destroy( languages );
#endif /* CAN_OCR */


  //
  // Can we give the option of doing 'find simmilar'?
  //
#ifdef CAN_PHASH
  phashAvailable = 1;
#endif /* CAN_PHASH */

  // Build Reply
  //
  resolution_s = itoa(resolution,10);
  maxRes_s = itoa(maxRes,10);
  minRes_s = itoa(minRes,10);

  o_concatf(&deviceList, "<Resolution><max>%s</max><min>%s</min><default>%s</default></Resolution><OCRLanguages>%s</OCRLanguages><phash>%d</phash>", maxRes_s, minRes_s, resolution_s, availableLangs, phashAvailable);

  free(maxRes_s);
  free(minRes_s);
  free(resolution_s);
  free(availableLangs);

  // The escaped string placeholder will be interprited in the sane dispatcher client
  answer = o_printf("<?xml version='1.0' encoding='utf-8'?>\n<Response><ScannerDetails>%s</ScannerDetails></Response>", deviceList);
  free(deviceList);

  return answer;

}
Example #11
0
int setOptions( char *uuid, SANE_Handle *openDeviceHandle, int *request_resolution ) {

  int option = 0;
  SANE_Status status;
  SANE_Fixed v_f;
  SANE_Int v_i;
  SANE_Bool v_b;
  char *v_c;
  //const char *modes[] = { SANE_VALUE_SCAN_MODE_COLOR, SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL };
  const char *modes_colour[] = { SANE_VALUE_SCAN_MODE_COLOR, "Color", SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL };
  const char *modes_gray[] = { SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL };
  const char *speeds[] = { "Auto", "Normal", "Fast", NULL };
  const char *compression[] = { "None", NULL };
  const char *sources[] = { "Auto", SANE_I18N ("Auto"), "Flatbed", SANE_I18N ("Flatbed"), 
                            "FlatBed", "Normal", SANE_I18N ("Normal"), NULL };

  int testScanner = 0;
  char *devName = getScanParam(uuid, SCAN_PARAM_DEVNAME);
  if ( strstr(devName, "test") != 0 ) {
    testScanner = 1;
  }
  free(devName);


  for (option = 0; option < 9999; option++) {

    const SANE_Option_Descriptor *sod = sane_get_option_descriptor (openDeviceHandle, option);

    // No more options    
    if (sod == NULL)
      break;

    // Just a placeholder
    if (sod->type == SANE_TYPE_GROUP
    || sod->name == NULL
    || option == 0)
      continue;

    log_option( option, sod );

    // Validation
    if ( (sod->cap & SANE_CAP_SOFT_SELECT) && (sod->cap & SANE_CAP_HARD_SELECT) ) {
      o_log(DEBUGM, "The backend said that '%s' is both hardward and software settable! Err", sod->name);
      updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, 0);
      return 0;
    }

    // we MUST set this value
    if ( (sod->cap & SANE_CAP_SOFT_DETECT) && ((sod->cap & SANE_CAP_INACTIVE) == 0) ) {

      // A hardware setting
      if ( sod->cap & SANE_CAP_HARD_SELECT ) {
        o_log(DEBUGM, "We've got no way of telling the user to set the hardward %s! Err", sod->name);
      }

      // a software setting
      else {

        int paramSetRet = 0;

        // Set scanning Source
        if ( strcmp(sod->name, SANE_NAME_SCAN_SOURCE) == 0 ) {
          if ( !setDefaultScannerOption(openDeviceHandle, sod, option, &paramSetRet) ) {
            int i, j; 
            int foundMatch = 0;
            for (i = 0; sources[i] != NULL; i++) {
              for (j = 0; sod->constraint.string_list[j]; j++) {
                if (strcmp (sources[i], sod->constraint.string_list[j]) == 0)
                  break;
              }
              if (sod->constraint.string_list[j] != NULL) {
                v_c = o_strdup(sources[i]);
                status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, &paramSetRet);
                free(v_c);
                foundMatch = 1;
                break;
              }
            }
            if( foundMatch == 0 ) {
              o_log(DEBUGM, "Non of the available options are appropriate.");
            }
          }
        }

        // Set scanning mode
        else if ( strcmp(sod->name, SANE_NAME_SCAN_MODE ) == 0 ) {
          const char **modes;
          char *requested_mode = getScanParam(uuid, SCAN_PARAM_FORMAT );
          if( 0 == strcmp( "colour", requested_mode ) ) {
            modes = modes_colour;
          }
          else {
            modes = modes_gray;
          }
          free( requested_mode );
          int i, j; 
          int foundMatch = 0;
          for (i = 0; modes[i] != NULL; i++) {
            for (j = 0; sod->constraint.string_list[j]; j++) {
              if (strcmp (modes[i], sod->constraint.string_list[j]) == 0)
                break;
            }
            if (sod->constraint.string_list[j] != NULL) {
              v_c = o_strdup(modes[i]);
              status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, &paramSetRet);
              free(v_c);
              foundMatch = 1;
              break;
            }
          }
          if( foundMatch == 0 ) {
            o_log(DEBUGM, "Non of the available options are appropriate.");
          }
        }

        else if ( strcmp(sod->name, "batch-scan" ) == 0 ) {
          v_b = SANE_FALSE;
          status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
        }

        else if ( strcmp(sod->name, "compression") == 0 ) {
            int i, j; 
            int foundMatch = 0;
            for (i = 0; compression[i] != NULL; i++) {
              for (j = 0; sod->constraint.string_list[j]; j++) {
              o_log(DEBUGM, "n list: %s", sod->constraint.string_list[j]);
                if (strcmp (compression[i], sod->constraint.string_list[j]) == 0)
                  break;
              }
              if (sod->constraint.string_list[j] != NULL) {
              o_log(DEBUGM, "Attempting to set compresstion to: %s", compression[i]);
                v_c = o_strdup(compression[i]);
                status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, &paramSetRet);
                free(v_c);
                foundMatch = 1;
                break;
              }
            }
            if( foundMatch == 0 ) {
              o_log(DEBUGM, "Non of the available options are appropriate.");
            }
        }

        // Set scanning depth
        else if ( strcmp(sod->name, SANE_NAME_BIT_DEPTH) == 0 ) {
          if ( !setDefaultScannerOption(openDeviceHandle, sod, option, &paramSetRet) ) {
            if( sod->type == SANE_TYPE_STRING ) {
              v_c = o_strdup("8");
              status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, &paramSetRet);
              free(v_c);
            }
            if (sod->type == SANE_TYPE_FIXED) {
              v_f = SANE_FIX( 8 );
              status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
            }
            else {
              v_i = 8;
              status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, &paramSetRet);
            }
          }
        }

        // Set Preview mode
        else if ( strcmp(sod->name, SANE_NAME_PREVIEW) == 0 ) {
          if ( !setDefaultScannerOption(openDeviceHandle, sod, option, &paramSetRet) ) {
            v_b = SANE_FALSE;
            status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
        }

        // Set scanning resolution
        else if ( strcmp(sod->name, SANE_NAME_SCAN_RESOLUTION) == 0 ) {

          char *request_resolution_s;

          request_resolution_s = getScanParam(uuid, SCAN_PARAM_REQUESTED_RESOLUTION);
          *request_resolution = atoi(request_resolution_s);
          free(request_resolution_s);

          if (sod->type == SANE_TYPE_FIXED) {
            v_f = SANE_FIX( *request_resolution );
            status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
          }
          else if (sod->type == SANE_TYPE_INT) {
            int sane_resolution = *request_resolution;
            status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &sane_resolution, &paramSetRet);
          }
         else {
            int sane_resolution = *request_resolution;
            if( sod->constraint.range->quant != 0 ) 
              sane_resolution = sane_resolution * sod->constraint.range->quant;
            status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &sane_resolution, &paramSetRet);
          }
        }

        else if ( strcmp(sod->name, SANE_NAME_SCAN_TL_Y) == 0 ) {
          v_f = sod->constraint.range->min;
          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_SCAN_TL_X) == 0 ) {
          v_f = sod->constraint.range->min;
          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_SCAN_BR_Y) == 0 ) {
          int pagelength;
          char *length_s;

          v_f = sod->constraint.range->max;
          length_s = getScanParam(uuid, SCAN_PARAM_LENGTH);
          pagelength = atoi(length_s);
          if(pagelength && pagelength >= 20 && pagelength < 100)
            v_f = SANE_FIX( ( SANE_UNFIX(v_f) * (double)pagelength) / 100);
          free(length_s);

          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_SCAN_BR_X) == 0 ) {
          v_f = sod->constraint.range->max;
          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_BRIGHTNESS) == 0 ) {
          v_f = 0;
          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_CONTRAST) == 0 ) {
          v_f = 0;
          status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, &paramSetRet);
        }

        else if ( strcmp(sod->name, SANE_NAME_SCAN_SPEED) == 0) {
          if ( !setDefaultScannerOption(openDeviceHandle, sod, option, &paramSetRet) ) {
            int i, j; 
            int foundMatch = 0;
            for (i = 0; speeds[i] != NULL; i++) {
              for (j = 0; sod->constraint.string_list[j]; j++) {
                if (strcmp (speeds[i], sod->constraint.string_list[j]) == 0)
                  break;
              }
              if (sod->constraint.string_list[j] != NULL) {
                v_c = o_strdup(speeds[i]);
                status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, &paramSetRet);
                free(v_c);
                foundMatch = 1;
                break;
              }
            }
            if( foundMatch == 0 ) {
              o_log(DEBUGM, "Non of the available options are appropriate.");
            }
          }
        }

        else if ( strcmp(sod->name, "custom-gamma") == 0 ) {
          v_b = SANE_FALSE;
          status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
        }

        // For the test 'virtual scanner'
        else if (testScanner == 1) {

          if ( strcmp(sod->name, "hand-scanner" ) == 0 ) {
            v_b = SANE_FALSE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
          else if ( strcmp(sod->name, "three-pass") == 0 ){
            v_b = SANE_FALSE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
          else if ( strcmp(sod->name, "three-pass-order") == 0 ) {
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "RGB", &paramSetRet);
          }
          else if ( strcmp(sod->name, "test-raw_imageture") == 0 ) {
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "Color pattern", &paramSetRet);
          }
          else if ( strcmp(sod->name, "read-delay") == 0 ) {
            v_b = SANE_TRUE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
          else if ( strcmp(sod->name, "fuzzy-parameters") == 0 ) {
            v_b = SANE_TRUE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
          else if ( strcmp(sod->name, "read-delay-duration") == 0 ) {
            v_i = 1000;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, &paramSetRet);
          }
          else if ( strcmp(sod->name, "read-limit") == 0 ) {
            v_b = SANE_TRUE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
          else if ( strcmp(sod->name, "read-limit-size") == 0 ) {
            v_i = sod->constraint.range->max;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, &paramSetRet);
          }
          else if ( strcmp(sod->name, "read-return-value") == 0 ) {
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "Default", &paramSetRet);
          }
          else if ( strcmp(sod->name, "ppl-loss") == 0 ) {
            v_i = 0;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, &paramSetRet);
          }
          else if ( strcmp(sod->name, "invert-endianess") == 0 ) {
            v_b = SANE_FALSE;
            status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, &paramSetRet);
          }
        }

        // not a 'well known' option
        else {
          // try setting automatically
          if ( !setDefaultScannerOption(openDeviceHandle, sod, option, &paramSetRet) )
            o_log(DEBUGM, "Could not set authmatically", sod->name);
        }

        if( status != SANE_STATUS_GOOD ) {
          handleSaneErrors("Cannot set no to", sod->name, status, paramSetRet);
          updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status);
          return 0;
        }

        if ( paramSetRet & SANE_INFO_RELOAD_OPTIONS ) {
          //start from the beginning again.
          option = 0;
        } 


      } // setable option
    }
    else {
      o_log(DEBUGM, "The option does not need to be set.");
    }

  } // options loop

  return 1;
}
Example #12
0
static void OyInit_color_options(SANE_Handle device)
{
   const SANE_Option_Descriptor *opt = NULL;
   SANE_Int num_options = 0;
   SANE_Status status;
   unsigned int opt_num = 0, i = 0, chars = 0;
   char buf[BUFSIZE];

   /* We got a device, find out how many options it has */
   status = sane_control_option(device, 0, SANE_ACTION_GET_VALUE, &num_options, 0);
   if (status != SANE_STATUS_GOOD) {
      fprintf(stderr, "unable to determine option count\n");
      exit(1);
   }

   color_option_names = (char **)malloc(sizeof(char *) * num_options);
   color_option_values = (char **)malloc(sizeof(char *) * num_options);
   memset(color_option_names, 0, sizeof(char *) * num_options);
   memset(color_option_values, 0, sizeof(char *) * num_options);

   for (opt_num = 1; opt_num < num_options; opt_num++) {
      opt = sane_get_option_descriptor(device, opt_num);
      if (opt->cap & SANE_CAP_COLOUR) {
         void *val = malloc(opt->size);

         color_option_names[i] = (char *)malloc(strlen(opt->name) + 1);
         strcpy(color_option_names[i], opt->name);

         sane_control_option(device, opt_num, SANE_ACTION_GET_VALUE, val, 0);
         switch (opt->type) {
            case SANE_TYPE_BOOL:
               color_option_values[i] = *(SANE_Bool *) val ? "true" : "false";
               break;
            case SANE_TYPE_INT:
               if (opt->size == (SANE_Int) sizeof(SANE_Word))
                  chars = sprintf(buf, "%d", *(SANE_Int *) val);  /* use snprintf( ..,128,.. ) */
               else
                  chars = print_int_vec((SANE_Int *) val, opt->size, buf, BUFSIZE);
               color_option_values[i] = (char *)malloc(chars + 1);
               strcpy(color_option_values[i], buf);
               break;
            case SANE_TYPE_FIXED:
               chars = sprintf(buf, "%f", SANE_UNFIX(*(SANE_Fixed *) val));
               color_option_values[i] = (char *)malloc(chars + 1);
               strcpy(color_option_values[i], buf);
               break;
            case SANE_TYPE_STRING:
               color_option_values[i] = (char *)malloc(strlen((char *)val) + 1);
               strcpy(color_option_values[i], (char *)val);
               break;
            case SANE_TYPE_BUTTON:
               color_option_values[i] = "button";
               break;
            default:
               fprintf(stderr, "Do not know what to do with option %d\n", opt->type);
               exit(0);
               break;
         }
         i++;
      }
   }
}
Example #13
0
static PyObject *setOption (_ScanDevice * self, PyObject * args)
{
    SANE_Status st;
    const SANE_Option_Descriptor *d;
    SANE_Int i;
    PyObject *value;
    int n;

    if (!PyArg_ParseTuple (args, "iO", &n, &value))
        raiseError("Invalid arguments.");

    if (self->h == NULL)
        return raiseDeviceClosedError();

    d = sane_get_option_descriptor (self->h, n);
    switch (d->type)
    {
        case (SANE_TYPE_BOOL):
            if (!PyInt_Check (value))
                return raiseError("SANE_Bool requires an integer.");

            SANE_Bool b = PyInt_AsLong(value);

            if (b != SANE_FALSE && b > SANE_TRUE)
                b = SANE_TRUE;

            st = sane_control_option (self->h, n, SANE_ACTION_SET_VALUE, (void *)&b, &i);
            break;

        case (SANE_TYPE_INT):
            if (!PyInt_Check (value))
                return raiseError("SANE_Int requires an integer.");

            SANE_Int j = PyInt_AsLong (value);
            st = sane_control_option (self->h, n, SANE_ACTION_SET_VALUE, (void *)&j, &i);
            break;

        case (SANE_TYPE_FIXED):
            if (!PyFloat_Check (value))
                return raiseError("SANE_Fixed requires an float.");

            SANE_Fixed f = SANE_FIX (PyFloat_AsDouble (value));
            st = sane_control_option (self->h, n, SANE_ACTION_SET_VALUE, (void *)&f, &i);
            break;

        case (SANE_TYPE_STRING):
            if (!PyUNICODE_CHECK (value))
                return raiseError("SANE_String requires a a string.");

            SANE_String s = malloc (d->size + 1);
            strncpy (s, PyUNICODE_AsBYTES (value), d->size - 1);
            ((SANE_String) s)[d->size - 1] = 0;
            st = sane_control_option (self->h, n, SANE_ACTION_SET_VALUE, (void *)s, &i);
            free(s);
            break;

        case (SANE_TYPE_BUTTON):
        case (SANE_TYPE_GROUP):
            break;
    }

    if (st != SANE_STATUS_GOOD)
        return raiseSaneError(st);

    return Py_BuildValue ("i", i);
}
Example #14
0
static PyObject *getOptions (_ScanDevice * self, PyObject * args)
{
    const SANE_Option_Descriptor *d;
    PyObject *list, *value;
    int i = 1;

    if (!PyArg_ParseTuple (args, ""))
        raiseError("Invalid arguments.");

    if (self->h == NULL)
        return raiseDeviceClosedError();

    if (!(list = PyList_New (0)))
        raiseError("Unable to allocate list.");

    do
    {
        d = sane_get_option_descriptor (self->h, i);
        if (d != NULL)
        {
            PyObject *constraint = NULL;
            int j;

            switch (d->constraint_type)
            {
            case (SANE_CONSTRAINT_NONE):
                Py_INCREF (Py_None);
                constraint = Py_None;
                break;
            case (SANE_CONSTRAINT_RANGE):
                if (d->type == SANE_TYPE_INT)
                    constraint =
                        Py_BuildValue ("iii", d->constraint.range->min,
                                       d->constraint.range->max,
                                       d->constraint.range->quant);
                else
                    constraint = Py_BuildValue ("ddd",
                                                SANE_UNFIX (d->
                                                            constraint.
                                                            range->min),
                                                SANE_UNFIX (d->
                                                            constraint.
                                                            range->max),
                                                SANE_UNFIX (d->
                                                            constraint.
                                                            range->quant));
                break;
            case (SANE_CONSTRAINT_WORD_LIST):
                constraint = PyList_New (d->constraint.word_list[0]);

                if (d->type == SANE_TYPE_INT)
                    for (j = 1; j <= d->constraint.word_list[0]; j++)
                        PyList_SetItem (constraint, j - 1,
                                        PyInt_FromLong (d->constraint.
                                                        word_list[j]));
                else
                    for (j = 1; j <= d->constraint.word_list[0]; j++)
                        PyList_SetItem (constraint, j - 1,
                                        PyFloat_FromDouble (SANE_UNFIX
                                                            (d->
                                                             constraint.
                                                             word_list[j])));
                break;
            case (SANE_CONSTRAINT_STRING_LIST):
                constraint = PyList_New (0);

                for (j = 0; d->constraint.string_list[j] != NULL; j++)
                    PyList_Append (constraint,
                                   PyUNICODE_FromUNICODE (d->constraint.
                                                        string_list[j]));
                break;
            }
            value = Py_BuildValue ("isssiiiiO", i, d->name, d->title, d->desc,
                                   d->type, d->unit, d->size, d->cap, constraint);

            PyList_Append (list, value);
        }
        i++;
    }

    while (d != NULL);
    return list;
}
Example #15
0
void
testsane (const char *dev_name)
{
  int hlp, x;
  SANE_Status bla;
  SANE_Int blubb;
  SANE_Handle hand;
  SANE_Parameters pars;
  const SANE_Option_Descriptor *sod;
  const SANE_Device **device_list;
  char buffer[2048];

  bla = sane_init (&blubb, auth_callback);
  fprintf (stderr, "Init : stat=%d ver=%x\nPress Enter to continue...",
	   bla, blubb);
  getchar ();
  if (bla != SANE_STATUS_GOOD)
    return;

  bla = sane_get_devices (&device_list, SANE_FALSE);
  fprintf (stderr, "GetDev : stat=%s\n", sane_strstatus (bla));
  if (bla != SANE_STATUS_GOOD)
    return;

  bla = sane_open (dev_name, &hand);
  fprintf (stderr, "Open : stat=%s hand=%p\n", sane_strstatus (bla), hand);
  if (bla != SANE_STATUS_GOOD)
    return;

  bla = sane_set_io_mode (hand, 0);
  fprintf (stderr, "SetIoMode : stat=%s\n", sane_strstatus (bla));

  for (hlp = 0; hlp < 9999; hlp++)
    {
      sod = sane_get_option_descriptor (hand, hlp);
      if (sod == NULL)
	break;
      fprintf (stderr, "Gopt(%d) : stat=%p\n", hlp, sod);
      fprintf (stderr, "name : %s\n", sod->name);
      fprintf (stderr, "title: %s\n", sod->title);
      fprintf (stderr, "desc : %s\n", sod->desc);

      fprintf (stderr, "type : %d\n", sod->type);
      fprintf (stderr, "unit : %d\n", sod->unit);
      fprintf (stderr, "size : %d\n", sod->size);
      fprintf (stderr, "cap  : %d\n", sod->cap);
      fprintf (stderr, "ctyp : %d\n", sod->constraint_type);
      switch (sod->constraint_type)
	{
	case SANE_CONSTRAINT_NONE:
	  break;
	case SANE_CONSTRAINT_STRING_LIST:
	  fprintf (stderr, "stringlist:\n");
	  break;
	case SANE_CONSTRAINT_WORD_LIST:
	  fprintf (stderr, "wordlist (%d) : ", sod->constraint.word_list[0]);
	  for (x = 1; x <= sod->constraint.word_list[0]; x++)
	    fprintf (stderr, " %d ", sod->constraint.word_list[x]);
	  fprintf (stderr, "\n");
	  break;
	case SANE_CONSTRAINT_RANGE:
	  fprintf (stderr, "range: %d-%d %d \n", sod->constraint.range->min,
		   sod->constraint.range->max, sod->constraint.range->quant);
	  break;
	}
    }

  bla = sane_get_parameters (hand, &pars);
  fprintf (stderr,
	   "Parm : stat=%s form=%d,lf=%d,bpl=%d,pixpl=%d,lin=%d,dep=%d\n",
	   sane_strstatus (bla),
	   pars.format, pars.last_frame,
	   pars.bytes_per_line, pars.pixels_per_line,
	   pars.lines, pars.depth);
  if (bla != SANE_STATUS_GOOD)
    return;

  bla = sane_start (hand);
  fprintf (stderr, "Start : stat=%s\n", sane_strstatus (bla));
  if (bla != SANE_STATUS_GOOD)
    return;

  do
    {
      bla = sane_read (hand, buffer, sizeof (buffer), &blubb);
      /*printf("Read : stat=%s len=%d\n",sane_strstatus (bla),blubb); */
      if (bla != SANE_STATUS_GOOD)
	{
	  if (bla == SANE_STATUS_EOF)
	    break;
	  return;
	}
      fwrite (buffer, 1, blubb, stdout);
    }
  while (1);

  sane_cancel (hand);
  fprintf (stderr, "Cancel.\n");

  sane_close (hand);
  fprintf (stderr, "Close\n");

  for (hlp = 0; hlp < 20; hlp++)
    fprintf (stderr, "STRS %d=%s\n", hlp, sane_strstatus (hlp));

  fprintf (stderr, "Exit.\n");
}