Re: Update for Epson Backend / Perfection 1200S Support

Karl Heinz Kremer (khk@khk.net)
Mon, 27 Dec 1999 14:43:20 -0500

--DBIVS5p969aUjpLe
Content-Type: multipart/mixed; boundary="uAKRQypu60I7Lcqm"

--uAKRQypu60I7Lcqm
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

Leonard,

here is my patch.

Karl Heinz

On Mon, Dec 27, 1999 at 09:23:11AM -0800, Leonard Bottleman wrote:
> If you find out who's in charge of the Epson backend code,
> please let us know.
>=20
> I've also made a few very small changes to add support for
> the Epson Action Scanner II (parallel port), but can't find
> anybody to send the changes to.
>=20
> I would like a copy of your patch -- thanks for offering.
>=20
> Leonard Bottleman leonard@teleport.com
>=20
> Karl Heinz Kremer wrote:
> >=20
> > I just got a note from Kaz Sasayama, saying that he's not
> > mainaining the Epson backend in the release code. Who is?
> >=20
> > I've made some changes to the code in order to support the
> > 1200S scanner. At the same time I also added some features
> > that would also work with other (already supported) Epson
> > scanners (like mirroring, gamma and color correction).
> >=20
> > Who shall I send the patch to?
> >=20
> > If somebody wants the patch before it goes into either a
> > new release or a new development snapshot, just drop me
> > a note.
> >=20
> > Karl Heinz
> >=20
> > --
> > Karl Heinz Kremer khk@khk.net
> > http://www.khk.net
> > ICQ: 41190739
> >=20
> > ---------------------------------------------------------------------=
-------------------------------
> > Part 1.2Type: application/pgp-signature
>=20
> --
> Source code, list archive, and docs: http://www.mostang.com/sane/
> To unsubscribe: echo unsubscribe sane-devel | mail majordomo@mostang.com

--=20
Karl Heinz Kremer khk@khk.net
http://www.khk.net
ICQ: 41190739

--uAKRQypu60I7Lcqm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="epson.patch"
Content-Transfer-Encoding: quoted-printable

*** epson.c.ORIG Sat Dec 25 09:22:50 1999
--- epson.c Sun Dec 26 16:49:02 1999
***************
*** 10,15 ****
--- 10,17 ----
Copyright (C) 1998 Christian Bucher
Copyright (C) 1998 Kling & Hautzinger GmbH
=20
+ Copyright (C) 1999 Karl Heinz Kremer
+=20
This file is part of the SANE package.
=20
This program is free software; you can redistribute it and/or
***************
*** 46,52 ****
=20
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. */
=20
#ifdef _AIX
# include <lalloca.h> /* MUST come first for AIX! */
--- 48,68 ----
=20
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.
!=20
! Changes:
!=20
! 26-DEC-1999 (Karl Heinz Kremer, khk@khk.net)
! added support for B7 and B8 level devices (Perfection 1200=
S)
! added mirroring support (does not yet take current scan ar=
ea
! selection into account) - at this time B8 is just a cop=
y of
! B7.
! added gamma and color correction support
! added auto area segmentation support
!=20
! */
!=20
!=20
=20
#ifdef _AIX
# include <lalloca.h> /* MUST come first for AIX! */
***************
*** 101,145 ****
#define EPSON_LEVEL_B4 5
#define EPSON_LEVEL_B5 6
#define EPSON_LEVEL_B6 7
=20
#define EPSON_LEVEL_DEFAULT EPSON_LEVEL_B3
=20
static EpsonCmdRec epson_cmd[] =3D
{
/*
! request identity
! | request status
! | | request condition
! | | | set color mode
! | | | | start scanning
! | | | | | set data format
! | | | | | | set resolution
! | | | | | | | set zoom
! | | | | | | | | set scan area
! | | | | | | | | | set brightness
! | | | | | | | | | | set gamma
! | | | | | | | | | | | set halftoning
! | | | | | | | | | | | | set color correction
! | | | | | | | | | | | | | initialize scanner
! | | | | | | | | | | | | | | set speed
! | | | | | | | | | | | | | | | set lcount
! | | | | | | | | | | | | | | | |
*/
! {"A1", 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1}
,
! {"A2", 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1}
,
! {"B1", 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1}
,
! {"B2", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1}
,
! {"B3", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B4", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B5", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B6", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
};
=20
/* TODO: speed */
--- 117,169 ----
#define EPSON_LEVEL_B4 5
#define EPSON_LEVEL_B5 6
#define EPSON_LEVEL_B6 7
+ #define EPSON_LEVEL_B7 8
+ #define EPSON_LEVEL_B8 9
=20
#define EPSON_LEVEL_DEFAULT EPSON_LEVEL_B3
=20
static EpsonCmdRec epson_cmd[] =3D
{
/*
! set mirroring
! | auto area segmentation
! | | request identity
! | | | request status
! | | | | request condition
! | | | | | set color mode
! | | | | | | start scanning
! | | | | | | | set data format
! | | | | | | | | set resolution
! | | | | | | | | | set zoom
! | | | | | | | | | | set scan area
! | | | | | | | | | | | set brightness
! | | | | | | | | | | | | set gamma
! | | | | | | | | | | | | | set halftoning
! | | | | | | | | | | | | | | set color correction
! | | | | | | | | | | | | | | | initialize scanner
! | | | | | | | | | | | | | | | | set speed
! | | | | | | | | | | | | | | | | | set lcount
! | | | | | | | | | | | | | | | | | |
*/
! {"A1", 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1}
,
! {"A2", 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1}
,
! {"B1", 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1}
,
! {"B2", 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1}
,
! {"B3", 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B4", 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B5", 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
,
! {"B6", 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
! ,
! {"B7", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
! ,
! {"B8", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}
};
=20
/* TODO: speed */
***************
*** 482,487 ****
--- 506,568 ----
}
=20
static SANE_Status
+ set_mirror (Epson_Scanner * s, int mirror)
+ {
+ SANE_Status status;
+ unsigned char params[1];
+=20
+ if (!s->hw->cmd->K)
+ return SANE_STATUS_GOOD;
+=20
+ send (s, "\033K", 2, &status);
+ status =3D expect_ack (s);
+ if (status !=3D SANE_STATUS_GOOD)
+ return status;
+ params[0] =3D mirror;
+ send (s, params, 1, &status);
+ status =3D expect_ack (s);
+ return status;
+ }
+=20
+ static SANE_Status
+ set_sharpness (Epson_Scanner * s, int sharpness)
+ {
+ SANE_Status status;
+ unsigned char params[1];
+=20
+ if (!s->hw->cmd->L)
+ return SANE_STATUS_GOOD;
+=20
+ send (s, "\033Q", 2, &status);
+ status =3D expect_ack (s);
+ if (status !=3D SANE_STATUS_GOOD)
+ return status;
+ params[0] =3D sharpness;
+ send (s, params, 1, &status);
+ status =3D expect_ack (s);
+ return status;
+ }
+=20
+ static SANE_Status
+ set_autosegment (Epson_Scanner * s, int autosegment)
+ {
+ SANE_Status status;
+ unsigned char params[1];
+=20
+ if (!s->hw->cmd->s)
+ return SANE_STATUS_GOOD;
+=20
+ send (s, "\033s", 2, &status);
+ status =3D expect_ack (s);
+ if (status !=3D SANE_STATUS_GOOD)
+ return status;
+ params[0] =3D autosegment;
+ send (s, params, 1, &status);
+ status =3D expect_ack (s);
+ return status;
+ }
+=20
+ static SANE_Status
reset (Epson_Scanner * s)
{
SANE_Status status;
***************
*** 611,616 ****
--- 692,712 ----
=20
#endif
=20
+ static size_t
+ max_string_size (const SANE_String_Const strings[])
+ {
+ size_t size, max_size =3D 0;
+ int i;
+=20
+ for (i =3D 0; strings[i]; ++i)
+ {
+ size =3D strlen (strings[i]) + 1;
+ if (size > max_size)
+ max_size =3D size;
+ }
+ return max_size;
+ }
+=20
#if 1
static EpsonHdr=20
command (Epson_Scanner * s, const u_char * cmd, size_t cmd_size, SANE_Sta=
tus * status)
***************
*** 932,938 ****
{
{0, 0x00, 0x30, 1},
{0, 0x00, 0x30, 8},
! {1, 0x02, 0x00, 8},
};
=20
static const SANE_String_Const mode_list[] =3D
--- 1028,1034 ----
{
{0, 0x00, 0x30, 1},
{0, 0x00, 0x30, 8},
! {1, 0x02, 0x00, 8}
};
=20
static const SANE_String_Const mode_list[] =3D
***************
*** 952,958 ****
0x80,
0x90,
0xa0,
! 0xb0
};
=20
static const SANE_String_Const halftone_list[] =3D
--- 1048,1059 ----
0x80,
0x90,
0xa0,
! 0xb0,
! 0x03,
! #if 0
! 0xc0,
! 0xd0,
! #endif
};
=20
static const SANE_String_Const halftone_list[] =3D
***************
*** 974,979 ****
--- 1075,1085 ----
"Dither B",
"Dither C",
"Dither D",
+ "Text Enhanced Technology",
+ #if 0
+ "Download pattern A",
+ "Download pattern B",
+ #endif
NULL
};
=20
***************
*** 982,988 ****
0x00,
0x10,
0x20,
! 0x30,
};
=20
static const SANE_String_Const dropout_list[] =3D
--- 1088,1094 ----
0x00,
0x10,
0x20,
! 0x30
};
=20
static const SANE_String_Const dropout_list[] =3D
***************
*** 999,1012 ****
=20
static const SANE_String_Const brightness_list[] =3D
{
! "Very light"
! ,"Lighter"
! ,"Light"
! ,"Normal"
! ,"Dark"
! ,"Darker"
! ,"Very dark"
! ,NULL
};
=20
static SANE_Status
--- 1105,1185 ----
=20
static const SANE_String_Const brightness_list[] =3D
{
! "Very light",
! "Lighter",
! "Light",
! "Normal",
! "Dark",
! "Darker",
! "Very dark",
! NULL
! };
!=20
! static int sharpness_params[] =3D
! {
! 0xfe,
! 0xff,
! 0x00,
! 0x01,
! 0x02
! };
!=20
! static const SANE_String_Const sharpness_list[] =3D
! {
! "Defocus",
! "Defocus slightly",
! "Normal",
! "Sharpness slightly",
! "Sharpness",
! NULL
! };
!=20
! static int gamma_params[] =3D
! {
! 0x01,
! 0x02,
! #if 0 =20
! 0x03,
! 0x04,
! #endif =20
! 0x00,
! 0x10,
! 0x20
! };
!=20
! static const SANE_String_Const gamma_list[] =3D
! {
! "CRT A, bi-level data",
! "CRT B, multi-level data",
! #if 0
! "User defined table, gamma =3D 1.0",
! "User defined table, gamma =3D 1.8",
! #endif =20
! "High density printer",
! "Low density printer",
! "High contrast printer",
! NULL
! };
!=20
! static int color_params[] =3D
! {
! 0x00,
! 0x01,
! 0x10,
! 0x20,
! 0x40,
! 0x80
! };
!=20
! static const SANE_String_Const color_list[] =3D
! {
! "No Correction",
! "User defined",
! "Impact-dot printers",
! "Thermal printers",
! "Inkjet printers",
! "CRT monitors",
! NULL
};
=20
static SANE_Status
***************
*** 1135,1140 ****
--- 1308,1371 ----
s->opt[OPT_BR_Y].constraint.range =3D &s->hw->y_range;
s->val[OPT_BR_Y] =3D s->hw->y_range.max;
=20
+ /* sharpness */
+ s->opt[OPT_SHARPNESS].name =3D "sharpness";
+ s->opt[OPT_SHARPNESS].title =3D "Sharpness";
+ s->opt[OPT_SHARPNESS].desc =3D "Control the sharpness of the image";
+ s->opt[OPT_SHARPNESS].type =3D SANE_TYPE_STRING;
+ s->opt[OPT_SHARPNESS].size =3D max_string_size(sharpness_list);
+ s->opt[OPT_SHARPNESS].constraint_type =3D SANE_CONSTRAINT_STRING_LIST;
+ s->opt[OPT_SHARPNESS].constraint.string_list =3D sharpness_list;
+ s->val[OPT_SHARPNESS] =3D 2; /* normal */
+=20
+ /* gamma correction */
+ s->opt[OPT_GAMMA].name =3D "gamma";
+ s->opt[OPT_GAMMA].title =3D "Gamma Correction";
+ s->opt[OPT_GAMMA].desc =3D "Control the gamma correction";
+ s->opt[OPT_GAMMA].type =3D SANE_TYPE_STRING;
+ s->opt[OPT_GAMMA].size =3D max_string_size(gamma_list);
+ s->opt[OPT_GAMMA].constraint_type =3D SANE_CONSTRAINT_STRING_LIST;
+ s->opt[OPT_GAMMA].constraint.string_list =3D gamma_list;
+ s->val[OPT_GAMMA] =3D 0; /* CRT 1 */
+=20
+ /* color correction */
+ s->opt[OPT_COLOR].name =3D "color";
+ s->opt[OPT_COLOR].title =3D "Color Correction";
+ s->opt[OPT_COLOR].desc =3D "Control the color correction";
+ s->opt[OPT_COLOR].type =3D SANE_TYPE_STRING;
+ s->opt[OPT_COLOR].size =3D max_string_size(color_list);
+ s->opt[OPT_COLOR].constraint_type =3D SANE_CONSTRAINT_STRING_LIST;
+ s->opt[OPT_COLOR].constraint.string_list =3D color_list;
+ s->val[OPT_COLOR] =3D 5; /* CRT monitor */
+=20
+ /* "Misc" group: */
+=20
+ s->opt[OPT_MISC_GROUP].title =3D "Misc";
+ s->opt[OPT_MISC_GROUP].desc =3D "";
+ s->opt[OPT_MISC_GROUP].type =3D SANE_TYPE_GROUP;
+ s->opt[OPT_MISC_GROUP].cap =3D SANE_CAP_ADVANCED;
+=20
+ /* mirroring */
+ s->opt[OPT_MIRROR].name =3D "mirror";
+ s->opt[OPT_MIRROR].title =3D "Mirror Image";
+ s->opt[OPT_MIRROR].desc =3D "Mirror the image horizontally";
+ s->opt[OPT_MIRROR].type =3D SANE_TYPE_BOOL;
+ s->opt[OPT_MIRROR].size =3D sizeof(SANE_Word);
+ s->opt[OPT_MIRROR].constraint_type =3D SANE_CONSTRAINT_NONE;
+ s->val[OPT_MIRROR] =3D SANE_FALSE;
+=20
+ /* auto segmentation */
+ s->opt[OPT_AUTOSEGMENT].name =3D "aas";
+ s->opt[OPT_AUTOSEGMENT].title =3D "AAS";
+ s->opt[OPT_AUTOSEGMENT].desc =3D "AAS";
+ s->opt[OPT_AUTOSEGMENT].type =3D SANE_TYPE_BOOL;
+ s->opt[OPT_AUTOSEGMENT].size =3D sizeof(SANE_Word);
+ s->opt[OPT_AUTOSEGMENT].constraint_type =3D SANE_CONSTRAINT_NONE;
+ s->val[OPT_AUTOSEGMENT] =3D SANE_FALSE;
+ /* disable AAS control for scanners that are don't have this capability=
*/
+ if (!s->hw->cmd->s)
+ s->opt[OPT_AUTOSEGMENT].cap |=3D SANE_CAP_INACTIVE;
+=20
return SANE_STATUS_GOOD;
}
=20
***************
*** 1225,1236 ****
--- 1456,1472 ----
case OPT_TL_Y:
case OPT_BR_X:
case OPT_BR_Y:
+ case OPT_MIRROR:
+ case OPT_AUTOSEGMENT:
*(SANE_Word *) value =3D s->val[option];
break;
case OPT_MODE:
case OPT_HALFTONE:
case OPT_DROPOUT:
case OPT_BRIGHTNESS:
+ case OPT_SHARPNESS:
+ case OPT_GAMMA:
+ case OPT_COLOR:
strcpy ((char *) value,
s->opt[option].constraint.string_list[s->val[option]]);
break;
***************
*** 1284,1294 ****
if (info !=3D NULL)
*info |=3D SANE_INFO_RELOAD_PARAMS;
break;
case OPT_MODE:
if (mode_params[optval - mode_list].depth !=3D 1)
! s->opt[OPT_HALFTONE].cap |=3D SANE_CAP_INACTIVE;
else
! s->opt[OPT_HALFTONE].cap &=3D ~SANE_CAP_INACTIVE;
if (mode_params[optval - mode_list].color)
s->opt[OPT_DROPOUT].cap |=3D SANE_CAP_INACTIVE;
else
--- 1520,1556 ----
if (info !=3D NULL)
*info |=3D SANE_INFO_RELOAD_PARAMS;
break;
+ case OPT_MIRROR:
+ case OPT_AUTOSEGMENT:
+ s->val[option] =3D *(SANE_Word *) value;
+ break;
case OPT_MODE:
if (mode_params[optval - mode_list].depth !=3D 1)
! {
! s->opt[OPT_HALFTONE].cap |=3D SANE_CAP_INACTIVE;
! /*
! * We are switching to a multi-bit mode. If the=20
! * scanner is in grayscale mode, then set the default=20
! * to CRT B (multi bit). This mimics the old
! * behavior where CRT A was used for single bit and
! * CRT B for multi bit. If the user selected anything
! * else, then the gamma setting is not modified.
! */
! if (!mode_params[optval - mode_list].color)
! s->val[OPT_GAMMA] =3D 1;
! }
else
! {
! s->opt[OPT_HALFTONE].cap &=3D ~SANE_CAP_INACTIVE;
! /*
! * We are switching to a single-bit mode. Set the=20
! * default to CRT A (single bit). This mimics the old
! * behavior where CRT A was used for single bit and
! * CRT B for multi bit. If the user selected anything
! * else, then the gamma setting is not modified.
! */
! s->val[OPT_GAMMA] =3D 0;
! }
if (mode_params[optval - mode_list].color)
s->opt[OPT_DROPOUT].cap |=3D SANE_CAP_INACTIVE;
else
***************
*** 1299,1304 ****
--- 1561,1569 ----
case OPT_HALFTONE:
case OPT_DROPOUT:
case OPT_BRIGHTNESS:
+ case OPT_COLOR:
+ case OPT_GAMMA:
+ case OPT_SHARPNESS:
s->val[option] =3D optval - s->opt[option].constraint.string_list;
break;
default:
***************
*** 1410,1425 ****
DBG (1, "sane_start: set_brightness failed: %s\n", sane_strstatus (=
status));
return status;
}
! status =3D set_gamma (s, s->params.depth =3D=3D 1 ? 1 : 2);
if (status !=3D SANE_STATUS_GOOD)
{
DBG (1, "sane_start: set_gamma failed: %s\n", sane_strstatus (statu=
s));
return status;
}
! status =3D set_color (s, 0x80);
if (status !=3D SANE_STATUS_GOOD)
{
DBG (1, "sane_start: set_color failed: %s\n", sane_strstatus (statu=
s));
return status;
}
status =3D set_speed (s, mode_params[s->val[OPT_MODE]].depth =3D=3D 1 ?=
1 : 0);
--- 1675,1708 ----
DBG (1, "sane_start: set_brightness failed: %s\n", sane_strstatus (=
status));
return status;
}
! status =3D set_gamma (s, gamma_params[s->val[OPT_GAMMA]]);
if (status !=3D SANE_STATUS_GOOD)
{
DBG (1, "sane_start: set_gamma failed: %s\n", sane_strstatus (statu=
s));
return status;
}
! status =3D set_color (s, color_params[s->val[OPT_COLOR]]);
if (status !=3D SANE_STATUS_GOOD)
{
DBG (1, "sane_start: set_color failed: %s\n", sane_strstatus (statu=
s));
+ return status;
+ }
+ status =3D set_mirror (s, s->val[OPT_MIRROR]);
+ if (status !=3D SANE_STATUS_GOOD)
+ {
+ DBG (1, "sane_start: set_mirror failed: %s\n", sane_strstatus (stat=
us));
+ return status;
+ }
+ status =3D set_autosegment (s, s->val[OPT_AUTOSEGMENT]);
+ if (status !=3D SANE_STATUS_GOOD)
+ {
+ DBG (1, "sane_start: set_autosegment failed: %s\n", sane_strstatus =
(status));
+ return status;
+ }
+ status =3D set_sharpness (s, sharpness_params[s->val[OPT_SHARPNESS]]);
+ if (status !=3D SANE_STATUS_GOOD)
+ {
+ DBG (1, "sane_start: set_sharpness failed: %s\n", sane_strstatus (s=
tatus));
return status;
}
status =3D set_speed (s, mode_params[s->val[OPT_MODE]].depth =3D=3D 1 ?=
1 : 0);
*** epson.h.ORIG Sat Dec 25 09:22:41 1999
--- epson.h Sat Dec 25 19:44:03 1999
***************
*** 55,61 ****
{
char *level;
=20
! int I:1 /* request identity */
,F:1 /* request status */
,S:1 /* request condition */
,C:1 /* set color mode */
--- 55,64 ----
{
char *level;
=20
! int=20
! K:1 /* set mirroring */
! ,s:1 /* auto area segmentation */
! ,I:1 /* request identity */
,F:1 /* request status */
,S:1 /* request condition */
,C:1 /* set color mode */
***************
*** 84,95 ****
--- 87,104 ----
OPT_HALFTONE,
OPT_DROPOUT,
OPT_BRIGHTNESS,
+ OPT_GAMMA,
+ OPT_COLOR,
+ OPT_SHARPNESS,
OPT_RESOLUTION,
OPT_GEOMETRY_GROUP,
OPT_TL_X,
OPT_TL_Y,
OPT_BR_X,
OPT_BR_Y,
+ OPT_MISC_GROUP,
+ OPT_MIRROR,
+ OPT_AUTOSEGMENT,
NUM_OPTIONS
};
=20

--uAKRQypu60I7Lcqm--

--DBIVS5p969aUjpLe
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: PGP 6.5.2

iQCVAwUBOGfBVx4KmkKPBVxtAQEQSgP/R4m0PQws8kjy03dX772TTDWwxH/seE4n
6+BI78R8ZhA+DHG+QzfVFUePWVZFaF+NPRoxw2vZpnwrW7TVKutEk2NFMxjfb0qw
u8ZGkX24O+a2IPOP7/K+INxKrlJO0N8gYkYh6vobrGXlflHJxH+/tnd6TX9Fakff
uuy3jiMAQOI=
=ld5o
-----END PGP SIGNATURE-----

--DBIVS5p969aUjpLe--

--
Source code, list archive, and docs: http://www.mostang.com/sane/
To unsubscribe: echo unsubscribe sane-devel | mail majordomo@mostang.com