kopia lustrzana https://gitlab.com/sane-project/backends
781 wiersze
18 KiB
Plaintext
781 wiersze
18 KiB
Plaintext
|
/* sane - Scanner Access Now Easy.
|
|||
|
Copyright (C) 1996, 1997 Andreas Beck
|
|||
|
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. */
|
|||
|
|
|||
|
/*
|
|||
|
Modification allows selection to scan part of the image.
|
|||
|
Shortcomings:
|
|||
|
* Only tested with color PNM
|
|||
|
* Not working with grey or 3-pass options
|
|||
|
|
|||
|
Changes written by G<>ran Thyni <goran@bildbasen.se>
|
|||
|
Copyright (C) 1998 JMS Bildbasen i Kiruna AB.
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef _AIX
|
|||
|
# include <lalloca.h> /* MUST come first for AIX! */
|
|||
|
#endif
|
|||
|
|
|||
|
#include <sane/config.h>
|
|||
|
|
|||
|
#include <lalloca.h>
|
|||
|
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#include <signal.h>
|
|||
|
|
|||
|
#include <sane/sane.h>
|
|||
|
#include <sane/sanei.h>
|
|||
|
#include <sane/saneopts.h>
|
|||
|
|
|||
|
#define BACKEND_NAME pnm
|
|||
|
#include <sane/sanei_backend.h>
|
|||
|
|
|||
|
#define MAGIC (void *)0xab730324
|
|||
|
|
|||
|
#define XBRMAX 750
|
|||
|
#define YBRMAX 1000
|
|||
|
|
|||
|
static int is_open = 0;
|
|||
|
static int tlx = 0, tly = 0, brx = XBRMAX, bry = YBRMAX;
|
|||
|
static int read_lines = 0;
|
|||
|
static int three_pass = 0;
|
|||
|
static int hand_scanner = 0;
|
|||
|
static int pass = 0;
|
|||
|
static char filename[128] = "/tmp/input.ppm";
|
|||
|
static SANE_Fixed bright = 0;
|
|||
|
static SANE_Fixed contr = 0;
|
|||
|
static SANE_Bool gray = SANE_FALSE;
|
|||
|
static enum
|
|||
|
{
|
|||
|
ppm_bitmap,
|
|||
|
ppm_greyscale,
|
|||
|
ppm_color
|
|||
|
}
|
|||
|
ppm_type = ppm_color;
|
|||
|
static FILE *infile = NULL;
|
|||
|
|
|||
|
static const SANE_Range percentage_range =
|
|||
|
{
|
|||
|
-100 << SANE_FIXED_SCALE_SHIFT, /* minimum */
|
|||
|
100 << SANE_FIXED_SCALE_SHIFT, /* maximum */
|
|||
|
0 << SANE_FIXED_SCALE_SHIFT /* quantization */
|
|||
|
};
|
|||
|
|
|||
|
static SANE_Range x_range =
|
|||
|
{
|
|||
|
0, /* minimum */
|
|||
|
XBRMAX, /* maximum */
|
|||
|
0, /* quantization */
|
|||
|
};
|
|||
|
|
|||
|
static SANE_Range y_range =
|
|||
|
{
|
|||
|
0, /* minimum */
|
|||
|
YBRMAX, /* maximum */
|
|||
|
0, /* quantization */
|
|||
|
};
|
|||
|
|
|||
|
#define OPT_TLX 4
|
|||
|
#define OPT_TLY 5
|
|||
|
#define OPT_BRX 6
|
|||
|
#define OPT_BRY 7
|
|||
|
|
|||
|
static const SANE_Option_Descriptor sod[] =
|
|||
|
{
|
|||
|
{ /* 0 */
|
|||
|
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}
|
|||
|
},
|
|||
|
{ /* 1 */
|
|||
|
"",
|
|||
|
"Source Selection",
|
|||
|
"Selection of the file to load.",
|
|||
|
SANE_TYPE_GROUP,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
0,
|
|||
|
0,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 2 */
|
|||
|
SANE_NAME_FILE,
|
|||
|
SANE_TITLE_FILE,
|
|||
|
SANE_DESC_FILE,
|
|||
|
SANE_TYPE_STRING,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
sizeof (filename),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 3 */
|
|||
|
"",
|
|||
|
"Image Size",
|
|||
|
"controls to set image size",
|
|||
|
SANE_TYPE_GROUP,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
0,
|
|||
|
SANE_CAP_ADVANCED,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 4 */
|
|||
|
SANE_NAME_SCAN_TL_X,
|
|||
|
SANE_TITLE_SCAN_TL_X,
|
|||
|
SANE_DESC_SCAN_TL_X,
|
|||
|
SANE_TYPE_INT,
|
|||
|
SANE_UNIT_PIXEL,
|
|||
|
sizeof(SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &x_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 5 */
|
|||
|
SANE_NAME_SCAN_TL_Y,
|
|||
|
SANE_TITLE_SCAN_TL_Y,
|
|||
|
SANE_DESC_SCAN_TL_Y,
|
|||
|
SANE_TYPE_INT,
|
|||
|
SANE_UNIT_PIXEL,
|
|||
|
sizeof(SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &y_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 6 */
|
|||
|
SANE_NAME_SCAN_BR_X,
|
|||
|
SANE_TITLE_SCAN_BR_X,
|
|||
|
SANE_DESC_SCAN_BR_X,
|
|||
|
SANE_TYPE_INT,
|
|||
|
SANE_UNIT_PIXEL,
|
|||
|
sizeof(SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &x_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 7 */
|
|||
|
SANE_NAME_SCAN_BR_Y,
|
|||
|
SANE_TITLE_SCAN_BR_Y,
|
|||
|
SANE_DESC_SCAN_BR_Y,
|
|||
|
SANE_TYPE_INT,
|
|||
|
SANE_UNIT_PIXEL,
|
|||
|
sizeof(SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &y_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 8 */
|
|||
|
"",
|
|||
|
"Image Enhancement",
|
|||
|
"A few controls to enhance image while loading",
|
|||
|
SANE_TYPE_GROUP,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
0,
|
|||
|
0,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 9 */
|
|||
|
SANE_NAME_BRIGHTNESS,
|
|||
|
SANE_TITLE_BRIGHTNESS,
|
|||
|
SANE_DESC_BRIGHTNESS,
|
|||
|
SANE_TYPE_FIXED,
|
|||
|
SANE_UNIT_PERCENT,
|
|||
|
sizeof (SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &percentage_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 10 */
|
|||
|
SANE_NAME_CONTRAST,
|
|||
|
SANE_TITLE_CONTRAST,
|
|||
|
SANE_DESC_CONTRAST,
|
|||
|
SANE_TYPE_FIXED,
|
|||
|
SANE_UNIT_PERCENT,
|
|||
|
sizeof (SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_RANGE,
|
|||
|
{(SANE_String_Const *) &percentage_range} /* this is ANSI conformant! */
|
|||
|
},
|
|||
|
{ /* 11 */
|
|||
|
"grayify",
|
|||
|
"Grayify",
|
|||
|
"Load the image as grayscale.",
|
|||
|
SANE_TYPE_BOOL,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
sizeof (SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 12 */
|
|||
|
"three-pass",
|
|||
|
"Three-Pass Simulation",
|
|||
|
"Simulate a three-pass scanner by returning 3 separate frames. "
|
|||
|
"For kicks, it returns green, then blue, then red.",
|
|||
|
SANE_TYPE_BOOL,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
sizeof (SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 13 */
|
|||
|
"hand-scanner",
|
|||
|
"Hand-Scanner Simulation",
|
|||
|
"Simulate a hand-scanner. Hand-scanners often do not know the image "
|
|||
|
"height a priori. Instead, they return a height of -1. Setting this "
|
|||
|
"option allows to test whether a frontend can handle this correctly.",
|
|||
|
SANE_TYPE_BOOL,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
sizeof (SANE_Word),
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
SANE_CONSTRAINT_NONE,
|
|||
|
{NULL}
|
|||
|
},
|
|||
|
{ /* 14 */
|
|||
|
"default-enhancements",
|
|||
|
"Defaults",
|
|||
|
"Set default values for enhancement controls (brightness & contrast).",
|
|||
|
SANE_TYPE_BUTTON,
|
|||
|
SANE_UNIT_NONE,
|
|||
|
0,
|
|||
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
|
|||
|
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. */
|
|||
|
};
|
|||
|
|
|||
|
/* This library is a demo implementation of a SANE backend. It
|
|||
|
implements a virtual device, a PNM file-filter. */
|
|||
|
SANE_Status
|
|||
|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
|
{
|
|||
|
DBG_INIT();
|
|||
|
|
|||
|
if (version_code)
|
|||
|
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
void sane_exit (void) { }
|
|||
|
|
|||
|
/* Device select/open/close */
|
|||
|
|
|||
|
static const SANE_Device dev[] =
|
|||
|
{
|
|||
|
{
|
|||
|
"0",
|
|||
|
"Noname",
|
|||
|
"PNM file reader",
|
|||
|
"virtual device"
|
|||
|
},
|
|||
|
{
|
|||
|
"1",
|
|||
|
"Noname",
|
|||
|
"PNM file reader",
|
|||
|
"virtual device"
|
|||
|
},
|
|||
|
};
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
|||
|
{
|
|||
|
static const SANE_Device * devlist[] =
|
|||
|
{
|
|||
|
dev + 0, dev + 1, 0
|
|||
|
};
|
|||
|
|
|||
|
*device_list = devlist;
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
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;
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
sane_close (SANE_Handle handle)
|
|||
|
{
|
|||
|
if (handle == MAGIC)
|
|||
|
is_open = 0;
|
|||
|
}
|
|||
|
|
|||
|
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];
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_control_option (SANE_Handle handle, SANE_Int option,
|
|||
|
SANE_Action action, void *value,
|
|||
|
SANE_Int * info)
|
|||
|
{
|
|||
|
SANE_Int myinfo = 0;
|
|||
|
SANE_Status status;
|
|||
|
|
|||
|
DBG(2, "control_option(handle=%p,opt=%d,act=%d,val=%p,info=%p)\n",
|
|||
|
handle, option, action, 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)
|
|||
|
return status;
|
|||
|
|
|||
|
switch (option)
|
|||
|
{
|
|||
|
case 2:
|
|||
|
strcpy (filename, value);
|
|||
|
if (access (filename, R_OK) == 0)
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
tlx = *(SANE_Word *) value;
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 5:
|
|||
|
tly = *(SANE_Word *) value;
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 6:
|
|||
|
brx = *(SANE_Word *) value;
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 7:
|
|||
|
bry = *(SANE_Word *) value;
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 9:
|
|||
|
bright = *(SANE_Word *) value;
|
|||
|
break;
|
|||
|
case 10:
|
|||
|
contr = *(SANE_Word *) value;
|
|||
|
break;
|
|||
|
case 11:
|
|||
|
gray = !!*(SANE_Word *) value;
|
|||
|
myinfo |= SANE_INFO_RELOAD_PARAMS;
|
|||
|
break;
|
|||
|
case 12:
|
|||
|
three_pass = !!*(SANE_Word *) value;
|
|||
|
break;
|
|||
|
case 13:
|
|||
|
hand_scanner = !!*(SANE_Word *) value;
|
|||
|
break;
|
|||
|
case 14:
|
|||
|
bright = contr = 0;
|
|||
|
myinfo |= SANE_INFO_RELOAD_OPTIONS;
|
|||
|
break;
|
|||
|
default:
|
|||
|
return SANE_STATUS_INVAL;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case SANE_ACTION_GET_VALUE:
|
|||
|
switch (option)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
*(SANE_Word *) value = NELEMS(sod);
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
strcpy (value, filename);
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
*(SANE_Word *) value = tlx;
|
|||
|
break;
|
|||
|
case 5:
|
|||
|
*(SANE_Word *) value = tly;
|
|||
|
break;
|
|||
|
case 6:
|
|||
|
*(SANE_Word *) value = brx;
|
|||
|
break;
|
|||
|
case 7:
|
|||
|
*(SANE_Word *) value = bry;
|
|||
|
break;
|
|||
|
case 9:
|
|||
|
*(SANE_Word *) value = bright;
|
|||
|
break;
|
|||
|
case 10:
|
|||
|
*(SANE_Word *) value = contr;
|
|||
|
break;
|
|||
|
case 11:
|
|||
|
*(SANE_Word *) value = gray;
|
|||
|
break;
|
|||
|
case 12:
|
|||
|
*(SANE_Word *) value = three_pass;
|
|||
|
break;
|
|||
|
case 13:
|
|||
|
*(SANE_Word *) value = hand_scanner;
|
|||
|
break;
|
|||
|
default:
|
|||
|
return SANE_STATUS_INVAL;
|
|||
|
}
|
|||
|
break;
|
|||
|
case SANE_ACTION_SET_AUTO:
|
|||
|
return SANE_STATUS_UNSUPPORTED; /* We are DUMB */
|
|||
|
}
|
|||
|
if (info)
|
|||
|
*info = myinfo;
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
get_line (char *buf, int len, FILE * f)
|
|||
|
{
|
|||
|
do
|
|||
|
fgets (buf, len, f);
|
|||
|
while (*buf == '#');
|
|||
|
}
|
|||
|
|
|||
|
static int
|
|||
|
getparmfromfile (void)
|
|||
|
{
|
|||
|
FILE *fn;
|
|||
|
int x, y;
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
parms.bytes_per_line = parms.pixels_per_line = parms.lines = 0;
|
|||
|
if ((fn = fopen (filename, "rb")) == NULL)
|
|||
|
return -1;
|
|||
|
|
|||
|
/* Skip comments. */
|
|||
|
do
|
|||
|
get_line (buf, sizeof (buf), fn);
|
|||
|
while (*buf == '#');
|
|||
|
if (!strncmp (buf, "P4", 2))
|
|||
|
{
|
|||
|
/* Binary monochrome. */
|
|||
|
parms.depth = 1;
|
|||
|
gray = SANE_TRUE;
|
|||
|
|
|||
|
ppm_type = ppm_bitmap;
|
|||
|
}
|
|||
|
else if (!strncmp (buf, "P5", 2))
|
|||
|
{
|
|||
|
/* Grayscale. */
|
|||
|
gray = SANE_TRUE;
|
|||
|
ppm_type = ppm_greyscale;
|
|||
|
}
|
|||
|
else if (strncmp (buf, "P6", 2))
|
|||
|
{
|
|||
|
DBG(2, "%s is not a recognized PPM\n", filename);
|
|||
|
fclose (fn);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
/* Skip comments. */
|
|||
|
do
|
|||
|
get_line (buf, sizeof (buf), fn);
|
|||
|
while (*buf == '#');
|
|||
|
sscanf (buf, "%d %d", &x, &y);
|
|||
|
|
|||
|
parms.last_frame = SANE_TRUE;
|
|||
|
parms.bytes_per_line = (ppm_type == ppm_bitmap) ? (x + 7) / 8 : x;
|
|||
|
parms.pixels_per_line = x;
|
|||
|
if (hand_scanner)
|
|||
|
parms.lines = -1;
|
|||
|
else
|
|||
|
parms.lines = y;
|
|||
|
if (gray)
|
|||
|
parms.format = SANE_FRAME_GRAY;
|
|||
|
else
|
|||
|
{
|
|||
|
if (three_pass)
|
|||
|
{
|
|||
|
parms.format = SANE_FRAME_RED + (pass + 1) % 3;
|
|||
|
parms.last_frame = (pass >= 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
parms.format = SANE_FRAME_RGB;
|
|||
|
parms.bytes_per_line *= 3;
|
|||
|
}
|
|||
|
}
|
|||
|
fclose (fn);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_get_parameters (SANE_Handle handle,
|
|||
|
SANE_Parameters * params)
|
|||
|
{
|
|||
|
int rc = SANE_STATUS_GOOD;
|
|||
|
if (handle != MAGIC || !is_open)
|
|||
|
rc = SANE_STATUS_INVAL; /* Unknown handle ... */
|
|||
|
else if (getparmfromfile ())
|
|||
|
rc = SANE_STATUS_INVAL;
|
|||
|
*params = parms;
|
|||
|
if (1)
|
|||
|
{
|
|||
|
params->lines = bry - tly;
|
|||
|
params->pixels_per_line = brx - tlx;
|
|||
|
params->bytes_per_line = params->pixels_per_line * 3;
|
|||
|
}
|
|||
|
return rc;
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_start (SANE_Handle handle)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
int nlines;
|
|||
|
|
|||
|
if (handle != MAGIC || !is_open)
|
|||
|
return SANE_STATUS_INVAL; /* Unknown handle ... */
|
|||
|
|
|||
|
if (infile != NULL)
|
|||
|
{
|
|||
|
fclose (infile);
|
|||
|
infile = NULL;
|
|||
|
read_lines = 0;
|
|||
|
if (!three_pass || ++pass >= 3)
|
|||
|
return SANE_STATUS_EOF;
|
|||
|
}
|
|||
|
|
|||
|
if (getparmfromfile ())
|
|||
|
return SANE_STATUS_INVAL;
|
|||
|
|
|||
|
if ((infile = fopen (filename, "rb")) == NULL)
|
|||
|
return SANE_STATUS_INVAL;
|
|||
|
|
|||
|
/* Skip the header (only two lines for a bitmap). */
|
|||
|
nlines = (ppm_type == ppm_bitmap) ? 1 : 0;
|
|||
|
while (nlines < 3)
|
|||
|
{
|
|||
|
/* Skip comments. */
|
|||
|
get_line (buf, sizeof (buf), infile);
|
|||
|
if (*buf != '#')
|
|||
|
nlines++;
|
|||
|
}
|
|||
|
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
static SANE_Int rgblength = 0;
|
|||
|
static SANE_Byte *rgbbuf = 0;
|
|||
|
static SANE_Byte rgbleftover[3] = {0, 0, 0};
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_read (SANE_Handle handle, SANE_Byte * data,
|
|||
|
SANE_Int max_length, SANE_Int * length)
|
|||
|
{
|
|||
|
int len, x, hlp;
|
|||
|
signal (SIGSEGV, SIG_DFL);
|
|||
|
if (handle != MAGIC || !is_open || !infile)
|
|||
|
return SANE_STATUS_INVAL; /* Unknown handle or no file to read... */
|
|||
|
again:
|
|||
|
if (feof (infile))
|
|||
|
{
|
|||
|
return SANE_STATUS_EOF;
|
|||
|
}
|
|||
|
if (!read_lines && tly)
|
|||
|
{
|
|||
|
fseek(infile, parms.bytes_per_line * tly, SEEK_CUR);
|
|||
|
read_lines = tly;
|
|||
|
}
|
|||
|
/* Allocate a buffer for the RGB values. */
|
|||
|
if (ppm_type == ppm_color && (gray || three_pass))
|
|||
|
{
|
|||
|
SANE_Byte *p, *q, *rgbend;
|
|||
|
|
|||
|
if (rgbbuf == 0 || rgblength < 3 * max_length)
|
|||
|
{
|
|||
|
/* Allocate a new rgbbuf. */
|
|||
|
if (rgbbuf) free (rgbbuf);
|
|||
|
rgblength = 3 * max_length;
|
|||
|
rgbbuf = malloc (rgblength);
|
|||
|
if (rgbbuf == 0)
|
|||
|
return SANE_STATUS_NO_MEM;
|
|||
|
}
|
|||
|
|
|||
|
/* Copy any leftovers into the buffer. */
|
|||
|
q = rgbbuf;
|
|||
|
p = rgbleftover + 1;
|
|||
|
while (p - rgbleftover <= rgbleftover[0])
|
|||
|
*q++ = *p++;
|
|||
|
|
|||
|
/* Slurp in the RGB buffer. */
|
|||
|
len = fread (q, 1, rgblength - rgbleftover[0], infile);
|
|||
|
if (len == 0) goto again;
|
|||
|
if (tlx || brx != XBRMAX)
|
|||
|
{
|
|||
|
len = (brx - tlx) * 3;
|
|||
|
}
|
|||
|
rgbend = rgbbuf + len;
|
|||
|
q = data;
|
|||
|
if (gray)
|
|||
|
{
|
|||
|
/* Zip through the buffer, converting color data to grayscale. */
|
|||
|
for (p = rgbbuf + tlx * 3; p < rgbend; p += 3)
|
|||
|
*q++ = ((long) p[0] + p[1] + p[2]) / 3;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
p = (rgbbuf + (pass + 1) % 3);
|
|||
|
p += tlx * 3;
|
|||
|
/* Zip through the buffer, extracting data for this pass. */
|
|||
|
for (; p < rgbend; p += 3)
|
|||
|
*q++ = *p;
|
|||
|
}
|
|||
|
|
|||
|
/* Save any leftovers in the array. */
|
|||
|
rgbleftover[0] = len % 3;
|
|||
|
p = rgbbuf + (len - rgbleftover[0]);
|
|||
|
q = rgbleftover + 1;
|
|||
|
while (p < rgbend)
|
|||
|
*q++ = *p++;
|
|||
|
len /= 3;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Suck in as much of the file as possible, since it's already in the
|
|||
|
correct format. */
|
|||
|
char *buf;
|
|||
|
int doread = parms.bytes_per_line;
|
|||
|
if (read_lines >= bry)
|
|||
|
return SANE_STATUS_EOF;
|
|||
|
buf = alloca(doread);
|
|||
|
len = fread (buf, 1, doread, infile);
|
|||
|
if (brx == XBRMAX && read_lines < YBRMAX)
|
|||
|
{
|
|||
|
memcpy(data, buf, len);
|
|||
|
bzero(data + len, XBRMAX * 3);
|
|||
|
len = XBRMAX * 3;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
len = (brx - tlx) * 3;
|
|||
|
memcpy(data, buf + (tlx * 3), len);
|
|||
|
}
|
|||
|
if (len == 0 && feof(infile)) /* goto again; */
|
|||
|
return SANE_STATUS_EOF;
|
|||
|
}
|
|||
|
if (parms.depth == 8)
|
|||
|
/* Do the transformations ... DEMO ONLY ! THIS MAKES NO SENSE ! */
|
|||
|
for (x = 0; x < len; x++)
|
|||
|
{
|
|||
|
hlp = *((unsigned char *) data + x) - 128;
|
|||
|
hlp *= (contr + (100 << SANE_FIXED_SCALE_SHIFT));
|
|||
|
hlp /= 100 << SANE_FIXED_SCALE_SHIFT;
|
|||
|
hlp += (bright >> SANE_FIXED_SCALE_SHIFT) + 128;
|
|||
|
if (hlp < 0)
|
|||
|
hlp = 0;
|
|||
|
if (hlp > 255)
|
|||
|
hlp = 255;
|
|||
|
*(data + x) = hlp;
|
|||
|
}
|
|||
|
*length = len;
|
|||
|
read_lines++;
|
|||
|
return SANE_STATUS_GOOD;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
sane_cancel (SANE_Handle handle)
|
|||
|
{
|
|||
|
pass = 0;
|
|||
|
if (infile != NULL)
|
|||
|
{
|
|||
|
fclose (infile);
|
|||
|
infile = NULL;
|
|||
|
read_lines = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
|
|||
|
{
|
|||
|
return SANE_STATUS_UNSUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
SANE_Status
|
|||
|
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
|
|||
|
{
|
|||
|
return SANE_STATUS_UNSUPPORTED;
|
|||
|
}
|