Merge branch 'master' of https://gitlab.com/sane-project/backends into newyearsbranch

resolve po/POTFILES.in
merge-requests/213/head^2
pimvantend 2020-03-10 20:09:49 +01:00
commit 04fc970b2e
169 zmienionych plików z 22053 dodań i 25767 usunięć

Wyświetl plik

@ -1,7 +1,3 @@
Authors of the SANE standard:
Andreas Beck and David Mosberger
Backends:
abaton: David Huggins-Daines

Wyświetl plik

@ -22,6 +22,9 @@ $ make install
- libusb-1.0.0-dev or similar
- libjpeg-dev or libjpeg8-dev or libjpeg-turbo-devel or turbojpeg-devel
- libpng-dev or similar
- libcurl4-gnutls-dev or similar
- libxml2-dev or similar
- libsnmp-dev or similar
2.2. Get the latest SANE backend from git:
You can download "daily git snapshot" from here:

Wyświetl plik

@ -30,6 +30,9 @@ terms:
to implement SANE interface conforming applications or libraries in
any way he or she sees fit.
The standard is maintained at https://gitlab.com/sane-project/standard
and published at https://sane-project.gitlab.io/standard/.
Frequently Asked Questions about the SANE licensing:
* Why don't you use the GNU LPGL ?

50
NEWS
Wyświetl plik

@ -1,5 +1,55 @@
<!-- -*- Mode: markdown -*- -->
## New with the next release
### Documentation
- removes the SANE Standard. This is now maintained as a separate
project at https://gitlab.com/sane-project/standard. HTML and PDF
versions can be found at https://sane-project.gitlab.io/standard/.
### Build
- removes the `--with-api-spec` option from `configure`
## New with 1.0.29 (released 2020-02-02)
### Backends
- adds an `escl` backend (theoretically supporting *all* AirPrint
devices with a scan unit)
- adds support for 23 new scanner models via existing backends
- significantly changes `genesys` and `pixma` backends
- fixes bugs in `canon_dr`, `fujitsu`, `hp3900`, `mustek_usb2`,
`plustek` and `xerox_mfp` backends
- fixes *all* compiler warnings on Debian 10 (#120)
- fixes portability issues for uClibc-ng and MacOS builds
- adds support to record and replay USB I/O traffic
- adds timestamps to debug logs
### Frontends
- fixes a 32-bit arithmetic overflow issue in `scanimage`
### Documentation
- updates translations for British English, Catalan, German,
Ukrainian, Valencian
- adds `scangearmp2` external backend descriptions
- updates `hpaio` and `utsushi` external backend descriptions
- adds the `ChangeLogs/` directory to the source tarball (#103)
### Build
- additionally requires `libcurl` and `libxml2` to build the `escl`
backend
- requires `libxml2` for USB I/O recording and replay functionality
- re-enables pthread support for backends that use its API directly,
irrespective of the `pthread_t` type (#153)
- moves the `genesys` and `pixma` backends to a directory of their own
## New with 1.0.28 (released 2019-07-31)
### Backends

Wyświetl plik

@ -252,21 +252,22 @@ AC_DEFUN([SANE_CHECK_PTHREAD],
[Define if pthread_t is integer.])
else
# Until the sanei_thread implementation is fixed.
have_pthread=no
use_pthread=no
fi
if test $use_pthread = yes ; then
AC_DEFINE_UNQUOTED(USE_PTHREAD, "$use_pthread",
[Define if pthreads should be used instead of forked processes.])
else
dnl Reset library in case it was found but we are not going to use it.
PTHREAD_LIBS=""
fi
if test "$have_pthread" = "yes" ; then
AM_CPPFLAGS="${AM_CPPFLAGS} -D_REENTRANT"
fi
AC_SUBST(PTHREAD_LIBS)
if test $use_pthread = yes ; then
AC_DEFINE_UNQUOTED(USE_PTHREAD, "$use_pthread",
[Define if pthreads should be used instead of forked processes.])
SANEI_THREAD_LIBS=$PTHREAD_LIBS
else
SANEI_THREAD_LIBS=""
fi
AC_SUBST(SANEI_THREAD_LIBS)
AC_MSG_CHECKING([whether to enable pthread support])
AC_MSG_RESULT([$have_pthread])
AC_MSG_CHECKING([whether to use pthread instead of fork])

3
backend/.gitignore vendored
Wyświetl plik

@ -1,5 +1,6 @@
*-s.c
*-s.cc
*-s.cpp
*.conf
.dirstamp
dll-preload.c
dll-preload.h

Wyświetl plik

@ -260,7 +260,7 @@ libagfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus
nodist_libsane_agfafocus_la_SOURCES = agfafocus-s.c
libsane_agfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus
libsane_agfafocus_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += agfafocus.conf.in
libapple_la_SOURCES = apple.c apple.h
@ -287,7 +287,7 @@ libartec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u
nodist_libsane_artec_eplus48u_la_SOURCES = artec_eplus48u-s.c
libsane_artec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u
libsane_artec_eplus48u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_artec_eplus48u_la_LIBADD = $(COMMON_LIBS) libartec_eplus48u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMEG_LIBS)
libsane_artec_eplus48u_la_LIBADD = $(COMMON_LIBS) libartec_eplus48u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMEG_LIBS)
EXTRA_DIST += artec_eplus48u.conf.in
libas6e_la_SOURCES = as6e.c as6e.h
@ -304,7 +304,7 @@ libavision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision
nodist_libsane_avision_la_SOURCES = avision-s.c
libsane_avision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision
libsane_avision_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += avision.conf.in
libbh_la_SOURCES = bh.c bh.h
@ -382,7 +382,7 @@ libcoolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan
nodist_libsane_coolscan_la_SOURCES = coolscan-s.c
libsane_coolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan
libsane_coolscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_coolscan_la_LIBADD = $(COMMON_LIBS) libcoolscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_coolscan_la_LIBADD = $(COMMON_LIBS) libcoolscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += coolscan.conf.in
libcoolscan2_la_SOURCES = coolscan2.c
@ -451,13 +451,13 @@ EXTRA_DIST += dmc.conf.in
if have_libavahi
if have_libcurl
if have_libxml2
libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c
libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c escl/escl_jpeg.c escl/escl_png.c escl/escl_tiff.c escl/escl_crop.c
libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
nodist_libsane_escl_la_SOURCES = escl-s.c
libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS)
libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(MATH_LIB) $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS)
endif
endif
endif
@ -518,6 +518,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/buffer.h genesys/buffer.cpp \
genesys/calibration.h \
genesys/command_set.h \
genesys/command_set_common.h genesys/command_set_common.cpp \
genesys/conv.h genesys/conv.cpp \
genesys/device.h genesys/device.cpp \
genesys/enums.h genesys/enums.cpp \
@ -548,7 +549,6 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/tables_gpo.cpp \
genesys/tables_model.cpp \
genesys/tables_motor.cpp \
genesys/tables_motor_profile.cpp \
genesys/tables_sensor.cpp \
genesys/test_scanner_interface.h genesys/test_scanner_interface.cpp \
genesys/test_settings.h genesys/test_settings.cpp \
@ -591,7 +591,7 @@ libhp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp
nodist_libsane_hp_la_SOURCES = hp-s.c
libsane_hp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp
libsane_hp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_hp_la_LIBADD = $(COMMON_LIBS) libhp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_hp_la_LIBADD = $(COMMON_LIBS) libhp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += hp.conf.in
# TODO: These should be moved to ../docs/hp; don't belong here.
EXTRA_DIST += hp.README hp.TODO
@ -602,7 +602,7 @@ libhp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500
nodist_libsane_hp3500_la_SOURCES = hp3500-s.c
libsane_hp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500
libsane_hp3500_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
libhp3900_la_SOURCES = hp3900.c
libhp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900
@ -794,7 +794,7 @@ libmicrotek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2
nodist_libsane_microtek2_la_SOURCES = microtek2-s.c
libsane_microtek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2
libsane_microtek2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_microtek2_la_LIBADD = $(COMMON_LIBS) libmicrotek2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_microtek2_la_LIBADD = $(COMMON_LIBS) libmicrotek2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += microtek2.conf.in
libmustek_la_SOURCES = mustek.c mustek.h
@ -803,7 +803,7 @@ libmustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek
nodist_libsane_mustek_la_SOURCES = mustek-s.c
libsane_mustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek
libsane_mustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_mustek_la_LIBADD = $(COMMON_LIBS) libmustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pa4s2.lo $(IEEE1284_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_mustek_la_LIBADD = $(COMMON_LIBS) libmustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pa4s2.lo $(IEEE1284_LIBS) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += mustek.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += mustek_scsi_pp.c mustek_scsi_pp.h
@ -836,7 +836,7 @@ libmustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2
nodist_libsane_mustek_usb2_la_SOURCES = mustek_usb2-s.c
libsane_mustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2
libsane_mustek_usb2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_mustek_usb2_la_LIBADD = $(COMMON_LIBS) libmustek_usb2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(PTHREAD_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_mustek_usb2_la_LIBADD = $(COMMON_LIBS) libmustek_usb2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(PTHREAD_LIBS) $(USB_LIBS) $(RESMGR_LIBS)
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += mustek_usb2_asic.c mustek_usb2_asic.h mustek_usb2_high.c mustek_usb2_high.h mustek_usb2_reflective.c mustek_usb2_transparent.c
@ -874,7 +874,7 @@ libpie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie
nodist_libsane_pie_la_SOURCES = pie-s.c
libsane_pie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie
libsane_pie_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += pie.conf.in
libpieusb_la_SOURCES = pieusb.h pieusb_buffer.c pieusb_buffer.h pieusb_scancmd.c pieusb_scancmd.h pieusb_specific.c pieusb_specific.h pieusb_usb.c pieusb_usb.h pieusb.c
@ -883,7 +883,7 @@ libpieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb
nodist_libsane_pieusb_la_SOURCES = pieusb-s.c
libsane_pieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb
libsane_pieusb_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_pieusb_la_LIBADD = $(COMMON_LIBS) libpieusb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo $(PTHREAD_LIBS) $(RESMGR_LIBS) $(USB_LIBS) $(MATH_LIB)
libsane_pieusb_la_LIBADD = $(COMMON_LIBS) libpieusb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) $(USB_LIBS) $(MATH_LIB)
EXTRA_DIST += pieusb.conf.in
libp5_la_SOURCES = p5.c p5.h p5_device.h
@ -903,16 +903,30 @@ libsane_pint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint
libsane_pint_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_pint_la_LIBADD = $(COMMON_LIBS) libpint.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo
libpixma_la_SOURCES = pixma.c pixma.h pixma_io_sanei.c pixma_io.h pixma_common.c pixma_common.h pixma_mp150.c pixma_mp730.c pixma_mp750.c pixma_mp800.c pixma_imageclass.c pixma_bjnp.c pixma_bjnp.h pixma_bjnp_private.h pixma_rename.h
libpixma_la_SOURCES = pixma/pixma.c \
pixma/pixma.h \
pixma/pixma_io_sanei.c \
pixma/pixma_io.h \
pixma/pixma_common.c \
pixma/pixma_common.h \
pixma/pixma_mp150.c \
pixma/pixma_mp730.c \
pixma/pixma_mp750.c \
pixma/pixma_mp800.c \
pixma/pixma_imageclass.c \
pixma/pixma_bjnp.c \
pixma/pixma_bjnp.h \
pixma/pixma_bjnp_private.h \
pixma/pixma_rename.h
libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma
nodist_libsane_pixma_la_SOURCES = pixma-s.c
libsane_pixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma
libsane_pixma_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += pixma.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += pixma_sane_options.c pixma_sane_options.h
# included in pixma.c
EXTRA_DIST += pixma/pixma_sane_options.c pixma/pixma_sane_options.h
libplustek_la_SOURCES = plustek.c plustek.h
libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek
@ -920,7 +934,7 @@ libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek
nodist_libsane_plustek_la_SOURCES = plustek-s.c
libsane_plustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek
libsane_plustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_plustek_la_LIBADD = $(COMMON_LIBS) libplustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_plustek_la_LIBADD = $(COMMON_LIBS) libplustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += plustek.conf.in
EXTRA_DIST += plustek-usb.c plustek-usb.h plustek-usbcal.c plustek-usbcalfile.c plustek-usbdevs.c plustek-usbhw.c plustek-usbimg.c plustek-usbio.c plustek-usbmap.c plustek-usbscan.c plustek-usbshading.c
@ -930,7 +944,7 @@ libplustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp
nodist_libsane_plustek_pp_la_SOURCES = plustek_pp-s.c
libsane_plustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp
libsane_plustek_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_plustek_pp_la_LIBADD = $(COMMON_LIBS) libplustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(IEEE1284_LIBS) $(PTHREAD_LIBS)
libsane_plustek_pp_la_LIBADD = $(COMMON_LIBS) libplustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(IEEE1284_LIBS) $(SANEI_THREAD_LIBS)
EXTRA_DIST += plustek_pp.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += plustek-pp_dac.c plustek-pp_dbg.h plustek-pp_detect.c plustek-pp_genericio.c plustek-pp_hwdefs.h plustek-pp_image.c plustek-pp_io.c plustek-pp_map.c plustek-pp_misc.c plustek-pp_models.c plustek-pp_motor.c plustek-pp_p12.c plustek-pp_p12ccd.c plustek-pp_p48xx.c plustek-pp_p9636.c plustek-pp_procfs.c plustek-pp_procs.h plustek-pp_ptdrv.c plustek-pp_scale.c plustek-pp_scan.h plustek-pp_scandata.h plustek-pp_sysdep.h plustek-pp_tpa.c plustek-pp_types.h plustek-pp_wrapper.c
@ -1037,7 +1051,7 @@ libsnapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan
nodist_libsane_snapscan_la_SOURCES = snapscan-s.c
libsane_snapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan
libsane_snapscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_snapscan_la_LIBADD = $(COMMON_LIBS) libsnapscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_snapscan_la_LIBADD = $(COMMON_LIBS) libsnapscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += snapscan.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += snapscan-data.c snapscan-mutex.c snapscan-options.c snapscan-scsi.c snapscan-sources.c snapscan-sources.h snapscan-usb.c snapscan-usb.h
@ -1048,7 +1062,7 @@ libsp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c
nodist_libsane_sp15c_la_SOURCES = sp15c-s.c
libsane_sp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c
libsane_sp15c_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_sp15c_la_LIBADD = $(COMMON_LIBS) libsp15c.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_sp15c_la_LIBADD = $(COMMON_LIBS) libsp15c.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += sp15c.conf.in
libst400_la_SOURCES = st400.c st400.h
@ -1075,7 +1089,7 @@ libtamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack
nodist_libsane_tamarack_la_SOURCES = tamarack-s.c
libsane_tamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack
libsane_tamarack_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_tamarack_la_LIBADD = $(COMMON_LIBS) libtamarack.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_tamarack_la_LIBADD = $(COMMON_LIBS) libtamarack.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += tamarack.conf.in
libtest_la_SOURCES = test.c test.h
@ -1084,7 +1098,7 @@ libtest_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test
nodist_libsane_test_la_SOURCES = test-s.c
libsane_test_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test
libsane_test_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_test_la_LIBADD = $(COMMON_LIBS) libtest.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_thread.lo $(PTHREAD_LIBS)
libsane_test_la_LIBADD = $(COMMON_LIBS) libtest.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_thread.lo $(SANEI_THREAD_LIBS)
EXTRA_DIST += test.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += test-picture.c
@ -1122,7 +1136,7 @@ libu12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12
nodist_libsane_u12_la_SOURCES = u12-s.c
libsane_u12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12
libsane_u12_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_u12_la_LIBADD = $(COMMON_LIBS) libu12.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_u12_la_LIBADD = $(COMMON_LIBS) libu12.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += u12.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += u12-ccd.c u12-hw.c u12-hwdef.h u12-if.c u12-image.c u12-io.c u12-map.c u12-motor.c u12-scanner.h u12-shading.c u12-tpa.c
@ -1133,7 +1147,7 @@ libumax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax
nodist_libsane_umax_la_SOURCES = umax-s.c
libsane_umax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax
libsane_umax_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_umax_la_LIBADD = $(COMMON_LIBS) libumax.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS)
libsane_umax_la_LIBADD = $(COMMON_LIBS) libumax.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += umax.conf.in
# TODO: Why are these distributed but not compiled?
EXTRA_DIST += umax-scanner.c umax-scanner.h umax-scsidef.h umax-uc1200s.c umax-uc1200se.c umax-uc1260.c umax-uc630.c umax-uc840.c umax-ug630.c umax-ug80.c umax-usb.c
@ -1212,7 +1226,7 @@ EXTRA_DIST += dll.aliases
# what backends are preloaded. It should include what is needed by
# those backends that are actually preloaded.
if preloadable_backends_enabled
PRELOADABLE_BACKENDS_LIBS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) $(XML_LIBS)
PRELOADABLE_BACKENDS_LIBS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) $(XML_LIBS)
PRELOADABLE_BACKENDS_DEPS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO)
endif
nodist_libsane_la_SOURCES = dll-s.c
@ -1221,4 +1235,4 @@ libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS)
libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_LIBS) $(DL_LIBS) $(XML_LIBS)
# WARNING: Automake is getting this wrong so have to do it ourselves.
libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_DEPS)
libsane_la_DEPENDENCIES = ../lib/liblib.la $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_DEPS)

Wyświetl plik

@ -4088,6 +4088,8 @@ get_double ( &(result[48] ) ));
dev->inquiry_button_control = BIT (result[50], 6) | BIT (result[51],2);
dev->inquiry_exposure_control = BIT(result[51],7);
if (dev->scanner_type != AV_FILM && !(dev->hw->feature_type & AV_FORCE_FILM))
dev->inquiry_exposure_control = 0;
dev->inquiry_max_shading_target = get_double ( &(result[75]) );
dev->inquiry_color_boundary = result[54];
@ -6221,7 +6223,12 @@ do_cancel (Avision_Scanner* s)
s->prepared = s->scanning = SANE_FALSE;
s->duplex_rear_valid = SANE_FALSE;
s->page = 0;
s->cancelled = 1;
s->cancelled = SANE_TRUE;
if (s->read_fds >= 0) {
close(s->read_fds);
s->read_fds = -1;
}
if (sanei_thread_is_valid (s->reader_pid)) {
int exit_status;
@ -6716,6 +6723,7 @@ reader_process (void *data)
sigset_t sigterm_set;
sigset_t ignore_set;
struct SIGACTION act;
int old;
FILE* fp;
FILE* rear_fp = 0; /* used to store the deinterlaced rear data */
@ -6757,21 +6765,30 @@ reader_process (void *data)
DBG (3, "reader_process:\n");
if (sanei_thread_is_forked())
if (sanei_thread_is_forked()) {
close (s->read_fds);
s->read_fds = -1;
sigfillset (&ignore_set);
sigdelset (&ignore_set, SIGTERM);
sigfillset (&ignore_set);
sigdelset (&ignore_set, SIGTERM);
#if defined (__APPLE__) && defined (__MACH__)
sigdelset (&ignore_set, SIGUSR2);
sigdelset (&ignore_set, SIGUSR2);
#endif
sigprocmask (SIG_SETMASK, &ignore_set, 0);
sigprocmask (SIG_SETMASK, &ignore_set, 0);
memset (&act, 0, sizeof (act));
sigaction (SIGTERM, &act, 0);
memset (&act, 0, sizeof (act));
sigaction (SIGTERM, &act, 0);
sigemptyset (&sigterm_set);
sigaddset (&sigterm_set, SIGTERM);
sigemptyset (&sigterm_set);
sigaddset (&sigterm_set, SIGTERM);
}
#ifdef USE_PTHREAD
else {
int old;
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old);
pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
}
#endif
gray_mode = color_mode_is_shaded (s->c_mode);
@ -6958,9 +6975,22 @@ reader_process (void *data)
(u_long) processed_bytes, (u_long) total_size);
DBG (5, "reader_process: this_read: %lu\n", (u_long) this_read);
sigprocmask (SIG_BLOCK, &sigterm_set, 0);
if (sanei_thread_is_forked())
sigprocmask (SIG_BLOCK, &sigterm_set, 0);
#ifdef USE_PTHREAD
else
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old);
#endif
status = read_data (s, stripe_data + stripe_fill, &this_read);
sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
if (sanei_thread_is_forked())
sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
#ifdef USE_PTHREAD
else
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old);
#endif
/* only EOF on the second stripe, as otherwise the rear page
is shorter */
@ -8332,7 +8362,7 @@ sane_start (SANE_Handle handle)
return SANE_STATUS_DEVICE_BUSY;
/* Clear cancellation status */
s->cancelled = 0;
s->cancelled = SANE_FALSE;
/* Make sure we have a current parameter set. Some of the
parameters will be overwritten below, but that's OK. */
@ -8560,8 +8590,10 @@ sane_start (SANE_Handle handle)
DBG (3, "sane_start: starting thread\n");
s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
if (sanei_thread_is_forked())
close (s->write_fds);
if (sanei_thread_is_forked()) {
close (s->write_fds);
s->write_fds = -1;
}
return SANE_STATUS_GOOD;

Wyświetl plik

@ -11,10 +11,10 @@ net
abaton
agfafocus
apple
avision
artec
artec_eplus48u
as6e
avision
bh
canon
canon630u
@ -25,33 +25,35 @@ cardscan
coolscan
#coolscan2
coolscan3
#dc25
#dc210
#dc240
#dc25
dell1600n_net
dmc
epjitsu
#epson
epson2
epsonds
escl
fujitsu
#gphoto2
genesys
#gphoto2
gt68xx
hp
hp3900
hpsj5s
hp3500
hp3900
hp4200
hp5400
hp5590
hpljm1005
hpsj5s
hs2p
ibm
kodak
kodakaio
kvs1025
kvs20xx
kvs40xx
leo
lexmark
ma1509
@ -67,6 +69,7 @@ nec
niash
#p5
pie
pieusb
pint
pixma
plustek
@ -92,7 +95,7 @@ teco3
#test
u12
umax
#umax_pp
umax1220u
#umax_pp
v4l
xerox_mfp

Wyświetl plik

@ -27,14 +27,14 @@
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <curl/curl.h>
#include "../include/sane/saneopts.h"
#include "../include/sane/sanei.h"
#include "../include/sane/sanei_backend.h"
#include "../include/sane/sanei_config.h"
#include "../include/sane/sanei_debug.h"
#define min(A,B) (((A)<(B)) ? (A) : (B))
#define max(A,B) (((A)>(B)) ? (A) : (B))
@ -54,9 +54,6 @@ typedef struct Handled {
capabilities_t *scanner;
SANE_Range x_range;
SANE_Range y_range;
unsigned char *img_data;
long img_size;
long img_read;
SANE_Bool cancel;
SANE_Bool write_scan_data;
SANE_Bool decompress_scan_data;
@ -64,18 +61,45 @@ typedef struct Handled {
SANE_Parameters ps;
} escl_sane_t;
struct my_error_mgr
static ESCL_Device *
escl_free_device(ESCL_Device *current)
{
struct jpeg_error_mgr errmgr;
jmp_buf escape;
};
if (!current) return NULL;
free((void*)current->ip_address);
free((void*)current->model_name);
free((void*)current->type);
free(current);
return NULL;
}
typedef struct
static SANE_Status
escl_check_and_add_device(ESCL_Device *current)
{
struct jpeg_source_mgr pub;
FILE *ctx;
unsigned char buffer[INPUT_BUFFER_SIZE];
} my_source_mgr;
if(!current) {
DBG (10, "ESCL_Device *current us null.\n");
return (SANE_STATUS_NO_MEM);
}
if (!current->ip_address) {
DBG (10, "Ip Address allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
if (current->port_nb == 0) {
DBG (10, "No port defined.\n");
return (SANE_STATUS_NO_MEM);
}
if (!current->model_name) {
DBG (10, "Modele Name allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
if (!current->type) {
DBG (10, "Scanner Type allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
++num_devices;
current->next = list_devices_primary;
list_devices_primary = current;
return (SANE_STATUS_GOOD);
}
/**
* \fn static SANE_Status escl_add_in_list(ESCL_Device *current)
@ -88,10 +112,18 @@ typedef struct
static SANE_Status
escl_add_in_list(ESCL_Device *current)
{
++num_devices;
current->next = list_devices_primary;
list_devices_primary = current;
return (SANE_STATUS_GOOD);
if(!current) {
DBG (10, "ESCL_Device *current us null.\n");
return (SANE_STATUS_NO_MEM);
}
if (SANE_STATUS_GOOD ==
escl_check_and_add_device(current)) {
list_devices_primary = current;
return (SANE_STATUS_GOOD);
}
current = escl_free_device(current);
return (SANE_STATUS_NO_MEM);
}
/**
@ -105,6 +137,8 @@ escl_add_in_list(ESCL_Device *current)
SANE_Status
escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type)
{
char tmp[PATH_MAX] = { 0 };
char *model = NULL;
ESCL_Device *current = NULL;
DBG (10, "escl_device_add\n");
for (current = list_devices_primary; current; current = current->next) {
@ -112,12 +146,18 @@ escl_device_add(int port_nb, const char *model_name, char *ip_address, char *typ
&& strcmp(current->type, type) == 0)
return (SANE_STATUS_GOOD);
}
current = malloc(sizeof(*current));
if (current == NULL)
return (SANE_STATUS_NO_MEM);
memset(current, 0, sizeof(*current));
current = (ESCL_Device*)calloc(1, sizeof(*current));
if (current == NULL) {
DBG (10, "New device allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
current->port_nb = port_nb;
current->model_name = strdup(model_name);
if (strcmp(type, "_uscan._tcp") != 0 && strcmp(type, "http") != 0) {
snprintf(tmp, sizeof(tmp), "%s SSL", model_name);
}
model = (char*)(tmp[0] != 0 ? tmp : model_name);
current->model_name = strdup(model);
current->ip_address = strdup(ip_address);
current->type = strdup(type);
return escl_add_in_list(current);
@ -158,18 +198,48 @@ max_string_size(const SANE_String_Const strings[])
static SANE_Device *
convertFromESCLDev(ESCL_Device *cdev)
{
SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device));
char tmp[PATH_MAX] = { 0 };
SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device));
if (!sdev) {
DBG (10, "Sane_Device allocation failure.\n");
return NULL;
}
if (strcmp(cdev->type, "_uscan._tcp") == 0 || strcmp(cdev->type, "http") == 0)
snprintf(tmp, sizeof(tmp), "http://%s:%d", cdev->ip_address, cdev->port_nb);
else
snprintf(tmp, sizeof(tmp), "https://%s:%d", cdev->ip_address, cdev->port_nb);
DBG( 1, "Escl add device : %s\n", tmp);
sdev->name = strdup(tmp);
if (!sdev->name) {
DBG (10, "Name allocation failure.\n");
goto freedev;
}
sdev->model = strdup(cdev->model_name);
if (!sdev->model) {
DBG (10, "Model allocation failure.\n");
goto freename;
}
sdev->vendor = strdup("ESCL");
if (!sdev->vendor) {
DBG (10, "Vendor allocation failure.\n");
goto freemodel;
}
sdev->type = strdup("flatbed scanner");
if (!sdev->type) {
DBG (10, "Scanner Type allocation failure.\n");
goto freevendor;
}
return (sdev);
freevendor:
free((void*)sdev->vendor);
freemodel:
free((void*)sdev->model);
freename:
free((void*)sdev->name);
freedev:
free((void*)sdev);
return NULL;
}
/**
@ -187,7 +257,7 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
DBG_INIT();
DBG (10, "escl sane_init\n");
SANE_Status status = SANE_STATUS_GOOD;
curl_global_init(CURL_GLOBAL_ALL);
if (version_code != NULL)
*version_code = SANE_VERSION_CODE(1, 0, 0);
if (status != SANE_STATUS_GOOD)
@ -217,6 +287,7 @@ sane_exit(void)
free (devlist);
list_devices_primary = NULL;
devlist = NULL;
curl_global_cleanup();
}
/**
@ -232,44 +303,52 @@ static SANE_Status
attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
{
int port = 0;
static int count = 0;
SANE_Status status;
static ESCL_Device *escl_device = NULL;
if (strncmp(line, "[device]", 8) == 0) {
count = 0;
escl_device = escl_free_device(escl_device);
escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
if (!escl_device) {
DBG (10, "New Escl_Device allocation failure.");
return (SANE_STATUS_NO_MEM);
}
}
if (strncmp(line, "ip", 2) == 0) {
const char *ip_space = sanei_config_skip_whitespace(line + 2);
DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE"));
if (escl_device != NULL && ip_space != NULL) {
count++;
DBG (10, "New Escl_Device IP Affected.");
escl_device->ip_address = strdup(ip_space);
}
}
if (sscanf(line, "port %i", &port) == 1 && port != 0) {
const char *port_space = sanei_config_skip_whitespace(line + 4);
if (escl_device != NULL && port_space != NULL) {
count++;
DBG (10, "New Escl_Device PORT [%d].", port);
if (escl_device != NULL) {
DBG (10, "New Escl_Device PORT Affected.");
escl_device->port_nb = port;
}
}
if (strncmp(line, "model", 5) == 0) {
const char *model_space = sanei_config_skip_whitespace(line + 5);
DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE"));
if (escl_device != NULL && model_space != NULL) {
count++;
DBG (10, "New Escl_Device MODEL Affected.");
escl_device->model_name = strdup(model_space);
}
}
if (strncmp(line, "type", 4) == 0) {
const char *type_space = sanei_config_skip_whitespace(line + 4);
DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE"));
if (escl_device != NULL && type_space != NULL) {
count++;
DBG (10, "New Escl_Device TYPE Affected.");
escl_device->type = strdup(type_space);
}
}
if (count == 4)
return (escl_add_in_list(escl_device));
return (SANE_STATUS_GOOD);
status = escl_check_and_add_device(escl_device);
if (status == SANE_STATUS_GOOD)
escl_device = NULL;
return status;
}
/**
@ -337,19 +416,19 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[i].size = sizeof (SANE_Word);
s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
}
s->x_range.min = 0;
s->x_range.max = s->scanner->MaxWidth - s->scanner->MinWidth;
s->x_range.quant = 1;
s->y_range.min = 0;
s->y_range.max = s->scanner->MaxHeight - s->scanner->MinHeight;
s->y_range.quant = 1;
s->x_range.min = PIXEL_TO_MM(s->scanner->MinWidth, 300.0);
s->x_range.max = PIXEL_TO_MM(s->scanner->MaxWidth, 300.0);
s->x_range.quant = 0;
s->y_range.min = PIXEL_TO_MM(s->scanner->MinHeight, 300.0);
s->y_range.max = PIXEL_TO_MM(s->scanner->MaxHeight, 300.0);
s->y_range.quant = 0;
s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
s->opt[OPT_MODE_GROUP].title = "Scan Mode";
s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE;
s->opt[OPT_MODE_GROUP].desc = "";
s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
s->opt[OPT_MODE_GROUP].cap = 0;
@ -363,8 +442,16 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
s->opt[OPT_MODE].constraint.string_list = s->scanner->ColorModes;
s->val[OPT_MODE].s = (char *)strdup(s->scanner->ColorModes[0]);
if (!s->val[OPT_MODE].s) {
DBG (10, "Color Mode Default allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
s->opt[OPT_MODE].size = max_string_size(s->scanner->ColorModes);
s->scanner->default_color = (char *)strdup(s->scanner->ColorModes[0]);
if (!s->scanner->default_color) {
DBG (10, "Color Mode Default allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
@ -389,8 +476,8 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
s->opt[OPT_GEOMETRY_GROUP].desc = "";
s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY;
s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
@ -399,37 +486,45 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
s->opt[OPT_TL_X].size = sizeof(SANE_Fixed);
s->opt[OPT_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
s->opt[OPT_TL_X].constraint.range = &s->x_range;
s->val[OPT_TL_X].w = s->scanner->RiskyLeftMargin;
s->val[OPT_TL_X].w = 0;
s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
s->opt[OPT_TL_Y].size = sizeof(SANE_Fixed);
s->opt[OPT_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
s->opt[OPT_TL_Y].constraint.range = &s->y_range;
s->val[OPT_TL_Y].w = s->scanner->RiskyTopMargin;
s->val[OPT_TL_Y].w = 0;
s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
s->opt[OPT_BR_X].size = sizeof(SANE_Fixed);
s->opt[OPT_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
s->opt[OPT_BR_X].constraint.range = &s->x_range;
s->val[OPT_BR_X].w = s->scanner->MaxWidth;
s->val[OPT_BR_X].w = s->x_range.max;
s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
s->opt[OPT_BR_Y].size = sizeof(SANE_Fixed);
s->opt[OPT_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
s->opt[OPT_BR_Y].constraint.range = &s->y_range;
s->val[OPT_BR_Y].w = s->scanner->MaxHeight;
s->val[OPT_BR_Y].w = s->y_range.max;
return (status);
}
@ -458,6 +553,10 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
if (handler == NULL)
return (SANE_STATUS_NO_MEM);
handler->name = strdup(name);
if (!handler->name) {
DBG (10, "Handle Name allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
handler->scanner = escl_capabilities(name, &status);
if (status != SANE_STATUS_GOOD)
return (status);
@ -467,8 +566,8 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
handler->ps.depth = 8;
handler->ps.last_frame = SANE_TRUE;
handler->ps.format = SANE_FRAME_RGB;
handler->ps.pixels_per_line = handler->val[OPT_BR_X].w;
handler->ps.lines = handler->val[OPT_BR_Y].w;
handler->ps.pixels_per_line = MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);
handler->ps.lines = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3;
status = sane_get_parameters(handler, 0);
if (status != SANE_STATUS_GOOD)
@ -492,7 +591,11 @@ sane_cancel(SANE_Handle h)
{
DBG (10, "escl sane_cancel\n");
escl_sane_t *handler = h;
if (handler->scanner->tmp)
{
fclose(handler->scanner->tmp);
handler->scanner->tmp = NULL;
}
handler->cancel = SANE_TRUE;
escl_scanner(handler->name, handler->result);
}
@ -528,7 +631,7 @@ sane_get_option_descriptor(SANE_Handle h, SANE_Int n)
if ((unsigned) n >= NUM_OPTIONS || n < 0)
return (0);
return (s->opt + n);
return (&s->opt[n]);
}
/**
@ -556,12 +659,12 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
return (SANE_STATUS_INVAL);
if (a == SANE_ACTION_GET_VALUE) {
switch (n) {
case OPT_NUM_OPTS:
case OPT_RESOLUTION:
case OPT_TL_X:
case OPT_TL_Y:
case OPT_BR_X:
case OPT_BR_Y:
case OPT_NUM_OPTS:
case OPT_RESOLUTION:
case OPT_PREVIEW:
case OPT_GRAY_PREVIEW:
*(SANE_Word *) v = handler->val[n].w;
@ -581,14 +684,10 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
case OPT_TL_Y:
case OPT_BR_X:
case OPT_BR_Y:
case OPT_NUM_OPTS:
case OPT_RESOLUTION:
case OPT_PREVIEW:
case OPT_GRAY_PREVIEW:
handler->val[n].w = *(SANE_Word *) v;
if (i && handler->val[n].w != *(SANE_Word *) v)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
handler->val[n].w = *(SANE_Word *) v;
break;
case OPT_RESOLUTION:
handler->val[n].w = *(SANE_Word *) v;
if (i)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
@ -597,6 +696,10 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
if (handler->val[n].s)
free (handler->val[n].s);
handler->val[n].s = strdup (v);
if (!handler->val[n].s) {
DBG (10, "OPT_MODE allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
if (i)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
break;
@ -607,43 +710,6 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
return (SANE_STATUS_GOOD);
}
#if(defined HAVE_LIBJPEG)
static void
error_exit(j_common_ptr cinfo)
{
longjmp(cinfo->client_data, 1);
}
/**
* \fn static void get_JPEG_dimension(FILE *fp, int *w, int *h)
* \brief Function that aims to get the dimensions of the jpeg image wich will be scanned.
* This function is called in the "sane_start" function.
*/
static void
get_JPEG_dimension(FILE *fp, int *w, int *h)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
jmp_buf env;
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = error_exit;
cinfo.client_data = env;
if (setjmp(env))
return;
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
jpeg_read_header(&cinfo, TRUE);
cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress(&cinfo);
*w = cinfo.output_width;
*h = cinfo.output_height;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fseek(fp, SEEK_SET, 0);
}
#endif
/**
* \fn SANE_Status sane_start(SANE_Handle h)
* \brief Function that initiates aquisition of an image from the device represented by handle 'h'.
@ -659,6 +725,7 @@ sane_start(SANE_Handle h)
escl_sane_t *handler = h;
int w = 0;
int he = 0;
int bps = 0;
if (handler->name == NULL)
return (SANE_STATUS_INVAL);
@ -666,10 +733,6 @@ sane_start(SANE_Handle h)
handler->write_scan_data = SANE_FALSE;
handler->decompress_scan_data = SANE_FALSE;
handler->end_read = SANE_FALSE;
handler->scanner->height = handler->val[OPT_BR_Y].w;
handler->scanner->width = handler->val[OPT_BR_X].w;
handler->scanner->pos_x = handler->val[OPT_TL_X].w;
handler->scanner->pos_y = handler->val[OPT_TL_Y].w;
if(handler->scanner->default_color)
free(handler->scanner->default_color);
if (handler->val[OPT_PREVIEW].w == SANE_TRUE)
@ -680,6 +743,10 @@ sane_start(SANE_Handle h)
handler->scanner->default_color = strdup("Grayscale8");
else
handler->scanner->default_color = strdup("RGB24");
if (!handler->scanner->default_color) {
DBG (10, "Default Color allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
for (i = 1; i < handler->scanner->SupportedResolutionsSize; i++)
{
if (val > handler->scanner->SupportedResolutions[i])
@ -695,18 +762,52 @@ sane_start(SANE_Handle h)
else
handler->scanner->default_color = strdup("RGB24");
}
handler->scanner->height = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
handler->scanner->width = MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);
handler->scanner->pos_x = MM_TO_PIXEL(handler->val[OPT_TL_X].w, 300.0);
handler->scanner->pos_y = MM_TO_PIXEL(handler->val[OPT_TL_Y].w, 300.0);
DBG(10, "Calculate Size Image [%dx%d|%dx%d]\n",
handler->scanner->pos_x,
handler->scanner->pos_y,
handler->scanner->height,
handler->scanner->width);
if (!handler->scanner->default_color) {
DBG (10, "Default Color allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
handler->result = escl_newjob(handler->scanner, handler->name, &status);
if (status != SANE_STATUS_GOOD)
return (status);
status = escl_scan(handler->scanner, handler->name, handler->result);
get_JPEG_dimension(handler->scanner->tmp, &w, &he);
fseek(handler->scanner->tmp, SEEK_SET, 0);
if (status != SANE_STATUS_GOOD)
return (status);
if (!strcmp(handler->scanner->default_format, "image/jpeg"))
{
status = get_JPEG_data(handler->scanner, &w, &he, &bps);
}
else if (!strcmp(handler->scanner->default_format, "image/png"))
{
status = get_PNG_data(handler->scanner, &w, &he, &bps);
}
else if (!strcmp(handler->scanner->default_format, "image/tiff"))
{
status = get_TIFF_data(handler->scanner, &w, &he, &bps);
}
else {
DBG(10, "Unknow image format\n");
return SANE_STATUS_INVAL;
}
DBG(10, "2-Size Image [%dx%d|%dx%d]\n", 0, 0, w, he);
if (status != SANE_STATUS_GOOD)
return (status);
handler->ps.depth = 8;
handler->ps.pixels_per_line = w;
handler->ps.lines = he;
handler->ps.bytes_per_line = w * 3;
handler->ps.bytes_per_line = w * bps;
handler->ps.last_frame = SANE_TRUE;
handler->ps.format = SANE_FRAME_RGB;
DBG(10, "Real Size Image [%dx%d|%dx%d]\n", 0, 0, w, he);
return (status);
}
@ -733,162 +834,11 @@ sane_get_parameters(SANE_Handle h, SANE_Parameters *p)
p->format = SANE_FRAME_RGB;
p->pixels_per_line = handler->ps.pixels_per_line;
p->lines = handler->ps.lines;
p->bytes_per_line = handler->ps.pixels_per_line * 3;
p->bytes_per_line = handler->ps.bytes_per_line;
}
return (status);
}
#if(defined HAVE_LIBJPEG)
/**
* \fn static boolean fill_input_buffer(j_decompress_ptr cinfo)
* \brief Called in the "skip_input_data" function.
*
* \return TRUE (everything is OK)
*/
static boolean
fill_input_buffer(j_decompress_ptr cinfo)
{
my_source_mgr *src = (my_source_mgr *) cinfo->src;
int nbytes = 0;
nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx);
if (nbytes <= 0) {
src->buffer[0] = (unsigned char) 0xFF;
src->buffer[1] = (unsigned char) JPEG_EOI;
nbytes = 2;
}
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = nbytes;
return (TRUE);
}
/**
* \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
* \brief Called in the "jpeg_RW_src" function.
*/
static void
skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
my_source_mgr *src = (my_source_mgr *) cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) src->pub.fill_input_buffer(cinfo);
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
static void
term_source(j_decompress_ptr __sane_unused__ cinfo)
{
return;
}
static void
init_source(j_decompress_ptr __sane_unused__ cinfo)
{
return;
}
/**
* \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx)
* \brief Called in the "escl_sane_decompressor" function.
*/
static void
jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx)
{
my_source_mgr *src;
if (cinfo->src == NULL) {
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
src = (my_source_mgr *) cinfo->src;
}
src = (my_source_mgr *) cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart;
src->pub.term_source = term_source;
src->ctx = ctx;
src->pub.bytes_in_buffer = 0;
src->pub.next_input_byte = NULL;
}
static void
my_error_exit(j_common_ptr cinfo)
{
struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
longjmp(err->escape, 1);
}
static void
output_no_message(j_common_ptr __sane_unused__ cinfo)
{
}
/**
* \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
* \brief Function that aims to decompress the jpeg image to SANE be able to read the image.
* This function is called in the "sane_read" function.
*
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_sane_decompressor(escl_sane_t *handler)
{
int start = 0;
struct jpeg_decompress_struct cinfo;
JSAMPROW rowptr[1];
unsigned char *surface = NULL;
struct my_error_mgr jerr;
int lineSize = 0;
if (handler->scanner->tmp == NULL)
return (SANE_STATUS_INVAL);
fseek(handler->scanner->tmp, SEEK_SET, 0);
start = ftell(handler->scanner->tmp);
cinfo.err = jpeg_std_error(&jerr.errmgr);
jerr.errmgr.error_exit = my_error_exit;
jerr.errmgr.output_message = output_no_message;
if (setjmp(jerr.escape)) {
jpeg_destroy_decompress(&cinfo);
if (surface != NULL)
free(surface);
return (SANE_STATUS_INVAL);
}
jpeg_create_decompress(&cinfo);
jpeg_RW_src(&cinfo, handler->scanner->tmp);
jpeg_read_header(&cinfo, TRUE);
cinfo.out_color_space = JCS_RGB;
cinfo.quantize_colors = FALSE;
jpeg_calc_output_dimensions(&cinfo);
surface = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
if (surface == NULL) {
jpeg_destroy_decompress(&cinfo);
fseek(handler->scanner->tmp, start, SEEK_SET);
return (SANE_STATUS_NO_MEM);
}
lineSize = cinfo.output_width * cinfo.output_components;
jpeg_start_decompress(&cinfo);
while (cinfo.output_scanline < cinfo.output_height) {
rowptr[0] = (JSAMPROW)surface + (lineSize * cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
}
handler->img_data = surface;
handler->img_size = lineSize * cinfo.output_height;
handler->img_read = 0;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(handler->scanner->tmp);
handler->scanner->tmp = NULL;
return (SANE_STATUS_GOOD);
}
#endif
/**
* \fn SANE_Status sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
@ -914,34 +864,31 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
if (!handler->write_scan_data)
handler->write_scan_data = SANE_TRUE;
if (!handler->decompress_scan_data) {
if (handler->scanner->tmp == NULL)
return (SANE_STATUS_INVAL);
status = escl_sane_decompressor(handler);
if (status != SANE_STATUS_GOOD)
return (status);
handler->decompress_scan_data = SANE_TRUE;
}
if (handler->img_data == NULL)
if (handler->scanner->img_data == NULL)
return (SANE_STATUS_INVAL);
if (!handler->end_read) {
readbyte = min((handler->img_size - handler->img_read), maxlen);
memcpy(buf, handler->img_data + handler->img_read, readbyte);
handler->img_read = handler->img_read + readbyte;
readbyte = min((handler->scanner->img_size - handler->scanner->img_read), maxlen);
memcpy(buf, handler->scanner->img_data + handler->scanner->img_read, readbyte);
handler->scanner->img_read = handler->scanner->img_read + readbyte;
*len = readbyte;
if (handler->img_read == handler->img_size)
if (handler->scanner->img_read == handler->scanner->img_size)
handler->end_read = SANE_TRUE;
else if (handler->img_read > handler->img_size) {
else if (handler->scanner->img_read > handler->scanner->img_size) {
*len = 0;
handler->end_read = SANE_TRUE;
free(handler->img_data);
handler->img_data = NULL;
free(handler->scanner->img_data);
handler->scanner->img_data = NULL;
return (SANE_STATUS_INVAL);
}
}
else {
*len = 0;
free(handler->img_data);
handler->img_data = NULL;
free(handler->scanner->img_data);
handler->scanner->img_data = NULL;
return (SANE_STATUS_EOF);
}
return (SANE_STATUS_GOOD);

Wyświetl plik

@ -43,11 +43,25 @@
#include "../include/sane/sane.h"
#include <stdio.h>
#include <math.h>
#ifndef BACKEND_NAME
#define BACKEND_NAME escl
#endif
#define DEBUG_NOT_STATIC
#include "../include/sane/sanei_debug.h"
#ifndef DBG_LEVEL
#define DBG_LEVEL PASTE(sanei_debug_, BACKEND_NAME)
#endif
#ifndef NDEBUG
# define DBGDUMP(level, buf, size) \
do { if (DBG_LEVEL >= (level)) sanei_escl_dbgdump(buf, size); } while (0)
#else
# define DBGDUMP(level, buf, size)
#endif
#define ESCL_CONFIG_FILE "escl.conf"
typedef struct {
@ -78,7 +92,7 @@ typedef struct capabilities
int pos_x;
int pos_y;
SANE_String default_color;
SANE_String_Const default_format;
SANE_String default_format;
SANE_Int default_resolution;
int MinWidth;
int MaxWidth;
@ -102,6 +116,9 @@ typedef struct capabilities
int RiskyTopMargin;
int RiskyBottomMargin;
FILE *tmp;
unsigned char *img_data;
long img_size;
long img_read;
int format_ext;
} capabilities_t;
@ -135,12 +152,30 @@ enum
NUM_OPTIONS
};
#define PIXEL_TO_MM(pixels, dpi) SANE_FIX((double)pixels * 25.4 / (dpi))
#define MM_TO_PIXEL(millimeters, dpi) (SANE_Word)round(SANE_UNFIX(millimeters) * (dpi) / 25.4)
ESCL_Device *escl_devices(SANE_Status *status);
SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type);
SANE_Status escl_device_add(int port_nb, const char *model_name,
char *ip_address, char *type);
SANE_Status escl_status(SANE_String_Const name);
capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, SANE_String_Const name, SANE_Status *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result);
char *escl_newjob(capabilities_t *scanner, SANE_String_Const name,
SANE_Status *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name,
char *result);
void escl_scanner(SANE_String_Const name, char *result);
unsigned char *escl_crop_surface(capabilities_t *scanner, unsigned char *surface,
int w, int h, int bps, int *width, int *height);
// JPEG
SANE_Status get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps);
// PNG
SANE_Status get_PNG_data(capabilities_t *scanner, int *width, int *height, int *bps);
// TIFF
SANE_Status get_TIFF_data(capabilities_t *scanner, int *width, int *height, int *bps);
#endif

Wyświetl plik

@ -21,6 +21,8 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
@ -181,7 +183,34 @@ find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner)
else if (strcmp(name, "ContentType") == 0)
scanner->ContentTypes = char_to_array(scanner->ContentTypes, &scanner->ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
else if (strcmp(name, "DocumentFormat") == 0)
{
int i = 0;
scanner->DocumentFormats = char_to_array(scanner->DocumentFormats, &scanner->DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
for(; i < scanner->DocumentFormatsSize; i++)
{
if (scanner->default_format == NULL && !strcmp(scanner->DocumentFormats[i], "image/jpeg"))
{
scanner->default_format = strdup("image/jpeg");
}
#if(defined HAVE_LIBPNG)
else if(!strcmp(scanner->DocumentFormats[i], "image/png") && (scanner->default_format == NULL || strcmp(scanner->default_format, "image/tiff")))
{
if (scanner->default_format)
free(scanner->default_format);
scanner->default_format = strdup("image/png");
}
#endif
#if(defined HAVE_TIFFIO_H)
else if(!strcmp(scanner->DocumentFormats[i], "image/tiff"))
{
if (scanner->default_format)
free(scanner->default_format);
scanner->default_format = strdup("image/tiff");
}
#endif
}
fprintf(stderr, "Capability : [%s]\n", scanner->default_format);
}
else if (strcmp(name, "DocumentFormatExt") == 0)
scanner->format_ext = 1;
else if (strcmp(name, "Intent") == 0)
@ -316,19 +345,20 @@ escl_capabilities(SANE_String_Const name, SANE_Status *status)
*status = SANE_STATUS_NO_MEM;
var->memory = malloc(1);
var->size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_capabilities);
DBG( 1, "Get Capabilities : %s\n", tmp);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
fprintf(stderr, "THERE IS NO SCANNER\n");
DBG( 1, "The scanner didn't respond.\n");
*status = SANE_STATUS_INVAL;
}
data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0);
@ -343,6 +373,5 @@ escl_capabilities(SANE_String_Const name, SANE_Status *status)
xmlMemoryDump();
curl_easy_cleanup(curl_handle);
free(var->memory);
curl_global_cleanup();
return (scanner);
}

Wyświetl plik

@ -0,0 +1,89 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char *
escl_crop_surface(capabilities_t *scanner,
unsigned char *surface,
int w,
int h,
int bps,
int *width,
int *height)
{
int x_off = 0, x = 0;
int real_w = 0;
int y_off = 0, y = 0;
int real_h = 0;
unsigned char *surface_crop = NULL;
DBG( 1, "Escl Image Crop\n");
if (w < (int)scanner->width)
scanner->width = w;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
if (h < (int)scanner->height)
scanner->height = h;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
x_off = scanner->pos_x;
real_w = scanner->width - x_off;
y_off = scanner->pos_y;
real_h = scanner->height - y_off;
*width = real_w;
*height = real_h;
if (x_off > 0 || real_w < scanner->width ||
y_off > 0 || real_h < scanner->height) {
surface_crop = (unsigned char *)malloc (sizeof (unsigned char) * real_w
* real_h * bps);
if(!surface_crop) {
DBG( 1, "Escl Crop : Surface_crop Memory allocation problem\n");
free(surface);
surface = NULL;
goto finish;
}
for (y = 0; y < real_h; y++)
{
for (x = 0; x < real_w; x++)
{
surface_crop[y * real_w + x] = surface[(y + y_off) * w + x + x_off];
}
}
free(surface);
surface = surface_crop;
}
// we don't need row pointers anymore
scanner->img_data = surface;
scanner->img_size = (int)(real_w * real_h * bps);
scanner->img_read = 0;
finish:
return surface;
}

Wyświetl plik

@ -21,6 +21,9 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <assert.h>
@ -142,21 +145,21 @@ escl_devices(SANE_Status *status)
*status = SANE_STATUS_GOOD;
if (!(simple_poll = avahi_simple_poll_new())) {
fprintf(stderr, "Failed to create simple poll object.\n");
DBG( 1, "Failed to create simple poll object.\n");
*status = SANE_STATUS_INVAL;
goto fail;
}
client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0,
client_callback, NULL, &error);
if (!client) {
fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
DBG( 1, "Failed to create client: %s\n", avahi_strerror(error));
*status = SANE_STATUS_INVAL;
goto fail;
}
if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, "_uscan._tcp",
NULL, 0, browse_callback, client))) {
fprintf(stderr, "Failed to create service browser: %s\n",
DBG( 1, "Failed to create service browser: %s\n",
avahi_strerror(avahi_client_errno(client)));
*status = SANE_STATUS_INVAL;
goto fail;
@ -165,7 +168,7 @@ escl_devices(SANE_Status *status)
AVAHI_PROTO_UNSPEC,
"_uscans._tcp", NULL, 0,
browse_callback, client))) {
fprintf(stderr, "Failed to create service browser: %s\n",
DBG( 1, "Failed to create service browser: %s\n",
avahi_strerror(avahi_client_errno(client)));
*status = SANE_STATUS_INVAL;
goto fail;

Wyświetl plik

@ -0,0 +1,255 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include "../include/sane/sanei.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if(defined HAVE_LIBJPEG)
# include <jpeglib.h>
#endif
#include <setjmp.h>
#define INPUT_BUFFER_SIZE 4096
#if(defined HAVE_LIBJPEG)
struct my_error_mgr
{
struct jpeg_error_mgr errmgr;
jmp_buf escape;
};
typedef struct
{
struct jpeg_source_mgr pub;
FILE *ctx;
unsigned char buffer[INPUT_BUFFER_SIZE];
} my_source_mgr;
/**
* \fn static boolean fill_input_buffer(j_decompress_ptr cinfo)
* \brief Called in the "skip_input_data" function.
*
* \return TRUE (everything is OK)
*/
static boolean
fill_input_buffer(j_decompress_ptr cinfo)
{
my_source_mgr *src = (my_source_mgr *) cinfo->src;
int nbytes = 0;
nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx);
if (nbytes <= 0) {
src->buffer[0] = (unsigned char) 0xFF;
src->buffer[1] = (unsigned char) JPEG_EOI;
nbytes = 2;
}
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = nbytes;
return (TRUE);
}
/**
* \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
* \brief Called in the "jpeg_RW_src" function.
*/
static void
skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
my_source_mgr *src = (my_source_mgr *) cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) src->pub.fill_input_buffer(cinfo);
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
static void
term_source(j_decompress_ptr __sane_unused__ cinfo)
{
return;
}
static void
init_source(j_decompress_ptr __sane_unused__ cinfo)
{
return;
}
/**
* \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx)
* \brief Called in the "escl_sane_decompressor" function.
*/
static void
jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx)
{
my_source_mgr *src;
if (cinfo->src == NULL) {
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
src = (my_source_mgr *) cinfo->src;
}
src = (my_source_mgr *) cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart;
src->pub.term_source = term_source;
src->ctx = ctx;
src->pub.bytes_in_buffer = 0;
src->pub.next_input_byte = NULL;
}
static void
my_error_exit(j_common_ptr cinfo)
{
struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
longjmp(err->escape, 1);
}
static void
output_no_message(j_common_ptr __sane_unused__ cinfo)
{
}
/**
* \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
* \brief Function that aims to decompress the jpeg image to SANE be able to read the image.
* This function is called in the "sane_read" function.
*
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
int start = 0;
struct jpeg_decompress_struct cinfo;
JSAMPROW rowptr[1];
unsigned char *surface = NULL;
struct my_error_mgr jerr;
int lineSize = 0;
JDIMENSION x_off = 0;
JDIMENSION y_off = 0;
JDIMENSION w = 0;
JDIMENSION h = 0;
int pos = 0;
if (scanner->tmp == NULL)
return (SANE_STATUS_INVAL);
fseek(scanner->tmp, SEEK_SET, 0);
start = ftell(scanner->tmp);
cinfo.err = jpeg_std_error(&jerr.errmgr);
jerr.errmgr.error_exit = my_error_exit;
jerr.errmgr.output_message = output_no_message;
if (setjmp(jerr.escape)) {
jpeg_destroy_decompress(&cinfo);
if (surface != NULL)
free(surface);
fseek(scanner->tmp, start, SEEK_SET);
DBG( 1, "Escl Jpeg : Error reading jpeg\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
}
jpeg_create_decompress(&cinfo);
jpeg_RW_src(&cinfo, scanner->tmp);
jpeg_read_header(&cinfo, TRUE);
cinfo.out_color_space = JCS_RGB;
cinfo.quantize_colors = FALSE;
jpeg_calc_output_dimensions(&cinfo);
if (cinfo.output_width < (unsigned int)scanner->width)
scanner->width = cinfo.output_width;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
if (cinfo.output_height < (unsigned int)scanner->height)
scanner->height = cinfo.output_height;
if (scanner->pos_y < 0)
scanner->pos_y = 0;
x_off = scanner->pos_x;
w = scanner->width - x_off;
y_off = scanner->pos_y;
h = scanner->height - y_off;
surface = malloc(w * h * cinfo.output_components);
if (surface == NULL) {
jpeg_destroy_decompress(&cinfo);
DBG( 1, "Escl Jpeg : Memory allocation problem\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_NO_MEM);
}
jpeg_start_decompress(&cinfo);
if (x_off > 0 || w < cinfo.output_width)
jpeg_crop_scanline(&cinfo, &x_off, &w);
lineSize = w * cinfo.output_components;
if (y_off > 0)
jpeg_skip_scanlines(&cinfo, y_off);
pos = 0;
while (cinfo.output_scanline < (unsigned int)scanner->height) {
rowptr[0] = (JSAMPROW)surface + (lineSize * pos); // ..cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
pos++;
}
scanner->img_data = surface;
scanner->img_size = lineSize * h;
scanner->img_read = 0;
*width = w;
*height = h;
*bps = cinfo.output_components;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(scanner->tmp);
scanner->tmp = NULL;
return (SANE_STATUS_GOOD);
}
#else
SANE_Status
get_JPEG_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);
}
#endif

Wyświetl plik

@ -21,6 +21,9 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdio.h>
@ -29,6 +32,12 @@
#include <curl/curl.h>
#ifdef PATH_MAX
# undef PATH_MAX
#endif
#define PATH_MAX 4096
struct uploading
{
const char *read_data;
@ -54,7 +63,7 @@ static const char settings[] =
" <pwg:YOffset>%d</pwg:YOffset>" \
" </pwg:ScanRegion>" \
" </pwg:ScanRegions>" \
" <pwg:DocumentFormat>image/jpeg</pwg:DocumentFormat>" \
" <pwg:DocumentFormat>%s</pwg:DocumentFormat>" \
"%s" \
" <scan:ColorMode>%s</scan:ColorMode>" \
" <scan:XResolution>%d</scan:XResolution>" \
@ -62,9 +71,15 @@ static const char settings[] =
" <pwg:InputSource>Platen</pwg:InputSource>" \
"</scan:ScanSettings>";
static const char formatExt[] =
static char formatExtJPEG[] =
" <scan:DocumentFormatExt>image/jpeg</scan:DocumentFormatExt>";
static char formatExtPNG[] =
" <scan:DocumentFormatExt>image/png</scan:DocumentFormatExt>";
static char formatExtTIFF[] =
" <scan:DocumentFormatExt>image/tiff</scan:DocumentFormatExt>";
/**
* \fn static size_t download_callback(void *str, size_t size, size_t nmemb, void *userp)
* \brief Callback function that stocks in memory the content of the 'job'. Example below :
@ -96,7 +111,7 @@ download_callback(void *str, size_t size, size_t nmemb, void *userp)
char *content = realloc(download->memory, download->size + realsize + 1);
if (content == NULL) {
fprintf(stderr, "not enough memory (realloc returned NULL)\n");
DBG( 1, "Not enough memory (realloc returned NULL)\n");
return (0);
}
download->memory = content;
@ -127,30 +142,48 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
char *location = NULL;
char *result = NULL;
char *temporary = NULL;
char *f_ext = "";
char *format_ext = NULL;
*status = SANE_STATUS_GOOD;
if (name == NULL || scanner == NULL) {
*status = SANE_STATUS_NO_MEM;
DBG( 1, "Create NewJob : the name or the scan are invalid.\n");
return (NULL);
}
upload = (struct uploading *)calloc(1, sizeof(struct uploading));
if (upload == NULL) {
*status = SANE_STATUS_NO_MEM;
DBG( 1, "Create NewJob : memory allocation failure\n");
return (NULL);
}
download = (struct downloading *)calloc(1, sizeof(struct downloading));
if (download == NULL) {
free(upload);
DBG( 1, "Create NewJob : memory allocation failure\n");
*status = SANE_STATUS_NO_MEM;
return (NULL);
}
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
if (scanner->format_ext == 1)
{
if (!strcmp(scanner->default_format, "image/jpeg"))
format_ext = formatExtJPEG;
else if (!strcmp(scanner->default_format, "image/png"))
format_ext = formatExtPNG;
else if (!strcmp(scanner->default_format, "image/tiff"))
format_ext = formatExtTIFF;
else
format_ext = f_ext;
}
else
format_ext = f_ext;
DBG( 1, "Create NewJob : %s\n", scanner->default_format);
if (curl_handle != NULL) {
snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0,
(scanner->format_ext == 1 ? formatExt : ""),
snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0, scanner->default_format,
format_ext,
scanner->default_color, scanner->default_resolution, scanner->default_resolution);
//fprintf(stderr, "CAP_DATA = %s\n", cap_data);
DBG( 1, "Create NewJob : %s\n", cap_data);
upload->read_data = strdup(cap_data);
upload->size = strlen(cap_data);
download->memory = malloc(1);
@ -168,37 +201,44 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, download_callback);
curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)download);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
fprintf(stderr, "THERE IS NO SCANNER\n");
DBG( 1, "Create NewJob : the scanner responded incorrectly.\n");
*status = SANE_STATUS_INVAL;
}
else {
if (download->memory != NULL) {
if (strstr(download->memory, "Location:")) {
temporary = strrchr(download->memory, '/');
char *tmp_location = strstr(download->memory, "Location:");
if (tmp_location) {
temporary = strchr(tmp_location, '\r');
if (temporary == NULL)
temporary = strchr(tmp_location, '\n');
if (temporary != NULL) {
location = strchr(temporary, '\r');
if (location == NULL)
location = strchr(temporary, '\n');
else {
*location = '\0';
result = strdup(temporary);
}
*temporary = '\0';
location = strrchr(tmp_location,'/');
if (location) {
result = strdup(location);
DBG( 1, "Create NewJob : %s\n", result);
*temporary = '\n';
}
}
if (result == NULL) {
DBG( 1, "Error : Create NewJob, no location\n");
*status = SANE_STATUS_INVAL;
}
free(download->memory);
}
else {
fprintf(stderr, "THERE IS NO LOCATION\n");
DBG( 1, "Create NewJob : The creation of the failed job\n");
*status = SANE_STATUS_INVAL;
}
}
else {
*status = SANE_STATUS_NO_MEM;
DBG( 1, "Create NewJob : The creation of the failed job\n");
return (NULL);
}
}
curl_easy_cleanup(curl_handle);
}
curl_global_cleanup();
if (upload != NULL)
free(upload);
if (download != NULL)

Wyświetl plik

@ -0,0 +1,196 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include "../include/sane/sanei.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if(defined HAVE_LIBPNG)
#include <png.h>
#endif
#include <setjmp.h>
#if(defined HAVE_LIBPNG)
/**
* \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
* \brief Function that aims to decompress the png image to SANE be able to read the image.
* This function is called in the "sane_read" function.
*
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_PNG_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
unsigned int w = 0;
unsigned int h = 0;
int components = 3;
unsigned char *surface = NULL; /* Image data */
unsigned int i = 0;
png_byte magic[8];
SANE_Status status = SANE_STATUS_GOOD;
// read magic number
fread (magic, 1, sizeof (magic), scanner->tmp);
// check for valid magic number
if (!png_check_sig (magic, sizeof (magic)))
{
DBG( 1, "Escl Png : PNG error is not a valid PNG image!\n");
status = SANE_STATUS_INVAL;
goto close_file;
}
// create a png read struct
png_structp png_ptr = png_create_read_struct
(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
DBG( 1, "Escl Png : PNG error create a png read struct\n");
status = SANE_STATUS_INVAL;
goto close_file;
}
// create a png info struct
png_infop info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
{
DBG( 1, "Escl Png : PNG error create a png info struct\n");
png_destroy_read_struct (&png_ptr, NULL, NULL);
status = SANE_STATUS_INVAL;
goto close_file;
}
// initialize the setjmp for returning properly after a libpng
// error occured
if (setjmp (png_jmpbuf (png_ptr)))
{
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
if (surface)
free (surface);
DBG( 1, "Escl Png : PNG read error.\n");
status = SANE_STATUS_INVAL;
goto close_file;
}
// setup libpng for using standard C fread() function
// with our FILE pointer
png_init_io (png_ptr, scanner->tmp);
// tell libpng that we have already read the magic number
png_set_sig_bytes (png_ptr, sizeof (magic));
// read png info
png_read_info (png_ptr, info_ptr);
int bit_depth, color_type;
// get some usefull information from header
bit_depth = png_get_bit_depth (png_ptr, info_ptr);
color_type = png_get_color_type (png_ptr, info_ptr);
// convert index color images to RGB images
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb (png_ptr);
else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA)
{
DBG(1, "PNG format not supported.\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
components = 4;
else
components = 3;
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
else if (bit_depth < 8)
png_set_packing (png_ptr);
// update info structure to apply transformations
png_read_update_info (png_ptr, info_ptr);
// retrieve updated information
png_get_IHDR (png_ptr, info_ptr,
(png_uint_32*)(&w),
(png_uint_32*)(&h),
&bit_depth, &color_type,
NULL, NULL, NULL);
*bps = components;
// we can now allocate memory for storing pixel data
surface = (unsigned char *)malloc (sizeof (unsigned char) * w
* h * components);
if (!surface) {
DBG( 1, "Escl Png : texels Memory allocation problem\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
png_bytep *row_pointers;
// setup a pointer array. Each one points at the begening of a row.
row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * h);
if (!row_pointers) {
DBG( 1, "Escl Png : row_pointers Memory allocation problem\n");
free(surface);
status = SANE_STATUS_NO_MEM;
goto close_file;
}
for (i = 0; i < h; ++i)
{
row_pointers[i] = (png_bytep)(surface +
((h - (i + 1)) * w * components));
}
// read pixel data using row pointers
png_read_image (png_ptr, row_pointers);
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, w, h, components, width, height);
if (!surface) {
DBG( 1, "Escl Png : Surface Memory allocation problem\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
free (row_pointers);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return (status);
}
#else
SANE_Status
get_PNG_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);
}
#endif

Wyświetl plik

@ -21,6 +21,9 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdlib.h>
@ -45,7 +48,6 @@ escl_scanner(SANE_String_Const name, char *result)
if (name == NULL || result == NULL)
return;
curl_global_init(CURL_GLOBAL_ALL);
CURL_CALL:
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
@ -54,7 +56,9 @@ CURL_CALL:
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
DBG( 1, "Reset Job : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
@ -68,5 +72,4 @@ CURL_CALL:
}
curl_easy_cleanup(curl_handle);
}
curl_global_cleanup();
}

Wyświetl plik

@ -21,6 +21,9 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdio.h>
@ -65,7 +68,6 @@ escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char
if (name == NULL)
return (SANE_STATUS_NO_MEM);
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
strcpy(scan_cmd, name);
@ -73,7 +75,9 @@ escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Scan : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
@ -90,7 +94,6 @@ escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char
}
else
status = SANE_STATUS_NO_MEM;
curl_global_cleanup();
}
return (status);
}

Wyświetl plik

@ -21,6 +21,9 @@
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdio.h>
@ -50,7 +53,7 @@ memory_callback_s(void *contents, size_t size, size_t nmemb, void *userp)
char *str = realloc(mem->memory, mem->size + realsize + 1);
if (str == NULL) {
fprintf(stderr, "not enough memory (realloc returned NULL)\n");
DBG(1, "not enough memory (realloc returned NULL)\n");
return (0);
}
mem->memory = str;
@ -132,19 +135,20 @@ escl_status(SANE_String_Const name)
return (SANE_STATUS_NO_MEM);
var->memory = malloc(1);
var->size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
DBG( 1, "Get Status : %s.\n", tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
fprintf(stderr, "THERE IS NO SCANNER\n");
DBG( 1, "The scanner didn't respond.\n");
status = SANE_STATUS_INVAL;
goto clean_data;
}
@ -168,6 +172,5 @@ clean_data:
curl_easy_cleanup(curl_handle);
free(var->memory);
free(var);
curl_global_cleanup();
return (status);
}

Wyświetl plik

@ -0,0 +1,118 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include "../include/sane/sanei.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if(defined HAVE_TIFFIO_H)
#include <tiffio.h>
#endif
#include <setjmp.h>
#if(defined HAVE_TIFFIO_H)
/**
* \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
* \brief Function that aims to decompress the png image to SANE be able to read the image.
* This function is called in the "sane_read" function.
*
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_TIFF_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
TIFF* tif = NULL;
uint32 w = 0;
uint32 h = 0;
unsigned char *surface = NULL; /* image data*/
int components = 4;
uint32 npixels = 0;
SANE_Status status = SANE_STATUS_GOOD;
lseek(fileno(scanner->tmp), 0, SEEK_SET);
tif = TIFFFdOpen(fileno(scanner->tmp), "temp", "r");
if (!tif) {
DBG( 1, "Escl Tiff : Can not open, or not a TIFF file.\n");
status = SANE_STATUS_INVAL;
goto close_file;
}
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
surface = (unsigned char*) malloc(npixels * sizeof (uint32));
if (surface != NULL)
{
DBG( 1, "Escl Tiff : raster Memory allocation problem.\n");
status = SANE_STATUS_INVAL;
goto close_tiff;
}
if (!TIFFReadRGBAImage(tif, w, h, (uint32 *)surface, 0))
{
DBG( 1, "Escl Tiff : Problem reading image data.\n");
status = SANE_STATUS_INVAL;
free(surface);
goto close_tiff;
}
*bps = components;
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, w, h, components, width, height);
if (!surface) {
DBG( 1, "Escl Tiff : Surface Memory allocation problem\n");
status = SANE_STATUS_INVAL;
}
close_tiff:
TIFFClose(tif);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return (status);
}
#else
SANE_Status
get_TIFF_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *w,
int __sane_unused__ *h,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);
}
#endif

Wyświetl plik

@ -383,6 +383,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define get_IN_op_halt(in) getbitfield(in+0x7a, 1, 7)
#define get_IN_return_path(in) getbitfield(in+0x7c, 1, 7)
#define get_IN_energy_star3(in) getbitfield(in+0x7c, 1, 6)
/* ==================================================================== */
/* page codes used by mode_sense and mode_select */
#define MS_pc_unk 0x2c /* Used by iX500 */
@ -763,6 +766,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define get_GHS_fb_open(in) getbitfield(in+0x03, 1, 3)
#define get_GHS_paper_end(in) getbitfield(in+0x03, 1, 2)
#define get_GHS_fb_on(in) getbitfield(in+0x03, 1, 1)
#define get_GHS_exit(in) getbitfield(in+0x03, 1, 0)
#define get_GHS_sleep(in) getbitfield(in+0x04, 1, 7)
#define get_GHS_clean(in) getbitfield(in+0x04, 1, 6)
@ -823,7 +827,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define SCANNER_CONTROL_len 10
#define set_SC_ric(icb, val) setbitfield(icb + 1, 1, 4, val)
#define set_SC_function(icb, val) setbitfield(icb + 1, 0xf, 0, val)
#define set_SC_function_1(icb, val) setbitfield(icb + 1, 0xf, 0, val)
#define set_SC_function_2(icb, val) icb[2] = (val >> 4)
#define SC_function_adf 0x00
#define SC_function_fb 0x01
#define SC_function_fb_hs 0x02
@ -836,6 +841,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define SC_function_scan_complete 0x09
#define SC_function_eject_complete 0x0a
#define SC_function_manual_feed 0x0c
#define SC_function_mfeed 0x0f
#define SC_function_continuous 0x1f
#define SC_function_rpath 0x2f
/* used with SC_function_panel */
#define set_SC_led_eb(icb, val) setbitfield(icb + 5, 1, 7, val)

Wyświetl plik

@ -603,8 +603,12 @@
v134 2019-02-23, MAN
- rewrite init_vpd for scanners which fail to report
overscan correctly
v135 2019-11-10, MAN
v135 2019-11-10, MAN (SANE 1.0.29)
- set has_MS_lamp=0 for fi-72x0, bug #134
v136 2020-02-07, MAN
- add support for fi-800R
- add support for card scanning slot (Return Path)
- fix bug with reading hardware sensors on first invocation
SANE FLOW DIAGRAM
@ -654,7 +658,7 @@
#include "fujitsu.h"
#define DEBUG 1
#define BUILD 134
#define BUILD 136
/* values for SANE_DEBUG_FUJITSU env var:
- errors 5
@ -678,6 +682,9 @@
#define STRING_ADFFRONT SANE_I18N("ADF Front")
#define STRING_ADFBACK SANE_I18N("ADF Back")
#define STRING_ADFDUPLEX SANE_I18N("ADF Duplex")
#define STRING_CARDFRONT SANE_I18N("Card Front")
#define STRING_CARDBACK SANE_I18N("Card Back")
#define STRING_CARDDUPLEX SANE_I18N("Card Duplex")
#define STRING_LINEART SANE_VALUE_SCAN_MODE_LINEART
#define STRING_HALFTONE SANE_VALUE_SCAN_MODE_HALFTONE
@ -1821,6 +1828,12 @@ init_vpd (struct fujitsu *s)
DBG (15, " object position halt: %d\n", s->has_op_halt);
}
if (payload_off >= 0x7c) {
s->has_return_path = get_IN_return_path(in);
DBG (15, " return path (card) scanning: %d\n", s->has_return_path);
DBG (15, " energy star 3: %d\n", get_IN_energy_star3(in));
}
DBG (10, "init_vpd: finish\n");
return SANE_STATUS_GOOD;
@ -2498,6 +2511,8 @@ init_user (struct fujitsu *s)
s->source = SOURCE_FLATBED;
else if(s->has_adf)
s->source = SOURCE_ADF_FRONT;
else if(s->has_return_path)
s->source = SOURCE_CARD_FRONT;
/* scan mode */
if(s->can_mode[MODE_LINEART])
@ -2875,6 +2890,16 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
s->source_list[i++]=STRING_ADFDUPLEX;
}
}
if(s->has_return_path){
s->source_list[i++]=STRING_CARDFRONT;
if(s->has_back){
s->source_list[i++]=STRING_CARDBACK;
}
if(s->has_duplex){
s->source_list[i++]=STRING_CARDDUPLEX;
}
}
s->source_list[i]=NULL;
opt->name = SANE_NAME_SCAN_SOURCE;
@ -3049,7 +3074,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &s->paper_x_range;
if(s->has_adf){
if(s->has_adf || s->has_return_path){
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
if(s->source == SOURCE_FLATBED){
opt->cap |= SANE_CAP_INACTIVE;
@ -3076,7 +3101,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &s->paper_y_range;
if(s->has_adf){
if(s->has_adf || s->has_return_path){
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
if(s->source == SOURCE_FLATBED){
opt->cap |= SANE_CAP_INACTIVE;
@ -4474,6 +4499,18 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->cap = SANE_CAP_INACTIVE;
}
if(option==OPT_CARD_LOADED){
opt->name = "card-loaded";
opt->title = SANE_I18N ("Card loaded");
opt->desc = SANE_I18N ("Card slot contains paper");
opt->type = SANE_TYPE_BOOL;
opt->unit = SANE_UNIT_NONE;
if (s->has_cmd_hw_status && s->has_return_path)
opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
else
opt->cap = SANE_CAP_INACTIVE;
}
if(option==OPT_SLEEP){
opt->name = "power-save";
opt->title = SANE_I18N ("Power saving");
@ -4697,6 +4734,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
else if(s->source == SOURCE_ADF_DUPLEX){
strcpy (val, STRING_ADFDUPLEX);
}
else if(s->source == SOURCE_CARD_FRONT){
strcpy (val, STRING_CARDFRONT);
}
else if(s->source == SOURCE_CARD_BACK){
strcpy (val, STRING_CARDBACK);
}
else if(s->source == SOURCE_CARD_DUPLEX){
strcpy (val, STRING_CARDDUPLEX);
}
return SANE_STATUS_GOOD;
case OPT_MODE:
@ -5215,6 +5261,11 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
*val_p = s->hw_adf_open;
return ret;
case OPT_CARD_LOADED:
ret = get_hardware_status(s,option);
*val_p = s->hw_card_loaded;
return ret;
case OPT_SLEEP:
ret = get_hardware_status(s,option);
*val_p = s->hw_sleep;
@ -5323,6 +5374,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
else if (!strcmp (val, STRING_ADFDUPLEX)) {
tmp = SOURCE_ADF_DUPLEX;
}
else if (!strcmp (val, STRING_CARDFRONT)) {
tmp = SOURCE_CARD_FRONT;
}
else if (!strcmp (val, STRING_CARDBACK)) {
tmp = SOURCE_CARD_BACK;
}
else if (!strcmp (val, STRING_CARDDUPLEX)) {
tmp = SOURCE_CARD_DUPLEX;
}
else{
tmp = SOURCE_FLATBED;
}
@ -5912,12 +5972,12 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
/* only run this if frontend has already read the last time we got it */
/* or if we don't care for such bookkeeping (private use) */
if (!option || s->hw_read[option-OPT_TOP]) {
if (!option || !s->hw_data_avail[option-OPT_TOP]) {
DBG (15, "get_hardware_status: running\n");
/* mark all values as unread */
memset(s->hw_read,0,sizeof(s->hw_read));
/* mark all values as available */
memset(s->hw_data_avail,1,sizeof(s->hw_data_avail));
if (s->has_cmd_hw_status){
unsigned char cmd[GET_HW_STATUS_len];
@ -5950,6 +6010,7 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
s->hw_hopper = get_GHS_hopper(in);
s->hw_omr = get_GHS_omr(in);
s->hw_adf_open = get_GHS_adf_open(in);
s->hw_card_loaded = get_GHS_exit(in);
s->hw_sleep = get_GHS_sleep(in);
s->hw_send_sw = get_GHS_send_sw(in);
@ -6015,7 +6076,7 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
}
if(option)
s->hw_read[option-OPT_TOP] = 1;
s->hw_data_avail[option-OPT_TOP] = 0;
DBG (10, "get_hardware_status: finish\n");
@ -6905,8 +6966,8 @@ sane_start (SANE_Handle handle)
}
/* low mem mode messes up the side marker, reset it */
if(s->source == SOURCE_ADF_DUPLEX && s->low_mem
&& s->eof_tx[SIDE_FRONT] && s->eof_tx[SIDE_BACK]
if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->low_mem && s->eof_tx[SIDE_FRONT] && s->eof_tx[SIDE_BACK]
){
s->side = SIDE_BACK;
}
@ -6915,7 +6976,7 @@ sane_start (SANE_Handle handle)
if(!s->started){
/* load side marker */
if(s->source == SOURCE_ADF_BACK){
if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
s->side = SIDE_BACK;
}
else{
@ -6936,6 +6997,12 @@ sane_start (SANE_Handle handle)
DBG (5, "sane_start: ERROR: cannot control fb, ignoring\n");
}
}
else if(s->source == SOURCE_CARD_FRONT || s->source == SOURCE_CARD_BACK || s->source == SOURCE_CARD_DUPLEX){
ret = scanner_control(s, SC_function_rpath);
if (ret != SANE_STATUS_GOOD) {
DBG (5, "sane_start: ERROR: cannot control rp, ignoring\n");
}
}
else{
ret = scanner_control(s, SC_function_adf);
if (ret != SANE_STATUS_GOOD) {
@ -7038,7 +7105,7 @@ sane_start (SANE_Handle handle)
}
}
/* if already running, duplex needs to switch sides */
else if(s->source == SOURCE_ADF_DUPLEX){
else if(s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX){
s->side = !s->side;
}
@ -7047,7 +7114,7 @@ sane_start (SANE_Handle handle)
/* otherwise buffered back page will be lost */
/* ingest paper with adf (no-op for fb) */
/* dont call object pos or scan on back side of duplex scan */
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK){
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
s->bytes_rx[0]=0;
s->bytes_rx[1]=0;
@ -7095,7 +7162,7 @@ sane_start (SANE_Handle handle)
}
/* store the number of front bytes */
if ( s->source != SOURCE_ADF_BACK ){
if ( s->source != SOURCE_ADF_BACK && s->source != SOURCE_CARD_BACK ){
s->bytes_tot[SIDE_FRONT] = s->s_params.bytes_per_line * s->s_params.lines;
s->buff_tot[SIDE_FRONT] = s->buffer_size;
@ -7114,13 +7181,14 @@ sane_start (SANE_Handle handle)
}
/* store the number of back bytes */
if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK ){
if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK
|| s->source == SOURCE_CARD_DUPLEX || s->source == SOURCE_CARD_BACK ){
s->bytes_tot[SIDE_BACK] = s->s_params.bytes_per_line * s->s_params.lines;
s->buff_tot[SIDE_BACK] = s->bytes_tot[SIDE_BACK];
/* the back buffer is normally very large, but some scanners or
* option combinations dont need it, so we make a small one */
if(s->low_mem || s->source == SOURCE_ADF_BACK
if(s->low_mem || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
|| s->duplex_interlace == DUPLEX_INTERLACE_NONE)
s->buff_tot[SIDE_BACK] = s->buffer_size;
}
@ -7308,13 +7376,14 @@ scanner_control (struct fujitsu *s, int function)
memset(cmd,0,cmdLen);
set_SCSI_opcode(cmd, SCANNER_CONTROL_code);
set_SC_function (cmd, function);
set_SC_function_1 (cmd, function);
set_SC_function_2 (cmd, function);
DBG (15, "scanner_control: function %d\n",function);
/* don't really need to ask for adf if that's the only option */
/* doing so causes the 3091 to complain */
if(function == SC_function_adf && !s->has_flatbed){
if(function == SC_function_adf && !s->has_flatbed && !s->has_return_path){
DBG (10, "scanner_control: adf function not required\n");
return ret;
}
@ -7486,7 +7555,7 @@ set_window (struct fujitsu *s)
set_WPDB_wdblen(header, SW_desc_len);
/* init the window block */
if (s->source == SOURCE_ADF_BACK) {
if (s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
set_WD_wid (desc1, WD_wid_back);
}
else{
@ -7675,7 +7744,7 @@ set_window (struct fujitsu *s)
}
/* when in duplex mode, copy first desc block into second */
if (s->source == SOURCE_ADF_DUPLEX) {
if (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX) {
memcpy (desc2, desc1, SW_desc_len);
set_WD_wid (desc2, WD_wid_back);
@ -7823,7 +7892,7 @@ get_pixelsize(struct fujitsu *s, int actual)
}
/*
* Issues the SCSI OBJECT POSITION command if an ADF is in use.
* Issues the SCSI OBJECT POSITION command if an ADF or card scanner is in use.
*/
static SANE_Status
object_position (struct fujitsu *s, int action)
@ -7880,9 +7949,9 @@ start_scan (struct fujitsu *s)
DBG (10, "start_scan: start\n");
if (s->source != SOURCE_ADF_DUPLEX) {
if (s->source != SOURCE_ADF_DUPLEX && s->source != SOURCE_CARD_DUPLEX) {
outLen--;
if(s->source == SOURCE_ADF_BACK) {
if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
out[0] = WD_wid_back;
}
}
@ -7983,7 +8052,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* swap sides if user asked for low-mem mode, we are duplexing,
* and there is data waiting on the other side */
if(s->low_mem && s->source == SOURCE_ADF_DUPLEX
if(s->low_mem
&& (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
|| (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
)
@ -8013,7 +8083,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
} /* end 3091 */
/* alternating jpeg duplex interlacing */
else if(s->source == SOURCE_ADF_DUPLEX
else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->s_params.format == SANE_FRAME_JPEG
&& s->jpeg_interlace == JPEG_INTERLACE_ALT
){
@ -8025,7 +8095,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
} /* end alt jpeg */
/* alternating pnm duplex interlacing */
else if(s->source == SOURCE_ADF_DUPLEX
else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->s_params.format != SANE_FRAME_JPEG
&& s->duplex_interlace == DUPLEX_INTERLACE_ALT
){
@ -8080,7 +8150,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* swap sides if user asked for low-mem mode, we are duplexing,
* and there is data waiting on the other side */
if(s->low_mem && s->source == SOURCE_ADF_DUPLEX
if(s->low_mem
&& (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
|| (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
)
@ -9291,6 +9362,10 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg)
DBG (5, "Medium error: Carrier sheet\n");
return SANE_STATUS_JAMMED;
}
if (0x0c == ascq) {
DBG (5, "Medium error: ADF blocked by card\n");
return SANE_STATUS_JAMMED;
}
if (0x10 == ascq) {
DBG (5, "Medium error: no ink cartridge\n");
return SANE_STATUS_IO_ERROR;
@ -10092,7 +10167,9 @@ buffer_deskew(struct fujitsu *s, int side)
DBG (10, "buffer_deskew: start\n");
/*only find skew on first image from a page, or if first image had error */
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK || s->deskew_stat){
if(s->side == SIDE_FRONT
|| s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
|| s->deskew_stat){
s->deskew_stat = sanei_magic_findSkew(
&s->s_params,s->buffers[side],s->resolution_x,s->resolution_y,

Wyświetl plik

@ -255,3 +255,6 @@ usb 0x04c5 0x1522
#ScanSnap iX1500
usb 0x04c5 0x159f
#fi-800R
usb 0x04c5 0x15fc

Wyświetl plik

@ -112,6 +112,7 @@ enum fujitsu_Option
OPT_HOPPER,
OPT_OMR,
OPT_ADF_OPEN,
OPT_CARD_LOADED,
OPT_SLEEP,
OPT_SEND_SW,
OPT_MANUAL_FEED,
@ -277,6 +278,7 @@ struct fujitsu
int has_comp_JPG2;
int has_comp_JPG3;
int has_op_halt;
int has_return_path;
/*FIXME: more endorser data? */
int endorser_type_f;
@ -361,7 +363,7 @@ struct fujitsu
/*mode group*/
SANE_String_Const mode_list[7];
SANE_String_Const source_list[5];
SANE_String_Const source_list[8];
SANE_Int res_list[17];
SANE_Range res_range;
@ -599,6 +601,7 @@ struct fujitsu
int hw_hopper;
int hw_omr;
int hw_adf_open;
int hw_card_loaded;
int hw_sleep;
int hw_send_sw;
@ -618,7 +621,7 @@ struct fujitsu
int hw_density_sw;
/* values which are used to track the frontend's access to sensors */
char hw_read[NUM_OPTIONS-OPT_TOP];
char hw_data_avail[NUM_OPTIONS-OPT_TOP];
};
#define CONNECTION_SCSI 0 /* SCSI interface */
@ -631,6 +634,9 @@ struct fujitsu
#define SOURCE_ADF_FRONT 1
#define SOURCE_ADF_BACK 2
#define SOURCE_ADF_DUPLEX 3
#define SOURCE_CARD_FRONT 4
#define SOURCE_CARD_BACK 5
#define SOURCE_CARD_DUPLEX 6
#define COMP_NONE WD_cmp_NONE
#define COMP_JPEG WD_cmp_JPG1

Wyświetl plik

@ -11,7 +11,7 @@
# Hewlett Packard ScanJet 2400c
usb 0x03f0 0x0a01
# Hewlett Packard ScanJet 3670c/3690c
# Hewlett Packard ScanJet 3670/3690c
usb 0x03f0 0x1405
# Plustek OpticPro ST24

Wyświetl plik

@ -63,8 +63,7 @@ struct Genesys_Calibration_Cache
Genesys_Frontend frontend;
Genesys_Sensor sensor;
size_t calib_pixels = 0;
size_t calib_channels = 0;
ScanSession session;
size_t average_size = 0;
std::vector<std::uint16_t> white_average_data;
std::vector<std::uint16_t> dark_average_data;
@ -75,8 +74,7 @@ struct Genesys_Calibration_Cache
last_calibration == other.last_calibration &&
frontend == other.frontend &&
sensor == other.sensor &&
calib_pixels == other.calib_pixels &&
calib_channels == other.calib_channels &&
session == other.session &&
average_size == other.average_size &&
white_average_data == other.white_average_data &&
dark_average_data == other.dark_average_data;
@ -94,8 +92,7 @@ void serialize(Stream& str, Genesys_Calibration_Cache& x)
serialize_newline(str);
serialize(str, x.sensor);
serialize_newline(str);
serialize(str, x.calib_pixels);
serialize(str, x.calib_channels);
serialize(str, x.session);
serialize(str, x.average_size);
serialize_newline(str);
serialize(str, x.white_average_data);

Wyświetl plik

@ -70,11 +70,10 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const = 0;
virtual void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
virtual void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
virtual void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const = 0;
virtual void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
/** Set up registers for a scan. Similar to init_regs_for_scan except that the session is
already computed from the session
@ -98,7 +97,6 @@ public:
*/
virtual void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const = 0;
virtual void search_start_position(Genesys_Device* dev) const = 0;
virtual void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
virtual void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
@ -134,11 +132,6 @@ public:
/// eject document from scanner
virtual void eject_document(Genesys_Device* dev) const = 0;
/**
* search for an black or white area in forward or reverse
* direction */
virtual void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const = 0;
/// move scanning head to transparency adapter
virtual void move_to_ta(Genesys_Device* dev) const = 0;
@ -159,6 +152,16 @@ public:
/// cold boot init function
virtual void asic_boot(Genesys_Device* dev, bool cold) const = 0;
/// checks if specific scan head is at home position
virtual bool is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const = 0;
/// enables or disables XPA slider motor
virtual void set_xpa_lamp_power(Genesys_Device& dev, bool set) const = 0;
/// enables or disables XPA slider motor
virtual void set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const = 0;
};
} // namespace genesys

Wyświetl plik

@ -0,0 +1,234 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
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.
*/
#define DEBUG_DECLARE_ONLY
#include "command_set_common.h"
#include "low.h"
namespace genesys {
CommandSetCommon::~CommandSetCommon() = default;
bool CommandSetCommon::is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const
{
struct HeadSettings {
ModelId model_id;
ScanHeadId scan_head;
GenesysRegisterSettingSet regs;
};
HeadSettings settings[] = {
{ ModelId::CANON_8600F,
ScanHeadId::PRIMARY, {
{ 0x6c, 0x20, 0x60 },
{ 0xa6, 0x00, 0x01 },
}
},
{ ModelId::CANON_8600F,
ScanHeadId::SECONDARY, {
{ 0x6c, 0x00, 0x60 },
{ 0xa6, 0x01, 0x01 },
}
},
};
for (const auto& setting : settings) {
if (setting.model_id == dev.model->model_id &&
setting.scan_head == scan_head)
{
auto reg_backup = apply_reg_settings_to_device_with_backup(dev, setting.regs);
auto status = scanner_read_status(dev);
apply_reg_settings_to_device(dev, reg_backup);
return status.is_at_home;
}
}
auto status = scanner_read_status(dev);
return status.is_at_home;
}
void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
{
DBG_HELPER(dbg);
struct LampSettings {
ModelId model_id;
ScanMethod scan_method;
GenesysRegisterSettingSet regs_on;
GenesysRegisterSettingSet regs_off;
};
// FIXME: BUG: we're not clearing the registers to the previous state when returning back when
// turning off the lamp
LampSettings settings[] = {
{ ModelId::CANON_4400F, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::CANON_8400F, ScanMethod::TRANSPARENCY, {
{ 0xa6, 0x34, 0xf4 },
}, {
{ 0xa6, 0x40, 0x70 },
}
},
{ ModelId::CANON_8400F, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0x6c, 0x40, 0x40 },
{ 0xa6, 0x01, 0xff },
}, {
{ 0x6c, 0x00, 0x40 },
{ 0xa6, 0x00, 0xff },
}
},
{ ModelId::CANON_8600F, ScanMethod::TRANSPARENCY, {
{ 0xa6, 0x34, 0xf4 },
{ 0xa7, 0xe0, 0xe0 },
}, {
{ 0xa6, 0x40, 0x70 },
}
},
{ ModelId::CANON_8600F, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa6, 0x00, 0xc0 },
{ 0xa7, 0xe0, 0xe0 },
{ 0x6c, 0x80, 0x80 },
}, {
{ 0xa6, 0x00, 0xc0 },
{ 0x6c, 0x00, 0x80 },
}
},
{ ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa8, 0x07, 0x07 },
}, {
{ 0xa8, 0x00, 0x07 },
}
},
{ ModelId::PLUSTEK_OPTICFILM_7300, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa8, 0x07, 0x07 },
}, {
{ 0xa8, 0x00, 0x07 },
}
},
};
for (const auto& setting : settings) {
if (setting.model_id == dev.model->model_id &&
setting.scan_method == dev.settings.scan_method)
{
apply_reg_settings_to_device(dev, set ? setting.regs_on : setting.regs_off);
return;
}
}
throw SaneException("Could not find XPA lamp settings");
}
void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const
{
DBG_HELPER(dbg);
struct MotorSettings {
ModelId model_id;
ResolutionFilter resolutions;
GenesysRegisterSettingSet regs_primary_and_secondary;
GenesysRegisterSettingSet regs_primary;
GenesysRegisterSettingSet regs_secondary;
};
MotorSettings settings[] = {
{ ModelId::CANON_8400F, { 400, 800, 1600, 3200 }, {
{ 0x6c, 0x00, 0x90 },
{ 0xa9, 0x04, 0x06 },
}, {
{ 0x6c, 0x90, 0x90 },
{ 0xa9, 0x02, 0x06 },
}, {}
},
{ ModelId::CANON_8600F, { 300, 600, 1200 }, {
{ 0x6c, 0x00, 0x60 },
{ 0xa6, 0x01, 0x41 },
}, {
{ 0x6c, 0x20, 0x62 },
{ 0xa6, 0x00, 0x41 },
}, {
{ 0x6c, 0x40, 0x62 },
{ 0xa6, 0x01, 0x41 },
}
},
{ ModelId::CANON_8600F, { 2400, 4800 }, {
{ 0x6c, 0x02, 0x62 },
{ 0xa6, 0x01, 0x41 },
}, {
{ 0x6c, 0x20, 0x62 },
{ 0xa6, 0x00, 0x41 },
}, {
{ 0x6c, 0x40, 0x62 },
{ 0xa6, 0x01, 0x41 },
}
},
{ ModelId::HP_SCANJET_G4050, ResolutionFilter::ANY, {
{ 0x6b, 0x81, 0x81 }, // set MULTFILM and GPOADF
{ 0x6c, 0x00, 0x40 }, // note that reverse change is not applied on off
// 0xa6 register 0x08 bit likely sets motor power. No move at all without that one
{ 0xa6, 0x08, 0x08 }, // note that reverse change is not applied on off
{ 0xa8, 0x00, 0x04 },
{ 0xa9, 0x30, 0x30 },
}, {
{ 0x6b, 0x00, 0x01 }, // BUG: note that only ADF is unset
{ 0xa8, 0x04, 0x04 },
{ 0xa9, 0x00, 0x10 }, // note that 0x20 bit is not reset
}, {}
},
{ ModelId::PLUSTEK_OPTICFILM_7200I, ResolutionFilter::ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7300, ResolutionFilter::ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ResolutionFilter::ANY, {}, {}, {} },
};
for (const auto& setting : settings) {
if (setting.model_id == dev.model->model_id &&
setting.resolutions.matches(dev.session.output_resolution))
{
switch (mode) {
case MotorMode::PRIMARY: {
apply_reg_settings_to_device(dev, setting.regs_primary);
break;
}
case MotorMode::PRIMARY_AND_SECONDARY: {
apply_reg_settings_to_device(dev, setting.regs_primary_and_secondary);
break;
}
case MotorMode::SECONDARY: {
apply_reg_settings_to_device(dev, setting.regs_secondary);
break;
}
}
regs.state.motor_mode = mode;
return;
}
}
throw SaneException("Motor settings have not been found");
}
} // namespace genesys

Wyświetl plik

@ -0,0 +1,48 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
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.
*/
#ifndef BACKEND_GENESYS_COMMAND_SET_COMMON_H
#define BACKEND_GENESYS_COMMAND_SET_COMMON_H
#include "command_set.h"
namespace genesys {
/** Common command set functionality
*/
class CommandSetCommon : public CommandSet
{
public:
~CommandSetCommon() override;
bool is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const override;
void set_xpa_lamp_power(Genesys_Device& dev, bool set) const override;
void set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const override;
};
} // namespace genesys
#endif // BACKEND_GENESYS_COMMAND_SET_COMMON_H

Wyświetl plik

@ -62,15 +62,24 @@ std::vector<unsigned> MethodResolutions::get_resolutions() const
return ret;
}
const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
const MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const
{
for (const auto& res_for_method : resolutions) {
for (auto res_method : res_for_method.methods) {
if (res_method == method) {
return res_for_method;
return &res_for_method;
}
}
}
return nullptr;
}
const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
{
const auto* ptr = get_resolution_settings_ptr(method);
if (ptr)
return *ptr;
throw SaneException("Could not find resolution settings for method %d",
static_cast<unsigned>(method));
}
@ -80,6 +89,12 @@ std::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const
return get_resolution_settings(method).get_resolutions();
}
bool Genesys_Model::has_method(ScanMethod method) const
{
return get_resolution_settings_ptr(method) != nullptr;
}
Genesys_Device::~Genesys_Device()
{
clear();
@ -124,10 +139,14 @@ unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const
}
}
void Genesys_Device::set_head_pos_unknown()
void Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head)
{
is_head_pos_primary_known_ = false;
is_head_pos_secondary_known_ = false;
if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
is_head_pos_primary_known_ = false;
}
if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
is_head_pos_secondary_known_ = false;
}
}
void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head)
@ -205,11 +224,10 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< " ignore_offsets: " << dev.ignore_offsets << '\n'
<< " model: (not printed)\n"
<< " reg: " << format_indent_braced_list(4, dev.reg) << '\n'
<< " calib_reg: " << format_indent_braced_list(4, dev.calib_reg) << '\n'
<< " initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n'
<< " settings: " << format_indent_braced_list(4, dev.settings) << '\n'
<< " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n'
<< " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n'
<< " frontend_is_init: " << dev.frontend_is_init << '\n'
<< " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
<< " motor: " << format_indent_braced_list(4, dev.motor) << '\n'
<< " control[0..6]: " << std::hex
@ -220,13 +238,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< static_cast<unsigned>(dev.control[4]) << ' '
<< static_cast<unsigned>(dev.control[5]) << '\n' << std::dec
<< " average_size: " << dev.average_size << '\n'
<< " calib_pixels: " << dev.calib_pixels << '\n'
<< " calib_lines: " << dev.calib_lines << '\n'
<< " calib_channels: " << dev.calib_channels << '\n'
<< " calib_resolution: " << dev.calib_resolution << '\n'
<< " calib_total_bytes_to_read: " << dev.calib_total_bytes_to_read << '\n'
<< " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n'
<< " calib_pixels_offset: " << dev.calib_pixels_offset << '\n'
<< " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n'
<< " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n'
<< " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n'
@ -262,11 +274,25 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
{
apply_reg_settings_to_device_with_backup(dev, regs);
}
GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs)
{
GenesysRegisterSettingSet backup;
for (const auto& reg : regs) {
uint8_t val = dev.interface->read_register(reg.address);
val = (val & ~reg.mask) | (reg.value & reg.mask);
dev.interface->write_register(reg.address, val);
std::uint8_t old_val = dev.interface->read_register(reg.address);
std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask);
dev.interface->write_register(reg.address, new_val);
using SettingType = GenesysRegisterSettingSet::SettingType;
backup.push_back(SettingType{reg.address,
static_cast<std::uint8_t>(old_val & reg.mask),
reg.mask});
}
return backup;
}
} // namespace genesys

Wyświetl plik

@ -55,6 +55,7 @@
#include "register.h"
#include "usb_device.h"
#include "scanner_interface.h"
#include "utilities.h"
#include <vector>
namespace genesys {
@ -77,24 +78,6 @@ struct Genesys_Gpo
GenesysRegisterSettingSet regs;
};
/// Stores a SANE_Fixed value which is automatically converted from and to floating-point values
class FixedFloat
{
public:
FixedFloat() = default;
FixedFloat(const FixedFloat&) = default;
FixedFloat(double number) : value_{SANE_FIX(number)} {}
FixedFloat& operator=(const FixedFloat&) = default;
FixedFloat& operator=(double number) { value_ = SANE_FIX(number); return *this; }
operator double() const { return value(); }
double value() const { return SANE_UNFIX(value_); }
private:
SANE_Fixed value_ = 0;
};
struct MethodResolutions
{
std::vector<ScanMethod> methods;
@ -143,49 +126,65 @@ struct Genesys_Model
// All offsets below are with respect to the sensor home position
// Start of scan area in mm
FixedFloat x_offset = 0;
float x_offset = 0;
// Start of scan area in mm (Amount of feeding needed to get to the medium)
FixedFloat y_offset = 0;
float y_offset = 0;
// Size of scan area in mm
FixedFloat x_size = 0;
float x_size = 0;
// Size of scan area in mm
FixedFloat y_size = 0;
float y_size = 0;
// Start of white strip in mm
FixedFloat y_offset_calib_white = 0;
// Start of white strip in mm for scanners that use separate dark and white shading calibration.
float y_offset_calib_white = 0;
// The size of the scan area that is used to acquire shading data in mm
float y_size_calib_mm = 0;
// Start of the black/white strip in mm for scanners that use unified dark and white shading
// calibration.
float y_offset_calib_dark_white_mm = 0;
// The size of the scan area that is used to acquire dark/white shading data in mm
float y_size_calib_dark_white_mm = 0;
// The width of the scan area that is used to acquire shading data
float x_size_calib_mm = 0;
// Start of black mark in mm
FixedFloat x_offset_calib_black = 0;
float x_offset_calib_black = 0;
// Start of scan area in transparency mode in mm
FixedFloat x_offset_ta = 0;
float x_offset_ta = 0;
// Start of scan area in transparency mode in mm
FixedFloat y_offset_ta = 0;
float y_offset_ta = 0;
// Size of scan area in transparency mode in mm
FixedFloat x_size_ta = 0;
float x_size_ta = 0;
// Size of scan area in transparency mode in mm
FixedFloat y_size_ta = 0;
float y_size_ta = 0;
// The position of the sensor when it's aligned with the lamp for transparency scanning
FixedFloat y_offset_sensor_to_ta = 0;
float y_offset_sensor_to_ta = 0;
// Start of white strip in transparency mode in mm
FixedFloat y_offset_calib_white_ta = 0;
float y_offset_calib_white_ta = 0;
// Start of black strip in transparency mode in mm
FixedFloat y_offset_calib_black_ta = 0;
float y_offset_calib_black_ta = 0;
// The size of the scan area that is used to acquire shading data in transparency mode in mm
float y_size_calib_ta_mm = 0;
// Size of scan area after paper sensor stop sensing document in mm
FixedFloat post_scan = 0;
float post_scan = 0;
// Amount of feeding needed to eject document after finishing scanning in mm
FixedFloat eject_feed = 0;
float eject_feed = 0;
// Line-distance correction (in pixel at optical_ydpi) for CCD scanners
SANE_Int ld_shift_r = 0;
@ -210,22 +209,24 @@ struct Genesys_Model
// stepper motor type
MotorId motor_id = MotorId::UNKNOWN;
// Which hacks are needed for this scanner?
SANE_Word flags = 0;
// Which customizations are needed for this scanner?
ModelFlag flags = ModelFlag::NONE;
// Button flags, described existing buttons for the model
SANE_Word buttons = 0;
// how many lines are used for shading calibration
SANE_Int shading_lines = 0;
// how many lines are used for shading calibration in TA mode
SANE_Int shading_ta_lines = 0;
// how many lines are used to search start position
SANE_Int search_lines = 0;
// returns nullptr if method is not supported
const MethodResolutions* get_resolution_settings_ptr(ScanMethod method) const;
// throws if method is not supported
const MethodResolutions& get_resolution_settings(ScanMethod method) const;
std::vector<unsigned> get_resolutions(ScanMethod method) const;
bool has_method(ScanMethod method) const;
};
/**
@ -267,36 +268,18 @@ struct Genesys_Device
std::unique_ptr<CommandSet> cmd_set;
Genesys_Register_Set reg;
Genesys_Register_Set calib_reg;
Genesys_Register_Set initial_regs;
Genesys_Settings settings;
Genesys_Frontend frontend, frontend_initial;
// whether the frontend is initialized. This is currently used just to preserve historical
// behavior
bool frontend_is_init = false;
Genesys_Gpo gpo;
Genesys_Motor motor;
std::uint8_t control[6] = {};
size_t average_size = 0;
// number of pixels used during shading calibration
size_t calib_pixels = 0;
// number of lines used during shading calibration
size_t calib_lines = 0;
size_t calib_channels = 0;
size_t calib_resolution = 0;
// bytes to read from USB when calibrating. If 0, this is not set
size_t calib_total_bytes_to_read = 0;
// the session that was configured for calibration
ScanSession calib_session;
// certain scanners support much higher resolution when scanning transparency, but we can't
// read whole width of the scanner as a single line at that resolution. Thus for stuff like
// calibration we want to read only the possible calibration area.
size_t calib_pixels_offset = 0;
// gamma overrides. If a respective array is not empty then it means that the gamma for that
// color is overridden.
std::vector<std::uint16_t> gamma_override_tables[3];
@ -360,7 +343,7 @@ struct Genesys_Device
bool is_head_pos_known(ScanHeadId scan_head) const;
unsigned head_pos(ScanHeadId scan_head) const;
void set_head_pos_unknown();
void set_head_pos_unknown(ScanHeadId scan_head);
void set_head_pos_zero(ScanHeadId scan_head);
void advance_head_pos_by_session(ScanHeadId scan_head);
void advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps);
@ -382,6 +365,10 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev);
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs);
GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs);
} // namespace genesys
#endif

Wyświetl plik

@ -192,7 +192,7 @@ enum class ModelId : unsigned
DCT_DOCKETPORT_487,
HP_SCANJET_2300C,
HP_SCANJET_2400C,
HP_SCANJET_3670C,
HP_SCANJET_3670,
HP_SCANJET_4850C,
HP_SCANJET_G4010,
HP_SCANJET_G4050,
@ -431,6 +431,76 @@ enum class AsicType : unsigned
};
enum class ModelFlag : unsigned
{
// no flags
NONE = 0,
// scanner is not tested, print a warning as it's likely it won't work
UNTESTED = 1 << 0,
// use 14-bit gamma table instead of 12-bit
GAMMA_14BIT = 1 << 1,
// skip lamp warmup (genesys_warmup())
SKIP_WARMUP = 1 << 4,
// repark head and check for lock by moving without scanning
REPARK = 1 << 7,
// do dark calibration
DARK_CALIBRATION = 1 << 8,
// whether scanner must wait for the head while parking
MUST_WAIT = 1 << 10,
// do dark and white calibration in one run
DARK_WHITE_CALIBRATION = 1 << 12,
// allow custom gamma tables
CUSTOM_GAMMA = 1 << 13,
// skip calibration completely, this is needed for sheet-fed scanners
NO_CALIBRATION = 1 << 14,
// the scanner uses multi-segment sensors that must be handled during calibration
SIS_SENSOR = 1 << 16,
// the head must be reparked between shading scans
SHADING_REPARK = 1 << 18,
// the scanner always uses maximum hwdpi to setup the sensor
FULL_HWDPI_MODE = 1 << 19,
// the scanner outputs 16-bit data that is byte-inverted
INVERTED_16BIT_DATA = 1 << 20,
// the scanner has transparency, but it's implemented using only one motor
UTA_NO_SECONDARY_MOTOR = 1 << 21
};
inline ModelFlag operator|(ModelFlag left, ModelFlag right)
{
return static_cast<ModelFlag>(static_cast<unsigned>(left) | static_cast<unsigned>(right));
}
inline ModelFlag& operator|=(ModelFlag& left, ModelFlag right)
{
left = left | right;
return left;
}
inline ModelFlag operator&(ModelFlag left, ModelFlag right)
{
return static_cast<ModelFlag>(static_cast<unsigned>(left) & static_cast<unsigned>(right));
}
inline bool has_flag(ModelFlag flags, ModelFlag which)
{
return (flags & which) == which;
}
enum class ScanFlag : unsigned
{
NONE = 0,
@ -438,14 +508,22 @@ enum class ScanFlag : unsigned
DISABLE_SHADING = 1 << 1,
DISABLE_GAMMA = 1 << 2,
DISABLE_BUFFER_FULL_MOVE = 1 << 3,
IGNORE_LINE_DISTANCE = 1 << 4,
DISABLE_LAMP = 1 << 5,
CALIBRATION = 1 << 6,
FEEDING = 1 << 7,
USE_XPA = 1 << 8,
ENABLE_LEDADD = 1 << 9,
USE_XCORRECTION = 1 << 10,
REVERSE = 1 << 11,
// if this flag is set the sensor will always be handled ignoring staggering of multiple
// sensors to achieve high resolution.
IGNORE_STAGGER_OFFSET = 1 << 4,
// if this flag is set the sensor will always be handled as if the components that scan
// different colors are at the same position.
IGNORE_COLOR_OFFSET = 1 << 5,
DISABLE_LAMP = 1 << 6,
CALIBRATION = 1 << 7,
FEEDING = 1 << 8,
USE_XPA = 1 << 9,
ENABLE_LEDADD = 1 << 10,
USE_XCORRECTION = 1 << 11,
REVERSE = 1 << 12,
};
inline ScanFlag operator|(ScanFlag left, ScanFlag right)
@ -524,6 +602,12 @@ enum class Direction : unsigned
BACKWARD = 1
};
enum class MotorMode : unsigned
{
PRIMARY = 0,
PRIMARY_AND_SECONDARY,
SECONDARY,
};
} // namespace genesys

Wyświetl plik

@ -56,7 +56,6 @@ struct Genesys_Calibration_Cache;
class CommandSet;
// device.h
class FixedFloat;
struct Genesys_Gpo;
struct MethodResolutions;
struct Genesys_Model;
@ -75,7 +74,6 @@ class Image;
// image_buffer.h
class ImageBuffer;
class FakeBufferModel;
class ImageBufferGenesysUsb;
// image_pipeline.h
@ -89,11 +87,11 @@ struct RawPixel;
// low.h
struct Genesys_USB_Device_Entry;
struct Motor_Profile;
// motor.h
struct Genesys_Motor;
struct MotorSlope;
struct MotorProfile;
struct MotorSlopeTable;
// register.h
@ -113,6 +111,7 @@ class ScannerInterfaceUsb;
class TestScannerInterface;
// sensor.h
class ScanMethodFilter;
class ResolutionFilter;
struct GenesysFrontendLayout;
struct Genesys_Frontend;

Wyświetl plik

@ -337,8 +337,6 @@ gl124_init_registers (Genesys_Device * dev)
// fine tune upon device description
const auto& sensor = sanei_genesys_find_sensor_any(dev);
sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
dev->calib_reg = dev->reg;
}
/**@brief send slope table for motor movement
@ -466,7 +464,7 @@ void CommandSetGl124::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
static void gl124_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const Motor_Profile& motor_profile,
const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
@ -711,7 +709,7 @@ static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
regs_set_optical_off(dev->model->asic_type, *reg);
r = sanei_genesys_get_address (reg, REG_0x01);
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION))
{
r->value &= ~REG_0x01_DVDSET;
} else {
@ -818,7 +816,7 @@ static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
dev->line_count = 0;
build_image_pipeline(dev, session);
build_image_pipeline(dev, sensor, session);
// MAXWD is expressed in 2 words unit
@ -856,9 +854,7 @@ void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Gene
} else {
exposure_time = sensor.exposure_lperiod;
}
const auto& motor_profile = sanei_genesys_get_motor_profile(*gl124_motor_profiles,
dev->model->motor_id,
exposure_time);
const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, static_cast<unsigned>(motor_profile.step_type));
@ -885,8 +881,7 @@ void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Gene
mflags |= MotorFlag::REVERSE;
}
gl124_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
dev->model->is_cis ? session.output_line_count * session.params.channels :
session.output_line_count,
session.optical_line_count,
dummy, move, session.params.scan_mode, mflags);
/*** prepares data reordering ***/
@ -909,21 +904,24 @@ ScanSession CommandSetGl124::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
int start;
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
/* start */
start = static_cast<int>(dev->model->x_offset);
start += static_cast<int>(settings.tl_x);
start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
unsigned move_dpi = dev->motor.base_ydpi / 4;
float move = dev->model->y_offset;
move += dev->settings.tl_y;
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
float start = dev->model->x_offset;
start += settings.tl_x;
start /= sensor.get_ccd_size_divisor_for_dpi(settings.xres);
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
session.params.startx = start;
session.params.starty = 0; // not used
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@ -1031,8 +1029,7 @@ void CommandSetGl124::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
// set up GPIO for scan
gl124_setup_scan_gpio(dev,dev->settings.yres);
// clear scan and feed count
dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT);
scanner_clear_scan_and_feed_counts(*dev);
// enable scan and motor
uint8_t val = dev->interface->read_register(REG_0x01);
@ -1069,155 +1066,27 @@ void CommandSetGl124::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
// from very top of scanner
void CommandSetGl124::search_start_position(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
int size;
Genesys_Register_Set local_reg = dev->reg;
int pixels = 600;
int dpi = 300;
/* sets for a 200 lines * 600 pixels */
/* normal scan with no shading */
// FIXME: the current approach of doing search only for one resolution does not work on scanners
// whith employ different sensors with potentially different settings.
const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, ScanMethod::FLATBED);
ScanSession session;
session.params.xres = dpi;
session.params.yres = dpi;
session.params.startx = 0;
session.params.starty = 0; /*we should give a small offset here~60 steps */
session.params.pixels = 600;
session.params.lines = dev->model->search_lines;
session.params.depth = 8;
session.params.channels = 1;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::GRAY;
session.params.color_filter = ColorFilter::GREEN;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::IGNORE_LINE_DISTANCE |
ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &local_reg, session);
// send to scanner
dev->interface->write_registers(local_reg);
size = pixels * dev->model->search_lines;
std::vector<uint8_t> data(size);
begin_scan(dev, sensor, &local_reg, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("search_start_position");
end_scan(dev, &local_reg, true);
dev->reg = local_reg;
return;
}
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl124_search_position.pnm", data.data(), 8, 1, pixels,
dev->model->search_lines);
}
end_scan(dev, &local_reg, true);
/* update regs to copy ASIC internal state */
dev->reg = local_reg;
for (auto& sensor_update :
sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
{
sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
dev->model->search_lines);
}
}
// sets up register for coarse gain calibration
// todo: check it for scanners using it
void CommandSetGl124::init_regs_for_coarse_calibration(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
session.params.lines = 20;
session.params.depth = 16;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::FEEDING |
ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
sanei_genesys_set_motor_power(regs, false);
DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
dev->interface->write_registers(regs);
}
// init registers for shading calibration shading calibration is done at dpihw
void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
int move, resolution, dpihw, factor;
/* initial calibration reg values */
regs = dev->reg;
dev->calib_channels = 3;
dev->calib_lines = dev->model->shading_lines;
dpihw = sensor.get_register_hwdpi(dev->settings.xres);
if(dpihw>=2400)
{
dev->calib_lines *= 2;
}
resolution=dpihw;
unsigned channels = 3;
unsigned dpihw = sensor.get_register_hwdpi(dev->settings.xres);
unsigned resolution = dpihw;
unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
resolution /= ccd_size_divisor;
dev->calib_lines /= ccd_size_divisor; // reducing just because we reduced the resolution
unsigned calib_lines =
static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution,
dev->calib_channels,
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
dev->calib_resolution = resolution;
dev->calib_total_bytes_to_read = 0;
factor = calib_sensor.optical_res / resolution;
dev->calib_pixels = calib_sensor.sensor_pixels / factor;
/* distance to move to reach white target at high resolution */
move=0;
unsigned move=0;
if (dev->settings.yres >= 1200) {
move = static_cast<int>(dev->model->y_offset_calib_white);
move = static_cast<int>((move * (dev->motor.base_ydpi/4)) / MM_PER_INCH);
@ -1229,17 +1098,16 @@ void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = move;
session.params.pixels = dev->calib_pixels;
session.params.lines = dev->calib_lines;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = calib_lines;
session.params.depth = 16;
session.params.channels = dev->calib_channels;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = ColorFilter::RED;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::DISABLE_BUFFER_FULL_MOVE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, calib_sensor);
try {
@ -1250,7 +1118,7 @@ void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
}
sanei_genesys_set_motor_power(regs, false);
dev->interface->write_registers(regs);
dev->calib_session = session;
}
void CommandSetGl124::wait_for_motor_stop(Genesys_Device* dev) const
@ -1274,52 +1142,21 @@ void CommandSetGl124::wait_for_motor_stop(Genesys_Device* dev) const
/** @brief set up registers for the actual scan
*/
void CommandSetGl124::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
void CommandSetGl124::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
float move;
int move_dpi;
float start;
auto session = calculate_scan_session(dev, sensor, dev->settings);
debug_dump(DBG_info, dev->settings);
/* y (motor) distance to move to reach scanned area */
move_dpi = dev->motor.base_ydpi/4;
move = static_cast<float>(dev->model->y_offset);
move += static_cast<float>(dev->settings.tl_y);
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
DBG (DBG_info, "%s: move=%f steps\n", __func__, move);
if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
if (dev->settings.get_channels() * dev->settings.yres >= 600 && session.params.starty > 700) {
scanner_move(*dev, dev->model->default_method,
static_cast<unsigned>(session.params.starty - 500),
Direction::FORWARD);
move=500;
session.params.starty = 500;
}
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
/* start */
start = static_cast<float>(dev->model->x_offset);
start += static_cast<float>(dev->settings.tl_x);
start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = dev->settings.pixels;
session.params.requested_pixels = dev->settings.requested_pixels;
session.params.lines = dev->settings.lines;
session.params.depth = dev->settings.depth;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::NONE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &dev->reg, session);
init_regs_for_scan_session(dev, sensor, &regs, session);
}
/**
@ -1439,14 +1276,11 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
(void) sensor;
DBG_HELPER(dbg);
int pixels;
int size;
unsigned resolution = 600;
unsigned channels = 3;
const auto& move_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
pixels = (move_sensor.sensor_pixels * 600) / move_sensor.optical_res;
/* initial calibration reg values */
regs = dev->reg;
@ -1456,7 +1290,7 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = 1;
session.params.depth = 8;
session.params.channels = channels;
@ -1466,14 +1300,12 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, move_sensor);
dev->cmd_set->init_regs_for_scan_session(dev, move_sensor, &regs, session);
size = pixels * 3;
std::vector<uint8_t> line(size);
// write registers and scan data
dev->interface->write_registers(regs);
@ -1486,14 +1318,13 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
return;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
// stop scanning
scanner_stop_action(*dev);
if (DBG_LEVEL >= DBG_data)
{
sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", line.data(), 8, 3, pixels, 1);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", image);
}
}
@ -1506,13 +1337,9 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
int num_pixels;
int total_size;
int resolution;
int dpihw;
int i, j;
int val;
int channels;
int i;
int avg[3];
int turn;
uint16_t exp[3],target;
@ -1521,7 +1348,7 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
move_to_calibration_area(dev, sensor, regs);
/* offset calibration is always done in 16 bit depth color mode */
channels = 3;
unsigned channels = 3;
dpihw = sensor.get_register_hwdpi(dev->settings.xres);
resolution = dpihw;
unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
@ -1529,7 +1356,6 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
num_pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
/* initial calibration reg values */
regs = dev->reg;
@ -1539,7 +1365,7 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;;
session.params.lines = 1;
session.params.depth = 16;
session.params.channels = channels;
@ -1549,14 +1375,12 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
total_size = num_pixels * channels * (session.params.depth / 8) * 1;
std::vector<uint8_t> line(total_size);
// initial loop values and boundaries
exp[0] = calib_sensor.exposure.red;
exp[1] = calib_sensor.exposure.green;
@ -1587,7 +1411,7 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
return calib_sensor.exposure;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
// stop scanning
scanner_stop_action(*dev);
@ -1596,29 +1420,16 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
{
char fn[30];
std::snprintf(fn, 30, "gl124_led_%02d.pnm", turn);
sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, channels, num_pixels,
1);
}
sanei_genesys_write_pnm_file(fn, image);
}
/* compute average */
for (j = 0; j < channels; j++)
{
avg[j] = 0;
for (i = 0; i < num_pixels; i++)
{
if (dev->model->is_cis)
val =
line[i * 2 + j * 2 * num_pixels + 1] * 256 +
line[i * 2 + j * 2 * num_pixels];
else
val =
line[i * 2 * channels + 2 * j + 1] * 256 +
line[i * 2 * channels + 2 * j];
avg[j] += val;
}
avg[j] /= num_pixels;
}
for (unsigned ch = 0; ch < channels; ch++) {
avg[ch] = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
avg[ch] += image.get_raw_channel(x, 0, ch);
}
avg[ch] /= image.get_width();
}
DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
@ -1692,9 +1503,9 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
{
DBG_HELPER(dbg);
unsigned channels;
int pass = 0, avg, total_size;
int pass = 0, avg;
int topavg, bottomavg, lines;
int top, bottom, black_pixels, pixels;
int top, bottom, black_pixels;
// no gain nor offset for TI AFE
uint8_t reg0a = dev->interface->read_register(REG_0x0A);
@ -1704,9 +1515,8 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
/* offset calibration is always done in color mode */
channels = 3;
dev->calib_pixels = sensor.sensor_pixels;
lines=1;
pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
@ -1725,19 +1535,14 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
sanei_genesys_set_motor_power(regs, false);
/* allocate memory for scans */
total_size = pixels * channels * lines * (session.params.depth / 8);
std::vector<uint8_t> first_line(total_size);
std::vector<uint8_t> second_line(total_size);
/* init gain */
dev->frontend.set_gain(0, 0);
dev->frontend.set_gain(1, 0);
@ -1759,16 +1564,16 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
return;
}
sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
if (DBG_LEVEL >= DBG_data)
{
char title[30];
std::snprintf(title, 30, "gl124_offset%03d.pnm", bottom);
sanei_genesys_write_pnm_file(title, first_line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file(title, first_line);
}
bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels);
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
/* now top value */
@ -1780,9 +1585,10 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
/* loop until acceptable level */
@ -1800,17 +1606,15 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
if (DBG_LEVEL >= DBG_data)
{
if (DBG_LEVEL >= DBG_data) {
char title[30];
std::snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1));
sanei_genesys_write_pnm_file(title, second_line.data(), session.params.depth,
channels, pixels, lines);
}
sanei_genesys_write_pnm_file(title, second_line);
}
avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
/* compute new boundaries */
@ -1845,12 +1649,8 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
int pixels;
int total_size;
int i, j, channels;
int max[3];
float gain[3],coeff;
int val, code, lines;
int code, lines;
// no gain nor offset for TI AFE
uint8_t reg0a = dev->interface->read_register(REG_0x0A);
@ -1859,7 +1659,7 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
}
/* coarse gain calibration is always done in color mode */
channels = 3;
unsigned channels = 3;
if(dev->settings.xres<sensor.optical_res)
{
@ -1868,14 +1668,13 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
coeff = 1.0f;
}
lines=10;
pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
@ -1885,7 +1684,8 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
@ -1899,9 +1699,7 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
dev->interface->write_registers(regs);
total_size = pixels * channels * (16 / session.params.depth) * lines;
std::vector<uint8_t> line(total_size);
std::vector<uint8_t> line(session.output_line_bytes);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
@ -1913,41 +1711,35 @@ void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys
return;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
// BUG: we probably want to read whole image, not just first line
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl124_gain.pnm", line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file("gl124_gain.pnm", image);
}
/* average value on each channel */
for (j = 0; j < channels; j++)
{
max[j] = 0;
for (i = pixels/4; i < (pixels*3/4); i++)
{
if (dev->model->is_cis) {
val = line[i + j * pixels];
} else {
val = line[i * channels + j];
}
for (unsigned ch = 0; ch < channels; ch++) {
max[j] += val;
}
max[j] = max[j] / (pixels/2);
auto width = image.get_width();
gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
total /= width / 2;
gain[ch] = (static_cast<float>(sensor.gain_white_ref) * coeff) / total;
/* turn logical gain value into gain code, checking for overflow */
code = static_cast<int>(283 - 208 / gain[j]);
if (code > 255)
code = 255;
else if (code < 0)
code = 0;
dev->frontend.set_gain(j, code);
code = static_cast<int>(283 - 208 / gain[ch]);
code = clamp(code, 0, 255);
dev->frontend.set_gain(ch, code);
DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j],
gain[j], dev->frontend.get_gain(j));
DBG(DBG_proc, "%s: channel %d, total=%d, gain = %f, setting:%d\n", __func__, ch,
static_cast<unsigned>(total),
gain[ch], dev->frontend.get_gain(ch));
}
if (dev->model->is_cis) {
@ -1989,9 +1781,9 @@ void CommandSetGl124::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = dev->motor.base_ydpi;
session.params.startx = sensor.sensor_pixels / 4;
session.params.startx = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH / 4;
session.params.starty = 0;
session.params.pixels = sensor.sensor_pixels / 2;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH / 2;
session.params.lines = 1;
session.params.depth = 8;
session.params.channels = *channels;
@ -2001,7 +1793,8 @@ void CommandSetGl124::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, reg, session);
@ -2011,7 +1804,6 @@ void CommandSetGl124::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
*total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */
sanei_genesys_set_motor_power(*reg, false);
dev->interface->write_registers(*reg);
}
/** @brief default GPIO values
@ -2244,16 +2036,6 @@ void CommandSetGl124::eject_document(Genesys_Device* dev) const
throw SaneException("not implemented");
}
void CommandSetGl124::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const
{
(void) dev;
(void) sensor;
(void) forward;
(void) black;
throw SaneException("not implemented");
}
void CommandSetGl124::move_to_ta(Genesys_Device* dev) const
{
(void) dev;

Wyświetl plik

@ -45,7 +45,7 @@
#define BACKEND_GENESYS_GL124_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
namespace genesys {
namespace gl124 {
@ -112,7 +112,7 @@ static Memory_layout layouts[]={
static void gl124_send_slope_table(Genesys_Device* dev, int table_nr,
const std::vector<uint16_t>& slope_table, int steps);
class CommandSetGl124 : public CommandSet
class CommandSetGl124 : public CommandSetCommon
{
public:
~CommandSetGl124() override = default;
@ -125,13 +125,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -148,8 +146,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -175,9 +171,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Wyświetl plik

@ -232,9 +232,8 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
regs->find_reg(0x01).value &= ~REG_0x01_CISSET;
}
/* if device has no calibration, don't enable shading correction */
if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)
{
// if device has no calibration, don't enable shading correction
if (has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION)) {
regs->find_reg(0x01).value &= ~REG_0x01_DVDSET;
}
@ -317,7 +316,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
sanei_genesys_set_dpihw(*regs, sensor, sensor.optical_res);
/* gamma enable for scans */
if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) {
if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
regs->find_reg(0x05).value |= REG_0x05_GMM14BIT;
}
@ -551,7 +550,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
dev->read_buffer.clear();
dev->read_buffer.alloc(session.buffer_size_read);
build_image_pipeline(dev, session);
build_image_pipeline(dev, sensor, session);
dev->read_active = true;
@ -666,7 +665,7 @@ gl646_init_regs (Genesys_Device * dev)
dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */
sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) {
if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
dev->reg.find_reg(0x05).value |= REG_0x05_GMM14BIT;
}
if (dev->model->adc_id == AdcId::AD_XP200) {
@ -1473,7 +1472,7 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
if (!i) /* the loop counted down to 0, scanner still is busy */
{
dev->set_head_pos_unknown();
dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY);
throw SaneException(SANE_STATUS_DEVICE_BUSY, "motor is still on: device busy");
}
@ -1567,7 +1566,7 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
// stop the motor
catch_all_exceptions(__func__, [&](){ gl646_stop_motor (dev); });
catch_all_exceptions(__func__, [&](){ end_scan_impl(dev, &dev->reg, true, false); });
dev->set_head_pos_unknown();
dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY);
throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home");
}
@ -1575,90 +1574,6 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
DBG(DBG_info, "%s: scanhead is still moving\n", __func__);
}
/**
* Automatically set top-left edge of the scan area by scanning an
* area at 300 dpi from very top of scanner
* @param dev device stucture describing the scanner
*/
void CommandSetGl646::search_start_position(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
Genesys_Settings settings;
unsigned int resolution, x, y;
/* we scan at 300 dpi */
resolution = get_closest_resolution(dev->model->sensor_id, 300, 1);
// FIXME: the current approach of doing search only for one resolution does not work on scanners
// whith employ different sensors with potentially different settings.
const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 1,
dev->model->default_method);
/* fill settings for a gray level scan */
settings.scan_method = dev->model->default_method;
settings.scan_mode = ScanColorMode::GRAY;
settings.xres = resolution;
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = 600;
settings.requested_pixels = settings.pixels;
settings.lines = dev->model->search_lines;
settings.depth = 8;
settings.color_filter = ColorFilter::RED;
settings.disable_interpolation = 0;
settings.threshold = 0;
// scan the desired area
std::vector<uint8_t> data;
simple_scan(dev, sensor, settings, true, true, false, data, "search_start_position");
// handle stagger case : reorder gray data and thus loose some lines
auto staggered_lines = dev->session.num_staggered_lines;
if (staggered_lines > 0) {
DBG(DBG_proc, "%s: 'un-staggering'\n", __func__);
for (y = 0; y < settings.lines - staggered_lines; y++) {
/* one point out of 2 is 'unaligned' */
for (x = 0; x < settings.pixels; x += 2)
{
data[y * settings.pixels + x] = data[(y + staggered_lines) * settings.pixels + x];
}
}
/* correct line number */
settings.lines -= staggered_lines;
}
if (DBG_LEVEL >= DBG_data)
{
sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1,
settings.pixels, settings.lines);
}
// now search reference points on the data
for (auto& sensor_update :
sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
{
sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0,
resolution, settings.pixels, settings.lines);
}
}
/**
* internally overriden during effective calibration
* sets up register for coarse gain calibration
*/
void CommandSetGl646::init_regs_for_coarse_calibration(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
(void) dev;
(void) sensor;
(void) regs;
}
/**
* init registers for shading calibration
* we assume that scanner's head is on an area suiting shading calibration.
@ -1694,10 +1609,13 @@ void CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
settings.yres = settings.xres;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (calib_sensor.sensor_pixels * settings.xres) / calib_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * settings.xres / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
dev->calib_lines = dev->model->shading_lines;
settings.lines = dev->calib_lines * (3 - ccd_size_divisor);
unsigned calib_lines =
static_cast<unsigned>(dev->model->y_size_calib_mm * settings.yres / MM_PER_INCH);
settings.lines = calib_lines;
settings.depth = 16;
settings.color_filter = dev->settings.color_filter;
@ -1706,14 +1624,8 @@ void CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
// we don't want top offset, but we need right margin to be the same than the one for the final
// scan
setup_for_scan(dev, calib_sensor, &dev->reg, settings, true, false, false, false);
/* used when sending shading calibration data */
dev->calib_pixels = settings.pixels;
dev->calib_channels = dev->session.params.channels;
if (!dev->model->is_cis) {
dev->calib_channels = 3;
}
dev->calib_session = setup_for_scan(dev, calib_sensor, &dev->reg, settings,
true, false, false, false);
/* no shading */
dev->reg.find_reg(0x01).value &= ~REG_0x01_DVDSET;
@ -1725,14 +1637,11 @@ void CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
/* TODO another flag to setup regs ? */
/* enforce needed LINCNT, getting rid of extra lines for color reordering */
if (!dev->model->is_cis) {
dev->reg.set24(REG_LINCNT, dev->calib_lines);
dev->reg.set24(REG_LINCNT, calib_lines);
} else {
dev->reg.set24(REG_LINCNT, dev->calib_lines * 3);
dev->reg.set24(REG_LINCNT, calib_lines * 3);
}
/* copy reg to calib_reg */
dev->calib_reg = dev->reg;
DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__,
dev->settings.xres, dev->settings.yres);
}
@ -1748,7 +1657,8 @@ bool CommandSetGl646::needs_home_before_init_regs_for_scan(Genesys_Device* dev)
* set up registers for the actual scan. The scan's parameters are given
* through the device settings. It allocates the scan buffers.
*/
void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
@ -1756,11 +1666,11 @@ void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sens
ScanSession session = calculate_scan_session(dev, sensor, dev->settings);
init_regs_for_scan_session(dev, sensor, &dev->reg, session);
init_regs_for_scan_session(dev, sensor, &regs, session);
/* gamma is only enabled at final scan time */
if (dev->settings.depth < 16) {
dev->reg.find_reg(0x05).value |= REG_0x05_GMMENB;
regs.find_reg(0x05).value |= REG_0x05_GMMENB;
}
}
@ -1775,14 +1685,14 @@ void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sens
* @param xcorrection take x geometry correction into account (fixed and detected offsets)
* @param ycorrection take y geometry correction into account
*/
static void setup_for_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set*regs,
Genesys_Settings settings,
bool split,
bool xcorrection,
bool ycorrection,
bool reverse)
static ScanSession setup_for_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set*regs,
Genesys_Settings settings,
bool split,
bool xcorrection,
bool ycorrection,
bool reverse)
{
DBG_HELPER(dbg);
@ -1794,12 +1704,12 @@ static void setup_for_scan(Genesys_Device* dev,
if (!split) {
if (!dev->model->is_sheetfed) {
if (ycorrection) {
move = static_cast<float>(dev->model->y_offset);
move = dev->model->y_offset;
}
// add tl_y to base movement
}
move += static_cast<float>(settings.tl_y);
move += settings.tl_y;
if (move < 0) {
DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move);
@ -1809,15 +1719,15 @@ static void setup_for_scan(Genesys_Device* dev,
move = static_cast<float>((move * dev->motor.optical_ydpi) / MM_PER_INCH);
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
float start = static_cast<float>(settings.tl_x);
float start = settings.tl_x;
if (xcorrection) {
if (settings.scan_method == ScanMethod::FLATBED) {
start += static_cast<float>(dev->model->x_offset);
start += dev->model->x_offset;
} else {
start += static_cast<float>(dev->model->x_offset_ta);
start += dev->model->x_offset_ta;
}
}
start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
@ -1845,6 +1755,8 @@ static void setup_for_scan(Genesys_Device* dev,
compute_session(dev, session, sensor);
dev->cmd_set->init_regs_for_scan_session(dev, sensor, regs, session);
return session;
}
/**
@ -1857,9 +1769,7 @@ void CommandSetGl646::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor
int address;
int bits;
/* gamma table size */
if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA)
{
if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
size = 16384;
bits = 14;
}
@ -1931,7 +1841,7 @@ SensorExposure CommandSetGl646::led_calibration(Genesys_Device* dev, const Genes
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = 1;
settings.depth = 16;
@ -2105,7 +2015,7 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = CALIBRATION_LINES;
settings.depth = 8;
@ -2216,7 +2126,7 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = CALIBRATION_LINES;
settings.depth = 8;
@ -2352,7 +2262,7 @@ static void ad_fe_coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sen
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = CALIBRATION_LINES;
settings.depth = 8;
@ -2459,7 +2369,7 @@ void CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys
if (settings.scan_method == ScanMethod::FLATBED)
{
settings.tl_x = 0;
settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
}
else
{
@ -2608,7 +2518,7 @@ void CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
settings.yres = resolution;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = (local_sensor.sensor_pixels * resolution) / local_sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = 2;
settings.depth = 8;
@ -2639,7 +2549,6 @@ void CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
// now registers are ok, write them to scanner
gl646_set_fe(dev, local_sensor, AFE_SET, settings.xres);
dev->interface->write_registers(*local_reg);
}
@ -2731,10 +2640,11 @@ void CommandSetGl646::init(Genesys_Device* dev) const
gl646_init_regs (dev);
// Init shading data
sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels);
sanei_genesys_init_shading_data(dev, sensor,
dev->model->x_size_calib_mm * sensor.optical_res /
MM_PER_INCH);
/* initial calibration reg values */
dev->calib_reg = dev->reg;
dev->initial_regs = dev->reg;
}
// execute physical unit init only if cold
@ -2828,16 +2738,13 @@ void CommandSetGl646::init(Genesys_Device* dev) const
/* ensure head is correctly parked, and check lock */
if (!dev->model->is_sheetfed) {
if (dev->model->flags & GENESYS_FLAG_REPARK)
{
if (has_flag(dev->model->flags, ModelFlag::REPARK)) {
// FIXME: if repark fails, we should print an error message that the scanner is locked and
// the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED
gl646_repark_head(dev);
}
else
{
} else {
move_back_home(dev, true);
}
}
}
/* here session and device are initialized */
@ -3015,7 +2922,7 @@ static void simple_move(Genesys_Device* dev, SANE_Int distance)
settings.yres = resolution;
settings.tl_y = 0;
settings.tl_x = 0;
settings.pixels = (sensor.sensor_pixels * settings.xres) / sensor.optical_res;
settings.pixels = dev->model->x_size_calib_mm * settings.xres / MM_PER_INCH;
settings.requested_pixels = settings.pixels;
settings.lines = static_cast<unsigned>((distance * settings.xres) / MM_PER_INCH);
settings.depth = 8;
@ -3130,8 +3037,7 @@ void CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const
}
/* XPA detection */
if (dev->model->flags & GENESYS_FLAG_XPA)
{
if (dev->model->has_method(ScanMethod::TRANSPARENCY)) {
switch (dev->model->gpio_id) {
case GpioId::HP3670:
case GpioId::HP2400:
@ -3208,154 +3114,6 @@ static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int
dev->interface->write_buffer(0x3c, addr, control, 4);
}
/**
* search for a full width black or white strip.
* @param dev scanner device
* @param forward true if searching forward, false if searching backward
* @param black true if searching for a black strip, false for a white strip
*/
void CommandSetGl646::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
bool black) const
{
DBG_HELPER(dbg);
(void) sensor;
Genesys_Settings settings;
int res = get_closest_resolution(dev->model->sensor_id, 75, 1);
unsigned int pass, count, found, x, y;
char title[80];
const auto& calib_sensor = sanei_genesys_find_sensor(dev, res, 1, ScanMethod::FLATBED);
/* we set up for a lowest available resolution color grey scan, full width */
settings.scan_method = dev->model->default_method;
settings.scan_mode = ScanColorMode::GRAY;
settings.xres = res;
settings.yres = res;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = static_cast<unsigned>((dev->model->x_size * res) / MM_PER_INCH);
settings.pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(res);
settings.requested_pixels = settings.pixels;
/* 15 mm at at time */
settings.lines = static_cast<unsigned>((15 * settings.yres) / MM_PER_INCH);
settings.depth = 8;
settings.color_filter = ColorFilter::RED;
settings.disable_interpolation = 0;
settings.threshold = 0;
/* signals if a strip of the given color has been found */
found = 0;
/* detection pass done */
pass = 0;
std::vector<uint8_t> data;
/* loop until strip is found or maximum pass number done */
while (pass < 20 && !found)
{
// scan a full width strip
simple_scan(dev, calib_sensor, settings, true, forward, false, data, "search_strip");
if (is_testing_mode()) {
return;
}
if (DBG_LEVEL >= DBG_data)
{
std::sprintf(title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", pass);
sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1,
settings.pixels, settings.lines);
}
/* search data to find black strip */
/* when searching forward, we only need one line of the searched color since we
* will scan forward. But when doing backward search, we need all the area of the
* same color */
if (forward)
{
for (y = 0; y < settings.lines && !found; y++)
{
count = 0;
/* count of white/black pixels depending on the color searched */
for (x = 0; x < settings.pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * settings.pixels + x] > 90)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * settings.pixels + x] < 60)
{
count++;
}
}
/* at end of line, if count >= 3%, line is not fully of the desired color
* so we must go to next line of the buffer */
/* count*100/pixels < 3 */
if ((count * 100) / settings.pixels < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
pass, y);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
}
}
}
else /* since calibration scans are done forward, we need the whole area
to be of the required color when searching backward */
{
count = 0;
for (y = 0; y < settings.lines; y++)
{
/* count of white/black pixels depending on the color searched */
for (x = 0; x < settings.pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * settings.pixels + x] > 60)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * settings.pixels + x] < 60)
{
count++;
}
}
}
/* at end of area, if count >= 3%, area is not fully of the desired color
* so we must go to next buffer */
if ((count * 100) / (settings.pixels * settings.lines) < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
}
}
pass++;
}
if (found)
{
DBG(DBG_info, "%s: strip found\n", __func__);
}
else
{
throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
}
}
void CommandSetGl646::wait_for_motor_stop(Genesys_Device* dev) const
{
(void) dev;
@ -3379,10 +3137,10 @@ ScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev,
float move = 0;
// XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */
if (!dev->model->is_sheetfed) {
move = static_cast<float>(dev->model->y_offset);
move = dev->model->y_offset;
// add tl_y to base movement
}
move += static_cast<float>(settings.tl_y);
move += settings.tl_y;
if (move < 0) {
DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move);
@ -3390,13 +3148,13 @@ ScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev,
}
move = static_cast<float>((move * dev->motor.optical_ydpi) / MM_PER_INCH);
float start = static_cast<float>(settings.tl_x);
float start = settings.tl_x;
if (settings.scan_method == ScanMethod::FLATBED) {
start += static_cast<float>(dev->model->x_offset);
start += dev->model->x_offset;
} else {
start += static_cast<float>(dev->model->x_offset_ta);
start += dev->model->x_offset_ta;
}
start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;

Wyświetl plik

@ -48,7 +48,7 @@
#define BACKEND_GENESYS_GL646_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#include "motor.h"
namespace genesys {
@ -68,14 +68,14 @@ static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint
* @param ycorrection true if scanner's Y geometry must be taken into account to
* compute Y, ie add top margins
*/
static void setup_for_scan(Genesys_Device* device,
const Genesys_Sensor& sensor,
Genesys_Register_Set*regs,
Genesys_Settings settings,
bool split,
bool xcorrection,
bool ycorrection,
bool reverse);
static ScanSession setup_for_scan(Genesys_Device* device,
const Genesys_Sensor& sensor,
Genesys_Register_Set*regs,
Genesys_Settings settings,
bool split,
bool xcorrection,
bool ycorrection,
bool reverse);
/**
* Does a simple move of the given distance by doing a scan at lowest resolution
@ -144,6 +144,10 @@ typedef struct
*/
static Motor_Master motor_master[] = {
/* HP3670 motor settings */
{MotorId::HP3670, 50, 3, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2329, 120, 229),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 75, 3, StepType::FULL, false, true, 1,
MotorSlope::create_from_steps(3429, 305, 200),
MotorSlope::create_from_steps(3399, 337, 192), 192},
@ -168,8 +172,8 @@ static Motor_Master motor_master[] = {
MotorSlope::create_from_steps(15937, 6375, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670,2400, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(15937, 12750, 3),
{MotorId::HP3670, 50, 1, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2329, 120, 229),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 75, 1, StepType::FULL, false, true, 1,
@ -196,10 +200,6 @@ static Motor_Master motor_master[] = {
MotorSlope::create_from_steps(15937, 6375, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670,2400, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(15937, 12750, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
/* HP2400/G2410 motor settings base motor dpi = 600 */
{MotorId::HP2400, 50, 3, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(8736, 601, 120),
@ -436,7 +436,7 @@ static Motor_Master motor_master[] = {
MotorSlope::create_from_steps(2000, 300, 255), 146}, /* 5500 guessed */
};
class CommandSetGl646 : public CommandSet
class CommandSetGl646 : public CommandSetCommon
{
public:
~CommandSetGl646() override = default;
@ -449,13 +449,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -472,8 +470,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -495,9 +491,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Plik diff jest za duży Load Diff

Wyświetl plik

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL841_H
#define BACKEND_GENESYS_GL841_H
@ -50,7 +50,7 @@
namespace genesys {
namespace gl841 {
class CommandSetGl841 : public CommandSet
class CommandSetGl841 : public CommandSetCommon
{
public:
~CommandSetGl841() override = default;
@ -63,13 +63,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -86,8 +84,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -109,9 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Plik diff jest za duży Load Diff

Wyświetl plik

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL843_H
#define BACKEND_GENESYS_GL843_H
@ -50,7 +50,7 @@
namespace genesys {
namespace gl843 {
class CommandSetGl843 : public CommandSet
class CommandSetGl843 : public CommandSetCommon
{
public:
~CommandSetGl843() override = default;
@ -63,13 +63,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -86,8 +84,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -109,9 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Wyświetl plik

@ -338,6 +338,16 @@ static constexpr RegAddr REG_CK4MAP = 0x7a;
static constexpr RegAddr REG_0x7E = 0x7e;
static constexpr RegAddr REG_0x80 = 0x80;
static constexpr RegMask REG_0x80_TABLE1_NORMAL = 0x03;
static constexpr RegShift REG_0x80S_TABLE1_NORMAL = 0;
static constexpr RegMask REG_0x80_TABLE2_BACK = 0x0c;
static constexpr RegShift REG_0x80S_TABLE2_BACK = 2;
static constexpr RegMask REG_0x80_TABLE4_FAST = 0x30;
static constexpr RegShift REG_0x80S_TABLE4_FAST = 4;
static constexpr RegMask REG_0x80_TABLE5_GO_HOME = 0xc0;
static constexpr RegShift REG_0x80S_TABLE5_GO_HOME = 6;
static constexpr RegAddr REG_0x9D = 0x9d;
static constexpr RegShift REG_0x9DS_STEPTIM = 2;

Wyświetl plik

@ -217,9 +217,6 @@ gl846_init_registers (Genesys_Device * dev)
const auto& sensor = sanei_genesys_find_sensor_any(dev);
sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
/* initalize calibration reg */
dev->calib_reg = dev->reg;
}
/**@brief send slope table for motor movement
@ -236,7 +233,6 @@ static void gl846_send_slope_table(Genesys_Device* dev, int table_nr,
{
DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
int i;
char msg[10000];
/* sanity check */
if(table_nr<0 || table_nr>4)
@ -251,16 +247,6 @@ static void gl846_send_slope_table(Genesys_Device* dev, int table_nr,
table[i * 2 + 1] = slope_table[i] >> 8;
}
if (DBG_LEVEL >= DBG_io)
{
std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
for (i = 0; i < steps; i++)
{
std::sprintf(msg+strlen(msg), "%d", slope_table[i]);
}
DBG (DBG_io, "%s: %s\n", __func__, msg);
}
if (dev->interface->is_mock()) {
dev->interface->record_slope_table(table_nr, slope_table);
}
@ -327,7 +313,7 @@ void CommandSetGl846::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
static void gl846_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const Motor_Profile& motor_profile,
const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
@ -400,7 +386,7 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
fast_step_type = StepType::QUARTER;
}
Motor_Profile fast_motor_profile = motor_profile;
MotorProfile fast_motor_profile = motor_profile;
fast_motor_profile.step_type = fast_step_type;
auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi,
@ -579,7 +565,7 @@ static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
r = sanei_genesys_get_address(reg, REG_0x01);
r->value |= REG_0x01_SHDAREA;
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION))
{
r->value &= ~REG_0x01_DVDSET;
}
@ -665,7 +651,7 @@ static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
build_image_pipeline(dev, session);
build_image_pipeline(dev, sensor, session);
/* MAXWD is expressed in 4 words unit */
// BUG: we shouldn't multiply by channels here
@ -705,9 +691,7 @@ void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Gene
slope_dpi = slope_dpi * (1 + dummy);
exposure_time = sensor.exposure_lperiod;
const auto& motor_profile = sanei_genesys_get_motor_profile(*gl846_motor_profiles,
dev->model->motor_id,
exposure_time);
const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
DBG(DBG_info, "%s : scan_step_type=%d\n", __func__,
@ -736,9 +720,7 @@ void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Gene
}
gl846_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
dev->model->is_cis ? session.output_line_count * session.params.channels
: session.output_line_count,
dummy, move, mflags);
session.optical_line_count, dummy, move, mflags);
/*** prepares data reordering ***/
@ -759,21 +741,33 @@ ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
int start;
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
/* start */
start = static_cast<int>(dev->model->x_offset);
start += static_cast<int>(settings.tl_x);
start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
/* Steps to move to reach scanning area:
- first we move to physical start of scanning either by a fixed steps amount from the
black strip or by a fixed amount from parking position, minus the steps done during
shading calibration.
- then we move by the needed offset whitin physical scanning area
*/
unsigned move_dpi = dev->motor.base_ydpi;
float move = dev->model->y_offset;
move = move + settings.tl_y;
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
move -= dev->head_pos(ScanHeadId::PRIMARY);
float start = dev->model->x_offset;
start = start + dev->settings.tl_x;
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
session.params.startx = start; // not used
session.params.starty = 0; // not used
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@ -782,7 +776,8 @@ ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
session.params.flags = ScanFlag::NONE;
// backtracking isn't handled well, so don't enable it
session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, sensor);
@ -817,10 +812,7 @@ void CommandSetGl846::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
dev->interface->write_register(REG_0x6C, val);
*/
val = REG_0x0D_CLRLNCNT;
dev->interface->write_register(REG_0x0D, val);
val = REG_0x0D_CLRMCNT;
dev->interface->write_register(REG_0x0D, val);
scanner_clear_scan_and_feed_counts(*dev);
val = dev->interface->read_register(REG_0x01);
val |= REG_0x01_SCAN;
@ -852,120 +844,6 @@ void CommandSetGl846::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
// from very top of scanner
void CommandSetGl846::search_start_position(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
int size;
Genesys_Register_Set local_reg;
int pixels = 600;
int dpi = 300;
local_reg = dev->reg;
/* sets for a 200 lines * 600 pixels */
/* normal scan with no shading */
// FIXME: the current approach of doing search only for one resolution does not work on scanners
// whith employ different sensors with potentially different settings.
const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
ScanSession session;
session.params.xres = dpi;
session.params.yres = dpi;
session.params.startx = 0;
session.params.starty = 0; /*we should give a small offset here~60 steps */
session.params.pixels = 600;
session.params.lines = dev->model->search_lines;
session.params.depth = 8;
session.params.channels = 1;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::GRAY;
session.params.color_filter = ColorFilter::GREEN;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &local_reg, session);
// send to scanner
dev->interface->write_registers(local_reg);
size = pixels * dev->model->search_lines;
std::vector<uint8_t> data(size);
begin_scan(dev, sensor, &local_reg, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("search_start_position");
end_scan(dev, &local_reg, true);
dev->reg = local_reg;
return;
}
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl846_search_position.pnm", data.data(), 8, 1, pixels,
dev->model->search_lines);
}
end_scan(dev, &local_reg, true);
/* update regs to copy ASIC internal state */
dev->reg = local_reg;
// TODO: find out where sanei_genesys_search_reference_point stores information,
// and use that correctly
for (auto& sensor_update :
sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
{
sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
dev->model->search_lines);
}
}
// sets up register for coarse gain calibration
// todo: check it for scanners using it
void CommandSetGl846::init_regs_for_coarse_calibration(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
session.params.lines = 20;
session.params.depth = 16;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
dev->interface->write_registers(regs);
}
// init registers for shading calibration
void CommandSetGl846::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
@ -973,136 +851,71 @@ void CommandSetGl846::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
DBG_HELPER(dbg);
float move;
dev->calib_channels = 3;
unsigned channels = 3;
unsigned resolution = sensor.get_register_hwdpi(dev->settings.xres);
/* initial calibration reg values */
regs = dev->reg;
dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution,
dev->calib_channels,
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
dev->calib_total_bytes_to_read = 0;
dev->calib_lines = dev->model->shading_lines;
if (dev->calib_resolution==4800) {
dev->calib_lines *= 2;
}
dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) /
calib_sensor.optical_res;
DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines);
DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels);
unsigned calib_lines =
static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH);
/* this is aworkaround insufficent distance for slope
* motor acceleration TODO special motor slope for shading */
move=1;
if(dev->calib_resolution<1200)
{
if (resolution < 1200) {
move=40;
}
ScanSession session;
session.params.xres = dev->calib_resolution;
session.params.yres = dev->calib_resolution;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = dev->calib_pixels;
session.params.lines = dev->calib_lines;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = calib_lines;
session.params.depth = 16;
session.params.channels = dev->calib_channels;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::DISABLE_BUFFER_FULL_MOVE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
dev->interface->write_registers(regs);
/* we use GENESYS_FLAG_SHADING_REPARK */
/* we use ModelFlag::SHADING_REPARK */
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
dev->calib_session = session;
}
/** @brief set up registers for the actual scan
*/
void CommandSetGl846::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
void CommandSetGl846::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
float move;
int move_dpi;
float start;
debug_dump(DBG_info, dev->settings);
auto session = calculate_scan_session(dev, sensor, dev->settings);
/* steps to move to reach scanning area:
- first we move to physical start of scanning
either by a fixed steps amount from the black strip
or by a fixed amount from parking position,
minus the steps done during shading calibration
- then we move by the needed offset whitin physical
scanning area
/* Fast move to scan area:
assumption: steps are expressed at maximum motor resolution
we need:
float y_offset;
float y_size;
float y_offset_calib;
mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */
/* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is
relative from origin, else, it is from parking position */
move_dpi = dev->motor.base_ydpi;
move = static_cast<float>(dev->model->y_offset);
move = static_cast<float>(move + dev->settings.tl_y);
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
move -= dev->head_pos(ScanHeadId::PRIMARY);
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
/* fast move to scan area */
/* we don't move fast the whole distance since it would involve
* computing acceleration/deceleration distance for scan
* resolution. So leave a remainder for it so scan makes the final
* move tuning */
if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
We don't move fast the whole distance since it would involve computing
acceleration/deceleration distance for scan resolution. So leave a remainder for it so
scan makes the final move tuning
*/
if (dev->settings.get_channels() * dev->settings.yres >= 600 && session.params.starty > 700) {
scanner_move(*dev, dev->model->default_method,
static_cast<unsigned>(session.params.starty - 500),
Direction::FORWARD);
move=500;
session.params.starty = 500;
}
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
/* start */
start = static_cast<float>(dev->model->x_offset);
start = static_cast<float>(start + dev->settings.tl_x);
start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = dev->settings.pixels;
session.params.requested_pixels = dev->settings.requested_pixels;
session.params.lines = dev->settings.lines;
session.params.depth = dev->settings.depth;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
// backtracking isn't handled well, so don't enable it
session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &dev->reg, session);
init_regs_for_scan_session(dev, sensor, &regs, session);
}
@ -1193,17 +1006,13 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
int num_pixels;
int total_size;
int used_res;
int i, j;
int val;
int channels;
int i;
int avg[3], top[3], bottom[3];
int turn;
uint16_t exp[3];
float move = static_cast<float>(dev->model->y_offset_calib_white);
float move = dev->model->y_offset_calib_white;
move = static_cast<float>((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH);
if(move>20)
{
@ -1213,11 +1022,10 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
DBG(DBG_io, "%s: move=%f steps\n", __func__, move);
/* offset calibration is always done in color mode */
channels = 3;
unsigned channels = 3;
used_res = sensor.get_register_hwdpi(dev->settings.xres);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels,
dev->settings.scan_method);
num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res;
/* initial calibration reg values */
regs = dev->reg;
@ -1227,7 +1035,7 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
session.params.yres = used_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.pixels = dev->model->x_size_calib_mm * used_res / MM_PER_INCH;
session.params.lines = 1;
session.params.depth = 16;
session.params.channels = channels;
@ -1237,14 +1045,12 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
total_size = num_pixels * channels * (session.params.depth / 8) * 1;
std::vector<uint8_t> line(total_size);
/* initial loop values and boundaries */
exp[0] = calib_sensor.exposure.red;
exp[1] = calib_sensor.exposure.green;
@ -1283,37 +1089,24 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
return calib_sensor.exposure;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
// stop scanning
scanner_stop_action(*dev);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
if (DBG_LEVEL >= DBG_data) {
char fn[30];
std::snprintf(fn, 30, "gl846_led_%02d.pnm", turn);
sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth,
channels, num_pixels, 1);
sanei_genesys_write_pnm_file(fn, image);
}
/* compute average */
for (j = 0; j < channels; j++)
{
avg[j] = 0;
for (i = 0; i < num_pixels; i++)
{
if (dev->model->is_cis)
val =
line[i * 2 + j * 2 * num_pixels + 1] * 256 +
line[i * 2 + j * 2 * num_pixels];
else
val =
line[i * 2 * channels + 2 * j + 1] * 256 +
line[i * 2 * channels + 2 * j];
avg[j] += val;
// compute average
for (unsigned ch = 0; ch < channels; ch++) {
avg[ch] = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
avg[ch] += image.get_raw_channel(x, 0, ch);
}
avg[j] /= num_pixels;
avg[ch] /= image.get_width();
}
DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
@ -1529,203 +1322,6 @@ void CommandSetGl846::update_home_sensor_gpio(Genesys_Device& dev) const
dev.interface->write_register(REG_0x6C, val);
}
/** @brief search for a full width black or white strip.
* This function searches for a black or white stripe across the scanning area.
* When searching backward, the searched area must completely be of the desired
* color since this area will be used for calibration which scans forward.
* @param dev scanner device
* @param forward true if searching forward, false if searching backward
* @param black true if searching for a black strip, false for a white strip
*/
void CommandSetGl846::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
bool black) const
{
DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
unsigned int pixels, lines, channels;
Genesys_Register_Set local_reg;
size_t size;
unsigned int pass, count, found, x, y;
char title[80];
set_fe(dev, sensor, AFE_SET);
scanner_stop_action(*dev);
// set up for a gray scan at lowest dpi
const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
unsigned dpi = resolution_settings.get_min_resolution_x();
channels = 1;
/* 10 MM */
/* lines = (10 * dpi) / MM_PER_INCH; */
/* shading calibation is done with dev->motor.base_ydpi */
lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi;
pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res;
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
local_reg = dev->reg;
ScanSession session;
session.params.xres = dpi;
session.params.yres = dpi;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_mode = ScanColorMode::GRAY;
session.params.color_filter = ColorFilter::RED;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA;
if (!forward) {
session.params.flags |= ScanFlag::REVERSE;
}
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &local_reg, session);
size = pixels * channels * lines * (session.params.depth / 8);
std::vector<uint8_t> data(size);
dev->interface->write_registers(local_reg);
begin_scan(dev, sensor, &local_reg, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("search_strip");
scanner_stop_action(*dev);
return;
}
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
scanner_stop_action(*dev);
pass = 0;
if (DBG_LEVEL >= DBG_data)
{
std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm",
black ? "black" : "white", forward ? "fwd" : "bwd", pass);
sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
channels, pixels, lines);
}
/* loop until strip is found or maximum pass number done */
found = 0;
while (pass < 20 && !found)
{
dev->interface->write_registers(local_reg);
// now start scan
begin_scan(dev, sensor, &local_reg, true);
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
scanner_stop_action(*dev);
if (DBG_LEVEL >= DBG_data)
{
std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm",
black ? "black" : "white", forward ? "fwd" : "bwd", pass);
sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
channels, pixels, lines);
}
/* search data to find black strip */
/* when searching forward, we only need one line of the searched color since we
* will scan forward. But when doing backward search, we need all the area of the
* same color */
if (forward)
{
for (y = 0; y < lines && !found; y++)
{
count = 0;
/* count of white/black pixels depending on the color searched */
for (x = 0; x < pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * pixels + x] > 90)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * pixels + x] < 60)
{
count++;
}
}
/* at end of line, if count >= 3%, line is not fully of the desired color
* so we must go to next line of the buffer */
/* count*100/pixels < 3 */
if ((count * 100) / pixels < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
pass, y);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
(100 * count) / pixels);
}
}
}
else /* since calibration scans are done forward, we need the whole area
to be of the required color when searching backward */
{
count = 0;
for (y = 0; y < lines; y++)
{
/* count of white/black pixels depending on the color searched */
for (x = 0; x < pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * pixels + x] > 90)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * pixels + x] < 60)
{
count++;
}
}
}
/* at end of area, if count >= 3%, area is not fully of the desired color
* so we must go to next buffer */
if ((count * 100) / (pixels * lines) < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
(100 * count) / pixels);
}
}
pass++;
}
if (found)
{
DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
}
else
{
throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
}
}
/**
* average dark pixels of a 8 bits scan
*/
@ -1768,9 +1364,9 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
{
DBG_HELPER(dbg);
unsigned channels;
int pass = 0, avg, total_size;
int pass = 0, avg;
int topavg, bottomavg, lines;
int top, bottom, black_pixels, pixels;
int top, bottom, black_pixels;
// no gain nor offset for AKM AFE
uint8_t reg04 = dev->interface->read_register(REG_0x04);
@ -1780,9 +1376,8 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
/* offset calibration is always done in color mode */
channels = 3;
dev->calib_pixels = sensor.sensor_pixels;
lines=1;
pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
@ -1801,18 +1396,14 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
sanei_genesys_set_motor_power(regs, false);
total_size = pixels * channels * lines * (session.params.depth / 8);
std::vector<uint8_t> first_line(total_size);
std::vector<uint8_t> second_line(total_size);
/* init gain */
dev->frontend.set_gain(0, 0);
dev->frontend.set_gain(1, 0);
@ -1834,16 +1425,15 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
return;
}
sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
std::snprintf(fn, 30, "gl846_offset%03d.pnm", bottom);
sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file(fn, first_line);
}
bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels);
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
/* now top value */
@ -1855,9 +1445,9 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
/* loop until acceptable level */
@ -1875,17 +1465,15 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
if (DBG_LEVEL >= DBG_data) {
char fn[30];
std::snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1));
sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file(fn, second_line);
}
avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
/* compute new boundaries */
@ -1910,12 +1498,8 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER(dbg);
int pixels;
int total_size;
int i, j, channels;
int max[3];
float gain[3],coeff;
int val, code, lines;
int code, lines;
DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi);
@ -1926,7 +1510,7 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
}
/* coarse gain calibration is always done in color mode */
channels = 3;
unsigned channels = 3;
/* follow CKSEL */
if(dev->settings.xres<sensor.optical_res)
@ -1938,14 +1522,13 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
coeff=1.0;
}
lines=10;
pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
@ -1955,7 +1538,8 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
@ -1969,10 +1553,6 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
dev->interface->write_registers(regs);
total_size = pixels * channels * (16 / session.params.depth) * lines;
std::vector<uint8_t> line(total_size);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
@ -1983,40 +1563,33 @@ void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys
return;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl846_gain.pnm", line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file("gl846_gain.pnm", image);
}
/* average value on each channel */
for (j = 0; j < channels; j++)
{
max[j] = 0;
for (i = pixels/4; i < (pixels*3/4); i++)
{
if (dev->model->is_cis)
val = line[i + j * pixels];
else
val = line[i * channels + j];
for (unsigned ch = 0; ch < channels; ch++) {
max[j] += val;
auto width = image.get_width();
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
max[j] = max[j] / (pixels/2);
gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
total /= width / 2;
gain[ch] = (static_cast<float>(sensor.gain_white_ref) * coeff) / total;
/* turn logical gain value into gain code, checking for overflow */
code = static_cast<int>(283 - 208 / gain[j]);
if (code > 255)
code = 255;
else if (code < 0)
code = 0;
dev->frontend.set_gain(j, code);
code = static_cast<int>(283 - 208 / gain[ch]);
code = clamp(code, 0, 255);
dev->frontend.set_gain(ch, code);
DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],
dev->frontend.get_gain(j));
DBG(DBG_proc, "%s: channel %d, total=%d, gain = %f, setting:%d\n", __func__, ch,
static_cast<unsigned>(total), gain[ch], dev->frontend.get_gain(ch));
}
if (dev->model->is_cis) {

Wyświetl plik

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL846_H
#define BACKEND_GENESYS_GL846_H
@ -125,7 +125,7 @@ static Memory_layout layouts[]={
{ nullptr, 0, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }
};
class CommandSetGl846 : public CommandSet
class CommandSetGl846 : public CommandSetCommon
{
public:
~CommandSetGl846() override = default;
@ -138,13 +138,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -161,8 +159,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -188,9 +184,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Wyświetl plik

@ -238,9 +238,6 @@ gl847_init_registers (Genesys_Device * dev)
const auto& sensor = sanei_genesys_find_sensor_any(dev);
sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
/* initalize calibration reg */
dev->calib_reg = dev->reg;
}
/**@brief send slope table for motor movement
@ -257,7 +254,6 @@ static void gl847_send_slope_table(Genesys_Device* dev, int table_nr,
{
DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
int i;
char msg[10000];
/* sanity check */
if(table_nr<0 || table_nr>4)
@ -272,16 +268,6 @@ static void gl847_send_slope_table(Genesys_Device* dev, int table_nr,
table[i * 2 + 1] = slope_table[i] >> 8;
}
if (DBG_LEVEL >= DBG_io)
{
std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
for (i = 0; i < steps; i++)
{
std::sprintf(msg + std::strlen(msg), "%d", slope_table[i]);
}
DBG (DBG_io, "%s: %s\n", __func__, msg);
}
if (dev->interface->is_mock()) {
dev->interface->record_slope_table(table_nr, slope_table);
}
@ -354,7 +340,7 @@ void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
static void gl847_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const Motor_Profile& motor_profile,
const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
@ -429,7 +415,7 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
fast_step_type = StepType::QUARTER;
}
Motor_Profile fast_motor_profile = motor_profile;
MotorProfile fast_motor_profile = motor_profile;
fast_motor_profile.step_type = fast_step_type;
auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi,
@ -585,7 +571,7 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
r->value |= REG_0x01_SHDAREA;
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION))
{
r->value &= ~REG_0x01_DVDSET;
}
@ -672,7 +658,7 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
build_image_pipeline(dev, session);
build_image_pipeline(dev, sensor, session);
/* MAXWD is expressed in 4 words unit */
// BUG: we shouldn't multiply by channels here
@ -712,9 +698,7 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene
slope_dpi = slope_dpi * (1 + dummy);
exposure_time = sensor.exposure_lperiod;
const auto& motor_profile = sanei_genesys_get_motor_profile(*gl847_motor_profiles,
dev->model->motor_id,
exposure_time);
const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
DBG(DBG_info, "%s : scan_step_type=%d\n", __func__,
@ -740,9 +724,7 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene
}
gl847_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
dev->model->is_cis ? session.output_line_count * session.params.channels
: session.output_line_count,
dummy, move, mflags);
session.optical_line_count, dummy, move, mflags);
dev->read_buffer.clear();
dev->read_buffer.alloc(session.buffer_size_read);
@ -761,21 +743,33 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
int start;
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
/* start */
start = static_cast<int>(dev->model->x_offset);
start = static_cast<int>(start + settings.tl_x);
start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
/* Steps to move to reach scanning area:
- first we move to physical start of scanning either by a fixed steps amount from the
black strip or by a fixed amount from parking position, minus the steps done during
shading calibration.
- then we move by the needed offset whitin physical scanning area
*/
unsigned move_dpi = dev->motor.base_ydpi;
float move = dev->model->y_offset;
move = move + settings.tl_y;
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
move -= dev->head_pos(ScanHeadId::PRIMARY);
float start = dev->model->x_offset;
start = start + dev->settings.tl_x;
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
session.params.startx = start; // not used
session.params.starty = 0; // not used
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@ -784,7 +778,8 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
session.params.flags = ScanFlag::NONE;
// backtracking isn't handled well, so don't enable it
session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, sensor);
@ -860,249 +855,71 @@ void CommandSetGl847::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
// from very top of scanner
void CommandSetGl847::search_start_position(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
int size;
Genesys_Register_Set local_reg;
int pixels = 600;
int dpi = 300;
local_reg = dev->reg;
/* sets for a 200 lines * 600 pixels */
/* normal scan with no shading */
// FIXME: the current approach of doing search only for one resolution does not work on scanners
// whith employ different sensors with potentially different settings.
const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
ScanSession session;
session.params.xres = dpi;
session.params.yres = dpi;
session.params.startx = 0;
session.params.starty = 0; /*we should give a small offset here~60 steps */
session.params.pixels = 600;
session.params.lines = dev->model->search_lines;
session.params.depth = 8;
session.params.channels = 1;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::GRAY;
session.params.color_filter = ColorFilter::GREEN;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &local_reg, session);
// send to scanner
dev->interface->write_registers(local_reg);
size = pixels * dev->model->search_lines;
std::vector<uint8_t> data(size);
begin_scan(dev, sensor, &local_reg, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("search_start_position");
end_scan(dev, &local_reg, true);
dev->reg = local_reg;
return;
}
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels,
dev->model->search_lines);
}
end_scan(dev, &local_reg, true);
/* update regs to copy ASIC internal state */
dev->reg = local_reg;
// TODO: find out where sanei_genesys_search_reference_point stores information,
// and use that correctly
for (auto& sensor_update :
sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
{
sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
dev->model->search_lines);
}
}
// sets up register for coarse gain calibration
// todo: check it for scanners using it
void CommandSetGl847::init_regs_for_coarse_calibration(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
session.params.lines = 20;
session.params.depth = 16;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
dev->interface->write_registers(regs);
}
// init registers for shading calibration
void CommandSetGl847::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
dev->calib_channels = 3;
unsigned channels = 3;
/* initial calibration reg values */
regs = dev->reg;
unsigned resolution = sensor.get_register_hwdpi(dev->settings.xres);
dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution,
dev->calib_channels,
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
dev->calib_total_bytes_to_read = 0;
dev->calib_lines = dev->model->shading_lines;
if (dev->calib_resolution == 4800) {
dev->calib_lines *= 2;
}
dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) /
calib_sensor.optical_res;
DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines);
DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels);
unsigned calib_lines =
static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH);
ScanSession session;
session.params.xres = dev->calib_resolution;
session.params.yres = dev->motor.base_ydpi;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 20;
session.params.pixels = dev->calib_pixels;
session.params.lines = dev->calib_lines;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;;
session.params.lines = calib_lines;
session.params.depth = 16;
session.params.channels = dev->calib_channels;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::DISABLE_BUFFER_FULL_MOVE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
dev->interface->write_registers(regs);
/* we use GENESYS_FLAG_SHADING_REPARK */
/* we use ModelFlag::SHADING_REPARK */
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
dev->calib_session = session;
}
/** @brief set up registers for the actual scan
*/
void CommandSetGl847::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
void CommandSetGl847::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
float move;
int move_dpi;
float start;
debug_dump(DBG_info, dev->settings);
auto session = calculate_scan_session(dev, sensor, dev->settings);
/* steps to move to reach scanning area:
- first we move to physical start of scanning
either by a fixed steps amount from the black strip
or by a fixed amount from parking position,
minus the steps done during shading calibration
- then we move by the needed offset whitin physical
scanning area
/* Fast move to scan area:
assumption: steps are expressed at maximum motor resolution
we need:
float y_offset;
float y_size;
float y_offset_calib;
mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */
/* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is
relative from origin, else, it is from parking position */
move_dpi = dev->motor.base_ydpi;
move = static_cast<float>(dev->model->y_offset);
move = static_cast<float>(move + dev->settings.tl_y);
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
move -= dev->head_pos(ScanHeadId::PRIMARY);
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
/* fast move to scan area */
/* we don't move fast the whole distance since it would involve
* computing acceleration/deceleration distance for scan
* resolution. So leave a remainder for it so scan makes the final
* move tuning */
if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
We don't move fast the whole distance since it would involve computing
acceleration/deceleration distance for scan resolution. So leave a remainder for it so
scan makes the final move tuning
*/
if (dev->settings.get_channels() * dev->settings.yres >= 600 && session.params.starty > 700) {
scanner_move(*dev, dev->model->default_method,
static_cast<unsigned>(session.params.starty - 500),
Direction::FORWARD);
move=500;
session.params.starty = 500;
}
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
/* start */
start = static_cast<float>(dev->model->x_offset);
start = static_cast<float>(start + dev->settings.tl_x);
start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = dev->settings.pixels;
session.params.requested_pixels = dev->settings.requested_pixels;
session.params.lines = dev->settings.lines;
session.params.depth = dev->settings.depth;
session.params.channels = dev->settings.get_channels();
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
// backtracking isn't handled well, so don't enable it
session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &dev->reg, session);
init_regs_for_scan_session(dev, sensor, &regs, session);
}
@ -1193,18 +1010,14 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
int num_pixels;
int total_size;
int used_res;
int i, j;
int val;
int channels;
int i;
int avg[3], top[3], bottom[3];
int turn;
uint16_t exp[3];
float move;
move = static_cast<float>(dev->model->y_offset_calib_white);
move = dev->model->y_offset_calib_white;
move = static_cast<float>((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH);
if (move > 20) {
scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move),
@ -1213,11 +1026,10 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
DBG(DBG_io, "%s: move=%f steps\n", __func__, move);
/* offset calibration is always done in color mode */
channels = 3;
unsigned channels = 3;
used_res = sensor.get_register_hwdpi(dev->settings.xres);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels,
dev->settings.scan_method);
num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res;
/* initial calibration reg values */
regs = dev->reg;
@ -1227,7 +1039,7 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
session.params.yres = used_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.pixels = dev->model->x_size_calib_mm * used_res / MM_PER_INCH;
session.params.lines = 1;
session.params.depth = 16;
session.params.channels = channels;
@ -1237,14 +1049,12 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
total_size = num_pixels * channels * (session.params.depth/8) * 1;
std::vector<uint8_t> line(total_size);
// initial loop values and boundaries
exp[0] = calib_sensor.exposure.red;
exp[1] = calib_sensor.exposure.green;
@ -1283,38 +1093,25 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
return calib_sensor.exposure;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
// stop scanning
scanner_stop_action(*dev);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
if (DBG_LEVEL >= DBG_data) {
char fn[30];
std::snprintf(fn, 30, "gl847_led_%02d.pnm", turn);
sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth,
channels, num_pixels, 1);
}
sanei_genesys_write_pnm_file(fn, image);
}
/* compute average */
for (j = 0; j < channels; j++)
{
avg[j] = 0;
for (i = 0; i < num_pixels; i++)
{
if (dev->model->is_cis)
val =
line[i * 2 + j * 2 * num_pixels + 1] * 256 +
line[i * 2 + j * 2 * num_pixels];
else
val =
line[i * 2 * channels + 2 * j + 1] * 256 +
line[i * 2 * channels + 2 * j];
avg[j] += val;
}
avg[j] /= num_pixels;
}
// compute average
for (unsigned ch = 0; ch < channels; ch++) {
avg[ch] = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
avg[ch] += image.get_raw_channel(x, 0, ch);
}
avg[ch] /= image.get_width();
}
DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
@ -1566,203 +1363,6 @@ void CommandSetGl847::update_home_sensor_gpio(Genesys_Device& dev) const
}
}
/** @brief search for a full width black or white strip.
* This function searches for a black or white stripe across the scanning area.
* When searching backward, the searched area must completely be of the desired
* color since this area will be used for calibration which scans forward.
* @param dev scanner device
* @param forward true if searching forward, false if searching backward
* @param black true if searching for a black strip, false for a white strip
*/
void CommandSetGl847::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
bool black) const
{
DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
unsigned int pixels, lines, channels;
Genesys_Register_Set local_reg;
size_t size;
unsigned int pass, count, found, x, y;
char title[80];
set_fe(dev, sensor, AFE_SET);
scanner_stop_action(*dev);
// set up for a gray scan at lowest dpi
const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
unsigned dpi = resolution_settings.get_min_resolution_x();
channels = 1;
/* 10 MM */
/* lines = (10 * dpi) / MM_PER_INCH; */
/* shading calibation is done with dev->motor.base_ydpi */
lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi;
pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res;
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
local_reg = dev->reg;
ScanSession session;
session.params.xres = dpi;
session.params.yres = dpi;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::GRAY;
session.params.color_filter = ColorFilter::RED;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA;
if (!forward) {
session.params.flags |= ScanFlag::REVERSE;
}
compute_session(dev, session, sensor);
size = pixels * channels * lines * (session.params.depth / 8);
std::vector<uint8_t> data(size);
init_regs_for_scan_session(dev, sensor, &local_reg, session);
dev->interface->write_registers(local_reg);
begin_scan(dev, sensor, &local_reg, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("search_strip");
scanner_stop_action(*dev);
return;
}
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
scanner_stop_action(*dev);
pass = 0;
if (DBG_LEVEL >= DBG_data)
{
std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm",
black ? "black" : "white", forward ? "fwd" : "bwd", pass);
sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
channels, pixels, lines);
}
/* loop until strip is found or maximum pass number done */
found = 0;
while (pass < 20 && !found)
{
dev->interface->write_registers(local_reg);
// now start scan
begin_scan(dev, sensor, &local_reg, true);
wait_until_buffer_non_empty(dev);
// now we're on target, we can read data
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
scanner_stop_action(*dev);
if (DBG_LEVEL >= DBG_data)
{
std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm",
black ? "black" : "white",
forward ? "fwd" : "bwd", static_cast<int>(pass));
sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
channels, pixels, lines);
}
/* search data to find black strip */
/* when searching forward, we only need one line of the searched color since we
* will scan forward. But when doing backward search, we need all the area of the
* same color */
if (forward)
{
for (y = 0; y < lines && !found; y++)
{
count = 0;
/* count of white/black pixels depending on the color searched */
for (x = 0; x < pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * pixels + x] > 90)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * pixels + x] < 60)
{
count++;
}
}
/* at end of line, if count >= 3%, line is not fully of the desired color
* so we must go to next line of the buffer */
/* count*100/pixels < 3 */
if ((count * 100) / pixels < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
pass, y);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
(100 * count) / pixels);
}
}
}
else /* since calibration scans are done forward, we need the whole area
to be of the required color when searching backward */
{
count = 0;
for (y = 0; y < lines; y++)
{
/* count of white/black pixels depending on the color searched */
for (x = 0; x < pixels; x++)
{
/* when searching for black, detect white pixels */
if (black && data[y * pixels + x] > 90)
{
count++;
}
/* when searching for white, detect black pixels */
if (!black && data[y * pixels + x] < 60)
{
count++;
}
}
}
/* at end of area, if count >= 3%, area is not fully of the desired color
* so we must go to next buffer */
if ((count * 100) / (pixels * lines) < 3)
{
found = 1;
DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
}
else
{
DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
(100 * count) / pixels);
}
}
pass++;
}
if (found)
{
DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
}
else
{
throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
}
}
/**
* average dark pixels of a 8 bits scan
*/
@ -1805,9 +1405,9 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
{
DBG_HELPER(dbg);
unsigned channels;
int pass = 0, avg, total_size;
int pass = 0, avg;
int topavg, bottomavg, lines;
int top, bottom, black_pixels, pixels;
int top, bottom, black_pixels;
// no gain nor offset for AKM AFE
uint8_t reg04 = dev->interface->read_register(REG_0x04);
@ -1817,9 +1417,8 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
/* offset calibration is always done in color mode */
channels = 3;
dev->calib_pixels = sensor.sensor_pixels;
lines=1;
pixels= (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
@ -1838,19 +1437,14 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, &regs, session);
sanei_genesys_set_motor_power(regs, false);
/* allocate memory for scans */
total_size = pixels * channels * lines * (session.params.depth / 8); /* colors * bytes_per_color * scan lines */
std::vector<uint8_t> first_line(total_size);
std::vector<uint8_t> second_line(total_size);
/* init gain */
dev->frontend.set_gain(0, 0);
dev->frontend.set_gain(1, 0);
@ -1872,16 +1466,14 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
return;
}
sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data) {
char fn[30];
std::snprintf(fn, 30, "gl847_offset%03d.pnm", bottom);
sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth,
channels, pixels, lines);
}
sanei_genesys_write_pnm_file(fn, first_line);
}
bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels);
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
/* now top value */
@ -1893,9 +1485,9 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
/* loop until acceptable level */
@ -1913,17 +1505,15 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->interface->write_registers(regs);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
begin_scan(dev, sensor, &regs, true);
sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data)
{
char fn[30];
if (DBG_LEVEL >= DBG_data) {
char fn[30];
std::snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1));
sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth,
channels, pixels, lines);
}
sanei_genesys_write_pnm_file(fn, second_line);
}
avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
/* compute new boundaries */
@ -1948,12 +1538,8 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
int pixels;
int total_size;
int i, j, channels;
int max[3];
float gain[3],coeff;
int val, code, lines;
int code, lines;
// no gain nor offset for AKM AFE
uint8_t reg04 = dev->interface->read_register(REG_0x04);
@ -1962,7 +1548,7 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
}
/* coarse gain calibration is always done in color mode */
channels = 3;
unsigned channels = 3;
/* follow CKSEL */
if(dev->settings.xres<sensor.optical_res)
@ -1974,14 +1560,13 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
coeff=1.0;
}
lines=10;
pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = pixels;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
@ -1991,7 +1576,8 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_LINE_DISTANCE;
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
@ -2005,10 +1591,6 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
dev->interface->write_registers(regs);
total_size = pixels * channels * (16 / session.params.depth) * lines;
std::vector<uint8_t> line(total_size);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
@ -2019,41 +1601,33 @@ void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys
return;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), session.params.depth,
channels, pixels, lines);
sanei_genesys_write_pnm_file("gl847_gain.pnm", image);
}
/* average value on each channel */
for (j = 0; j < channels; j++)
{
max[j] = 0;
for (i = pixels/4; i < (pixels*3/4); i++)
{
if (dev->model->is_cis) {
val = line[i + j * pixels];
} else {
val = line[i * channels + j];
}
for (unsigned ch = 0; ch < channels; ch++) {
max[j] += val;
}
max[j] = max[j] / (pixels/2);
auto width = image.get_width();
gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
total /= width / 2;
gain[ch] = (static_cast<float>(sensor.gain_white_ref) * coeff) / total;
/* turn logical gain value into gain code, checking for overflow */
code = static_cast<int>(283 - 208 / gain[j]);
if (code > 255)
code = 255;
else if (code < 0)
code = 0;
dev->frontend.set_gain(j, code);
code = static_cast<int>(283 - 208 / gain[ch]);
code = clamp(code, 0, 255);
dev->frontend.set_gain(ch, code);
DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],
dev->frontend.get_gain(j));
DBG(DBG_proc, "%s: channel %d, total=%d, gain = %f, setting:%d\n", __func__, ch,
static_cast<unsigned>(total), gain[ch], dev->frontend.get_gain(ch));
}
if (dev->model->is_cis) {

Wyświetl plik

@ -45,7 +45,7 @@
#define BACKEND_GENESYS_GL847_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
namespace genesys {
namespace gl847 {
@ -113,7 +113,7 @@ static Memory_layout layouts[]={
}
};
class CommandSetGl847 : public CommandSet
class CommandSetGl847 : public CommandSetCommon
{
public:
~CommandSetGl847() override = default;
@ -126,13 +126,11 @@ public:
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
@ -149,8 +147,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -176,9 +172,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,

Wyświetl plik

@ -89,47 +89,11 @@ bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data)
return got_data;
}
void FakeBufferModel::push_step(std::size_t buffer_size, std::size_t row_bytes)
{
sizes_.push_back(buffer_size);
available_sizes_.push_back(0);
row_bytes_.push_back(row_bytes);
}
std::size_t FakeBufferModel::available_space() const
{
if (sizes_.empty())
throw SaneException("Model has not been setup");
return sizes_.front() - available_sizes_.front();
}
void FakeBufferModel::simulate_read(std::size_t size)
{
if (sizes_.empty()) {
throw SaneException("Model has not been setup");
}
if (available_space() < size) {
throw SaneException("Attempted to simulate read of too much memory");
}
available_sizes_.front() += size;
for (unsigned i = 1; i < sizes_.size(); ++i) {
auto avail_src = available_sizes_[i - 1];
auto avail_dst = sizes_[i] - available_sizes_[i];
auto avail = (std::min(avail_src, avail_dst) / row_bytes_[i]) * row_bytes_[i];
available_sizes_[i - 1] -= avail;
available_sizes_[i] += avail;
}
available_sizes_.back() = 0;
}
ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size,
const FakeBufferModel& buffer_model,
std::size_t buffer_size,
ProducerCallback producer) :
remaining_size_{total_size},
buffer_model_{buffer_model},
buffer_size_{buffer_size},
producer_{producer}
{}
@ -179,7 +143,7 @@ bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data)
std::size_t ImageBufferGenesysUsb::get_read_size()
{
std::size_t size = buffer_model_.available_space();
std::size_t size = buffer_size_;
// never read an odd number. exception: last read
// the chip internal counter does not count half words.
@ -195,8 +159,6 @@ std::size_t ImageBufferGenesysUsb::get_read_size()
size &= ~0xff;
}
buffer_model_.simulate_read(size);
return size;
}

Wyświetl plik

@ -73,23 +73,6 @@ private:
std::vector<std::uint8_t> buffer_;
};
class FakeBufferModel
{
public:
FakeBufferModel() {}
void push_step(std::size_t buffer_size, std::size_t row_bytes);
std::size_t available_space() const;
void simulate_read(std::size_t size);
private:
std::vector<std::size_t> sizes_;
std::vector<std::size_t> available_sizes_;
std::vector<std::size_t> row_bytes_;
};
// This class is similar to ImageBuffer, but preserves historical peculiarities of buffer handling
// in the backend to preserve exact behavior
class ImageBufferGenesysUsb
@ -98,7 +81,7 @@ public:
using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
ImageBufferGenesysUsb() {}
ImageBufferGenesysUsb(std::size_t total_size, const FakeBufferModel& buffer_model,
ImageBufferGenesysUsb(std::size_t total_size, std::size_t buffer_size,
ProducerCallback producer);
std::size_t remaining_size() const { return remaining_size_; }
@ -115,12 +98,12 @@ private:
std::size_t remaining_size_ = 0;
std::size_t buffer_size_ = 0;
std::size_t buffer_offset_ = 0;
std::size_t buffer_end_ = 0;
std::vector<std::uint8_t> buffer_;
FakeBufferModel buffer_model_;
ProducerCallback producer_;
};

Wyświetl plik

@ -109,11 +109,11 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb(
std::size_t width, std::size_t height, PixelFormat format, std::size_t total_size,
const FakeBufferModel& buffer_model, ProducerCallback producer) :
std::size_t buffer_size, ProducerCallback producer) :
width_{width},
height_{height},
format_{format},
buffer_{total_size, buffer_model, producer}
buffer_{total_size, buffer_size, producer}
{
set_remaining_bytes(total_size);
}
@ -666,16 +666,21 @@ bool ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data)
ImagePipelineNodeCalibrate::ImagePipelineNodeCalibrate(ImagePipelineNode& source,
const std::vector<std::uint16_t>& bottom,
const std::vector<std::uint16_t>& top) :
const std::vector<std::uint16_t>& top,
std::size_t x_start) :
source_{source}
{
auto size = std::min(bottom.size(), top.size());
std::size_t size = 0;
if (bottom.size() >= x_start && top.size() >= x_start) {
size = std::min(bottom.size() - x_start, top.size() - x_start);
}
offset_.reserve(size);
multiplier_.reserve(size);
for (std::size_t i = 0; i < size; ++i) {
offset_.push_back(bottom[i] / 65535.0f);
multiplier_.push_back(65535.0f / (top[i] - bottom[i]));
offset_.push_back(bottom[i + x_start] / 65535.0f);
multiplier_.push_back(65535.0f / (top[i + x_start] - bottom[i + x_start]));
}
}

Wyświetl plik

@ -157,8 +157,7 @@ public:
ImagePipelineNodeBufferedGenesysUsb(std::size_t width, std::size_t height,
PixelFormat format, std::size_t total_size,
const FakeBufferModel& buffer_model,
ProducerCallback producer);
std::size_t buffer_size, ProducerCallback producer);
std::size_t get_width() const override { return width_; }
std::size_t get_height() const override { return height_; }
@ -476,7 +475,7 @@ class ImagePipelineNodeCalibrate : public ImagePipelineNode
public:
ImagePipelineNodeCalibrate(ImagePipelineNode& source, const std::vector<std::uint16_t>& bottom,
const std::vector<std::uint16_t>& top);
const std::vector<std::uint16_t>& top, std::size_t x_start);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height(); }

Wyświetl plik

@ -516,7 +516,7 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
dev->model->line_mode_color_order);
auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
auto height = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1);
auto height = session.optical_line_count;
Image image(width, height, format);
@ -534,26 +534,33 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
ImagePipelineStack pipeline;
pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && session.params.depth == 16) {
dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
if (session.segment_count > 1) {
auto output_width = session.output_segment_pixel_group_count * session.segment_count;
pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
session.conseq_pixel_dist,
1, 1);
}
if (has_flag(dev->model->flags, ModelFlag::INVERTED_16BIT_DATA) && session.params.depth == 16) {
pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
}
#ifdef WORDS_BIGENDIAN
if (depth == 16) {
dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
if (session.params.depth == 16) {
pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
}
#endif
if (dev->model->is_cis && session.params.channels == 3) {
dev->pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
}
if (dev->pipeline.get_output_format() == PixelFormat::BGR888) {
dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
if (pipeline.get_output_format() == PixelFormat::BGR888) {
pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
}
if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) {
dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
if (pipeline.get_output_format() == PixelFormat::BGR161616) {
pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
}
return pipeline.get_image();
@ -615,20 +622,9 @@ void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sen
regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
if (dev->model->asic_type == AsicType::GL841) {
regs_set_exposure(dev->model->asic_type, regs, {0x0101, 0x0101, 0x0101});
regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
regs.set8(0x19, 0xff);
}
if (dev->model->asic_type == AsicType::GL843) {
if (dev->model->model_id == ModelId::PANASONIC_KV_SS080 ||
dev->model->model_id == ModelId::HP_SCANJET_4850C ||
dev->model->model_id == ModelId::HP_SCANJET_G4010 ||
dev->model->model_id == ModelId::HP_SCANJET_G4050)
{
// BUG: datasheet says we shouldn't set exposure to zero
regs_set_exposure(dev->model->asic_type, regs, {0, 0, 0});
}
}
}
regs.state.is_lamp_on = set;
}
@ -794,70 +790,9 @@ static unsigned align_int_up(unsigned num, unsigned alignment)
return num;
}
void compute_session_buffer_sizes(AsicType asic, ScanSession& s)
std::size_t compute_session_buffer_sizes(const ScanSession& s)
{
size_t line_bytes = s.output_line_bytes;
size_t line_bytes_stagger = s.output_line_bytes;
if (asic != AsicType::GL646) {
// BUG: this is historical artifact and should be removed. Note that buffer sizes affect
// how often we request the scanner for data and thus change the USB traffic.
line_bytes_stagger =
multiply_by_depth_ceil(s.optical_pixels, s.params.depth) * s.params.channels;
}
struct BufferConfig {
size_t* result_size = nullptr;
size_t lines = 0;
size_t lines_mult = 0;
size_t max_size = 0; // does not apply if 0
size_t stagger_lines = 0;
BufferConfig() = default;
BufferConfig(std::size_t* rs, std::size_t l, std::size_t lm, std::size_t ms,
std::size_t sl) :
result_size{rs},
lines{l},
lines_mult{lm},
max_size{ms},
stagger_lines{sl}
{}
};
std::array<BufferConfig, 4> configs;
if (asic == AsicType::GL124 || asic == AsicType::GL843) {
configs = { {
{ &s.buffer_size_read, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_lines, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_shrink, 16, 1, 0, 0 },
{ &s.buffer_size_out, 8, 1, 0, 0 },
} };
} else if (asic == AsicType::GL841) {
size_t max_buf = sanei_genesys_get_bulk_max_size(asic);
configs = { {
{ &s.buffer_size_read, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_lines, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_shrink, 8, 1, max_buf, 0 },
{ &s.buffer_size_out, 8, 1, 0, 0 },
} };
} else {
configs = { {
{ &s.buffer_size_read, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_lines, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
{ &s.buffer_size_shrink, 8, 1, 0, 0 },
{ &s.buffer_size_out, 8, 1, 0, 0 },
} };
}
for (BufferConfig& config : configs) {
size_t buf_size = line_bytes * config.lines;
if (config.max_size > 0 && buf_size > config.max_size) {
buf_size = (config.max_size / line_bytes) * line_bytes;
}
buf_size *= config.lines_mult;
buf_size += line_bytes_stagger * config.stagger_lines;
*config.result_size = buf_size;
}
return s.output_line_bytes * (32 + s.max_color_shift_lines + s.num_staggered_lines);
}
void compute_session_pipeline(const Genesys_Device* dev, ScanSession& s)
@ -900,7 +835,7 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
if (has_flag(s.params.flags, ScanFlag::USE_XCORRECTION) && sensor.ccd_start_xoffset > 0) {
s.pixel_startx = sensor.ccd_start_xoffset;
}
s.pixel_startx += s.params.startx;
s.pixel_startx += s.params.startx * sensor.optical_res / s.params.xres;
if (sensor.stagger_config.stagger_at_resolution(s.params.xres, s.params.yres) > 0) {
s.pixel_startx |= 1;
@ -912,7 +847,9 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
s.pixel_endx /= sensor.ccd_pixels_per_system_pixel() * s.ccd_size_divisor;
} else if (dev->model->asic_type == AsicType::GL841) {
s.pixel_startx = ((sensor.ccd_start_xoffset + s.params.startx) * s.optical_resolution)
unsigned startx = s.params.startx * sensor.optical_res / s.params.xres;
s.pixel_startx = ((sensor.ccd_start_xoffset + startx) * s.optical_resolution)
/ sensor.optical_res;
s.pixel_startx += sensor.dummy_pixel + 1;
@ -937,15 +874,22 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
s.pixel_endx = s.pixel_startx + s.optical_pixels;
} else if (dev->model->asic_type == AsicType::GL843) {
unsigned startx = s.params.startx * sensor.optical_res / s.params.xres;
s.pixel_startx = (s.params.startx + sensor.dummy_pixel) / ccd_pixels_per_system_pixel;
s.pixel_startx = (startx + sensor.dummy_pixel) / ccd_pixels_per_system_pixel;
s.pixel_endx = s.pixel_startx + s.optical_pixels / ccd_pixels_per_system_pixel;
s.pixel_startx /= s.hwdpi_divisor;
s.pixel_endx /= s.hwdpi_divisor;
// in case of stagger we have to start at an odd coordinate
bool stagger_starts_even = dev->model->model_id == ModelId::CANON_8400F;
bool stagger_starts_even = false;
if (dev->model->model_id == ModelId::CANON_4400F ||
dev->model->model_id == ModelId::CANON_8400F)
{
stagger_starts_even = true;
}
if (s.num_staggered_lines > 0) {
if (!stagger_starts_even && (s.pixel_startx & 1) == 0) {
s.pixel_startx++;
@ -960,7 +904,9 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
dev->model->asic_type == AsicType::GL846 ||
dev->model->asic_type == AsicType::GL847)
{
s.pixel_startx = s.params.startx;
unsigned startx = s.params.startx * sensor.optical_res / s.params.xres;
s.pixel_startx = startx;
if (s.num_staggered_lines > 0) {
s.pixel_startx |= 1;
@ -973,7 +919,9 @@ void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
s.pixel_endx /= s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel;
} else if (dev->model->asic_type == AsicType::GL124) {
s.pixel_startx = s.params.startx;
unsigned startx = s.params.startx * sensor.optical_res / s.params.xres;
s.pixel_startx = startx;
if (s.num_staggered_lines > 0) {
s.pixel_startx |= 1;
@ -1067,9 +1015,8 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
// to retrieve from the chip
s.output_pixels = (s.optical_pixels * s.output_resolution) / s.optical_resolution;
// Note: staggering is not applied for calibration. Staggering starts at 2400 dpi
s.num_staggered_lines = 0;
if (!has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE))
if (!has_flag(s.params.flags, ScanFlag::IGNORE_STAGGER_OFFSET))
{
s.num_staggered_lines = sensor.stagger_config.stagger_at_resolution(s.params.xres,
s.params.yres);
@ -1091,12 +1038,14 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.color_shift_lines_b = (s.color_shift_lines_b * s.params.yres) / dev->motor.base_ydpi;
s.max_color_shift_lines = 0;
if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE)) {
if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_COLOR_OFFSET)) {
s.max_color_shift_lines = std::max(s.color_shift_lines_r, std::max(s.color_shift_lines_g,
s.color_shift_lines_b));
}
s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines;
s.optical_line_count = dev->model->is_cis ? s.output_line_count * s.params.channels
: s.output_line_count;
s.output_channel_bytes = multiply_by_depth_ceil(s.output_pixels, s.params.depth);
s.output_line_bytes = s.output_channel_bytes * s.params.channels;
@ -1150,16 +1099,15 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
if (dev->model->asic_type == AsicType::GL124 ||
dev->model->asic_type == AsicType::GL843)
{
s.output_segment_pixel_group_count = multiply_by_depth_ceil(
s.output_pixels / s.ccd_size_divisor / s.segment_count, s.params.depth);
s.output_segment_pixel_group_count = s.output_pixels /
(s.ccd_size_divisor * s.segment_count);
}
if (dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846 ||
dev->model->asic_type == AsicType::GL847)
{
s.output_segment_pixel_group_count = multiply_by_depth_ceil(
s.optical_pixels / (s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel),
s.params.depth);
s.output_segment_pixel_group_count = s.optical_pixels /
(s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel);
}
s.output_line_bytes_requested = multiply_by_depth_ceil(
@ -1168,7 +1116,7 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count;
s.output_total_bytes = s.output_line_bytes * s.output_line_count;
compute_session_buffer_sizes(dev->model->asic_type, s);
s.buffer_size_read = compute_session_buffer_sizes(s);
compute_session_pipeline(dev, s);
compute_session_pixel_offsets(dev, s, sensor);
@ -1179,6 +1127,8 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis && dev->settings.true_gray);
}
s.use_host_side_calib = sensor.use_host_side_calib;
if (dev->model->asic_type == AsicType::GL841 ||
dev->model->asic_type == AsicType::GL843)
{
@ -1219,25 +1169,8 @@ static std::size_t get_usb_buffer_read_size(AsicType asic, const ScanSession& se
}
}
static FakeBufferModel get_fake_usb_buffer_model(const ScanSession& session)
{
FakeBufferModel model;
model.push_step(session.buffer_size_read, 1);
if (session.pipeline_needs_reorder) {
model.push_step(session.buffer_size_lines, session.output_line_bytes);
}
if (session.pipeline_needs_ccd) {
model.push_step(session.buffer_size_shrink, session.output_line_bytes);
}
if (session.pipeline_needs_shrink) {
model.push_step(session.buffer_size_out, session.output_line_bytes);
}
return model;
}
void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
void build_image_pipeline(Genesys_Device* dev, const Genesys_Sensor& sensor,
const ScanSession& session)
{
static unsigned s_pipeline_index = 0;
@ -1255,7 +1188,7 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
return true;
};
auto lines = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1);
auto lines = session.optical_line_count;
dev->pipeline.clear();
@ -1281,7 +1214,7 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
dev->pipeline.push_first_node<ImagePipelineNodeBufferedGenesysUsb>(
width, lines, format, read_bytes_left_after_deseg,
get_fake_usb_buffer_model(session), read_data_from_usb);
session.buffer_size_read, read_data_from_usb);
}
if (DBG_LEVEL >= DBG_io2) {
@ -1290,7 +1223,7 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
"_0_before_swap.pnm");
}
if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && depth == 16) {
if (has_flag(dev->model->flags, ModelFlag::INVERTED_16BIT_DATA) && depth == 16) {
dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
}
@ -1342,11 +1275,19 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
"_3_after_stagger.pnm");
}
if ((dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) &&
!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
if (session.use_host_side_calib &&
!has_flag(dev->model->flags, ModelFlag::NO_CALIBRATION) &&
!has_flag(session.params.flags, ScanFlag::DISABLE_SHADING))
{
unsigned pixel_shift = session.params.startx;
if (dev->model->model_id == ModelId::CANON_4400F) {
pixel_shift =
session.params.startx * sensor.optical_res / dev->calib_session.params.xres;
}
dev->pipeline.push_node<ImagePipelineNodeCalibrate>(dev->dark_average_data,
dev->white_average_data);
dev->white_average_data,
pixel_shift *
dev->calib_session.params.channels);
if (DBG_LEVEL >= DBG_io2) {
dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
@ -1486,8 +1427,7 @@ void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/)
dev->settings.color_filter = ColorFilter::RED;
/* duplicate initial values into calibration registers */
dev->calib_reg = dev->reg;
dev->initial_regs = dev->reg;
const auto& sensor = sanei_genesys_find_sensor_any(dev);
@ -1497,8 +1437,15 @@ void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/)
dev->already_initialized = true;
// Move to home if needed
if (dev->model->model_id == ModelId::CANON_8600F) {
if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::SECONDARY)) {
dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
}
if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::PRIMARY)) {
dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
}
}
dev->cmd_set->move_back_home(dev, true);
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
// Set powersaving (default = 15 minutes)
dev->cmd_set->set_powersaving(dev, 15);
@ -1706,63 +1653,61 @@ void sanei_genesys_wait_for_home(Genesys_Device* dev)
}
}
/** @brief motor profile
* search for the database of motor profiles and get the best one. Each
* profile is at full step and at a reference exposure. Use first entry
* by default.
* @param motors motor profile database
* @param motor_type motor id
* @param exposure exposure time
* @return a pointer to a Motor_Profile struct
*/
const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector<Motor_Profile>& motors,
MotorId motor_id, int exposure)
const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session)
{
int idx;
int best_i = -1;
idx=-1;
for (std::size_t i = 0; i < motors.size(); ++i) {
// exact match
if (motors[i].motor_id == motor_id && motors[i].exposure==exposure) {
return motors[i];
for (unsigned i = 0; i < profiles.size(); ++i) {
const auto& profile = profiles[i];
if (!profile.resolutions.matches(session.params.yres)) {
continue;
}
if (!profile.scan_methods.matches(session.params.scan_method)) {
continue;
}
// closest match
if (motors[i].motor_id == motor_id) {
/* if profile exposure is higher than the required one,
* the entry is a candidate for the closest match */
if (motors[i].exposure == 0 || motors[i].exposure >= exposure)
{
if(idx<0)
{
/* no match found yet */
idx=i;
}
else
{
/* test for better match */
if(motors[i].exposure<motors[idx].exposure)
{
idx=i;
}
if (profile.max_exposure == exposure) {
return &profile;
}
if (profile.max_exposure == 0 || profile.max_exposure >= exposure) {
if (best_i < 0) {
// no match found yet
best_i = i;
} else {
// test for better match
if (profiles[i].max_exposure < profiles[best_i].max_exposure) {
best_i = i;
}
}
}
}
/* default fallback */
if(idx<0)
{
DBG (DBG_warn,"%s: using default motor profile\n",__func__);
idx=0;
if (best_i < 0) {
return nullptr;
}
return motors[idx];
return &profiles[best_i];
}
const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session)
{
const auto* profile = get_motor_profile_ptr(profiles, exposure, session);
if (profile == nullptr) {
throw SaneException("Motor slope is not configured");
}
return *profile;
}
MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
unsigned step_multiplier,
const Motor_Profile& motor_profile)
const MotorProfile& motor_profile)
{
unsigned target_speed_w = ((exposure * dpi) / base_dpi);
@ -1773,7 +1718,7 @@ MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int expos
}
MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
const Motor_Profile& motor_profile)
const MotorProfile& motor_profile)
{
return create_slope_table(motor_profile.slope, motor_profile.slope.max_speed_w,
motor_profile.step_type,

Wyświetl plik

@ -108,39 +108,6 @@
#define GENESYS_GREEN 1
#define GENESYS_BLUE 2
/* Flags */
#define GENESYS_FLAG_UNTESTED (1 << 0) /**< Print a warning for these scanners */
#define GENESYS_FLAG_14BIT_GAMMA (1 << 1) /**< use 14bit Gamma table instead of 12 */
#define GENESYS_FLAG_XPA (1 << 3)
#define GENESYS_FLAG_SKIP_WARMUP (1 << 4) /**< skip genesys_warmup() */
/** @brief offset calibration flag
* signals that the scanner does offset calibration. In this case off_calibration() and
* coarse_gain_calibration() functions must be implemented
*/
#define GENESYS_FLAG_OFFSET_CALIBRATION (1 << 5)
#define GENESYS_FLAG_SEARCH_START (1 << 6) /**< do start search before scanning */
#define GENESYS_FLAG_REPARK (1 << 7) /**< repark head (and check for lock) by
moving without scanning */
#define GENESYS_FLAG_DARK_CALIBRATION (1 << 8) /**< do dark calibration */
#define GENESYS_FLAG_MUST_WAIT (1 << 10) /**< tells wether the scanner must wait for the head when parking */
#define GENESYS_FLAG_HAS_UTA (1 << 11) /**< scanner has a transparency adapter */
#define GENESYS_FLAG_DARK_WHITE_CALIBRATION (1 << 12) /**< yet another calibration method. does white and dark shading in one run, depending on a black and a white strip*/
#define GENESYS_FLAG_CUSTOM_GAMMA (1 << 13) /**< allow custom gamma tables */
#define GENESYS_FLAG_NO_CALIBRATION (1 << 14) /**< allow scanners to use skip the calibration, needed for sheetfed scanners */
#define GENESYS_FLAG_SIS_SENSOR (1 << 16) /**< handling of multi-segments sensors in software */
#define GENESYS_FLAG_SHADING_NO_MOVE (1 << 17) /**< scanner doesn't move sensor during shading calibration */
#define GENESYS_FLAG_SHADING_REPARK (1 << 18) /**< repark head between shading scans */
#define GENESYS_FLAG_FULL_HWDPI_MODE (1 << 19) /**< scanner always use maximum hw dpi to setup the sensor */
// scanner has infrared transparency scanning capability
#define GENESYS_FLAG_HAS_UTA_INFRARED (1 << 20)
// scanner calibration is handled on the host side
#define GENESYS_FLAG_CALIBRATION_HOST_SIDE (1 << 21)
#define GENESYS_FLAG_16BIT_DATA_INVERTED (1 << 22)
#define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */
#define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */
#define GENESYS_HAS_FILE_SW (1 << 1) /**< scanner has FILE button */
@ -215,22 +182,6 @@ struct Genesys_USB_Device_Entry {
Genesys_Model model;
};
/**
* structure for motor database
*/
struct Motor_Profile
{
MotorId motor_id;
int exposure; // used only to select the wanted motor
StepType step_type; // default step type for given exposure
MotorSlope slope;
};
extern StaticInit<std::vector<Motor_Profile>> gl843_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl846_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl847_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl124_motor_profiles;
/*--------------------------------------------------------------------------*/
/* common functions needed by low level specific functions */
/*--------------------------------------------------------------------------*/
@ -335,16 +286,23 @@ void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& s
extern void sanei_genesys_stop_motor(Genesys_Device* dev);
extern void sanei_genesys_search_reference_point(Genesys_Device* dev, Genesys_Sensor& sensor,
const uint8_t* src_data, int start_pixel, int dpi,
int width, int height);
// moves the scan head by the specified steps at the motor base dpi
void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, Direction direction);
void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home);
void scanner_move_back_home_ta(Genesys_Device& dev);
/** Search for a full width black or white strip.
This function searches for a black or white stripe across the scanning area.
When searching backward, the searched area must completely be of the desired
color since this area will be used for calibration which scans forward.
@param dev scanner device
@param forward true if searching forward, false if searching backward
@param black true if searching for a black strip, false for a white strip
*/
void scanner_search_strip(Genesys_Device& dev, bool forward, bool black);
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev);
extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
@ -373,22 +331,11 @@ void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs);
void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& sensor,
unsigned dpihw);
inline uint16_t sanei_genesys_fixup_exposure_value(uint16_t value)
{
if ((value & 0xff00) == 0) {
value |= 0x100;
}
if ((value & 0x00ff) == 0) {
value |= 0x1;
}
return value;
}
inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure)
{
exposure.red = sanei_genesys_fixup_exposure_value(exposure.red);
exposure.green = sanei_genesys_fixup_exposure_value(exposure.green);
exposure.blue = sanei_genesys_fixup_exposure_value(exposure.blue);
exposure.red = std::max<std::uint16_t>(1, exposure.red);
exposure.green = std::max<std::uint16_t>(1, exposure.green);
exposure.blue = std::max<std::uint16_t>(1, exposure.blue);
return exposure;
}
@ -404,15 +351,20 @@ void scanner_stop_action_no_move(Genesys_Device& dev, Genesys_Register_Set& regs
bool scanner_is_motor_stopped(Genesys_Device& dev);
const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector<Motor_Profile>& motors,
MotorId motor_id, int exposure);
const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
unsigned step_multiplier,
const Motor_Profile& motor_profile);
const MotorProfile& motor_profile);
MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
const Motor_Profile& motor_profile);
const MotorProfile& motor_profile);
/** @brief find lowest motor resolution for the device.
* Parses the resolution list for motor and
@ -451,7 +403,8 @@ extern void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev,
void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor);
void build_image_pipeline(Genesys_Device* dev, const ScanSession& session);
void build_image_pipeline(Genesys_Device* dev, const Genesys_Sensor& sensor,
const ScanSession& session);
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type);
@ -509,8 +462,8 @@ void genesys_init_sensor_tables();
void genesys_init_frontend_tables();
void genesys_init_gpo_tables();
void genesys_init_motor_tables();
void genesys_init_motor_profile_tables();
void genesys_init_usb_device_tables();
void verify_usb_device_tables();
template<class T>
void debug_dump(unsigned level, const T& value)

Wyświetl plik

@ -164,15 +164,31 @@ std::ostream& operator<<(std::ostream& out, const MotorSlope& slope)
return out;
}
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile)
{
out << "MotorProfile{\n"
<< " max_exposure: " << profile.max_exposure << '\n'
<< " step_type: " << profile.step_type << '\n'
<< " motor_vref: " << profile.motor_vref << '\n'
<< " resolutions: " << format_indent_braced_list(4, profile.resolutions) << '\n'
<< " scan_methods: " << format_indent_braced_list(4, profile.scan_methods) << '\n'
<< " slope: " << format_indent_braced_list(4, profile.slope) << '\n'
<< '}';
return out;
}
std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor)
{
out << "Genesys_Motor{\n"
<< " id: " << static_cast<unsigned>(motor.id) << '\n'
<< " base_ydpi: " << motor.base_ydpi << '\n'
<< " optical_ydpi: " << motor.optical_ydpi << '\n'
<< " slopes: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorSlope",
motor.slopes))
<< " profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.profiles)) << '\n'
<< " fast_profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.fast_profiles)) << '\n'
<< '}';
return out;
}

Wyświetl plik

@ -44,9 +44,11 @@
#ifndef BACKEND_GENESYS_MOTOR_H
#define BACKEND_GENESYS_MOTOR_H
#include <algorithm>
#include <cstdint>
#include <vector>
#include "enums.h"
#include "sensor.h"
namespace genesys {
@ -137,6 +139,26 @@ MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_spee
std::ostream& operator<<(std::ostream& out, const MotorSlope& slope);
struct MotorProfile
{
MotorProfile() = default;
MotorProfile(const MotorSlope& a_slope, StepType a_step_type, unsigned a_max_exposure) :
slope{a_slope}, step_type{a_step_type}, max_exposure{a_max_exposure}
{}
MotorSlope slope;
StepType step_type = StepType::FULL;
int motor_vref = -1;
// the resolutions this profile is good for
ResolutionFilter resolutions = ResolutionFilter::ANY;
// the scan method this profile is good for. If the list is empty, good for any method.
ScanMethodFilter scan_methods = ScanMethodFilter::ANY;
unsigned max_exposure = 0; // 0 - any exposure
};
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile);
struct Genesys_Motor
{
@ -149,24 +171,40 @@ struct Genesys_Motor
// maximum resolution in y-direction. Unit: 1/inch
int optical_ydpi = 0;
// slopes to derive individual slopes from
std::vector<MotorSlope> slopes;
std::vector<MotorProfile> profiles;
// slopes to derive individual slopes from for fast moving
std::vector<MotorProfile> fast_profiles;
MotorSlope& get_slope(StepType step_type)
MotorSlope& get_slope_with_step_type(StepType step_type)
{
return slopes[static_cast<unsigned>(step_type)];
for (auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
const MotorSlope& get_slope(StepType step_type) const
const MotorSlope& get_slope_with_step_type(StepType step_type) const
{
return slopes[static_cast<unsigned>(step_type)];
for (const auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
StepType max_step_type() const
{
if (slopes.empty()) {
throw std::runtime_error("Slopes table is empty");
if (profiles.empty()) {
throw std::runtime_error("Profiles table is empty");
}
return static_cast<StepType>(slopes.size() - 1);
StepType step_type = StepType::FULL;
for (const auto& p : profiles) {
step_type = static_cast<StepType>(
std::max(static_cast<unsigned>(step_type),
static_cast<unsigned>(p.step_type)));
}
return step_type;
}
};

Wyświetl plik

@ -44,6 +44,7 @@
#ifndef BACKEND_GENESYS_REGISTER_H
#define BACKEND_GENESYS_REGISTER_H
#include "enums.h"
#include "utilities.h"
#include <algorithm>
@ -76,7 +77,7 @@ struct GenesysRegisterSetState
bool is_lamp_on = false;
bool is_xpa_on = false;
bool is_motor_on = false;
bool is_xpa_motor_on = false;
MotorMode motor_mode = MotorMode::PRIMARY;
};
template<class Value>

Wyświetl plik

@ -56,11 +56,6 @@ namespace genesys {
class ScannerInterface
{
public:
enum Flags {
FLAG_NONE = 0,
FLAG_SWAP_REGISTERS = 1 << 0,
FLAG_SMALL_ADDRESS = 1 << 1
};
virtual ~ScannerInterface();
@ -77,10 +72,10 @@ public:
// GL646, GL841, GL843 have different ways to write to RAM and to gamma tables
// FIXME: remove flags when updating tests
virtual void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags = FLAG_NONE) = 0;
std::size_t size) = 0;
virtual void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags = FLAG_NONE) = 0;
std::size_t size) = 0;
// GL845, GL846, GL847 and GL124 have a uniform way to write to RAM tables
virtual void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) = 0;

Wyświetl plik

@ -351,7 +351,7 @@ void ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data,
}
void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
if (dev_->model->asic_type != AsicType::GL646 &&
@ -362,19 +362,9 @@ void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, st
}
if (dev_->model->asic_type == AsicType::GL843) {
if (flags & FLAG_SWAP_REGISTERS) {
if (!(flags & FLAG_SMALL_ADDRESS)) {
write_register(0x29, ((addr >> 20) & 0xff));
}
write_register(0x2a, ((addr >> 12) & 0xff));
write_register(0x2b, ((addr >> 4) & 0xff));
} else {
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
if (!(flags & FLAG_SMALL_ADDRESS)) {
write_register(0x29, ((addr >> 20) & 0xff));
}
}
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
write_register(0x29, ((addr >> 20) & 0xff));
} else {
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
@ -383,24 +373,25 @@ void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, st
}
void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
if (dev_->model->asic_type != AsicType::GL646 &&
dev_->model->asic_type != AsicType::GL841 &&
if (dev_->model->asic_type != AsicType::GL841 &&
dev_->model->asic_type != AsicType::GL843)
{
throw SaneException("Unsupported transfer mode");
}
if (flags & FLAG_SWAP_REGISTERS) {
write_register(0x5b, ((addr >> 12) & 0xff));
write_register(0x5c, ((addr >> 4) & 0xff));
} else {
write_register(0x5c, ((addr >> 4) & 0xff));
write_register(0x5b, ((addr >> 12) & 0xff));
}
write_register(0x5b, ((addr >> 12) & 0xff));
write_register(0x5c, ((addr >> 4) & 0xff));
bulk_write_data(type, data, size);
if (dev_->model->asic_type == AsicType::GL843) {
// it looks like we need to reset the address so that subsequent buffer operations work.
// Most likely the MTRTBL register is to blame.
write_register(0x5b, 0);
write_register(0x5c, 0);
}
}
void ScannerInterfaceUsb::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data)

Wyświetl plik

@ -67,9 +67,9 @@ public:
void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override;
void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override;

Wyświetl plik

@ -122,6 +122,16 @@ std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions)
return out;
}
std::ostream& operator<<(std::ostream& out, const ScanMethodFilter& methods)
{
if (methods.matches_any()) {
out << "ANY";
return out;
}
out << format_vector_unsigned(4, methods.methods());
return out;
}
std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
{
out << "Genesys_Sensor{\n"
@ -138,7 +148,6 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
<< " black_pixels: " << sensor.black_pixels << '\n'
<< " dummy_pixel: " << sensor.dummy_pixel << '\n'
<< " ccd_start_xoffset: " << sensor.ccd_start_xoffset << '\n'
<< " sensor_pixels: " << sensor.sensor_pixels << '\n'
<< " fau_gain_white_ref: " << sensor.fau_gain_white_ref << '\n'
<< " gain_white_ref: " << sensor.gain_white_ref << '\n'
<< " exposure: " << format_indent_braced_list(4, sensor.exposure) << '\n'
@ -147,6 +156,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, sensor.segment_order)) << '\n'
<< " stagger_config: " << format_indent_braced_list(4, sensor.stagger_config) << '\n'
<< " use_host_side_calib: " << sensor.use_host_side_calib << '\n'
<< " custom_base_regs: " << format_indent_braced_list(4, sensor.custom_base_regs) << '\n'
<< " custom_regs: " << format_indent_braced_list(4, sensor.custom_regs) << '\n'
<< " custom_fe_regs: " << format_indent_braced_list(4, sensor.custom_fe_regs) << '\n'

Wyświetl plik

@ -290,6 +290,46 @@ void serialize(Stream& str, ResolutionFilter& x)
}
class ScanMethodFilter
{
public:
struct Any {};
static constexpr Any ANY{};
ScanMethodFilter() : matches_any_{false} {}
ScanMethodFilter(Any) : matches_any_{true} {}
ScanMethodFilter(std::initializer_list<ScanMethod> methods) :
matches_any_{false},
methods_{methods}
{}
bool matches(ScanMethod method) const
{
if (matches_any_)
return true;
auto it = std::find(methods_.begin(), methods_.end(), method);
return it != methods_.end();
}
bool operator==(const ScanMethodFilter& other) const
{
return matches_any_ == other.matches_any_ && methods_ == other.methods_;
}
bool matches_any() const { return matches_any_; }
const std::vector<ScanMethod>& methods() const { return methods_; }
private:
bool matches_any_ = false;
std::vector<ScanMethod> methods_;
template<class Stream>
friend void serialize(Stream& str, ResolutionFilter& x);
};
std::ostream& operator<<(std::ostream& out, const ScanMethodFilter& methods);
struct Genesys_Sensor {
Genesys_Sensor() = default;
@ -334,8 +374,6 @@ struct Genesys_Sensor {
int dummy_pixel = 0;
// last pixel of CCD margin at optical resolution
int ccd_start_xoffset = 0;
// total pixels used by the sensor
int sensor_pixels = 0;
// TA CCD target code (reference gain)
int fau_gain_white_ref = 0;
// CCD target code (reference gain)
@ -359,6 +397,9 @@ struct Genesys_Sensor {
// high-enough resolution, every other pixel column is shifted
StaggerConfig stagger_config;
// True if calibration should be performed on host-side
bool use_host_side_calib = false;
GenesysRegisterSettingSet custom_base_regs; // gl646-specific
GenesysRegisterSettingSet custom_regs;
GenesysRegisterSettingSet custom_fe_regs;
@ -366,12 +407,10 @@ struct Genesys_Sensor {
// red, green and blue gamma coefficient for default gamma tables
AssignableArray<float, 3> gamma;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_logical_hwdpi_fun;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_register_hwdpi_fun;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_ccd_size_divisor_fun;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_hwdpi_divisor_fun;
unsigned get_logical_hwdpi(unsigned xres) const { return get_logical_hwdpi_fun(*this, xres); }
unsigned get_register_hwdpi(unsigned xres) const { return get_register_hwdpi_fun(*this, xres); }
unsigned get_ccd_size_divisor_for_dpi(unsigned xres) const
{
@ -412,7 +451,6 @@ struct Genesys_Sensor {
black_pixels == other.black_pixels &&
dummy_pixel == other.dummy_pixel &&
ccd_start_xoffset == other.ccd_start_xoffset &&
sensor_pixels == other.sensor_pixels &&
fau_gain_white_ref == other.fau_gain_white_ref &&
gain_white_ref == other.gain_white_ref &&
exposure == other.exposure &&
@ -420,6 +458,7 @@ struct Genesys_Sensor {
segment_size == other.segment_size &&
segment_order == other.segment_order &&
stagger_config == other.stagger_config &&
use_host_side_calib == other.use_host_side_calib &&
custom_base_regs == other.custom_base_regs &&
custom_regs == other.custom_regs &&
custom_fe_regs == other.custom_fe_regs &&
@ -438,7 +477,6 @@ void serialize(Stream& str, Genesys_Sensor& x)
serialize(str, x.black_pixels);
serialize(str, x.dummy_pixel);
serialize(str, x.ccd_start_xoffset);
serialize(str, x.sensor_pixels);
serialize(str, x.fau_gain_white_ref);
serialize(str, x.gain_white_ref);
serialize_newline(str);
@ -453,6 +491,8 @@ void serialize(Stream& str, Genesys_Sensor& x)
serialize_newline(str);
serialize(str, x.stagger_config);
serialize_newline(str);
serialize(str, x.use_host_side_calib);
serialize_newline(str);
serialize(str, x.custom_base_regs);
serialize_newline(str);
serialize(str, x.custom_regs);

Wyświetl plik

@ -72,14 +72,20 @@ std::ostream& operator<<(std::ostream& out, const SetupParams& params)
{
StreamStateSaver state_saver{out};
bool reverse = has_flag(params.flags, ScanFlag::REVERSE);
out << "SetupParams{\n"
<< " xres: " << params.xres << " yres: " << params.yres << '\n'
<< " lines: " << params.lines << '\n'
<< " pixels per line (actual): " << params.pixels << '\n'
<< " pixels per line (requested): " << params.requested_pixels << '\n'
<< " xres: " << params.xres
<< " startx: " << params.startx
<< " pixels per line (actual): " << params.pixels
<< " pixels per line (requested): " << params.requested_pixels << '\n'
<< " yres: " << params.yres
<< " lines: " << params.lines
<< " starty: " << params.starty << (reverse ? " (reverse)" : "") << '\n'
<< " depth: " << params.depth << '\n'
<< " channels: " << params.channels << '\n'
<< " startx: " << params.startx << " starty: " << params.starty << '\n'
<< " scan_mode: " << params.scan_mode << '\n'
<< " color_filter: " << params.color_filter << '\n'
<< " flags: " << params.flags << '\n'
@ -87,6 +93,45 @@ std::ostream& operator<<(std::ostream& out, const SetupParams& params)
return out;
}
bool ScanSession::operator==(const ScanSession& other) const
{
return params == other.params &&
computed == other.computed &&
hwdpi_divisor == other.hwdpi_divisor &&
ccd_size_divisor == other.ccd_size_divisor &&
optical_resolution == other.optical_resolution &&
optical_pixels == other.optical_pixels &&
optical_pixels_raw == other.optical_pixels_raw &&
optical_line_count == other.optical_line_count &&
output_resolution == other.output_resolution &&
output_pixels == other.output_pixels &&
output_channel_bytes == other.output_channel_bytes &&
output_line_bytes == other.output_line_bytes &&
output_line_bytes_raw == other.output_line_bytes_raw &&
output_line_bytes_requested == other.output_line_bytes_requested &&
output_line_count == other.output_line_count &&
output_total_bytes_raw == other.output_total_bytes_raw &&
output_total_bytes == other.output_total_bytes &&
num_staggered_lines == other.num_staggered_lines &&
max_color_shift_lines == other.max_color_shift_lines &&
color_shift_lines_r == other.color_shift_lines_r &&
color_shift_lines_g == other.color_shift_lines_g &&
color_shift_lines_b == other.color_shift_lines_b &&
segment_count == other.segment_count &&
pixel_startx == other.pixel_startx &&
pixel_endx == other.pixel_endx &&
pixel_count_multiplier == other.pixel_count_multiplier &&
conseq_pixel_dist == other.conseq_pixel_dist &&
output_segment_pixel_group_count == other.output_segment_pixel_group_count &&
output_segment_start_offset == other.output_segment_start_offset &&
buffer_size_read == other.buffer_size_read &&
enable_ledadd == other.enable_ledadd &&
use_host_side_calib == other.use_host_side_calib &&
pipeline_needs_reorder == other.pipeline_needs_reorder &&
pipeline_needs_ccd == other.pipeline_needs_ccd &&
pipeline_needs_shrink == other.pipeline_needs_shrink;
}
std::ostream& operator<<(std::ostream& out, const ScanSession& session)
{
out << "ScanSession{\n"
@ -96,6 +141,7 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " optical_resolution: " << session.optical_resolution << '\n'
<< " optical_pixels: " << session.optical_pixels << '\n'
<< " optical_pixels_raw: " << session.optical_pixels_raw << '\n'
<< " optical_line_count: " << session.optical_line_count << '\n'
<< " output_resolution: " << session.output_resolution << '\n'
<< " output_pixels: " << session.output_pixels << '\n'
<< " output_line_bytes: " << session.output_line_bytes << '\n'
@ -114,9 +160,8 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " output_segment_pixel_group_count: "
<< session.output_segment_pixel_group_count << '\n'
<< " buffer_size_read: " << session.buffer_size_read << '\n'
<< " buffer_size_read: " << session.buffer_size_lines << '\n'
<< " buffer_size_shrink: " << session.buffer_size_shrink << '\n'
<< " buffer_size_out: " << session.buffer_size_out << '\n'
<< " enable_ledadd: " << session.enable_ledadd << '\n'
<< " use_host_side_calib: " << session.use_host_side_calib << '\n'
<< " filters: "
<< (session.pipeline_needs_reorder ? " reorder": "")
<< (session.pipeline_needs_ccd ? " ccd": "")

Wyświetl plik

@ -60,9 +60,9 @@ struct Genesys_Settings
unsigned yres = 0;
//x start on scan table in mm
double tl_x = 0;
float tl_x = 0;
// y start on scan table in mm
double tl_y = 0;
float tl_y = 0;
// number of lines at scan resolution
unsigned int lines = 0;
@ -116,7 +116,7 @@ struct SetupParams {
unsigned xres = NOT_SET;
// resolution in y direction
unsigned yres = NOT_SET;
// start pixel in X direction, from dummy_pixel + 1
// start pixel in X direction, from dummy_pixel + 1. Counted in terms of xres.
unsigned startx = NOT_SET;
// start pixel in Y direction, counted according to base_ydpi
unsigned starty = NOT_SET;
@ -228,6 +228,9 @@ struct ScanSession {
// only on gl846, g847
unsigned optical_pixels_raw = 0;
// the number of optical scan lines. Equal to output_line_count on CCD scanners.
unsigned optical_line_count = 0;
// the resolution of the output data.
// gl843-only
unsigned output_resolution = 0;
@ -297,15 +300,15 @@ struct ScanSession {
// Currently it's always zero.
unsigned output_segment_start_offset = 0;
// the sizes of the corresponding buffers
// the size of the read buffer.
size_t buffer_size_read = 0;
size_t buffer_size_lines = 0;
size_t buffer_size_shrink = 0;
size_t buffer_size_out = 0;
// whether to enable ledadd functionality
bool enable_ledadd = false;
// whether calibration should be performed host-side
bool use_host_side_calib = false;
// what pipeline modifications are needed
bool pipeline_needs_reorder = false;
bool pipeline_needs_ccd = false;
@ -317,10 +320,53 @@ struct ScanSession {
throw std::runtime_error("ScanSession is not computed");
}
}
bool operator==(const ScanSession& other) const;
};
std::ostream& operator<<(std::ostream& out, const ScanSession& session);
template<class Stream>
void serialize(Stream& str, ScanSession& x)
{
serialize(str, x.params);
serialize_newline(str);
serialize(str, x.computed);
serialize(str, x.hwdpi_divisor);
serialize(str, x.ccd_size_divisor);
serialize(str, x.optical_resolution);
serialize(str, x.optical_pixels);
serialize(str, x.optical_pixels_raw);
serialize(str, x.optical_line_count);
serialize(str, x.output_resolution);
serialize(str, x.output_pixels);
serialize(str, x.output_channel_bytes);
serialize(str, x.output_line_bytes);
serialize(str, x.output_line_bytes_raw);
serialize(str, x.output_line_bytes_requested);
serialize(str, x.output_line_count);
serialize(str, x.output_total_bytes_raw);
serialize(str, x.output_total_bytes);
serialize(str, x.num_staggered_lines);
serialize(str, x.max_color_shift_lines);
serialize(str, x.color_shift_lines_r);
serialize(str, x.color_shift_lines_g);
serialize(str, x.color_shift_lines_b);
serialize(str, x.segment_count);
serialize(str, x.pixel_startx);
serialize(str, x.pixel_endx);
serialize(str, x.pixel_count_multiplier);
serialize(str, x.conseq_pixel_dist);
serialize(str, x.output_segment_pixel_group_count);
serialize(str, x.output_segment_start_offset);
serialize(str, x.buffer_size_read);
serialize(str, x.enable_ledadd);
serialize(str, x.use_host_side_calib);
serialize(str, x.pipeline_needs_reorder);
serialize(str, x.pipeline_needs_ccd);
serialize(str, x.pipeline_needs_shrink);
}
std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params);
} // namespace genesys

Wyświetl plik

@ -53,12 +53,14 @@ void genesys_init_motor_tables()
{
s_motors.init();
MotorProfile profile;
Genesys_Motor motor;
motor.id = MotorId::UMAX;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -66,8 +68,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::MD_5345; // MD5345/6228/6471
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128));
motor.profiles.push_back({MotorSlope::create_from_steps(2000, 1375, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(2000, 1375, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -75,17 +77,17 @@ void genesys_init_motor_tables()
motor.id = MotorId::ST24;
motor.base_ydpi = 2400;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128));
motor.profiles.push_back({MotorSlope::create_from_steps(2289, 2100, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(2289, 2100, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::HP3670;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -93,8 +95,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::HP2400;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -102,8 +104,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::HP2300;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128));
motor.profiles.push_back({MotorSlope::create_from_steps(3200, 1200, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3200, 1200, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -111,8 +113,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_35;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1400, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1400, 60), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -120,8 +122,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::XP200;
motor.base_ydpi = 600;
motor.optical_ydpi = 600;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -130,8 +132,8 @@ void genesys_init_motor_tables()
motor.base_ydpi = 300;
motor.optical_ydpi = 600;
// works best with GPIO10, GPIO14 off
motor.slopes.push_back(MotorSlope::create_from_steps(3700, 3700, 2));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
motor.profiles.push_back({MotorSlope::create_from_steps(3700, 3700, 2), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -139,8 +141,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::DP665;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 2500, 10));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
motor.profiles.push_back({MotorSlope::create_from_steps(3000, 2500, 10), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -148,8 +150,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::ROADWARRIOR;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 2600, 10));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
motor.profiles.push_back({MotorSlope::create_from_steps(3000, 2600, 10), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -157,8 +159,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::DSMOBILE_600;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8));
motor.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8));
motor.profiles.push_back({MotorSlope::create_from_steps(6666, 3700, 8), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(6666, 3700, 8), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -166,9 +168,12 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_100;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 255),
StepType::HALF, 1432});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 279),
StepType::QUARTER, 2712});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 5280});
s_motors->push_back(std::move(motor));
@ -176,9 +181,14 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_200;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 255),
StepType::HALF, 1432});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 279),
StepType::QUARTER, 2712});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 5280});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 10416});
s_motors->push_back(std::move(motor));
@ -186,9 +196,16 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_700;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
StepType::HALF, 1424});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
StepType::HALF, 1504});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 2022, 127),
StepType::HALF, 2696});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
StepType::HALF, 2848});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 15864, 2),
StepType::EIGHTH, 10576});
s_motors->push_back(std::move(motor));
@ -196,9 +213,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::KVSS080;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.profiles.push_back({MotorSlope::create_from_steps(44444, 500, 489),
StepType::HALF, 8000});
s_motors->push_back(std::move(motor));
@ -206,9 +222,14 @@ void genesys_init_motor_tables()
motor.id = MotorId::G4050;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.profiles.push_back({MotorSlope::create_from_steps(7842, 320, 602),
StepType::HALF, 8016});
motor.profiles.push_back({MotorSlope::create_from_steps(9422, 254, 1004),
StepType::HALF, 15624});
motor.profiles.push_back({MotorSlope::create_from_steps(28032, 2238, 604),
StepType::HALF, 56064});
motor.profiles.push_back({MotorSlope::create_from_steps(42752, 1706, 610),
StepType::QUARTER, 42752});
s_motors->push_back(std::move(motor));
@ -216,9 +237,27 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_4400F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 727 * 2, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 1;
profile.resolutions = { 300, 600 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 727 * 2, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = { 1200, 2400, 4800, 9600 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 279 * 2, 1000);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -226,9 +265,31 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_8400F;
motor.base_ydpi = 1600;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(20202 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = ResolutionFilter::ANY;
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = ResolutionFilter::ANY;
profile.scan_methods = { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = ResolutionFilter::ANY;
profile.scan_methods = ScanMethodFilter::ANY;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -236,9 +297,64 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_8600F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
profile.resolutions = { 300, 600 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 1200, 2400 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 4800 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 300, 600 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 1;
profile.resolutions = { 1200, 2400 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = { 4800 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(59240, 582, 1020);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -246,7 +362,14 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_110;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 255),
StepType::FULL, 2768});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 469),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2632, 3),
StepType::HALF, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 10432, 3),
StepType::QUARTER, 20864});
s_motors->push_back(std::move(motor));
@ -254,7 +377,14 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_120;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 864, 127),
StepType::FULL, 4608});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2010, 63),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62464, 2632, 3),
StepType::QUARTER, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62592, 10432, 5),
StepType::QUARTER, 20864});
s_motors->push_back(std::move(motor));
@ -262,7 +392,14 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_210;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 255),
StepType::FULL, 2768});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 469),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2632, 3),
StepType::HALF, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 10432, 4),
StepType::QUARTER, 20864});
s_motors->push_back(std::move(motor));
@ -270,8 +407,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::PLUSTEK_OPTICPRO_3600;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 3250, 60), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -279,6 +416,19 @@ void genesys_init_motor_tables()
motor.id = MotorId::PLUSTEK_OPTICFILM_7200I;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(34722 * 2, 454 * 2, 40);
profile.step_type = StepType::HALF;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(34722 * 2, 454 * 2, 40);
profile.step_type = StepType::HALF;
profile.motor_vref = 0;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -286,6 +436,19 @@ void genesys_init_motor_tables()
motor.id = MotorId::PLUSTEK_OPTICFILM_7300;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -293,6 +456,19 @@ void genesys_init_motor_tables()
motor.id = MotorId::PLUSTEK_OPTICFILM_7500I;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -300,8 +476,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::IMG101;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
@ -309,8 +485,8 @@ void genesys_init_motor_tables()
motor.id = MotorId::PLUSTEK_OPTICBOOK_3800;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
@ -318,7 +494,7 @@ void genesys_init_motor_tables()
motor.id = MotorId::CANON_LIDE_80;
motor.base_ydpi = 2400;
motor.optical_ydpi = 4800; // 9600
motor.slopes.push_back(MotorSlope::create_from_steps(9560, 1912, 31));
motor.profiles.push_back({MotorSlope::create_from_steps(9560, 1912, 31), StepType::FULL, 0});
s_motors->push_back(std::move(motor));
}

Wyświetl plik

@ -1,380 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
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.
*/
#define DEBUG_DECLARE_ONLY
#include "low.h"
namespace genesys {
StaticInit<std::vector<Motor_Profile>> gl843_motor_profiles;
void genesys_init_motor_profile_tables_gl843()
{
gl843_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::KVSS080;
profile.exposure = 8000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(44444, 500, 489);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 8016;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(7842, 320, 602);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 15624;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(9422, 254, 1004);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 42752;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(42752, 1706, 610);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 56064;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(28032, 2238, 604);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_4400F;
profile.exposure = 11640;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(49152, 484, 1014);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_8400F;
profile.exposure = 50000;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(8743, 300, 794);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_8600F;
profile.exposure = 0x59d8;
profile.step_type = StepType::QUARTER;
// FIXME: if the exposure is lower then we'll select another motor
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I;
profile.exposure = 0;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(39682, 1191, 15);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7300;
profile.exposure = 0x2f44;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(31250, 1512, 6);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I;
profile.exposure = 0;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(31250, 1375, 7);
gl843_motor_profiles->push_back(profile);
}
StaticInit<std::vector<Motor_Profile>> gl846_motor_profiles;
void genesys_init_motor_profile_tables_gl846()
{
gl846_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::IMG101;
profile.exposure = 11000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017);
gl846_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800;
profile.exposure = 11000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017);
gl846_motor_profiles->push_back(profile);
}
/**
* database of motor profiles
*/
StaticInit<std::vector<Motor_Profile>> gl847_motor_profiles;
void genesys_init_motor_profile_tables_gl847()
{
gl847_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 1432;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 2712;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(46876, 534, 279);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 5280;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 1432;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 2712;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(46876, 534, 279);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 5280;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 10416;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 1504;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 2696;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 2022, 127);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 10576;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(46876, 15864, 2);
gl847_motor_profiles->push_back(profile);
}
StaticInit<std::vector<Motor_Profile>> gl124_motor_profiles;
void genesys_init_motor_profile_tables_gl124()
{
gl124_motor_profiles.init();
// NEXT LPERIOD=PREVIOUS*2-192
Motor_Profile profile;
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 2768;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 335, 255);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 335, 469);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 10528;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62496, 10432, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 4608;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 864, 127);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2010, 63);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 10528;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62464, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62592, 10432, 5);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 2768;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 335, 255);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 335, 469);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 10528;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62496, 10432, 4);
gl124_motor_profiles->push_back(profile);
}
void genesys_init_motor_profile_tables()
{
genesys_init_motor_profile_tables_gl843();
genesys_init_motor_profile_tables_gl846();
genesys_init_motor_profile_tables_gl847();
genesys_init_motor_profile_tables_gl124();
}
} // namespace genesys

Wyświetl plik

@ -137,23 +137,21 @@ void TestScannerInterface::bulk_write_data(std::uint8_t addr, std::uint8_t* data
}
void TestScannerInterface::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
(void) type;
(void) addr;
(void) data;
(void) size;
(void) flags;
}
void TestScannerInterface::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
(void) type;
(void) addr;
(void) data;
(void) size;
(void) flags;
}
void TestScannerInterface::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data)

Wyświetl plik

@ -74,9 +74,9 @@ public:
void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override;
void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override;
std::uint16_t read_fe_register(std::uint8_t address) override;

Wyświetl plik

@ -50,8 +50,31 @@
#include <sstream>
#include <vector>
namespace genesys {
// just like SANE_FIX and SANE_UNFIX except that the conversion is done by a function and argument
// precision is handled correctly
inline SANE_Word double_to_fixed(double v)
{
return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
}
inline SANE_Word float_to_fixed(float v)
{
return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
}
inline float fixed_to_float(SANE_Word v)
{
return static_cast<float>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
}
inline double fixed_to_double(SANE_Word v)
{
return static_cast<double>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
}
template<class T>
void compute_array_percentile_approx(T* result, const T* data,
std::size_t line_count, std::size_t elements_per_line,

Wyświetl plik

@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 20020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
@ -138,6 +139,16 @@ typedef struct
}
TScanParams;
/*
* Panel settings. We can read and set these.
*
*/
typedef struct
{
SANE_Word copycount; // 0..99 LCD display value
SANE_Word bwcolour; // 1=Colour or 2=Black/White from scan type LEDs
}
TPanelInfo;
#endif /* NO _HP5400_H_ */

Wyświetl plik

@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
Copyright (c) 2003 Henning Meier-Geinitz, <henning@meier-geinitz.de>
@ -149,11 +150,137 @@ SetLamp (THWParams * pHWParams, int fLampOn)
if (fLampOn)
{
if (WriteByte (pHWParams->iXferHandle, 0x0000, 0x01) == 0)
return 0;
return 0;
}
return -1;
}
HP5400_SANE_STATIC
int
GetSensors(THWParams * pHWParams, uint16_t *sensorMap)
{
/*
* Read until we get 0.
* Max 10 iterations for safety.
*
*/
uint16_t thisSensorMap = 0;
size_t iterCount = 10;
do
{
if (hp5400_command_read
(pHWParams->iXferHandle, CMD_GETSENSORS, sizeof (uint16_t), &thisSensorMap) < 0)
{
HP5400_DBG (DBG_MSG, "failed to read sensors\n");
return -1;
}
*sensorMap |= thisSensorMap;
} while (iterCount-- && (thisSensorMap > 0));
return 0;
}
HP5400_SANE_STATIC
int
GetPanelInfo (THWParams * pHWParams, TPanelInfo *panelInfo)
{
struct PanelInfo info;
if (hp5400_command_read (pHWParams->iXferHandle, CMD_READPANEL,
sizeof(info), &info) < 0)
{
HP5400_DBG (DBG_MSG, "failed to read panel info\n");
return -1;
}
panelInfo->copycount = (SANE_Word)info.copycount;
panelInfo->bwcolour = (SANE_Word)info.bwcolour;
return 0;
}
HP5400_SANE_STATIC
int
SetCopyCount(THWParams * pHWParams, SANE_Word copyCount)
{
/*
* I don't know what most of these things are but it is
* necessary to send something sane otherwise we get an error from the scanner.
* I got these settings from a USB trace.
* Hopefully, we will learn what it is all about at some point
* and hopefully it doesn't screw with other settings.
*
*/
uint8_t packetImage[] = {0x02, 0x06, 0x32, 0x01,
0xf2, 0x40, 0x16, 0x01,
0x7b, 0x41, 0x16, 0x01,
0xdc, 0x06, 0x32, 0x01,
0xd7, 0x5b, 0x16, 0x01,
0xac, 0x06, 0x32, 0x01,
0xf8, 0xd7, 0x18, 0x01,
0xd8, 0x06, 0x32, 0x01,
0x2c, 0xf3, 0x12, 0x00,
0x70, 0x8d, 0x18, 0x01,
0x7b, 0x00, 0x00, 0x00};
struct PanelInfo workingInfo;
(void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
workingInfo.copycount = (uint8_t)copyCount;
if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
sizeof(workingInfo), &workingInfo) < 0)
{
HP5400_DBG (DBG_MSG, "failed to write panel info\n");
return -1;
}
return 0;
}
HP5400_SANE_STATIC
int
SetColourBW(THWParams * pHWParams, SANE_Word colourBW)
{
/*
* I don't know what most of these things are but it is
* necessary to send something sane otherwise we get an error from the scanner.
* I got these settings from a USB trace.
* Hopefully, we will learn what it is all about at some point
* and hopefully it doesn't screw with other settings.
*
*/
uint8_t packetImage[] = {0x03, 0x06, 0x32, 0x01,
0xf2, 0x40, 0x16, 0x01,
0x7b, 0x41, 0x16, 0x01,
0xdc, 0x06, 0x32, 0x01,
0xd7, 0x5b, 0x16, 0x01,
0xac, 0x06, 0x32, 0x01,
0xf8, 0xd7, 0x18, 0x01,
0xd8, 0x06, 0x32, 0x01,
0x68, 0xf5, 0x12, 0x00,
0x70, 0x8d, 0x18, 0x01,
0x7b, 0x00, 0x00, 0x00};
struct PanelInfo workingInfo;
(void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
workingInfo.bwcolour = (uint8_t)colourBW;
if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
sizeof(workingInfo), &workingInfo) < 0)
{
HP5400_DBG (DBG_MSG, "failed to write panel info\n");
return -1;
}
return 0;
}
HP5400_SANE_STATIC
int
WarmupLamp (int iHandle)

Wyświetl plik

@ -2,6 +2,7 @@
#define _HP5400_INTERNAL_H_
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Ralph Little <skelband@gmail.com>
(C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
(c) 2003 Martijn van Oosterhout, kleptog@svana.org
(c) 2002 Bertrik Sikken, bertrik@zonnet.nl
@ -73,6 +74,9 @@
#define CMD_SCANREQUEST 0x2505 /* This is for previews */
#define CMD_SCANREQUEST2 0x2500 /* This is for real scans */
#define CMD_SCANRESPONSE 0x3400
#define CMD_GETSENSORS 0x2000
#define CMD_READPANEL 0x2100 // Reads info from the scanner. BW/Col + Copy Count. Others, not sure.
#define CMD_WRITEPANEL 0x2200 // Ditto for setting.
/* Testing stuff to make it work */
#define CMD_SETDPI 0x1500 /* ??? */
@ -130,11 +134,40 @@ PACKED;
struct ScanResponse
{
uint16_t x1; /* Usually 0x0000 or 0x4000 */
uint32_t transfersize; /* Number of bytes to be transferred */
uint32_t xsize; /* Shape of returned bitmap */
uint16_t ysize; /* Why does the X get more bytes? */
uint16_t pad[2]; /* Zero padding to 16 bytes??? */
uint16_t x1; /* Usually 0x0000 or 0x4000 */
uint32_t transfersize; /* Number of bytes to be transferred */
uint32_t xsize; /* Shape of returned bitmap */
uint16_t ysize; /* Why does the X get more bytes? */
uint16_t pad[2]; /* Zero padding to 16 bytes??? */
}
PACKED;
/*
* Note: this is the structure of the response we get from CMD_READPANEL.
* We only know about two items for the moment. The rest will be ignored
* until we understand it better.
*
* 44 bytes in total.
*
* Since we don't know what the other things mean, I will assume that they
* mean the same things for Get and SET. For SET, we will have to GET, change
* what we wish change and SET it back otherwise goodness knows what evil
* we will unleash.
*
* Note that for setting, different values in the buffer seem to apply betwen the copy count
* and the colour/BW switch setting. I don't know what that means at the moment.
*
* I'm calling it PanelInfo because I can't think of anything better.
* That may change as the other values are revealed.
*
*/
struct PanelInfo
{
uint32_t unknown1[10];
uint8_t unknown2;
uint8_t copycount; // 0..99 from the LCD display.
uint8_t bwcolour; // 1 or 2 from the Colour/BW leds.
uint8_t unknown3;
}
PACKED;
@ -156,6 +189,22 @@ HP5400_SANE_STATIC
int
SetLamp (THWParams * pHWParams, int fLampOn);
HP5400_SANE_STATIC
int
GetSensors (THWParams * pHWParams, uint16_t *sensorMap);
HP5400_SANE_STATIC
int
GetPanelInfo (THWParams * pHWParams, TPanelInfo *panelInfo);
HP5400_SANE_STATIC
int
SetCopyCount(THWParams * pHWParams, SANE_Word copyCount);
HP5400_SANE_STATIC
int
SetColourBW(THWParams * pHWParams, SANE_Word colourBW);
HP5400_SANE_STATIC
int
WarmupLamp (int iHandle);

Wyświetl plik

@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
@ -71,28 +72,6 @@
#include "hp5400.h"
/* includes for data transfer methods */
#include "hp5400.h"
#ifdef STANDALONE
#include "hp5400_scanner.h"
#endif
#if defined(LINUX_USB_SUPPORT)
#include "hp5400_linux.c"
#endif
#if defined(USCANNER_SUPPORT)
#include "hp5400_uscanner.c"
#endif
#if defined(LIBUSB_SUPPORT)
#include "hp5400_libusb.c"
#endif
#if defined(LIBIEEE1284_SUPPORT)
#include "hp5400_ieee1284.c"
#endif
/* other definitions */
#ifndef min
#define min(A,B) (((A)<(B)) ? (A) : (B))
@ -115,30 +94,91 @@ typedef enum
{
optCount = 0,
optGroupGeometry,
optTLX, optTLY, optBRX, optBRY,
optDPI,
optGroupImage,
optGroupGeometry,
optTLX, optTLY, optBRX, optBRY,
optGroupEnhancement,
optGammaTableRed, /* Gamma Tables */
optGammaTableGreen,
optGammaTableBlue,
optGroupSensors,
optSensorScanTo,
optSensorWeb,
optSensorReprint,
optSensorEmail,
optSensorCopy,
optSensorMoreOptions,
optSensorCancel,
optSensorPowerSave,
optSensorCopiesUp,
optSensorCopiesDown,
optSensorColourBW,
optSensorColourBWState,
optSensorCopyCount,
// Unsupported as yet.
//optGroupMisc,
//optLamp,
//optCalibrate,
optLast, /* Disable the offset code */
optGroupMisc,
optOffsetX, optOffsetY
/* put temporarily disabled options here after optLast */
/*
optLamp,
*/
}
EOptionIndex;
/*
* Array mapping (optSensor* - optGroupSensors - 1) to the bit mask of the
* corresponding sensor bit that we get from the scanner.
* All sensor bits are reported as a complete 16-bit word with individual bits set
* to indicate that the sensor has been activated.
* They seem to be latched so that they are picked up on next query and a number
* of bits can be set in any one query.
*
*/
#define SENSOR_BIT_SCAN 0x0400
#define SENSOR_BIT_WEB 0x0200
#define SENSOR_BIT_REPRINT 0x0002
#define SENSOR_BIT_EMAIL 0x0080
#define SENSOR_BIT_COPY 0x0040
#define SENSOR_BIT_MOREOPTIONS 0x0004
#define SENSOR_BIT_CANCEL 0x0100
#define SENSOR_BIT_POWERSAVE 0x2000
#define SENSOR_BIT_COPIESUP 0x0008
#define SENSOR_BIT_COPIESDOWN 0x0020
#define SENSOR_BIT_COLOURBW 0x0010
uint16_t sensorMaskMap[] =
{
SENSOR_BIT_SCAN,
SENSOR_BIT_WEB,
SENSOR_BIT_REPRINT,
SENSOR_BIT_EMAIL,
SENSOR_BIT_COPY,
SENSOR_BIT_MOREOPTIONS,
SENSOR_BIT_CANCEL,
// Special buttons.
// These affect local machine settings, but we can still detect them being pressed.
SENSOR_BIT_POWERSAVE,
SENSOR_BIT_COPIESUP,
SENSOR_BIT_COPIESDOWN,
SENSOR_BIT_COLOURBW,
// Extra entries to make the array up to the 16 possible bits.
0x0000, // Unused
0x0000, // Unused
0x0000, // Unused
0x0000, // Unused
0x0000 // Unused
};
typedef union
{
SANE_Word w;
@ -165,6 +205,8 @@ typedef struct
int fScanning; /* TRUE if actively scanning */
int fCanceled;
uint16_t sensorMap; /* Contains the current unreported sensor bits. */
}
TScanner;
@ -191,18 +233,19 @@ static const SANE_Device **_pSaneDevList = 0;
/* option constraints */
static const SANE_Range rangeGammaTable = {0, 65535, 1};
static const SANE_Range rangeCopyCountTable = {0, 99, 1};
static SANE_String_Const modeSwitchList[] = {
SANE_VALUE_SCAN_MODE_COLOR,
SANE_VALUE_SCAN_MODE_GRAY,
NULL
};
#ifdef SUPPORT_2400_DPI
static const SANE_Int setResolutions[] = {6, 75, 150, 300, 600, 1200, 2400};
#else
static const SANE_Int setResolutions[] = {5, 75, 150, 300, 600, 1200};
#endif
static const SANE_Range rangeXmm = {0, 220, 1};
static const SANE_Range rangeYmm = {0, 300, 1};
static const SANE_Range rangeXoffset = {0, 20, 1};
static const SANE_Range rangeYoffset = {0, 70, 1};
static const SANE_Int offsetX = 5;
static const SANE_Int offsetY = 52;
static const SANE_Range rangeXmm = {0, 216, 1};
static const SANE_Range rangeYmm = {0, 297, 1};
static void _InitOptions(TScanner *s)
{
@ -248,8 +291,22 @@ static void _InitOptions(TScanner *s)
pVal->w = (SANE_Word)optLast;
break;
case optDPI:
pDesc->name = SANE_NAME_SCAN_RESOLUTION;
pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
pDesc->unit = SANE_UNIT_DPI;
pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
pDesc->constraint.word_list = setResolutions;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = setResolutions[1];
break;
//---------------------------------
case optGroupGeometry:
pDesc->title = "Geometry";
pDesc->name = SANE_NAME_GEOMETRY;
pDesc->title = SANE_TITLE_GEOMETRY;
pDesc->desc = SANE_DESC_GEOMETRY;
pDesc->type = SANE_TYPE_GROUP;
pDesc->size = 0;
break;
@ -262,7 +319,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeXmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = rangeXmm.min + offsetX;
pVal->w = rangeXmm.min;
break;
case optTLY:
@ -273,7 +330,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeYmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = rangeYmm.min + offsetY;
pVal->w = rangeYmm.min;
break;
case optBRX:
@ -284,7 +341,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeXmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = rangeXmm.max + offsetX;
pVal->w = rangeXmm.max;
break;
case optBRY:
@ -295,22 +352,14 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeYmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = rangeYmm.max + offsetY;
pVal->w = rangeYmm.max;
break;
case optDPI:
pDesc->name = SANE_NAME_SCAN_RESOLUTION;
pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
pDesc->unit = SANE_UNIT_DPI;
pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
pDesc->constraint.word_list = setResolutions;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
pVal->w = setResolutions[1];
break;
case optGroupImage:
pDesc->title = SANE_I18N("Image");
//---------------------------------
case optGroupEnhancement:
pDesc->name = SANE_NAME_ENHANCEMENT;
pDesc->title = SANE_TITLE_ENHANCEMENT;
pDesc->desc = SANE_DESC_ENHANCEMENT;
pDesc->type = SANE_TYPE_GROUP;
pDesc->size = 0;
break;
@ -348,34 +397,130 @@ static void _InitOptions(TScanner *s)
pVal->wa = s->aGammaTableB;
break;
//---------------------------------
case optGroupSensors:
pDesc->name = SANE_NAME_SENSORS;
pDesc->title = SANE_TITLE_SENSORS;
pDesc->type = SANE_TYPE_GROUP;
pDesc->desc = SANE_DESC_SENSORS;
pDesc->size = 0;
break;
case optSensorScanTo:
pDesc->name = SANE_NAME_SCAN;
pDesc->title = SANE_TITLE_SCAN;
pDesc->desc = SANE_DESC_SCAN;
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorWeb:
pDesc->name = SANE_I18N("web");
pDesc->title = SANE_I18N("Share-To-Web button");
pDesc->desc = SANE_I18N("Scan an image and send it on the web");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorReprint:
pDesc->name = SANE_I18N("reprint");
pDesc->title = SANE_I18N("Reprint Photos button");
pDesc->desc = SANE_I18N("Button for reprinting photos");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorEmail:
pDesc->name = SANE_NAME_EMAIL;
pDesc->title = SANE_TITLE_EMAIL;
pDesc->desc = SANE_DESC_EMAIL;
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorCopy:
pDesc->name = SANE_NAME_COPY;
pDesc->title = SANE_TITLE_COPY;
pDesc->desc = SANE_DESC_COPY;
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorMoreOptions:
pDesc->name = SANE_I18N("more-options");
pDesc->title = SANE_I18N("More Options button");
pDesc->desc = SANE_I18N("Button for additional options/configuration");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorCancel:
pDesc->name = SANE_NAME_CANCEL;
pDesc->title = SANE_TITLE_CANCEL;
pDesc->desc = SANE_DESC_CANCEL;
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorPowerSave:
pDesc->name = SANE_I18N("power-save");
pDesc->title = SANE_I18N("Power Save button");
pDesc->desc = SANE_I18N("Puts the scanner in an energy-conservation mode");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorCopiesUp:
pDesc->name = SANE_I18N("copies-up");
pDesc->title = SANE_I18N("Increase Copies button");
pDesc->desc = SANE_I18N("Increase the number of copies");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorCopiesDown:
pDesc->name = SANE_I18N("copies-down");
pDesc->title = SANE_I18N("Decrease Copies button");
pDesc->desc = SANE_I18N("Decrease the number of copies");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorColourBW:
pDesc->name = SANE_I18N("color-bw");
pDesc->title = SANE_I18N("Select color/BW button");
pDesc->desc = SANE_I18N("Alternates between color and black/white scanning");
pDesc->type = SANE_TYPE_BOOL;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorColourBWState:
pDesc->name = SANE_I18N("color-bw-state");
pDesc->title = SANE_I18N("Read color/BW button state");
pDesc->desc = SANE_I18N("Reads state of BW/colour panel setting");
pDesc->type = SANE_TYPE_STRING;
pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
pDesc->constraint.string_list = modeSwitchList;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
break;
case optSensorCopyCount:
pDesc->name = SANE_I18N("copies-count");
pDesc->title = SANE_I18N("Read copy count value");
pDesc->desc = SANE_I18N("Reads state of copy count panel setting");
pDesc->type = SANE_TYPE_INT;
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeCopyCountTable;
pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
break;
#if 0
case optGroupMisc:
pDesc->title = SANE_I18N("Miscellaneous");
pDesc->type = SANE_TYPE_GROUP;
pDesc->size = 0;
break;
case optOffsetX:
pDesc->title = SANE_I18N("offset X");
pDesc->desc = SANE_I18N("Hardware internal X position of the scanning area.");
pDesc->unit = SANE_UNIT_MM;
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeXoffset;
pDesc->cap = SANE_CAP_SOFT_SELECT;
pVal->w = offsetX;
break;
case optOffsetY:
pDesc->title = SANE_I18N("offset Y");
pDesc->desc = SANE_I18N("Hardware internal Y position of the scanning area.");
pDesc->unit = SANE_UNIT_MM;
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeYoffset;
pDesc->cap = SANE_CAP_SOFT_SELECT;
pVal->w = offsetY;
break;
#if 0
case optLamp:
pDesc->name = "lamp";
pDesc->title = SANE_I18N("Lamp status");
@ -385,8 +530,7 @@ static void _InitOptions(TScanner *s)
/* switch the lamp on when starting for first the time */
pVal->w = SANE_TRUE;
break;
#endif
#if 0
case optCalibrate:
pDesc->name = "calibrate";
pDesc->title = SANE_I18N("Calibrate");
@ -467,7 +611,7 @@ sane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
SANE_String_Const proper_str;
int nline = 0;
/* prevent compiler from complaing about unused parameters */
/* prevent compiler from complaining about unused parameters */
pfnAuth = pfnAuth;
strcpy(usb_devfile, "/dev/usb/scanner0");
@ -531,7 +675,6 @@ sane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
*piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
}
return SANE_STATUS_GOOD;
}
@ -694,7 +837,7 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
/* Get options of type SANE_Word */
case optBRX:
case optTLX:
*(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - s->aValues[optOffsetX].w; */
*(SANE_Word *) pVal = s->aValues[n].w;
HP5400_DBG (DBG_MSG,
"sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
*(SANE_Word *) pVal);
@ -702,14 +845,12 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
case optBRY:
case optTLY:
*(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - - s->aValues[optOffsetY].w; */
*(SANE_Word *) pVal = s->aValues[n].w;
HP5400_DBG (DBG_MSG,
"sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
*(SANE_Word *) pVal);
break;
case optOffsetX:
case optOffsetY:
case optCount:
case optDPI:
HP5400_DBG (DBG_MSG,
@ -726,14 +867,94 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size);
break;
case optSensorScanTo:
case optSensorWeb:
case optSensorReprint:
case optSensorEmail:
case optSensorCopy:
case optSensorMoreOptions:
case optSensorCancel:
case optSensorPowerSave:
case optSensorCopiesUp:
case optSensorCopiesDown:
case optSensorColourBW:
{
HP5400_DBG (DBG_MSG, "Reading sensor state\n");
uint16_t sensorMap;
if (GetSensors(&s->HWParams, &sensorMap) != 0)
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE could not retrieve sensors\n");
return SANE_STATUS_IO_ERROR;
}
HP5400_DBG (DBG_MSG, "Sensor state=%x\n", sensorMap);
// Add read flags to what we already have so that we can report them when requested.
s->sensorMap |= sensorMap;
// Look up the mask based on the option number.
uint16_t mask = sensorMaskMap[n - optGroupSensors - 1];
*(SANE_Word *) pVal = (s->sensorMap & mask)? 1:0;
s->sensorMap &= ~mask;
break;
}
case optSensorCopyCount:
{
HP5400_DBG (DBG_MSG, "Reading copy count\n");
TPanelInfo panelInfo;
if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
return SANE_STATUS_IO_ERROR;
}
HP5400_DBG (DBG_MSG, "Copy count setting=%u\n", panelInfo.copycount);
*(SANE_Word *) pVal = panelInfo.copycount;
break;
}
case optSensorColourBWState:
{
HP5400_DBG (DBG_MSG, "Reading BW/Colour setting\n");
TPanelInfo panelInfo;
if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
return SANE_STATUS_IO_ERROR;
}
HP5400_DBG (DBG_MSG, "BW/Colour setting=%u\n", panelInfo.bwcolour);
// Just for safety:
if (panelInfo.bwcolour < 1)
{
panelInfo.bwcolour = 1;
}
else if (panelInfo.bwcolour > 2)
{
panelInfo.bwcolour = 2;
}
(void)strcpy((SANE_String)pVal, modeSwitchList[panelInfo.bwcolour - 1]);
break;
}
#if 0
/* Get options of type SANE_Bool */
case optLamp:
GetLamp (&s->HWParams, &fLampIsOn);
*(SANE_Bool *) pVal = fLampIsOn;
break;
#endif
#if 0
case optCalibrate:
/* although this option has nothing to read,
it's added here to avoid a warning when running scanimage --help */
@ -761,26 +982,70 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
case optBRX:
case optTLX:
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetX].w; */
break;
{
// Check against legal values.
SANE_Word value = *(SANE_Word *) pVal;
if ((value < s->aOptions[n].constraint.range->min) ||
(value > s->aOptions[n].constraint.range->max))
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE out of range X value\n");
return SANE_STATUS_INVAL;
}
case optBRY:
case optTLY:
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetY].w; */
break;
case optDPI:
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
#ifdef SUPPORT_2400_DPI
(s->aValues[n].w) = *(SANE_Word *) pVal;
#else
(s->aValues[n].w) = min (1200, *(SANE_Word *) pVal);
#endif
break;
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
s->aValues[n].w = value;
break;
}
case optBRY:
case optTLY:
{
// Check against legal values.
SANE_Word value = *(SANE_Word *) pVal;
if ((value < s->aOptions[n].constraint.range->min) ||
(value > s->aOptions[n].constraint.range->max))
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE out of range Y value\n");
return SANE_STATUS_INVAL;
}
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
s->aValues[n].w = value;
break;
}
case optDPI:
{
// Check against legal values.
SANE_Word dpiValue = *(SANE_Word *) pVal;
// First check too large.
SANE_Word maxRes = setResolutions[setResolutions[0]];
if (dpiValue > maxRes)
{
dpiValue = maxRes;
}
else // Check smaller values: if not exact match, pick next higher available.
{
for (SANE_Int resIdx = 1; resIdx <= setResolutions[0]; resIdx++)
{
if (dpiValue <= setResolutions[resIdx])
{
dpiValue = setResolutions[resIdx];
break;
}
}
}
info |= SANE_INFO_RELOAD_PARAMS;
s->ScanParams.iLines = 0; /* Forget actual image settings */
(s->aValues[n].w) = dpiValue;
break;
}
case optGammaTableRed:
case optGammaTableGreen:
@ -788,6 +1053,70 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
HP5400_DBG (DBG_MSG, "Writing gamma table\n");
memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size);
break;
case optSensorColourBWState:
{
SANE_String bwColour = (SANE_String)pVal;
SANE_Word bwColourValue;
if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_COLOR) == 0)
{
bwColourValue = 1;
}
else if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_GRAY) == 0)
{
bwColourValue = 2;
}
else
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE invalid colour/bw mode\n");
return SANE_STATUS_INVAL;
}
HP5400_DBG (DBG_MSG, "Setting BW/Colour state=%d\n", bwColourValue);
/*
* Now write it with the other panel settings back to the scanner.
*
*/
if (SetColourBW(&s->HWParams, bwColourValue) != 0)
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE could not set colour/BW mode\n");
return SANE_STATUS_IO_ERROR;
}
break;
}
case optSensorCopyCount:
{
SANE_Word copyCount = *(SANE_Word *) pVal;
if (copyCount < 0)
{
copyCount = 0;
}
else if (copyCount > 99)
{
copyCount = 99;
}
HP5400_DBG (DBG_MSG, "Setting Copy Count=%d\n", copyCount);
/*
* Now write it with the other panel settings back to the scanner.
*
*/
if (SetCopyCount(&s->HWParams, copyCount) != 0)
{
HP5400_DBG (DBG_ERR,
"sane_control_option: SANE_ACTION_SET_VALUE could not set copy count\n");
return SANE_STATUS_IO_ERROR;
}
break;
}
/*
case optLamp:
fVal = *(SANE_Bool *)pVal;
@ -924,6 +1253,7 @@ sane_start (SANE_Handle h)
s->ScanParams.iLinesRead = 0;
s->fScanning = TRUE;
s->fCanceled = FALSE;
return SANE_STATUS_GOOD;
}
@ -944,6 +1274,11 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
/* nothing has been read for the moment */
*len = 0;
if (!s->fScanning || s->fCanceled)
{
HP5400_DBG (DBG_MSG, "sane_read: we're not scanning.\n");
return SANE_STATUS_EOF;
}
/* if we read all the lines return EOF */

Wyświetl plik

@ -32,13 +32,13 @@ convenient lines to paste
export SANE_DEBUG_KODAKAIO=20
for ubuntu prior to 12.10
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-avahi BACKENDS="kodakaio test"
for ubuntu 12.10
./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi BACKENDS="kodakaio test"
for ubuntu 14.10 up to at least 17.04
./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi BACKENDS="kodakaio test"
If you want to use the test backend, for example with sane-troubleshoot, you should enable it in /etc/sane.d/dll.conf

Wyświetl plik

@ -34,8 +34,8 @@
#include "../include/sane/sanei_debug.h"
/* SANE backend operations, see Sane standard 1.04 documents (sane_dev.pdf)
for details */
/* SANE backend operations, see SANE Standard for details
https://sane-project.gitlab.io/standard/ */
/* Init the KV-S1025 SANE backend. This function must be called before any other
SANE function can be called. */

Wyświetl plik

@ -119,8 +119,8 @@ typedef uint32_t uint32_t;
/** \name Version of the driver */
/**@{*/
#define PIXMA_VERSION_MAJOR 0
#define PIXMA_VERSION_MINOR 26
#define PIXMA_VERSION_BUILD 0
#define PIXMA_VERSION_MINOR 27
#define PIXMA_VERSION_BUILD 2
/**@}*/
/** \name Error codes */

Wyświetl plik

@ -39,6 +39,7 @@
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#undef BACKEND_NAME
#define BACKEND_NAME bjnp
@ -117,6 +118,40 @@ static int bjnp_no_devices = 0;
* Private functions
*/
static const struct pixma_config_t *lookup_scanner(const char *makemodel,
const struct pixma_config_t *const pixma_devices[])
{
int i;
const struct pixma_config_t *cfg;
char *match;
for (i = 0; pixma_devices[i]; i++)
{
/* loop through the device classes (mp150, mp730 etc) */
for (cfg = pixma_devices[i]; cfg->name; cfg++)
{
/* loop through devices in class */
PDBG( bjnp_dbg( LOG_DEBUG3, "lookup_scanner: Checking for %s in %s\n", makemodel, cfg->model));
if ((match = strcasestr (makemodel, cfg->model)) != NULL)
{
/* possible match found, make sure it is not a partial match */
/* MP600 and MP600R are different models! */
/* some models contain ranges, so check for a '-' too */
if ((match[strlen(cfg->model)] == ' ') ||
(match[strlen(cfg->model)] == '\0') ||
(match[strlen(cfg->model)] == '-'))
{
PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model found: Name %s(%s) matches %s\n", cfg->model, cfg->name, makemodel));
return cfg;
}
}
}
}
PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model %s not found, giving up!\n", makemodel));
return NULL;
}
static void
u8tohex (char *string, const uint8_t *value, int len )
{
@ -1811,16 +1846,15 @@ static void add_scanner(SANE_Int *dev_no,
const char *uri,
SANE_Status (*attach_bjnp)
(SANE_String_Const devname,
SANE_String_Const makemodel,
SANE_String_Const serial,
const struct pixma_config_t *
const pixma_devices[]),
const struct pixma_config_t *const pixma_devices[])
const struct pixma_config_t *cfg),
const struct pixma_config_t *const pixma_devices[])
{
char scanner_host[BJNP_HOST_MAX];
char serial[BJNP_SERIAL_MAX];
char makemodel[BJNP_MODEL_MAX];
const struct pixma_config_t *cfg = NULL;
/* Allocate device structure for scanner */
switch (bjnp_allocate_device (uri, dev_no, scanner_host))
@ -1833,17 +1867,32 @@ static void add_scanner(SANE_Int *dev_no,
}
else
{
/*
* inform caller of found scanner
*/
/*
* fetch scanner configuration
*/
if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL)
{
PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: Scanner %s is not supported, model is unknown! Please report upstream\n", makemodel));
break;
}
determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial);
/*
* inform caller of found scanner
*/
attach_bjnp (uri, makemodel,
serial, pixma_devices);
PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n",
uri, serial, device[*dev_no].mac_address));
determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial);
switch (attach_bjnp (uri, serial, cfg))
{
case SANE_STATUS_GOOD:
PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n",
uri, serial, device[*dev_no].mac_address));
break;
default:
PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: unexpected error (out of memory?), adding %s\n", makemodel));
}
}
break;
case BJNP_STATUS_ALREADY_ALLOCATED:
PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s was added before, good!\n",
@ -1898,10 +1947,7 @@ int add_timeout_to_uri(char *uri, int timeout, int max_len)
return 0;
}
/*
* Public functions
*/
/** Public functions **/
/** Initialize sanei_bjnp.
*
@ -1926,11 +1972,9 @@ sanei_bjnp_init (void)
extern SANE_Status
sanei_bjnp_find_devices (const char **conf_devices,
SANE_Status (*attach_bjnp)
(SANE_String_Const devname,
SANE_String_Const makemodel,
SANE_String_Const serial,
const struct pixma_config_t *
const pixma_devices[]),
(SANE_String_Const devname,
SANE_String_Const serial,
const struct pixma_config_t *cfg),
const struct pixma_config_t *const pixma_devices[])
{
int numbytes = 0;

Wyświetl plik

@ -81,12 +81,10 @@ extern void sanei_bjnp_init (void);
extern SANE_Status
sanei_bjnp_find_devices (const char **conf_devices,
SANE_Status (*attach_bjnp)
(SANE_String_Const devname,
SANE_String_Const makemodel,
SANE_String_Const serial,
const struct pixma_config_t *
const pixma_devices[]),
const struct pixma_config_t *const pixma_devices[]);
(SANE_String_Const devname,
SANE_String_Const serial,
const struct pixma_config_t *cfg),
const struct pixma_config_t *const pixma_devices[]);
/** Open a BJNP device.
*

Wyświetl plik

@ -119,6 +119,7 @@
#define MF420_PID 0x27f1
#define MF260_PID 0x27f4
#define MF740_PID 0x27fb
#define MF743_PID 0x27fc
#define MF640_PID 0x27fe
#define MF645_PID 0x27fd
@ -972,11 +973,12 @@ const pixma_config_t pixma_iclass_devices[] = {
DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */
DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0),
DEV ("Canon i-SENSYS MF110 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0),
DEV ("Canon i-SENSYS MF110/910 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0),
DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF740 Series", "MF740", MF740_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF741C/743C", "MF741C/743C", MF743_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), /* ADFDUP restricted to 300dpi */
DEV ("Canon i-SENSYS MF640 Series", "MF642C/643C/644C", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF645C", "MF645C", MF645_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */
DEV (NULL, NULL, 0, 0, 0, 0, 0, 0)

Wyświetl plik

@ -107,39 +107,6 @@ get_scanner_info (unsigned devnr)
return si;
}
static const struct pixma_config_t *lookup_scanner(const char *makemodel,
const struct pixma_config_t *const pixma_devices[])
{
int i;
const struct pixma_config_t *cfg;
char *match;
for (i = 0; pixma_devices[i]; i++)
{
/* loop through the device classes (mp150, mp730 etc) */
for (cfg = pixma_devices[i]; cfg->name; cfg++)
{
/* loop through devices in class */
if ((match = strcasestr (makemodel, cfg->model)) != NULL)
{
/* possible match found, make sure it is not a partial match */
/* MP600 and MP600R are different models! */
/* some models contain ranges, so check for a '-' too */
if ((match[strlen(cfg->model)] == ' ') ||
(match[strlen(cfg->model)] == '\0') ||
(match[strlen(cfg->model)] == '-'))
{
pixma_dbg (3, "Scanner model found: Name %s(%s) matches %s\n", cfg->model, cfg->name, makemodel);
return cfg;
}
}
pixma_dbg (20, "Scanner model %s(%s) not found, giving up! %s\n", cfg->model, cfg->name, makemodel);
}
}
return NULL;
}
static SANE_Status
attach (SANE_String_Const devname)
{
@ -160,13 +127,11 @@ attach (SANE_String_Const devname)
static SANE_Status
attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel,
attach_bjnp (SANE_String_Const devname,
SANE_String_Const serial,
const struct pixma_config_t *const pixma_devices[])
const struct pixma_config_t *cfg)
{
scanner_info_t *si;
const pixma_config_t *cfg;
SANE_Status error;
si = (scanner_info_t *) calloc (1, sizeof (*si));
if (!si)
@ -174,19 +139,14 @@ attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel,
si->devname = strdup (devname);
if (!si->devname)
return SANE_STATUS_NO_MEM;
if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL)
error = SANE_STATUS_INVAL;
else
{
si->cfg = cfg;
sprintf(si->serial, "%s_%s", cfg->model, serial);
si -> interface = INT_BJNP;
si->next = first_scanner;
first_scanner = si;
nscanners++;
error = SANE_STATUS_GOOD;
}
return error;
si->cfg = cfg;
sprintf(si->serial, "%s_%s", cfg->model, serial);
si -> interface = INT_BJNP;
si->next = first_scanner;
first_scanner = si;
nscanners++;
return SANE_STATUS_GOOD;
}
static void

Wyświetl plik

@ -1765,7 +1765,7 @@ const pixma_config_t pixma_mp150_devices[] = {
/* Latest devices (2018) Generation 5 CIS */
DEVICE ("Canon MAXIFY MB5400 Series", "MB5400", MB5400_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG),
DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP),
DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG),
DEVICE ("Canon PIXMA TS9100 Series", "TS9100", TS9100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
DEVICE ("Canon PIXMA TR7500 Series", "TR7500", TR7500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),

Wyświetl plik

@ -306,7 +306,7 @@ cano_AdjustLightsource( Plustek_Device *dev )
min_rgb.Blue = hw->blue_lamp_on;
if((dev->adj.rlampoff != -1) &&
(dev->adj.glampoff != -1) && (dev->adj.rlampoff != -1)) {
(dev->adj.glampoff != -1) && (dev->adj.blampoff != -1)) {
DBG( _DBG_INFO, "- function skipped, using frontend values!\n" );
return SANE_TRUE;
}

Wyświetl plik

@ -212,6 +212,7 @@ static int isSupportedDevice(struct device __sane_unused__ *dev)
/* blacklist malfunctioning device(s) */
if (!strncmp(dev->sane.model, "SCX-4500W", 9) ||
!strncmp(dev->sane.model, "C460", 4) ||
!!strstr(dev->sane.model, "CLX-3170") ||
!strncmp(dev->sane.model, "M288x", 5))
return 0;
return 1;

Wyświetl plik

@ -769,54 +769,6 @@ AC_ARG_ENABLE(parport-directio,
fi
])
dnl ******************************************************************
dnl SANE API specification format conversion support
dnl ******************************************************************
AC_ARG_WITH(api-spec,
AS_HELP_STRING([--with-api-spec],
[convert API spec to supported output formats @<:@default=check@:>@]),
[],
[with_api_spec=check])
dnl Test for all tools that may be involved. These tests are fast and
dnl running them allows for the Makefile targets to be formulated such
dnl that any non-requested formats can be made using a one-off without
dnl the need to reconfigure.
AC_PATH_PROG(MAKEINDEX, makeindex, no)
AC_PATH_PROG(DVIPS, dvips, no)
AC_PATH_PROG(LATEX, latex, no)
AC_PATH_PROG(PDFLATEX, pdflatex, no)
AC_PATH_PROG(FIG2DEV, fig2dev, no)
AC_PATH_PROG(GS, gs, no)
AC_PATH_PROG(DLH, dlh, no)
AC_PATH_PROG(PPMTOGIF, ppmtogif, no)
AS_IF([test xno != "x$with_api_spec"],
[dnl Flag formats for which all required tools have been found
AS_IF([ test xno != "x$MAKEINDEX" \
&& test xno != "x$DVIPS" \
&& test xno != "x$FIG2DEV" \
&& test xno != "x$LATEX"], [with_api_ps=yes])
AS_IF([ test xno != "x$MAKEINDEX" \
&& test xno != "x$PDFLATEX" \
&& test xno != "x$FIG2DEV" \
&& test xno != "x$GS"], [with_api_pdf=yes])
AS_IF([ test xno != "x$MAKEINDEX" \
&& test xno != "x$DVIPS" \
&& test xno != "x$FIG2DEV" \
&& test xno != "x$DLH" \
&& test xno != "x$GS" \
&& test xno != "x$PPMTOFIG" ], [with_api_html=yes])
AS_IF([test xyes = "x$with_api_spec" \
&& test xyes != "x$with_api_ps" \
&& test xyes != "x$with_api_pdf" \
&& test xyes != "x$with_api_html"],
[AC_MSG_ERROR([tools to convert the API spec are missing])
])
])
AM_CONDITIONAL(WITH_API_PS, [test x$with_api_ps = xyes])
AM_CONDITIONAL(WITH_API_PDF, [test x$with_api_pdf = xyes])
AM_CONDITIONAL(WITH_API_HTML, [test x$with_api_html = xyes])
dnl ***********************************************************************
dnl Write output files
dnl ***********************************************************************

13
doc/.gitignore vendored
Wyświetl plik

@ -2,24 +2,11 @@
*.5
*.7
*.8
*.eps
*.html
*.pdf
descriptions-external.db
descriptions.db
doxygen-genesys.conf
doxygen-sanei.conf
doxygen_sqlite3.db
genesys-html
sane.aux
sane.cb
sane.dvi
sane.idx
sane.ilg
sane.ind
sane.lof
sane.log
sane.lot
sane.ps
sane.toc
sanei-html

Wyświetl plik

@ -82,11 +82,10 @@ HTML_PAGES = sane-backends.html sane-backends-external.html \
endif
doc_DATA = $(HTML_PAGES)
all: bemans $(API_SPECS) html-pages
all: bemans html-pages
dist_doc_DATA = backend-writing.txt
nobase_dist_doc_DATA = $(BEDOCS)
doc_DATA += $(API_SPECS)
EXTRA_DIST += descriptions.txt releases.txt sane-logo2.jpg sane-logo.png \
sane.png
@ -218,89 +217,6 @@ install-data-local: install-beman5
uninstall-local:
rm -rf $(DESTDIR)$(beman5dir)/sane-*.5
## SANE API specification format conversion support
API_SPECS =
if WITH_API_PS
API_SPECS += sane.ps
endif
if WITH_API_PDF
API_SPECS += sane.pdf
endif
if WITH_API_HTML
API_SPECS += sane-html
endif
API_SPEC_INPUTS = $(srcdir)/sane.tex
API_SPEC_INPUTS += $(srcdir)/net.tex
EXTRA_DIST += $(API_SPEC_INPUTS)
API_SPEC_TEX_FIGS =
API_SPEC_TEX_FIGS += figs/area.fig
API_SPEC_TEX_FIGS += figs/flow.fig
API_SPEC_TEX_FIGS += figs/hierarchy.fig
API_SPEC_TEX_FIGS += figs/image-data.fig
API_SPEC_TEX_FIGS += figs/xfer.fig
EXTRA_DIST += $(API_SPEC_TEX_FIGS)
API_SPEC_EPS_FIGS =
API_SPEC_EPS_FIGS += figs/area.eps
API_SPEC_EPS_FIGS += figs/flow.eps
API_SPEC_EPS_FIGS += figs/hierarchy.eps
API_SPEC_EPS_FIGS += figs/image-data.eps
API_SPEC_EPS_FIGS += figs/xfer.eps
API_SPEC_PDF_FIGS =
API_SPEC_PDF_FIGS += figs/area.pdf
API_SPEC_PDF_FIGS += figs/flow.pdf
API_SPEC_PDF_FIGS += figs/hierarchy.pdf
API_SPEC_PDF_FIGS += figs/image-data.pdf
API_SPEC_PDF_FIGS += figs/xfer.pdf
## These icons are referred to in the generated HTML output.
API_SPEC_HTML_ICONS =
API_SPEC_HTML_ICONS += icons/contents.gif
API_SPEC_HTML_ICONS += icons/index.gif
API_SPEC_HTML_ICONS += icons/next.gif icons/next_gr.gif
API_SPEC_HTML_ICONS += icons/previous.gif icons/previous_gr.gif
API_SPEC_HTML_ICONS += icons/references.gif icons/references_gr.gif
API_SPEC_HTML_ICONS += icons/up.gif icons/up_gr.gif
EXTRA_DIST += $(API_SPEC_HTML_ICONS)
am_TEXINPUTS = TEXINPUTS="$(builddir):$(srcdir):$$TEXINPUTS"
sane.ind: $(API_SPEC_INPUTS)
@echo Generating index for $<...
@touch sane.ind
@$(am_TEXINPUTS) $(LATEX) $< </dev/null >/dev/null && \
$(MAKEINDEX) -q sane.idx && \
$(am_TEXINPUTS) $(LATEX) $< </dev/null >/dev/null
.fig.eps:
@test -d $(@D) || $(MKDIR_P) $(@D)
$(FIG2DEV) -L eps $< $@
sane.dvi: $(API_SPEC_INPUTS) $(API_SPEC_EPS_FIGS) sane.ind
@echo Generating $@ from $<...
@$(am_TEXINPUTS) $(LATEX) $< </dev/null >/dev/null
sane.ps: sane.dvi
@echo Generating $@ from $<...
@$(am_TEXINPUTS) $(DVIPS) -q $< -o $@
.fig.pdf:
@test -d $(@D) || $(MKDIR_P) $(@D)
$(FIG2DEV) -L pdf $< $@
sane.pdf: $(API_SPEC_INPUTS) $(API_SPEC_PDF_FIGS) sane.ind
@echo Generating $@ from $<...
@$(am_TEXINPUTS) $(PDFLATEX) $< >/dev/null
sane-html: sane.dvi
$(am_TEXINPUTS) $(DLH) $(srcdir)/sane.tex
## ^^
html-man: $(MANPAGES)
@for page in $(MANPAGES); do \
echo "translating $${page} to $${page}.html..."; \
@ -347,20 +263,12 @@ descriptions-external.db: $(DESC_EXT_FILES) ../tools/sane-desc
> descriptions-external.db
html-pages: $(HTML_PAGES)
html-local: html-pages html-man sane-html
clean-local:
rm -f *.toc *.aux *.log *.cp *.fn *.tp *.vr *.pg *.ky *.blg *.idx *.cb
rm -f *.ilg
rm -f $(API_SPEC_EPS_FIGS) $(API_SPEC_PDF_FIGS)
-rmdir figs
html-local: html-pages html-man
distclean-local:
rm -f $(MANPAGES)
rm -f *.lot *.lof *.ind
rm -f sane.dvi sane.ps sane-backends.html sane-backends-external.html
rm -f sane-backends.html sane-backends-external.html
rm -f sane-mfgs.html sane-mfgs-external.html
rm -f sane/*.html sane/*.gif
rm -f doxygen-sanei.conf doxygen-genesys.conf
-rm -rf sane sanei-html
for manpage in $(MANPAGES) ; do \

Some files were not shown because too many files have changed in this diff Show More