2001-09-10 23:11:17 +00:00
|
|
|
|
/* Please note! This is extremely alpha code, and is really intended as
|
|
|
|
|
* a "proof of concept" since I don't yet know whether it's going to
|
|
|
|
|
* to be practical and/or possible to implement a the complete backend.
|
2002-01-19 02:06:40 +00:00
|
|
|
|
* It's also been tested with only cameras I have access to: the Kodak DC240
|
|
|
|
|
* and the Directory Browse "camera." I'm very interested
|
2001-09-18 04:26:13 +00:00
|
|
|
|
* in learning what it would take to support more cameras. In
|
|
|
|
|
* particular, the current incarnation will only support cameras
|
2001-09-30 03:12:22 +00:00
|
|
|
|
* that directly generate jpeg files.
|
2001-09-10 23:11:17 +00:00
|
|
|
|
*
|
|
|
|
|
* However, having said that, I've already found it to be quite useful
|
|
|
|
|
* even in its current form - one reason is that gphoto2 provides access
|
|
|
|
|
* to the camera via USB which is not supported by the regular DC240
|
|
|
|
|
* backend and is dramatically faster than the serial port.
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
* _S_A_N_E - Scanner Access Now Easy.
|
|
|
|
|
|
|
|
|
|
gphoto2.c
|
|
|
|
|
|
|
|
|
|
03/12/01 - Peter Fales
|
|
|
|
|
|
|
|
|
|
Based on the dc210 driver, (C) 1998 Brian J. Murrell (which is
|
|
|
|
|
based on dc25 driver (C) 1998 by Peter Fales)
|
|
|
|
|
|
|
|
|
|
This file (C) 2001 by Peter Fales
|
|
|
|
|
|
|
|
|
|
This file is part of the SANE package.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
|
|
|
MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
|
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
|
|
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
|
|
|
to produce an executable, this does not by itself cause the
|
|
|
|
|
resulting executable to be covered by the GNU General Public
|
|
|
|
|
License. Your use of that executable is in no way restricted on
|
|
|
|
|
account of linking the SANE library code into it.
|
|
|
|
|
|
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
|
|
|
the executable file might be covered by the GNU General Public
|
|
|
|
|
License.
|
|
|
|
|
|
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
|
|
|
a subsequent release, you agree by submitting the changes that
|
|
|
|
|
those changes may be distributed with this exception intact.
|
|
|
|
|
|
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
|
|
|
whether to permit this exception to apply to your modifications.
|
|
|
|
|
If you do not wish that, delete this exception notice.
|
|
|
|
|
|
|
|
|
|
***************************************************************************
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
This file implements a SANE backend for digital cameras
|
|
|
|
|
supported by the gphoto2 libraries.
|
|
|
|
|
|
|
|
|
|
THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!!
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
(feedback to: peter@fales.com
|
|
|
|
|
|
|
|
|
|
This backend is based somewhat on the dc25 backend included in this
|
|
|
|
|
package by Peter Fales, and the dc210 backend by Brian J. Murrell
|
|
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "sane/config.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include "cdjpeg.h"
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
|
|
|
|
|
#include "sane/sane.h"
|
|
|
|
|
#include "sane/sanei.h"
|
|
|
|
|
#include "sane/saneopts.h"
|
|
|
|
|
|
|
|
|
|
#define BACKEND_NAME gphoto2
|
|
|
|
|
#include "sane/sanei_backend.h"
|
|
|
|
|
|
2002-01-15 02:34:40 +00:00
|
|
|
|
/* PSF 1/12/02 - gphoto2.h does a #include of config.h. We don't have
|
|
|
|
|
* config.h by that name (we call it sane/config.h), so the #undef of
|
|
|
|
|
* HAVE_CONFIG_H will cause it to skip that.
|
|
|
|
|
*/
|
2002-01-13 04:10:23 +00:00
|
|
|
|
#undef HAVE_CONFIG_H
|
2001-09-07 02:40:21 +00:00
|
|
|
|
#include "gphoto2.h"
|
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
#include <gphoto2-camera.h>
|
1994-10-29 05:52:22 +00:00
|
|
|
|
#include <gphoto2-port-log.h>
|
2001-09-13 00:34:57 +00:00
|
|
|
|
|
2002-01-18 03:52:20 +00:00
|
|
|
|
#define CHECK_EXIT(f) {int res = f; if (res < 0) {DBG (0,"ERROR: %s\n", gp_result_as_string (res)); return (SANE_STATUS_INVAL);}}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
#define CHECK_RET(f) {int res = f; if (res < 0) {DBG (0,"ERROR: %s\n", gp_result_as_string (res)); return (SANE_STATUS_INVAL);}}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
#ifndef PATH_MAX
|
|
|
|
|
# define PATH_MAX 1024
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define MAGIC (void *)0xab730324
|
|
|
|
|
#define GPHOTO2_CONFIG_FILE "gphoto2.conf"
|
|
|
|
|
|
|
|
|
|
static SANE_Bool is_open = 0;
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* Options selected by frontend: */
|
|
|
|
|
static SANE_Bool gphoto2_opt_thumbnails; /* Read thumbnails */
|
|
|
|
|
static SANE_Bool gphoto2_opt_snap; /* Take new picture */
|
|
|
|
|
static SANE_Bool gphoto2_opt_lowres; /* Set low resolution */
|
|
|
|
|
static SANE_Bool gphoto2_opt_erase; /* Erase after downloading */
|
|
|
|
|
static SANE_Bool gphoto2_opt_autoinc; /* Increment image number */
|
|
|
|
|
static SANE_Bool dumpinquiry; /* Dump status info */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* Used for jpeg decompression */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static struct jpeg_decompress_struct cinfo;
|
|
|
|
|
static djpeg_dest_ptr dest_mgr = NULL;
|
|
|
|
|
|
|
|
|
|
static SANE_Int highres_height = 960, highres_width = 1280;
|
|
|
|
|
static SANE_Int thumb_height = 120, thumb_width = 160;
|
2001-09-25 00:33:07 +00:00
|
|
|
|
static SANE_String TopFolder; /* Fixed part of path strings */
|
2002-01-19 02:06:40 +00:00
|
|
|
|
static SANE_Int SubDirs = 1; /* Search for Sub directories */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
static GPHOTO2 Cam_data; /* Other camera data */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
static SANE_Range image_range = {
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
static SANE_String *folder_list;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Int current_folder = 0;
|
|
|
|
|
|
|
|
|
|
static SANE_Option_Descriptor sod[] = {
|
|
|
|
|
{
|
|
|
|
|
SANE_NAME_NUM_OPTIONS,
|
|
|
|
|
SANE_TITLE_NUM_OPTIONS,
|
|
|
|
|
SANE_DESC_NUM_OPTIONS,
|
|
|
|
|
SANE_TYPE_INT,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
|
|
|
|
SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_IMAGE_SELECTION 1
|
|
|
|
|
{
|
|
|
|
|
"",
|
|
|
|
|
"Image Selection",
|
|
|
|
|
"Selection of the image to load.",
|
|
|
|
|
SANE_TYPE_GROUP,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_FOLDER 2
|
|
|
|
|
{
|
|
|
|
|
"folder",
|
|
|
|
|
"Folder",
|
|
|
|
|
"Select folder within camera",
|
|
|
|
|
SANE_TYPE_STRING,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
256,
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_STRING_LIST,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_IMAGE_NUMBER 3
|
|
|
|
|
{
|
|
|
|
|
"image",
|
|
|
|
|
"Image Number",
|
|
|
|
|
"Select Image Number to load from camera",
|
|
|
|
|
SANE_TYPE_INT,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
4,
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_RANGE,
|
|
|
|
|
{(SANE_String_Const *) & image_range} /* this is ANSI conformant! */
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_THUMBS 4
|
|
|
|
|
{
|
|
|
|
|
"thumbs",
|
|
|
|
|
"Load Thumbnail",
|
|
|
|
|
"Load the image as thumbnail.",
|
|
|
|
|
SANE_TYPE_BOOL,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_SNAP 5
|
|
|
|
|
{
|
|
|
|
|
"snap",
|
|
|
|
|
"Snap new picture",
|
|
|
|
|
"Take new picture and download it",
|
|
|
|
|
SANE_TYPE_BOOL,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT /* | SANE_CAP_ADVANCED */ ,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_LOWRES 6
|
|
|
|
|
{
|
|
|
|
|
"lowres",
|
|
|
|
|
"Low Resolution",
|
|
|
|
|
"Resolution of new picture or selected image (must be manually specified)",
|
|
|
|
|
SANE_TYPE_BOOL,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
2001-09-18 04:26:13 +00:00
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE /* Until we figure out how to support it */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
/* | SANE_CAP_ADVANCED */ ,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_ERASE 7
|
|
|
|
|
{
|
|
|
|
|
"erase",
|
|
|
|
|
"Erase",
|
|
|
|
|
"Erase the picture after downloading",
|
|
|
|
|
SANE_TYPE_BOOL,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_DEFAULT 8
|
|
|
|
|
{
|
|
|
|
|
"default-enhancements",
|
|
|
|
|
"Defaults",
|
|
|
|
|
"Set default values for enhancement controls.",
|
|
|
|
|
SANE_TYPE_BUTTON,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
0,
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_INIT_GPHOTO2 9
|
|
|
|
|
{
|
|
|
|
|
"camera-init",
|
|
|
|
|
"Re-establish Communications",
|
|
|
|
|
"Re-establish communications with camera (in case of timeout, etc.)",
|
|
|
|
|
SANE_TYPE_BUTTON,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
0,
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
#define GPHOTO2_OPT_AUTOINC 10
|
|
|
|
|
{
|
|
|
|
|
"autoinc",
|
|
|
|
|
"Auto Increment",
|
|
|
|
|
"Increment image number after each scan",
|
|
|
|
|
SANE_TYPE_BOOL,
|
|
|
|
|
SANE_UNIT_NONE,
|
|
|
|
|
sizeof (SANE_Word),
|
|
|
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED,
|
|
|
|
|
SANE_CONSTRAINT_NONE,
|
|
|
|
|
{NULL}
|
|
|
|
|
}
|
|
|
|
|
,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static SANE_Parameters parms = {
|
|
|
|
|
SANE_FRAME_RGB,
|
|
|
|
|
0,
|
|
|
|
|
0, /* Number of bytes returned per scan line: */
|
|
|
|
|
0, /* Number of pixels per scan line. */
|
|
|
|
|
0, /* Number of lines for the current scan. */
|
|
|
|
|
8, /* Number of bits per sample. */
|
|
|
|
|
};
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
|
|
|
|
|
CameraList *dir_list;
|
|
|
|
|
Camera *camera;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-10 23:11:17 +00:00
|
|
|
|
/* Buffer to hold line currently being processed by sane_read */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Byte *linebuffer = NULL;
|
|
|
|
|
static SANE_Int linebuffer_size = 0;
|
|
|
|
|
static SANE_Int linebuffer_index = 0;
|
|
|
|
|
|
2001-09-18 04:26:13 +00:00
|
|
|
|
/* used for setting up commands */
|
2001-09-10 23:11:17 +00:00
|
|
|
|
static SANE_Char cmdbuf[256];
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* Structures used by gphoto2 API */
|
1994-10-29 05:52:22 +00:00
|
|
|
|
static CameraAbilities abilities;
|
2001-09-18 04:26:13 +00:00
|
|
|
|
static CameraFile *data_file;
|
|
|
|
|
static const char *data_ptr;
|
2002-01-18 03:52:20 +00:00
|
|
|
|
static unsigned long data_file_total_size, data_file_current_index;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
static SANE_Int hack_fd;
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
/* Device select/open/close */
|
|
|
|
|
|
|
|
|
|
static SANE_Device dev[] = {
|
|
|
|
|
{
|
|
|
|
|
"0",
|
|
|
|
|
"Gphoto2",
|
|
|
|
|
"Supported",
|
|
|
|
|
"still camera"},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const SANE_Device *devlist[] = {
|
|
|
|
|
dev + 0, 0
|
|
|
|
|
};
|
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
/*
|
|
|
|
|
* debug_func - called for gphoto2 debugging output (if enabled)
|
|
|
|
|
*/
|
2002-01-19 02:06:40 +00:00
|
|
|
|
static void
|
2001-11-12 04:29:14 +00:00
|
|
|
|
debug_func (GPLogLevel level, const char *domain, const char *format,
|
1994-10-29 05:52:22 +00:00
|
|
|
|
va_list args, void UNUSEDARG * data)
|
|
|
|
|
{
|
|
|
|
|
if (level == GP_LOG_ERROR)
|
|
|
|
|
DBG (0, "%s(ERROR): ", domain);
|
|
|
|
|
else
|
|
|
|
|
DBG (0, "%s(%i): ", domain, level);
|
|
|
|
|
sanei_debug_msg (0, DBG_LEVEL, STRINGIFY (BACKEND_NAME), format, args);
|
|
|
|
|
DBG (0, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* init_gphoto2() - Initialize interface to camera using gphoto2 API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Int
|
|
|
|
|
init_gphoto2 (void)
|
|
|
|
|
{
|
2001-11-08 01:14:50 +00:00
|
|
|
|
CameraList *list;
|
1994-10-29 05:52:22 +00:00
|
|
|
|
GPPortInfoList *il;
|
|
|
|
|
GPPortInfo info;
|
|
|
|
|
SANE_Int n, m, port;
|
|
|
|
|
CameraAbilitiesList *al;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2002-01-16 02:15:50 +00:00
|
|
|
|
gp_log (GP_LOG_VERBOSE, "SANE", "Initializing\n");
|
2001-10-16 00:26:58 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (!Cam_data.camera_name)
|
|
|
|
|
{
|
|
|
|
|
DBG (0, "Camera name not specified in config file\n");
|
2002-01-18 03:52:20 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
2001-09-25 00:33:07 +00:00
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
|
2002-01-20 05:31:06 +00:00
|
|
|
|
if (camera)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We get here if re-initializing the camera: either because
|
|
|
|
|
* the user clicked the "re-establish" button, or we need to
|
|
|
|
|
* recalculate the number of photos after taking a picture.
|
|
|
|
|
* We must release the old camera before starting over.
|
|
|
|
|
*/
|
|
|
|
|
CHECK_RET (gp_camera_unref (camera));
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
CHECK_RET (gp_camera_new (&camera));
|
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (gp_abilities_list_new (&al));
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_abilities_list_load (al, NULL));
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (m =
|
|
|
|
|
gp_abilities_list_lookup_model (al,
|
|
|
|
|
(char *) Cam_data.camera_name));
|
|
|
|
|
CHECK_RET (gp_abilities_list_get_abilities (al, m, &abilities));
|
|
|
|
|
CHECK_RET (gp_abilities_list_free (al));
|
|
|
|
|
CHECK_RET (gp_camera_set_abilities (camera, abilities));
|
2001-09-25 00:33:07 +00:00
|
|
|
|
|
|
|
|
|
if (!Cam_data.port)
|
|
|
|
|
{
|
|
|
|
|
DBG (0, "Camera port not specified in config file\n");
|
2002-01-18 03:52:20 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
2001-09-25 00:33:07 +00:00
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
|
|
|
|
|
CHECK_RET (gp_port_info_list_new (&il));
|
|
|
|
|
CHECK_RET (gp_port_info_list_load (il));
|
|
|
|
|
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (strcmp (Cam_data.port, "Browse") != 0)
|
|
|
|
|
{
|
|
|
|
|
port = gp_port_info_list_lookup_path (il, Cam_data.port);
|
|
|
|
|
CHECK_RET (gp_port_info_list_get_info (il, port, &info));
|
|
|
|
|
CHECK_RET (gp_camera_set_port_info (camera, info));
|
|
|
|
|
gp_port_info_list_free (il);
|
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
DBG (4, "init_gphoto2: about to initialize port\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
/*
|
|
|
|
|
* Setting of speed only makes sense for serial ports. gphoto2
|
|
|
|
|
* knows that and will complain if we try to set the speed for
|
|
|
|
|
* ports other than serial ones. Because we are paranoid here and
|
|
|
|
|
* check every single error message returned by gphoto2, we need
|
|
|
|
|
* to make sure that we have a serial port.
|
|
|
|
|
*/
|
|
|
|
|
if (Cam_data.speed && !strncmp (Cam_data.port, "serial:", 7))
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
2001-11-08 01:14:50 +00:00
|
|
|
|
/*
|
|
|
|
|
* Not sure why we need this hack. The API keeps opening/closing
|
|
|
|
|
* the port, and that seems to confuse the camera. Holding
|
|
|
|
|
* the port open seems to fix it.
|
|
|
|
|
*/
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if ((hack_fd = open (Cam_data.port + 7, O_RDONLY)) < 0)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
2001-11-08 01:14:50 +00:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_USLEEP
|
|
|
|
|
usleep (200);
|
|
|
|
|
#else
|
|
|
|
|
sleep (1);
|
|
|
|
|
#endif
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_camera_set_port_speed (camera, Cam_data.speed));
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_init (camera, NULL));
|
2001-09-25 00:33:07 +00:00
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (!(abilities.operations & GP_OPERATION_CAPTURE_IMAGE))
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
2002-01-18 03:52:20 +00:00
|
|
|
|
DBG (20, "Camera does not support image capture\n");
|
|
|
|
|
sod[GPHOTO2_OPT_SNAP].cap |= SANE_CAP_INACTIVE;
|
2001-09-25 00:33:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-20 05:31:06 +00:00
|
|
|
|
if (!(abilities.file_operations & GP_FILE_OPERATION_PREVIEW))
|
2002-01-19 02:06:40 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (20, "Camera does not support image preview\n");
|
|
|
|
|
sod[GPHOTO2_OPT_THUMBS].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(abilities.file_operations & GP_FILE_OPERATION_DELETE))
|
|
|
|
|
{
|
|
|
|
|
DBG (20, "Camera does not support image deletion\n");
|
|
|
|
|
sod[GPHOTO2_OPT_ERASE].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
for (n = 0; abilities.speed[n]; n++)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.speed[n] == Cam_data.speed)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.speed[n] == 0)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (0,
|
|
|
|
|
"%s: error: %d is not a valid speed for this camers. Use \"gphoto2 --camera \"%s\" --abilities\" for list.\n",
|
|
|
|
|
"init_gphoto2", Cam_data.camera_name, Cam_data.speed);
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
DBG (4, "init_gphoto2: about to get folders\n");
|
|
|
|
|
|
|
|
|
|
CHECK_RET (gp_list_new (&list));
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_folder_list_folders (camera, TopFolder, list, NULL));
|
2001-09-18 04:26:13 +00:00
|
|
|
|
n = gp_list_count (list);
|
|
|
|
|
if (n < 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, "Unable to get file list\n");
|
|
|
|
|
return SANE_STATUS_INVAL;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* close_gphoto2() - Shutdown camera interface
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static void
|
2001-09-25 00:33:07 +00:00
|
|
|
|
close_gphoto2 (void)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Put the camera back to 9600 baud
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (gp_camera_unref (camera))
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (1, "close_gphoto2: error: could not close device\n");
|
|
|
|
|
}
|
2001-11-08 01:14:50 +00:00
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
close (hack_fd);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* get_info() - Get overall information about camera: folder names,
|
|
|
|
|
* number of pictures, etc.
|
|
|
|
|
*/
|
|
|
|
|
SANE_Int
|
2001-09-07 02:40:21 +00:00
|
|
|
|
get_info (void)
|
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
SANE_String_Const val;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Int n;
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.pic_taken == 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
image_range.min = 0;
|
|
|
|
|
image_range.max = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE;
|
|
|
|
|
image_range.min = 1;
|
2001-09-13 00:34:57 +00:00
|
|
|
|
image_range.max = Cam_data.pic_taken;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
2002-01-18 03:52:20 +00:00
|
|
|
|
{
|
|
|
|
|
n = read_dir (TopFolder, 0);
|
|
|
|
|
}
|
2002-01-19 02:06:40 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2002-01-18 03:52:20 +00:00
|
|
|
|
n = 1;
|
2002-01-19 02:06:40 +00:00
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
/* If we've already got a folder_list, free it up before starting
|
|
|
|
|
* the new one
|
|
|
|
|
*/
|
|
|
|
|
if (folder_list != NULL)
|
|
|
|
|
{
|
|
|
|
|
int tmp;
|
|
|
|
|
for (tmp = 0; folder_list[tmp]; tmp++)
|
2002-01-19 02:06:40 +00:00
|
|
|
|
{
|
2001-09-07 02:40:21 +00:00
|
|
|
|
free (folder_list[tmp]);
|
|
|
|
|
}
|
|
|
|
|
free (folder_list);
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-18 04:26:13 +00:00
|
|
|
|
folder_list =
|
2001-11-08 01:14:50 +00:00
|
|
|
|
(SANE_String *) malloc ((n + 1) * sizeof (SANE_String_Const *));
|
2002-01-18 03:52:20 +00:00
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-18 03:52:20 +00:00
|
|
|
|
for (n = 0; n < gp_list_count (dir_list); n++)
|
2002-01-19 02:06:40 +00:00
|
|
|
|
{
|
|
|
|
|
gp_list_get_name (dir_list, n, &val);
|
|
|
|
|
folder_list[n] = strdup (val);
|
|
|
|
|
if (strchr ((const char *) folder_list[n], ' '))
|
2002-01-18 03:52:20 +00:00
|
|
|
|
{
|
|
|
|
|
*strchr ((const char *) folder_list[n], ' ') = '\0';
|
|
|
|
|
}
|
2002-01-19 02:06:40 +00:00
|
|
|
|
}
|
2002-01-18 03:52:20 +00:00
|
|
|
|
if (n == 0)
|
2002-01-19 02:06:40 +00:00
|
|
|
|
{
|
|
|
|
|
folder_list[n++] = (SANE_String) strdup ("");
|
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2002-01-19 02:06:40 +00:00
|
|
|
|
else
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-19 02:06:40 +00:00
|
|
|
|
n = 0;
|
|
|
|
|
folder_list[n++] = "N/A";
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
folder_list[n] = NULL;
|
|
|
|
|
sod[GPHOTO2_OPT_FOLDER].constraint.string_list =
|
|
|
|
|
(SANE_String_Const *) folder_list;
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.pic_taken = 0;
|
2001-09-18 04:26:13 +00:00
|
|
|
|
Cam_data.pic_left = 1; /* Just a guess! */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
return SANE_STATUS_GOOD;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* erase() - erase file from camera corresponding to
|
|
|
|
|
* current picture number. Does not update any of the other
|
|
|
|
|
* backend data structures.
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Int
|
|
|
|
|
erase (void)
|
|
|
|
|
{
|
2001-09-18 04:26:13 +00:00
|
|
|
|
SANE_String_Const filename;
|
2001-09-10 23:11:17 +00:00
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
|
|
|
|
{
|
|
|
|
|
sprintf (cmdbuf, "%s/%s", (char *) TopFolder,
|
|
|
|
|
(const char *) folder_list[current_folder]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strcpy (cmdbuf, TopFolder);
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_list_get_name
|
|
|
|
|
(dir_list, Cam_data.current_picture_number - 1, &filename));
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_file_delete (camera, cmdbuf, filename, NULL));
|
2001-09-10 23:11:17 +00:00
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* change_res() - FIXME: Would like to set resolution, but haven't figure
|
|
|
|
|
* out how to control that yet.
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Int
|
|
|
|
|
change_res (SANE_Byte res)
|
|
|
|
|
{
|
|
|
|
|
|
2001-09-10 23:11:17 +00:00
|
|
|
|
return (res - res);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_init() - Initialization function from SANE API. Initialize some
|
|
|
|
|
* data structures, verify that all the necessary config information
|
|
|
|
|
* is present, and initialize gphoto2
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_init (SANE_Int * version_code, SANE_Auth_Callback UNUSEDARG authorize)
|
|
|
|
|
{
|
2001-09-25 00:33:07 +00:00
|
|
|
|
SANE_Int n, entries;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Char f[] = "sane_init";
|
|
|
|
|
SANE_Char dev_name[PATH_MAX], *p;
|
|
|
|
|
SANE_Char buf[256];
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CameraAbilitiesList *al;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
size_t len;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
|
|
DBG_INIT ();
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
DBG (1,
|
|
|
|
|
"GPHOTO2 Backend $Id$\n");
|
2001-11-13 01:41:55 +00:00
|
|
|
|
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (getenv ("GP_DEBUG"))
|
|
|
|
|
{
|
1994-10-29 05:52:22 +00:00
|
|
|
|
gp_log_add_func (atoi (getenv ("GP_DEBUG")), debug_func, NULL);
|
2001-09-18 04:26:13 +00:00
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
if (version_code)
|
|
|
|
|
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
|
|
|
|
|
|
|
|
|
|
fp = sanei_config_open (GPHOTO2_CONFIG_FILE);
|
|
|
|
|
|
|
|
|
|
if (!fp)
|
|
|
|
|
{
|
|
|
|
|
/* default to /dev/whatever instead of insisting on config file */
|
2001-09-10 23:11:17 +00:00
|
|
|
|
DBG (1, "warning: %s: missing config file '%s'\n", f,
|
|
|
|
|
GPHOTO2_CONFIG_FILE);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (sanei_config_read (dev_name, sizeof (dev_name), fp))
|
|
|
|
|
{
|
|
|
|
|
dev_name[sizeof (dev_name) - 1] = '\0';
|
|
|
|
|
DBG (20, "%s: config- %s\n", f, dev_name);
|
|
|
|
|
|
|
|
|
|
if (dev_name[0] == '#')
|
|
|
|
|
continue; /* ignore line comments */
|
|
|
|
|
len = strlen (dev_name);
|
|
|
|
|
if (!len)
|
|
|
|
|
continue; /* ignore empty lines */
|
|
|
|
|
if (strncmp (dev_name, "port=", 5) == 0)
|
|
|
|
|
{
|
1994-10-29 05:52:22 +00:00
|
|
|
|
GPPortInfoList *list;
|
|
|
|
|
GPPortInfo info;
|
|
|
|
|
int result;
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
p = dev_name + 5;
|
|
|
|
|
if (p)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
Cam_data.port = strdup (p);
|
|
|
|
|
DBG (20, "Config file port=%s\n", Cam_data.port);
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* Validate port */
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (gp_port_info_list_new (&list));
|
|
|
|
|
result = gp_port_info_list_load (list);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
{
|
|
|
|
|
gp_port_info_list_free (list);
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
entries = gp_port_info_list_count (list);
|
|
|
|
|
if (entries < 0)
|
|
|
|
|
{
|
|
|
|
|
gp_port_info_list_free (list);
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
2001-09-10 23:11:17 +00:00
|
|
|
|
for (n = 0; n < entries; n++)
|
|
|
|
|
{
|
1994-10-29 05:52:22 +00:00
|
|
|
|
result = gp_port_info_list_get_info (list, n, &info);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
{
|
|
|
|
|
gp_port_info_list_free (list);
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (strcmp (Cam_data.port, info.path) == 0)
|
2001-09-10 23:11:17 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (n == entries)
|
|
|
|
|
{
|
|
|
|
|
DBG (0,
|
|
|
|
|
"%s: error: %s is not a valid gphoto2 port. Use \"gphoto2 --list-ports\" for list.\n",
|
2001-09-25 00:33:07 +00:00
|
|
|
|
"init_gphoto2", Cam_data.port);
|
2002-01-18 03:52:20 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
2001-09-10 23:11:17 +00:00
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
else if (strncmp (dev_name, "camera=", 7) == 0)
|
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.camera_name = strdup (dev_name + 7);
|
|
|
|
|
DBG (20, "Config file camera=%s\n", Cam_data.camera_name);
|
|
|
|
|
sprintf (buf, "Image selection - %s", Cam_data.camera_name);
|
2001-09-10 23:11:17 +00:00
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (gp_abilities_list_new (&al));
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_abilities_list_load (al, NULL));
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (entries = gp_abilities_list_count (al));
|
|
|
|
|
|
2001-09-10 23:11:17 +00:00
|
|
|
|
for (n = 0; n < entries; n++)
|
|
|
|
|
{
|
1994-10-29 05:52:22 +00:00
|
|
|
|
CHECK_RET (gp_abilities_list_get_abilities
|
|
|
|
|
(al, n, &abilities));
|
|
|
|
|
if (strcmp (Cam_data.camera_name, abilities.model) == 0)
|
2001-09-10 23:11:17 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (n == entries)
|
|
|
|
|
{
|
|
|
|
|
DBG (0,
|
|
|
|
|
"%s: error: %s is not a valid camera type. Use \"gphoto2 --list-cameras\" for list.\n",
|
2001-09-13 00:34:57 +00:00
|
|
|
|
f, Cam_data.camera_name);
|
2001-09-10 23:11:17 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-15 04:44:35 +00:00
|
|
|
|
/* Special case: Force port to special value for the
|
|
|
|
|
* "Directory Browse" camera - overriding anything in
|
|
|
|
|
* the config file - or more likely when not specified
|
|
|
|
|
* in the config file.
|
|
|
|
|
*/
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (strcmp (Cam_data.camera_name, "Directory Browse") == 0)
|
|
|
|
|
{
|
|
|
|
|
Cam_data.port = "Browse";
|
|
|
|
|
}
|
2002-01-15 04:44:35 +00:00
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_SELECTION].title = strdup (buf);
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp (dev_name, "dumpinquiry") == 0)
|
|
|
|
|
{
|
|
|
|
|
dumpinquiry = SANE_TRUE;
|
|
|
|
|
}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
else if (strncmp (dev_name, "speed=", 6) == 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-25 00:33:07 +00:00
|
|
|
|
sscanf (&dev_name[6], "%d", &Cam_data.speed);
|
|
|
|
|
|
|
|
|
|
DBG (20, "Config file speed=%u\n", Cam_data.speed);
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
else if (strncmp (dev_name, "resolution=", 11) == 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-25 00:33:07 +00:00
|
|
|
|
sscanf (&dev_name[11], "%dx%d", &highres_width,
|
|
|
|
|
&highres_height);
|
|
|
|
|
DBG (20, "Config file resolution=%ux%u\n", highres_width,
|
|
|
|
|
highres_height);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
else if (strncmp (dev_name, "thumb_resolution=", 17) == 0)
|
|
|
|
|
{
|
|
|
|
|
sscanf (&dev_name[17], "%dx%d", &thumb_width, &thumb_height);
|
|
|
|
|
DBG (20, "Config file thumb_resolution=%ux%u\n", thumb_width,
|
|
|
|
|
thumb_height);
|
|
|
|
|
}
|
|
|
|
|
else if (strncmp (dev_name, "topfolder=", 10) == 0)
|
|
|
|
|
{
|
2002-01-18 03:52:20 +00:00
|
|
|
|
/* Make sure TopFolder is non-null */
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (strlen (dev_name) > 10)
|
|
|
|
|
{
|
|
|
|
|
TopFolder = strdup (&dev_name[10]);
|
|
|
|
|
DBG (20, "Config file topfolder=%s\n", TopFolder);
|
|
|
|
|
}
|
2002-01-18 03:52:20 +00:00
|
|
|
|
}
|
|
|
|
|
else if (strncmp (dev_name, "subdirs=", 8) == 0)
|
|
|
|
|
{
|
2002-01-19 02:06:40 +00:00
|
|
|
|
SubDirs = atoi (&dev_name[8]);
|
|
|
|
|
if (SubDirs == 0)
|
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_FOLDER].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
DBG (20, "Config file subdirs=%d\n", SubDirs);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fclose (fp);
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
dev[0].name = strdup (Cam_data.port);
|
2001-11-08 01:14:50 +00:00
|
|
|
|
|
|
|
|
|
DBG (3, "sane_init: about to init_gphoto2\n");
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (init_gphoto2 () != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
DBG (3, "sane_init: about to get_info\n");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (get_info () != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (1, "error: could not get info\n");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
close_gphoto2 ();
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* load the current images array */
|
2001-11-08 01:14:50 +00:00
|
|
|
|
DBG (3, "sane_init: about to get_pictures_info\n");
|
2001-09-07 02:40:21 +00:00
|
|
|
|
get_pictures_info ();
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.pic_taken == 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.current_picture_number = 0;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
parms.bytes_per_line = 0;
|
|
|
|
|
parms.pixels_per_line = 0;
|
|
|
|
|
parms.lines = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.current_picture_number = 1;
|
2001-09-10 23:11:17 +00:00
|
|
|
|
/* OLD:
|
2001-09-13 00:34:57 +00:00
|
|
|
|
set_res (Cam_data.Pictures[Cam_data.current_picture_number - 1].low_res);
|
2001-09-10 23:11:17 +00:00
|
|
|
|
*/
|
2001-09-18 04:26:13 +00:00
|
|
|
|
set_res (gphoto2_opt_lowres);
|
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
if (dumpinquiry)
|
|
|
|
|
{
|
2001-09-25 00:33:07 +00:00
|
|
|
|
SANE_Int x = 0;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
DBG (0, "\nCamera information:\n~~~~~~~~~~~~~~~~~\n\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
DBG (0, "Model : %s\n", abilities.model);
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, "Pictures : %d\n", Cam_data.pic_taken);
|
|
|
|
|
DBG (0, "Serial port support : %s\n",
|
1994-10-29 06:03:05 +00:00
|
|
|
|
(abilities.port & GP_PORT_SERIAL) ? "yes" : "no");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, "USB support : %s\n",
|
1994-10-29 06:03:05 +00:00
|
|
|
|
(abilities.port & GP_PORT_USB) ? "yes" : "no");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.speed[0] != 0)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (0, "Transfer speeds supported :\n");
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
DBG (0, " : %i\n",
|
1994-10-29 05:52:22 +00:00
|
|
|
|
abilities.speed[x]);
|
2001-09-25 00:33:07 +00:00
|
|
|
|
x++;
|
|
|
|
|
}
|
1994-10-29 05:52:22 +00:00
|
|
|
|
while (abilities.speed[x] != 0);
|
2001-09-25 00:33:07 +00:00
|
|
|
|
}
|
|
|
|
|
DBG (0, "Capture choices :\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.operations & GP_OPERATION_CAPTURE_IMAGE)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, " : Image\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.operations & GP_OPERATION_CAPTURE_VIDEO)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, " : Video\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.operations & GP_OPERATION_CAPTURE_AUDIO)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, " : Audio\n");
|
1994-10-29 05:52:22 +00:00
|
|
|
|
if (abilities.operations & GP_OPERATION_CAPTURE_PREVIEW)
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (0, " : Preview\n");
|
|
|
|
|
DBG (0, "Configuration support : %s\n",
|
1994-10-29 05:52:22 +00:00
|
|
|
|
abilities.operations & GP_OPERATION_CONFIG ? "yes" : "no");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
|
|
|
|
|
DBG (0, "Delete files on camera support : %s\n",
|
1994-10-29 05:52:22 +00:00
|
|
|
|
abilities.
|
2001-09-25 00:33:07 +00:00
|
|
|
|
file_operations & GP_FILE_OPERATION_DELETE ? "yes" : "no");
|
|
|
|
|
DBG (0, "File preview (thumbnail) support : %s\n",
|
1994-10-29 05:52:22 +00:00
|
|
|
|
abilities.
|
2001-09-25 00:33:07 +00:00
|
|
|
|
file_operations & GP_FILE_OPERATION_PREVIEW ? "yes" : "no");
|
|
|
|
|
DBG (0, "File upload support : %s\n",
|
1994-10-29 05:52:22 +00:00
|
|
|
|
abilities.
|
2001-09-25 00:33:07 +00:00
|
|
|
|
folder_operations & GP_FOLDER_OPERATION_PUT_FILE ? "yes" : "no");
|
|
|
|
|
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_exit() - Required by SANE API, but otherwise not used
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
void
|
|
|
|
|
sane_exit (void)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_get_devices() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_get_devices (const SANE_Device *** device_list, SANE_Bool
|
|
|
|
|
UNUSEDARG local_only)
|
|
|
|
|
{
|
|
|
|
|
DBG (127, "sane_get_devices called\n");
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
*device_list = devlist;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_open() - From SANE API
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|
|
|
|
{
|
|
|
|
|
SANE_Int i;
|
|
|
|
|
|
|
|
|
|
DBG (127, "sane_open for device %s\n", devicename);
|
|
|
|
|
if (!devicename[0])
|
|
|
|
|
{
|
|
|
|
|
i = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < NELEMS (dev); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (devicename, dev[i].name) == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i >= NELEMS (dev))
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_open)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_open = 1;
|
|
|
|
|
*handle = MAGIC;
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
DBG (4, "sane_open: pictures taken=%d\n", Cam_data.pic_taken);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_close() - From SANE API
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
void
|
|
|
|
|
sane_close (SANE_Handle handle)
|
|
|
|
|
{
|
|
|
|
|
DBG (127, "sane_close called\n");
|
|
|
|
|
if (handle == MAGIC)
|
|
|
|
|
is_open = 0;
|
|
|
|
|
|
|
|
|
|
DBG (127, "sane_close returning\n");
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_get_option_descriptor() - From SANE API
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
const SANE_Option_Descriptor *
|
|
|
|
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
|
|
|
|
{
|
|
|
|
|
if (handle != MAGIC || !is_open)
|
|
|
|
|
return NULL; /* wrong device */
|
|
|
|
|
if (option < 0 || option >= NELEMS (sod))
|
|
|
|
|
return NULL;
|
|
|
|
|
return &sod[option];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SANE_Int myinfo = 0;
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_control_option() - From SANE API
|
|
|
|
|
*/
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_control_option (SANE_Handle handle, SANE_Int option,
|
|
|
|
|
SANE_Action action, void *value, SANE_Int * info)
|
|
|
|
|
{
|
|
|
|
|
SANE_Status status;
|
|
|
|
|
|
|
|
|
|
DBG (127, "control_option(handle=%p,opt=%s,act=%s,val=%p,info=%p)\n",
|
|
|
|
|
handle, sod[option].title,
|
|
|
|
|
(action ==
|
|
|
|
|
SANE_ACTION_SET_VALUE ? "SET" : (action ==
|
|
|
|
|
SANE_ACTION_GET_VALUE ? "GET" :
|
|
|
|
|
"SETAUTO")), value, info);
|
|
|
|
|
|
|
|
|
|
if (handle != MAGIC || !is_open)
|
|
|
|
|
return SANE_STATUS_INVAL; /* Unknown handle ... */
|
|
|
|
|
|
|
|
|
|
if (option < 0 || option >= NELEMS (sod))
|
|
|
|
|
return SANE_STATUS_INVAL; /* Unknown option ... */
|
|
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
|
{
|
|
|
|
|
case SANE_ACTION_SET_VALUE:
|
|
|
|
|
status = sanei_constrain_value (sod + option, value, &myinfo);
|
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
DBG (2, "Constraint error in control_option\n");
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (option)
|
|
|
|
|
{
|
|
|
|
|
case GPHOTO2_OPT_IMAGE_NUMBER:
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (*(SANE_Word *) value <= Cam_data.pic_taken)
|
|
|
|
|
Cam_data.current_picture_number = *(SANE_Word *) value;
|
|
|
|
|
else
|
|
|
|
|
Cam_data.current_picture_number = Cam_data.pic_taken;
|
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|
|
|
|
|
|
|
|
|
/* get the image's resolution, unless the camera has no
|
|
|
|
|
* pictures yet
|
|
|
|
|
*/
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.pic_taken != 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-10 23:11:17 +00:00
|
|
|
|
/* OLD:
|
2001-09-13 00:34:57 +00:00
|
|
|
|
set_res (Cam_data.
|
|
|
|
|
Pictures[Cam_data.current_picture_number - 1].low_res);
|
2001-09-10 23:11:17 +00:00
|
|
|
|
*/
|
2001-09-18 04:26:13 +00:00
|
|
|
|
set_res (gphoto2_opt_lowres);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_THUMBS:
|
|
|
|
|
gphoto2_opt_thumbnails = !!*(SANE_Word *) value;
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.pic_taken != 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-10 23:11:17 +00:00
|
|
|
|
/* OLD:
|
2001-09-13 00:34:57 +00:00
|
|
|
|
set_res (Cam_data.
|
|
|
|
|
Pictures[Cam_data.current_picture_number - 1].low_res);
|
2001-09-10 23:11:17 +00:00
|
|
|
|
*/
|
2001-09-18 04:26:13 +00:00
|
|
|
|
set_res (gphoto2_opt_lowres);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_SNAP:
|
|
|
|
|
gphoto2_opt_snap = !!*(SANE_Word *) value;
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
|
|
|
|
|
/* if we are snapping a new one */
|
|
|
|
|
if (gphoto2_opt_snap)
|
|
|
|
|
{
|
|
|
|
|
/* activate the resolution setting */
|
|
|
|
|
sod[GPHOTO2_OPT_LOWRES].cap &= ~SANE_CAP_INACTIVE;
|
|
|
|
|
/* and de-activate the image number selector */
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* deactivate the resolution setting */
|
2001-09-25 00:33:07 +00:00
|
|
|
|
sod[GPHOTO2_OPT_LOWRES].cap |= SANE_CAP_INACTIVE;
|
2001-09-10 23:11:17 +00:00
|
|
|
|
/* and activate the image number selector, if there are
|
|
|
|
|
* pictures available */
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.current_picture_number)
|
2001-09-10 23:11:17 +00:00
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
/* set params according to resolution settings */
|
|
|
|
|
set_res (gphoto2_opt_lowres);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_LOWRES:
|
|
|
|
|
gphoto2_opt_lowres = !!*(SANE_Word *) value;
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* FIXME - change the number of pictures left depending on resolution
|
2001-09-07 02:40:21 +00:00
|
|
|
|
perhaps just call get_info again?
|
|
|
|
|
*/
|
|
|
|
|
set_res (gphoto2_opt_lowres);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_ERASE:
|
|
|
|
|
gphoto2_opt_erase = !!*(SANE_Word *) value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_AUTOINC:
|
|
|
|
|
gphoto2_opt_autoinc = !!*(SANE_Word *) value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_FOLDER:
|
|
|
|
|
printf ("FIXME set folder not implemented yet\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_DEFAULT:
|
|
|
|
|
gphoto2_opt_thumbnails = 0;
|
|
|
|
|
gphoto2_opt_snap = 0;
|
|
|
|
|
|
|
|
|
|
/* deactivate the resolution setting */
|
2001-09-25 00:33:07 +00:00
|
|
|
|
sod[GPHOTO2_OPT_LOWRES].cap |= SANE_CAP_INACTIVE;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
/* and activate the image number selector */
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE;
|
|
|
|
|
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
DBG (1, "FIXME: Set all defaults here!\n");
|
2001-09-07 02:40:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_INIT_GPHOTO2:
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (init_gphoto2 () != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (get_info () != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (1, "error: could not get info\n");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
close_gphoto2 ();
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* load the current images array */
|
|
|
|
|
get_pictures_info ();
|
|
|
|
|
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SANE_ACTION_GET_VALUE:
|
|
|
|
|
switch (option)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
*(SANE_Word *) value = NELEMS (sod);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_IMAGE_NUMBER:
|
2001-09-13 00:34:57 +00:00
|
|
|
|
*(SANE_Word *) value = Cam_data.current_picture_number;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_THUMBS:
|
|
|
|
|
*(SANE_Word *) value = gphoto2_opt_thumbnails;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_SNAP:
|
|
|
|
|
*(SANE_Word *) value = gphoto2_opt_snap;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_LOWRES:
|
|
|
|
|
*(SANE_Word *) value = gphoto2_opt_lowres;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_ERASE:
|
|
|
|
|
*(SANE_Word *) value = gphoto2_opt_erase;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_AUTOINC:
|
|
|
|
|
*(SANE_Word *) value = gphoto2_opt_autoinc;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPHOTO2_OPT_FOLDER:
|
|
|
|
|
if (folder_list == NULL)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
strncpy ((char *) value, (const char *) folder_list[current_folder],
|
|
|
|
|
256);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SANE_ACTION_SET_AUTO:
|
|
|
|
|
switch (option)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
return SANE_STATUS_UNSUPPORTED; /* We are DUMB */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info)
|
|
|
|
|
{
|
|
|
|
|
*info = myinfo;
|
|
|
|
|
myinfo = 0;
|
|
|
|
|
}
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_get_parameters() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
|
|
|
|
|
{
|
|
|
|
|
SANE_Int rc = SANE_STATUS_GOOD;
|
|
|
|
|
|
|
|
|
|
DBG (127, "sane_get_params called, wid=%d,height=%d\n",
|
|
|
|
|
parms.pixels_per_line, parms.lines);
|
|
|
|
|
|
|
|
|
|
if (handle != MAGIC || !is_open)
|
|
|
|
|
rc = SANE_STATUS_INVAL; /* Unknown handle ... */
|
|
|
|
|
|
|
|
|
|
parms.last_frame = SANE_TRUE; /* Have no idea what this does */
|
|
|
|
|
*params = parms;
|
|
|
|
|
DBG (127, "sane_get_params return %d\n", rc);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
struct jpeg_source_mgr pub;
|
|
|
|
|
JOCTET *buffer;
|
|
|
|
|
}
|
|
|
|
|
my_source_mgr;
|
|
|
|
|
typedef my_source_mgr *my_src_ptr;
|
|
|
|
|
|
|
|
|
|
METHODDEF (void)
|
|
|
|
|
jpeg_init_source (j_decompress_ptr UNUSEDARG cinfo)
|
|
|
|
|
{
|
|
|
|
|
/* nothing to do */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
METHODDEF (boolean) jpeg_fill_input_buffer (j_decompress_ptr cinfo)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
my_src_ptr src = (my_src_ptr) cinfo->src;
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
if (data_file_current_index + 512 > data_file_total_size)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-30 03:12:22 +00:00
|
|
|
|
n = data_file_total_size - data_file_current_index;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
n = 512;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
memcpy (src->buffer, data_ptr + data_file_current_index, n);
|
|
|
|
|
data_file_current_index += n;
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-07 02:40:21 +00:00
|
|
|
|
src->pub.next_input_byte = src->buffer;
|
|
|
|
|
src->pub.bytes_in_buffer = n;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
METHODDEF (void) jpeg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
my_src_ptr src = (my_src_ptr) cinfo->src;
|
|
|
|
|
|
|
|
|
|
if (num_bytes > 0)
|
|
|
|
|
{
|
|
|
|
|
while (num_bytes > (long) src->pub.bytes_in_buffer)
|
|
|
|
|
{
|
|
|
|
|
num_bytes -= (long) src->pub.bytes_in_buffer;
|
|
|
|
|
(void) jpeg_fill_input_buffer (cinfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
src->pub.next_input_byte += (size_t) num_bytes;
|
|
|
|
|
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
METHODDEF (void)
|
|
|
|
|
jpeg_term_source (j_decompress_ptr UNUSEDARG cinfo)
|
|
|
|
|
{
|
|
|
|
|
/* no work necessary here */
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_start() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_start (SANE_Handle handle)
|
|
|
|
|
{
|
2001-09-18 04:26:13 +00:00
|
|
|
|
SANE_String_Const filename, mime_type;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
DBG (127, "sane_start called\n");
|
|
|
|
|
if (handle != MAGIC || !is_open ||
|
2001-09-18 04:26:13 +00:00
|
|
|
|
(Cam_data.current_picture_number == 0
|
|
|
|
|
&& gphoto2_opt_snap == SANE_FALSE))
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL; /* Unknown handle ... */
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.scanning)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_EOF;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This shouldn't normally happen, but we allow it as a special case
|
|
|
|
|
* when batch/autoinc are in effect. The first illegal picture number
|
|
|
|
|
* terminates the scan
|
|
|
|
|
*/
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.current_picture_number > Cam_data.pic_taken)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gphoto2_opt_snap)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Don't allow picture unless there is room in the
|
|
|
|
|
* camera.
|
|
|
|
|
*/
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.pic_left == 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (3, "No room to store new picture\n");
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (snap_pic () == SANE_STATUS_INVAL)
|
|
|
|
|
{
|
|
|
|
|
DBG (1, "Failed to snap new picture\n");
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-08 01:14:50 +00:00
|
|
|
|
DBG (4, "sane_start: about to get file\n");
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_file_new (&data_file));
|
2001-11-08 01:14:50 +00:00
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
2002-01-18 03:52:20 +00:00
|
|
|
|
{
|
|
|
|
|
sprintf (cmdbuf, "%s/%s", (char *) TopFolder,
|
2002-01-19 02:06:40 +00:00
|
|
|
|
(const char *) folder_list[current_folder]);
|
2002-01-18 03:52:20 +00:00
|
|
|
|
}
|
2002-01-19 02:06:40 +00:00
|
|
|
|
else
|
2002-01-18 03:52:20 +00:00
|
|
|
|
{
|
2002-01-19 02:06:40 +00:00
|
|
|
|
strcpy (cmdbuf, TopFolder);
|
2002-01-18 03:52:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_list_get_name
|
|
|
|
|
(dir_list, Cam_data.current_picture_number - 1, &filename));
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_camera_file_get (camera, cmdbuf, filename,
|
|
|
|
|
gphoto2_opt_thumbnails ? GP_FILE_TYPE_PREVIEW
|
2002-01-13 04:10:23 +00:00
|
|
|
|
: GP_FILE_TYPE_NORMAL, data_file, NULL));
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
CHECK_RET (gp_file_get_mime_type (data_file, &mime_type));
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (strcmp (GP_MIME_JPEG, mime_type) != 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-18 04:26:13 +00:00
|
|
|
|
DBG (0, "FIXME - Only jpeg files currently supported\n");
|
2002-01-18 03:52:20 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
CHECK_RET (gp_file_get_data_and_size
|
|
|
|
|
(data_file, &data_ptr, &data_file_total_size));
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
converter_init ();
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2002-01-15 04:44:35 +00:00
|
|
|
|
/* Check if a linebuffer has been allocated. If we had one
|
|
|
|
|
* previously, free it up and allocate one for (possibly) new
|
|
|
|
|
* size. parms.bytes_per_line is set by converter_init()
|
2001-09-07 02:40:21 +00:00
|
|
|
|
*/
|
|
|
|
|
if (linebuffer == NULL)
|
|
|
|
|
{
|
2002-01-15 04:44:35 +00:00
|
|
|
|
linebuffer = malloc (parms.bytes_per_line);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2002-01-19 02:06:40 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free (linebuffer);
|
2002-01-15 04:44:35 +00:00
|
|
|
|
linebuffer = malloc (parms.bytes_per_line);
|
2002-01-19 02:06:40 +00:00
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
if (linebuffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.scanning = SANE_TRUE; /* don't overlap scan requests */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_read() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data,
|
|
|
|
|
SANE_Int max_length, SANE_Int * length)
|
|
|
|
|
{
|
|
|
|
|
/* If there is anything in the buffer, satisfy the read from there */
|
|
|
|
|
if (linebuffer_size && linebuffer_index < linebuffer_size)
|
|
|
|
|
{
|
|
|
|
|
*length = linebuffer_size - linebuffer_index;
|
|
|
|
|
|
|
|
|
|
if (*length > max_length)
|
|
|
|
|
{
|
|
|
|
|
*length = max_length;
|
|
|
|
|
}
|
|
|
|
|
memcpy (data, linebuffer + linebuffer_index, *length);
|
|
|
|
|
linebuffer_index += *length;
|
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
if (converter_scan_complete ())
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-15 04:04:38 +00:00
|
|
|
|
SANE_Status retval;
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
*length = 0;
|
2002-01-15 04:04:38 +00:00
|
|
|
|
retval = converter_do_scan_complete_cleanup ();
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
if (retval != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-30 03:12:22 +00:00
|
|
|
|
return retval;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
*length = converter_fill_buffer ();
|
2001-09-07 02:40:21 +00:00
|
|
|
|
linebuffer_size = *length;
|
|
|
|
|
linebuffer_index = 0;
|
|
|
|
|
|
|
|
|
|
if (*length > max_length)
|
|
|
|
|
{
|
|
|
|
|
*length = max_length;
|
|
|
|
|
}
|
|
|
|
|
memcpy (data, linebuffer + linebuffer_index, *length);
|
|
|
|
|
linebuffer_index += *length;
|
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_cancel() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
void
|
|
|
|
|
sane_cancel (SANE_Handle UNUSEDARG handle)
|
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.scanning)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.scanning = SANE_FALSE; /* done with scan */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
DBG (4, "sane_cancel: not scanning - nothing to do\n");
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_set_io_mode() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_set_io_mode (SANE_Handle UNUSEDARG handle, SANE_Bool
|
|
|
|
|
UNUSEDARG non_blocking)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* sane_get_select_fd() - From SANE API
|
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
SANE_Status
|
|
|
|
|
sane_get_select_fd (SANE_Handle UNUSEDARG handle, SANE_Int * UNUSEDARG fd)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* get_pictures_info - load information about all pictures currently in
|
|
|
|
|
* camera: Mainly the mapping of picture number
|
2001-09-30 03:12:22 +00:00
|
|
|
|
* to picture name. We'ld like to get other
|
|
|
|
|
* information such as image size, but the API
|
|
|
|
|
* doesn't provide any support for that.
|
2001-09-07 02:40:21 +00:00
|
|
|
|
*/
|
|
|
|
|
static PictureInfo *
|
|
|
|
|
get_pictures_info (void)
|
|
|
|
|
{
|
|
|
|
|
SANE_Char f[] = "get_pictures_info";
|
|
|
|
|
SANE_Char path[256];
|
|
|
|
|
SANE_Int num_pictures;
|
|
|
|
|
SANE_Int p;
|
|
|
|
|
PictureInfo *pics;
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if (Cam_data.Pictures)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-13 00:34:57 +00:00
|
|
|
|
free (Cam_data.Pictures);
|
|
|
|
|
Cam_data.Pictures = NULL;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcpy (path, TopFolder);
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-18 03:52:20 +00:00
|
|
|
|
if (folder_list[current_folder] != NULL)
|
2002-01-19 02:06:40 +00:00
|
|
|
|
{
|
|
|
|
|
strcat (path, "/");
|
|
|
|
|
strcat (path, (const char *) folder_list[current_folder]);
|
|
|
|
|
}
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
num_pictures = read_dir (path, 1);
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.pic_taken = num_pictures;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
if (num_pictures > 0)
|
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE;
|
|
|
|
|
image_range.min = 1;
|
|
|
|
|
image_range.max = num_pictures;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
if ((pics = (PictureInfo *) malloc (Cam_data.pic_taken *
|
2001-09-07 02:40:21 +00:00
|
|
|
|
sizeof (PictureInfo))) == NULL)
|
|
|
|
|
{
|
|
|
|
|
DBG (1, "%s: error: allocate memory for pictures array\n", f);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
for (p = 0; p < Cam_data.pic_taken; p++)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (get_picture_info (pics + p, p) == -1)
|
|
|
|
|
{
|
|
|
|
|
free (pics);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.Pictures = pics;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return pics;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/*
|
2001-11-08 01:14:50 +00:00
|
|
|
|
* get_picture_info() - get info about picture p. Currently we have no
|
2001-09-30 03:12:22 +00:00
|
|
|
|
* way to get information about a picture beyond it's name.
|
2001-09-25 00:33:07 +00:00
|
|
|
|
*/
|
2001-09-07 02:40:21 +00:00
|
|
|
|
static SANE_Int
|
|
|
|
|
get_picture_info (PictureInfo * pic, SANE_Int p)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
SANE_Char f[] = "get_picture_info";
|
2001-09-18 04:26:13 +00:00
|
|
|
|
const char *name;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
DBG (4, "%s: info for pic #%d\n", f, p);
|
|
|
|
|
|
2001-09-18 04:26:13 +00:00
|
|
|
|
gp_list_get_name (dir_list, p, &name);
|
2001-09-13 00:34:57 +00:00
|
|
|
|
DBG (4, "Name is %s\n", name);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
2001-09-13 00:34:57 +00:00
|
|
|
|
read_info (name);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
pic->low_res = SANE_FALSE;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* snap_pic - take a picture (and call get_pictures_info to re-create
|
|
|
|
|
* the directory related data structures)
|
|
|
|
|
*/
|
|
|
|
|
static SANE_Status
|
|
|
|
|
snap_pic (void)
|
|
|
|
|
{
|
|
|
|
|
SANE_Char f[] = "snap_pic";
|
2001-09-18 04:26:13 +00:00
|
|
|
|
CameraFilePath path;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
/* make sure camera is set to our settings state */
|
|
|
|
|
if (change_res (gphoto2_opt_lowres) == -1)
|
|
|
|
|
{
|
|
|
|
|
DBG (1, "%s: Failed to set resolution\n", f);
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-20 05:31:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* This is needed when the camera has no files and the first picture
|
|
|
|
|
* is taken. I guess it's because a folder needs to be created and
|
|
|
|
|
* the filesystem doesn't know about it.
|
|
|
|
|
*/
|
|
|
|
|
if (Cam_data.pic_taken == 0)
|
|
|
|
|
{
|
|
|
|
|
gp_filesystem_reset (camera->fs);
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_capture (camera, GP_CAPTURE_IMAGE, &path, NULL));
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
/* Can't just increment picture count, because if the camera has
|
|
|
|
|
* zero pictures we may not know the folder name. Start over
|
2001-11-12 04:29:14 +00:00
|
|
|
|
* with get_info and get_pictures_info. (We didn't have the call
|
|
|
|
|
* to init_gphoto2() here before, but that was causing us to not
|
|
|
|
|
* see the new image - need to use a biggger hammer to get it to
|
|
|
|
|
* re-read the camera directory
|
2001-09-07 02:40:21 +00:00
|
|
|
|
*/
|
2002-01-15 04:04:38 +00:00
|
|
|
|
|
2001-11-12 04:29:14 +00:00
|
|
|
|
if (init_gphoto2 () != SANE_STATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-25 00:33:07 +00:00
|
|
|
|
if (get_info () != SANE_STATUS_GOOD)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
DBG (1, "error: could not get info\n");
|
2001-09-25 00:33:07 +00:00
|
|
|
|
close_gphoto2 ();
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (get_pictures_info () == NULL)
|
|
|
|
|
{
|
|
|
|
|
DBG (1, "%s: Failed to get new picture info\n", f);
|
2001-09-25 00:33:07 +00:00
|
|
|
|
/* FIXME - I guess we should try to erase the image here */
|
2001-09-07 02:40:21 +00:00
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap |= SANE_CAP_INACTIVE;
|
2001-09-13 00:34:57 +00:00
|
|
|
|
Cam_data.current_picture_number = Cam_data.pic_taken;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
|
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* read_dir - read a list of file names from the specified directory
|
|
|
|
|
* and create a linked list of file name entries in
|
|
|
|
|
* alphabetical order. The first entry in the list will
|
|
|
|
|
* be "picture #1", etc.
|
|
|
|
|
*/
|
|
|
|
|
static SANE_Int
|
|
|
|
|
read_dir (SANE_String dir, SANE_Bool read_files)
|
|
|
|
|
{
|
|
|
|
|
SANE_Int retval = 0;
|
|
|
|
|
SANE_Char f[] = "read_dir";
|
|
|
|
|
|
|
|
|
|
/* Free up current list */
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (dir_list != NULL)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (gp_list_free (dir_list) < 0)
|
|
|
|
|
{
|
|
|
|
|
DBG (0, "%s: errror: gp_list_free failed\n", f);
|
|
|
|
|
}
|
|
|
|
|
dir_list = NULL;
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (gp_list_new (&dir_list) < 0)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2001-09-18 04:26:13 +00:00
|
|
|
|
DBG (0, "%s: errror: gp_list_new failed\n", f);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-09-18 04:26:13 +00:00
|
|
|
|
if (read_files)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_folder_list_files (camera, dir, dir_list, NULL));
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
else
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
2002-01-13 04:10:23 +00:00
|
|
|
|
CHECK_RET (gp_camera_folder_list_folders (camera, dir, dir_list, NULL));
|
2001-09-07 02:40:21 +00:00
|
|
|
|
}
|
2001-09-18 04:26:13 +00:00
|
|
|
|
|
|
|
|
|
retval = gp_list_count (dir_list);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* read_info - read the info block from camera for the specified file
|
2001-09-30 03:12:22 +00:00
|
|
|
|
* NOT YET SUPPORTED - If it were we could use it to do things
|
|
|
|
|
* like update the image size parameters displayed by the GUI
|
2001-09-07 02:40:21 +00:00
|
|
|
|
*/
|
|
|
|
|
static SANE_Int
|
2001-09-13 00:34:57 +00:00
|
|
|
|
read_info (SANE_String_Const fname)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
SANE_Char path[256];
|
|
|
|
|
|
1994-10-29 05:52:22 +00:00
|
|
|
|
strcpy (path, "\\DCIM\\");
|
2001-09-13 00:34:57 +00:00
|
|
|
|
strcat (path, (const char *) folder_list[current_folder]);
|
2001-09-07 02:40:21 +00:00
|
|
|
|
strcat (path, "\\");
|
|
|
|
|
strcat (path, fname);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* set_res - set picture size depending on resolution settings
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2001-10-16 00:26:58 +00:00
|
|
|
|
set_res (SANE_Int UNUSEDARG lowres)
|
2001-09-07 02:40:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (gphoto2_opt_thumbnails)
|
|
|
|
|
{
|
|
|
|
|
parms.bytes_per_line = THUMB_WIDTH * 3;
|
|
|
|
|
parms.pixels_per_line = THUMB_WIDTH;
|
|
|
|
|
parms.lines = THUMB_HEIGHT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parms.bytes_per_line = HIGHRES_WIDTH * 3;
|
|
|
|
|
parms.pixels_per_line = HIGHRES_WIDTH;
|
|
|
|
|
parms.lines = HIGHRES_HEIGHT;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-09-30 03:12:22 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* converter_do_scan_complete_cleanup - do everything that needs to be
|
|
|
|
|
* once a "scan" has been completed: Unref the file, Erase the image,
|
|
|
|
|
* and increment image number to point to next picture.
|
|
|
|
|
*/
|
|
|
|
|
static SANE_Status
|
|
|
|
|
converter_do_scan_complete_cleanup (void)
|
|
|
|
|
{
|
|
|
|
|
CameraList *tmp_list;
|
|
|
|
|
SANE_Int i;
|
|
|
|
|
SANE_String_Const filename;
|
|
|
|
|
|
|
|
|
|
gp_file_unref (data_file);
|
|
|
|
|
|
|
|
|
|
if (gphoto2_opt_erase)
|
|
|
|
|
{
|
|
|
|
|
DBG (127, "sane_read bp%d, erase image\n", __LINE__);
|
|
|
|
|
if (erase () == -1)
|
|
|
|
|
{
|
|
|
|
|
DBG (1, "Failed to erase memory\n");
|
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-01-19 02:06:40 +00:00
|
|
|
|
if (SubDirs)
|
|
|
|
|
{
|
|
|
|
|
sprintf (cmdbuf, "%s/%s", (char *) TopFolder,
|
|
|
|
|
(const char *) folder_list[current_folder]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strcpy (cmdbuf, TopFolder);
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-30 03:12:22 +00:00
|
|
|
|
CHECK_RET (gp_list_get_name
|
|
|
|
|
(dir_list, Cam_data.current_picture_number - 1, &filename));
|
|
|
|
|
|
|
|
|
|
Cam_data.pic_taken--;
|
|
|
|
|
Cam_data.pic_left++;
|
|
|
|
|
if (Cam_data.current_picture_number > Cam_data.pic_taken)
|
|
|
|
|
{
|
|
|
|
|
Cam_data.current_picture_number = Cam_data.pic_taken;
|
|
|
|
|
}
|
|
|
|
|
image_range.max--;
|
|
|
|
|
if (image_range.max == 0)
|
|
|
|
|
{
|
|
|
|
|
sod[GPHOTO2_OPT_IMAGE_NUMBER].cap |= SANE_CAP_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
|
|
|
|
|
|
|
|
|
|
/* Too bad we don't have an API function for deleting a
|
|
|
|
|
* list item. Instead, we copy all the entries in the
|
|
|
|
|
* current list, skipping over the deleted entry, and then
|
|
|
|
|
* replace the current list with the new list.
|
|
|
|
|
*/
|
|
|
|
|
gp_list_new (&tmp_list);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < gp_list_count (dir_list); i++)
|
|
|
|
|
{
|
|
|
|
|
SANE_String_Const tfilename;
|
|
|
|
|
|
|
|
|
|
CHECK_RET (gp_list_get_name (dir_list, i, &tfilename));
|
|
|
|
|
/* If not the one to delete, copy to the new list */
|
|
|
|
|
if (strcmp (tfilename, filename) != 0)
|
|
|
|
|
{
|
|
|
|
|
CHECK_RET (gp_list_append (tmp_list, tfilename, NULL));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
gp_list_free (dir_list);
|
|
|
|
|
dir_list = tmp_list;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (gphoto2_opt_autoinc)
|
|
|
|
|
{
|
|
|
|
|
if (Cam_data.current_picture_number <= Cam_data.pic_taken)
|
|
|
|
|
{
|
|
|
|
|
Cam_data.current_picture_number++;
|
|
|
|
|
|
|
|
|
|
myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
|
|
|
|
|
|
|
|
|
|
/* get the image's resolution */
|
|
|
|
|
/* OLD:
|
|
|
|
|
set_res (Cam_data.Pictures[Cam_data.current_picture_number - 1].
|
|
|
|
|
low_res);
|
|
|
|
|
*/
|
|
|
|
|
set_res (gphoto2_opt_lowres);
|
|
|
|
|
}
|
|
|
|
|
DBG (4, "Increment count to %d (total %d)\n",
|
|
|
|
|
Cam_data.current_picture_number, Cam_data.pic_taken);
|
|
|
|
|
}
|
|
|
|
|
return SANE_STATUS_EOF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* converter_fill_buffer - Fill line buffer with next input line from image.
|
|
|
|
|
* Currently assumes jpeg, but this is where we would put the switch
|
|
|
|
|
* to handle other image types.
|
|
|
|
|
*/
|
|
|
|
|
static SANE_Int
|
|
|
|
|
converter_fill_buffer (void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FIXME: Current implementation reads one scan line at a time. Part
|
|
|
|
|
* of the reason for this is in the original code is to give the frontend
|
|
|
|
|
* a chance to update * the progress marker periodically. Since the gphoto2
|
|
|
|
|
* driver sucks in the whole image before decoding it, perhaps we could
|
|
|
|
|
* come up with a simpler implementation.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
SANE_Int lines = 1;
|
|
|
|
|
|
|
|
|
|
(void) jpeg_read_scanlines (&cinfo, dest_mgr->buffer, lines);
|
|
|
|
|
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, lines, (char *) linebuffer);
|
|
|
|
|
|
|
|
|
|
return cinfo.output_width * cinfo.output_components * lines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* converter_scan_complete - Check if all the data for the image has been read.
|
|
|
|
|
* Currently assumes jpeg, but this is where we would put the
|
|
|
|
|
* switch to handle other image types.
|
|
|
|
|
*/
|
|
|
|
|
static SANE_Bool
|
|
|
|
|
converter_scan_complete (void)
|
|
|
|
|
{
|
|
|
|
|
if (cinfo.output_scanline >= cinfo.output_height)
|
|
|
|
|
{
|
|
|
|
|
return SANE_TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return SANE_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* converter_init - Initialize image conversion data.
|
|
|
|
|
* Currently assumes jpeg, but this is where we would put the
|
|
|
|
|
* switch to handle other image types.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
converter_init (void)
|
|
|
|
|
{
|
|
|
|
|
SANE_Int row_stride;
|
|
|
|
|
struct jpeg_error_mgr jerr;
|
|
|
|
|
my_src_ptr src;
|
|
|
|
|
|
|
|
|
|
data_file_current_index = 0;
|
|
|
|
|
|
|
|
|
|
cinfo.err = jpeg_std_error (&jerr);
|
|
|
|
|
jpeg_create_decompress (&cinfo);
|
|
|
|
|
|
|
|
|
|
cinfo.src =
|
|
|
|
|
(struct jpeg_source_mgr *) (*cinfo.mem->
|
|
|
|
|
alloc_small) ((j_common_ptr) & cinfo,
|
|
|
|
|
JPOOL_PERMANENT,
|
|
|
|
|
sizeof (my_source_mgr));
|
|
|
|
|
src = (my_src_ptr) cinfo.src;
|
|
|
|
|
|
|
|
|
|
src->buffer = (JOCTET *) (*cinfo.mem->alloc_small) ((j_common_ptr) &
|
|
|
|
|
cinfo,
|
|
|
|
|
JPOOL_PERMANENT,
|
|
|
|
|
1024 * sizeof (JOCTET));
|
|
|
|
|
src->pub.init_source = jpeg_init_source;
|
|
|
|
|
src->pub.fill_input_buffer = jpeg_fill_input_buffer;
|
|
|
|
|
src->pub.skip_input_data = jpeg_skip_input_data;
|
|
|
|
|
src->pub.resync_to_restart = jpeg_resync_to_restart; /* default */
|
|
|
|
|
src->pub.term_source = jpeg_term_source;
|
|
|
|
|
src->pub.bytes_in_buffer = 0;
|
|
|
|
|
src->pub.next_input_byte = NULL;
|
|
|
|
|
|
|
|
|
|
(void) jpeg_read_header (&cinfo, TRUE);
|
|
|
|
|
dest_mgr = sanei_jpeg_jinit_write_ppm (&cinfo);
|
|
|
|
|
(void) jpeg_start_decompress (&cinfo);
|
|
|
|
|
|
|
|
|
|
row_stride = cinfo.output_width * cinfo.output_components;
|
|
|
|
|
|
|
|
|
|
parms.bytes_per_line = cinfo.output_width * 3; /* 3 colors */
|
|
|
|
|
parms.pixels_per_line = cinfo.output_width;
|
|
|
|
|
parms.lines = cinfo.output_height;
|
|
|
|
|
|
|
|
|
|
}
|