From b839a26abc3c40c49aa06ee78d933a9beddd593c Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Thu, 1 Jan 2015 01:22:10 +0000 Subject: [PATCH] import libksane, skanlite and ksaneplugin (bootstrap will fail) --- CMakeLists.txt | 4 + ksaneplugin/CMakeLists.txt | 25 + ksaneplugin/COPYING | 510 +++++ ksaneplugin/Messages.sh | 2 + .../cmake/modules/COPYING-CMAKE-SCRIPTS | 22 + ksaneplugin/cmake/modules/FindKSane.cmake | 44 + ksaneplugin/ksane_scan_service.desktop | 81 + ksaneplugin/sanedialog.cpp | 114 + ksaneplugin/sanedialog.h | 52 + libksane/.directory | 3 + libksane/.gitignore | 2 + libksane/AUTHORS | 8 + libksane/CMakeLists.txt | 83 + libksane/COPYING | 340 +++ libksane/COPYING-CMAKE-SCRIPTS | 22 + libksane/COPYING.LIB | 510 +++++ libksane/COPYING.twain | 33 + libksane/ChangeLog | 12 + libksane/NEWS | 5 + libksane/README | 72 + libksane/TODO | 49 + libksane/cmake/templates/KSaneConfig.cmake.in | 10 + .../cmake/templates/libksane.lsm.cmake.in | 15 + libksane/cmake/templates/libksane.pc.cmake.in | 12 + libksane/ksanetwain/CMakeLists.txt | 35 + libksane/ksanetwain/ktwain_widget.cpp | 149 ++ libksane/ksanetwain/twain.h | 1977 +++++++++++++++++ libksane/ksanetwain/twainiface.cpp | 595 +++++ libksane/ksanetwain/twainiface.h | 127 ++ libksane/libksane/CMakeLists.txt | 79 + libksane/libksane/Mainpage.dox | 15 + libksane/libksane/Messages.sh | 3 + libksane/libksane/dummy-hplip.cpp | 33 + libksane/libksane/hi16-action-black-white.png | Bin 0 -> 129 bytes libksane/libksane/hi16-action-color.png | Bin 0 -> 803 bytes libksane/libksane/hi16-action-gray-scale.png | Bin 0 -> 182 bytes libksane/libksane/ksane.h | 307 +++ libksane/libksane/ksane_auth.cpp | 136 ++ libksane/libksane/ksane_auth.h | 63 + libksane/libksane/ksane_device_dialog.cpp | 189 ++ libksane/libksane/ksane_device_dialog.h | 83 + .../libksane/ksane_find_devices_thread.cpp | 107 + libksane/libksane/ksane_find_devices_thread.h | 57 + libksane/libksane/ksane_preview_thread.cpp | 472 ++++ libksane/libksane/ksane_preview_thread.h | 94 + libksane/libksane/ksane_scan_thread.cpp | 311 +++ libksane/libksane/ksane_scan_thread.h | 88 + libksane/libksane/ksane_viewer.cpp | 1102 +++++++++ libksane/libksane/ksane_viewer.h | 128 ++ libksane/libksane/ksane_viewer_test.cpp | 52 + libksane/libksane/ksane_widget.cpp | 931 ++++++++ libksane/libksane/ksane_widget_private.cpp | 1134 ++++++++++ libksane/libksane/ksane_widget_private.h | 204 ++ libksane/libksane/libksane_export.h | 40 + .../libksane/options/ksane_opt_button.cpp | 71 + libksane/libksane/options/ksane_opt_button.h | 58 + .../libksane/options/ksane_opt_checkbox.cpp | 138 ++ .../libksane/options/ksane_opt_checkbox.h | 68 + libksane/libksane/options/ksane_opt_combo.cpp | 380 ++++ libksane/libksane/options/ksane_opt_combo.h | 76 + libksane/libksane/options/ksane_opt_entry.cpp | 114 + libksane/libksane/options/ksane_opt_entry.h | 65 + .../libksane/options/ksane_opt_fslider.cpp | 176 ++ libksane/libksane/options/ksane_opt_fslider.h | 72 + libksane/libksane/options/ksane_opt_gamma.cpp | 109 + libksane/libksane/options/ksane_opt_gamma.h | 64 + .../libksane/options/ksane_opt_slider.cpp | 164 ++ libksane/libksane/options/ksane_opt_slider.h | 71 + libksane/libksane/options/ksane_option.cpp | 343 +++ libksane/libksane/options/ksane_option.h | 122 + libksane/libksane/selectionitem.cpp | 262 +++ libksane/libksane/selectionitem.h | 82 + libksane/libksane/splittercollapser.cpp | 307 +++ libksane/libksane/splittercollapser.h | 69 + libksane/libksane/version.h.cmake.in | 30 + libksane/libksane/widgets/gamma_disp.cpp | 90 + libksane/libksane/widgets/gamma_disp.h | 76 + libksane/libksane/widgets/ksane_button.cpp | 51 + libksane/libksane/widgets/ksane_button.h | 67 + .../libksane/widgets/ksane_option_widget.cpp | 74 + .../libksane/widgets/ksane_option_widget.h | 70 + .../libksane/widgets/labeled_checkbox.cpp | 62 + libksane/libksane/widgets/labeled_checkbox.h | 74 + libksane/libksane/widgets/labeled_combo.cpp | 101 + libksane/libksane/widgets/labeled_combo.h | 100 + libksane/libksane/widgets/labeled_entry.cpp | 81 + libksane/libksane/widgets/labeled_entry.h | 81 + libksane/libksane/widgets/labeled_fslider.cpp | 176 ++ libksane/libksane/widgets/labeled_fslider.h | 110 + libksane/libksane/widgets/labeled_gamma.cpp | 199 ++ libksane/libksane/widgets/labeled_gamma.h | 93 + libksane/libksane/widgets/labeled_slider.cpp | 141 ++ libksane/libksane/widgets/labeled_slider.h | 104 + skanlite/.directory | 3 + skanlite/CMakeLists.txt | 21 + skanlite/src/CMakeLists.txt | 14 + skanlite/src/COPYING | 346 +++ skanlite/src/ImageViewer.cpp | 138 ++ skanlite/src/ImageViewer.h | 58 + skanlite/src/KSaneImageSaver.cpp | 236 ++ skanlite/src/KSaneImageSaver.h | 61 + skanlite/src/Messages.sh | 3 + skanlite/src/SaveLocation.cpp | 65 + skanlite/src/SaveLocation.h | 49 + skanlite/src/SaveLocation.ui | 123 + skanlite/src/TODO | 4 + skanlite/src/main.cpp | 87 + skanlite/src/settings.ui | 412 ++++ skanlite/src/skanlite.cpp | 546 +++++ skanlite/src/skanlite.desktop | 153 ++ skanlite/src/skanlite.h | 99 + skanlite/src/version.h.cmake | 24 + 112 files changed, 17574 insertions(+) create mode 100644 ksaneplugin/CMakeLists.txt create mode 100644 ksaneplugin/COPYING create mode 100644 ksaneplugin/Messages.sh create mode 100644 ksaneplugin/cmake/modules/COPYING-CMAKE-SCRIPTS create mode 100644 ksaneplugin/cmake/modules/FindKSane.cmake create mode 100644 ksaneplugin/ksane_scan_service.desktop create mode 100644 ksaneplugin/sanedialog.cpp create mode 100644 ksaneplugin/sanedialog.h create mode 100644 libksane/.directory create mode 100644 libksane/.gitignore create mode 100644 libksane/AUTHORS create mode 100644 libksane/CMakeLists.txt create mode 100644 libksane/COPYING create mode 100644 libksane/COPYING-CMAKE-SCRIPTS create mode 100644 libksane/COPYING.LIB create mode 100644 libksane/COPYING.twain create mode 100644 libksane/ChangeLog create mode 100644 libksane/NEWS create mode 100644 libksane/README create mode 100644 libksane/TODO create mode 100644 libksane/cmake/templates/KSaneConfig.cmake.in create mode 100644 libksane/cmake/templates/libksane.lsm.cmake.in create mode 100644 libksane/cmake/templates/libksane.pc.cmake.in create mode 100644 libksane/ksanetwain/CMakeLists.txt create mode 100644 libksane/ksanetwain/ktwain_widget.cpp create mode 100644 libksane/ksanetwain/twain.h create mode 100644 libksane/ksanetwain/twainiface.cpp create mode 100644 libksane/ksanetwain/twainiface.h create mode 100644 libksane/libksane/CMakeLists.txt create mode 100644 libksane/libksane/Mainpage.dox create mode 100755 libksane/libksane/Messages.sh create mode 100644 libksane/libksane/dummy-hplip.cpp create mode 100644 libksane/libksane/hi16-action-black-white.png create mode 100644 libksane/libksane/hi16-action-color.png create mode 100644 libksane/libksane/hi16-action-gray-scale.png create mode 100644 libksane/libksane/ksane.h create mode 100644 libksane/libksane/ksane_auth.cpp create mode 100644 libksane/libksane/ksane_auth.h create mode 100644 libksane/libksane/ksane_device_dialog.cpp create mode 100644 libksane/libksane/ksane_device_dialog.h create mode 100644 libksane/libksane/ksane_find_devices_thread.cpp create mode 100644 libksane/libksane/ksane_find_devices_thread.h create mode 100644 libksane/libksane/ksane_preview_thread.cpp create mode 100644 libksane/libksane/ksane_preview_thread.h create mode 100644 libksane/libksane/ksane_scan_thread.cpp create mode 100644 libksane/libksane/ksane_scan_thread.h create mode 100644 libksane/libksane/ksane_viewer.cpp create mode 100644 libksane/libksane/ksane_viewer.h create mode 100644 libksane/libksane/ksane_viewer_test.cpp create mode 100644 libksane/libksane/ksane_widget.cpp create mode 100644 libksane/libksane/ksane_widget_private.cpp create mode 100644 libksane/libksane/ksane_widget_private.h create mode 100644 libksane/libksane/libksane_export.h create mode 100644 libksane/libksane/options/ksane_opt_button.cpp create mode 100644 libksane/libksane/options/ksane_opt_button.h create mode 100644 libksane/libksane/options/ksane_opt_checkbox.cpp create mode 100644 libksane/libksane/options/ksane_opt_checkbox.h create mode 100644 libksane/libksane/options/ksane_opt_combo.cpp create mode 100644 libksane/libksane/options/ksane_opt_combo.h create mode 100644 libksane/libksane/options/ksane_opt_entry.cpp create mode 100644 libksane/libksane/options/ksane_opt_entry.h create mode 100644 libksane/libksane/options/ksane_opt_fslider.cpp create mode 100644 libksane/libksane/options/ksane_opt_fslider.h create mode 100644 libksane/libksane/options/ksane_opt_gamma.cpp create mode 100644 libksane/libksane/options/ksane_opt_gamma.h create mode 100644 libksane/libksane/options/ksane_opt_slider.cpp create mode 100644 libksane/libksane/options/ksane_opt_slider.h create mode 100644 libksane/libksane/options/ksane_option.cpp create mode 100644 libksane/libksane/options/ksane_option.h create mode 100644 libksane/libksane/selectionitem.cpp create mode 100644 libksane/libksane/selectionitem.h create mode 100644 libksane/libksane/splittercollapser.cpp create mode 100644 libksane/libksane/splittercollapser.h create mode 100644 libksane/libksane/version.h.cmake.in create mode 100644 libksane/libksane/widgets/gamma_disp.cpp create mode 100644 libksane/libksane/widgets/gamma_disp.h create mode 100644 libksane/libksane/widgets/ksane_button.cpp create mode 100644 libksane/libksane/widgets/ksane_button.h create mode 100644 libksane/libksane/widgets/ksane_option_widget.cpp create mode 100644 libksane/libksane/widgets/ksane_option_widget.h create mode 100644 libksane/libksane/widgets/labeled_checkbox.cpp create mode 100644 libksane/libksane/widgets/labeled_checkbox.h create mode 100644 libksane/libksane/widgets/labeled_combo.cpp create mode 100644 libksane/libksane/widgets/labeled_combo.h create mode 100644 libksane/libksane/widgets/labeled_entry.cpp create mode 100644 libksane/libksane/widgets/labeled_entry.h create mode 100644 libksane/libksane/widgets/labeled_fslider.cpp create mode 100644 libksane/libksane/widgets/labeled_fslider.h create mode 100644 libksane/libksane/widgets/labeled_gamma.cpp create mode 100644 libksane/libksane/widgets/labeled_gamma.h create mode 100644 libksane/libksane/widgets/labeled_slider.cpp create mode 100644 libksane/libksane/widgets/labeled_slider.h create mode 100644 skanlite/.directory create mode 100644 skanlite/CMakeLists.txt create mode 100644 skanlite/src/CMakeLists.txt create mode 100644 skanlite/src/COPYING create mode 100644 skanlite/src/ImageViewer.cpp create mode 100644 skanlite/src/ImageViewer.h create mode 100644 skanlite/src/KSaneImageSaver.cpp create mode 100644 skanlite/src/KSaneImageSaver.h create mode 100755 skanlite/src/Messages.sh create mode 100644 skanlite/src/SaveLocation.cpp create mode 100644 skanlite/src/SaveLocation.h create mode 100644 skanlite/src/SaveLocation.ui create mode 100644 skanlite/src/TODO create mode 100644 skanlite/src/main.cpp create mode 100644 skanlite/src/settings.ui create mode 100644 skanlite/src/skanlite.cpp create mode 100644 skanlite/src/skanlite.desktop create mode 100644 skanlite/src/skanlite.h create mode 100644 skanlite/src/version.h.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 44b70f00..dac18d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,8 @@ macro_optional_add_subdirectory (kdenetwork-filesharing) macro_optional_add_subdirectory (kfilemetadata) # macro_optional_add_subdirectory (kfilereplace) macro_optional_add_subdirectory (lokalize) +# FIXME: make skanlite and ksaneplugin find libksane +macro_optional_add_subdirectory (libksane) macro_optional_add_subdirectory (libkscreen) # FIXME: make kget find libktorrent macro_optional_add_subdirectory (libktorrent) @@ -53,6 +55,7 @@ macro_optional_add_subdirectory (kolourpaint) macro_optional_add_subdirectory (kompare) macro_optional_add_subdirectory (krdc) macro_optional_add_subdirectory (krfb) +macro_optional_add_subdirectory (ksaneplugin) macro_optional_add_subdirectory (ksnapshot) macro_optional_add_subdirectory (ksystemlog) macro_optional_add_subdirectory (ktimer) @@ -61,5 +64,6 @@ macro_optional_add_subdirectory (kuser) macro_optional_add_subdirectory (okular) macro_optional_add_subdirectory (partitionmanager) macro_optional_add_subdirectory (print-manager) +macro_optional_add_subdirectory (skanlite) macro_optional_add_subdirectory (svgpart) macro_optional_add_subdirectory (thumbnailers) diff --git a/ksaneplugin/CMakeLists.txt b/ksaneplugin/CMakeLists.txt new file mode 100644 index 00000000..1d6b8a3a --- /dev/null +++ b/ksaneplugin/CMakeLists.txt @@ -0,0 +1,25 @@ + +project(ksaneplugin) + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules ) + +find_package(KDE4 REQUIRED) +include(KDE4Defaults) +include(MacroLibrary) +include(MacroOptionalAddSubdirectory) + +find_package(KSane REQUIRED) +include_directories(${KSANE_INCLUDE_DIR}) +add_definitions (${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS} ${KDE4_DEFINITIONS} -DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) +include_directories (${QDBUS_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +########### target ############### +kde4_add_plugin(ksaneplugin sanedialog.cpp) + +target_link_libraries(ksaneplugin ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KSANE_LIBRARY}) + +install(TARGETS ksaneplugin DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### install files ############### +install( FILES ksane_scan_service.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/ksaneplugin/COPYING b/ksaneplugin/COPYING new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/ksaneplugin/COPYING @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ksaneplugin/Messages.sh b/ksaneplugin/Messages.sh new file mode 100644 index 00000000..4a2ee74a --- /dev/null +++ b/ksaneplugin/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/ksaneplugin.pot diff --git a/ksaneplugin/cmake/modules/COPYING-CMAKE-SCRIPTS b/ksaneplugin/cmake/modules/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..ab3c4d25 --- /dev/null +++ b/ksaneplugin/cmake/modules/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ksaneplugin/cmake/modules/FindKSane.cmake b/ksaneplugin/cmake/modules/FindKSane.cmake new file mode 100644 index 00000000..bab0f560 --- /dev/null +++ b/ksaneplugin/cmake/modules/FindKSane.cmake @@ -0,0 +1,44 @@ +# cmake macro to test if libksane is installed +# +# KSANE_FOUND - system has KSANE libs +# KSANE_INCLUDE_DIR - the KSANE include directory +# KSANE_LIBRARY - The library needed to use KSANE + +if (KSANE_INCLUDE_DIR) + # Already in cache, be silent + set(KSANE_FIND_QUIETLY TRUE) +endif (KSANE_INCLUDE_DIR) + +FIND_FILE(KSANE_LOCAL_FOUND libksane/version.h.cmake ${CMAKE_SOURCE_DIR}/libs/libksane NO_DEFAULT_PATH) + +if (KSANE_LOCAL_FOUND) + set(KSANE_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/libs/libksane) + set(KSANE_DEFINITIONS -I${KSANE_INCLUDE_DIR}) + set(KSANE_LIBRARY ksane) + message(STATUS "Found KSane library in local sub-folder: ${KSANE_LIBRARY}") + set(KSANE_FOUND TRUE) + MARK_AS_ADVANCED(KSANE_INCLUDE_DIR KSANE_LIBRARY) +else (KSANE_LOCAL_FOUND) + + FIND_PATH(KSANE_INCLUDE_DIR libksane/ksane.h ${KDE4_INCLUDES}) + + FIND_LIBRARY(KSANE_LIBRARY ksane PATH ${KDE4_LIB_DIR}) + + if (KSANE_INCLUDE_DIR AND KSANE_LIBRARY) + set(KSANE_FOUND TRUE) + else (KSANE_INCLUDE_DIR AND KSANE_LIBRARY) + set(KSANE_FOUND FALSE) + endif (KSANE_INCLUDE_DIR AND KSANE_LIBRARY) + + if (KSANE_FOUND) + if (NOT KSane_FIND_QUIETLY) + message(STATUS "Found libksane: ${KSANE_LIBRARY}") + endif (NOT KSane_FIND_QUIETLY) + else (KSANE_FOUND) + if (KSane_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libksane") + endif (KSane_FIND_REQUIRED) + endif (KSANE_FOUND) +endif (KSANE_LOCAL_FOUND) + +MARK_AS_ADVANCED(KSANE_INCLUDE_DIR KSANE_LIBRARY) \ No newline at end of file diff --git a/ksaneplugin/ksane_scan_service.desktop b/ksaneplugin/ksane_scan_service.desktop new file mode 100644 index 00000000..a8fc3877 --- /dev/null +++ b/ksaneplugin/ksane_scan_service.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Type=Service +Name=KDE Scan Service +Name[af]=Kde Skandeer Diens +Name[ar]=خدمة المسح لكدي +Name[ast]=Serviciu de dixitalización de KDE +Name[bg]=Услуга за сканиране +Name[br]=Damanterien skramm +Name[bs]=KDE‑ov servis za skeniranje +Name[ca]=Servei d'escaneig del KDE +Name[ca@valencia]=Servei d'escaneig del KDE +Name[cs]=Skenovací služba pro KDE +Name[cy]=Gwasanaeth Sganio KDE +Name[da]=KDE Skanneservice +Name[de]=Scan-Dienst von KDE +Name[el]=Υπηρεσία σάρωσης του KDE +Name[en_GB]=KDE Scan Service +Name[eo]=KDE skana servo +Name[es]=Servicio de digitalización de KDE +Name[et]=KDE skaneerimisteenus +Name[eu]=KDEren eskaneatze zerbitzua +Name[fa]=خدمت پویش KDE +Name[fi]=KDE :n skannauspalvelu +Name[fr]=Service de numérisation de KDE +Name[ga]=Seirbhís Scanta KDE +Name[gl]=Servizo de escáner de KDE +Name[he]=שירות הסריקה של KDE +Name[hi]=केडीई स्कैन सर्विस +Name[hne]=केडीई स्कैन सर्विस +Name[hr]=KDE skan servis +Name[hu]=KDE lapolvasó szolgáltatás +Name[ia]=Servicio de scander de KDE +Name[is]=KDE myndlesaraþjónusta +Name[it]=Servizio di scansione di KDE +Name[ja]=KDE スキャンサービス +Name[kk]=KDE сканер қызметі +Name[km]=សេវា​ស្កេន​របស់ KDE +Name[ko]=KDE 스캔 서비스 +Name[ku]=KDE Servîsa Venihêrînê +Name[lt]=KDE skanavimo tarnyba +Name[lv]=KDE skenēšanas serviss +Name[mr]=केडीई स्कॅन सेवा +Name[ms]=Perkhidmatan Imbas KDE +Name[nb]=KDE skannetjeneste +Name[nds]=Bildinleesdeenst för KDE +Name[ne]=केडीई स्क्यान सेवा +Name[nl]=KDE Scannerdiensten +Name[nn]=KDE Skanningsteneste +Name[pa]=KDE ਸਕੈਨ ਸਰਵਿਸ +Name[pl]=Usługa skanowania KDE +Name[pt]=Serviço de Digitalização do KDE +Name[pt_BR]=Serviço de digitalização do KDE +Name[ro]=Serviciu de scanare KDE +Name[ru]=Служба сканирования KDE +Name[se]=KDE skánnenbálválus +Name[si]=KDE ස්කෑන් සේවාව +Name[sk]=Skenovacia služba pre KDE +Name[sl]=Storitev optičnega branja za KDE +Name[sr]=КДЕ‑ов сервис за скенирање +Name[sr@ijekavian]=КДЕ‑ов сервис за скенирање +Name[sr@ijekavianlatin]=KDE‑ov servis za skeniranje +Name[sr@latin]=KDE‑ov servis za skeniranje +Name[sv]=KDE:s bildläsartjänst +Name[ta]=கேடிஇ வருடு சேவை +Name[tg]=Сканеронӣ дар KDE +Name[th]=บริการสแกนภาพ-K +Name[tr]=KDE Tarayıcı Servisi +Name[ug]=KDE شويلىلاش مۇلازىمىتى +Name[uk]=Служба сканування KDE +Name[uz]=KDE skan qilish xizmati +Name[uz@cyrillic]=KDE скан қилиш хизмати +Name[vi]=Dịch vụ quét của KDE +Name[wa]=Siervice di scanaedje di KDE +Name[xh]=Inkonzo yemita yovavanyo ye KDE +Name[x-test]=xxKDE Scan Servicexx +Name[zh_CN]=KDE 扫描服务 +Name[zh_HK]=KDE 掃描服務 +Name[zh_TW]=KDE 掃描服務 +X-KDE-Library=ksaneplugin +InitialPreference=3 +X-KDE-ServiceTypes=KScan/KScanDialog diff --git a/ksaneplugin/sanedialog.cpp b/ksaneplugin/sanedialog.cpp new file mode 100644 index 00000000..31064775 --- /dev/null +++ b/ksaneplugin/sanedialog.cpp @@ -0,0 +1,114 @@ +/* ============================================================ + * + * Date : 2008-04-17 + * Description : Sane plugin interface for KDE + * + * Copyright (C) 2008 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#include "sanedialog.h" + +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY(SaneDialogFactory, registerPlugin();) +K_EXPORT_PLUGIN(SaneDialogFactory("ksaneplugin")) + + +/////////////////////////////////////////////////////////////////// + + +SaneDialog::SaneDialog(QWidget *parent, const QVariantList &) + : KScanDialog(Plain, Close, parent) +{ + ksanew = new KSaneIface::KSaneWidget(this); + addPage(ksanew, QString()); + + connect(ksanew, SIGNAL(imageReady(QByteArray &, int, int, int, int)), + this, SLOT(imageReady(QByteArray &, int, int, int, int))); + + openDev = QString(); +} + + +bool SaneDialog::setup() +{ + if(!ksanew) { + // new failed + return false; + } + if (!openDev.isEmpty()) { + return true; + } + // need to select a scanner + openDev = ksanew->selectDevice(0); + if (openDev.isEmpty()) { + // either no scanner was found or then cancel was pressed. + return false; + } + if (ksanew->openDevice(openDev) == false) { + // could not open the scanner + KMessageBox::sorry(0, i18n("Opening the selected scanner failed.")); + openDev = QString(); + return false; + } + + // restore scan dialog size and all options for the selected device if available + KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); + restoreDialogSize(KConfigGroup(configPtr, "ScanDialog")); + QString groupName = openDev; + if (configPtr->hasGroup(groupName)) { + KConfigGroup group(configPtr, groupName); + QStringList keys = group.keyList(); + for (int i = 0; i < keys.count(); i++) + ksanew->setOptVal(keys[i], group.readEntry(keys[i])); + } + + return true; +} + +SaneDialog::~SaneDialog() +{ + if (ksanew && !openDev.isEmpty()) { + // save scan dialog size and all options for the selected device if available + KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); + KConfigGroup group(configPtr, "ScanDialog"); + saveDialogSize(group, KConfigGroup::Persistent); + group = configPtr->group(openDev); + QMap opts; + ksanew->getOptVals(opts); + QMap::const_iterator i = opts.constBegin(); + for (; i != opts.constEnd(); ++i) + group.writeEntry(i.key(), i.value(), KConfigGroup::Persistent); + } +} + +void SaneDialog::imageReady(QByteArray &data, int w, int h, int bpl, int f) +{ + /* copy the image data into img */ + QImage img = ksanew->toQImage(data, w, h, bpl, (KSaneIface::KSaneWidget::ImageFormat)f); + emit finalImage(img, nextId()); +} + + +#include "sanedialog.moc" diff --git a/ksaneplugin/sanedialog.h b/ksaneplugin/sanedialog.h new file mode 100644 index 00000000..4b11a6a5 --- /dev/null +++ b/ksaneplugin/sanedialog.h @@ -0,0 +1,52 @@ +/* ============================================================ + * + * Date : 2008-04-17 + * Description : Sane plugin interface for KDE + * + * Copyright (C) 2008 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef SANEDIALOG_H +#define SANEDIALOG_H + +#include +#include + + +class SaneDialog : public KScanDialog +{ + Q_OBJECT + + public: + explicit SaneDialog( QWidget *parent = 0, const QVariantList &args = QVariantList() ); + ~SaneDialog(); + + virtual bool setup(); + + protected slots: + void imageReady(QByteArray &, int, int, int, int); + + private: + KSaneIface::KSaneWidget *ksanew; + QString openDev; +}; + + +#endif // SCAN_H diff --git a/libksane/.directory b/libksane/.directory new file mode 100644 index 00000000..ecc54e4a --- /dev/null +++ b/libksane/.directory @@ -0,0 +1,3 @@ +[Dolphin] +Timestamp=2015,1,1,1,18,6 +Version=3 diff --git a/libksane/.gitignore b/libksane/.gitignore new file mode 100644 index 00000000..41554037 --- /dev/null +++ b/libksane/.gitignore @@ -0,0 +1,2 @@ +*.kate-swp +tests/databases/*/*.db diff --git a/libksane/AUTHORS b/libksane/AUTHORS new file mode 100644 index 00000000..3a64db60 --- /dev/null +++ b/libksane/AUTHORS @@ -0,0 +1,8 @@ +AUTHORS AND MAINTAINERS: + +Kare Sars +Caulier Gilles + +CONTRIBUTORS: + +Angelo Naselli diff --git a/libksane/CMakeLists.txt b/libksane/CMakeLists.txt new file mode 100644 index 00000000..ec4916b7 --- /dev/null +++ b/libksane/CMakeLists.txt @@ -0,0 +1,83 @@ +PROJECT(libksane) + +MESSAGE(STATUS "----------------------------------------------------------------------------------") +MESSAGE(STATUS "Starting CMake configuration for: libksane") + +# building separately or as part of kdegraphics ? +IF(NOT KDE4_FOUND) + FIND_PACKAGE(KDE4 REQUIRED) +ENDIF(NOT KDE4_FOUND) + +# Check if sane API is available. +IF (NOT WIN32) + FIND_PACKAGE(Sane) + macro_log_feature(SANE_FOUND "SANE development toolkit" "Scanner Access Now Easy (SANE) development package" "http://www.sane-project.org" TRUE "" "Needed by libksane") +ENDIF (NOT WIN32) + +ADD_DEFINITIONS (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +INCLUDE_DIRECTORIES (${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${KDE4_INCLUDES} + ${CMAKE_CURRENT_BINARY_DIR}/libksane) + +# ======================================================= +# Information to update before to release this library. + +# Library version history: +# API ABI +# 0.1.0 => 0.1.0 +# 0.1.1 => 0.1.1 +# 0.2.0 => 0.2.0 + +# Library API version +SET(KSANE_LIB_MAJOR_VERSION "0") +SET(KSANE_LIB_MINOR_VERSION "3") +SET(KSANE_LIB_PATCH_VERSION "0") + +# Suffix to add at end of version string. Usual values are: +# "-git" : alpha code unstable from git. Do not use in production +# "-beta1" : beta1 release. +# "-beta2" : beta2 release. +# "-beta3" : beta3 release. +# "-rc" : release candidate. +# "" : final relase. Can be used in production. +SET(KSANE_LIB_SUFFIX_VERSION "") + +# Library ABI version used by linker. +# For details : http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info +SET(KSANE_LIB_SO_CUR_VERSION "0") +SET(KSANE_LIB_SO_REV_VERSION "2") +SET(KSANE_LIB_SO_AGE_VERSION "0") + +# ======================================================= +# Set env. variables accordinly. + +SET(KSANE_LIB_VERSION_STRING "${KSANE_LIB_MAJOR_VERSION}.${KSANE_LIB_MINOR_VERSION}.${KSANE_LIB_PATCH_VERSION}${KSANE_LIB_SUFFIX_VERSION}") +SET(KSANE_LIB_VERSION_ID "0x0${KSANE_LIB_MAJOR_VERSION}0${KSANE_LIB_MINOR_VERSION}0${KSANE_LIB_PATCH_VERSION}") + +SET(KSANE_LIB_SO_VERSION_STRING "${KSANE_LIB_SO_CUR_VERSION}.${KSANE_LIB_SO_REV_VERSION}.${KSANE_LIB_SO_AGE_VERSION}") + +# ======================================================= + +ADD_DEFINITIONS(-DKDE_DEFAULT_DEBUG_AREA=51004) + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libksane/version.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libksane/version.h) + +# ======================================================= + +# To prevent warnings from M$ compiler +IF(WIN32 AND MSVC) + ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) + ADD_DEFINITIONS(-D_ATL_SECURE_NO_WARNINGS) + ADD_DEFINITIONS(-D_AFX_SECURE_NO_WARNINGS) +ENDIF(WIN32 AND MSVC) + +# ======================================================= + +IF (SANE_FOUND) + ADD_SUBDIRECTORY(libksane) +ELSE (SANE_FOUND) + ADD_SUBDIRECTORY(ksanetwain) +ENDIF (SANE_FOUND) + +macro_display_feature_log() diff --git a/libksane/COPYING b/libksane/COPYING new file mode 100644 index 00000000..c13faf0d --- /dev/null +++ b/libksane/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libksane/COPYING-CMAKE-SCRIPTS b/libksane/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..4b417765 --- /dev/null +++ b/libksane/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libksane/COPYING.LIB b/libksane/COPYING.LIB new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/libksane/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/libksane/COPYING.twain b/libksane/COPYING.twain new file mode 100644 index 00000000..57727d46 --- /dev/null +++ b/libksane/COPYING.twain @@ -0,0 +1,33 @@ +The file twain.h may be copied under the TWAIN License as specified at +http://www.twain.org/license.shtm + +The TWAIN License + +The TWAIN Working Group grants customer ("Customer") the worldwide, +royalty-free, non-exclusive license to reproduce and distribute the +software and documentation of the TWAIN toolkit ("TWAIN Toolkit"). The +TWAIN Toolkit was designed to be used by third parties to assist them +in becoming compliant with the TWAIN standard, but it has not been +developed to the standards of a commercial product. Consequently, the +TWAIN toolkit is provided AS IS without any warranty. THE TWAIN +Working Group disclaims all warranties in the TWAIN toolkit whether +implied, express or statutory, including, without limitation, the +implied warranties of merchantability, noninfringement of third party +rights and fitness for a particular purpose. The TWAIN Working Group +disclaims all liability for damages, whether direct, indirect, +special, incidental, or consequential, arising from the reproduction, +distribution, modification, or other use of the TWAIN Toolkit. + +As a condition of this license, Customer agrees to include in software +programs based in whole or in part on the TWAIN Toolkit the following +providions in (i) the header or similar file in such software and (ii) +prominently in its documentation and to require its sublicensees to +include these provisions in similar locations: The TWAIN Toolkit is +distributed as is. The developer and distributors of the TWAIN Toolkit +expressly disclaim all implied, express or statutory warranties +including, without limitation, the implied warranties of +merchantability, noninfringement of third party rights and fitness for +a particular purpose. Neither the developers nor the distributors will +be liable for damages, whether direct, indirect, special, incidental, +or consequential, as a result of the reproduction, modification, +distribution or other use of the TWAIN Toolkit. diff --git a/libksane/ChangeLog b/libksane/ChangeLog new file mode 100644 index 00000000..bb38e643 --- /dev/null +++ b/libksane/ChangeLog @@ -0,0 +1,12 @@ +0.1.2 + +- Add support for button parameters +- Move the progress bar so that it is more visible during scan + +0.1.1 + +- Add toQImage() for a nicer API + +0.1.0 + +- Initial release \ No newline at end of file diff --git a/libksane/NEWS b/libksane/NEWS new file mode 100644 index 00000000..fec62ec8 --- /dev/null +++ b/libksane/NEWS @@ -0,0 +1,5 @@ +0.1.0 +------------------------------------------------------------------------ +First implementation + +For details and info about previous versions, see ChangeLog. diff --git a/libksane/README b/libksane/README new file mode 100644 index 00000000..6ba33d06 --- /dev/null +++ b/libksane/README @@ -0,0 +1,72 @@ +SANE Library interface for KDE + +This library is a part of Kipi-Plugins project (http://www.digikam.org) + +-- AUTHORS ------------------------------------------------------------ + +See AUTHORS file for details. + +-- ABOUT -------------------------------------------------------------- + +Libksane is a KDE interface for SANE library to control flat scanners. + +This library is used by kipi-plugins, digiKam and others kipi host programs. + +The library documentation is available on header files. + +-- DEPENDENCIES ------------------------------------------------------- + +CMake >= 2.4.x http://www.cmake.org +libqt >= 4.2.x http://www.qtsoftware.com +libkde >= 4.0.x http://www.kde.org +libsane >= 1.0.18 http://www.sane-project.org + +-- INSTALL ------------------------------------------------------------ + +In order to compile, especially when QT3/Qt4 are installed at the same time, +just use something like that: + +# export VERBOSE=1 +# export QTDIR=/usr/lib/qt4/ +# export PATH=$QTDIR/bin:$PATH +# cmake . +# make + +Usual CMake options: + +-DCMAKE_INSTALL_PREFIX : decide where the program will be install on your computer. +-DCMAKE_BUILD_TYPE : decide which type of build you want. You can chose between "debugfull", "debug", "profile", "relwithdebinfo" and "release". The default is "relwithdebinfo" (-O2 -g). + +Compared to old KDE3 autoconf options: + +"cmake . -DCMAKE_BUILD_TYPE=debugfull" is equivalent to "./configure --enable-debug=full" +"cmake . -DCMAKE_INSTALL_PREFIX=/usr" is equivalent to "./configure --prefix=/usr" + +More details can be found ata this url: http://techbase.kde.org/Development/Tutorials/CMake#Environment_Variables + +Note: To know KDE install path on your computer, use 'kde-config --prefix' command line like this (with full debug object enabled): + +"cmake . -DCMAKE_BUILD_TYPE=debugfull -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix`" + +-- CONTACT ------------------------------------------------------------ + +If you have questions, comments, suggestions to make do email at: + +kde-imaging@kde.org + +IRC channel from freenode.net server: + +#kde-imaging + +-- BUGS --------------------------------------------------------------- + +IMPORTANT : the bugreports and wishlist are hosted by the KDE bugs report +system who can be contacted by the standard Kde help menu of plugins dialog. +A mail will be automatically sent to the Kipi mailing list. +There is no need to contact directly the Kipi mailing list for a bug report +or a devel wish. + +The current Kipi bugs and devel wish reported to the Kde bugs report can be see +at this url : + +http://bugs.kde.org/buglist.cgi?product=kipiplugins&component=libksane&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED diff --git a/libksane/TODO b/libksane/TODO new file mode 100644 index 00000000..82f5ee7f --- /dev/null +++ b/libksane/TODO @@ -0,0 +1,49 @@ +TODO list of new features: + +* Cleanup the code for closing the device +* Progressive final scan: scan can provide huge image especially in 16 bits color depth. +Send image data to host application by block, not the whole image at once. + + + +# KSaneCore (most signals/slots from KSaneWidget) +QList options() const // handles to sane options +KSaneBasicOptions* createBasicOptions(QWidget *parent=0) const // A widget with current "basic options" +KSaneSpecialOptions* createSpecialOptions(QWidget *parent=0) const // A widget with the rest of the options +void signalPreviewUpdated(QImage *img); + +KSaneCore never displays popups and always emits userMessage like signals for user information + + +# KSaneOption +virtual QWidget* createWidget(QWidget* parent=0) const; // Create a KSaneOptionWidget and connect it to the option +QString saneName() const; // Technical name of the sane option +QString title() const; // Translated option title +QString description() const; // Translated option description + +Cleanup public API + +# KSaneOptionWidget +Remove label and custom label size code + +# KSaneBasicOptions(QWidget *parent=0) // Use private header for basic/Special selection +bool loadOptions(const QList &options) + +# KSaneSpecialOptions(QWidget *parent=0) // Use private header for basic/Special selection +bool loadOptions(const QList &options) + +# KSanePreview +Figure out how to minimize copying the image data to all possible preview widgets +void "connectToCore"(KSaneCore*) // connect to previewUpdated(..), scanProgress(), ... + +# KSaneWidget +Use KSaneCore + KSaneBasicOptions + KSaneSpecialOptions + KSanePreview to create a GUI like the current +Forward userMessage signals if connected or popup a dialog + + +#General cleanup: +-> enum xxx { }; for easier signal/slot handling +float -> qreal + +# Pure Qt library option? + diff --git a/libksane/cmake/templates/KSaneConfig.cmake.in b/libksane/cmake/templates/KSaneConfig.cmake.in new file mode 100644 index 00000000..292b4d07 --- /dev/null +++ b/libksane/cmake/templates/KSaneConfig.cmake.in @@ -0,0 +1,10 @@ +GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) + +find_library(KSANE_LIBRARY NAMES ksane HINTS ${_IMPORT_PREFIX}/lib NO_DEFAULT_PATH) +find_path(KSANE_INCLUDE_DIR NAMES libksane/ksane.h HINTS ${_IMPORT_PREFIX}/include NO_DEFAULT_PATH) +SET(KSANE_LIBRARY "${KSANE_LIBRARY}" CACHE FILEPATH "KSane image scanning library") +SET(KSANE_INCLUDE_DIR "${KSANE_INCLUDE_DIR}" CACHE PATH "Include path for KSane library") +SET(KSANE_FOUND TRUE) diff --git a/libksane/cmake/templates/libksane.lsm.cmake.in b/libksane/cmake/templates/libksane.lsm.cmake.in new file mode 100644 index 00000000..2c570289 --- /dev/null +++ b/libksane/cmake/templates/libksane.lsm.cmake.in @@ -0,0 +1,15 @@ +Begin4 +Title: libksane +Version: ${KSANE_LIB_VERSION_STRING} +Entered-date: 2007-09-13 +Description: libksane is a C++ library for SANE interface to control flat scanners. +Keywords: kde image sane scanner digiKam kipi-plugins +Author: caulier dot gilles at gmail dot com (Gilles Caulier) + kare dot sars at iki dot fi (Kare Sars) +Maintained-by: +Primary-site: http://www.digikam.org +Alternate-site: http://www.digikam.org +Original-site: +Platforms: +Copying-policy: LGPL +End diff --git a/libksane/cmake/templates/libksane.pc.cmake.in b/libksane/cmake/templates/libksane.pc.cmake.in new file mode 100644 index 00000000..8e2dbaaa --- /dev/null +++ b/libksane/cmake/templates/libksane.pc.cmake.in @@ -0,0 +1,12 @@ +prefix=${CMAKE_INSTALL_PREFIX} +exec_prefix=${BIN_INSTALL_DIR} +libdir=${LIB_INSTALL_DIR} +includedir=${INCLUDE_INSTALL_DIR} + +Name: libksane +Description: libksane is a C++ library for SANE interface to control flat scanners. +URL: http://www.digikam.org +Requires: +Version: ${KSANE_LIB_VERSION_STRING} +Libs: -L${LIB_INSTALL_DIR} -lksane +Cflags: -I${INCLUDE_INSTALL_DIR} diff --git a/libksane/ksanetwain/CMakeLists.txt b/libksane/ksanetwain/CMakeLists.txt new file mode 100644 index 00000000..d179c620 --- /dev/null +++ b/libksane/ksanetwain/CMakeLists.txt @@ -0,0 +1,35 @@ +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../libksane/version.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/version.h) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libksane + ${CMAKE_CURRENT_BINARY_DIR}) + +IF( WIN32 ) + ADD_DEFINITIONS( -DMAKE_KSANE_LIB ) +ENDIF() + +set(ktwain_src + twainiface.cpp + ktwain_widget.cpp +) + +KDE4_ADD_LIBRARY(ksane SHARED ${ktwain_src}) + +TARGET_LINK_LIBRARIES(ksane ${KDE4_KDEUI_LIBS}) + +SET_TARGET_PROPERTIES(ksane PROPERTIES + VERSION ${KSANE_LIB_SO_VERSION_STRING} + SOVERSION ${KSANE_LIB_SO_CUR_VERSION} + LINK_FLAGS -Wl,-subsystem,console +) + +install(TARGETS ksane ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../libksane/ksane.h + ${CMAKE_CURRENT_SOURCE_DIR}/../libksane/libksane_export.h + ${CMAKE_CURRENT_BINARY_DIR}/version.h + DESTINATION ${INCLUDE_INSTALL_DIR}/libksane COMPONENT Devel) + +configure_file(../cmake/templates/KSaneConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/KSaneConfig.cmake @ONLY) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KSaneConfig.cmake + DESTINATION ${LIB_INSTALL_DIR}/cmake/KSane) diff --git a/libksane/ksanetwain/ktwain_widget.cpp b/libksane/ksanetwain/ktwain_widget.cpp new file mode 100644 index 00000000..a77114ca --- /dev/null +++ b/libksane/ksanetwain/ktwain_widget.cpp @@ -0,0 +1,149 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-05-11 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#include "../libksane/ksane.h" +#include "../libksane/ksane.moc" + +// Qt includes +#include +#include +#include +#include + +// KDE includes +#include +#include + +// Local includes +#include "twainiface.h" + +namespace KSaneIface +{ + + +KSaneWidget::KSaneWidget(QWidget* parent) + : QWidget(parent), d(new KSaneWidgetPrivate) +{ + KPushButton *openDialog = new KPushButton; + openDialog->setText(i18n("Open scan dialog")); + QHBoxLayout *lay = new QHBoxLayout; + lay->addWidget(openDialog); + setLayout(lay); + + connect(openDialog, SIGNAL(clicked()), d, SLOT(ReOpenDialog())); + + // Forward signals from the private class + //connect(d, SIGNAL(scanProgress(int)), this, SIGNAL(scanProgress(int))); + connect(d, SIGNAL(ImageReady(QByteArray&,int,int,int,int)), + this, SIGNAL(imageReady(QByteArray&,int,int,int,int))); + //connect(d, SIGNAL(scanDone(int,QString)), this, SIGNAL(scanDone(int,QString))); + + + +} + +KSaneWidget::~KSaneWidget() +{ + delete d; +} + +QString KSaneWidget::selectDevice(QWidget* parent) +{ + //qDebug() << "KSaneWidget::selectDevice"; + return d->SelectSource(); +} + +bool KSaneWidget::openDevice(const QString &device_name) +{ + //qDebug() << "KSaneWidget::openDevice" << device_name; + if (!d->OpenSource(device_name)) return false; + QTimer::singleShot(0, d, SLOT(OpenDialog())); + + return true; +} + + +bool KSaneWidget::closeDevice() +{ + //qDebug() << "KSaneWidget::closeDevice"; + d->CloseDSM(); + return true; +} + +QImage KSaneWidget::toQImage(const QByteArray &data, + int width, + int height, + int bytes_per_line, + ImageFormat format) +{ + QImage img = QImage::fromData(data, "BMP"); + return img; +} + +QImage KSaneWidget::toQImageSilent(const QByteArray &data, + int width, + int height, + int bytes_per_line, + ImageFormat format) +{ + return KSaneWidget::toQImage(data, + width, + height, + bytes_per_line, + format); +} + + +void KSaneWidget::scanFinal() +{ +} + +void KSaneWidget::scanCancel() +{ + emit scanProgress(0); +} + +// stubbed functions that will not get an implementation any time soon. +QString KSaneWidget::vendor() const {return QString();} +QString KSaneWidget::make() const {return QString();} +QString KSaneWidget::model() const {return QString();} +void KSaneWidget::getOptVals(QMap &opts) {opts.clear();} +bool KSaneWidget::getOptVal(const QString &optname, QString &value){return false;} +int KSaneWidget::setOptVals(const QMap &opts) {return 0;} +bool KSaneWidget::setOptVal(const QString &option, const QString &value) {return false;} +void KSaneWidget::setScanButtonText(const QString &scanLabel) {} +void KSaneWidget::setPreviewButtonText(const QString &previewLabel) {} +void KSaneWidget::enableAutoSelect(bool enable) {} +float KSaneWidget::currentDPI() {return 0.0;} +void KSaneWidget::setPreviewResolution(float dpi){Q_UNUSED(dpi);} +void KSaneWidget::setSelection(QPointF lefttop, QPointF rightbottom){Q_UNUSED(lefttop); Q_UNUSED(rightbottom);} +void KSaneWidget::setOptionsCollapsed(bool){} +void KSaneWidget::setScanButtonHidden(bool){} +void KSaneWidget::initGetDeviceList() const {} + + +} // NameSpace KSaneIface diff --git a/libksane/ksanetwain/twain.h b/libksane/ksanetwain/twain.h new file mode 100644 index 00000000..47b5f158 --- /dev/null +++ b/libksane/ksanetwain/twain.h @@ -0,0 +1,1977 @@ +// krazy:skip +/* ======================================================================== *\ + + Copyright (C) 1991, 1992 TWAIN Working Group: Aldus, Caere, Eastman-Kodak, + Hewlett-Packard and Logitech Corporations. All rights reserved. + + Copyright (C) 1997 TWAIN Working Group: Bell+Howell, Canon, DocuMagix, + Fujitsu, Genoa Technology, Hewlett-Packard, Kofax Imaging Products, and + Ricoh Corporation. All rights reserved. + + Copyright 1998 TWAIN Working Group: Adobe Systems Incorporated, + Canon Information Systems, Eastman Kodak Company, + Fujitsu Computer Products of America, Genoa Technology, + Hewlett-Packard Company, Intel Corporation, Kofax Image Products, + JFL Peripheral Solutions Inc., Ricoh Corporation, and Xerox Corporation. + All rights reserved. + + Copyright 2000 TWAIN Working Group: Adobe Systems Incorporated, + Canon Information Systems, Digimarc Corporation, Eastman Kodak Company, + Fujitsu Computer Products of America, Hewlett-Packard Company, + JFL Peripheral Solutions Inc., Ricoh Corporation, and Xerox Corporation. + All rights reserved. + + + TWAIN.h - This is the definitive include file for applications and + data sources written to the TWAIN specification. + It defines constants, data structures, messages etc. + for the public interface to TWAIN. + + Revision History: + version 1.0, March 6, 1992. TWAIN 1.0. + version 1.1, January 1993. Tech Notes 1.1 + version 1.5, June 1993. Specification Update 1.5 + Change DC to TW + Change filename from DC.H to TWAIN.H + version 1.5, July 1993. Remove spaces from country identifiers + + version 1.7, July 1997 Added Capabilities and data structure for + document imaging and digital cameras. + KHL. + version 1.7, July 1997 Inserted Borland compatibile structure packing + directives provided by Mentor. JMH + version 1.7, Aug 1997 Expanded file tabs to spaces. + NOTE: future authors should be sure to have + their editors set to automatically expand tabs + to spaces (original tab setting was 4 spaces). + version 1.7, Sept 1997 Added job control values + Added return codes + version 1.7, Sept 1997 changed definition of pRGBRESPONSE to + pTW_RGBRESPONSE + version 1.7 Aug 1998 Added missing TWEI_BARCODEROTATION values + TWBCOR_ types JMH + version 1.8 August 1998 Added new types and definitions required + for 1.8 Specification JMH + version 1.8 January 1999 Changed search mode from SRCH_ to TWBD_ as + in 1.8 Specification, added TWBT_MAXICODE JMH + version 1.8 January 1999 Removed undocumented duplicate AUTO JMH + version 1.8 March 1999 Removed undocumented 1.8 caps: + CAP_FILESYSTEM + CAP_PAPERBINDING + CAP_PASSTHRU + CAP_POWERDOWNTIME + ICAP_AUTODISCARDBLANKPAGES + * CAP_PAGEMULTIPLEACQUIRE - is CAP_REACQUIREALLOWED, + requires spec change. JMH + Added Mac structure packing modifications JMH + version 1.9 March 2000 Added new types and definations required + for 1.9 Specification MLM + version 1.9 March 2000 Added ICAP_JPEGQUALITY, TWJQ_ values, + updated TWON_PROTOCOLMINOR for Release v1.9 MN +\* ======================================================================== */ + +#ifndef TWAIN +#define TWAIN + +/* SDH - 02/08/95 - TWUNK */ +/* Force 32-bit twain to use same packing of twain structures as existing */ +/* 16-bit twain. This allows 16/32-bit thunking. */ +#ifdef WIN32 + + #include + + #ifdef __MINGW32__ + #pragma pack (push, 2) + #elif __BORLANDC__ //(Mentor June 13, 1996) if using a Borland compiler + #pragma option -a2 //(Mentor June 13, 1996) switch to word alignment + #else //(Mentor June 13, 1996) if we're using some other compiler + #pragma pack (push, before_twain) + #pragma pack (2) + #endif //(Mentor June 13, 1996) +#else /* WIN32 */ +#endif /* WIN32 */ + +/**************************************************************************** + * TWAIN Version * + ****************************************************************************/ +#define TWON_PROTOCOLMINOR 9 /* Changed for Version 1.9 */ +#define TWON_PROTOCOLMAJOR 1 + +/**************************************************************************** + * Platform Dependent Definitions and Typedefs * + ****************************************************************************/ + +/* Define one of the following, depending on the platform */ +/* #define _MAC_ */ +/* #define _UNIX_ */ +#define _MSWIN_ + +#ifdef _MSWIN_ + typedef HANDLE TW_HANDLE; + typedef LPVOID TW_MEMREF; + + /* SDH - 05/05/95 - TWUNK */ + /* For common code between 16 and 32 bits. */ + #ifdef WIN32 + #define TW_HUGE + #else /* WIN32 */ + #define TW_HUGE huge + #endif /* WIN32 */ + typedef BYTE TW_HUGE * HPBYTE; + typedef void TW_HUGE * HPVOID; +#endif /* _MSWIN_ */ + +#ifdef _MAC_ + /* + * NOTE: + * Corrected to allow building of TWAIN MacOS PowerPC Applications + * and MacOS PowerPC TWAIN sources. + * + * The modification allows a PowerPC Application to use a + * TWAIN 68k Source and a PowerPC Source to be used by a 68k Application. + * + * The modification concerns the data alignment of the C-Structures used by + * TWAIN during the communication between the Application and Source. + * + * The Data Alignment must be 68k code and not PowerPC. + * - Paul Plaquette, LOGi 27, FRANCE-Montpellier + */ + #if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k + #elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) + #elif PRAGMA_STRUCT_PACK + #pragma pack(2) + #endif + + #define PASCAL pascal + #define FAR + typedef Handle TW_HANDLE; + typedef char *TW_MEMREF; +#endif /* _MAC_ */ + +#ifdef _UNIX_ + #define PASCAL pascal + typedef unsigned char *TW_HANDLE; + typedef unsigned char *TW_MEMREF; +#endif /* _UNIX_ */ + +/**************************************************************************** + * Type Definitions * + ****************************************************************************/ + +/* String types. These include room for the strings and a NULL char, * + * or, on the Mac, a length byte followed by the string. * + * TW_STR255 must hold less than 256 chars so length fits in first byte. */ +typedef char TW_STR32[34], FAR *pTW_STR32; +typedef char TW_STR64[66], FAR *pTW_STR64; +typedef char TW_STR128[130], FAR *pTW_STR128; +typedef char TW_STR255[256], FAR *pTW_STR255; +typedef char TW_STR1024[1026], FAR *pTW_STR1024; /* added 1.9 */ +typedef wchar_t TW_UNI512[512], FAR *pTW_UNI512; /* added 1.9 */ + +/* Numeric types. */ +typedef char TW_INT8, FAR *pTW_INT8; +typedef short TW_INT16, FAR *pTW_INT16; +typedef long TW_INT32, FAR *pTW_INT32; +typedef unsigned char TW_UINT8, FAR *pTW_UINT8; +typedef unsigned short TW_UINT16, FAR *pTW_UINT16; +typedef unsigned long TW_UINT32, FAR *pTW_UINT32; +typedef unsigned short TW_BOOL, FAR *pTW_BOOL; + +/* Fixed point structure type. */ +typedef struct { + TW_INT16 Whole; /* maintains the sign */ + TW_UINT16 Frac; +} TW_FIX32, FAR *pTW_FIX32; + +/**************************************************************************** + * Structure Definitions * + ****************************************************************************/ + +/* No DAT needed. */ +typedef struct { + TW_FIX32 X; + TW_FIX32 Y; + TW_FIX32 Z; +} TW_CIEPOINT, FAR * pTW_CIEPOINT; + +/* No DAT needed. */ +typedef struct { + TW_FIX32 StartIn; + TW_FIX32 BreakIn; + TW_FIX32 EndIn; + TW_FIX32 StartOut; + TW_FIX32 BreakOut; + TW_FIX32 EndOut; + TW_FIX32 Gamma; + TW_FIX32 SampleCount; /* if =0 use the gamma */ +} TW_DECODEFUNCTION, FAR * pTW_DECODEFUNCTION; + +/* No DAT needed. */ +typedef struct { + TW_UINT8 Index; /* Value used to index into the color table. */ + TW_UINT8 Channel1; /* First tri-stimulus value (e.g Red) */ + TW_UINT8 Channel2; /* Second tri-stimulus value (e.g Green) */ + TW_UINT8 Channel3; /* Third tri-stimulus value (e.g Blue) */ +} TW_ELEMENT8, FAR * pTW_ELEMENT8; + +/* No DAT. Defines a frame rectangle in ICAP_UNITS coordinates. */ +typedef struct { + TW_FIX32 Left; + TW_FIX32 Top; + TW_FIX32 Right; + TW_FIX32 Bottom; +} TW_FRAME, FAR * pTW_FRAME; + +/* No DAT needed. Used to manage memory buffers. */ +typedef struct { + TW_UINT32 Flags; /* Any combination of the TWMF_ constants. */ + TW_UINT32 Length; /* Number of bytes stored in buffer TheMem. */ + TW_MEMREF TheMem; /* Pointer or handle to the allocated memory buffer. */ +} TW_MEMORY, FAR * pTW_MEMORY; + +/* No DAT needed. */ +typedef struct { + TW_DECODEFUNCTION Decode[3]; + TW_FIX32 Mix[3][3]; +} TW_TRANSFORMSTAGE, FAR * pTW_TRANSFORMSTAGE; + +/* No DAT needed. Describes version of software currently running. */ +typedef struct { + TW_UINT16 MajorNum; /* Major revision number of the software. */ + TW_UINT16 MinorNum; /* Incremental revision number of the software. */ + TW_UINT16 Language; /* e.g. TWLG_SWISSFRENCH */ + TW_UINT16 Country; /* e.g. TWCY_SWITZERLAND */ + TW_STR32 Info; /* e.g. "1.0b3 Beta release" */ +} TW_VERSION, FAR * pTW_VERSION; + +/* TWON_ARRAY. Container for array of values (a simplified TW_ENUMERATION) */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 NumItems; /* How many items in ItemList */ + TW_UINT8 ItemList[1]; /* Array of ItemType values starts here */ +} TW_ARRAY, FAR * pTW_ARRAY; + +/* TWON_ENUMERATION. Container for a collection of values. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 NumItems; /* How many items in ItemList */ + TW_UINT32 CurrentIndex; /* Current value is in ItemList[CurrentIndex] */ + TW_UINT32 DefaultIndex; /* Powerup value is in ItemList[DefaultIndex] */ + TW_UINT8 ItemList[1]; /* Array of ItemType values starts here */ +} TW_ENUMERATION, FAR * pTW_ENUMERATION; + +/* TWON_ONEVALUE. Container for one value. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 Item; +} TW_ONEVALUE, FAR * pTW_ONEVALUE; + +/* TWON_RANGE. Container for a range of values. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 MinValue; /* Starting value in the range. */ + TW_UINT32 MaxValue; /* Final value in the range. */ + TW_UINT32 StepSize; /* Increment from MinValue to MaxValue. */ + TW_UINT32 DefaultValue; /* Power-up value. */ + TW_UINT32 CurrentValue; /* The value that is currently in effect. */ +} TW_RANGE, FAR * pTW_RANGE; + +/* DAT_CAPABILITY. Used by application to get/set capability from/in a data source. */ +typedef struct { + TW_UINT16 Cap; /* id of capability to set or get, e.g. CAP_BRIGHTNESS */ + TW_UINT16 ConType; /* TWON_ONEVALUE, _RANGE, _ENUMERATION or _ARRAY */ + TW_HANDLE hContainer; /* Handle to container of type Dat */ +} TW_CAPABILITY, FAR * pTW_CAPABILITY; + +/* DAT_CIECOLOR. */ +typedef struct { + TW_UINT16 ColorSpace; + TW_INT16 LowEndian; + TW_INT16 DeviceDependent; + TW_INT32 VersionNumber; + TW_TRANSFORMSTAGE StageABC; + TW_TRANSFORMSTAGE StageLMN; + TW_CIEPOINT WhitePoint; + TW_CIEPOINT BlackPoint; + TW_CIEPOINT WhitePaper; + TW_CIEPOINT BlackInk; + TW_FIX32 Samples[1]; +} TW_CIECOLOR, FAR * pTW_CIECOLOR; + +/* DAT_EVENT. For passing events down from the application to the DS. */ +typedef struct { + TW_MEMREF pEvent; /* Windows pMSG or Mac pEvent. */ + TW_UINT16 TWMessage; /* TW msg from data source, e.g. MSG_XFERREADY */ +} TW_EVENT, FAR * pTW_EVENT; + +/* DAT_GRAYRESPONSE */ +typedef struct { + TW_ELEMENT8 Response[1]; +} TW_GRAYRESPONSE, FAR * pTW_GRAYRESPONSE; + +/* DAT_IDENTITY. Identifies the program/library/code resource. */ +typedef struct { + TW_UINT32 Id; /* Unique number. In Windows, application hWnd */ + TW_VERSION Version; /* Identifies the piece of code */ + TW_UINT16 ProtocolMajor; /* Application and DS must set to TWON_PROTOCOLMAJOR */ + TW_UINT16 ProtocolMinor; /* Application and DS must set to TWON_PROTOCOLMINOR */ + TW_UINT32 SupportedGroups; /* Bit field OR combination of DG_ constants */ + TW_STR32 Manufacturer; /* Manufacturer name, e.g. "Hewlett-Packard" */ + TW_STR32 ProductFamily; /* Product family name, e.g. "ScanJet" */ + TW_STR32 ProductName; /* Product name, e.g. "ScanJet Plus" */ +} TW_IDENTITY, FAR * pTW_IDENTITY; + +/* DAT_IMAGEINFO. Application gets detailed image info from DS with this. */ +typedef struct { + TW_FIX32 XResolution; /* Resolution in the horizontal */ + TW_FIX32 YResolution; /* Resolution in the vertical */ + TW_INT32 ImageWidth; /* Columns in the image, -1 if unknown by DS*/ + TW_INT32 ImageLength; /* Rows in the image, -1 if unknown by DS */ + TW_INT16 SamplesPerPixel; /* Number of samples per pixel, 3 for RGB */ + TW_INT16 BitsPerSample[8]; /* Number of bits for each sample */ + TW_INT16 BitsPerPixel; /* Number of bits for each padded pixel */ + TW_BOOL Planar; /* True if Planar, False if chunky */ + TW_INT16 PixelType; /* How to interp data; photo interp (TWPT_) */ + TW_UINT16 Compression; /* How the data is compressed (TWCP_xxxx) */ +} TW_IMAGEINFO, FAR * pTW_IMAGEINFO; + +/* DAT_IMAGELAYOUT. Provides image layout information in current units. */ +typedef struct { + TW_FRAME Frame; /* Frame coords within larger document */ + TW_UINT32 DocumentNumber; + TW_UINT32 PageNumber; /* Reset when you go to next document */ + TW_UINT32 FrameNumber; /* Reset when you go to next page */ +} TW_IMAGELAYOUT, FAR * pTW_IMAGELAYOUT; + +/* DAT_IMAGEMEMXFER. Used to pass image data (e.g. in strips) from DS to application.*/ +typedef struct { + TW_UINT16 Compression; /* How the data is compressed */ + TW_UINT32 BytesPerRow; /* Number of bytes in a row of data */ + TW_UINT32 Columns; /* How many columns */ + TW_UINT32 Rows; /* How many rows */ + TW_UINT32 XOffset; /* How far from the side of the image */ + TW_UINT32 YOffset; /* How far from the top of the image */ + TW_UINT32 BytesWritten; /* How many bytes written in Memory */ + TW_MEMORY Memory; /* Mem struct used to pass actual image data */ +} TW_IMAGEMEMXFER, FAR * pTW_IMAGEMEMXFER; + +/* Changed in 1.1: QuantTable, HuffmanDC, HuffmanAC TW_MEMREF -> TW_MEMORY */ +/* DAT_JPEGCOMPRESSION. Based on JPEG Draft International Std, ver 10918-1. */ +typedef struct { + TW_UINT16 ColorSpace; /* One of the TWPT_xxxx values */ + TW_UINT32 SubSampling; /* Two word "array" for subsampling values */ + TW_UINT16 NumComponents; /* Number of color components in image */ + TW_UINT16 RestartFrequency; /* Frequency of restart marker codes in MDU's */ + TW_UINT16 QuantMap[4]; /* Mapping of components to QuantTables */ + TW_MEMORY QuantTable[4]; /* Quantization tables */ + TW_UINT16 HuffmanMap[4]; /* Mapping of components to Huffman tables */ + TW_MEMORY HuffmanDC[2]; /* DC Huffman tables */ + TW_MEMORY HuffmanAC[2]; /* AC Huffman tables */ +} TW_JPEGCOMPRESSION, FAR * pTW_JPEGCOMPRESSION; + +/* DAT_PALETTE8. Color palette when TWPT_PALETTE pixels xfer'd in mem buf. */ +typedef struct { + TW_UINT16 NumColors; /* Number of colors in the color table. */ + TW_UINT16 PaletteType; /* TWPA_xxxx, specifies type of palette. */ + TW_ELEMENT8 Colors[256]; /* Array of palette values starts here. */ +} TW_PALETTE8, FAR * pTW_PALETTE8; + +/* DAT_PENDINGXFERS. Used with MSG_ENDXFER to indicate additional data. */ +typedef struct { + TW_UINT16 Count; + union { + TW_UINT32 EOJ; + TW_UINT32 Reserved; + }; +} TW_PENDINGXFERS, FAR *pTW_PENDINGXFERS; + +/* DAT_RGBRESPONSE */ +typedef struct { + TW_ELEMENT8 Response[1]; +} TW_RGBRESPONSE, FAR * pTW_RGBRESPONSE; + +/* DAT_SETUPFILEXFER. Sets up DS to application data transfer via a file. */ +typedef struct { + TW_STR255 FileName; + TW_UINT16 Format; /* Any TWFF_ constant */ + TW_INT16 VRefNum; /* Used for Mac only */ +} TW_SETUPFILEXFER, FAR * pTW_SETUPFILEXFER; + +/* DAT_SETUPFILEXFER2. Sets up DS to application data transfer via a file. */ +/* Added 1.9 */ +typedef struct { + TW_MEMREF FileName; /* Pointer to file name text */ + TW_UINT16 FileNameType; /* TWTY_STR1024 or TWTY_UNI512 */ + TW_UINT16 Format; /* Any TWFF_ constant */ + TW_INT16 VRefNum; /* Used for Mac only */ + TW_UINT32 parID; /* Used for Mac only */ +} TW_SETUPFILEXFER2, FAR * pTW_SETUPFILEXFER2; + +/* DAT_SETUPMEMXFER. Sets up DS to application data transfer via a memory buffer. */ +typedef struct { + TW_UINT32 MinBufSize; + TW_UINT32 MaxBufSize; + TW_UINT32 Preferred; +} TW_SETUPMEMXFER, FAR * pTW_SETUPMEMXFER; + +/* DAT_STATUS. Application gets detailed status info from a data source with this. */ +typedef struct { + TW_UINT16 ConditionCode; /* Any TWCC_ constant */ + TW_UINT16 Reserved; /* Future expansion space */ +} TW_STATUS, FAR * pTW_STATUS; + +/* DAT_USERINTERFACE. Coordinates UI between application and data source. */ +typedef struct { + TW_BOOL ShowUI; /* TRUE if DS should bring up its UI */ + TW_BOOL ModalUI; /* For Mac only - true if the DS's UI is modal */ + TW_HANDLE hParent; /* For windows only - Application window handle */ +} TW_USERINTERFACE, FAR * pTW_USERINTERFACE; + +/* SDH - 03/21/95 - TWUNK */ +/* DAT_TWUNKIDENTITY. Provides DS identity and 'other' information necessary */ +/* across thunk link. */ +typedef struct { + TW_IDENTITY identity; /* Identity of data source. */ + TW_STR255 dsPath; /* Full path and file name of data source. */ +} TW_TWUNKIDENTITY, FAR * pTW_TWUNKIDENTITY; + +/* SDH - 03/21/95 - TWUNK */ +/* Provides DS_Entry parameters over thunk link. */ +typedef struct +{ + TW_INT8 destFlag; /* TRUE if dest is not NULL */ + TW_IDENTITY dest; /* Identity of data source (if used) */ + TW_INT32 dataGroup; /* DSM_Entry dataGroup parameter */ + TW_INT16 dataArgType; /* DSM_Entry dataArgType parameter */ + TW_INT16 message; /* DSM_Entry message parameter */ + TW_INT32 pDataSize; /* Size of pData (0 if NULL) */ + // TW_MEMREF pData; /* Based on implementation specifics, a */ + /* pData parameter makes no sense in this */ + /* structure, but data (if provided) will be*/ + /* appended in the data block. */ + } TW_TWUNKDSENTRYPARAMS, FAR * pTW_TWUNKDSENTRYPARAMS; + +/* SDH - 03/21/95 - TWUNK */ +/* Provides DS_Entry results over thunk link. */ +typedef struct +{ + TW_UINT16 returnCode; /* Thunker DsEntry return code. */ + TW_UINT16 conditionCode; /* Thunker DsEntry condition code. */ + TW_INT32 pDataSize; /* Size of pData (0 if NULL) */ + // TW_MEMREF pData; /* Based on implementation specifics, a */ + /* pData parameter makes no sense in this */ + /* structure, but data (if provided) will be*/ + /* appended in the data block. */ +} TW_TWUNKDSENTRYRETURN, FAR * pTW_TWUNKDSENTRYRETURN; + +/* WJD - 950818 */ +/* Added for 1.6 Specification */ +/* TWAIN 1.6 CAP_SUPPORTEDCAPSEXT structure */ +typedef struct +{ + TW_UINT16 Cap; /* Which CAP/ICAP info is relevant to */ + TW_UINT16 Properties; /* Messages this CAP/ICAP supports */ +} TW_CAPEXT, FAR * pTW_CAPEXT; + +/* ----------------------------------------------------------------------- *\ + + Version 1.7: Added Following data structure for Document Imaging + July 1997 Enhancement. + KHL TW_CUSTOMDSDATA -- For Saving and Restoring Source's + state. + TW_INFO -- Each attribute for extended image + information. + TW_EXTIMAGEINFO -- Extended image information structure. + +\* ----------------------------------------------------------------------- */ + +typedef struct { + TW_UINT32 InfoLength; /* Length of Information in bytes. */ + TW_HANDLE hData; /* Place holder for data, DS Allocates */ +}TW_CUSTOMDSDATA, FAR *pTW_CUSTOMDSDATA; + +typedef struct { + TW_UINT16 InfoID; + TW_UINT16 ItemType; + TW_UINT16 NumItems; + TW_UINT16 CondCode; + TW_UINT32 Item; +}TW_INFO, FAR* pTW_INFO; + +typedef struct { + TW_UINT32 NumInfos; + TW_INFO Info[1]; +}TW_EXTIMAGEINFO, FAR* pTW_EXTIMAGEINFO; + +/* Added 1.8 */ + +/* DAT_AUDIOINFO, information about audio data */ +typedef struct { + TW_STR255 Name; /* name of audio data */ + TW_UINT32 Reserved; /* reserved space */ +} TW_AUDIOINFO, FAR * pTW_AUDIOINFO; + +/* DAT_DEVICEEVENT, information about events */ +typedef struct { + TW_UINT32 Event; /* One of the TWDE_xxxx values. */ + TW_STR255 DeviceName; /* The name of the device that generated the event */ + TW_UINT32 BatteryMinutes; /* Battery Minutes Remaining */ + TW_INT16 BatteryPercentage; /* Battery Percentage Remaining */ + TW_INT32 PowerSupply; /* Power Supply */ + TW_FIX32 XResolution; /* Resolution */ + TW_FIX32 YResolution; /* Resolution */ + TW_UINT32 FlashUsed2; /* Flash Used2 */ + TW_UINT32 AutomaticCapture; /* Automatic Capture */ + TW_UINT32 TimeBeforeFirstCapture; /* Automatic Capture */ + TW_UINT32 TimeBetweenCaptures; /* Automatic Capture */ +} TW_DEVICEEVENT, FAR * pTW_DEVICEEVENT; + +/* DAT_FILESYSTEM, information about TWAIN file system */ +typedef struct { + /* DG_CONTROL / DAT_FILESYSTEM / MSG_xxxx fields */ + TW_STR255 InputName; /* The name of the input or source file */ + TW_STR255 OutputName; /* The result of an operation or the name of a destination file */ + TW_MEMREF Context; /* Source specific data used to remember state information */ + /* DG_CONTROL / DAT_FILESYSTEM / MSG_DELETE field */ + int Recursive; /* recursively delete all sub-directories */ + /* DG_CONTROL / DAT_FILESYSTEM / MSG_GETINFO fields */ + TW_INT32 FileType; /* One of the TWFT_xxxx values */ + TW_UINT32 Size; /* Size of current FileType */ + TW_STR32 CreateTimeDate; /* creation date of the file */ + TW_STR32 ModifiedTimeDate; /* last date the file was modified */ + TW_UINT32 FreeSpace; /* bytes of free space on the current device */ + TW_INT32 NewImageSize; /* estimate of the amount of space a new image would take up */ + TW_UINT32 NumberOfFiles; /* number of files, depends on FileType */ + TW_UINT32 NumberOfSnippets; /* number of audio snippets */ + TW_UINT32 DeviceGroupMask; /* used to group cameras (ex: front/rear bitonal, front/rear grayscale...) */ + char Reserved[508]; /**/ +} TW_FILESYSTEM, FAR * pTW_FILESYSTEM; + +/* DAT_PASSTHRU, device dependant data to pass through Data Source */ +typedef struct { + TW_MEMREF pCommand; /* Pointer to Command buffer */ + TW_UINT32 CommandBytes; /* Number of bytes in Command buffer */ + TW_INT32 Direction; /* One of the TWDR_xxxx values. Defines the direction of data flow */ + TW_MEMREF pData; /* Pointer to Data buffer */ + TW_UINT32 DataBytes; /* Number of bytes in Data buffer */ + TW_UINT32 DataBytesXfered; /* Number of bytes successfully transferred */ +} TW_PASSTHRU, FAR * pTW_PASSTHRU; + +/* DAT_SETUPAUDIOFILEXFER, information required to setup an audio file transfer */ +typedef struct { + TW_STR255 FileName; /* full path target file */ + TW_UINT16 Format; /* one of TWAF_xxxx */ + TW_INT16 VRefNum; +} TW_SETUPAUDIOFILEXFER, FAR * pTW_SETUPAUDIOFILEXFER; + +#ifdef _MAC_ + /* + * Restore original Macintosh structure packing + */ + #if PRAGMA_STRUCT_ALIGN + #pragma options align=reset + #elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) + #elif PRAGMA_STRUCT_PACK + #pragma pack() + #endif +#endif /* _MAC_ */ + +/**************************************************************************** + * Generic Constants * + ****************************************************************************/ + +#define TWON_ARRAY 3 /* indicates TW_ARRAY container */ +#define TWON_ENUMERATION 4 /* indicates TW_ENUMERATION container */ +#define TWON_ONEVALUE 5 /* indicates TW_ONEVALUE container */ +#define TWON_RANGE 6 /* indicates TW_RANGE container */ + +#define TWON_ICONID 962 /* res Id of icon used in USERSELECT lbox */ +#define TWON_DSMID 461 /* res Id of the DSM version num resource */ +#define TWON_DSMCODEID 63 /* res Id of the Mac SM Code resource */ + +#define TWON_DONTCARE8 0xff +#define TWON_DONTCARE16 0xffff +#define TWON_DONTCARE32 0xffffffff + +/* Flags used in TW_MEMORY structure. */ +#define TWMF_APPOWNS 0x1 +#define TWMF_DSMOWNS 0x2 +#define TWMF_DSOWNS 0x4 +#define TWMF_POINTER 0x8 +#define TWMF_HANDLE 0x10 + +/* Palette types for TW_PALETTE8 */ +#define TWPA_RGB 0 +#define TWPA_GRAY 1 +#define TWPA_CMY 2 + +/* There are four containers used for capabilities negotiation: + * TWON_ONEVALUE, TWON_RANGE, TWON_ENUMERATION, TWON_ARRAY + * In each container structure ItemType can be TWTY_INT8, TWTY_INT16, etc. + * The kind of data stored in the container can be determined by doing + * DCItemSize[ItemType] where the following is defined in TWAIN glue code: + * DCItemSize[]= { sizeof(TW_INT8), + * sizeof(TW_INT16), + * etc. + * sizeof(TW_UINT32) }; + * + */ + +#define TWTY_INT8 0x0000 /* Means Item is a TW_INT8 */ +#define TWTY_INT16 0x0001 /* Means Item is a TW_INT16 */ +#define TWTY_INT32 0x0002 /* Means Item is a TW_INT32 */ + +#define TWTY_UINT8 0x0003 /* Means Item is a TW_UINT8 */ +#define TWTY_UINT16 0x0004 /* Means Item is a TW_UINT16 */ +#define TWTY_UINT32 0x0005 /* Means Item is a TW_UINT32 */ + +#define TWTY_BOOL 0x0006 /* Means Item is a TW_BOOL */ + +#define TWTY_FIX32 0x0007 /* Means Item is a TW_FIX32 */ + +#define TWTY_FRAME 0x0008 /* Means Item is a TW_FRAME */ + +#define TWTY_STR32 0x0009 /* Means Item is a TW_STR32 */ +#define TWTY_STR64 0x000a /* Means Item is a TW_STR64 */ +#define TWTY_STR128 0x000b /* Means Item is a TW_STR128 */ +#define TWTY_STR255 0x000c /* Means Item is a TW_STR255 */ +#define TWTY_STR1024 0x000d /* Means Item is a TW_STR1024...added 1.9 */ +#define TWTY_UNI512 0x000e /* Means Item is a TW_UNI512...added 1.9 */ + +/**************************************************************************** + * Capability Constants * + ****************************************************************************/ + +/* ICAP_BITORDER values (BO_ means Bit Order) */ +#define TWBO_LSBFIRST 0 +#define TWBO_MSBFIRST 1 + +/* ICAP_COMPRESSION values (CP_ means ComPression ) */ +#define TWCP_NONE 0 +#define TWCP_PACKBITS 1 +#define TWCP_GROUP31D 2 /* Follows CCITT spec (no End Of Line) */ +#define TWCP_GROUP31DEOL 3 /* Follows CCITT spec (has End Of Line) */ +#define TWCP_GROUP32D 4 /* Follows CCITT spec (use cap for K Factor) */ +#define TWCP_GROUP4 5 /* Follows CCITT spec */ +#define TWCP_JPEG 6 /* Use capability for more info */ +#define TWCP_LZW 7 /* Must license from Unisys and IBM to use */ +#define TWCP_JBIG 8 /* For Bitonal images -- Added 1.7 KHL */ +/* Added 1.8 */ +#define TWCP_PNG 9 +#define TWCP_RLE4 10 +#define TWCP_RLE8 11 +#define TWCP_BITFIELDS 12 + + +/* ICAP_IMAGEFILEFORMAT values (FF_means File Format) */ +#define TWFF_TIFF 0 /* Tagged Image File Format */ +#define TWFF_PICT 1 /* Macintosh PICT */ +#define TWFF_BMP 2 /* Windows Bitmap */ +#define TWFF_XBM 3 /* X-Windows Bitmap */ +#define TWFF_JFIF 4 /* JPEG File Interchange Format */ +#define TWFF_FPX 5 /* Flash Pix */ +#define TWFF_TIFFMULTI 6 /* Multi-page tiff file */ +#define TWFF_PNG 7 +#define TWFF_SPIFF 8 +#define TWFF_EXIF 9 + + +/* ICAP_FILTER values (FT_ means Filter Type) */ +#define TWFT_RED 0 +#define TWFT_GREEN 1 +#define TWFT_BLUE 2 +#define TWFT_NONE 3 +#define TWFT_WHITE 4 +#define TWFT_CYAN 5 +#define TWFT_MAGENTA 6 +#define TWFT_YELLOW 7 +#define TWFT_BLACK 8 + +/* ICAP_LIGHTPATH values (LP_ means Light Path) */ +#define TWLP_REFLECTIVE 0 +#define TWLP_TRANSMISSIVE 1 + +/* ICAP_LIGHTSOURCE values (LS_ means Light Source) */ +#define TWLS_RED 0 +#define TWLS_GREEN 1 +#define TWLS_BLUE 2 +#define TWLS_NONE 3 +#define TWLS_WHITE 4 +#define TWLS_UV 5 +#define TWLS_IR 6 + +/* ICAP_ORIENTATION values (OR_ means ORientation) */ +#define TWOR_ROT0 0 +#define TWOR_ROT90 1 +#define TWOR_ROT180 2 +#define TWOR_ROT270 3 +#define TWOR_PORTRAIT TWOR_ROT0 +#define TWOR_LANDSCAPE TWOR_ROT270 + +/* ICAP_PLANARCHUNKY values (PC_ means Planar/Chunky ) */ +#define TWPC_CHUNKY 0 +#define TWPC_PLANAR 1 + +/* ICAP_PIXELFLAVOR values (PF_ means Pixel Flavor) */ +#define TWPF_CHOCOLATE 0 /* zero pixel represents darkest shade */ +#define TWPF_VANILLA 1 /* zero pixel represents lightest shade */ + +/* ICAP_PIXELTYPE values (PT_ means Pixel Type) */ +#define TWPT_BW 0 /* Black and White */ +#define TWPT_GRAY 1 +#define TWPT_RGB 2 +#define TWPT_PALETTE 3 +#define TWPT_CMY 4 +#define TWPT_CMYK 5 +#define TWPT_YUV 6 +#define TWPT_YUVK 7 +#define TWPT_CIEXYZ 8 + +/* ICAP_SUPPORTEDSIZES values (SS_ means Supported Sizes) */ +#define TWSS_NONE 0 +#define TWSS_A4LETTER 1 +#define TWSS_B5LETTER 2 +#define TWSS_USLETTER 3 +#define TWSS_USLEGAL 4 +/* Added 1.5 */ +#define TWSS_A5 5 +#define TWSS_B4 6 +#define TWSS_B6 7 +//#define TWSS_B 8 +/* Added 1.7 */ +#define TWSS_USLEDGER 9 +#define TWSS_USEXECUTIVE 10 +#define TWSS_A3 11 +#define TWSS_B3 12 +#define TWSS_A6 13 +#define TWSS_C4 14 +#define TWSS_C5 15 +#define TWSS_C6 16 +/* Added 1.8 */ +#define TWSS_4A0 17 +#define TWSS_2A0 18 +#define TWSS_A0 19 +#define TWSS_A1 20 +#define TWSS_A2 21 +#define TWSS_A4 TWSS_A4LETTER +#define TWSS_A7 22 +#define TWSS_A8 23 +#define TWSS_A9 24 +#define TWSS_A10 25 +#define TWSS_ISOB0 26 +#define TWSS_ISOB1 27 +#define TWSS_ISOB2 28 +#define TWSS_ISOB3 TWSS_B3 +#define TWSS_ISOB4 TWSS_B4 +#define TWSS_ISOB5 29 +#define TWSS_ISOB6 TWSS_B6 +#define TWSS_ISOB7 30 +#define TWSS_ISOB8 31 +#define TWSS_ISOB9 32 +#define TWSS_ISOB10 33 +#define TWSS_JISB0 34 +#define TWSS_JISB1 35 +#define TWSS_JISB2 36 +#define TWSS_JISB3 37 +#define TWSS_JISB4 38 +#define TWSS_JISB5 TWSS_B5LETTER +#define TWSS_JISB6 39 +#define TWSS_JISB7 40 +#define TWSS_JISB8 41 +#define TWSS_JISB9 42 +#define TWSS_JISB10 43 +#define TWSS_C0 44 +#define TWSS_C1 45 +#define TWSS_C2 46 +#define TWSS_C3 47 +#define TWSS_C7 48 +#define TWSS_C8 49 +#define TWSS_C9 50 +#define TWSS_C10 51 +#define TWSS_USSTATEMENT 52 +#define TWSS_BUSINESSCARD 53 + +/* ICAP_XFERMECH values (SX_ means Setup XFer) */ +#define TWSX_NATIVE 0 +#define TWSX_FILE 1 +#define TWSX_MEMORY 2 +#define TWSX_FILE2 3 /* added 1.9 */ + +/* ICAP_UNITS values (UN_ means UNits) */ +#define TWUN_INCHES 0 +#define TWUN_CENTIMETERS 1 +#define TWUN_PICAS 2 +#define TWUN_POINTS 3 +#define TWUN_TWIPS 4 +#define TWUN_PIXELS 5 + +/* Added 1.5 */ +/* ICAP_BITDEPTHREDUCTION values (BR_ means Bitdepth Reduction) */ +#define TWBR_THRESHOLD 0 +#define TWBR_HALFTONE 1 +#define TWBR_CUSTHALFTONE 2 +#define TWBR_DIFFUSION 3 + +/* Added 1.7 */ +/* ICAP_DUPLEX values */ +#define TWDX_NONE 0 +#define TWDX_1PASSDUPLEX 1 +#define TWDX_2PASSDUPLEX 2 + +/* Added 1.7 */ +/* TWEI_BARCODETYPE values */ +#define TWBT_3OF9 0 +#define TWBT_2OF5INTERLEAVED 1 +#define TWBT_2OF5NONINTERLEAVED 2 +#define TWBT_CODE93 3 +#define TWBT_CODE128 4 +#define TWBT_UCC128 5 +#define TWBT_CODABAR 6 +#define TWBT_UPCA 7 +#define TWBT_UPCE 8 +#define TWBT_EAN8 9 +#define TWBT_EAN13 10 +#define TWBT_POSTNET 11 +#define TWBT_PDF417 12 +/* Added 1.8 */ +#define TWBT_2OF5INDUSTRIAL 13 +#define TWBT_2OF5MATRIX 14 +#define TWBT_2OF5DATALOGIC 15 +#define TWBT_2OF5IATA 16 +#define TWBT_3OF9FULLASCII 17 +#define TWBT_CODABARWITHSTARTSTOP 18 +#define TWBT_MAXICODE 19 + +/* Added 1.7 */ +/* TWEI_DESKEWSTATUS values */ +#define TWDSK_SUCCESS 0 +#define TWDSK_REPORTONLY 1 +#define TWDSK_FAIL 2 +#define TWDSK_DISABLED 3 + +/* Added 1.7 */ +/* TWEI_PATCHCODE values */ +#define TWPCH_PATCH1 0 +#define TWPCH_PATCH2 1 +#define TWPCH_PATCH3 2 +#define TWPCH_PATCH4 3 +#define TWPCH_PATCH6 4 +#define TWPCH_PATCHT 5 + +/* Added 1.7 */ +/* CAP_JOBCONTROL values */ +#define TWJC_NONE 0 +#define TWJC_JSIC 1 +#define TWJC_JSIS 2 +#define TWJC_JSXC 3 +#define TWJC_JSXS 4 + +/* Added 1.7 */ +/* TWEI_BARCODEROTATION values (BCOR_ means barcode rotation) */ +#define TWBCOR_ROT0 0 +#define TWBCOR_ROT90 1 +#define TWBCOR_ROT180 2 +#define TWBCOR_ROT270 3 +#define TWBCOR_ROTX 4 + +/* Added 1.8 */ +/* ACAP_AUDIOFILEFORMAT values (AF_ means audio format) */ +#define TWAF_WAV 0 +#define TWAF_AIFF 1 +#define TWAF_AU 3 +#define TWAF_SND 4 + +/* CAP_ALARMS values (AL_ means alarms) */ +#define TWAL_ALARM 0 +#define TWAL_FEEDERERROR 1 +#define TWAL_FEEDERWARNING 2 +#define TWAL_BARCODE 3 +#define TWAL_DOUBLEFEED 4 +#define TWAL_JAM 5 +#define TWAL_PATCHCODE 6 +#define TWAL_POWER 7 +#define TWAL_SKEW 8 + +/* CAP_CLEARBUFFERS values (CB_ means clear buffers) */ +#define TWCB_AUTO 0 +#define TWCB_CLEAR 1 +#define TWCB_NOCLEAR 2 + +/* CAP_DEVICEEVENT values (DE_ means device event) */ +#define TWDE_CUSTOMEVENTS 0x8000 +#define TWDE_CHECKAUTOMATICCAPTURE 0 +#define TWDE_CHECKBATTERY 1 +#define TWDE_CHECKDEVICEONLINE 2 +#define TWDE_CHECKFLASH 3 +#define TWDE_CHECKPOWERSUPPLY 4 +#define TWDE_CHECKRESOLUTION 5 +#define TWDE_DEVICEADDED 6 +#define TWDE_DEVICEOFFLINE 7 +#define TWDE_DEVICEREADY 8 +#define TWDE_DEVICEREMOVED 9 +#define TWDE_IMAGECAPTURED 10 +#define TWDE_IMAGEDELETED 11 +#define TWDE_PAPERDOUBLEFEED 12 +#define TWDE_PAPERJAM 13 +#define TWDE_LAMPFAILURE 14 +#define TWDE_POWERSAVE 15 +#define TWDE_POWERSAVENOTIFY 16 + +/* CAP_FEEDERALIGNMENT values (FA_ means feeder alignment) */ +#define TWFA_NONE 0 +#define TWFA_LEFT 1 +#define TWFA_CENTER 2 +#define TWFA_RIGHT 3 + +/* CAP_FEEDERORDER values (FO_ means feeder order) */ +#define TWFO_FIRSTPAGEFIRST 0 +#define TWFO_LASTPAGEFIRST 1 + +/* CAP_FILESYSTEM values (FS_ means file system) */ +#define TWFS_FILESYSTEM 0 +#define TWFS_RECURSIVEDELETE 1 + +/* CAP_POWERSUPPLY values (PS_ means power supply) */ +#define TWPS_EXTERNAL 0 +#define TWPS_BATTERY 1 + +/* CAP_PRINTER values (PR_ means printer) */ +#define TWPR_IMPRINTERTOPBEFORE 0 +#define TWPR_IMPRINTERTOPAFTER 1 +#define TWPR_IMPRINTERBOTTOMBEFORE 2 +#define TWPR_IMPRINTERBOTTOMAFTER 3 +#define TWPR_ENDORSERTOPBEFORE 4 +#define TWPR_ENDORSERTOPAFTER 5 +#define TWPR_ENDORSERBOTTOMBEFORE 6 +#define TWPR_ENDORSERBOTTOMAFTER 7 + +/* CAP_PRINTERMODE values (PM_ means printer mode) */ +#define TWPM_SINGLESTRING 0 +#define TWPM_MULTISTRING 1 +#define TWPM_COMPOUNDSTRING 2 + +/* ICAP_BARCODESEARCHMODE values (TWBD_ means search) */ +#define TWBD_HORZ 0 +#define TWBD_VERT 1 +#define TWBD_HORZVERT 2 +#define TWBD_VERTHORZ 3 + +/* ICAP_FLASHUSED2 values (FL_ means flash) */ +#define TWFL_NONE 0 +#define TWFL_OFF 1 +#define TWFL_ON 2 +#define TWFL_AUTO 3 +#define TWFL_REDEYE 4 + +/* ICAP_FLIPROTATION values (FR_ means flip rotation) */ +#define TWFR_BOOK 0 +#define TWFR_FANFOLD 1 + +/* ICAP_IMAGEFILTER values (IF_ means image filter) */ +#define TWIF_NONE 0 +#define TWIF_AUTO 1 +#define TWIF_LOWPASS 2 +#define TWIF_BANDPASS 3 +#define TWIF_HIGHPASS 4 +#define TWIF_TEXT TWIF_BANDPASS +#define TWIF_FINELINE TWIF_HIGHPASS + +/* ICAP_NOISEFILTER values (NF_ means noise filter) */ +#define TWNF_NONE 0 +#define TWNF_AUTO 1 +#define TWNF_LONEPIXEL 2 +#define TWNF_MAJORITYRULE 3 + +/* ICAP_OVERSCAN values (OV_ means overscan) */ +#define TWOV_NONE 0 +#define TWOV_AUTO 1 +#define TWOV_TOPBOTTOM 2 +#define TWOV_LEFTRIGHT 3 +#define TWOV_ALL 4 + +/* TW_FILESYSTEM.FileType values (FT_ means file type) */ +#define TWFY_CAMERA 0 +#define TWFY_CAMERATOP 1 +#define TWFY_CAMERABOTTOM 2 +#define TWFY_CAMERAPREVIEW 3 +#define TWFY_DOMAIN 4 +#define TWFY_HOST 5 +#define TWFY_DIRECTORY 6 +#define TWFY_IMAGE 7 +#define TWFY_UNKNOWN 8 + +/* ICAP_JPEGQUALITY values (JQ_ means jpeg quality) */ +#define TWJQ_UNKNOWN -4 +#define TWJQ_LOW -3 +#define TWJQ_MEDIUM -2 +#define TWJQ_HIGH -1 + +/**************************************************************************** + * Country Constants * + ****************************************************************************/ + +#define TWCY_AFGHANISTAN 1001 +#define TWCY_ALGERIA 213 +#define TWCY_AMERICANSAMOA 684 +#define TWCY_ANDORRA 033 +#define TWCY_ANGOLA 1002 +#define TWCY_ANGUILLA 8090 +#define TWCY_ANTIGUA 8091 +#define TWCY_ARGENTINA 54 +#define TWCY_ARUBA 297 +#define TWCY_ASCENSIONI 247 +#define TWCY_AUSTRALIA 61 +#define TWCY_AUSTRIA 43 +#define TWCY_BAHAMAS 8092 +#define TWCY_BAHRAIN 973 +#define TWCY_BANGLADESH 880 +#define TWCY_BARBADOS 8093 +#define TWCY_BELGIUM 32 +#define TWCY_BELIZE 501 +#define TWCY_BENIN 229 +#define TWCY_BERMUDA 8094 +#define TWCY_BHUTAN 1003 +#define TWCY_BOLIVIA 591 +#define TWCY_BOTSWANA 267 +#define TWCY_BRITAIN 6 +#define TWCY_BRITVIRGINIS 8095 +#define TWCY_BRAZIL 55 +#define TWCY_BRUNEI 673 +#define TWCY_BULGARIA 359 +#define TWCY_BURKINAFASO 1004 +#define TWCY_BURMA 1005 +#define TWCY_BURUNDI 1006 +#define TWCY_CAMAROON 237 +#define TWCY_CANADA 2 +#define TWCY_CAPEVERDEIS 238 +#define TWCY_CAYMANIS 8096 +#define TWCY_CENTRALAFREP 1007 +#define TWCY_CHAD 1008 +#define TWCY_CHILE 56 +#define TWCY_CHINA 86 +#define TWCY_CHRISTMASIS 1009 +#define TWCY_COCOSIS 1009 +#define TWCY_COLOMBIA 57 +#define TWCY_COMOROS 1010 +#define TWCY_CONGO 1011 +#define TWCY_COOKIS 1012 +#define TWCY_COSTARICA 506 +#define TWCY_CUBA 005 +#define TWCY_CYPRUS 357 +#define TWCY_CZECHOSLOVAKIA 42 +#define TWCY_DENMARK 45 +#define TWCY_DJIBOUTI 1013 +#define TWCY_DOMINICA 8097 +#define TWCY_DOMINCANREP 8098 +#define TWCY_EASTERIS 1014 +#define TWCY_ECUADOR 593 +#define TWCY_EGYPT 20 +#define TWCY_ELSALVADOR 503 +#define TWCY_EQGUINEA 1015 +#define TWCY_ETHIOPIA 251 +#define TWCY_FALKLANDIS 1016 +#define TWCY_FAEROEIS 298 +#define TWCY_FIJIISLANDS 679 +#define TWCY_FINLAND 358 +#define TWCY_FRANCE 33 +#define TWCY_FRANTILLES 596 +#define TWCY_FRGUIANA 594 +#define TWCY_FRPOLYNEISA 689 +#define TWCY_FUTANAIS 1043 +#define TWCY_GABON 241 +#define TWCY_GAMBIA 220 +#define TWCY_GERMANY 49 +#define TWCY_GHANA 233 +#define TWCY_GIBRALTER 350 +#define TWCY_GREECE 30 +#define TWCY_GREENLAND 299 +#define TWCY_GRENADA 8099 +#define TWCY_GRENEDINES 8015 +#define TWCY_GUADELOUPE 590 +#define TWCY_GUAM 671 +#define TWCY_GUANTANAMOBAY 5399 +#define TWCY_GUATEMALA 502 +#define TWCY_GUINEA 224 +#define TWCY_GUINEABISSAU 1017 +#define TWCY_GUYANA 592 +#define TWCY_HAITI 509 +#define TWCY_HONDURAS 504 +#define TWCY_HONGKONG 852 +#define TWCY_HUNGARY 36 +#define TWCY_ICELAND 354 +#define TWCY_INDIA 91 +#define TWCY_INDONESIA 62 +#define TWCY_IRAN 98 +#define TWCY_IRAQ 964 +#define TWCY_IRELAND 353 +#define TWCY_ISRAEL 972 +#define TWCY_ITALY 39 +#define TWCY_IVORYCOAST 225 +#define TWCY_JAMAICA 8010 +#define TWCY_JAPAN 81 +#define TWCY_JORDAN 962 +#define TWCY_KENYA 254 +#define TWCY_KIRIBATI 1018 +#define TWCY_KOREA 82 +#define TWCY_KUWAIT 965 +#define TWCY_LAOS 1019 +#define TWCY_LEBANON 1020 +#define TWCY_LIBERIA 231 +#define TWCY_LIBYA 218 +#define TWCY_LIECHTENSTEIN 41 +#define TWCY_LUXENBOURG 352 +#define TWCY_MACAO 853 +#define TWCY_MADAGASCAR 1021 +#define TWCY_MALAWI 265 +#define TWCY_MALAYSIA 60 +#define TWCY_MALDIVES 960 +#define TWCY_MALI 1022 +#define TWCY_MALTA 356 +#define TWCY_MARSHALLIS 692 +#define TWCY_MAURITANIA 1023 +#define TWCY_MAURITIUS 230 +#define TWCY_MEXICO 3 +#define TWCY_MICRONESIA 691 +#define TWCY_MIQUELON 508 +#define TWCY_MONACO 33 +#define TWCY_MONGOLIA 1024 +#define TWCY_MONTSERRAT 8011 +#define TWCY_MOROCCO 212 +#define TWCY_MOZAMBIQUE 1025 +#define TWCY_NAMIBIA 264 +#define TWCY_NAURU 1026 +#define TWCY_NEPAL 977 +#define TWCY_NETHERLANDS 31 +#define TWCY_NETHANTILLES 599 +#define TWCY_NEVIS 8012 +#define TWCY_NEWCALEDONIA 687 +#define TWCY_NEWZEALAND 64 +#define TWCY_NICARAGUA 505 +#define TWCY_NIGER 227 +#define TWCY_NIGERIA 234 +#define TWCY_NIUE 1027 +#define TWCY_NORFOLKI 1028 +#define TWCY_NORWAY 47 +#define TWCY_OMAN 968 +#define TWCY_PAKISTAN 92 +#define TWCY_PALAU 1029 +#define TWCY_PANAMA 507 +#define TWCY_PARAGUAY 595 +#define TWCY_PERU 51 +#define TWCY_PHILLIPPINES 63 +#define TWCY_PITCAIRNIS 1030 +#define TWCY_PNEWGUINEA 675 +#define TWCY_POLAND 48 +#define TWCY_PORTUGAL 351 +#define TWCY_QATAR 974 +#define TWCY_REUNIONI 1031 +#define TWCY_ROMANIA 40 +#define TWCY_RWANDA 250 +#define TWCY_SAIPAN 670 +#define TWCY_SANMARINO 39 +#define TWCY_SAOTOME 1033 +#define TWCY_SAUDIARABIA 966 +#define TWCY_SENEGAL 221 +#define TWCY_SEYCHELLESIS 1034 +#define TWCY_SIERRALEONE 1035 +#define TWCY_SINGAPORE 65 +#define TWCY_SOLOMONIS 1036 +#define TWCY_SOMALI 1037 +#define TWCY_SOUTHAFRICA 27 +#define TWCY_SPAIN 34 +#define TWCY_SRILANKA 94 +#define TWCY_STHELENA 1032 +#define TWCY_STKITTS 8013 +#define TWCY_STLUCIA 8014 +#define TWCY_STPIERRE 508 +#define TWCY_STVINCENT 8015 +#define TWCY_SUDAN 1038 +#define TWCY_SURINAME 597 +#define TWCY_SWAZILAND 268 +#define TWCY_SWEDEN 46 +#define TWCY_SWITZERLAND 41 +#define TWCY_SYRIA 1039 +#define TWCY_TAIWAN 886 +#define TWCY_TANZANIA 255 +#define TWCY_THAILAND 66 +#define TWCY_TOBAGO 8016 +#define TWCY_TOGO 228 +#define TWCY_TONGAIS 676 +#define TWCY_TRINIDAD 8016 +#define TWCY_TUNISIA 216 +#define TWCY_TURKEY 90 +#define TWCY_TURKSCAICOS 8017 +#define TWCY_TUVALU 1040 +#define TWCY_UGANDA 256 +#define TWCY_USSR 7 +#define TWCY_UAEMIRATES 971 +#define TWCY_UNITEDKINGDOM 44 +#define TWCY_USA 1 +#define TWCY_URUGUAY 598 +#define TWCY_VANUATU 1041 +#define TWCY_VATICANCITY 39 +#define TWCY_VENEZUELA 58 +#define TWCY_WAKE 1042 +#define TWCY_WALLISIS 1043 +#define TWCY_WESTERNSAHARA 1044 +#define TWCY_WESTERNSAMOA 1045 +#define TWCY_YEMEN 1046 +#define TWCY_YUGOSLAVIA 38 +#define TWCY_ZAIRE 243 +#define TWCY_ZAMBIA 260 +#define TWCY_ZIMBABWE 263 +/* Added for 1.8 */ +#define TWCY_ALBANIA 355 +#define TWCY_ARMENIA 374 +#define TWCY_AZERBAIJAN 994 +#define TWCY_BELARUS 375 +#define TWCY_BOSNIAHERZGO 387 +#define TWCY_CAMBODIA 855 +#define TWCY_CROATIA 385 +#define TWCY_CZECHREPUBLIC 420 +#define TWCY_DIEGOGARCIA 246 +#define TWCY_ERITREA 291 +#define TWCY_ESTONIA 372 +#define TWCY_GEORGIA 995 +#define TWCY_LATVIA 371 +#define TWCY_LESOTHO 266 +#define TWCY_LITHUANIA 370 +#define TWCY_MACEDONIA 389 +#define TWCY_MAYOTTEIS 269 +#define TWCY_MOLDOVA 373 +#define TWCY_MYANMAR 95 +#define TWCY_NORTHKOREA 850 +#define TWCY_PUERTORICO 787 +#define TWCY_RUSSIA 7 +#define TWCY_SERBIA 381 +#define TWCY_SLOVAKIA 421 +#define TWCY_SLOVENIA 386 +#define TWCY_SOUTHKOREA 82 +#define TWCY_UKRAINE 380 +#define TWCY_USVIRGINIS 340 +#define TWCY_VIETNAM 84 + +/**************************************************************************** + * Language Constants * + ****************************************************************************/ + +#define TWLG_DAN 0 /* Danish */ +#define TWLG_DUT 1 /* Dutch */ +#define TWLG_ENG 2 /* International English */ +#define TWLG_FCF 3 /* French Canadian */ +#define TWLG_FIN 4 /* Finnish */ +#define TWLG_FRN 5 /* French */ +#define TWLG_GER 6 /* German */ +#define TWLG_ICE 7 /* Icelandic */ +#define TWLG_ITN 8 /* Italian */ +#define TWLG_NOR 9 /* Norwegian */ +#define TWLG_POR 10 /* Portuguese */ +#define TWLG_SPA 11 /* Spanish */ +#define TWLG_SWE 12 /* Swedish */ +#define TWLG_USA 13 /* U.S. English */ +/* Added for 1.8 */ +#define TWLG_USERLOCALE -1 +#define TWLG_AFRIKAANS 14 +#define TWLG_ALBANIA 15 +#define TWLG_ARABIC 16 +#define TWLG_ARABIC_ALGERIA 17 +#define TWLG_ARABIC_BAHRAIN 18 +#define TWLG_ARABIC_EGYPT 19 +#define TWLG_ARABIC_IRAQ 20 +#define TWLG_ARABIC_JORDAN 21 +#define TWLG_ARABIC_KUWAIT 22 +#define TWLG_ARABIC_LEBANON 23 +#define TWLG_ARABIC_LIBYA 24 +#define TWLG_ARABIC_MOROCCO 25 +#define TWLG_ARABIC_OMAN 26 +#define TWLG_ARABIC_QATAR 27 +#define TWLG_ARABIC_SAUDIARABIA 28 +#define TWLG_ARABIC_SYRIA 29 +#define TWLG_ARABIC_TUNISIA 30 +#define TWLG_ARABIC_UAE 31 /* United Arabic Emirates */ +#define TWLG_ARABIC_YEMEN 32 +#define TWLG_BASQUE 33 +#define TWLG_BYELORUSSIAN 34 +#define TWLG_BULGARIAN 35 +#define TWLG_CATALAN 36 +#define TWLG_CHINESE 37 +#define TWLG_CHINESE_HONGKONG 38 +#define TWLG_CHINESE_PRC 39 /* People's Republic of China */ +#define TWLG_CHINESE_SINGAPORE 40 +#define TWLG_CHINESE_SIMPLIFIED 41 +#define TWLG_CHINESE_TAIWAN 42 +#define TWLG_CHINESE_TRADITIONAL 43 +#define TWLG_CROATIA 44 +#define TWLG_CZECH 45 +#define TWLG_DANISH TWLG_DAN +#define TWLG_DUTCH TWLG_DUT +#define TWLG_DUTCH_BELGIAN 46 +#define TWLG_ENGLISH TWLG_ENG +#define TWLG_ENGLISH_AUSTRALIAN 47 +#define TWLG_ENGLISH_CANADIAN 48 +#define TWLG_ENGLISH_IRELAND 49 +#define TWLG_ENGLISH_NEWZEALAND 50 +#define TWLG_ENGLISH_SOUTHAFRICA 51 +#define TWLG_ENGLISH_UK 52 +#define TWLG_ENGLISH_USA TWLG_USA +#define TWLG_ESTONIAN 53 +#define TWLG_FAEROESE 54 +#define TWLG_FARSI 55 +#define TWLG_FINNISH TWLG_FIN +#define TWLG_FRENCH TWLG_FRN +#define TWLG_FRENCH_BELGIAN 56 +#define TWLG_FRENCH_CANADIAN TWLG_FCF +#define TWLG_FRENCH_LUXEMBOURG 57 +#define TWLG_FRENCH_SWISS 58 +#define TWLG_GERMAN TWLG_GER +#define TWLG_GERMAN_AUSTRIAN 59 +#define TWLG_GERMAN_LUXEMBOURG 60 +#define TWLG_GERMAN_LIECHTENSTEIN 61 +#define TWLG_GERMAN_SWISS 62 +#define TWLG_GREEK 63 +#define TWLG_HEBREW 64 +#define TWLG_HUNGARIAN 65 +#define TWLG_ICELANDIC TWLG_ICE +#define TWLG_INDONESIAN 66 +#define TWLG_ITALIAN TWLG_ITN +#define TWLG_ITALIAN_SWISS 67 +#define TWLG_JAPANESE 68 +#define TWLG_KOREAN 69 +#define TWLG_KOREAN_JOHAB 70 +#define TWLG_LATVIAN 71 +#define TWLG_LITHUANIAN 72 +#define TWLG_NORWEGIAN TWLG_NOR +#define TWLG_NORWEGIAN_BOKMAL 73 +#define TWLG_NORWEGIAN_NYNORSK 74 +#define TWLG_POLISH 75 +#define TWLG_PORTUGUESE TWLG_POR +#define TWLG_PORTUGUESE_BRAZIL 76 +#define TWLG_ROMANIAN 77 +#define TWLG_RUSSIAN 78 +#define TWLG_SERBIAN_LATIN 79 +#define TWLG_SLOVAK 80 +#define TWLG_SLOVENIAN 81 +#define TWLG_SPANISH TWLG_SPA +#define TWLG_SPANISH_MEXICAN 82 +#define TWLG_SPANISH_MODERN 83 +#define TWLG_SWEDISH TWLG_SWE +#define TWLG_THAI 84 +#define TWLG_TURKISH 85 +#define TWLG_UKRANIAN 86 +/* More stuff added for 1.8 */ +#define TWLG_ASSAMESE 87 +#define TWLG_BENGALI 88 +#define TWLG_BIHARI 89 +#define TWLG_BODO 90 +#define TWLG_DOGRI 91 +#define TWLG_GUJARATI 92 +#define TWLG_HARYANVI 93 +#define TWLG_HINDI 94 +#define TWLG_KANNADA 95 +#define TWLG_KASHMIRI 96 +#define TWLG_MALAYALAM 97 +#define TWLG_MARATHI 98 +#define TWLG_MARWARI 99 +#define TWLG_MEGHALAYAN 100 +#define TWLG_MIZO 101 +#define TWLG_NAGA 102 +#define TWLG_ORISSI 103 +#define TWLG_PUNJABI 104 +#define TWLG_PUSHTU 105 +#define TWLG_SERBIAN_CYRILLIC 106 +#define TWLG_SIKKIMI 107 +#define TWLG_SWEDISH_FINLAND 108 +#define TWLG_TAMIL 109 +#define TWLG_TELUGU 110 +#define TWLG_TRIPURI 111 +#define TWLG_URDU 112 +#define TWLG_VIETNAMESE 113 + +/**************************************************************************** + * Data Groups * + ****************************************************************************/ + +/* More Data Groups may be added in the future. + * Possible candidates include text, vector graphics, sound, etc. + * NOTE: Data Group constants must be powers of 2 as they are used + * as bitflags when Application asks DSM to present a list of DSs. + */ + +#define DG_CONTROL 0x0001L /* data pertaining to control */ +#define DG_IMAGE 0x0002L /* data pertaining to raster images */ +/* Added 1.8 */ +#define DG_AUDIO 0x0004L /* data pertaining to audio */ + +/**************************************************************************** + * Data Argument Types * + ****************************************************************************/ + +/* SDH - 03/23/95 - WATCH */ +/* The thunker requires knowledge about size of data being passed in the */ +/* lpData parameter to DS_Entry (which is not readily available due to */ +/* type LPVOID. Thus, we key off the DAT_ argument to determine the size. */ +/* This has a couple implications: */ +/* 1) Any additional DAT_ features require modifications to the thunk code */ +/* for thunker support. */ +/* 2) Any applications which use the custom capabailites are not supported */ +/* under thunking since we have no way of knowing what size data (if */ +/* any) is being passed. */ + +#define DAT_NULL 0x0000 /* No data or structure. */ +#define DAT_CUSTOMBASE 0x8000 /* Base of custom DATs. */ + +/* Data Argument Types for the DG_CONTROL Data Group. */ +#define DAT_CAPABILITY 0x0001 /* TW_CAPABILITY */ +#define DAT_EVENT 0x0002 /* TW_EVENT */ +#define DAT_IDENTITY 0x0003 /* TW_IDENTITY */ +#define DAT_PARENT 0x0004 /* TW_HANDLE, application win handle in Windows */ +#define DAT_PENDINGXFERS 0x0005 /* TW_PENDINGXFERS */ +#define DAT_SETUPMEMXFER 0x0006 /* TW_SETUPMEMXFER */ +#define DAT_SETUPFILEXFER 0x0007 /* TW_SETUPFILEXFER */ +#define DAT_STATUS 0x0008 /* TW_STATUS */ +#define DAT_USERINTERFACE 0x0009 /* TW_USERINTERFACE */ +#define DAT_XFERGROUP 0x000a /* TW_UINT32 */ +/* SDH - 03/21/95 - TWUNK */ +/* Additional message required for thunker to request the special */ +/* identity information. */ +#define DAT_TWUNKIDENTITY 0x000b /* TW_TWUNKIDENTITY */ +#define DAT_CUSTOMDSDATA 0x000c /* TW_CUSTOMDSDATA. */ +/* Added 1.8 */ +#define DAT_DEVICEEVENT 0x000d /* TW_DEVICEEVENT */ +#define DAT_FILESYSTEM 0x000e /* TW_FILESYSTEM */ +#define DAT_PASSTHRU 0x000f /* TW_PASSTHRU */ + +/* Data Argument Types for the DG_IMAGE Data Group. */ +#define DAT_IMAGEINFO 0x0101 /* TW_IMAGEINFO */ +#define DAT_IMAGELAYOUT 0x0102 /* TW_IMAGELAYOUT */ +#define DAT_IMAGEMEMXFER 0x0103 /* TW_IMAGEMEMXFER */ +#define DAT_IMAGENATIVEXFER 0x0104 /* TW_UINT32 loword is hDIB, PICHandle */ +#define DAT_IMAGEFILEXFER 0x0105 /* Null data */ +#define DAT_CIECOLOR 0x0106 /* TW_CIECOLOR */ +#define DAT_GRAYRESPONSE 0x0107 /* TW_GRAYRESPONSE */ +#define DAT_RGBRESPONSE 0x0108 /* TW_RGBRESPONSE */ +#define DAT_JPEGCOMPRESSION 0x0109 /* TW_JPEGCOMPRESSION */ +#define DAT_PALETTE8 0x010a /* TW_PALETTE8 */ +#define DAT_EXTIMAGEINFO 0x010b /* TW_EXTIMAGEINFO -- for 1.7 Spec. */ + +/* Added 1.8 */ +/* Data Argument Types for the DG_AUDIO Data Group. */ +#define DAT_AUDIOFILEXFER 0x0201 /* Null data */ +#define DAT_AUDIOINFO 0x0202 /* TW_AUDIOINFO */ +#define DAT_AUDIONATIVEXFER 0x0203 /* TW_UINT32 handle to WAV, (AIFF Mac) */ + +/* Added 1.9 */ +#define DAT_ SETUPFILEXFER2 0x0301 /* New file xfer operation */ + +/**************************************************************************** + * Messages * + ****************************************************************************/ + +/* All message constants are unique. + * Messages are grouped according to which DATs they are used with.*/ + +#define MSG_NULL 0x0000 /* Used in TW_EVENT structure */ +#define MSG_CUSTOMBASE 0x8000 /* Base of custom messages */ + +/* Generic messages may be used with any of several DATs. */ +#define MSG_GET 0x0001 /* Get one or more values */ +#define MSG_GETCURRENT 0x0002 /* Get current value */ +#define MSG_GETDEFAULT 0x0003 /* Get default (e.g. power up) value */ +#define MSG_GETFIRST 0x0004 /* Get first of a series of items, e.g. DSs */ +#define MSG_GETNEXT 0x0005 /* Iterate through a series of items. */ +#define MSG_SET 0x0006 /* Set one or more values */ +#define MSG_RESET 0x0007 /* Set current value to default value */ +#define MSG_QUERYSUPPORT 0x0008 /* Get supported operations on the cap. */ + +/* Messages used with DAT_NULL */ +#define MSG_XFERREADY 0x0101 /* The data source has data ready */ +#define MSG_CLOSEDSREQ 0x0102 /* Request for Application. to close DS */ +#define MSG_CLOSEDSOK 0x0103 /* Tell the Application. to save the state. */ +/* Added 1.8 */ +#define MSG_DEVICEEVENT 0X0104 /* Some event has taken place */ + +/* Messages used with a pointer to a DAT_STATUS structure */ +#define MSG_CHECKSTATUS 0x0201 /* Get status information */ + +/* Messages used with a pointer to DAT_PARENT data */ +#define MSG_OPENDSM 0x0301 /* Open the DSM */ +#define MSG_CLOSEDSM 0x0302 /* Close the DSM */ + +/* Messages used with a pointer to a DAT_IDENTITY structure */ +#define MSG_OPENDS 0x0401 /* Open a data source */ +#define MSG_CLOSEDS 0x0402 /* Close a data source */ +#define MSG_USERSELECT 0x0403 /* Put up a dialog of all DS */ + +/* Messages used with a pointer to a DAT_USERINTERFACE structure */ +#define MSG_DISABLEDS 0x0501 /* Disable data transfer in the DS */ +#define MSG_ENABLEDS 0x0502 /* Enable data transfer in the DS */ +#define MSG_ENABLEDSUIONLY 0x0503 /* Enable for saving DS state only. */ + +/* Messages used with a pointer to a DAT_EVENT structure */ +#define MSG_PROCESSEVENT 0x0601 + +/* Messages used with a pointer to a DAT_PENDINGXFERS structure */ +#define MSG_ENDXFER 0x0701 +#define MSG_STOPFEEDER 0x0702 + +/* Added 1.8 */ +/* Messages used with a pointer to a DAT_FILESYSTEM structure */ +#define MSG_CHANGEDIRECTORY 0x0801 +#define MSG_CREATEDIRECTORY 0x0802 +#define MSG_DELETE 0x0803 +#define MSG_FORMATMEDIA 0x0804 +#define MSG_GETCLOSE 0x0805 +#define MSG_GETFIRSTFILE 0x0806 +#define MSG_GETINFO 0x0807 +#define MSG_GETNEXTFILE 0x0808 +#define MSG_RENAME 0x0809 +#define MSG_COPY 0x080A +#define MSG_AUTOMATICCAPTUREDIRECTORY 0x080B + + +/* Messages used with a pointer to a DAT_PASSTHRU structure */ +#define MSG_PASSTHRU 0x0901 + +/**************************************************************************** + * Capabilities * + ****************************************************************************/ + +#define CAP_CUSTOMBASE 0x8000 /* Base of custom capabilities */ + +/* all data sources are REQUIRED to support these caps */ +#define CAP_XFERCOUNT 0x0001 + +/* image data sources are REQUIRED to support these caps */ +#define ICAP_COMPRESSION 0x0100 +#define ICAP_PIXELTYPE 0x0101 +#define ICAP_UNITS 0x0102 /* default is TWUN_INCHES */ +#define ICAP_XFERMECH 0x0103 + +/* all data sources MAY support these caps */ +#define CAP_AUTHOR 0x1000 +#define CAP_CAPTION 0x1001 +#define CAP_FEEDERENABLED 0x1002 +#define CAP_FEEDERLOADED 0x1003 +#define CAP_TIMEDATE 0x1004 +#define CAP_SUPPORTEDCAPS 0x1005 +#define CAP_EXTENDEDCAPS 0x1006 +#define CAP_AUTOFEED 0x1007 +#define CAP_CLEARPAGE 0x1008 +#define CAP_FEEDPAGE 0x1009 +#define CAP_REWINDPAGE 0x100a +#define CAP_INDICATORS 0x100b /* Added 1.1 */ +#define CAP_SUPPORTEDCAPSEXT 0x100c /* Added 1.6 */ +#define CAP_PAPERDETECTABLE 0x100d /* Added 1.6 */ +#define CAP_UICONTROLLABLE 0x100e /* Added 1.6 */ +#define CAP_DEVICEONLINE 0x100f /* Added 1.6 */ +#define CAP_AUTOSCAN 0x1010 /* Added 1.6 */ +#define CAP_THUMBNAILSENABLED 0x1011 /* Added 1.7 */ +#define CAP_DUPLEX 0x1012 /* Added 1.7 */ +#define CAP_DUPLEXENABLED 0x1013 /* Added 1.7 */ +#define CAP_ENABLEDSUIONLY 0x1014 /* Added 1.7 */ +#define CAP_CUSTOMDSDATA 0x1015 /* Added 1.7 */ +#define CAP_ENDORSER 0x1016 /* Added 1.7 */ +#define CAP_JOBCONTROL 0x1017 /* Added 1.7 */ +#define CAP_ALARMS 0x1018 /* Added 1.8 */ +#define CAP_ALARMVOLUME 0x1019 /* Added 1.8 */ +#define CAP_AUTOMATICCAPTURE 0x101a /* Added 1.8 */ +#define CAP_TIMEBEFOREFIRSTCAPTURE 0x101b /* Added 1.8 */ +#define CAP_TIMEBETWEENCAPTURES 0x101c /* Added 1.8 */ +#define CAP_CLEARBUFFERS 0x101d /* Added 1.8 */ +#define CAP_MAXBATCHBUFFERS 0x101e /* Added 1.8 */ +#define CAP_DEVICETIMEDATE 0x101f /* Added 1.8 */ +#define CAP_POWERSUPPLY 0x1020 /* Added 1.8 */ +#define CAP_CAMERAPREVIEWUI 0x1021 /* Added 1.8 */ +#define CAP_DEVICEEVENT 0x1022 /* Added 1.8 */ +#define CAP_SERIALNUMBER 0x1024 /* Added 1.8 */ +#define CAP_PRINTER 0x1026 /* Added 1.8 */ +#define CAP_PRINTERENABLED 0x1027 /* Added 1.8 */ +#define CAP_PRINTERINDEX 0x1028 /* Added 1.8 */ +#define CAP_PRINTERMODE 0x1029 /* Added 1.8 */ +#define CAP_PRINTERSTRING 0x102a /* Added 1.8 */ +#define CAP_PRINTERSUFFIX 0x102b /* Added 1.8 */ +#define CAP_LANGUAGE 0x102c /* Added 1.8 */ +#define CAP_FEEDERALIGNMENT 0x102d /* Added 1.8 */ +#define CAP_FEEDERORDER 0x102e /* Added 1.8 */ +#define CAP_REACQUIREALLOWED 0x1030 /* Added 1.8 */ +#define CAP_BATTERYMINUTES 0x1032 /* Added 1.8 */ +#define CAP_BATTERYPERCENTAGE 0x1033 /* Added 1.8 */ + +/* image data sources MAY support these caps */ +#define ICAP_AUTOBRIGHT 0x1100 +#define ICAP_BRIGHTNESS 0x1101 +#define ICAP_CONTRAST 0x1103 +#define ICAP_CUSTHALFTONE 0x1104 +#define ICAP_EXPOSURETIME 0x1105 +#define ICAP_FILTER 0x1106 +#define ICAP_FLASHUSED 0x1107 +#define ICAP_GAMMA 0x1108 +#define ICAP_HALFTONES 0x1109 +#define ICAP_HIGHLIGHT 0x110a +#define ICAP_IMAGEFILEFORMAT 0x110c +#define ICAP_LAMPSTATE 0x110d +#define ICAP_LIGHTSOURCE 0x110e +#define ICAP_ORIENTATION 0x1110 +#define ICAP_PHYSICALWIDTH 0x1111 +#define ICAP_PHYSICALHEIGHT 0x1112 +#define ICAP_SHADOW 0x1113 +#define ICAP_FRAMES 0x1114 +#define ICAP_XNATIVERESOLUTION 0x1116 +#define ICAP_YNATIVERESOLUTION 0x1117 +#define ICAP_XRESOLUTION 0x1118 +#define ICAP_YRESOLUTION 0x1119 +#define ICAP_MAXFRAMES 0x111a +#define ICAP_TILES 0x111b +#define ICAP_BITORDER 0x111c +#define ICAP_CCITTKFACTOR 0x111d +#define ICAP_LIGHTPATH 0x111e +#define ICAP_PIXELFLAVOR 0x111f +#define ICAP_PLANARCHUNKY 0x1120 +#define ICAP_ROTATION 0x1121 +#define ICAP_SUPPORTEDSIZES 0x1122 +#define ICAP_THRESHOLD 0x1123 +#define ICAP_XSCALING 0x1124 +#define ICAP_YSCALING 0x1125 +#define ICAP_BITORDERCODES 0x1126 +#define ICAP_PIXELFLAVORCODES 0x1127 +#define ICAP_JPEGPIXELTYPE 0x1128 +#define ICAP_TIMEFILL 0x112a +#define ICAP_BITDEPTH 0x112b +#define ICAP_BITDEPTHREDUCTION 0x112c /* Added 1.5 */ +#define ICAP_UNDEFINEDIMAGESIZE 0x112d /* Added 1.6 */ +#define ICAP_IMAGEDATASET 0x112e /* Added 1.7 */ +#define ICAP_EXTIMAGEINFO 0x112f /* Added 1.7 */ +#define ICAP_MINIMUMHEIGHT 0x1130 /* Added 1.7 */ +#define ICAP_MINIMUMWIDTH 0x1131 /* Added 1.7 */ +#define ICAP_FLIPROTATION 0x1136 /* Added 1.8 */ +#define ICAP_BARCODEDETECTIONENABLED 0x1137 /* Added 1.8 */ +#define ICAP_SUPPORTEDBARCODETYPES 0x1138 /* Added 1.8 */ +#define ICAP_BARCODEMAXSEARCHPRIORITIES 0x1139 /* Added 1.8 */ +#define ICAP_BARCODESEARCHPRIORITIES 0x113a /* Added 1.8 */ +#define ICAP_BARCODESEARCHMODE 0x113b /* Added 1.8 */ +#define ICAP_BARCODEMAXRETRIES 0x113c /* Added 1.8 */ +#define ICAP_BARCODETIMEOUT 0x113d /* Added 1.8 */ +#define ICAP_ZOOMFACTOR 0x113e /* Added 1.8 */ +#define ICAP_PATCHCODEDETECTIONENABLED 0x113f /* Added 1.8 */ +#define ICAP_SUPPORTEDPATCHCODETYPES 0x1140 /* Added 1.8 */ +#define ICAP_PATCHCODEMAXSEARCHPRIORITIES 0x1141 /* Added 1.8 */ +#define ICAP_PATCHCODESEARCHPRIORITIES 0x1142 /* Added 1.8 */ +#define ICAP_PATCHCODESEARCHMODE 0x1143 /* Added 1.8 */ +#define ICAP_PATCHCODEMAXRETRIES 0x1144 /* Added 1.8 */ +#define ICAP_PATCHCODETIMEOUT 0x1145 /* Added 1.8 */ +#define ICAP_FLASHUSED2 0x1146 /* Added 1.8 */ +#define ICAP_IMAGEFILTER 0x1147 /* Added 1.8 */ +#define ICAP_NOISEFILTER 0x1148 /* Added 1.8 */ +#define ICAP_OVERSCAN 0x1149 /* Added 1.8 */ +#define ICAP_AUTOMATICBORDERDETECTION 0x1150 /* Added 1.8 */ +#define ICAP_AUTOMATICDESKEW 0x1151 /* Added 1.8 */ +#define ICAP_AUTOMATICROTATE 0x1152 /* Added 1.8 */ +#define ICAP_JPEGQUALITY 0x1153 /* Added 1.9 */ + +/* image data sources MAY support these audio caps */ +#define ACAP_AUDIOFILEFORMAT 0x1201 /* Added 1.8 */ +#define ACAP_XFERMECH 0x1202 /* Added 1.8 */ + +/* ----------------------------------------------------------------------- *\ + + Version 1.7: Following is Extended Image Info Attributes. + July 1997 + KHL + +\* ----------------------------------------------------------------------- */ + +#define TWEI_BARCODEX 0x1200 +#define TWEI_BARCODEY 0x1201 +#define TWEI_BARCODETEXT 0x1202 +#define TWEI_BARCODETYPE 0x1203 +#define TWEI_DESHADETOP 0x1204 +#define TWEI_DESHADELEFT 0x1205 +#define TWEI_DESHADEHEIGHT 0x1206 +#define TWEI_DESHADEWIDTH 0x1207 +#define TWEI_DESHADESIZE 0x1208 +#define TWEI_SPECKLESREMOVED 0x1209 +#define TWEI_HORZLINEXCOORD 0x120A +#define TWEI_HORZLINEYCOORD 0x120B +#define TWEI_HORZLINELENGTH 0x120C +#define TWEI_HORZLINETHICKNESS 0x120D +#define TWEI_VERTLINEXCOORD 0x120E +#define TWEI_VERTLINEYCOORD 0x120F +#define TWEI_VERTLINELENGTH 0x1210 +#define TWEI_VERTLINETHICKNESS 0x1211 +#define TWEI_PATCHCODE 0x1212 +#define TWEI_ENDORSEDTEXT 0x1213 +#define TWEI_FORMCONFIDENCE 0x1214 +#define TWEI_FORMTEMPLATEMATCH 0x1215 +#define TWEI_FORMTEMPLATEPAGEMATCH 0x1216 +#define TWEI_FORMHORZDOCOFFSET 0x1217 +#define TWEI_FORMVERTDOCOFFSET 0x1218 +#define TWEI_BARCODECOUNT 0x1219 +#define TWEI_BARCODECONFIDENCE 0x121A +#define TWEI_BARCODEROTATION 0x121B +#define TWEI_BARCODETEXTLENGTH 0x121C +#define TWEI_DESHADECOUNT 0x121D +#define TWEI_DESHADEBLACKCOUNTOLD 0x121E +#define TWEI_DESHADEBLACKCOUNTNEW 0x121F +#define TWEI_DESHADEBLACKRLMIN 0x1220 +#define TWEI_DESHADEBLACKRLMAX 0x1221 +#define TWEI_DESHADEWHITECOUNTOLD 0x1222 +#define TWEI_DESHADEWHITECOUNTNEW 0x1223 +#define TWEI_DESHADEWHITERLMIN 0x1224 +#define TWEI_DESHADEWHITERLAVE 0x1225 +#define TWEI_DESHADEWHITERLMAX 0x1226 +#define TWEI_BLACKSPECKLESREMOVED 0x1227 +#define TWEI_WHITESPECKLESREMOVED 0x1228 +#define TWEI_HORZLINECOUNT 0x1229 +#define TWEI_VERTLINECOUNT 0x122A +#define TWEI_DESKEWSTATUS 0x122B +#define TWEI_SKEWORIGINALANGLE 0x122C +#define TWEI_SKEWFINALANGLE 0x122D +#define TWEI_SKEWCONFIDENCE 0x122E +#define TWEI_SKEWWINDOWX1 0x122F +#define TWEI_SKEWWINDOWY1 0x1230 +#define TWEI_SKEWWINDOWX2 0x1231 +#define TWEI_SKEWWINDOWY2 0x1232 +#define TWEI_SKEWWINDOWX3 0x1233 +#define TWEI_SKEWWINDOWY3 0x1234 +#define TWEI_SKEWWINDOWX4 0x1235 +#define TWEI_SKEWWINDOWY4 0x1236 +#define TWEI_BOOKNAME 0x1238 /* added 1.9 */ +#define TWEI_CHAPTERNUMBER 0x1239 /* added 1.9 */ +#define TWEI_DOCUMENTNUMBER 0x123A /* added 1.9 */ +#define TWEI_PAGENUMBER 0x123B /* added 1.9 */ +#define TWEI_CAMERA 0x123C /* added 1.9 */ +#define TWEI_FRAMENUMBER 0x123D /* added 1.9 */ +#define TWEI_FRAME 0x123E /* added 1.9 */ +#define TWEI_PIXELFLAVOR 0x123F /* added 1.9 */ + +#define TWEJ_NONE 0x0000 +#define TWEJ_MIDSEPARATOR 0x0001 +#define TWEJ_PATCH1 0x0002 +#define TWEJ_PATCH2 0x0003 +#define TWEJ_PATCH3 0x0004 +#define TWEJ_PATCH4 0x0005 +#define TWEJ_PATCH6 0x0006 +#define TWEJ_PATCHT 0x0007 + +/* Added 1.8 */ +/* TW_PASSTHRU.Direction values */ +#define TWDR_GET 1 +#define TWDR_SET 2 + +/*************************************************************************** + * Return Codes and Condition Codes section * + ***************************************************************************/ + +/* Return Codes: DSM_Entry and DS_Entry may return any one of these values. */ +#define TWRC_CUSTOMBASE 0x8000 + +#define TWRC_SUCCESS 0 +#define TWRC_FAILURE 1 /* Application may get TW_STATUS for info on failure */ +#define TWRC_CHECKSTATUS 2 /* "tried hard"; get status */ +#define TWRC_CANCEL 3 +#define TWRC_DSEVENT 4 +#define TWRC_NOTDSEVENT 5 +#define TWRC_XFERDONE 6 +#define TWRC_ENDOFLIST 7 /* After MSG_GETNEXT if nothing left */ +#define TWRC_INFONOTSUPPORTED 8 +#define TWRC_DATANOTAVAILABLE 9 + +/* Condition Codes: Application gets these by doing DG_CONTROL DAT_STATUS MSG_GET. */ +#define TWCC_CUSTOMBASE 0x8000 + +#define TWCC_SUCCESS 0 /* It worked! */ +#define TWCC_BUMMER 1 /* Failure due to unknown causes */ +#define TWCC_LOWMEMORY 2 /* Not enough memory to perform operation */ +#define TWCC_NODS 3 /* No Data Source */ +#define TWCC_MAXCONNECTIONS 4 /* DS is connected to max possible applications */ +#define TWCC_OPERATIONERROR 5 /* DS or DSM reported error, application shouldn't */ +#define TWCC_BADCAP 6 /* Unknown capability */ +#define TWCC_BADPROTOCOL 9 /* Unrecognized MSG DG DAT combination */ +#define TWCC_BADVALUE 10 /* Data parameter out of range */ +#define TWCC_SEQERROR 11 /* DG DAT MSG out of expected sequence */ +#define TWCC_BADDEST 12 /* Unknown destination Application/Source in DSM_Entry */ +#define TWCC_CAPUNSUPPORTED 13 /* Capability not supported by source */ +#define TWCC_CAPBADOPERATION 14 /* Operation not supported by capability */ +#define TWCC_CAPSEQERROR 15 /* Capability has dependancy on other capability */ +/* Added 1.8 */ +#define TWCC_DENIED 16 /* File System operation is denied (file is protected) */ +#define TWCC_FILEEXISTS 17 /* Operation failed because file already exists. */ +#define TWCC_FILENOTFOUND 18 /* File not found */ +#define TWCC_NOTEMPTY 19 /* Operation failed because directory is not empty */ +#define TWCC_PAPERJAM 20 /* The feeder is jammed */ +#define TWCC_PAPERDOUBLEFEED 21 /* The feeder detected multiple pages */ +#define TWCC_FILEWRITEERROR 22 /* Error writing the file (meant for things like disk full conditions) */ +#define TWCC_CHECKDEVICEONLINE 23 /* The device went offline prior to or during this operation */ + + +/* bit patterns: for query the operation that are supported by the data source on a capability */ +/* Application gets these through DG_CONTROL/DAT_CAPABILITY/MSG_QUERYSUPPORT */ +/* Added 1.6 */ +#define TWQC_GET 0x0001 +#define TWQC_SET 0x0002 +#define TWQC_GETDEFAULT 0x0004 +#define TWQC_GETCURRENT 0x0008 +#define TWQC_RESET 0x0010 + + +/**************************************************************************** + * Entry Points * + ****************************************************************************/ + +/********************************************************************** + * Function: DSM_Entry, the only entry point into the Data Source Manager. + * + * Parameters: + * pOrigin Identifies the source module of the message. This could + * identify an Application, a Source, or the Source Manager. + * + * pDest Identifies the destination module for the message. + * This could identify an application or a data source. + * If this is NULL, the message goes to the Source Manager. + * + * DG The Data Group. + * Example: DG_IMAGE. + * + * DAT The Data Attribute Type. + * Example: DAT_IMAGEMEMXFER. + * + * MSG The message. Messages are interpreted by the destination module + * with respect to the Data Group and the Data Attribute Type. + * Example: MSG_GET. + * + * pData A pointer to the data structure or variable identified + * by the Data Attribute Type. + * Example: (TW_MEMREF)&ImageMemXfer + * where ImageMemXfer is a TW_IMAGEMEMXFER structure. + * + * Returns: + * ReturnCode + * Example: TWRC_SUCCESS. + * + ********************************************************************/ + +/* Don't mangle the name "DSM_Entry" if we're compiling in C++! */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _MSWIN_ +TW_UINT16 FAR PASCAL DSM_Entry( pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +typedef TW_UINT16 (FAR PASCAL *DSMENTRYPROC)(pTW_IDENTITY, pTW_IDENTITY, + TW_UINT32, TW_UINT16, + TW_UINT16, TW_MEMREF); +#else /* _MSWIN_ */ + +FAR PASCAL TW_UINT16 DSM_Entry( pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +typedef TW_UINT16 (*DSMENTRYPROC)(pTW_IDENTITY, pTW_IDENTITY, + TW_UINT32, TW_UINT16, + TW_UINT16, TW_MEMREF); +#endif /* _MSWIN_ */ + +#ifdef __cplusplus +} +#endif /* cplusplus */ + + +/********************************************************************** + * Function: DS_Entry, the entry point provided by a Data Source. + * + * Parameters: + * pOrigin Identifies the source module of the message. This could + * identify an application or the Data Source Manager. + * + * DG The Data Group. + * Example: DG_IMAGE. + * + * DAT The Data Attribute Type. + * Example: DAT_IMAGEMEMXFER. + * + * MSG The message. Messages are interpreted by the data source + * with respect to the Data Group and the Data Attribute Type. + * Example: MSG_GET. + * + * pData A pointer to the data structure or variable identified + * by the Data Attribute Type. + * Example: (TW_MEMREF)&ImageMemXfer + * where ImageMemXfer is a TW_IMAGEMEMXFER structure. + * + * Returns: + * ReturnCode + * Example: TWRC_SUCCESS. + * + * Note: + * The DSPROC type is only used by an application when it calls + * a Data Source directly, bypassing the Data Source Manager. + * + ********************************************************************/ +/* Don't mangle the name "DS_Entry" if we're compiling in C++! */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _MSWIN_ + #ifdef _WIN32 + __declspec(dllexport) TW_UINT16 FAR PASCAL DS_Entry (pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + #else /* _WIN32 */ + TW_UINT16 FAR PASCAL DS_Entry (pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + #endif /* _WIN32 */ + + typedef TW_UINT16 (FAR PASCAL *DSENTRYPROC) (pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); +#else /* _MSWIN_ */ +FAR PASCAL TW_UINT16 DS_Entry( pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +typedef TW_UINT16 (*DSENTRYPROC)(pTW_IDENTITY, + TW_UINT32, TW_UINT16, + TW_UINT16, TW_MEMREF); +#endif /* _MSWIN_ */ + +#ifdef __cplusplus +} +#endif /* cplusplus */ + +/* SDH - 02/08/95 - TWUNK */ +/* Force 32-bit twain to use same packing of twain structures as existing */ +/* 16-bit twain. This allows 16/32-bit thunking. */ +#ifdef WIN32 + #ifdef __MINGW32__ + #pragma pack (pop) + #elif __BORLANDC__ //(Mentor June 13, 1996) if we're using a Borland compiler + #pragma option -a. //(Mentor October 30, 1996) switch back to original alignment + #else //(Mentor June 13, 1996) if NOT using a Borland compiler + #pragma pack (pop, before_twain) + #endif //(Mentor June 13, 1996) +#else /* WIN32 */ +#endif /* WIN32 */ + +#endif /* TWAIN */ diff --git a/libksane/ksanetwain/twainiface.cpp b/libksane/ksanetwain/twainiface.cpp new file mode 100644 index 00000000..0eaf4d1f --- /dev/null +++ b/libksane/ksanetwain/twainiface.cpp @@ -0,0 +1,595 @@ +/* ============================================================ + * + * This file is a part of kdegraphics + * + * Date : 2009-05-12 + * Description : Twain interface + * + * Copyright (C) 2002-2003 Stephan Stapel + * Copyright (C) 2008-2009 by Gilles Caulier + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + + // I renamed the class to KSaneWidgetPrivate to remove + // the need for a wrapper class with this name. (Kare) + +#include "twainiface.moc" +#include "ksane.h" + +#define TWCPP_ANYCOUNT (-1) +#define TWCPP_CANCELTHIS (1) +#define TWCPP_CANCELALL (2) +#define TWCPP_DOTRANSFER (0) + +#include +#include + +#include + +namespace KSaneIface +{ + +KSaneWidgetPrivate::KSaneWidgetPrivate(): QWidget(0) +{ + // This is a dumy widget not visible. We use Qwidget to dispatch Windows event to + // Twain interface. This is not possible to do it using QObject as well. + + m_hMessageWnd = 0; + m_hTwainDLL = NULL; + m_pDSMProc = NULL; + m_bDSOpen = false; + m_bDSMOpen = false; + m_bSourceEnabled = false; + m_bModalUI = true; + m_nImageCount = TWCPP_ANYCOUNT; + + InitTwain(); +} + +KSaneWidgetPrivate::~KSaneWidgetPrivate() +{ + ReleaseTwain(); +} + +bool KSaneWidgetPrivate::winEvent(MSG* pMsg, long* result) +{ + return ProcessMessage(*pMsg); +} + +/** Initializes TWAIN interface . Is already called from the constructor. + It should be called again if ReleaseTwain is called. + hWnd is the window which has to subclassed in order to receive + Twain messaged. Normally - this would be your main application window. + */ +bool KSaneWidgetPrivate::InitTwain() +{ + char libName[512]; + + if((m_hTwainDLL && m_pDSMProc)) { + return true; + } + + memset(&m_AppId,0,sizeof(m_AppId)); + + if(!IsWindow(this->winId())) { + return false; + } + + m_hMessageWnd = this->winId(); + strcpy(libName, "TWAIN_32.DLL"); + + m_hTwainDLL = LoadLibraryA(libName); + if(m_hTwainDLL != NULL) + { + if(!(m_pDSMProc = (DSMENTRYPROC)GetProcAddress(m_hTwainDLL, (LPCSTR)MAKEINTRESOURCE(1)))) + { + FreeLibrary(m_hTwainDLL); + m_hTwainDLL = NULL; + } + } + + if((m_hTwainDLL && m_pDSMProc)) + { + // Expects all the fields in m_AppId to be set except for the id field. + m_AppId.Id = 0; // Initialize to 0 (Source Manager will assign real value) + m_AppId.Version.MajorNum = 0; // Your app's version number + m_AppId.Version.MinorNum = 2; + m_AppId.Version.Language = TWLG_USA; + m_AppId.Version.Country = TWCY_USA; + strcpy(m_AppId.Version.Info, "libksane"); + + m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR; + m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR; + m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL; + strcpy(m_AppId.Manufacturer, "KDE"); + strcpy(m_AppId.ProductFamily, "Generic"); + strcpy(m_AppId.ProductName, "libksane"); + + m_bDSMOpen= CallTwainProc(&m_AppId, NULL, DG_CONTROL, + DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&m_hMessageWnd); + return true; + } + else { + return false; + } +} + +/** Releases the twain interface . Need not be called unless you + want to specifically shut it down. + */ +void KSaneWidgetPrivate::ReleaseTwain() +{ + if((m_hTwainDLL && m_pDSMProc)) + { + CloseDSM(); + FreeLibrary(m_hTwainDLL); + m_hTwainDLL = NULL; + m_pDSMProc = NULL; + } +} + +/** Entry point into Twain. For a complete description of this + routine please refer to the Twain specification 1.8 + */ +bool KSaneWidgetPrivate::CallTwainProc(pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, + TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData) +{ + if (!(m_hTwainDLL && m_pDSMProc)) { + m_returnCode = TWRC_FAILURE; + return false; + } + + m_returnCode = (*m_pDSMProc)(pOrigin, pDest, DG, DAT, MSG, pData); + + if(m_returnCode == TWRC_FAILURE) { + (*m_pDSMProc)(pOrigin, pDest, DG_CONTROL, DAT_STATUS, MSG_GET, &m_Status); + } + return (m_returnCode == TWRC_SUCCESS); +} + +/** Called to display a dialog box to select the Twain source to use. + This can be overridden if a list of all sources is available + to the application. These sources can be enumerated by Twain. + it is not yet supportted by KSaneWidgetPrivate. + */ +QString KSaneWidgetPrivate::SelectSource() +{ + TW_IDENTITY src; + memset(&src, 0, sizeof(src)); + + // debug printouts + bool ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &src); + while (ret_ok) { + ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &src); + } + + // set the default entry selected + CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &src); + + // now open the selection dialog + if (!CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &src)) { + return QString(); + } + + QString source; + source += src.ProductName; + source += ';'; + source += src.ProductFamily; + source += ';'; + source += src.Manufacturer; + //qDebug()<< source; + return source; +} + +/** Closes the Data Source + */ +void KSaneWidgetPrivate::CloseDS() +{ + if(DSOpen()) { + if(m_bSourceEnabled) { + TW_USERINTERFACE twUI; + if(CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_USERINTERFACE, MSG_DISABLEDS, &twUI)) { + m_bSourceEnabled = false; + } + } + CallTwainProc(&m_AppId, NULL, DG_CONTROL, + DAT_IDENTITY, MSG_CLOSEDS, (TW_MEMREF)&m_Source); + m_bDSOpen = false; + } +} + +/** Closes the Data Source Manager */ +void KSaneWidgetPrivate::CloseDSM() +{ + if(m_hTwainDLL && m_pDSMProc && m_bDSMOpen) { + CloseDS(); + CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF)&m_hMessageWnd); + m_bDSMOpen = false; + } +} + +/** Returns true if the Data Source is Open */ +bool KSaneWidgetPrivate::DSOpen() const +{ + //qDebug() << m_hTwainDLL << m_pDSMProc << m_bDSMOpen << m_bDSOpen; + return (m_hTwainDLL && m_pDSMProc) && m_bDSMOpen && m_bDSOpen; +} + +/** Opens a Data Source */ +bool KSaneWidgetPrivate::OpenSource(const QString &source) +{ + if (source.isEmpty()) { + return false; + } + + QStringList splited = source.split(';'); + if (splited.size() != 3) { + return false; + } + + // go thorough the list and check if the source is available + bool ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &m_Source); + while (ret_ok) { + //qDebug() << m_Source.Id << m_Source.Version.MajorNum << m_Source.Version.MinorNum; + //qDebug() << m_Source.Manufacturer << m_Source.ProductFamily << m_Source.ProductName; + if (QString(m_Source.ProductName) == splited[0]) break; + ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &m_Source); + } + + if (!ret_ok) { + // CallTwainProc failed when reading beyond the last source + return false; + } + + // open the source + if (m_hTwainDLL && m_pDSMProc && m_bDSMOpen) { + m_bDSOpen = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, (TW_MEMREF)&m_Source); + //qDebug() << "OpenSource(qst..) m_bDSOpen" << m_bDSOpen; + } + + SetImageCount(TWCPP_ANYCOUNT); + + return DSOpen(); +} + +/** Re-Opens a Data Source */ +bool KSaneWidgetPrivate::ReOpenDialog() +{ + //qDebug() << "ReOpenSource:" << m_hTwainDLL << m_pDSMProc << m_bDSMOpen << m_bDSOpen; + + if (DSOpen()) { + // already open + return true; + } + // open the source + if (m_hTwainDLL && m_pDSMProc && m_bDSMOpen) { + m_bDSOpen = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, (TW_MEMREF)&m_Source); + //qDebug() << "ReOpenSource() m_bDSOpen" << m_bDSOpen; + } + + SetImageCount(TWCPP_ANYCOUNT); + + if (DSOpen()) { + return EnableSource(true); + } + //else + return false; +} + + +/** Should be called from the main message loop of the application. Can always be called, + it will not process the message unless a scan is in progress. */ +bool KSaneWidgetPrivate::ProcessMessage(MSG msg) +{ + // TODO: don't really know why... + if (msg.message == 528) return false; + + if (m_hMessageWnd == 0) return false; + + if(m_bSourceEnabled) { + TW_UINT16 twRC = TWRC_NOTDSEVENT; + + TW_EVENT twEvent; + twEvent.pEvent = (TW_MEMREF)&msg; + //memset(&twEvent, 0, sizeof(TW_EVENT)); + twEvent.TWMessage = MSG_NULL; + + CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_EVENT, MSG_PROCESSEVENT, (TW_MEMREF)&twEvent); + + if(m_returnCode != TWRC_NOTDSEVENT) { + TranslateMessage(twEvent); + } + return (twRC==TWRC_DSEVENT); + } + return false; +} + +/** Queries the capability of the Twain Data Source */ +bool KSaneWidgetPrivate::GetCapability(TW_CAPABILITY& twCap, TW_UINT16 cap, TW_UINT16 conType) +{ + if(DSOpen()) + { + twCap.Cap = cap; + twCap.ConType = conType; + twCap.hContainer = NULL; + + if(CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_CAPABILITY, MSG_GET, (TW_MEMREF)&twCap)) + { + return true; + } + } + return false; +} + +/** Queries the capability of the Twain Data Source */ +bool KSaneWidgetPrivate::GetCapability(TW_UINT16 cap, TW_UINT32& value) +{ + TW_CAPABILITY twCap; + if(GetCapability(twCap, cap)) + { + pTW_ONEVALUE pVal; + pVal = (pTW_ONEVALUE )GlobalLock(twCap.hContainer); + + if(pVal) + { + value = pVal->Item; + GlobalUnlock(pVal); + GlobalFree(twCap.hContainer); + return true; + } + } + return false; +} + +/** Sets the capability of the Twain Data Source */ +bool KSaneWidgetPrivate::SetCapability(TW_UINT16 cap, TW_UINT16 value, bool sign) +{ + if(DSOpen()) { + TW_CAPABILITY twCap; + pTW_ONEVALUE pVal; + bool ret_value = false; + twCap.Cap = cap; + twCap.ConType = TWON_ONEVALUE; + twCap.hContainer = GlobalAlloc(GHND,sizeof(TW_ONEVALUE)); + + if(twCap.hContainer) { + pVal = (pTW_ONEVALUE)GlobalLock(twCap.hContainer); + pVal->ItemType = sign ? TWTY_INT16 : TWTY_UINT16; + pVal->Item = (TW_UINT32)value; + GlobalUnlock(twCap.hContainer); + ret_value = SetCapability(twCap); + GlobalFree(twCap.hContainer); + } + return ret_value; + } + return false; +} + +/** Sets the capability of the Twain Data Source */ +bool KSaneWidgetPrivate::SetCapability(TW_CAPABILITY& cap) +{ + if(DSOpen()) { + return CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_CAPABILITY, MSG_SET, (TW_MEMREF)&cap); + } + return false; +} + +/** Sets the number of images which can be accpeted by the application at one time */ +bool KSaneWidgetPrivate::SetImageCount(TW_INT16 nCount) +{ + if(SetCapability(CAP_XFERCOUNT,(TW_UINT16)nCount,true)) { + m_nImageCount = nCount; + return true; + } + else { + if(m_returnCode == TWRC_CHECKSTATUS) { + TW_UINT32 count = 0; + + if(GetCapability(CAP_XFERCOUNT, count)) { + nCount = (TW_INT16)count; + + if(SetCapability(CAP_XFERCOUNT, nCount)) { + m_nImageCount = nCount; + return true; + } + } + } + } + return false; +} + +/** Called to enable the Twain Acquire Dialog. This too can be + * overridden but is a helluva job. */ +bool KSaneWidgetPrivate::OpenDialog() +{ + EnableSource(true); + return true; +} + +/** Called to enable the Twain Acquire Dialog. This too can be + * overridden but is a helluva job. */ +bool KSaneWidgetPrivate::EnableSource(bool showUI) +{ + //qDebug() << "DSOpen() =" << DSOpen(); + if(DSOpen() && !m_bSourceEnabled) { + TW_USERINTERFACE twUI; + twUI.ShowUI = showUI; + twUI.hParent = (TW_HANDLE)m_hMessageWnd; + + if(CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI)) + { + m_bSourceEnabled = true; + m_bModalUI = twUI.ModalUI; + } + else { + m_bSourceEnabled = false; + m_bModalUI = true; + } + //qDebug() << "EnableSource:ModalUI=" << twUI.ModalUI; + return m_bSourceEnabled; + } + return false; +} + +/** Called by ProcessMessage to Translate a TWAIN message */ +void KSaneWidgetPrivate::TranslateMessage(TW_EVENT& twEvent) +{ + switch(twEvent.TWMessage) + { + case MSG_XFERREADY: + //qDebug() << "MSG_XFERREADY"; + TransferImage(); + break; + + case MSG_CLOSEDSREQ: + //qDebug() << "MSG_CLOSEDSREQ"; + CloseDS(); + break; + } +} + +/** Gets Imageinfo for an image which is about to be transferred. */ +bool KSaneWidgetPrivate::GetImageInfo(TW_IMAGEINFO& info) +{ + if(m_bSourceEnabled) { + return CallTwainProc(&m_AppId, &m_Source, DG_IMAGE, + DAT_IMAGEINFO, MSG_GET, (TW_MEMREF)&info); + } + return false; +} + +/** Transfers the image or cancels the transfer depending on the state of the TWAIN system */ +void KSaneWidgetPrivate::TransferImage() +{ + TW_IMAGEINFO info; + bool bContinue=true; + + while(bContinue) { + if(GetImageInfo(info)) { + int permission = TWCPP_DOTRANSFER; + + switch(permission) + { + case TWCPP_CANCELTHIS: + bContinue=EndTransfer(); + break; + + case TWCPP_CANCELALL: + CancelTransfer(); + bContinue=false; + break; + + case TWCPP_DOTRANSFER: + bContinue=GetImage(info); + break; + } + } + } +} + +/** Ends the current transfer. + Returns true if the more images are pending */ +bool KSaneWidgetPrivate::EndTransfer() +{ + TW_PENDINGXFERS twPend; + if(CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, + DAT_PENDINGXFERS, MSG_ENDXFER, (TW_MEMREF)&twPend)) + { + return twPend.Count != 0; + } + return false; +} + +/** Aborts all transfers */ +void KSaneWidgetPrivate::CancelTransfer() +{ + TW_PENDINGXFERS twPend; + CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, (TW_MEMREF)&twPend); +} + +/** Calls TWAIN to actually get the image */ +bool KSaneWidgetPrivate::GetImage(TW_IMAGEINFO& info) +{ + TW_MEMREF pdata; + CallTwainProc(&m_AppId, &m_Source, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &pdata); + + switch(m_returnCode) + { + case TWRC_XFERDONE: + //qDebug()<< "GetImage:TWRC_XFERDONE"; + ImageData(pdata, info); + break; + + case TWRC_CANCEL: + //qDebug()<< "GetImage:TWRC_CANCEL"; + break; + + case TWRC_FAILURE: + //qDebug()<< "GetImage:TWRC_FAILURE"; + CancelTransfer(); + return false; + break; + } + + GlobalFree(pdata); + return EndTransfer(); +} + +void KSaneWidgetPrivate::ImageData(TW_MEMREF pdata, TW_IMAGEINFO& info) +{ + if (pdata && (info.ImageWidth != -1) && (info.ImageLength != - 1)) + { + // Under Windows, Twain interface return a DIB data structure. + // See http://en.wikipedia.org/wiki/Device-independent_bitmap#DIBs_in_memory for details. + HGLOBAL hDIB = (HGLOBAL)(qptrdiff)pdata; + int size = (int)GlobalSize(hDIB); + const char* bits = (const char*)GlobalLock(hDIB); + + // DIB is BMP without header. we will add it to load data in QImage using std loader from Qt. + QByteArray baBmp; + QDataStream ds(&baBmp, QIODevice::WriteOnly); + + ds.writeRawData("BM", 2); + + qint32 filesize = size + 14; + ds << filesize; + + qint16 reserved = 0; + ds << reserved; + ds << reserved; + + qint32 pixOffset = 14 + 40 + 0; + ds << pixOffset; + + ds.writeRawData(bits, size); + + emit ImageReady(baBmp, 0,0,0, (int)KSaneWidget::FormatBMP); + + GlobalUnlock(hDIB); + + } +} + +} // namespace KSaneIface diff --git a/libksane/ksanetwain/twainiface.h b/libksane/ksanetwain/twainiface.h new file mode 100644 index 00000000..2dbad17b --- /dev/null +++ b/libksane/ksanetwain/twainiface.h @@ -0,0 +1,127 @@ +/* ============================================================ + * + * This file is a part of kdegraphics + * + * Date : 2009-05-12 + * Description : Twain interface + * + * Copyright (C) 2002-2003 Stephan Stapel + * Copyright (C) 2008-2009 by Gilles Caulier + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef TWAINIFACE_H +#define TWAINIFACE_H + +#include "twain.h" + +// Windows includes +#include + +#include + +namespace KSaneIface +{ + +class KSaneWidgetPrivate : public QWidget +{ + Q_OBJECT + +public: + + KSaneWidgetPrivate(); + ~KSaneWidgetPrivate(); + + /** + * Hook-in. See class documentation for details! + * @result One should return false to get the message being + * processed by the application (should return false by default!) + */ + bool winEvent(MSG* pMsg, long *result); + + void CloseDSM(); + QString SelectSource(); + bool OpenSource(const QString &device); + +public Q_SLOTS: + + bool OpenDialog(); + bool ReOpenDialog(); + + +Q_SIGNALS: + + void ImageReady(QByteArray &data, int width, int height, int bytes_per_line, int format); + +private: + + bool InitTwain(); + void ReleaseTwain(); + + bool ProcessMessage(MSG msg); + + bool SetImageCount(TW_INT16 nCount=1); + bool DSOpen() const; + + + bool CallTwainProc(pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, + TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, + TW_MEMREF pData); + + bool EnableSource(bool showUI); + void CloseDS(); + + bool GetCapability(TW_CAPABILITY& twCap, TW_UINT16 cap, TW_UINT16 conType=TWON_DONTCARE16); + bool GetCapability(TW_UINT16 cap, TW_UINT32& value); + bool SetCapability(TW_UINT16 cap, TW_UINT16 value, bool sign=false); + bool SetCapability(TW_CAPABILITY& twCap); + + bool GetImageInfo(TW_IMAGEINFO& info); + + void TranslateMessage(TW_EVENT& twEvent); + void TransferImage(); + bool EndTransfer(); + void CancelTransfer(); + bool GetImage(TW_IMAGEINFO& info); + + void ImageData(TW_MEMREF pdata, TW_IMAGEINFO& info); + +protected: + + bool m_bDSMOpen; + bool m_bDSOpen; + bool m_bSourceEnabled; + bool m_bModalUI; + + int m_nImageCount; + + HINSTANCE m_hTwainDLL; + DSMENTRYPROC m_pDSMProc; + + TW_IDENTITY m_AppId; + TW_IDENTITY m_Source; + TW_STATUS m_Status; + TW_INT16 m_returnCode; + HWND m_hMessageWnd; +}; + +} // namespace KSaneIface + +#endif /* TWAINIFACE_H */ diff --git a/libksane/libksane/CMakeLists.txt b/libksane/libksane/CMakeLists.txt new file mode 100644 index 00000000..41ba6ba0 --- /dev/null +++ b/libksane/libksane/CMakeLists.txt @@ -0,0 +1,79 @@ + +INCLUDE_DIRECTORIES(${SANE_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/options + ${CMAKE_CURRENT_SOURCE_DIR}/widgets +) + +SET(ksane_LIB_SRCS + widgets/gamma_disp.cpp + widgets/labeled_gamma.cpp + widgets/labeled_checkbox.cpp + widgets/labeled_entry.cpp + widgets/labeled_combo.cpp + widgets/labeled_fslider.cpp + widgets/labeled_slider.cpp + widgets/ksane_button.cpp + widgets/ksane_option_widget.cpp + ksane_viewer.cpp + selectionitem.cpp + ksane_device_dialog.cpp + ksane_find_devices_thread.cpp + ksane_widget.cpp + ksane_scan_thread.cpp + ksane_preview_thread.cpp + ksane_widget_private.cpp + splittercollapser.cpp + ksane_auth.cpp + options/ksane_option.cpp + options/ksane_opt_button.cpp + options/ksane_opt_checkbox.cpp + options/ksane_opt_entry.cpp + options/ksane_opt_gamma.cpp + options/ksane_opt_slider.cpp + options/ksane_opt_fslider.cpp + options/ksane_opt_combo.cpp + ) + +KDE4_ADD_LIBRARY(ksane SHARED ${ksane_LIB_SRCS}) + +TARGET_LINK_LIBRARIES(ksane ${KDE4_KDEUI_LIBS} + ${SANE_LIBRARY} + ) + +SET_TARGET_PROPERTIES(ksane PROPERTIES VERSION ${KSANE_LIB_SO_VERSION_STRING} SOVERSION ${KSANE_LIB_SO_CUR_VERSION}) + +OPTION(COMPILE_VIEWER_TESTAPP "Compile a small test application for the viewer") + +IF (COMPILE_VIEWER_TESTAPP) + message("Compile testapp") + kde4_add_executable(viewer_test ksane_viewer.cpp ksane_viewer_test.cpp selectionitem.cpp) + target_link_libraries(viewer_test ${KDE4_KDEUI_LIBS}) +ENDIF() + +INSTALL(TARGETS ksane ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +CONFIGURE_FILE(../cmake/templates/KSaneConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/KSaneConfig.cmake @ONLY) + +# Check if compilation is done through digiKam SC or not. If yes, do not install header files. +IF (NOT DIGIKAMSC_COMPILE_LIBKSANE) + + INSTALL(FILES ksane.h + libksane_export.h + ${CMAKE_CURRENT_BINARY_DIR}/version.h + DESTINATION ${INCLUDE_INSTALL_DIR}/libksane COMPONENT Devel) + + IF(NOT WIN32) + CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake/templates/libksane.pc.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libksane.pc) + CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake/templates/libksane.lsm.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libksane.lsm) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libksane.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig ) + ENDIF(NOT WIN32) + + # Install find cmake script to the system for client applications. + + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/KSaneConfig.cmake + DESTINATION ${LIB_INSTALL_DIR}/cmake/KSane) + +ENDIF() + +KDE4_INSTALL_ICONS(${ICON_INSTALL_DIR}) + diff --git a/libksane/libksane/Mainpage.dox b/libksane/libksane/Mainpage.dox new file mode 100644 index 00000000..10214e03 --- /dev/null +++ b/libksane/libksane/Mainpage.dox @@ -0,0 +1,15 @@ +/** @mainpage libKSane + +@brief A library for dealing with scanners + +LibKSane is a KDE interface for SANE library to control flat scanners. + +This library provides a widget to control a scanner, KSaneWidget. Internally, +it will use the SANE library (or +directly use TWAIN on Windows if SANE is not available). + +@see KSaneWidget + +*/ + +// vim:ft=doxygen diff --git a/libksane/libksane/Messages.sh b/libksane/libksane/Messages.sh new file mode 100755 index 00000000..b7b6b3c4 --- /dev/null +++ b/libksane/libksane/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$XGETTEXT `find . -name \*.cpp` ../ksanetwain/*.cpp -o $podir/libksane.pot + diff --git a/libksane/libksane/dummy-hplip.cpp b/libksane/libksane/dummy-hplip.cpp new file mode 100644 index 00000000..c9511425 --- /dev/null +++ b/libksane/libksane/dummy-hplip.cpp @@ -0,0 +1,33 @@ +// krazy:skip +//begin strings from hplip-3.9.2/scan/sane/common.h to make them translatable +I18N_NOOP("None"); +I18N_NOOP("MH"); +I18N_NOOP("MR"); +I18N_NOOP("MMR"); +I18N_NOOP("JPEG"); +I18N_NOOP("Auto"); +I18N_NOOP("Flatbed"); +I18N_NOOP("ADF"); +I18N_NOOP("Advanced"); +I18N_NOOP("Compression"); +I18N_NOOP("Selects the scanner compression "\ + "method for faster scans, possibly at the expense of image quality."); +I18N_NOOP("JPEG compression factor"); +I18N_NOOP("Sets the scanner JPEG compression "\ + "factor. Larger numbers mean better compression, " \ + "and smaller numbers mean better image quality."); +I18N_NOOP("Batch scan"); +I18N_NOOP("Enables continuous scanning with automatic document feeder (ADF)."); +I18N_NOOP("Duplex"); +I18N_NOOP("Enables scanning on both sides of the page."); +I18N_NOOP("Geometry"); +I18N_NOOP("Length measurement"); +I18N_NOOP("Selects how the scanned image "\ + "length is measured and reported, which is impossible to know in advance for scrollfed scans."); +I18N_NOOP("Unknown"); +I18N_NOOP("Unlimited"); +I18N_NOOP("Approximate"); +I18N_NOOP("Padded"); +I18N_NOOP("Exact"); +I18N_NOOP("???"); +//end strings from hplip-3.9.2/scan/sane/common.h to make them translatable diff --git a/libksane/libksane/hi16-action-black-white.png b/libksane/libksane/hi16-action-black-white.png new file mode 100644 index 0000000000000000000000000000000000000000..0b08fc7d1f34c2fba3db4d4171b6bb7e1769f9b8 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx*Bp9q_EZ7UAI14-?iy0WWg+Z8+Vb&Z8pdfpR zr>`sfbrumeWlh1R;s&4)Q literal 0 HcmV?d00001 diff --git a/libksane/libksane/hi16-action-color.png b/libksane/libksane/hi16-action-color.png new file mode 100644 index 0000000000000000000000000000000000000000..3890715d95e53354e41e1f8c454d53f22680bdb2 GIT binary patch literal 803 zcmV+;1Kj+HP)WFU8GbZ8({Xk{QrNlj4iWF>9@00M_eL_t(|+HH?Ls2o)o zhM$=^XZC0A%--C+cdvhFio|k?G^Pqz*hH`i*a$XaV=35aVIhbJ>9sPX2qH)zm4$60 zAp{l?)J8G6H@ohxll`5a-7~(jmvGg*GY{V|ocB5Bc>E`Q?@BINVG) zT;C+w+)cls=2X0YmCc722*+R29$%n20yAJMs9=8u-PQMW%XiX`H^2Q)(6?W`PCL87 znQVt7gVq?r6G5+py(R2E7TJ)_>T>$_`rZ>kKe+uOQT8JT)0nOnoe|Ll8pEyNpwPcL zbp8?}NJhWYS*GblH#I0L8(nR5Z0zr~wODjTrzJr{bB>O_-Mte)>~K-}Qf{k{p!mSM z?)Q6f%!A~4?9OvF;j;x^Zw7lOr%3+!o~t~j-WgDY$IQGVrW_A5<}a9`&nt@tcG;A? z?UC#>iFQM5uMN8`6(vX}l+6uuf2rbQX0$ZJ-V*<1bL?@hZD1}E3yV;*<&(q_(P3j$ zCruU0{V7cqLlvzQMl+zmZ<-^RwrZH2V!DyU!Je_WAYf8E6`TZ`)K6FmbL9BhRw|Sb z=VArB6&!e=1^ac4c7zcn8M!2dC`IKQ?vWWde%Ry;qb0pgt|G88;Cz^>tQXyt35Gv$ z60Ia$>M8I4lDdcHr#h|L>;7l)hR@dqe5;bmE1)5eBFAGY$rvkvVL&Cp`V$l*$eUcP zTfAW`msF+{Gr+PG`sfbrume6$N$q*vCL2*%H@?66gHf+|;}h2Ir#G#FEq$h4Rdj426)4R0VfW-+=ci zs(C<#OiAAEE)4(M`_JqL^5i^S977~7Cnp?WU@NODym>X&I6TL`>gUP!hk6Zc46YUV VtlQtb + * Copyright (C) 2007 by Gilles Caulier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_H +#define KSANE_H + +// Qt includes +#include + +// Local includes +#include "libksane_export.h" + +/** This namespace collects all methods and classes in LibKSane. */ +namespace KSaneIface +{ + +class KSaneWidgetPrivate; + +/** + * This class provides the widget containing the scan options and the preview. + * @author Kare Sars + */ +class LIBKSANE_EXPORT KSaneWidget : public QWidget +{ + Q_OBJECT + friend class KSaneWidgetPrivate; + +public: + /** This enumeration describes the type of the returned data. + * The number of formats might grow, so it is wise to be prepared fro more.*/ + typedef enum + { + FormatBlackWhite, /**< One bit per pixel 1 = black 0 = white */ + FormatGrayScale8, /**< Grayscale with one byte per pixel 0 = black 255 = white */ + FormatGrayScale16, /**< Grayscale withtTwo bytes per pixel. + * The byte order is the one provided by libsane. */ + FormatRGB_8_C, /**< Every pixel consists of three colors in the order Read, + * Grean and Blue, with one byte per color (no alpha channel). */ + FormatRGB_16_C, /**< Every pixel consists of three colors in the order Read, + * Grean and Blue, with two bytes per color(no alpha channel). + * The byte order is the one provided by libsane. */ + FormatBMP, /**< The image data is returned as a BMP. */ + FormatNone = 0xFFFF /**< This enumeration value should never be returned to the user */ + } ImageFormat; + + /** @note There might come more enumerations in the future. */ + typedef enum + { + NoError, /**< The scanning was finished successfully.*/ + ErrorCannotSegment, /**< If this error status is returned libksane can not segment the + * returned data. Scanning without segmentation should work. + * @note segmentation is not implemented yet.*/ + ErrorGeneral, /**< The error string should contain an error message. */ + Information /**< There is some information to the user. */ + } ScanStatus; + + struct DeviceInfo + { + QString name; /* unique device name */ + QString vendor; /* device vendor string */ + QString model; /* device model name */ + QString type; /* device type (e.g., "flatbed scanner") */ + }; + + /** This constructor initializes the private class variables, but the widget is left empty. + * The options and the preview are added with the call to openDevice(). */ + KSaneWidget(QWidget* parent=0); + + /** Standard destructor */ + ~KSaneWidget(); + + /** This helper method displays a dialog for selecting a scanner. The libsane + * device name of the selected scanner device is returned. */ + QString selectDevice(QWidget* parent=0); + + /** + * Get the list of available scanning devices. Connect to availableDevices() + * which is fired once these devices are known. + */ + void initGetDeviceList() const; + + /** This method opens the specified scanner device and adds the scan options to the + * KSane widget. + * @param device_name is the libsane device name for the scanner to open. + * @return 'true' if all goes well and 'false' if the specified scanner can not be opened. */ + bool openDevice(const QString &device_name); + + /** This method closes the currently open scanner device. + * @return 'true' if all goes well and 'false' if no device is open. */ + bool closeDevice(); + + KDE_DEPRECATED bool makeQImage(const QByteArray &, int, int, int, ImageFormat, QImage &); + + /** + * This is a convenience method that can be used to create a QImage from the image data + * returned by the imageReady(...) signal. + * @note: If the image data has 16 bits/color the * data is truncated to 8 bits/color + * since QImage does not support 16 bits/color. A warning message will be shown. + * + * @param data is the byte data containing the image. + * @param width is the width of the image in pixels. + * @param height is the height of the image in pixels. + * @param bytes_per_line is the number of bytes used per line. This might include padding + * and is probably only relevant for 'FormatBlackWhite'. + * @param format is the KSane image format of the data. + * @return This function returns the provided image data as a QImage. */ + QImage toQImage(const QByteArray &data, + int width, + int height, + int bytes_per_line, + ImageFormat format); + + /** + * This is a convenience method that can be used to create a QImage from the image data + * returned by the imageReady(...) signal. + * @note: If the image data has 16 bits/color the * data is truncated to 8 bits/color, but + * unlike toQImage() this function will not give a warning. + * + * @param data is the byte data containing the image. + * @param width is the width of the image in pixels. + * @param height is the height of the image in pixels. + * @param bytes_per_line is the number of bytes used per line. This might include padding + * and is probably only relevant for 'FormatBlackWhite'. + * @param format is the KSane image format of the data. + * @return This function returns the provided image data as a QImage. */ + QImage toQImageSilent(const QByteArray &data, + int width, + int height, + int bytes_per_line, + ImageFormat format); + + /** This method returns the vendor name of the scanner (Same as make). */ + QString vendor() const; + /** This method returns the make name of the scanner. */ + QString make() const; + /** This methos returns the model of the scanner. */ + QString model() const; + + /** This method returns the current resolution of the acquired image, + * in dots per inch. + * @note This function should be called from the slot connected + * to the imageReady signal. The connection should not be queued. + * @return the resolution used for scanning or 0.0 on failure. */ + float currentDPI(); + + /** This method returns the scan area's width in mm + * @return Width of the scannable area in mm */ + float scanAreaWidth(); + + /** This method returns the scan area's height in mm + * @return Height of the scannable area in mm */ + float scanAreaHeight(); + + /** This method sets the selection according to the given points + * @note The points are defined with respect to the scan areas top-left corner in mm + * @param topLeft Upper left corner of the selection (in mm) + * @param bottomRight Lower right corner of the selection (in mm) */ + void setSelection(QPointF topLeft, QPointF bottomRight); + + /** This function is used to set the preferred resolution for scanning the preview. + * @param dpi is the wanted scan resolution for the preview + * @note if the set value is not supported, the cloasest one is used + * @note setting the value 0 means that the default calculated value should be used */ + void setPreviewResolution(float dpi); + + /** This method reads the available parameters and their values and + * returns them in a QMap (Name, value) + * @param opts is a QMap with the parameter names and values. */ + void getOptVals(QMap &opts); + + /** This method can be used to write many parameter values at once. + * @param opts is a QMap with the parameter names and values. + * @return This function returns the number of successful writes. */ + int setOptVals(const QMap &opts); + + /** This function reads one parameter value into a string. + * @param optname is the name of the parameter to read. + * @param value is the string representation of the value. + * @return this function returns true if the read was successful. */ + bool getOptVal(const QString &optname, QString &value); + + /** This function writes one parameter value into a string. + * @param optname is the name of the parameter to write. + * @param value is the string representation of the value. + * @return this function returns true if the write was successful. */ + bool setOptVal(const QString &optname, const QString &value); + + /** This function sets the label on the final scan button + * @param scanLabel is the new label for the button. */ + void setScanButtonText(const QString &scanLabel); + + /** This function sets the label on the preview button + * @param previewLabel is the new label for the button. */ + void setPreviewButtonText(const QString &previewLabel); + + /** This function can be used to enable/disable automatic selections on previews. + * The default state is enabled. + * @param enable specifies if the auto selection should be turned on or off. */ + void enableAutoSelect(bool enable); + + /** This function is used to programatically collapse/restore the options. + * @param collapse defines the state to set. */ + void setOptionsCollapsed(bool collapse); + + /** This function is used hide/show the final scan button. + * @param hidden defines the state to set. */ + void setScanButtonHidden(bool hidden); + +public Q_SLOTS: + /** This method can be used to cancel a scan or prevent an automatic new scan. */ + void scanCancel(); + + /** This method can be used to start a scan (if no GUI is needed). + * @note libksane may return one or more images as a result of one invocation of this slot. + * If no more images are wanted scanCancel should be called in the slot handling the + * imageReady signal. */ + void scanFinal(); + +Q_SIGNALS: + /** + * This Signal is emitted when a final scan is ready. + * @param data is the byte data containing the image. + * @param width is the width of the image in pixels. + * @param height is the height of the image in pixels. + * @param bytes_per_line is the number of bytes used per line. This might include padding + * and is probably only relevant for 'FormatBlackWhite'. + * @param format is the KSane image format of the data. */ + void imageReady(QByteArray &data, int width, int height, + int bytes_per_line, int format); + + /** + * This signal is emitted when the scanning has ended. + * @param status contains a ScanStatus status code. + * @param strStatus If an error has occurred this string will contain an error message. + * otherwise the string is empty. */ + void scanDone(int status, const QString &strStatus); + + /** + * This signal is emitted when the user is to be notified about something. + * @note If no slot is connected to this signal the message will be displayed in a KMessageBox. + * @param type contains a ScanStatus code to identify the type of message (error/info/...). + * @param msg is the message to the user. + * otherwise the string is empty. */ + void userMessage(int type, const QString &strStatus); + + /** + * This Signal is emitted for progress information during a scan. + * The GUI already has a progress bar, but if the GUI is hidden, + * this can be used to display a progress bar. + * @param percent is the percentage of the scan progress (0-100). */ + void scanProgress(int percent); + + /** + * This signal is emitted every time the device list is updated or + * after initGetDeviceList() is called. + * @param deviceList is a QList of KSaneWidget::DeviceInfo that contain the + * device name, model, vendor and type of the attached scanners. + * @note The list is only a snapshot of the current available devices. Devices + * might be added or removed/opened after the signal is emitted. + */ + void availableDevices(const QList &deviceList); + + /** + * This Signal is emitted when a hardware button is pressed. + * @param optionName is the untranslated technical name of the sane-option. + * @param optionLabel is the translated user visible label of the sane-option. + * @param pressed indicates if the value is true or false. + * @note The SANE standard does not specify hardware buttons and their behaviors, + * so this signal is emitted for sane-options that behave like hardware buttons. + * That is the sane-options are read-only and type boolean. The naming of hardware + * buttons also differ from backend to backend. + */ + void buttonPressed(const QString &optionName, const QString &optionLabel, bool pressed); + +private: + + KSaneWidgetPrivate * const d; +}; + +} // NameSpace KSaneIface + +#endif // SANE_WIDGET_H diff --git a/libksane/libksane/ksane_auth.cpp b/libksane/libksane/ksane_auth.cpp new file mode 100644 index 00000000..dc882722 --- /dev/null +++ b/libksane/libksane/ksane_auth.cpp @@ -0,0 +1,136 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2010 +* Description : Sane authentication helpers. +* +* Copyright (C) 2010 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#include "ksane_auth.h" + +// Qt includes +#include +#include + +// KDE includes +#include + +namespace KSaneIface +{ + +static KSaneAuth *s_instance = 0; +static QMutex s_mutex; + +struct KSaneAuth::Private +{ + struct AuthStruct + { + QString resource; + QString username; + QString password; + }; + + QList authList; +}; + +KSaneAuth *KSaneAuth::getInstance() +{ + s_mutex.lock(); + + if (s_instance == 0) { + s_instance = new KSaneAuth(); + } + s_mutex.unlock(); + + return s_instance; +} + +KSaneAuth::KSaneAuth() : d(new Private) {} + +KSaneAuth::~KSaneAuth() +{ + d->authList.clear(); + delete d; +} + +void KSaneAuth::setDeviceAuth(const QString &resource, const QString &username, const QString &password) +{ + // This is a short list so we do not need a QMap... + int i; + for (i=0; iauthList.size(); i++) { + if (resource == d->authList.at(i).resource) { + // update the existing node + d->authList[i].username = username; + d->authList[i].password = password; + break; + } + } + if (i==d->authList.size()) { + // Add a new list node + Private::AuthStruct tmp; + tmp.resource = resource; + tmp.username = username; + tmp.password = password; + d->authList << tmp; + } +} + +void KSaneAuth::clearDeviceAuth(const QString &resource) +{ + // This is a short list so we do not need a QMap... + for (int i=0; iauthList.size(); i++) { + if (resource == d->authList.at(i).resource) { + d->authList.removeAt(i); + return; + } + } +} + +/** static function called by sane_open to get authorization from user */ +void KSaneAuth::authorization(SANE_String_Const resource, SANE_Char *username, SANE_Char *password) +{ + kDebug() << resource; + // This is vague in the standard... what can I find in the resource string? + // I have found that "resource contains the backend name + "$MD5$....." + // it does not contain unique identifiers like ":libusb:001:004" + // -> remove $MD5 and later before comparison... + QString res(resource); + int end = res.indexOf("$MD5$"); + res = res.left(end); + kDebug() << res; + + QList list = getInstance()->d->authList; + for (int i=0; i +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#ifndef KSANE_AUTH_H +#define KSANE_AUTH_H + +// Qt includes +#include + +// Sane includes +extern "C" +{ +#include +#include +} + +namespace KSaneIface +{ + +class KSaneAuth +{ + public: + static KSaneAuth *getInstance(); + ~KSaneAuth(); + + void setDeviceAuth(const QString &resource, const QString &username, const QString &password); + void clearDeviceAuth(const QString &resource); + static void authorization(SANE_String_Const resource, SANE_Char *username, SANE_Char *password); + + private: + KSaneAuth(); + struct Private; + Private * const d; +}; + +} + + +#endif diff --git a/libksane/libksane/ksane_device_dialog.cpp b/libksane/libksane/ksane_device_dialog.cpp new file mode 100644 index 00000000..4c3e6151 --- /dev/null +++ b/libksane/libksane/ksane_device_dialog.cpp @@ -0,0 +1,189 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2008 by Kare Sars + * Copyright (C) 2009 by Grzegorz Kurtyka + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "ksane_device_dialog.h" +#include "ksane_device_dialog.moc" + + +// Sane includes +extern "C" +{ +#include +#include +} + + +// KDE includes +#include +#include + +#include +#include + +namespace KSaneIface +{ + +KSaneDeviceDialog::KSaneDeviceDialog(QWidget *parent) + : KDialog(parent) +{ + + setButtons(KDialog::User1 | KDialog::Ok | KDialog::Cancel); + setButtonText(User1, i18n("Reload devices list")); + + m_btnGroup = new QButtonGroup(this); + + m_btnBox = new QGroupBox; + QVBoxLayout *layout = new QVBoxLayout; + m_btnContainer = new QWidget; + m_btnLayout = new QVBoxLayout(m_btnContainer); + QScrollArea *area = new QScrollArea; + + m_btnBox->setLayout(layout); + + QLabel *explanation = + new QLabel(i18n("The SANE (Scanner Access Now Easy) system could not find any device.
" + "Check that the scanner is plugged in and turned on
" + "or check your systems scanner setup.
" + "For details about SANE see the " + "SANE homepage.")); + explanation->setOpenExternalLinks(true); + int l,t,r,b; + layout->getContentsMargins(&l, &t, &r, &b); + explanation->setContentsMargins(l, t, r, b); + + layout->addWidget(explanation); + m_btnBox->adjustSize(); // make sure to see the complete explanation text + layout->addWidget(area); + layout->setContentsMargins(0,0,0,0); + + area->setWidgetResizable(true); + area->setFrameShape(QFrame::NoFrame); + area->setWidget(m_btnContainer); + + setMainWidget(m_btnBox); + setMinimumHeight(200); + m_findDevThread = FindSaneDevicesThread::getInstance(); + + connect(m_findDevThread, SIGNAL(finished()), this, SLOT(updateDevicesList())); + connect(this, SIGNAL(user1Clicked()), this, SLOT(reloadDevicesList())); + + reloadDevicesList(); +} + +KSaneDeviceDialog::~KSaneDeviceDialog() { + ///@todo wait for thread to finish if its running +} + +void KSaneDeviceDialog::reloadDevicesList() +{ + setAvailable(false); + while (!m_btnGroup->buttons().isEmpty()) { + delete m_btnGroup->buttons().takeFirst(); + } + m_btnBox->setTitle(i18n("Looking for devices. Please wait.")); + m_btnBox->layout()->itemAt(0)->widget()->hide(); // explanation + enableButton(KDialog::User1, false); + + if(!m_findDevThread->isRunning()) { + m_findDevThread->start(); + } +} + +void KSaneDeviceDialog::setAvailable(bool avail) +{ + enableButtonOk(avail); + if(avail) { + m_selectedDevice = getSelectedName(); + setButtonFocus(KDialog::Ok); + } +} + +void KSaneDeviceDialog::setDefault(QString defaultBackend) +{ + m_selectedDevice = defaultBackend; +} + +QString KSaneDeviceDialog::getSelectedName() { + QAbstractButton *selectedButton = m_btnGroup->checkedButton(); + if(selectedButton) { + return selectedButton->objectName(); + } + return QString(); +} + +void KSaneDeviceDialog::updateDevicesList() +{ + while (!m_btnGroup->buttons().isEmpty()) { + delete m_btnGroup->buttons().takeFirst(); + } + + const QList list = m_findDevThread->devicesList(); + if (list.isEmpty()) { + m_btnBox->setTitle(i18n("Sorry. No devices found.")); + m_btnBox->layout()->itemAt(0)->widget()->show(); // explanation + m_btnBox->layout()->itemAt(1)->widget()->hide(); // scroll area + enableButton(KDialog::User1, true); + return; + } + + delete m_btnLayout; + m_btnLayout = new QVBoxLayout; + m_btnContainer->setLayout(m_btnLayout); + m_btnBox->setTitle(i18n("Found devices:")); + m_btnBox->layout()->itemAt(0)->widget()->hide(); // explanation + m_btnBox->layout()->itemAt(1)->widget()->show(); // scroll area + + for (int i=0; i< list.size(); i++) { + QRadioButton *b = new QRadioButton(this); + b->setObjectName(list[i].name); + b->setToolTip(list[i].name); + b->setText(QString("%1 : %2\n%3") + .arg(list[i].vendor) + .arg(list[i].model) + .arg(list[i].name)); + + m_btnLayout->addWidget(b); + m_btnGroup->addButton(b); + connect(b, SIGNAL(clicked(bool)), this, SLOT(setAvailable(bool))); + if((i==0) || (list[i].name == m_selectedDevice)) { + b->setChecked(true); + setAvailable(true); + } + } + + m_btnLayout->addStretch(); + + if(list.size() == 1) { + button(KDialog::Ok)->animateClick(); + } + + enableButton(KDialog::User1, true); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/ksane_device_dialog.h b/libksane/libksane/ksane_device_dialog.h new file mode 100644 index 00000000..ebf42c14 --- /dev/null +++ b/libksane/libksane/ksane_device_dialog.h @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2010 by Kare Sars + * Copyright (C) 2009 by Grzegorz Kurtyka + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_DEVICE_DIALOG_H +#define KSANE_DEVICE_DIALOG_H + +#include "ksane_find_devices_thread.h" + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include + + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +class KSaneDeviceDialog : public KDialog +{ + Q_OBJECT + +public: + + KSaneDeviceDialog(QWidget *parent=0); + ~KSaneDeviceDialog(); + + QString getSelectedName(); + void setDefault(QString); + +public Q_SLOTS: + void reloadDevicesList(); + +private Q_SLOTS: + void setAvailable(bool avail); + void updateDevicesList(); + +private: + QWidget *m_btnContainer; + QGroupBox *m_btnBox; + QButtonGroup *m_btnGroup; + QVBoxLayout *m_btnLayout; + QString m_defaultBackend; + QString m_selectedDevice; + FindSaneDevicesThread *m_findDevThread; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/ksane_find_devices_thread.cpp b/libksane/libksane/ksane_find_devices_thread.cpp new file mode 100644 index 00000000..0a865b6b --- /dev/null +++ b/libksane/libksane/ksane_find_devices_thread.cpp @@ -0,0 +1,107 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Grzegorz Kurtyka + * Copyright (C) 2010 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#include "ksane_find_devices_thread.h" +#include "ksane_find_devices_thread.moc" + +#include "ksane_widget_private.h" + +// Sane includes +extern "C" +{ +#include +#include +} + +// KDE includes +#include + +// Qt includes +#include + +namespace KSaneIface +{ +static FindSaneDevicesThread *s_instancesane = 0; +static QMutex s_mutexsane; + +FindSaneDevicesThread *FindSaneDevicesThread::getInstance() +{ + s_mutexsane.lock(); + + if (s_instancesane == 0) { + s_instancesane = new FindSaneDevicesThread(); + } + s_mutexsane.unlock(); + + return s_instancesane; +} + +FindSaneDevicesThread::FindSaneDevicesThread() : QThread(0) +{ +} + +FindSaneDevicesThread::~FindSaneDevicesThread() +{ + s_mutexsane.lock(); + wait(); + s_mutexsane.unlock(); +} + + +void FindSaneDevicesThread::run() +{ + SANE_Device const **devList; + //SANE_Int version; + SANE_Status status; + + // This is unfortunately not very reliable as many back-ends do not refresh + // the device list after the sane_init() call... + status = sane_get_devices(&devList, SANE_FALSE); + + m_deviceList.clear(); + if (status == SANE_STATUS_GOOD) { + int i = 0; + KSaneWidget::DeviceInfo tmp; + + while(devList[i] != 0) { + tmp.name = devList[i]->name; + tmp.vendor = devList[i]->vendor; + tmp.model = devList[i]->model; + tmp.type = devList[i]->type; + m_deviceList << tmp; + i++; + } + } +} + +const QList FindSaneDevicesThread::devicesList() const +{ + return m_deviceList; +} + +} diff --git a/libksane/libksane/ksane_find_devices_thread.h b/libksane/libksane/ksane_find_devices_thread.h new file mode 100644 index 00000000..82079703 --- /dev/null +++ b/libksane/libksane/ksane_find_devices_thread.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2008 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_FIND_DEVICES_THREAD_H +#define KSANE_FIND_DEVICES_THREAD_H + +#include "ksane.h" + +#include +#include + +namespace KSaneIface +{ + +class FindSaneDevicesThread : public QThread { + Q_OBJECT + + public: + static FindSaneDevicesThread *getInstance(); + ~FindSaneDevicesThread(); + void run(); + + const QList devicesList() const; + + private: + FindSaneDevicesThread(); + + QList m_deviceList; +}; + +} + +#endif diff --git a/libksane/libksane/ksane_preview_thread.cpp b/libksane/libksane/ksane_preview_thread.cpp new file mode 100644 index 00000000..bc254441 --- /dev/null +++ b/libksane/libksane/ksane_preview_thread.cpp @@ -0,0 +1,472 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2009-11-13 +* Description : Sane interface for KDE +* +* Copyright (C) 2009 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +// Local includes +#include "ksane_preview_thread.moc" + +#include +#include + + +namespace KSaneIface +{ + KSanePreviewThread::KSanePreviewThread(SANE_Handle handle, QImage *img): + QThread(), + status(SANE_STATUS_GOOD), + m_frameSize(0), + m_frameRead(0), + m_dataSize(0), + m_frame_t_count(0), + m_pixel_x(0), + m_pixel_y(0), + m_px_c_index(0), + m_img(img), + m_saneHandle(handle), + m_invertColors(false), + m_readStatus(READ_READY), +// m_scanProgress(0), + m_saneStartDone(false), + m_imageResized(false) + { + m_px_colors[0] = 0; + m_px_colors[1] = 0; + m_px_colors[2] = 0; + } + + void KSanePreviewThread::setPreviewInverted(bool inverted) + { + m_invertColors = inverted; + } + + void KSanePreviewThread::cancelScan() + { + m_readStatus = READ_CANCEL; + } + + void KSanePreviewThread::run() + { + m_dataSize = 0; + m_readStatus = READ_ON_GOING; + m_saneStartDone = false; + + // Start the scanning with sane_start + status = sane_start(m_saneHandle); + + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_start=" << sane_strstatus(status); + sane_cancel(m_saneHandle); + m_readStatus = READ_ERROR; + return; + } + + // Read image parameters + status = sane_get_parameters(m_saneHandle, &m_params); + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_get_parameters=" << sane_strstatus(status); + sane_cancel(m_saneHandle); + m_readStatus = READ_ERROR; + return; + } + + // calculate data size + m_frameSize = m_params.lines * m_params.bytes_per_line; + if ((m_params.format == SANE_FRAME_RED) || + (m_params.format == SANE_FRAME_GREEN) || + (m_params.format == SANE_FRAME_BLUE)) + { + // this is unfortunately calculated again for every frame.... + m_dataSize = m_frameSize*3; + } + else { + m_dataSize = m_frameSize; + } + + // create a new image if necessary + if ((m_img->height() != m_params.lines) || + (m_img->width() != m_params.pixels_per_line)) + { + // just hope that the frame size is not changed between different frames of the same image. + if (m_params.lines > 0) { + *m_img = QImage(m_params.pixels_per_line, m_params.lines, QImage::Format_RGB32); + } + else { + // handscanners have the number of lines -1 -> make room for something + *m_img = QImage(m_params.pixels_per_line, m_params.pixels_per_line, QImage::Format_RGB32); + } + m_img->fill(0xFFFFFFFF); + } + m_imageResized = false; + m_pixel_x = 0; + m_pixel_y = 0; + m_frameRead = 0; + m_px_c_index = 0; + m_frame_t_count = 0; + + // set the m_saneStartDone here so the new QImage gets allocated before updating the preview. + m_saneStartDone = true; + + + while (m_readStatus == READ_ON_GOING) { + readData(); + } + } + + int KSanePreviewThread::scanProgress() + { + // handscanners have negative data size + if (m_dataSize <= 0) return 0; + + int bytesRead; + + if (m_frameSize < m_dataSize) { + bytesRead = m_frameRead + (m_frameSize * m_frame_t_count); + } + else { + bytesRead = m_frameRead; + } + + return (int)(((float)bytesRead * 100.0)/m_dataSize); + } + + void KSanePreviewThread::readData() + { + SANE_Int readBytes; + status = sane_read(m_saneHandle, m_readData, PREVIEW_READ_CHUNK_SIZE, &readBytes); + + switch (status) + { + case SANE_STATUS_GOOD: + // continue to parsing the data + break; + + case SANE_STATUS_EOF: + // (handscanners have negative frame size) + if (m_frameRead < m_frameSize) { + kDebug() << "frameRead =" << m_frameRead << ", frameSize =" << m_frameSize; + m_readStatus = READ_ERROR; + return; + } + if (m_params.last_frame == SANE_TRUE) { + // this is where it all ends well :) + m_readStatus = READ_READY; + return; + } + else { + // start reading next frame + SANE_Status status = sane_start(m_saneHandle); + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_start =" << sane_strstatus(status); + m_readStatus = READ_ERROR; + return; + } + status = sane_get_parameters(m_saneHandle, &m_params); + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_get_parameters =" << sane_strstatus(status); + m_readStatus = READ_ERROR; + sane_cancel(m_saneHandle); + return; + } + //kDebug() << "New Frame"; + m_frameRead = 0; + m_pixel_x = 0; + m_pixel_y = 0; + m_px_c_index = 0; + m_frame_t_count++; + break; + } + default: + kDebug() << "sane_read=" << status << "=" << sane_strstatus(status); + m_readStatus = READ_ERROR; + sane_cancel(m_saneHandle); + return; + } + + copyToPreviewImg(readBytes); + } + + #define inc_pixel(x,y,ppl) { x++; if (x>=ppl) { y++; x=0;} } + #define inc_color_index(index) { index++; if (index==3) index=0;} + + #define index_red8_to_argb8(i) (i*4 + 2) + #define index_red16_to_argb8(i) (i*2 + 2) + + #define index_green8_to_argb8(i) (i*4 + 1) + #define index_green16_to_argb8(i) (i*2 + 1) + + #define index_blue8_to_argb8(i) (i*4) + #define index_blue16_to_argb8(i) (i*2) + + void KSanePreviewThread::copyToPreviewImg(int read_bytes) + { + QMutexLocker locker(&imgMutex); + int index; + uchar *imgBits = m_img->bits(); + if (m_invertColors) { + if (m_params.depth >= 8) { + for(int i=0; i= m_img->height()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + m_imageResized = true; + } + for (j=7; j>=0; --j) { + if ((m_readData[i] & (1<setPixel(m_pixel_x, + m_pixel_y, + qRgb(255,255,255)); + } + else { + m_img->setPixel(m_pixel_x, + m_pixel_y, + qRgb(0,0,0)); + } + m_pixel_x++; + if(m_pixel_x >= m_params.pixels_per_line) { + m_pixel_x = 0; + m_pixel_y++; + break; + } + if (m_pixel_y >= m_params.lines) break; + } + m_frameRead++; + } + return; + } + else if (m_params.depth == 8) { + for (int i=0; im_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index ] = m_readData[i]; + imgBits[index + 1] = m_readData[i]; + imgBits[index + 2] = m_readData[i]; + m_frameRead++; + } + return; + } + else if (m_params.depth == 16) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index ] = m_readData[i+1]; + imgBits[index + 1] = m_readData[i+1]; + imgBits[index + 2] = m_readData[i+1]; + } + m_frameRead++; + } + return; + } + break; + + case SANE_FRAME_RGB: + if (m_params.depth == 8) { + for (int i=0; i= m_img->height()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + m_imageResized = true; + } + m_img->setPixel(m_pixel_x, + m_pixel_y, + qRgb(m_px_colors[0], + m_px_colors[1], + m_px_colors[2])); + inc_pixel(m_pixel_x, m_pixel_y, m_params.pixels_per_line); + } + } + return; + } + else if (m_params.depth == 16) { + for (int i=0; i= m_img->height()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + m_imageResized = true; + } + m_img->setPixel(m_pixel_x, + m_pixel_y, + qRgb(m_px_colors[0], + m_px_colors[1], + m_px_colors[2])); + inc_pixel(m_pixel_x, m_pixel_y, m_params.pixels_per_line); + } + } + } + return; + } + break; + + case SANE_FRAME_RED: + if (m_params.depth == 8) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_red8_to_argb8(m_frameRead)] = m_readData[i]; + m_frameRead++; + } + return; + } + else if (m_params.depth == 16) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_red16_to_argb8(m_frameRead)] = m_readData[i+1]; + } + m_frameRead++; + } + return; + } + break; + + case SANE_FRAME_GREEN: + if (m_params.depth == 8) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_green8_to_argb8(m_frameRead)] = m_readData[i]; + m_frameRead++; + } + return; + } + else if (m_params.depth == 16) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_green16_to_argb8(m_frameRead)] = m_readData[i+1]; + } + m_frameRead++; + } + return; + } + break; + + case SANE_FRAME_BLUE: + if (m_params.depth == 8) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_blue8_to_argb8(m_frameRead)] = m_readData[i]; + m_frameRead++; + } + return; + } + else if (m_params.depth == 16) { + for (int i=0; i m_img->numBytes()) { + // resize the image + *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width()); + imgBits = m_img->bits(); + m_imageResized = true; + } + imgBits[index_blue16_to_argb8(m_frameRead)] = m_readData[i+1]; + } + m_frameRead++; + } + return; + } + break; + } + + kWarning() << "Format" << m_params.format + << "and depth" << m_params.format + << "is not yet suppoeted by libksane!"; + m_readStatus = READ_ERROR; + return; + } + + bool KSanePreviewThread::saneStartDone() + { + return m_saneStartDone; + } + + bool KSanePreviewThread::imageResized() + { + if (m_imageResized) { + m_imageResized = false; + return true; + } + return false; + } + +} // NameSpace KSaneIface diff --git a/libksane/libksane/ksane_preview_thread.h b/libksane/libksane/ksane_preview_thread.h new file mode 100644 index 00000000..b969ac21 --- /dev/null +++ b/libksane/libksane/ksane_preview_thread.h @@ -0,0 +1,94 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-11-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_PREVIEW_THREAD_H +#define KSANE_PREVIEW_THREAD_H + +// Sane includes +extern "C" +{ + #include + #include +} + +#include +#include +#include + +#define PREVIEW_READ_CHUNK_SIZE 100000 + +namespace KSaneIface +{ + class KSanePreviewThread: public QThread + { + Q_OBJECT + public: + typedef enum + { + READ_ON_GOING, + READ_ERROR, + READ_CANCEL, + READ_READY + } ReadStatus; + + KSanePreviewThread(SANE_Handle handle, QImage *img); + void run(); + void setPreviewInverted(bool); + void cancelScan(); + int scanProgress(); + bool saneStartDone(); + bool imageResized(); + + SANE_Status status; + QMutex imgMutex; + + private: + void readData(); + void copyToPreviewImg(int readBytes); + + SANE_Byte m_readData[PREVIEW_READ_CHUNK_SIZE]; + int m_frameSize; + int m_frameRead; + int m_dataSize; + int m_frame_t_count; + int m_pixel_x; + int m_pixel_y; + int m_px_colors[3]; + int m_px_c_index; + SANE_Parameters m_params; + QImage *m_img; + SANE_Handle m_saneHandle; + bool m_invertColors; + ReadStatus m_readStatus; +// int m_scanProgress; + bool m_saneStartDone; + bool m_imageResized; + }; +} + + +#endif diff --git a/libksane/libksane/ksane_scan_thread.cpp b/libksane/libksane/ksane_scan_thread.cpp new file mode 100644 index 00000000..acde2738 --- /dev/null +++ b/libksane/libksane/ksane_scan_thread.cpp @@ -0,0 +1,311 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2009-11-13 +* Description : Sane interface for KDE +* +* Copyright (C) 2009 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +// Local includes +#include "ksane_scan_thread.moc" + +#include + +namespace KSaneIface +{ + + + KSaneScanThread::KSaneScanThread(SANE_Handle handle, QByteArray *data): + QThread(), + m_data(data), + m_saneHandle(handle), + m_frameSize(0), + m_frameRead(0), + m_frame_t_count(0), + m_dataSize(0), + m_saneStatus(SANE_STATUS_GOOD), + m_readStatus(READ_READY), + m_invertColors(false), + m_saneStartDone(false) + {} + + void KSaneScanThread::setImageInverted(bool inverted) + { + m_invertColors = inverted; + } + + SANE_Status KSaneScanThread::saneStatus() + { + return m_saneStatus; + } + + KSaneScanThread::ReadStatus KSaneScanThread::frameStatus() + { + return m_readStatus; + } + + void KSaneScanThread::cancelScan() + { + m_readStatus = READ_CANCEL; + } + + int KSaneScanThread::scanProgress() + { + if (m_dataSize == 0) return 0; + + int bytesRead; + + if (m_frameSize < m_dataSize) { + bytesRead = m_frameRead + (m_frameSize * m_frame_t_count); + } + else { + bytesRead = m_frameRead; + } + return (int)(((float)bytesRead * 100.0)/m_dataSize); + } + + SANE_Parameters KSaneScanThread::saneParameters() + { + return m_params; + } + + void KSaneScanThread::run() + { + m_dataSize = 0; + m_readStatus = READ_ON_GOING; + m_saneStartDone = false; + + // Start the scanning with sane_start + m_saneStatus = sane_start(m_saneHandle); + + m_saneStartDone = true; + + if (m_readStatus == READ_CANCEL) { + return; + } + + if (m_saneStatus != SANE_STATUS_GOOD) { + kDebug() << "sane_start=" << sane_strstatus(m_saneStatus); + m_readStatus = READ_ERROR; + // oneFinalScanDone() does the sane_cancel() + return; + } + + // Read image parameters + m_saneStatus = sane_get_parameters(m_saneHandle, &m_params); + if (m_saneStatus != SANE_STATUS_GOOD) { + kDebug() << "sane_get_parameters=" << sane_strstatus(m_saneStatus); + m_readStatus = READ_ERROR; + // oneFinalScanDone() does the sane_cancel() + return; + } + + // calculate data size + m_frameSize = m_params.lines * m_params.bytes_per_line; + if ((m_params.format == SANE_FRAME_RED) || + (m_params.format == SANE_FRAME_GREEN) || + (m_params.format == SANE_FRAME_BLUE)) + { + m_dataSize = m_frameSize*3; + } + else { + m_dataSize = m_frameSize; + } + + m_data->clear(); + if (m_dataSize > 0) { + m_data->reserve(m_dataSize); + } + + m_frameRead = 0; + m_frame_t_count = 0; + m_readStatus = READ_ON_GOING; + while (m_readStatus == READ_ON_GOING) { + readData(); + } + } + + void KSaneScanThread::readData() + { + SANE_Int readBytes = 0; + m_saneStatus = sane_read(m_saneHandle, m_readData, SCAN_READ_CHUNK_SIZE, &readBytes); + + switch (m_saneStatus) + { + case SANE_STATUS_GOOD: + // continue to parsing the data + break; + + case SANE_STATUS_EOF: + if (m_frameRead < m_frameSize) { + kDebug() << "frameRead =" << m_frameRead << ", frameSize =" << m_frameSize << "readBytes =" << readBytes; + if ((readBytes > 0) && ((m_frameRead + readBytes) <= m_frameSize)) { + kDebug() << "This is not a standard compliant backend"; + copyToScanData(readBytes); + } + m_readStatus = READ_READY; // It is better to return a broken image than nothing + return; + } + if (m_params.last_frame == SANE_TRUE) { + // this is where it all ends well :) + m_readStatus = READ_READY; + return; + } + else { + // start reading next frame + m_saneStatus = sane_start(m_saneHandle); + if (m_saneStatus != SANE_STATUS_GOOD) { + kDebug() << "sane_start =" << sane_strstatus(m_saneStatus); + m_readStatus = READ_ERROR; + return; + } + m_saneStatus = sane_get_parameters(m_saneHandle, &m_params); + if (m_saneStatus != SANE_STATUS_GOOD) { + kDebug() << "sane_get_parameters =" << sane_strstatus(m_saneStatus); + m_readStatus = READ_ERROR; + sane_cancel(m_saneHandle); + return; + } + //kDebug() << "New Frame"; + m_frameRead = 0; + m_frame_t_count++; + break; + } + default: + kDebug() << "sane_read=" << m_saneStatus << "=" << sane_strstatus(m_saneStatus); + m_readStatus = READ_ERROR; + sane_cancel(m_saneHandle); + return; + } + + copyToScanData(readBytes); + } + + #define index_red8_to_rgb8(i) (i*3) + #define index_red16_to_rgb16(i) ((i/2)*6 + i%2) + + #define index_green8_to_rgb8(i) (i*3 + 1) + #define index_green16_to_rgb16(i) ((i/2)*6 + i%2 + 2) + + #define index_blue8_to_rgb8(i) (i*3 + 2) + #define index_blue16_to_rgb16(i) ((i/2)*6 + i%2 + 4) + + void KSaneScanThread::copyToScanData(int readBytes) + { + if (m_invertColors) { + if (m_params.depth == 16) { + //if (readBytes%2) qDebug() << "readBytes=" << readBytes; + quint16 *u16ptr = reinterpret_cast(m_readData); + for(int i=0; iappend((const char*)m_readData, readBytes); + m_frameRead += readBytes; + return; + case SANE_FRAME_RGB: + if (m_params.depth == 1) { + break; + } + m_data->append((const char*)m_readData, readBytes); + m_frameRead += readBytes; + return; + + case SANE_FRAME_RED: + if (m_params.depth == 8) { + for (int i=0; i + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_SCAN_THREAD_H +#define KSANE_SCAN_THREAD_H + +// Sane includes +extern "C" +{ + #include + #include +} + +#include +#include + +#define SCAN_READ_CHUNK_SIZE 100000 + +namespace KSaneIface +{ + class KSaneScanThread: public QThread + { + Q_OBJECT + public: + typedef enum + { + READ_ON_GOING, + READ_ERROR, + READ_CANCEL, + READ_READY + } ReadStatus; + + KSaneScanThread(SANE_Handle handle, QByteArray *data); + void run(); + void setImageInverted(bool); + void cancelScan(); + int scanProgress(); + bool saneStartDone(); + + ReadStatus frameStatus(); + SANE_Status saneStatus(); + SANE_Parameters saneParameters(); + + private: + void readData(); + void copyToScanData(int readBytes); + + SANE_Byte m_readData[SCAN_READ_CHUNK_SIZE]; + QByteArray *m_data; + SANE_Handle m_saneHandle; + SANE_Parameters m_params; + int m_frameSize; + int m_frameRead; + int m_frame_t_count; + int m_dataSize; + SANE_Status m_saneStatus; + ReadStatus m_readStatus; + bool m_invertColors; + bool m_saneStartDone; + }; +} + + +#endif diff --git a/libksane/libksane/ksane_viewer.cpp b/libksane/libksane/ksane_viewer.cpp new file mode 100644 index 00000000..cb08fe86 --- /dev/null +++ b/libksane/libksane/ksane_viewer.cpp @@ -0,0 +1,1102 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2008-11-15 +* Description : Preview image viewer that can handle a selection. +* +* Copyright (C) 2008 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#include "ksane_viewer.h" +#include "ksane_viewer.moc" +#include "selectionitem.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace KSaneIface +{ + +struct KSaneViewer::Private +{ + QGraphicsScene *scene; + SelectionItem *selection; + QImage *img; + + QList selectionList; + SelectionItem::Intersects change; + + QPointF lastSPoint; + int m_left_last_x; + int m_left_last_y; + + QAction *zoomInAction; + QAction *zoomOutAction; + QAction *zoomSelAction; + QAction *zoom2FitAction; + QAction *clrSelAction; + + QGraphicsRectItem *hideLeft; + QGraphicsRectItem *hideRight; + QGraphicsRectItem *hideTop; + QGraphicsRectItem *hideBottom; + QGraphicsRectItem *hideArea; +}; + +KSaneViewer::KSaneViewer(QImage * img, QWidget *parent) : QGraphicsView(parent), d(new Private) +{ + d->img = img; + + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setMouseTracking(true); + + // Init the scene + d->scene = new QGraphicsScene; + d->scene->setSceneRect(0, 0, img->width(), img->height()); + setScene(d->scene); + + d->selection = new SelectionItem(QRectF()); + d->selection->setZValue(10); + d->selection->setSaved(false); + d->selection->setMaxRight(img->width()); + d->selection->setMaxBottom(img->height()); + d->selection->setRect(d->scene->sceneRect()); + d->selection->setVisible(false); + + d->hideTop = new QGraphicsRectItem; + d->hideBottom = new QGraphicsRectItem; + d->hideRight = new QGraphicsRectItem; + d->hideLeft = new QGraphicsRectItem; + d->hideArea = new QGraphicsRectItem; + + d->hideTop->setOpacity(0.4); + d->hideBottom->setOpacity(0.4); + d->hideRight->setOpacity(0.4); + d->hideLeft->setOpacity(0.4); + d->hideArea->setOpacity(0.6); + + d->hideTop->setPen(Qt::NoPen); + d->hideBottom->setPen(Qt::NoPen); + d->hideRight->setPen(Qt::NoPen); + d->hideLeft->setPen(Qt::NoPen); + d->hideArea->setPen(Qt::NoPen); + + d->hideTop->setBrush(QBrush(Qt::black)); + d->hideBottom->setBrush(QBrush(Qt::black)); + d->hideRight->setBrush(QBrush(Qt::black)); + d->hideLeft->setBrush(QBrush(Qt::black)); + + d->scene->addItem(d->selection); + d->scene->addItem(d->hideLeft); + d->scene->addItem(d->hideRight); + d->scene->addItem(d->hideTop); + d->scene->addItem(d->hideBottom); + d->scene->addItem(d->hideArea); + + d->change = SelectionItem::None; + d->selectionList.clear(); + + // create context menu + d->zoomInAction = new QAction(KIcon("zoom-in"), i18n("Zoom In"), this); + connect(d->zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn())); + + d->zoomOutAction = new QAction(KIcon("zoom-out"), i18n("Zoom Out"), this); + connect(d->zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut())); + + d->zoomSelAction = new QAction(KIcon("zoom-fit-best"), i18n("Zoom to Selection"), this); + connect(d->zoomSelAction, SIGNAL(triggered()), this, SLOT(zoomSel())); + + d->zoom2FitAction = new QAction(KIcon("document-preview"), i18n("Zoom to Fit"), this); + connect(d->zoom2FitAction, SIGNAL(triggered()), this, SLOT(zoom2Fit())); + + d->clrSelAction = new QAction(KIcon("edit-clear"), i18n("Clear Selections"), this); + connect(d->clrSelAction, SIGNAL(triggered()), this, SLOT(clearSelections())); + + addAction(d->zoomInAction); + addAction(d->zoomOutAction); + addAction(d->zoomSelAction); + addAction(d->zoom2FitAction); + addAction(d->clrSelAction); + setContextMenuPolicy(Qt::ActionsContextMenu); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::drawBackground(QPainter *painter, const QRectF &rect) +{ + painter->fillRect(rect, QColor(0x70, 0x70, 0x70)); + painter->drawImage(rect, *d->img, rect); +} + +// ------------------------------------------------------------------------ +KSaneViewer::~KSaneViewer() +{ + // first remove any old saved selections + clearSavedSelections(); + + delete d; +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setQImage(QImage *img) +{ + if (img == 0) return; + + // remove selections + clearSelections(); + + // clear zoom + setMatrix(QMatrix()); + + d->scene->setSceneRect(0, 0, img->width(), img->height()); + d->selection->setMaxRight(img->width()); + d->selection->setMaxBottom(img->height()); + d->img = img; +} + +// ------------------------------------------------------------------------ +void KSaneViewer::updateImage() +{ + setCacheMode(QGraphicsView::CacheNone); + repaint(); + setCacheMode(QGraphicsView::CacheBackground); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::zoomIn() +{ + scale(1.5, 1.5); + d->selection->saveZoom(transform().m11()); + for (int i=0; iselectionList.size(); ++i) { + d->selectionList[i]->saveZoom(transform().m11()); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::zoomOut() +{ + scale(1.0 / 1.5, 1.0 / 1.5); + d->selection->saveZoom(transform().m11()); + for (int i=0; iselectionList.size(); ++i) { + d->selectionList[i]->saveZoom(transform().m11()); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::zoomSel() +{ + if (d->selection->isVisible()) { + fitInView(d->selection->boundingRect() , Qt::KeepAspectRatio); + d->selection->saveZoom(transform().m11()); + for (int i=0; iselectionList.size(); ++i) { + d->selectionList[i]->saveZoom(transform().m11()); + } + } + else { + zoom2Fit(); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::zoom2Fit() +{ + fitInView(d->img->rect(), Qt::KeepAspectRatio); + d->selection->saveZoom(transform().m11()); + for (int i=0; iselectionList.size(); ++i) { + d->selectionList[i]->saveZoom(transform().m11()); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setTLX(float ratio) +{ + if (!d->selection->isVisible()) return; // only correct the selection if it is visible + QRectF rect = d->selection->rect(); + rect.setLeft(ratio * d->img->width()); + d->selection->setRect(rect); + updateSelVisibility(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setTLY(float ratio) +{ + if (!d->selection->isVisible()) return; // only correct the selection if it is visible + QRectF rect = d->selection->rect(); + rect.setTop(ratio * d->img->height()); + d->selection->setRect(rect); + updateSelVisibility(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setBRX(float ratio) +{ + if (!d->selection->isVisible()) return; // only correct the selection if it is visible + QRectF rect = d->selection->rect(); + rect.setRight(ratio * d->img->width()); + d->selection->setRect(rect); + updateSelVisibility(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setBRY(float ratio) +{ + if (!d->selection->isVisible()) return; // only correct the selection if it is visible + QRectF rect = d->selection->rect(); + rect.setBottom(ratio * d->img->height()); + d->selection->setRect(rect); + updateSelVisibility(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setSelection(float tl_x, float tl_y, float br_x, float br_y) +{ + QRectF rect; + rect.setCoords(tl_x * d->img->width(), + tl_y * d->img->height(), + br_x * d->img->width(), + br_y * d->img->height()); + + d->selection->setRect(rect); + updateSelVisibility(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setHighlightArea(float tl_x, float tl_y, float br_x, float br_y) +{ + QRectF rect; + + // Left reason for rect: setCoords(x1,y1,x2,y2) != setRect(x1,x2, width, height) + rect.setCoords(0,0, tl_x * d->img->width(), d->img->height()); + d->hideLeft->setRect(rect); + + // Right + rect.setCoords(br_x * d->img->width(), + 0, + d->img->width(), + d->img->height()); + d->hideRight->setRect(rect); + + // Top + rect.setCoords(tl_x * d->img->width(), + 0, + br_x * d->img->width(), + tl_y * d->img->height()); + d->hideTop->setRect(rect); + + // Bottom + rect.setCoords(tl_x * d->img->width(), + br_y * d->img->height(), + br_x * d->img->width(), + d->img->height()); + d->hideBottom->setRect(rect); + + // hide area + rect.setCoords(tl_x * d->img->width(), tl_y* d->img->height(), + br_x * d->img->width(), br_y* d->img->height()); + + d->hideArea->setRect(rect); + + d->hideLeft->show(); + d->hideRight->show(); + d->hideTop->show(); + d->hideBottom->show(); + // the hide area is hidden until setHighlightShown is called. + d->hideArea->hide(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::setHighlightShown(int percentage, QColor hideColor) +{ + if (percentage >= 100) { + d->hideArea->hide(); + return; + } + + d->hideArea->setBrush(hideColor); + + qreal diff = d->hideBottom->rect().top() - d->hideTop->rect().bottom(); + diff -= (diff * percentage) / 100; + + QRectF rect = d->hideArea->rect(); + rect.setTop(d->hideBottom->rect().top() - diff); + + d->hideArea->setRect(rect); + + d->hideArea->show(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::updateHighlight() +{ + if (d->selection->isVisible()) { + QRectF rect; + // Left + rect.setCoords(0,0, d->selection->rect().left(), d->img->height()); + d->hideLeft->setRect(rect); + + // Right + rect.setCoords(d->selection->rect().right(), + 0, + d->img->width(), + d->img->height()); + d->hideRight->setRect(rect); + + // Top + rect.setCoords(d->selection->rect().left(), + 0, + d->selection->rect().right(), + d->selection->rect().top()); + d->hideTop->setRect(rect); + + // Bottom + rect.setCoords(d->selection->rect().left(), + d->selection->rect().bottom(), + d->selection->rect().right(), + d->img->height()); + d->hideBottom->setRect(rect); + + d->hideLeft->show(); + d->hideRight->show(); + d->hideTop->show(); + d->hideBottom->show(); + d->hideArea->hide(); + } + else { + d->hideLeft->hide(); + d->hideRight->hide(); + d->hideTop->hide(); + d->hideBottom->hide(); + d->hideArea->hide(); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::clearHighlight() +{ + d->hideLeft + ->hide(); + d->hideRight->hide(); + d->hideTop->hide(); + d->hideBottom->hide(); + d->hideArea->hide(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::updateSelVisibility() +{ + if ((d->selection->rect().width() >0.001) && + (d->selection->rect().height() > 0.001) && + ((d->img->width() - d->selection->rect().width() > 0.1) || + (d->img->height() - d->selection->rect().height() > 0.1))) + { + d->selection->setVisible(true); + } + else { + d->selection->setVisible(false); + } + updateHighlight(); +} + +// ---- Return the saved selection list size + 1 if the selection is visible - +int KSaneViewer::selListSize() { + if (d->selection->isVisible()) { + return (d->selectionList.size() + 1); + } + else { + return d->selectionList.size(); + } +} + +// ---- First return the "saved" selection sthen the active selection ----------- +bool KSaneViewer::selectionAt(int index, float &tl_x, float &tl_y, float &br_x, float &br_y) +{ + if ((index < 0) || (index > d->selectionList.size())) { + activeSelection(tl_x, tl_y, br_x, br_y); + return false; + } + if (index == d->selectionList.size()) { + return activeSelection(tl_x, tl_y, br_x, br_y); + } + + tl_x = d->selectionList[index]->rect().left() / d->img->width(); + tl_y = d->selectionList[index]->rect().top() / d->img->height(); + br_x = d->selectionList[index]->rect().right() / d->img->width(); + br_y = d->selectionList[index]->rect().bottom() / d->img->height(); + return true; +} + +// ------------------------------------------------------------------------ +bool KSaneViewer::activeSelection(float &tl_x, float &tl_y, float &br_x, float &br_y) +{ + if (!d->selection->isVisible()) { + tl_x = 0.0; + tl_y = 0.0; + br_x = 1.0; + br_y = 1.0; + return true; + } + + tl_x = d->selection->rect().left() / d->img->width(); + tl_y = d->selection->rect().top() / d->img->height(); + br_x = d->selection->rect().right() / d->img->width(); + br_y = d->selection->rect().bottom() / d->img->height(); + + if ((tl_x == br_x) || (tl_y == br_y)) { + tl_x = 0.0; + tl_y = 0.0; + br_x = 1.0; + br_y = 1.0; + return false; // just precaution + } + return true; +} + +// ------------------------------------------------------------------------ +void KSaneViewer::clearActiveSelection() +{ + d->selection->setRect(QRectF(0,0,0,0)); + d->selection->intersects(QPointF(100,100)); // don't show the add sign + d->selection->setVisible(false); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::clearSavedSelections() +{ + // first remove any old saved selections + SelectionItem *tmp; + while (!d->selectionList.isEmpty()) { + tmp = d->selectionList.takeFirst(); + d->scene->removeItem(tmp); + delete tmp; + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::clearSelections() +{ + clearActiveSelection(); + clearSavedSelections(); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::wheelEvent(QWheelEvent *e) +{ + if(e->modifiers() == Qt::ControlModifier) { + if(e->delta() > 0) { + zoomIn(); + } else { + zoomOut(); + } + } else { + QGraphicsView::wheelEvent(e); + } +} + +// ------------------------------------------------------------------------ +void KSaneViewer::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton) + { + d->m_left_last_x = e->x(); + d->m_left_last_y = e->y(); + QPointF scenePoint = mapToScene(e->pos()); + d->lastSPoint = scenePoint; + if (e->modifiers() != Qt::ControlModifier) { + if (!d->selection->isVisible()) { + d->selection->setVisible(true); + d->selection->setRect(QRectF(scenePoint, QSizeF(0,0))); + d->selection->intersects(scenePoint); // just to disable add/remove + d->change = SelectionItem::BottomRight; + } + else if (d->selection->intersects(scenePoint) == SelectionItem::None) { + d->selection->setRect(QRectF(scenePoint, QSizeF(0,0))); + d->change = SelectionItem::BottomRight; + } + updateHighlight(); + } + } + QGraphicsView::mousePressEvent(e); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::mouseReleaseEvent(QMouseEvent *e) +{ + bool removed = false; + if (e->button() == Qt::LeftButton) { + if ((d->selection->rect().width() < 0.001) || + (d->selection->rect().height() < 0.001)) + { + emit newSelection(0.0,0.0, 0.0, 0.0); + clearActiveSelection(); + } + + QPointF scenePoint = mapToScene(e->pos()); + for (int i=0; iselectionList.size(); i++) { + if (d->selectionList[i]->intersects(scenePoint) == SelectionItem::AddRemove) { + d->scene->removeItem(d->selectionList[i]); + SelectionItem *tmp = d->selectionList[i]; + d->selectionList.removeAt(i); + d->selection->setVisible(true); + d->selection->setRect(tmp->rect()); + d->selection->intersects(scenePoint); // just to enable add/remove + delete tmp; + removed = true; + break; + } + } + if (!removed && (d->selection->intersects(scenePoint) == SelectionItem::AddRemove)) { + // add the current selection + SelectionItem *tmp = new SelectionItem(d->selection->rect()); + d->selectionList.push_back(tmp); + d->selectionList.back()->setSaved(true); + d->selectionList.back()->saveZoom(transform().m11()); + d->scene->addItem(d->selectionList.back()); + d->selectionList.back()->setZValue(9); + d->selectionList.back()->intersects(scenePoint); + + // clear the old one + emit newSelection(0.0,0.0, 0.0, 0.0); + clearActiveSelection(); + } + } + + if ((e->modifiers() != Qt::ControlModifier) && + (d->selection->isVisible()) && + (d->img->width() > 0.001) && + (d->img->height() > 0.001)) + { + float tlx = d->selection->rect().left() / d->img->width(); + float tly = d->selection->rect().top() / d->img->height(); + float brx = d->selection->rect().right() / d->img->width(); + float bry = d->selection->rect().bottom() / d->img->height(); + + emit newSelection(tlx, tly, brx, bry); + } + updateHighlight(); + QGraphicsView::mouseReleaseEvent(e); +} + +// ------------------------------------------------------------------------ +void KSaneViewer::mouseMoveEvent(QMouseEvent *e) +{ + QPointF scenePoint = mapToScene(e->pos()); + + if (e->buttons()&Qt::LeftButton) + { + if (e->modifiers() == Qt::ControlModifier) + { + int dx = e->x() - d->m_left_last_x; + int dy = e->y() - d->m_left_last_y; + verticalScrollBar()->setValue(verticalScrollBar()->value()-dy); + horizontalScrollBar()->setValue(horizontalScrollBar()->value()-dx); + d->m_left_last_x = e->x(); + d->m_left_last_y = e->y(); + } + else { + ensureVisible(QRectF(scenePoint, QSizeF(0,0)), 1, 1); + QRectF rect = d->selection->rect(); + switch (d->change) + { + case SelectionItem::None: + // should not be here :) + break; + case SelectionItem::Top: + if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y()); + else { + d->change = SelectionItem::Bottom; + rect.setBottom(scenePoint.y()); + } + break; + case SelectionItem::TopRight: + if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x()); + else { + rect.setLeft(scenePoint.x()); + d->change = SelectionItem::TopLeft; + } + if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y()); + else { + rect.setBottom(scenePoint.y()); + d->change = SelectionItem::BottomLeft; + } // FIXME arrow + break; + case SelectionItem::Right: + if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x()); + else { + rect.setLeft(scenePoint.x()); + d->change = SelectionItem::Left; + } + break; + case SelectionItem::BottomRight: + if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x()); + else { + rect.setLeft(scenePoint.x()); + d->change = SelectionItem::BottomLeft; + } + if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y()); + else { + rect.setTop(scenePoint.y()); + d->change = SelectionItem::TopRight; + } // FIXME arrow + break; + case SelectionItem::Bottom: + if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y()); + else { + d->change = SelectionItem::Top; + rect.setTop(scenePoint.y()); + } + break; + case SelectionItem::BottomLeft: + if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x()); + else { + rect.setRight(scenePoint.x()); + d->change = SelectionItem::BottomRight; + } + if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y()); + else { + rect.setTop(scenePoint.y()); + d->change = SelectionItem::TopLeft; + } // FIXME arrow + break; + case SelectionItem::Left: + if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x()); + else { + rect.setRight(scenePoint.x()); + d->change = SelectionItem::Right; + } + break; + case SelectionItem::TopLeft: + if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x()); + else { + rect.setRight(scenePoint.x()); + d->change = SelectionItem::TopRight; + } + if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y()); + else { + rect.setBottom(scenePoint.y()); + d->change = SelectionItem::BottomLeft; + }// FIXME arrow + break; + case SelectionItem::Move: + rect.translate(d->selection->fixTranslation(scenePoint-d->lastSPoint)); + break; + case SelectionItem::AddRemove: + // do nothing + break; + } + d->selection->setRect(rect); + } + } + else if (d->selection->isVisible()) { + d->change = d->selection->intersects(scenePoint); + + switch (d->change) + { + case SelectionItem::None: + viewport()->setCursor(Qt::CrossCursor); + break; + case SelectionItem::Top: + viewport()->setCursor(Qt::SizeVerCursor); + break; + case SelectionItem::TopRight: + viewport()->setCursor(Qt::SizeBDiagCursor); + break; + case SelectionItem::Right: + viewport()->setCursor(Qt::SizeHorCursor); + break; + case SelectionItem::BottomRight: + viewport()->setCursor(Qt::SizeFDiagCursor); + break; + case SelectionItem::Bottom: + viewport()->setCursor(Qt::SizeVerCursor); + break; + case SelectionItem::BottomLeft: + viewport()->setCursor(Qt::SizeBDiagCursor); + break; + case SelectionItem::Left: + viewport()->setCursor(Qt::SizeHorCursor); + break; + case SelectionItem::TopLeft: + viewport()->setCursor(Qt::SizeFDiagCursor); + break; + case SelectionItem::Move: + viewport()->setCursor(Qt::SizeAllCursor); + break; + case SelectionItem::AddRemove: + viewport()->setCursor(Qt::ArrowCursor); + break; + } + } + else { + viewport()->setCursor(Qt::CrossCursor); + } + + // now check the selection list + for (int i=0; iselectionList.size(); i++) { + if (d->selectionList[i]->intersects(scenePoint) == SelectionItem::AddRemove) { + viewport()->setCursor(Qt::ArrowCursor); + } + } + + d->lastSPoint = scenePoint; + updateHighlight(); + QGraphicsView::mouseMoveEvent(e); +} + +// The change trigger before adding to the sum +static const int DIFF_TRIGGER = 8; + +// The selection start/stop level trigger +static const int SUM_TRIGGER = 4; + +// The selection start/stop level trigger for the floating average +static const int AVERAGE_TRIGGER = 7; + +// The selection start/stop margin +static const int SEL_MARGIN = 3; + +// Maximum number of allowed selections (this could be a settable variable) +static const int MAX_NUM_SELECTIONS = 8; + +// floating average 'div' must be one less than 'count' +static const int AVERAGE_COUNT = 50; +static const int AVERAGE_MULT = 49; + +// Minimum selection area compared to the whole image +static const float MIN_AREA_SIZE = 0.01; +// ------------------------------------------------------------------------ +void KSaneViewer::findSelections(float area) +{ + // Reduce the size of the image to decrease noise and calculation time + float multiplier = sqrt(area/(d->img->height() * d->img->width())); + + int width = (int)(d->img->width() * multiplier); + int height = (int)(d->img->height() * multiplier); + + QImage img = d->img->scaled(width, height, Qt::KeepAspectRatio); + height = img.height(); // the size was probably not exact + width = img.width(); + + QVector colSums(width + SEL_MARGIN + 1); + qint64 rowSum; + colSums.fill(0); + int pix; + int diff; + int hSelStart=-1; + int hSelEnd=-1; + int hSelMargin = 0; + int wSelStart=-1; + int wSelEnd=-1; + int wSelMargin = 0; + + for (int h=1; h DIFF_TRIGGER) { + colSums[0] += diff; + rowSum += diff; + } + + // Special case for the right most pixel + pix = qGray(img.pixel(width - 1, h)); + diff = qAbs(pix - qGray(img.pixel(width - 2, h))); + diff += qAbs(pix - qGray(img.pixel(width - 1, h-1))); + diff += qAbs(pix - qGray(img.pixel(width - 1, h+1))); + if (diff > DIFF_TRIGGER) { + colSums[width - 1] += diff; + rowSum += diff; + } + + for (int w=1; w < (width - 1); w++) { + pix = qGray(img.pixel(w, h)); + diff = 0; + // how much does the pixel differ from the surrounding + diff += qAbs(pix - qGray(img.pixel(w - 1, h))); + diff += qAbs(pix - qGray(img.pixel(w + 1, h))); + diff += qAbs(pix - qGray(img.pixel(w, h - 1))); + diff += qAbs(pix - qGray(img.pixel(w, h + 1))); + if (diff > DIFF_TRIGGER) { + colSums[w] += diff; + rowSum += diff; + } + } + } + + if ((rowSum/width) > SUM_TRIGGER) { + if (hSelStart < 0) { + if (hSelMargin < SEL_MARGIN) hSelMargin++; + if (hSelMargin == SEL_MARGIN) hSelStart = h - SEL_MARGIN + 1; + } + } + else { + if (hSelStart >= 0) { + if (hSelMargin > 0) hSelMargin--; + } + if ((hSelStart > -1) && ((hSelMargin == 0) || (h==height-1))) { + if (h==height-1) { + hSelEnd = h - hSelMargin; + } + else { + hSelEnd = h - SEL_MARGIN; + } + // We have the end of the vertical selection + // now figure out the horizontal part of the selection + for (int w=0; w <= width; w++) { // colSums[width] will be 0 + if ((colSums[w]/(h - hSelStart)) > SUM_TRIGGER) { + if (wSelStart < 0) { + if (wSelMargin < SEL_MARGIN) wSelMargin++; + if (wSelMargin == SEL_MARGIN) wSelStart = w - SEL_MARGIN + 1; + } + } + else { + if (wSelStart >= 0) { + if (wSelMargin > 0) wSelMargin--; + } + if ((wSelStart >= 0) && ((wSelMargin == 0) || (w == width))) { + if (w == width) { + wSelEnd = width; + } + else { + wSelEnd = w - SEL_MARGIN +1; + } + + // we have the end of a horizontal selection + if ((wSelEnd-wSelStart) < width) { + // skip selections that span the whole width + // calculate the coordinates in the original size + int x1 = wSelStart / multiplier; + int y1 = hSelStart / multiplier; + int x2 = wSelEnd / multiplier; + int y2 = hSelEnd / multiplier; + float selArea = (float)(wSelEnd - wSelStart) * (float)(hSelEnd-hSelStart); + if (selArea > (area * MIN_AREA_SIZE)) { + SelectionItem *tmp = new SelectionItem(QRect(QPoint(x1, y1), QPoint(x2, y2))); + d->selectionList.push_back(tmp); + d->selectionList.back()->setSaved(true); + d->selectionList.back()->saveZoom(transform().m11()); + d->scene->addItem(d->selectionList.back()); + d->selectionList.back()->setZValue(9); + } + } + wSelStart = -1; + wSelEnd = -1; + wSelMargin = 0; + } + } + } + hSelStart = -1; + hSelEnd = -1; + hSelMargin = 0; + colSums.fill(0); + } + } + } + + if (d->selectionList.size() > MAX_NUM_SELECTIONS) { + // smaller area or should we give up?? + clearSavedSelections(); + //findSelections(area/2); + // instead of trying to find probably broken selections just give up + // and do not force broken selections on the user. + } + else { + // 1/multiplier is the error margin caused by the resolution reduction + refineSelections(qRound(1/multiplier)); + // check that the selections are big enough + float minArea = d->img->height() * d->img->width() * MIN_AREA_SIZE; + + int i = 0; + while (i < d->selectionList.size()) { + if ((d->selectionList[i]->rect().width() * d->selectionList[i]->rect().height()) < minArea) { + d->scene->removeItem(d->selectionList[i]); + d->selectionList.removeAt(i); + } + else { + i++; + } + } + } +} + +QSize KSaneViewer::sizeHint() const +{ + return QSize(250, 300); // a sensible size for a scan preview +} + +void KSaneViewer::refineSelections(int pixelMargin) +{ + // The end result + int hSelStart; + int hSelEnd; + int wSelStart; + int wSelEnd; + + for (int i=0; iselectionList.size(); i++) { + QRectF selRect = d->selectionList.at(i)->rect(); + + // original values + hSelStart = (int)selRect.top(); + hSelEnd = (int)selRect.bottom(); + wSelStart = (int)selRect.left(); + wSelEnd = (int)selRect.right(); + + // Top + // Too long iteration should not be a problem since the loop should be interrupted by the limit + hSelStart = refineRow(hSelStart - pixelMargin, hSelEnd, wSelStart, wSelEnd); + + // Bottom (from the bottom up wards) + hSelEnd = refineRow(hSelEnd + pixelMargin, hSelStart, wSelStart, wSelEnd); + + // Left + wSelStart = refineColumn(wSelStart - pixelMargin, wSelEnd, hSelStart, hSelEnd); + + // Right + wSelEnd = refineColumn(wSelEnd + pixelMargin, wSelStart, hSelStart, hSelEnd); + + // Now update the selection + d->selectionList.at(i)->setRect(QRectF(QPointF(wSelStart, hSelStart), QPointF(wSelEnd, hSelEnd))); + } +} + +int KSaneViewer::refineRow(int fromRow, int toRow, int colStart, int colEnd) +{ + int pix; + int diff; + float rowTrigger; + int row; + int addSub = (fromRow < toRow) ? 1 : -1; + + colStart -= 2; //add some margin + colEnd += 2; //add some margin + + if (colStart < 1) colStart = 1; + if (colEnd >= d->img->width()-1) colEnd = d->img->width() - 2; + + if (fromRow < 1) fromRow = 1; + if (fromRow >= d->img->height()-1) fromRow = d->img->height() - 2; + + if (toRow < 1) toRow = 1; + if (toRow >= d->img->height()-1) toRow = d->img->height() - 2; + + row = fromRow; + while (row != toRow) { + rowTrigger = 0; + for (int w=colStart; wimg->pixel(w, row)); + // how much does the pixel differ from the surrounding + diff += qAbs(pix - qGray(d->img->pixel(w-1, row))); + diff += qAbs(pix - qGray(d->img->pixel(w+1, row))); + diff += qAbs(pix - qGray(d->img->pixel(w, row-1))); + diff += qAbs(pix - qGray(d->img->pixel(w, row+1))); + if (diff <= DIFF_TRIGGER) diff = 0; + + rowTrigger = ((rowTrigger * AVERAGE_MULT) + diff) / AVERAGE_COUNT; + + if (rowTrigger > AVERAGE_TRIGGER) { + break; + } + } + + if (rowTrigger > AVERAGE_TRIGGER) { + // row == 1 _probably_ means that the selection should start from 0 + // but that can not be detected if we start from 1 => include one extra column + if (row == 1) row = 0; + if (row == (d->img->width() -2)) row = d->img->width(); + return row; + } + row += addSub; + } + return row; +} + +int KSaneViewer::refineColumn(int fromCol, int toCol, int rowStart, int rowEnd) +{ + int pix; + int diff; + float colTrigger; + int col; + int count; + int addSub = (fromCol < toCol) ? 1 : -1; + + rowStart -= 2; //add some margin + rowEnd += 2; //add some margin + + if (rowStart < 1) rowStart = 1; + if (rowEnd >= d->img->height()-1) rowEnd = d->img->height() - 2; + + if (fromCol < 1) fromCol = 1; + if (fromCol >= d->img->width()-1) fromCol = d->img->width() - 2; + + if (toCol < 1) toCol = 1; + if (toCol >= d->img->width()-1) toCol = d->img->width() - 2; + + col = fromCol; + while (col != toCol) { + colTrigger = 0; + count = 0; + for (int row=rowStart; rowimg->pixel(col, row)); + // how much does the pixel differ from the surrounding + diff += qAbs(pix - qGray(d->img->pixel(col-1, row))); + diff += qAbs(pix - qGray(d->img->pixel(col+1, row))); + diff += qAbs(pix - qGray(d->img->pixel(col, row-1))); + diff += qAbs(pix - qGray(d->img->pixel(col, row+1))); + if (diff <= DIFF_TRIGGER) diff = 0; + + colTrigger = ((colTrigger * AVERAGE_MULT) + diff) / AVERAGE_COUNT; + + if (colTrigger > AVERAGE_TRIGGER) { + break; + } + } + + if (colTrigger > AVERAGE_TRIGGER) { + // col == 1 _probably_ means that the selection should start from 0 + // but that can not be detected if we start from 1 => include one extra column + if (col == 1) col = 0; + if (col == (d->img->width() -2)) col = d->img->width(); + return col; + } + col += addSub; + } + return col; +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/ksane_viewer.h b/libksane/libksane/ksane_viewer.h new file mode 100644 index 00000000..f7b47447 --- /dev/null +++ b/libksane/libksane/ksane_viewer.h @@ -0,0 +1,128 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2008-11-15 +* Description : Preview image viewer that can handle a selection. +* +* Copyright (C) 2008 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#ifndef KSANE_VIEWER_H +#define KSANE_VIEWER_H + +#include +#include + +namespace KSaneIface +{ + +class KSaneViewer : public QGraphicsView +{ + Q_OBJECT + public: + explicit KSaneViewer(QImage *img, QWidget *parent = 0); + ~KSaneViewer(); + + void setQImage(QImage *img); + void updateImage(); + /** Find selections in the picture + * \param area this parameter determine the area of the reduced sized image. */ + void findSelections(float area = 10000.0); + + virtual QSize sizeHint() const; + + public Q_SLOTS: + + void setTLX(float ratio); + void setTLY(float ratio); + void setBRX(float ratio); + void setBRY(float ratio); + + /** This function is used to set a selection without the user setting it. + * \note all parameters must be in the range 0.0 -> 1.0. + * \param tl_x is the x coordinate of the top left corner 0=0 1=image with. + * \param tl_y is the y coordinate of the top left corner 0=0 1=image height. + * \param br_x is the x coordinate of the bottom right corner 0=0 1=image with. + * \param br_y is the y coordinate of the bottom right corner 0=0 1=image height. */ + void setSelection(float tl_x, float tl_y, float br_x, float br_y); + void clearActiveSelection(); + void clearSavedSelections(); + void clearSelections(); + + /** This function is used to darken everything except what is inside the given area. + * \note all parameters must be in the range 0.0 -> 1.0. + * \param tl_x is the x coordinate of the top left corner 0=0 1=image with. + * \param tl_y is the y coordinate of the top left corner 0=0 1=image height. + * \param br_x is the x coordinate of the bottom right corner 0=0 1=image with. + * \param br_y is the y coordinate of the bottom right corner 0=0 1=image height. */ + void setHighlightArea(float tl_x, float tl_y, float br_x, float br_y); + + /** This function sets the percentage of the highlighted area that is visible. The rest is hidden. + * \param percentage is the percentage of the highlighted area that is shown. + * \param hideColor is the color to use to hide the highlighted area of the image.*/ + void setHighlightShown(int percentage, QColor hideColor = Qt::white); + + /** This function removes the highlight area. */ + void clearHighlight(); + + void zoomIn(); + void zoomOut(); + void zoomSel(); + void zoom2Fit(); + + int selListSize(); + /* This function returns the active visible selection in index 0 and after that the "saved" ones */ + bool selectionAt(int index, float &tl_x, float &tl_y, float &br_x, float &br_y); + + Q_SIGNALS: + void newSelection(float tl_x, float tl_y, float br_x, float br_y); + + protected: + void wheelEvent(QWheelEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void drawBackground(QPainter *painter, const QRectF &rect); + + private: + void updateSelVisibility(); + void updateHighlight(); + bool activeSelection(float &tl_x, float &tl_y, float &br_x, float &br_y); + void refineSelections(int pixelMargin); + + // fromRow is the row to start the iterations from. fromRow can be grater than toRow. + // rowStart is the x1 coordinate of the row + // all parameters are corrected to be valid pixel indexes, + // but start must be < end + int refineRow(int fromRow, int toRow, int rowStart, int rowEnd); + int refineColumn(int fromCol, int toCol, int colStart, int colEnd); + + struct Private; + Private * const d; + +}; + +} // NameSpace KSaneIface + + +#endif + + diff --git a/libksane/libksane/ksane_viewer_test.cpp b/libksane/libksane/ksane_viewer_test.cpp new file mode 100644 index 00000000..de564ec1 --- /dev/null +++ b/libksane/libksane/ksane_viewer_test.cpp @@ -0,0 +1,52 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2010-03-17 +* Description : Preview image viewer that can handle a selection. +* +* Copyright (C) 2010 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#include "ksane_viewer.h" + +#include +#include + +int main (int argc, char *argv[]) +{ + QApplication app(argc, argv); + + if (argc != 2) { + kDebug() << "An image filename is needed."; + return 1; + } + QImage img(argv[1]); + + KSaneIface::KSaneViewer viewer(&img); + + viewer.findSelections(); + + viewer.show(); + + viewer.zoom2Fit(); + + return app.exec(); +} diff --git a/libksane/libksane/ksane_widget.cpp b/libksane/libksane/ksane_widget.cpp new file mode 100644 index 00000000..c49ff57f --- /dev/null +++ b/libksane/libksane/ksane_widget.cpp @@ -0,0 +1,931 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-24 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2010 by Kare Sars + * Copyright (C) 2009 by Matthias Nagl + * Copyright (C) 2009 by Grzegorz Kurtyka + * Copyright (C) 2007-2008 by Gilles Caulier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#include "ksane.h" +#include "ksane.moc" + +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +// KDE includes +#include +#include +#include + +// Local includes +#include "ksane_widget_private.h" +#include "ksane_option.h" +#include "ksane_opt_button.h" +#include "ksane_opt_checkbox.h" +#include "ksane_opt_combo.h" +#include "ksane_opt_entry.h" +#include "ksane_opt_fslider.h" +#include "ksane_opt_gamma.h" +#include "ksane_opt_slider.h" +#include "ksane_device_dialog.h" +#include "labeled_gamma.h" + +namespace KSaneIface +{ +static int s_objectCount = 0; +static QMutex s_objectMutex; + +static const QString InvetColorsOption = QString("KSane::InvertColors"); + +KSaneWidget::KSaneWidget(QWidget* parent) + : QWidget(parent), d(new KSaneWidgetPrivate(this)) +{ + SANE_Int version; + SANE_Status status; + + //kDebug() << "The language is:" << KGlobal::locale()->language(); + //kDebug() << "Languagelist" << KGlobal::locale()->languageList(); + KGlobal::locale()->insertCatalog("libksane"); + KGlobal::locale()->insertCatalog("sane-backends"); + + s_objectMutex.lock(); + s_objectCount++; + + if (s_objectCount == 1) { + // only call sane init for the first instance + status = sane_init(&version, &KSaneAuth::authorization); + if (status != SANE_STATUS_GOOD) { + kDebug() << "libksane: sane_init() failed(" + << sane_strstatus(status) << ")"; + } + else { + //kDebug() << "Sane Version = " + // << SANE_VERSION_MAJOR(version) << "." + // << SANE_VERSION_MINORparent(version) << "." + // << SANE_VERSION_BUILD(version); + } + } + s_objectMutex.unlock(); + + // read the device list to get a list of vendor and model info + d->m_findDevThread->start(); + + d->m_readValsTmr.setSingleShot(true); + connect(&d->m_readValsTmr, SIGNAL(timeout()), d, SLOT(valReload())); + + d->m_updProgressTmr.setSingleShot(false); + d->m_updProgressTmr.setInterval(300); + connect(&d->m_updProgressTmr, SIGNAL(timeout()), d, SLOT(updateProgress())); + + // Create the static UI + // create the preview + d->m_previewViewer = new KSaneViewer(&(d->m_previewImg), this); + connect(d->m_previewViewer, SIGNAL(newSelection(float,float,float,float)), + d, SLOT(handleSelection(float,float,float,float))); + + + d->m_warmingUp = new QLabel; + d->m_warmingUp->setText(i18n("Waiting for the scan to start.")); + d->m_warmingUp->setAlignment(Qt::AlignCenter); + d->m_warmingUp->setAutoFillBackground(true); + d->m_warmingUp->setBackgroundRole(QPalette::Highlight); + //d->m_warmingUp->setForegroundRole(QPalette::HighlightedText); + d->m_warmingUp->hide(); + + d->m_progressBar = new QProgressBar; + d->m_progressBar->setMaximum(100); + + d->m_cancelBtn = new KPushButton; + d->m_cancelBtn->setIcon(KIcon("process-stop")); + d->m_cancelBtn->setToolTip(i18n("Cancel current scan operation")); + connect(d->m_cancelBtn, SIGNAL(clicked()), this, SLOT(scanCancel())); + + d->m_activityFrame = new QWidget; + QHBoxLayout *progress_lay = new QHBoxLayout(d->m_activityFrame); + progress_lay->setContentsMargins(0,0,0,0); + progress_lay->addWidget(d->m_progressBar, 100); + progress_lay->addWidget(d->m_cancelBtn, 0); + d->m_activityFrame->hide(); + + d->m_zInBtn = new QToolButton(this); + d->m_zInBtn->setAutoRaise(true); + d->m_zInBtn->setIcon(KIcon("zoom-in")); + d->m_zInBtn->setToolTip(i18n("Zoom In")); + connect(d->m_zInBtn, SIGNAL(clicked()), d->m_previewViewer, SLOT(zoomIn())); + + d->m_zOutBtn = new QToolButton(this); + d->m_zOutBtn->setAutoRaise(true); + d->m_zOutBtn->setIcon(KIcon("zoom-out")); + d->m_zOutBtn->setToolTip(i18n("Zoom Out")); + connect(d->m_zOutBtn, SIGNAL(clicked()), d->m_previewViewer, SLOT(zoomOut())); + + d->m_zSelBtn = new QToolButton(this); + d->m_zSelBtn->setAutoRaise(true); + d->m_zSelBtn->setIcon(KIcon("zoom-fit-best")); + d->m_zSelBtn->setToolTip(i18n("Zoom to Selection")); + connect(d->m_zSelBtn, SIGNAL(clicked()), d->m_previewViewer, SLOT(zoomSel())); + + d->m_zFitBtn = new QToolButton(this); + d->m_zFitBtn->setAutoRaise(true); + d->m_zFitBtn->setIcon(KIcon("document-preview")); + d->m_zFitBtn->setToolTip(i18n("Zoom to Fit")); + connect(d->m_zFitBtn, SIGNAL(clicked()), d->m_previewViewer, SLOT(zoom2Fit())); + + d->m_clearSelBtn = new QToolButton(this); + d->m_clearSelBtn->setAutoRaise(true); + d->m_clearSelBtn->setIcon(KIcon("edit-clear")); + d->m_clearSelBtn->setToolTip(i18n("Clear Selections")); + connect(d->m_clearSelBtn, SIGNAL(clicked()), d->m_previewViewer, SLOT(clearSelections())); + + d->m_prevBtn = new KPushButton(this); + d->m_prevBtn->setIcon(KIcon("document-import")); + d->m_prevBtn->setToolTip(i18n("Scan Preview Image")); + d->m_prevBtn->setText(i18nc("Preview button text", "Preview")); + connect(d->m_prevBtn, SIGNAL(clicked()), d, SLOT(startPreviewScan())); + + d->m_scanBtn = new KPushButton(this); + d->m_scanBtn->setIcon(KIcon("document-save")); + d->m_scanBtn->setToolTip(i18n("Scan Final Image")); + d->m_scanBtn->setText(i18nc("Final scan button text", "Scan")); + d->m_scanBtn->setFocus(Qt::OtherFocusReason); + connect(d->m_scanBtn, SIGNAL(clicked()), d, SLOT(startFinalScan())); + + d->m_btnFrame = new QWidget; + QHBoxLayout *btn_lay = new QHBoxLayout(d->m_btnFrame); + btn_lay->setContentsMargins(0,0,0,0); + btn_lay->addWidget(d->m_zInBtn); + btn_lay->addWidget(d->m_zOutBtn); + btn_lay->addWidget(d->m_zSelBtn); + btn_lay->addWidget(d->m_zFitBtn); + btn_lay->addWidget(d->m_clearSelBtn); + btn_lay->addStretch(100); + btn_lay->addWidget(d->m_prevBtn); + btn_lay->addWidget(d->m_scanBtn); + + // calculate the height of the waiting/scanning/buttons frames to avoid jumpiness. + int minHeight = d->m_btnFrame->sizeHint().height(); + if (d->m_activityFrame->sizeHint().height() > minHeight) minHeight = d->m_activityFrame->sizeHint().height(); + if (d->m_warmingUp->sizeHint().height() > minHeight) minHeight = d->m_warmingUp->sizeHint().height(); + d->m_btnFrame->setMinimumHeight(minHeight); + d->m_activityFrame->setMinimumHeight(minHeight); + d->m_warmingUp->setMinimumHeight(minHeight); + + d->m_previewFrame = new QWidget; + QVBoxLayout *preview_layout = new QVBoxLayout(d->m_previewFrame); + preview_layout->setContentsMargins(0,0,0,0); + preview_layout->addWidget(d->m_previewViewer, 100); + preview_layout->addWidget(d->m_warmingUp, 0); + preview_layout->addWidget(d->m_activityFrame, 0); + preview_layout->addWidget(d->m_btnFrame, 0); + + // Create Options Widget + d->m_optsTabWidget = new KTabWidget; + + // Add the basic options tab + d->m_basicScrollA = new QScrollArea; + d->m_basicScrollA->setWidgetResizable(true); + d->m_basicScrollA->setFrameShape(QFrame::NoFrame); + d->m_optsTabWidget->addTab(d->m_basicScrollA, i18n("Basic Options")); + + // Add the other options tab + d->m_otherScrollA = new QScrollArea; + d->m_otherScrollA->setWidgetResizable(true); + d->m_otherScrollA->setFrameShape(QFrame::NoFrame); + d->m_optsTabWidget->addTab(d->m_otherScrollA, i18n("Scanner Specific Options")); + + + d->m_splitter = new QSplitter(this); + d->m_splitter->addWidget(d->m_optsTabWidget); + d->m_splitter->setStretchFactor(0,0); + d->m_splitter->addWidget(d->m_previewFrame); + d->m_splitter->setStretchFactor(1,100); + + d->m_optionsCollapser = new SplitterCollapser(d->m_splitter, d->m_optsTabWidget); + + QHBoxLayout *base_layout = new QHBoxLayout(this); + base_layout->addWidget(d->m_splitter); + base_layout->setContentsMargins(0,0,0,0); + + // disable the interface in case no device is opened. + d->m_optsTabWidget->setDisabled(true); + d->m_previewViewer->setDisabled(true); + d->m_btnFrame->setDisabled(true); + +} + +KSaneWidget::~KSaneWidget() +{ + while (!closeDevice()) usleep(1000); + // wait for any thread to exit + + s_objectMutex.lock(); + s_objectCount--; + if (s_objectCount <= 0) { + // only delete the find-devices and authorization singletons and call sane_exit + // if this is the last instance + delete d->m_findDevThread; + delete d->m_auth; + sane_exit(); + } + s_objectMutex.unlock(); + delete d; +} + +QString KSaneWidget::vendor() const +{ + d->m_findDevThread->wait(); + d->devListUpdated(); // this is just a wrapped if (m_vendor.isEmpty()) statement if the vendor is known + // devListUpdated here is to ensure that we do not come in between finished and the devListUpdated slot + + return d->m_vendor; +} +QString KSaneWidget::make() const +{ + return vendor(); +} +QString KSaneWidget::model() const +{ + d->m_findDevThread->wait(); + d->devListUpdated(); // this is just a wrapped if (m_vendor.isEmpty()) statement if the vendor is known + // devListUpdated here is to ensure that we do not come in between finished and the devListUpdated slot + + return d->m_model; +} + +QString KSaneWidget::selectDevice(QWidget* parent) +{ + QString selected_name; + QPointer sel = new KSaneDeviceDialog(parent); + + // sel.setDefault(prev_backend); // set default scanner - perhaps application using libksane should remember that + if(sel->exec() == KDialog::Accepted) { + selected_name = sel->getSelectedName(); + } + delete sel; + return selected_name; +} + +void KSaneWidget::initGetDeviceList() const +{ + // update the device list if needed to get the vendor and model info + if (d->m_findDevThread->devicesList().size() == 0) { + //kDebug() << "initGetDeviceList() starting thread..."; + d->m_findDevThread->start(); + } + else { + //kDebug() << "initGetDeviceList() have existing data..."; + d->signalDevListUpdate(); + } +} + +bool KSaneWidget::openDevice(const QString &deviceName) +{ + int i=0; + const SANE_Option_Descriptor *optDesc; + SANE_Status status; + SANE_Word numSaneOptions; + SANE_Int res; + KPasswordDialog *dlg; + KWallet::Wallet *saneWallet; + QString myFolderName("ksane"); + QMap wallet_entry; + + if (d->m_saneHandle != 0) { + // this KSaneWidget already has an open device + return false; + } + + // don't bother trying to open if the device string is empty + if (deviceName.isEmpty()) { + return false; + } + // save the device name + d->m_devName = deviceName; + + // Try to open the device + status = sane_open(deviceName.toLatin1(), &d->m_saneHandle); + + bool password_dialog_ok = true; + + // prepare wallet for authentication and create password dialog + if(status == SANE_STATUS_ACCESS_DENIED) { + saneWallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), winId() ); + + if(saneWallet) { + dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword); + if(!saneWallet->hasFolder(myFolderName)) { + saneWallet->createFolder(myFolderName); + } + saneWallet->setFolder(myFolderName); + saneWallet->readMap(deviceName.toLatin1(), wallet_entry); + if(!wallet_entry.empty() || true) { + dlg->setUsername( wallet_entry["username"] ); + dlg->setPassword( wallet_entry["password"] ); + dlg->setKeepPassword( true ); + } + } else { + dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine); + } + dlg->setPrompt(i18n("Authentication required for resource: %1", deviceName ) ); + + } + + // sane_open failed due to insufficient authorization + // retry opening device with user provided data assisted with kwallet records + while (status == SANE_STATUS_ACCESS_DENIED) { + + password_dialog_ok = dlg->exec(); + if(!password_dialog_ok) { + delete dlg; + d->m_devName.clear(); + return false; //the user canceled + } + + // add/update the device user-name and password for authentication + d->m_auth->setDeviceAuth(d->m_devName, dlg->username(), dlg->password()); + + status = sane_open(deviceName.toLatin1(), &d->m_saneHandle); + + // store password in wallet on successful authentication + if(dlg->keepPassword() && status != SANE_STATUS_ACCESS_DENIED) { + QMap entry; + entry["username"] = dlg->username().toUtf8(); + entry["password"] = dlg->password().toUtf8(); + if(saneWallet) { + saneWallet->writeMap(deviceName.toLatin1(), entry); + } + } + } + + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_open(\"" << deviceName << "\", &handle) failed! status = " << sane_strstatus(status); + d->m_auth->clearDeviceAuth(d->m_devName); + d->m_devName.clear(); + return false; + } + + // update the device list if needed to get the vendor and model info + if (d->m_findDevThread->devicesList().size() == 0) { + d->m_findDevThread->start(); + } + else { + // use the "old" existing list + d->devListUpdated(); + // if m_vendor is not updated it means that the list needs to be updated. + if (d->m_vendor.isEmpty()) { + d->m_findDevThread->start(); + } + } + + // Read the options (start with option 0 the number of parameters) + optDesc = sane_get_option_descriptor(d->m_saneHandle, 0); + if (optDesc == 0) { + d->m_auth->clearDeviceAuth(d->m_devName); + d->m_devName.clear(); + return false; + } + QVarLengthArray data(optDesc->size); + status = sane_control_option(d->m_saneHandle, 0, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + d->m_auth->clearDeviceAuth(d->m_devName); + d->m_devName.clear(); + return false; + } + numSaneOptions = *reinterpret_cast(data.data()); + + // read the rest of the options + for (i=1; im_saneHandle, i))) { + case KSaneOption::TYPE_DETECT_FAIL: + d->m_optList.append(new KSaneOption(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_CHECKBOX: + d->m_optList.append(new KSaneOptCheckBox(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_SLIDER: + d->m_optList.append(new KSaneOptSlider(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_F_SLIDER: + d->m_optList.append(new KSaneOptFSlider(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_COMBO: + d->m_optList.append(new KSaneOptCombo(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_ENTRY: + d->m_optList.append(new KSaneOptEntry(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_GAMMA: + d->m_optList.append(new KSaneOptGamma(d->m_saneHandle, i)); + break; + case KSaneOption::TYPE_BUTTON: + d->m_optList.append(new KSaneOptButton(d->m_saneHandle, i)); + break; + } + } + + // do the connections of the option parameters + for (i=1; im_optList.size(); ++i) { + //kDebug() << d->m_optList.at(i)->name(); + connect (d->m_optList.at(i), SIGNAL(optsNeedReload()), d, SLOT(optReload())); + connect (d->m_optList.at(i), SIGNAL(valsNeedReload()), d, SLOT(scheduleValReload())); + + if (d->m_optList.at(i)->needsPolling()) { + //kDebug() << d->m_optList.at(i)->name() << " needs polling"; + d->m_pollList.append(d->m_optList.at(i)); + KSaneOptCheckBox *buttonOption = qobject_cast(d->m_optList.at(i)); + if (buttonOption) { + connect(buttonOption, SIGNAL(buttonPressed(QString,QString,bool)), + this, SIGNAL(buttonPressed(QString,QString,bool))); + } + } + } + + // start polling the poll options + if (d->m_pollList.size() > 0) { + d->m_optionPollTmr.start(); + } + + // Create the preview thread + d->m_previewThread = new KSanePreviewThread(d->m_saneHandle, &d->m_previewImg); + connect(d->m_previewThread, SIGNAL(finished()), d, SLOT(previewScanDone())); + + // Create the read thread + d->m_scanThread = new KSaneScanThread(d->m_saneHandle, &d->m_scanData); + connect(d->m_scanThread, SIGNAL(finished()), d, SLOT(oneFinalScanDone())); + + // Create the options interface + d->createOptInterface(); + + // try to set KSaneWidget default values + d->setDefaultValues(); + + // Enable the interface + d->m_optsTabWidget->setDisabled(false); + d->m_previewViewer->setDisabled(false); + d->m_btnFrame->setDisabled(false); + + // estimate the preview size and create an empty image + // this is done so that you can select scan area without + // having to scan a preview. + d->updatePreviewSize(); + QTimer::singleShot(1000, d->m_previewViewer, SLOT(zoom2Fit())); + return true; +} + + +bool KSaneWidget::closeDevice() +{ + if (!d->m_saneHandle) { + return true; + } + + if (d->m_scanThread->isRunning()) { + d->m_scanThread->cancelScan(); + d->m_closeDevicePending = true; + return false; + } + + if (d->m_previewThread->isRunning()) { + d->m_previewThread->cancelScan(); + d->m_closeDevicePending = true; + return false; + } + + d->m_auth->clearDeviceAuth(d->m_devName); + // else + sane_close(d->m_saneHandle); + d->m_saneHandle = 0; + d->clearDeviceOptions(); + + // disable the interface until a new device is opened. + d->m_optsTabWidget->setDisabled(true); + d->m_previewViewer->setDisabled(true); + d->m_btnFrame->setDisabled(true); + + return true; +} + +#define inc_pixel(x,y,ppl) { x++; if (x>=ppl) { y++; x=0;} } + +QImage KSaneWidget::toQImageSilent(const QByteArray &data, + int width, + int height, + int bytes_per_line, + ImageFormat format) +{ + QImage img; + int j=0; + QVector table; + QRgb *imgLine; + + switch (format) + { + case FormatBlackWhite: + img = QImage((uchar*)data.data(), + width, + height, + bytes_per_line, + QImage::Format_Mono); + // The color table must be set + table.append(0xFFFFFFFF); + table.append(0xFF000000); + img.setColorTable(table); + break; + + case FormatGrayScale8: + { + img = QImage(width, height, QImage::Format_RGB32); + int dI = 0; + for (int i=0; (i(img.scanLine(i)); + for (j=0; (j(img.scanLine(i)); + for (j=0; (j(img.scanLine(i)); + for (j=0; (j(img.scanLine(i)); + for (j=0; (jalertUser(KSaneWidget::ErrorGeneral, i18n("The image data contained 16 bits per color, " + "but the color depth has been truncated to 8 bits per color.")); + } + return toQImageSilent(data, width, height, bytes_per_line, format); +} + +void KSaneWidget::scanFinal() +{ + if (d->m_btnFrame->isEnabled()) { + d->startFinalScan(); + } + else { + // if the button frame is disabled, there is no open device to scan from + emit scanDone(KSaneWidget::ErrorGeneral, ""); + } +} + +void KSaneWidget::scanCancel() +{ + if (d->m_scanThread->isRunning()) { + d->m_scanThread->cancelScan(); + } + + if (d->m_previewThread->isRunning()) { + d->m_previewThread->cancelScan(); + } +} + +void KSaneWidget::setPreviewResolution(float dpi) +{ + d->m_previewDPI = dpi; +} + +void KSaneWidget::getOptVals(QMap &opts) +{ + KSaneOption *option; + opts.clear(); + QString tmp; + + for (int i=1; im_optList.size(); i++) { + option = d->m_optList.at(i); + if (option->getValue(tmp)) { + opts[option->name()] = tmp; + } + } + // Special handling for non sane option + opts[InvetColorsOption] = d->m_invertColors->isChecked() ? "true" : "false"; +} + +bool KSaneWidget::getOptVal(const QString &optname, QString &value) +{ + KSaneOption *option; + + if ((option = d->getOption(optname)) != 0) { + return option->getValue(value); + } + // Special handling for non sane option + if (optname == InvetColorsOption) { + value = d->m_invertColors->isChecked() ? "true" : "false"; + return true; + } + return false; +} + +int KSaneWidget::setOptVals(const QMap &opts) +{ + QString tmp; + int i; + int ret=0; + + for (i=0; im_optList.size(); i++) { + if (opts.contains(d->m_optList.at(i)->name())) { + tmp = opts[d->m_optList.at(i)->name()]; + if (d->m_optList.at(i)->setValue(tmp) == false) { + ret++; + } + } + } + if ((d->m_splitGamChB) && + (d->m_optGamR) && + (d->m_optGamG) && + (d->m_optGamB)) + { + // check if the current gamma values are identical. if they are identical, + // uncheck the "Separate color intensity tables" checkbox + QString redGamma; + QString greenGamma; + QString blueGamma; + d->m_optGamR->getValue(redGamma); + d->m_optGamG->getValue(greenGamma); + d->m_optGamB->getValue(blueGamma); + if ((redGamma == greenGamma) && (greenGamma == blueGamma)) { + d->m_splitGamChB->setChecked(false); + // set the values to the common gamma widget + d->m_commonGamma->setValues(redGamma); + } + else { + d->m_splitGamChB->setChecked(true); + } + } + + // special handling for non-sane option + if (opts.contains(InvetColorsOption)) { + tmp = opts[InvetColorsOption]; + if ((tmp.compare("true", Qt::CaseInsensitive) == 0) || + (tmp.compare("1") == 0)) + { + d->m_invertColors->setChecked(true); + } + else { + d->m_invertColors->setChecked(false); + } + } + return ret; +} + +bool KSaneWidget::setOptVal(const QString &option, const QString &value) +{ + KSaneOption *opt; + + if ((opt = d->getOption(option)) != 0) { + if (opt->setValue(value)) { + if ((d->m_splitGamChB) && + (d->m_optGamR) && + (d->m_optGamG) && + (d->m_optGamB) && + ((opt == d->m_optGamR) || + (opt == d->m_optGamG) || + (opt == d->m_optGamB))) + { + // check if the current gamma values are identical. if they are identical, + // uncheck the "Separate color intensity tables" checkbox + QString redGamma; + QString greenGamma; + QString blueGamma; + d->m_optGamR->getValue(redGamma); + d->m_optGamG->getValue(greenGamma); + d->m_optGamB->getValue(blueGamma); + if ((redGamma == greenGamma) && (greenGamma == blueGamma)) { + d->m_splitGamChB->setChecked(false); + // set the values to the common gamma widget + d->m_commonGamma->setValues(redGamma); + } + else { + d->m_splitGamChB->setChecked(true); + } + } + return true; + } + } + + // special handling for non-sane option + if (option == InvetColorsOption) { + if ((value.compare("true", Qt::CaseInsensitive) == 0) || + (value.compare("1") == 0)) + { + d->m_invertColors->setChecked(true); + } + else { + d->m_invertColors->setChecked(false); + } + return true; + } + + return false; +} + +void KSaneWidget::setScanButtonText(const QString &scanLabel) +{ + if (d->m_scanBtn == 0) { + kError() << "setScanButtonText was called before KSaneWidget was initialized"; + return; + } + d->m_scanBtn->setText(scanLabel); +} + +void KSaneWidget::setPreviewButtonText(const QString &previewLabel) +{ + if (d->m_scanBtn == 0) { + kError() << "setPreviewButtonText was called before KSaneWidget was initialized"; + return; + } + d->m_prevBtn->setText(previewLabel); +} + +void KSaneWidget::enableAutoSelect(bool enable) +{ + d->m_autoSelect = enable; +} + +float KSaneWidget::currentDPI() +{ + if (d->m_optRes) { + float value; + if (d->m_optRes->getValue(value)) { + return value; + } + } + return 0.0; +} + +float KSaneWidget::scanAreaWidth() +{ + float result = 0.0; + if (d->m_optBrX) { + if (d->m_optBrX->getUnit() == SANE_UNIT_PIXEL) { + d->m_optBrX->getMaxValue(result); + result = result / currentDPI() / 25.4; + } + else if (d->m_optBrX->getUnit() == SANE_UNIT_MM) { + d->m_optBrX->getMaxValue(result); + } + } + return result; +} + +float KSaneWidget::scanAreaHeight() +{ + float result = 0.0; + if (d->m_optBrY) { + if (d->m_optBrY->getUnit() == SANE_UNIT_PIXEL) { + d->m_optBrY->getMaxValue(result); + result = result / currentDPI() / 25.4; + } + else if (d->m_optBrY->getUnit() == SANE_UNIT_MM) { + d->m_optBrY->getMaxValue(result); + } + } + return result; +} + +void KSaneWidget::setSelection(QPointF topLeft, QPointF bottomRight) +{ + if (!d->m_optBrX || !d->m_optBrY || !d->m_optTlX || !d->m_optTlY) { + return; + } + float xmax, ymax; + d->m_optBrX->getMaxValue(xmax); + d->m_optBrY->getMaxValue(ymax); + if (topLeft.x() < 0.0 || topLeft.y() < 0.0 || bottomRight.x() < 0.0 || bottomRight.y() < 0.0) { + d->m_previewViewer->clearActiveSelection(); + d->m_optTlX->setValue(0.0); + d->m_optTlY->setValue(0.0); + d->m_optBrX->setValue(xmax); + d->m_optBrY->setValue(ymax); + } + + if (d->m_optBrY->getUnit() == SANE_UNIT_MM) { + // clear selection if values are out of bounds + if (topLeft.x() > xmax || topLeft.y() > ymax || bottomRight.x() > xmax || bottomRight.y() > ymax) { + d->m_previewViewer->clearActiveSelection(); + d->m_optTlX->setValue(0.0); + d->m_optTlY->setValue(0.0); + d->m_optBrX->setValue(xmax); + d->m_optBrY->setValue(ymax); + } + d->m_previewViewer->setSelection(topLeft.x(), topLeft.y(), bottomRight.x(), bottomRight.y()); + d->m_optTlX->setValue(topLeft.x()); + d->m_optTlY->setValue(topLeft.y()); + d->m_optBrX->setValue(bottomRight.x()); + d->m_optBrY->setValue(bottomRight.y()); + } + else if (d->m_optBrY->getUnit() == SANE_UNIT_PIXEL) { + const float mmperinch = 25.4; + const float dpi = currentDPI(); + const float m = dpi / mmperinch; + if (m*topLeft.x() > xmax || m*topLeft.y() > ymax || m*bottomRight.x() > xmax || m*bottomRight.y() > ymax) { + d->m_previewViewer->clearActiveSelection(); + d->m_optTlX->setValue(0.0); + d->m_optTlY->setValue(0.0); + d->m_optBrX->setValue(xmax); + d->m_optBrY->setValue(ymax); + } + d->m_previewViewer->setSelection(m*topLeft.x(), m*topLeft.y(), m*bottomRight.x(), m*bottomRight.y()); + d->m_optTlX->setValue(m*topLeft.x()); + d->m_optTlY->setValue(m*topLeft.y()); + d->m_optBrX->setValue(m*bottomRight.x()); + d->m_optBrY->setValue(m*bottomRight.y()); + } +} + +void KSaneWidget::setOptionsCollapsed(bool collapse) +{ + if (collapse) { + QTimer::singleShot(0, d->m_optionsCollapser, SLOT(slotCollapse())); + } + else { + QTimer::singleShot(0, d->m_optionsCollapser, SLOT(slotRestore())); + } +} + +void KSaneWidget::setScanButtonHidden(bool hidden) +{ + d->m_scanBtn->setHidden(hidden); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/ksane_widget_private.cpp b/libksane/libksane/ksane_widget_private.cpp new file mode 100644 index 00000000..1fdb498e --- /dev/null +++ b/libksane/libksane/ksane_widget_private.cpp @@ -0,0 +1,1134 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2008 by Kare Sars + * Copyright (C) 2007-2008 by Gilles Caulier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "ksane_widget_private.h" +#include "ksane_widget_private.moc" + +// Qt includes +#include +#include +#include +#include +#include + +// KDE includes +#include + +#define SCALED_PREVIEW_MAX_SIDE 400 + +static const int ActiveSelection = 100000; + +namespace KSaneIface +{ + +KSaneWidgetPrivate::KSaneWidgetPrivate(KSaneWidget *parent): +q(parent) +{ + // Device independent UI variables + m_optsTabWidget = 0; + m_basicOptsTab = 0; + m_otherOptsTab = 0; + m_zInBtn = 0; + m_zOutBtn = 0; + m_zSelBtn = 0; + m_zFitBtn = 0; + m_clearSelBtn = 0; + m_prevBtn = 0; + m_scanBtn = 0; + m_cancelBtn = 0; + m_previewViewer = 0; + m_autoSelect = true; + m_selIndex = ActiveSelection; + m_warmingUp = 0; + m_progressBar = 0; + + // scanning variables + m_isPreview = false; + + m_saneHandle = 0; + m_previewThread = 0; + m_scanThread = 0; + + m_splitGamChB = 0; + m_commonGamma = 0; + m_previewDPI = 0; + m_invertColors = 0; + + m_previewWidth = 0; + m_previewHeight = 0; + + clearDeviceOptions(); + + m_findDevThread = FindSaneDevicesThread::getInstance(); + connect(m_findDevThread, SIGNAL(finished()), this, SLOT(devListUpdated())); + connect(m_findDevThread, SIGNAL(finished()), this, SLOT(signalDevListUpdate())); + + m_auth = KSaneAuth::getInstance(); + m_optionPollTmr.setInterval(100); + connect(&m_optionPollTmr, SIGNAL(timeout()), this, SLOT(pollPollOptions())); +} + +void KSaneWidgetPrivate::clearDeviceOptions() +{ + m_optSource = 0; + m_colorOpts = 0; + m_optNegative = 0; + m_optFilmType = 0; + m_optMode = 0; + m_optDepth = 0; + m_optRes = 0; + m_optResX = 0; + m_optResY = 0; + m_optTlX = 0; + m_optTlY = 0; + m_optBrX = 0; + m_optBrY = 0; + m_optGamR = 0; + m_optGamG = 0; + m_optGamB = 0; + m_optPreview = 0; + m_optWaitForBtn = 0; + m_scanOngoing = false; + m_closeDevicePending = false; + + // delete all the options in the list. + while (!m_optList.isEmpty()) { + delete m_optList.takeFirst(); + } + m_pollList.clear(); + m_optionPollTmr.stop(); + + // remove the remaining layouts/widgets and read thread + delete m_basicOptsTab; + m_basicOptsTab = 0; + + delete m_otherOptsTab; + m_otherOptsTab = 0; + + delete m_previewThread; + m_previewThread = 0; + + delete m_scanThread; + m_scanThread = 0; + + m_devName.clear(); +} + +void KSaneWidgetPrivate::devListUpdated() +{ + if (m_vendor.isEmpty()) { + const QList list = m_findDevThread->devicesList(); + if (list.size() == 0) return; + for (int i=0; iavailableDevices(m_findDevThread->devicesList())); +} + +KSaneWidget::ImageFormat KSaneWidgetPrivate::getImgFormat(SANE_Parameters ¶ms) +{ + switch(params.format) + { + case SANE_FRAME_GRAY: + switch(params.depth) + { + case 1: + return KSaneWidget::FormatBlackWhite; + case 8: + return KSaneWidget::FormatGrayScale8; + case 16: + return KSaneWidget::FormatGrayScale16; + default: + return KSaneWidget::FormatNone; + } + case SANE_FRAME_RGB: + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + switch (params.depth) + { + case 8: + return KSaneWidget::FormatRGB_8_C; + case 16: + return KSaneWidget::FormatRGB_16_C; + default: + return KSaneWidget::FormatNone; + } +} + return KSaneWidget::FormatNone; +} + +int KSaneWidgetPrivate::getBytesPerLines(SANE_Parameters ¶ms) +{ + switch (getImgFormat(params)) + { + case KSaneWidget::FormatBlackWhite: + case KSaneWidget::FormatGrayScale8: + case KSaneWidget::FormatGrayScale16: + return params.bytes_per_line; + + case KSaneWidget::FormatRGB_8_C: + return params.pixels_per_line*3; + + case KSaneWidget::FormatRGB_16_C: + return params.pixels_per_line*6; + + case KSaneWidget::FormatNone: + case KSaneWidget::FormatBMP: // to remove warning (BMP is omly valid in the twain wrapper) + return 0; + } + return 0; +} + + +KSaneOption *KSaneWidgetPrivate::getOption(const QString &name) +{ + int i; + for (i=0; iname() == name) { + return m_optList.at(i); + } + } + return 0; +} + +void KSaneWidgetPrivate::createOptInterface() +{ + m_basicOptsTab = new QWidget; + m_basicScrollA->setWidget(m_basicOptsTab); + + QVBoxLayout *basic_layout = new QVBoxLayout(m_basicOptsTab); + KSaneOption *option; + // Scan Source + if ((option = getOption(SANE_NAME_SCAN_SOURCE)) != 0) { + m_optSource = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + connect(m_optSource, SIGNAL(valueChanged()), this, SLOT(checkInvert()), Qt::QueuedConnection); + } + // film-type (note: No translation) + if ((option = getOption(QString("film-type"))) != 0) { + m_optFilmType = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + connect(m_optFilmType, SIGNAL(valueChanged()), this, SLOT(checkInvert()), Qt::QueuedConnection); + } + else if ((option = getOption(SANE_NAME_NEGATIVE)) != 0) { + m_optNegative = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + // Scan mode + if ((option = getOption(SANE_NAME_SCAN_MODE)) != 0) { + m_optMode = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + // Bitdepth + if ((option = getOption(SANE_NAME_BIT_DEPTH)) != 0) { + m_optDepth = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + // Threshold + if ((option = getOption(SANE_NAME_THRESHOLD)) != 0) { + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + // Resolution + if ((option = getOption(SANE_NAME_SCAN_RESOLUTION)) != 0) { + m_optRes = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + // These two next resolution options are a bit tricky. + if ((option = getOption(SANE_NAME_SCAN_X_RESOLUTION)) != 0) { + m_optResX = option; + if (!m_optRes) m_optRes = m_optResX; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + if ((option = getOption(SANE_NAME_SCAN_Y_RESOLUTION)) != 0) { + m_optResY = option; + option->createWidget(m_basicOptsTab); + basic_layout->addWidget(option->widget()); + } + + // save a pointer to the preview option if possible + if ((option = getOption(SANE_NAME_PREVIEW)) != 0) { + m_optPreview = option; + } + + // save a pointer to the "wait-for-button" option if possible (Note: No translation) + if ((option = getOption("wait-for-button")) != 0) { + m_optWaitForBtn = option; + } + + // scan area (Do not add the widgets) + if ((option = getOption(SANE_NAME_SCAN_TL_X)) != 0) { + m_optTlX = option; + connect (option, SIGNAL(fValueRead(float)), this, SLOT(setTLX(float))); + } + if ((option = getOption(SANE_NAME_SCAN_TL_Y)) != 0) { + m_optTlY = option; + connect (option, SIGNAL(fValueRead(float)), this, SLOT(setTLY(float))); + } + if ((option = getOption(SANE_NAME_SCAN_BR_X)) != 0) { + m_optBrX = option; + connect (option, SIGNAL(fValueRead(float)), this, SLOT(setBRX(float))); + } + if ((option = getOption(SANE_NAME_SCAN_BR_Y)) != 0) { + m_optBrY = option; + connect (option, SIGNAL(fValueRead(float)), this, SLOT(setBRY(float))); + } + + // Color Options Frame + m_colorOpts = new QWidget(m_basicOptsTab); + basic_layout->addWidget(m_colorOpts); + QVBoxLayout *color_lay = new QVBoxLayout(m_colorOpts); + color_lay->setContentsMargins(0,0,0,0); + + // Add Color correction to the color "frame" + if ((option = getOption(SANE_NAME_BRIGHTNESS)) != 0) { + option->createWidget(m_colorOpts); + color_lay->addWidget(option->widget()); + } + if ((option = getOption(SANE_NAME_CONTRAST)) != 0) { + option->createWidget(m_colorOpts); + color_lay->addWidget(option->widget()); + } + + // Add gamma tables to the color "frame" + QWidget *gamma_frm = new QWidget(m_colorOpts); + color_lay->addWidget(gamma_frm); + QVBoxLayout *gam_frm_l = new QVBoxLayout(gamma_frm); + gam_frm_l->setContentsMargins(0,0,0,0); + + if ((option = getOption(SANE_NAME_GAMMA_VECTOR_R)) != 0) { + m_optGamR = option; + option->createWidget(gamma_frm); + gam_frm_l->addWidget(option->widget()); + } + if ((option = getOption(SANE_NAME_GAMMA_VECTOR_G)) != 0) { + m_optGamG = option; + option->createWidget(gamma_frm); + gam_frm_l->addWidget(option->widget()); + } + if ((option = getOption(SANE_NAME_GAMMA_VECTOR_B)) != 0) { + m_optGamB = option; + option->createWidget(gamma_frm); + gam_frm_l->addWidget(option->widget()); + } + + if ((m_optGamR != 0) && (m_optGamG != 0) && (m_optGamB != 0)) { + LabeledGamma *gamma = reinterpret_cast(m_optGamR->widget()); + m_commonGamma = new LabeledGamma(m_colorOpts, i18n(SANE_TITLE_GAMMA_VECTOR), gamma->size()); + + color_lay->addWidget(m_commonGamma); + + m_commonGamma->setToolTip(i18n(SANE_DESC_GAMMA_VECTOR)); + + connect(m_commonGamma, SIGNAL(gammaChanged(int,int,int)), m_optGamR->widget(), SLOT(setValues(int,int,int))); + connect(m_commonGamma, SIGNAL(gammaChanged(int,int,int)), m_optGamG->widget(), SLOT(setValues(int,int,int))); + connect(m_commonGamma, SIGNAL(gammaChanged(int,int,int)), m_optGamB->widget(), SLOT(setValues(int,int,int))); + + m_splitGamChB = new LabeledCheckbox(m_colorOpts, i18n("Separate color intensity tables")); + color_lay->addWidget(m_splitGamChB); + + connect (m_splitGamChB, SIGNAL(toggled(bool)), gamma_frm, SLOT(setVisible(bool))); + connect (m_splitGamChB, SIGNAL(toggled(bool)), m_commonGamma, SLOT(setHidden(bool))); + + gamma_frm->hide(); + } + + if ((option = getOption(SANE_NAME_BLACK_LEVEL)) != 0) { + option->createWidget(m_colorOpts); + color_lay->addWidget(option->widget()); + } + if ((option = getOption(SANE_NAME_WHITE_LEVEL)) != 0) { + option->createWidget(m_colorOpts); + color_lay->addWidget(option->widget()); + } + + m_invertColors = new LabeledCheckbox(m_colorOpts, i18n("Invert colors")); + color_lay->addWidget(m_invertColors); + m_invertColors->setChecked(false); + connect(m_invertColors, SIGNAL(toggled(bool)), this, SLOT(invertPreview())); + + // add a stretch to the end to keep the parameters at the top + basic_layout->addStretch(); + + + // Remaining (un known) options go to the "Other Options" + m_otherOptsTab = new QWidget; + m_otherScrollA->setWidget(m_otherOptsTab); + + QVBoxLayout *other_layout = new QVBoxLayout(m_otherOptsTab); + + // add the remaining parameters + for (int i=0; iwidget() == 0) && + (m_optList.at(i)->name() != SANE_NAME_SCAN_TL_X) && + (m_optList.at(i)->name() != SANE_NAME_SCAN_TL_Y) && + (m_optList.at(i)->name() != SANE_NAME_SCAN_BR_X) && + (m_optList.at(i)->name() != SANE_NAME_SCAN_BR_Y) && + (m_optList.at(i)->name() != SANE_NAME_PREVIEW) && + (m_optList.at(i)->hasGui())) + { + m_optList.at(i)->createWidget(m_otherOptsTab); + other_layout->addWidget(m_optList.at(i)->widget()); + } + } + + // add a stretch to the end to keep the parameters at the top + other_layout->addStretch(); + + // calculate label widths + int labelWidth = 0; + KSaneOptionWidget *tmpOption; + // Basic Options + for (int i=0; icount(); i++) { + if (basic_layout->itemAt(i) && basic_layout->itemAt(i)->widget()) { + tmpOption = qobject_cast(basic_layout->itemAt(i)->widget()); + if (tmpOption) { + labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); + } + } + } + // Color Options + for (int i=0; icount(); i++) { + if (basic_layout->itemAt(i) && basic_layout->itemAt(i)->widget()) { + tmpOption = qobject_cast(basic_layout->itemAt(i)->widget()); + if (tmpOption) { + labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); + } + } + } + // Set label widths + for (int i=0; icount(); i++) { + if (basic_layout->itemAt(i) && basic_layout->itemAt(i)->widget()) { + tmpOption = qobject_cast(basic_layout->itemAt(i)->widget()); + if (tmpOption) { + tmpOption->setLabelWidth(labelWidth); + } + } + } + for (int i=0; icount(); i++) { + if (color_lay->itemAt(i) && color_lay->itemAt(i)->widget()) { + tmpOption = qobject_cast(color_lay->itemAt(i)->widget()); + if (tmpOption) { + tmpOption->setLabelWidth(labelWidth); + } + } + } + // Other Options + labelWidth=0; + for (int i=0; icount(); i++) { + if (other_layout->itemAt(i) && other_layout->itemAt(i)->widget()) { + tmpOption = qobject_cast(other_layout->itemAt(i)->widget()); + if (tmpOption) { + labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); + } + } + } + for (int i=0; icount(); i++) { + if (other_layout->itemAt(i) && other_layout->itemAt(i)->widget()) { + tmpOption = qobject_cast(other_layout->itemAt(i)->widget()); + if (tmpOption) { + tmpOption->setLabelWidth(labelWidth); + } + } + } + + // encsure that we do not get a scrollbar at the bottom of the option of the options + int min_width = m_basicOptsTab->sizeHint().width(); + if (min_width < m_otherOptsTab->sizeHint().width()) { + min_width = m_otherOptsTab->sizeHint().width(); + } + + m_optsTabWidget->setMinimumWidth(min_width + m_basicScrollA->verticalScrollBar()->sizeHint().width() + 5); +} + +void KSaneWidgetPrivate::setDefaultValues() +{ + KSaneOption *option; + + // Try to get Color mode by default + if ((option = getOption(SANE_NAME_SCAN_MODE)) != 0) { + option->setValue(i18n(SANE_VALUE_SCAN_MODE_COLOR)); + } + + // Try to set 8 bit color + if ((option = getOption(SANE_NAME_BIT_DEPTH)) != 0) { + option->setValue(8); + } + + // Try to set Scan resolution to 600 DPI + if (m_optRes != 0) { + m_optRes->setValue(600); + } +} + +void KSaneWidgetPrivate::scheduleValReload() +{ + m_readValsTmr.start(5); +} + +void KSaneWidgetPrivate::optReload() +{ + int i; + + for (i=0; ireadOption(); + // Also read the values + m_optList.at(i)->readValue(); + } + // Gamma table special case + if (m_optGamR && m_optGamG && m_optGamB) { + m_commonGamma->setHidden(m_optGamR->state() == KSaneOption::STATE_HIDDEN); + m_splitGamChB->setHidden(m_optGamR->state() == KSaneOption::STATE_HIDDEN); + } + + // estimate the preview size and create an empty image + // this is done so that you can select scan area without + // having to scan a preview. + updatePreviewSize(); + + // ensure that we do not get a scrollbar at the bottom of the option of the options + int min_width = m_basicOptsTab->sizeHint().width(); + if (min_width < m_otherOptsTab->sizeHint().width()) { + min_width = m_otherOptsTab->sizeHint().width(); + } + + m_optsTabWidget->setMinimumWidth(min_width + m_basicScrollA->verticalScrollBar()->sizeHint().width() + 5); + + m_previewViewer->zoom2Fit(); +} + +void KSaneWidgetPrivate::valReload() +{ + int i; + QString tmp; + + for (i=0; ireadValue(); + } + +} + +void KSaneWidgetPrivate::handleSelection(float tl_x, float tl_y, float br_x, float br_y) { + + if ((m_optTlX == 0) || (m_optTlY == 0) || (m_optBrX == 0) || (m_optBrY == 0)) { + // clear the selection since we can not set one + m_previewViewer->setTLX(0); + m_previewViewer->setTLY(0); + m_previewViewer->setBRX(0); + m_previewViewer->setBRY(0); + return; + } + float max_x, max_y; + + if ((m_previewImg.width()==0) || (m_previewImg.height()==0)) return; + + m_optBrX->getMaxValue(max_x); + m_optBrY->getMaxValue(max_y); + float ftl_x = tl_x*max_x; + float ftl_y = tl_y*max_y; + float fbr_x = br_x*max_x; + float fbr_y = br_y*max_y; + + m_optTlX->setValue(ftl_x); + m_optTlY->setValue(ftl_y); + m_optBrX->setValue(fbr_x); + m_optBrY->setValue(fbr_y); +} + +void KSaneWidgetPrivate::setTLX(float ftlx) +{ + // ignore this during an active scan + if (m_previewThread->isRunning()) return; + if (m_scanThread->isRunning()) return; + if (m_scanOngoing) return; + + float max, ratio; + + //kDebug() << "setTLX " << ftlx; + m_optBrX->getMaxValue(max); + ratio = ftlx / max; + //kDebug() << " -> " << ratio; + m_previewViewer->setTLX(ratio); +} + +void KSaneWidgetPrivate::setTLY(float ftly) +{ + // ignore this during an active scan + if (m_previewThread->isRunning()) return; + if (m_scanThread->isRunning()) return; + if (m_scanOngoing) return; + + float max, ratio; + + //kDebug() << "setTLY " << ftly; + m_optBrY->getMaxValue(max); + ratio = ftly / max; + //kDebug() << " -> " << ratio; + m_previewViewer->setTLY(ratio); +} + +void KSaneWidgetPrivate::setBRX(float fbrx) +{ + // ignore this during an active scan + if (m_previewThread->isRunning()) return; + if (m_scanThread->isRunning()) return; + if (m_scanOngoing) return; + + float max, ratio; + + //kDebug() << "setBRX " << fbrx; + m_optBrX->getMaxValue(max); + ratio = fbrx / max; + //kDebug() << " -> " << ratio; + m_previewViewer->setBRX(ratio); +} + +void KSaneWidgetPrivate::setBRY(float fbry) +{ + // ignore this during an active scan + if (m_previewThread->isRunning()) return; + if (m_scanThread->isRunning()) return; + if (m_scanOngoing) return; + + float max, ratio; + + //kDebug() << "setBRY " << fbry; + m_optBrY->getMaxValue(max); + ratio = fbry / max; + //kDebug() << " -> " << ratio; + m_previewViewer->setBRY(ratio); +} + +void KSaneWidgetPrivate::updatePreviewSize() +{ + float max_x=0, max_y=0; + float ratio; + int x,y; + + // check if an update is necessary + if (m_optBrX != 0) { + m_optBrX->getMaxValue(max_x); + } + if (m_optBrY != 0) { + m_optBrY->getMaxValue(max_y); + } + if ((max_x == m_previewWidth) && (max_y == m_previewHeight)) { + //kDebug() << "no preview size change"; + return; + } + + // The preview size has changed + m_previewWidth = max_x; + m_previewHeight = max_y; + + // set the scan area to the whole area + m_previewViewer->clearSelections(); + if (m_optTlX != 0) { + m_optTlX->setValue(0); + } + if (m_optTlY != 0) { + m_optTlY->setValue(0); + } + + if (m_optBrX != 0) { + m_optBrX->setValue(max_x); + } + if (m_optBrY != 0) { + m_optBrY->setValue(max_y); + } + + // create a "scaled" image of the preview + ratio = max_x/max_y; + if (ratio < 1) { + x=SCALED_PREVIEW_MAX_SIDE; + y=(int)(SCALED_PREVIEW_MAX_SIDE/ratio); + } + else { + y=SCALED_PREVIEW_MAX_SIDE; + x=(int)(SCALED_PREVIEW_MAX_SIDE/ratio); + } + + m_previewImg = QImage(x, y, QImage::Format_RGB32); + m_previewImg.fill(0xFFFFFFFF); + + // set the new image + m_previewViewer->setQImage(&m_previewImg); +} + +void KSaneWidgetPrivate::startPreviewScan() +{ + if (m_scanOngoing) return; + m_scanOngoing = true; + + SANE_Status status; + float max_x, max_y; + float dpi; + + // store the current settings of parameters to be changed + if (m_optDepth != 0) m_optDepth->storeCurrentData(); + if (m_optRes != 0) m_optRes->storeCurrentData(); + if (m_optResX != 0) m_optResX->storeCurrentData(); + if (m_optResY != 0) m_optResY->storeCurrentData(); + if (m_optPreview != 0) m_optPreview->storeCurrentData(); + + // check if we can modify the selection + if ((m_optTlX != 0) && (m_optTlY != 0) && + (m_optBrX != 0) && (m_optBrY != 0)) + { + // get maximums + m_optBrX->getMaxValue(max_x); + m_optBrY->getMaxValue(max_y); + // select the whole area + m_optTlX->setValue(0); + m_optTlY->setValue(0); + m_optBrX->setValue(max_x); + m_optBrY->setValue(max_y); + + } + else { + // no use to try auto selections if you can not use them + m_autoSelect = false; + } + + if (m_optRes != 0) { + if (m_previewDPI >= 25.0) { + m_optRes->setValue(m_previewDPI); + if ((m_optResY != 0) && (m_optRes->name() == SANE_NAME_SCAN_X_RESOLUTION)) { + m_optResY->setValue(m_previewDPI); + } + } + else { + // set the resopution to getMinValue and increase if necessary + SANE_Parameters params; + m_optRes->getMinValue(dpi); + do { + m_optRes->setValue(dpi); + if ((m_optResY != 0) && (m_optRes->name() == SANE_NAME_SCAN_X_RESOLUTION)) { + m_optResY->setValue(dpi); + } + //check what image size we would get in a scan + status = sane_get_parameters(m_saneHandle, ¶ms); + if (status != SANE_STATUS_GOOD) { + kDebug() << "sane_get_parameters=" << sane_strstatus(status); + previewScanDone(); + return; + } + + if (dpi > 600) break; + + // Increase the dpi value + dpi += 25.0; + } + while ((params.pixels_per_line < 300) || ((params.lines > 0) && (params.lines < 300))); + + if (params.pixels_per_line == 0) { + // This is a security measure for broken backends + m_optRes->getMinValue(dpi); + m_optRes->setValue(dpi); + kDebug() << "Setting minimum DPI value for a broken back-end"; + } + } + } + + // set preview option to true if possible + if (m_optPreview != 0) m_optPreview->setValue(SANE_TRUE); + + // execute valReload if there is a pending value reload + while (m_readValsTmr.isActive()) { + m_readValsTmr.stop(); + valReload(); + } + + // clear the preview + m_previewViewer->clearHighlight(); + m_previewViewer->clearSelections(); + m_previewImg.fill(0xFFFFFFFF); + updatePreviewSize(); + + setBusy(true); + + m_progressBar->setValue(0); + m_isPreview = true; + m_previewThread->setPreviewInverted(m_invertColors->isChecked()); + m_previewThread->start(); + m_updProgressTmr.start(); +} + +void KSaneWidgetPrivate::previewScanDone() +{ + // even if the scan is finished successfully we need to call sane_cancel() + sane_cancel(m_saneHandle); + + if (m_closeDevicePending) { + setBusy(false); + sane_close(m_saneHandle); + m_saneHandle = 0; + clearDeviceOptions(); + emit (q->scanDone(KSaneWidget::NoError, "")); + return; + } + + // restore the original settings of the changed parameters + if (m_optDepth != 0) m_optDepth->restoreSavedData(); + if (m_optRes != 0) m_optRes->restoreSavedData(); + if (m_optResX != 0) m_optResX->restoreSavedData(); + if (m_optResY != 0) m_optResY->restoreSavedData(); + if (m_optPreview != 0) m_optPreview->restoreSavedData(); + + m_previewViewer->setQImage(&m_previewImg); + m_previewViewer->zoom2Fit(); + + if ((m_previewThread->status != SANE_STATUS_GOOD) && + (m_previewThread->status != SANE_STATUS_EOF)) + { + alertUser(KSaneWidget::ErrorGeneral, i18n(sane_strstatus(m_previewThread->status))); + } + else if (m_autoSelect) { + m_previewViewer->findSelections(); + } + + setBusy(false); + m_scanOngoing = false; + m_updProgressTmr.stop(); + + emit (q->scanDone(KSaneWidget::NoError, "")); + + return; +} + + +void KSaneWidgetPrivate::startFinalScan() +{ + if (m_scanOngoing) return; + m_scanOngoing = true; + m_isPreview = false; + + float x1=0,y1=0, x2=0,y2=0, max_x, max_y; + + m_selIndex = 0; + + if ((m_optTlX != 0) && (m_optTlY != 0) && (m_optBrX != 0) && (m_optBrY != 0)) { + // get maximums + m_optBrX->getMaxValue(max_x); + m_optBrY->getMaxValue(max_y); + + // reead the selection from the viewer + m_previewViewer->selectionAt(m_selIndex, x1,y1,x2,y2); + m_previewViewer->setHighlightArea(x1,y1,x2,y2); + m_selIndex++; + + // calculate the option values + x1 *= max_x; y1 *= max_y; + x2 *= max_x; y2 *= max_y; + + // now set the selection + m_optTlX->setValue(x1); + m_optTlY->setValue(y1); + m_optBrX->setValue(x2); + m_optBrY->setValue(y2); + } + + // execute a pending value reload + while (m_readValsTmr.isActive()) { + m_readValsTmr.stop(); + valReload(); + } + + setBusy(true); + m_updProgressTmr.start(); + m_scanThread->setImageInverted(m_invertColors->isChecked()); + m_scanThread->start(); +} + +void KSaneWidgetPrivate::oneFinalScanDone() +{ + m_updProgressTmr.stop(); + updateProgress(); + + if (m_closeDevicePending) { + setBusy(false); + sane_close(m_saneHandle); + m_saneHandle = 0; + clearDeviceOptions(); + return; + } + + if (m_scanThread->frameStatus() == KSaneScanThread::READ_READY) + { + // scan finished OK + SANE_Parameters params = m_scanThread->saneParameters(); + int lines = params.lines; + if (lines == -1) { + // this is probably a handscanner -> calculate the size from the read data + int bytesPerLine = qMax(getBytesPerLines(params), 1); // ensure no div by 0 + lines = m_scanData.size() / bytesPerLine; + } + emit (q->imageReady(m_scanData, + params.pixels_per_line, + lines, + getBytesPerLines(params), + (int)getImgFormat(params))); + + // now check if we should have automatic ADF batch scaning + if (m_optSource){ + QString source; + m_optSource->getValue(source); + + if (source.contains("Automatic Document Feeder")) { + // in batch mode only one area can be scanned per page + //kDebug() << "source == \"Automatic Document Feeder\""; + m_updProgressTmr.start(); + m_scanThread->start(); + return; + } + } + + // Check if we have a "wait for button" batch scanning + if (m_optWaitForBtn) { + kDebug() << m_optWaitForBtn->name(); + QString wait; + m_optWaitForBtn->getValue(wait); + + kDebug() << "wait ==" << wait; + if (wait == "true") { + // in batch mode only one area can be scanned per page + //kDebug() << "source == \"Automatic Document Feeder\""; + m_updProgressTmr.start(); + m_scanThread->start(); + return; + } + } + + // not batch scan, call sane_cancel to be able to change parameters. + sane_cancel(m_saneHandle); + + //kDebug() << "index=" << m_selIndex << "size=" << m_previewViewer->selListSize(); + // check if we have multiple selections. + if (m_previewViewer->selListSize() > m_selIndex) + { + if ((m_optTlX != 0) && (m_optTlY != 0) && (m_optBrX != 0) && (m_optBrY != 0)) { + float x1=0,y1=0, x2=0,y2=0, max_x, max_y; + + // get maximums + m_optBrX->getMaxValue(max_x); + m_optBrY->getMaxValue(max_y); + + // read the selection from the viewer + m_previewViewer->selectionAt(m_selIndex, x1,y1,x2,y2); + + // set the highlight + m_previewViewer->setHighlightArea(x1,y1,x2,y2); + + // calculate the option values + x1 *= max_x; y1 *= max_y; + x2 *= max_x; y2 *= max_y; + + // now set the selection + m_optTlX->setValue(x1); + m_optTlY->setValue(y1); + m_optBrX->setValue(x2); + m_optBrY->setValue(y2); + m_selIndex++; + + // execute a pending value reload + while (m_readValsTmr.isActive()) { + m_readValsTmr.stop(); + valReload(); + } + m_updProgressTmr.start(); + m_scanThread->start(); + return; + } + } + emit (q->scanDone(KSaneWidget::NoError, "")); + } + else { + switch(m_scanThread->saneStatus()) + { + case SANE_STATUS_GOOD: + case SANE_STATUS_CANCELLED: + case SANE_STATUS_EOF: + break; + case SANE_STATUS_NO_DOCS: + emit (q->scanDone(KSaneWidget::Information, i18n(sane_strstatus(m_scanThread->saneStatus())))); + alertUser(KSaneWidget::Information, i18n(sane_strstatus(m_scanThread->saneStatus()))); + break; + case SANE_STATUS_UNSUPPORTED: + case SANE_STATUS_IO_ERROR: + case SANE_STATUS_NO_MEM: + case SANE_STATUS_INVAL: + case SANE_STATUS_JAMMED: + case SANE_STATUS_COVER_OPEN: + case SANE_STATUS_DEVICE_BUSY: + case SANE_STATUS_ACCESS_DENIED: + emit (q->scanDone(KSaneWidget::ErrorGeneral, i18n(sane_strstatus(m_scanThread->saneStatus())))); + alertUser(KSaneWidget::ErrorGeneral, i18n(sane_strstatus(m_scanThread->saneStatus()))); + break; + } + } + + sane_cancel(m_saneHandle); + + // clear the highlight + m_previewViewer->setHighlightArea(0,0,1,1); + setBusy(false); + m_scanOngoing = false; +} + +void KSaneWidgetPrivate::setBusy(bool busy) +{ + if (busy) { + m_warmingUp->show(); + m_activityFrame->hide(); + m_btnFrame->hide(); + m_optionPollTmr.stop(); + } + else { + m_warmingUp->hide(); + m_activityFrame->hide(); + m_btnFrame->show(); + if (m_pollList.size() > 0) { + m_optionPollTmr.start(); + } + } + + m_optsTabWidget->setDisabled(busy); + m_previewViewer->setDisabled(busy); + + m_scanBtn->setFocus(Qt::OtherFocusReason); +} + +void KSaneWidgetPrivate::checkInvert() +{ + if (!m_optSource) return; + if (!m_optFilmType) return; + if (m_scanOngoing) return; + + QString source; + QString filmtype; + m_optSource->getValue(source); + m_optFilmType->getValue(filmtype); + + if ((source.contains(i18nc("This is compared to the option string returned by sane", + "Transparency"), Qt::CaseInsensitive)) && + (filmtype.contains(i18nc("This is compared to the option string returned by sane", + "Negative"), Qt::CaseInsensitive))) + { + m_invertColors->setChecked(true); + } + else { + m_invertColors->setChecked(false); + } +} + +void KSaneWidgetPrivate::invertPreview() +{ + m_previewImg.invertPixels(); + m_previewViewer->updateImage(); +} + +void KSaneWidgetPrivate::updateProgress() +{ + int progress; + if (m_isPreview) { + progress = m_previewThread->scanProgress(); + if (m_previewThread->saneStartDone()) { + if (!m_progressBar->isVisible() || m_previewThread->imageResized()) { + m_warmingUp->hide(); + m_activityFrame->show(); + // the image size might have changed + m_previewThread->imgMutex.lock(); + m_previewViewer->setQImage(&m_previewImg); + m_previewViewer->zoom2Fit(); + m_previewThread->imgMutex.unlock(); + } + else { + m_previewThread->imgMutex.lock(); + m_previewViewer->updateImage(); + m_previewThread->imgMutex.unlock(); + } + } + } + else { + if (!m_progressBar->isVisible() && (m_scanThread->saneStartDone())) { + m_warmingUp->hide(); + m_activityFrame->show(); + } + progress = m_scanThread->scanProgress(); + m_previewViewer->setHighlightShown(progress); + } + + m_progressBar->setValue(progress); + emit (q->scanProgress(progress)); +} + +void KSaneWidgetPrivate::alertUser(int type, const QString &strStatus) +{ + if (q->receivers(SIGNAL(userMessage(int,QString))) == 0) { + switch (type) { + case KSaneWidget::ErrorGeneral: + KMessageBox::sorry(0, strStatus); + break; + default: + KMessageBox::information(0, strStatus); + break; + } + } + else { + emit (q->userMessage(type, strStatus)); + } +} + +void KSaneWidgetPrivate::pollPollOptions() +{ + for (int i=1; ireadValue(); + } +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/ksane_widget_private.h b/libksane/libksane/ksane_widget_private.h new file mode 100644 index 00000000..8adf06f2 --- /dev/null +++ b/libksane/libksane/ksane_widget_private.h @@ -0,0 +1,204 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_WIDGET_PRIVATE_H +#define KSANE_WIDGET_PRIVATE_H + +// Sane includes +extern "C" +{ + #include + #include +} + +// Qt includes +#include +#include +#include +#include +#include + +// KDE includes +#include +#include +#include +#include +#include +#include + +// Local includes +#include "ksane.h" +#include "ksane_option.h" +#include "ksane_viewer.h" +#include "labeled_gamma.h" +#include "labeled_checkbox.h" +#include "splittercollapser.h" +#include "ksane_scan_thread.h" +#include "ksane_preview_thread.h" +#include "ksane_find_devices_thread.h" +#include "ksane_auth.h" + +#define IMG_DATA_R_SIZE 100000 + +/** This namespace collects all methods and classes in LibKSane. */ +namespace KSaneIface +{ + class KSaneWidgetPrivate: public QObject + { + Q_OBJECT + + public: + KSaneWidgetPrivate(KSaneWidget *); + void clearDeviceOptions(); + void createOptInterface(); + void updatePreviewSize(); + void setDefaultValues(); + void setBusy(bool busy); + KSaneOption *getOption(const QString &name); + KSaneWidget::ImageFormat getImgFormat(SANE_Parameters ¶ms); + int getBytesPerLines(SANE_Parameters ¶ms); + + public Q_SLOTS: + void devListUpdated(); + void signalDevListUpdate(); + void startFinalScan(); + void previewScanDone(); + void oneFinalScanDone(); + void updateProgress(); + + private Q_SLOTS: + void scheduleValReload(); + void optReload(); + void valReload(); + void handleSelection(float tl_x, float tl_y, float br_x, float br_y); + void setTLX(float x); + void setTLY(float y); + void setBRX(float x); + void setBRY(float y); + + void startPreviewScan(); + + void checkInvert(); + void invertPreview(); + void pollPollOptions(); + + public: + void alertUser(int type, const QString &strStatus); + + public: + // backend independent + KTabWidget *m_optsTabWidget; + QScrollArea *m_basicScrollA; + QWidget *m_basicOptsTab; + QWidget *m_colorOpts; + QScrollArea *m_otherScrollA; + QWidget *m_otherOptsTab; + LabeledCheckbox *m_invertColors; + + QSplitter *m_splitter; + SplitterCollapser *m_optionsCollapser; + + QWidget *m_previewFrame; + KSaneViewer *m_previewViewer; + QWidget *m_btnFrame; + QToolButton *m_zInBtn; + QToolButton *m_zOutBtn; + QToolButton *m_zSelBtn; + QToolButton *m_zFitBtn; + QToolButton *m_clearSelBtn; + KPushButton *m_scanBtn; + KPushButton *m_prevBtn; + + QWidget *m_activityFrame; + QLabel *m_warmingUp; + QProgressBar *m_progressBar; + KPushButton *m_cancelBtn; + + // device info + SANE_Handle m_saneHandle; + QString m_devName; + QString m_vendor; + QString m_model; + + // Option variables + QList m_optList; + QList m_pollList; + KSaneOption *m_optSource; + KSaneOption *m_optNegative; + KSaneOption *m_optFilmType; + KSaneOption *m_optMode; + KSaneOption *m_optDepth; + KSaneOption *m_optRes; + KSaneOption *m_optResX; + KSaneOption *m_optResY; + KSaneOption *m_optTlX; + KSaneOption *m_optTlY; + KSaneOption *m_optBrX; + KSaneOption *m_optBrY; + KSaneOption *m_optPreview; + KSaneOption *m_optGamR; + KSaneOption *m_optGamG; + KSaneOption *m_optGamB; + LabeledCheckbox *m_splitGamChB; + LabeledGamma *m_commonGamma; + KSaneOption *m_optWaitForBtn; + + // preview variables + float m_previewWidth; + float m_previewHeight; + float m_previewDPI; + QImage m_previewImg; + bool m_isPreview; + bool m_autoSelect; + + int m_selIndex; + + bool m_scanOngoing; + bool m_closeDevicePending; + + // final image data + QByteArray m_scanData; + + // option handling + QTimer m_readValsTmr; + QTimer m_updProgressTmr; + QTimer m_optionPollTmr; + KSaneScanThread *m_scanThread; + KSanePreviewThread *m_previewThread; + + QString m_saneUserName; + QString m_sanePassword; + + FindSaneDevicesThread *m_findDevThread; + KSaneAuth *m_auth; + KSaneWidget *q; + }; + + +} // NameSpace KSaneIface + +#endif // SANE_WIDGET_H diff --git a/libksane/libksane/libksane_export.h b/libksane/libksane/libksane_export.h new file mode 100644 index 00000000..a7eb8180 --- /dev/null +++ b/libksane/libksane/libksane_export.h @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef LIBKSANE_EXPORT_H +#define LIBKSANE_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef LIBKSANE_EXPORT +# if defined(MAKE_KSANE_LIB) + /* We are building this library */ +# define LIBKSANE_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define LIBKSANE_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef LIBKSANE_EXPORT_DEPRECATED +# define LIBKSANE_EXPORT_DEPRECATED KDE_DEPRECATED LIBKSANE_EXPORT +# endif + +#endif diff --git a/libksane/libksane/options/ksane_opt_button.cpp b/libksane/libksane/options/ksane_opt_button.cpp new file mode 100644 index 00000000..fe8513dc --- /dev/null +++ b/libksane/libksane/options/ksane_opt_button.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_button.h" +#include "ksane_opt_button.moc" + +#include "ksane_button.h" + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +KSaneOptButton::KSaneOptButton(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_button(0) +{ +} + +void KSaneOptButton::createWidget(QWidget *parent) +{ + if (m_widget) return; + + readOption(); + + if (!m_optDesc) { + kDebug() << "This is a bug"; + m_widget = new KSaneOptionWidget(parent, ""); + return; + } + + m_widget = m_button = new KSaneButton(parent, i18n(m_optDesc->title)); + m_widget->setToolTip(i18n(m_optDesc->desc)); + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + + updateVisibility(); + readValue(); +} + +void KSaneOptButton::buttonClicked() +{ + unsigned char data[4]; + writeData(data); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_button.h b/libksane/libksane/options/ksane_opt_button.h new file mode 100644 index 00000000..51968251 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_button.h @@ -0,0 +1,58 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_BUTTON_H +#define KSANE_OPT_BUTTON_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class KSaneButton; + +class KSaneOptButton : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptButton(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + bool hasGui() {return true;} + +private Q_SLOTS: + void buttonClicked(); + +private: + KSaneButton *m_button; +}; + +} // NameSpace KSaneIface + +#endif // KSANE_BUTTON_OPT_H diff --git a/libksane/libksane/options/ksane_opt_checkbox.cpp b/libksane/libksane/options/ksane_opt_checkbox.cpp new file mode 100644 index 00000000..60451ace --- /dev/null +++ b/libksane/libksane/options/ksane_opt_checkbox.cpp @@ -0,0 +1,138 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_checkbox.h" +#include "ksane_opt_checkbox.moc" + +#include "labeled_checkbox.h" + +// Qt includes +#include + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +KSaneOptCheckBox::KSaneOptCheckBox(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_checkbox(0), m_checked(false) +{ +} + +void KSaneOptCheckBox::createWidget(QWidget *parent) +{ + if (m_widget) return; + + readOption(); + + if (!m_optDesc) { + kDebug() << "This is a bug"; + m_widget = new KSaneOptionWidget(parent, ""); + return; + } + + m_widget = m_checkbox = new LabeledCheckbox(parent, i18n(m_optDesc->title)); + m_widget->setToolTip(i18n(m_optDesc->desc)); + + connect(m_checkbox, SIGNAL(toggled(bool)), this, SLOT(checkboxChanged(bool))); + + updateVisibility(); + readValue(); +} + +void KSaneOptCheckBox::checkboxChanged(bool toggled) +{ + unsigned char data[4]; + + m_checked = toggled; + fromSANE_Word(data, (toggled) ? 1:0); + writeData(data); +} + +void KSaneOptCheckBox::readValue() +{ + if (state() == STATE_HIDDEN) return; + + // read the current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + return; + } + bool old = m_checked; + m_checked = (toSANE_Word(data.data()) != 0) ? true:false; + if (m_checkbox) { + m_checkbox->setChecked(m_checked); + } + if ((old != m_checked) && ((m_optDesc->cap & SANE_CAP_SOFT_SELECT) == 0)) { + emit buttonPressed(name(), i18n(m_optDesc->title), m_checked); + } +} + +bool KSaneOptCheckBox::getValue(float &val) +{ + if (state() == STATE_HIDDEN) return false; + val = m_checked ? 1.0 : 0.0; + return true; +} + +bool KSaneOptCheckBox::setValue(float val) +{ + if (state() == STATE_HIDDEN) return false; + checkboxChanged(val == 0); + readValue(); + return true; +} + +bool KSaneOptCheckBox::getValue(QString &val) +{ + if (state() == STATE_HIDDEN) return false; + val = m_checked ? "true" : "false"; + return true; +} + +bool KSaneOptCheckBox::setValue(const QString &val) +{ + if (state() == STATE_HIDDEN) return false; + if ((val.compare("true", Qt::CaseInsensitive) == 0) || + (val.compare("1") == 0)) + { + checkboxChanged(true); + } + else { + checkboxChanged(false); + } + readValue(); + return true; +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_checkbox.h b/libksane/libksane/options/ksane_opt_checkbox.h new file mode 100644 index 00000000..0a6fba26 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_checkbox.h @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_CHECKBOX_H +#define KSANE_OPT_CHECKBOX_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledCheckbox; + +class KSaneOptCheckBox : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptCheckBox(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + +private Q_SLOTS: + void checkboxChanged(bool toggled); + +Q_SIGNALS: + void buttonPressed(const QString &optionName, const QString &optionLabel, bool pressed); + +private: + LabeledCheckbox *m_checkbox; + bool m_checked; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_opt_combo.cpp b/libksane/libksane/options/ksane_opt_combo.cpp new file mode 100644 index 00000000..e48e2d10 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_combo.cpp @@ -0,0 +1,380 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_combo.h" +#include "ksane_opt_combo.moc" + +#include "labeled_combo.h" + +// Qt includes +#include + +// KDE includes +#include +#include +#include + +namespace KSaneIface +{ +static const char tmp_binary[] = "Binary"; + +KSaneOptCombo::KSaneOptCombo(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_combo(0) +{ +} + +void KSaneOptCombo::createWidget(QWidget *parent) +{ + if (m_widget) return; + + m_widget = m_combo = new LabeledCombo(parent, "", QStringList()); + readOption(); + m_widget->setToolTip(i18n(m_optDesc->desc)); + connect(m_combo, SIGNAL(activated(int)), this, SLOT(comboboxChangedIndex(int))); + readValue(); +} + +void KSaneOptCombo::readValue() +{ + if (state() == STATE_HIDDEN) return; + + // read that current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + return; + } + + + m_currentText = getSaneComboString(data.data()); + if (m_combo != 0) { + if (m_combo->currentText() != m_currentText) { + m_combo->setCurrentText(m_currentText); + emit valueChanged(); + } + } +} + +void KSaneOptCombo::readOption() +{ + KSaneOption::readOption(); + + if (!m_combo) return; + + QString saved = m_combo->currentText(); + + m_strList = genComboStringList(); + m_combo->clear(); + m_combo->setLabelText(i18n(m_optDesc->title)); + m_combo->addItems(m_strList); + m_combo->setIcon(KIcon("color"), getSaneComboString((unsigned char*)SANE_VALUE_SCAN_MODE_COLOR)); + m_combo->setIcon(KIcon("gray-scale"), + getSaneComboString((unsigned char*)SANE_VALUE_SCAN_MODE_GRAY)); + m_combo->setIcon(KIcon("black-white"), + getSaneComboString((unsigned char*)SANE_VALUE_SCAN_MODE_LINEART)); + // The epkowa/epson backend uses "Binary" which is the same as "Lineart" + m_combo->setIcon(KIcon("black-white"), i18n(tmp_binary)); + + // set the previous value + m_combo->setCurrentText(saved); +} + + +QStringList &KSaneOptCombo::genComboStringList() +{ + int i; + m_strList.clear(); + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + for (i=1; i<=m_optDesc->constraint.word_list[0]; ++i) { + m_strList += getSaneComboString((int)m_optDesc->constraint.word_list[i]); + } + break; + case SANE_TYPE_FIXED: + for (i=1; i<=m_optDesc->constraint.word_list[0]; ++i) { + m_strList += getSaneComboString((float)SANE_UNFIX(m_optDesc->constraint.word_list[i])); + } + break; + case SANE_TYPE_STRING: + i=0; + while (m_optDesc->constraint.string_list[i] != 0) { + m_strList += getSaneComboString((unsigned char *)m_optDesc->constraint.string_list[i]); + i++; + } + break; + default : + m_strList += "NOT HANDELED"; + break; + } + return m_strList; +} + +QString KSaneOptCombo::getSaneComboString(int ival) +{ + switch(m_optDesc->unit) + { + case SANE_UNIT_NONE: break; + case SANE_UNIT_PIXEL: return i18np("%1 Pixel","%1 Pixels", ival); + case SANE_UNIT_BIT: return i18np("%1 Bit","%1 Bits", ival); + case SANE_UNIT_MM: return i18np("%1 mm","%1 mm", ival); + case SANE_UNIT_DPI: return i18np("%1 DPI","%1 DPI", ival); + case SANE_UNIT_PERCENT: return i18np("%1 %","%1 %", ival); + case SANE_UNIT_MICROSECOND: return i18np("%1 µs","%1 µs", ival); + } + return QString::number(ival); +} + +QString KSaneOptCombo::getSaneComboString(float fval) +{ + switch(m_optDesc->unit) + { + case SANE_UNIT_NONE: break; + case SANE_UNIT_PIXEL: return i18ncp("Parameter and Unit","%1 Pixel", "%1 Pixels", fval); + case SANE_UNIT_BIT: return i18ncp("Parameter and Unit","%1 Bit","%1 Bits", fval); + case SANE_UNIT_MM: return i18nc("Parameter and Unit (Millimeter)","%1 mm", fval); + case SANE_UNIT_DPI: return i18nc("Parameter and Unit (Dots Per Inch)","%1 DPI", fval); + case SANE_UNIT_PERCENT: return i18nc("Parameter and Unit (Percentage)","%1 %", fval); + case SANE_UNIT_MICROSECOND: return i18nc("Parameter and Unit (Microseconds)","%1 µs", fval); + } + return QString::number(fval, 'F', 4); +} + +QString KSaneOptCombo::getSaneComboString(unsigned char *data) +{ + QString tmp; + if (data == 0) return QString(); + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + return getSaneComboString((int)toSANE_Word(data)); + case SANE_TYPE_FIXED: + return getSaneComboString((float)SANE_UNFIX(toSANE_Word(data))); + case SANE_TYPE_STRING: + tmp = i18n(reinterpret_cast(data)); + tmp = tmp.simplified(); + return tmp; + default : + break; + } + return QString(); +} + + + +void KSaneOptCombo::comboboxChangedIndex(int i) +{ + if (m_combo && (m_combo->currentText() == m_currentText)) { + return; + } + + unsigned char data[4]; + void *dataPtr; + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + fromSANE_Word(data, m_optDesc->constraint.word_list[i+1]); + dataPtr = data; + break; + case SANE_TYPE_STRING: + dataPtr = (void *)m_optDesc->constraint.string_list[i]; + break; + default: + kDebug() << "can not handle type:" << m_optDesc->type; + return; + } + writeData(dataPtr); + readValue(); + emit valueChanged(); +} + +bool KSaneOptCombo::getMinValue(float &val) +{ + if (state() == STATE_HIDDEN) return false; + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + val = (float)m_optDesc->constraint.word_list[1]; + for (int i=2; i<=m_optDesc->constraint.word_list[0]; i++) { + val = qMin((float)m_optDesc->constraint.word_list[i], val); + } + break; + case SANE_TYPE_FIXED: + val = (float)SANE_UNFIX(m_optDesc->constraint.word_list[1]); + for (int i=2; i<=m_optDesc->constraint.word_list[0]; i++) { + val = qMin((float)SANE_UNFIX(m_optDesc->constraint.word_list[i]), val); + } + break; + default: + kDebug() << "can not handle type:" << m_optDesc->type; + return false; + } + return true; +} + +bool KSaneOptCombo::getValue(float &val) +{ + if (state() == STATE_HIDDEN) return false; + + // read that current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + kDebug() << m_optDesc->name << "sane_control_option returned" << status; + return false; + } + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + val = (float)toSANE_Word(data.data()); + return true; + case SANE_TYPE_FIXED: + val = SANE_UNFIX(toSANE_Word(data.data())); + return true; + default: + kDebug() << "Type" << m_optDesc->type << "not supported!"; + break; + } + return false; +} + +bool KSaneOptCombo::setValue(float value) +{ + unsigned char data[4]; + float tmp; + float minDiff; + int i; + int minIndex = 1; + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + tmp = (float)m_optDesc->constraint.word_list[minIndex]; + minDiff = qAbs(value - tmp); + for (i=2; i<=m_optDesc->constraint.word_list[0]; ++i) { + tmp = (float)m_optDesc->constraint.word_list[i]; + if (qAbs(value - tmp) < minDiff) { + minDiff = qAbs(value - tmp); + minIndex = i; + } + } + fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]); + writeData(data); + readValue(); + return (minDiff < 1.0); + case SANE_TYPE_FIXED: + tmp = (float)SANE_UNFIX(m_optDesc->constraint.word_list[minIndex]); + minDiff = qAbs(value - tmp); + for (i=2; i<=m_optDesc->constraint.word_list[0]; ++i) { + tmp = (float)SANE_UNFIX(m_optDesc->constraint.word_list[i]); + if (qAbs(value - tmp) < minDiff) { + minDiff = qAbs(value - tmp); + minIndex = i; + } + } + fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]); + writeData(data); + readValue(); + return (minDiff < 1.0); + default: + kDebug() << "can not handle type:" << m_optDesc->type; + break; + } + return false; +} + +bool KSaneOptCombo::getValue(QString &val) +{ + if (state() == STATE_HIDDEN) return false; + val = m_currentText; + return true; +} + +bool KSaneOptCombo::setValue(const QString &val) +{ + if (state() == STATE_HIDDEN) return false; + if (val == m_currentText) return true; + + unsigned char data[4]; + void *data_ptr; + SANE_Word fixed; + int i; + float f; + bool ok; + QString tmp; + + switch (m_optDesc->type) + { + case SANE_TYPE_INT: + tmp = val.left(val.indexOf(' ')); // strip the unit + // accept float formating of the string + i = (int)(tmp.toFloat(&ok)); + if (ok == false) return false; + fromSANE_Word(data, i); + data_ptr = data; + break; + case SANE_TYPE_FIXED: + tmp = val.left(val.indexOf(' ')); // strip the unit + f = tmp.toFloat(&ok); + if (ok == false) return false; + fixed = SANE_FIX(f); + fromSANE_Word(data, fixed); + data_ptr = data; + break; + case SANE_TYPE_STRING: + i = 0; + while (m_optDesc->constraint.string_list[i] != 0) { + tmp = getSaneComboString((unsigned char *)m_optDesc->constraint.string_list[i]); + if (val == tmp) { + data_ptr = (void *)m_optDesc->constraint.string_list[i]; + break; + } + i++; + } + if (m_optDesc->constraint.string_list[i] == 0) return false; + break; + default: + kDebug() << "can only handle SANE_TYPE: INT, FIXED and STRING"; + return false; + } + writeData(data_ptr); + + readValue(); + return true; +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_combo.h b/libksane/libksane/options/ksane_opt_combo.h new file mode 100644 index 00000000..2fb1844e --- /dev/null +++ b/libksane/libksane/options/ksane_opt_combo.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_COMBO_H +#define KSANE_OPT_COMBO_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledCombo; + +class KSaneOptCombo : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptCombo(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + void readOption(); + + bool getMinValue(float &max); + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + +private Q_SLOTS: + void comboboxChangedIndex(int val); + +Q_SIGNALS: + void valueChanged(); + +private: + QStringList &genComboStringList(); + QString getSaneComboString(int ival); + QString getSaneComboString(float fval); + QString getSaneComboString(unsigned char *data); + + LabeledCombo *m_combo; + QString m_currentText; + QStringList m_strList; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_opt_entry.cpp b/libksane/libksane/options/ksane_opt_entry.cpp new file mode 100644 index 00000000..cdc1b104 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_entry.cpp @@ -0,0 +1,114 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_entry.h" +#include "ksane_opt_entry.moc" + +#include "labeled_entry.h" + +// Qt includes +#include + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +KSaneOptEntry::KSaneOptEntry(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_entry(0) +{ +} + +void KSaneOptEntry::createWidget(QWidget *parent) +{ + if (m_widget) return; + + readOption(); + + if (!m_optDesc) { + kDebug() << "This is a bug"; + m_widget = new KSaneOptionWidget(parent, ""); + return; + } + + m_widget = m_entry = new LabeledEntry(parent, i18n(m_optDesc->title)); + m_widget->setToolTip(i18n(m_optDesc->desc)); + connect(m_entry, SIGNAL(entryEdited(QString)), this, SLOT(entryChanged(QString))); + updateVisibility(); + readValue(); +} + +void KSaneOptEntry::entryChanged(const QString& text) +{ + QString tmp; + tmp += text.left(m_optDesc->size); + if (tmp != text) { + m_entry->setText(tmp); + writeData(tmp.toLatin1().data()); + } +} + +void KSaneOptEntry::readValue() +{ + if (state() == STATE_HIDDEN) return; + + // read that current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + return; + } + + m_string = QString(reinterpret_cast(data.data())); + if (m_entry != 0) { + m_entry->setText(m_string); + } +} + +bool KSaneOptEntry::getValue(float &) {return false;} +bool KSaneOptEntry::setValue(float) {return false;} + +bool KSaneOptEntry::getValue(QString &val) +{ + if (state() == STATE_HIDDEN) return false; + val = m_string; + return true; +} + +bool KSaneOptEntry::setValue(const QString &val) +{ + if (state() == STATE_HIDDEN) return false; + entryChanged(val); + readValue(); + return true; +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_entry.h b/libksane/libksane/options/ksane_opt_entry.h new file mode 100644 index 00000000..9dc68d3e --- /dev/null +++ b/libksane/libksane/options/ksane_opt_entry.h @@ -0,0 +1,65 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_ENTRY_H +#define KSANE_OPT_ENTRY_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledEntry; + +class KSaneOptEntry : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptEntry(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + +private Q_SLOTS: + void entryChanged(const QString &text); + +private: + LabeledEntry *m_entry; + QString m_string; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_opt_fslider.cpp b/libksane/libksane/options/ksane_opt_fslider.cpp new file mode 100644 index 00000000..460cbe34 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_fslider.cpp @@ -0,0 +1,176 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_fslider.h" +#include "ksane_opt_fslider.moc" + +#include "labeled_fslider.h" + +// Qt includes +#include + +// KDE includes +#include +#include + +static const float FIXED_MAX = 32767.0; +static const float FIXED_MIN =-32768.0; +static const float MIN_FIXED_STEP = 0.0001; +namespace KSaneIface +{ + +KSaneOptFSlider::KSaneOptFSlider(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_slider(0), m_fVal(0), m_minChange(MIN_FIXED_STEP) +{ +} + +void KSaneOptFSlider::createWidget(QWidget *parent) +{ + if (m_widget) return; + + m_widget = m_slider = new LabeledFSlider(parent, "", FIXED_MIN, FIXED_MAX, MIN_FIXED_STEP); + readOption(); + m_widget->setToolTip(i18n(m_optDesc->desc)); + connect(m_slider, SIGNAL(valueChanged(float)), this, SLOT(sliderChanged(float))); + readValue(); +} + +void KSaneOptFSlider::readOption() +{ + KSaneOption::readOption(); + + if (!m_slider) return; + + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + m_slider->setRange(SANE_UNFIX(m_optDesc->constraint.range->min), + SANE_UNFIX(m_optDesc->constraint.range->max)); + + float tmpStep = SANE_UNFIX(m_optDesc->constraint.range->quant); + if (tmpStep < MIN_FIXED_STEP) tmpStep = MIN_FIXED_STEP; + m_slider->setStep(tmpStep); + } + else { + m_slider->setRange(FIXED_MIN, FIXED_MAX); + m_slider->setStep(MIN_FIXED_STEP); + } + m_minChange = m_slider->step()/2; + m_slider->setSuffix(unitDoubleString()); + m_slider->setLabelText(i18n(m_optDesc->title)); +} + +void KSaneOptFSlider::readValue() +{ + if (state() == STATE_HIDDEN) return; + + // read that current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + return; + } + + m_fVal = SANE_UNFIX(toSANE_Word(data.data())); + if (m_slider != 0) { + if (((m_slider->value() - m_fVal) >= m_minChange) || + ((m_fVal- m_slider->value()) >= m_minChange)) + { + m_slider->setValue(m_fVal); + } + } + emit fValueRead(m_fVal); +} + + +void KSaneOptFSlider::sliderChanged(float val) +{ + if (((val-m_fVal) >= m_minChange) || ((m_fVal-val) >= m_minChange)) { + unsigned char data[4]; + SANE_Word fixed; + //kDebug() <name << fVal << "!=" << val; + m_fVal = val; + fixed = SANE_FIX(val); + fromSANE_Word(data, fixed); + writeData(data); + } +} + +bool KSaneOptFSlider::getMinValue(float &val) +{ + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + val = SANE_UNFIX(m_optDesc->constraint.range->min); + } + else { + val = FIXED_MIN; + } + return true; +} + +bool KSaneOptFSlider::getMaxValue(float &max) +{ + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + max = SANE_UNFIX(m_optDesc->constraint.range->max); + } + else { + max = FIXED_MAX; + } + return true; +} + +bool KSaneOptFSlider::getValue(float &val) +{ + if (state() == STATE_HIDDEN) return false; + val = m_fVal; + return true; +} + +bool KSaneOptFSlider::setValue(float val) +{ + if (state() == STATE_HIDDEN) return false; + sliderChanged(val); + readValue(); + return true; +} + +bool KSaneOptFSlider::getValue(QString &val) +{ + if (state() == STATE_HIDDEN) return false; + val = QString::number(m_fVal, 'F', 6); + return true; +} + +bool KSaneOptFSlider::setValue(const QString &val) +{ + if (state() == STATE_HIDDEN) return false; + sliderChanged(val.toFloat()); + readValue(); + return true; +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_fslider.h b/libksane/libksane/options/ksane_opt_fslider.h new file mode 100644 index 00000000..793b80ed --- /dev/null +++ b/libksane/libksane/options/ksane_opt_fslider.h @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_FSLIDER_H +#define KSANE_OPT_FSLIDER_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledFSlider; + +class KSaneOptFSlider : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptFSlider(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + void readOption(); + + bool getMinValue(float &max); + bool getMaxValue(float &max); + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + + Q_SIGNALS: + void fValueRead(float); + +private Q_SLOTS: + void sliderChanged(float val); + +private: + LabeledFSlider *m_slider; + float m_fVal; + float m_minChange; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_opt_gamma.cpp b/libksane/libksane/options/ksane_opt_gamma.cpp new file mode 100644 index 00000000..be39f381 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_gamma.cpp @@ -0,0 +1,109 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-31 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_gamma.h" +#include "ksane_opt_gamma.moc" + +#include "labeled_gamma.h" + +// Qt includes +#include + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +KSaneOptGamma::KSaneOptGamma(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_gamma(0) +{ +} + +void KSaneOptGamma::createWidget(QWidget *parent) +{ + if (m_widget) return; + + readOption(); + + if (!m_optDesc) { + kDebug() << "This is a bug"; + m_widget = new KSaneOptionWidget(parent, ""); + return; + } + + m_widget = m_gamma = new LabeledGamma(parent, i18n(m_optDesc->title), + m_optDesc->size/sizeof(SANE_Word)); + connect(m_gamma, SIGNAL(gammaTableChanged(QVector)), + this, SLOT(gammaTableChanged(QVector))); + if (strcmp(m_optDesc->name, SANE_NAME_GAMMA_VECTOR_R) == 0) m_gamma->setColor(Qt::red); + if (strcmp(m_optDesc->name, SANE_NAME_GAMMA_VECTOR_G) == 0) m_gamma->setColor(Qt::green); + if (strcmp(m_optDesc->name, SANE_NAME_GAMMA_VECTOR_B) == 0) m_gamma->setColor(Qt::blue); + + m_widget->setToolTip(i18n(m_optDesc->desc)); + updateVisibility(); + readValue(); +} + +void KSaneOptGamma::gammaTableChanged(const QVector &gam_tbl) +{ + QVector copy = gam_tbl; + writeData(copy.data()); +} + +void KSaneOptGamma::readValue() +{ + // Unfortunately gamma table to brigthness, contrast and gamma is + // not easy nor fast.. ergo not done +} + +bool KSaneOptGamma::getValue(float &) {return false;} +bool KSaneOptGamma::setValue(float) {return false;} + +bool KSaneOptGamma::getValue(QString &val) +{ + if (!m_gamma) return false; + if (state() == STATE_HIDDEN) return false; + int bri; + int con; + int gam; + m_gamma->getValues(bri, con, gam); + val = QString().sprintf("%d:%d:%d", bri, con, gam); + return true; +} + +bool KSaneOptGamma::setValue(const QString &val) +{ + if (!m_gamma) return false; + if (state() == STATE_HIDDEN) return false; + + m_gamma->setValues(val); + return true; +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_gamma.h b/libksane/libksane/options/ksane_opt_gamma.h new file mode 100644 index 00000000..a0b48c1e --- /dev/null +++ b/libksane/libksane/options/ksane_opt_gamma.h @@ -0,0 +1,64 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-31 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_GAMMA_H +#define KSANE_OPT_GAMMA_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledGamma; + +class KSaneOptGamma : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptGamma(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + +private Q_SLOTS: + void gammaTableChanged(const QVector &gam_tbl); + +private: + LabeledGamma *m_gamma; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_opt_slider.cpp b/libksane/libksane/options/ksane_opt_slider.cpp new file mode 100644 index 00000000..5b21570f --- /dev/null +++ b/libksane/libksane/options/ksane_opt_slider.cpp @@ -0,0 +1,164 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_opt_slider.h" +#include "ksane_opt_slider.moc" + +#include "labeled_slider.h" + +// Qt includes +#include + +// KDE includes +#include +#include + +static const int KSW_INT_MAX = 2147483647; +static const int KSW_INT_MIN = -2147483647-1; // prevent warning + + +namespace KSaneIface +{ + +KSaneOptSlider::KSaneOptSlider(const SANE_Handle handle, const int index) +: KSaneOption(handle, index), m_slider(0), m_iVal(0) +{ +} + +void KSaneOptSlider::createWidget(QWidget *parent) +{ + if (m_widget) return; + + m_widget = m_slider = new LabeledSlider(parent, "", KSW_INT_MIN, KSW_INT_MAX, 1); + readOption(); + m_widget->setToolTip(i18n(m_optDesc->desc)); + connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int))); + readValue(); +} + + +void KSaneOptSlider::readValue() +{ + if (state() == STATE_HIDDEN) return; + + // read that current value + QVarLengthArray data(m_optDesc->size); + SANE_Status status; + SANE_Int res; + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res); + if (status != SANE_STATUS_GOOD) { + return; + } + + m_iVal = toSANE_Word(data.data()); + if ((m_slider != 0) && (m_slider->value() != m_iVal)) { + m_slider->setValue(m_iVal); + } + emit fValueRead((float)m_iVal); +} + +void KSaneOptSlider::readOption() +{ + KSaneOption::readOption(); + + if (!m_slider) return; + + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + m_slider->setRange(m_optDesc->constraint.range->min, m_optDesc->constraint.range->max); + m_slider->setStep(m_optDesc->constraint.range->quant); + } + else { + m_slider->setRange(KSW_INT_MIN, KSW_INT_MAX); + m_slider->setStep(1); + } + m_slider->setSuffix(unitString()); + m_slider->setLabelText(i18n(m_optDesc->title)); +} + +void KSaneOptSlider::sliderChanged(int val) +{ + if (val == m_iVal) return; + unsigned char data[4]; + m_iVal = val; + fromSANE_Word(data, val); + writeData(data); +} + +bool KSaneOptSlider::getMinValue(float &val) +{ + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + val = (float)m_optDesc->constraint.range->min; + } + else { + val = (float)KSW_INT_MIN; + } + return true; +} + +bool KSaneOptSlider::getMaxValue(float &val) +{ + if (m_optDesc->constraint_type == SANE_CONSTRAINT_RANGE) { + val = (float)m_optDesc->constraint.range->max; + } + else { + val = (float)KSW_INT_MAX; + } + return true; +} + +bool KSaneOptSlider::getValue(float &val) +{ + if (state() == STATE_HIDDEN) return false; + val = (float)m_iVal; + return true; +} + +bool KSaneOptSlider::setValue(float val) +{ + if (state() == STATE_HIDDEN) return false; + sliderChanged((int)val); + readValue(); + return true; +} + +bool KSaneOptSlider::getValue(QString &val) +{ + if (state() == STATE_HIDDEN) return false; + val = QString::number(m_iVal); + return true; +} + +bool KSaneOptSlider::setValue(const QString &val) +{ + if (state() == STATE_HIDDEN) return false; + sliderChanged(val.toInt()); + readValue(); + return true; +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_opt_slider.h b/libksane/libksane/options/ksane_opt_slider.h new file mode 100644 index 00000000..8e73e0c3 --- /dev/null +++ b/libksane/libksane/options/ksane_opt_slider.h @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPT_SLIDER_H +#define KSANE_OPT_SLIDER_H + +#include "ksane_option.h" + +namespace KSaneIface +{ + +class LabeledSlider; + +class KSaneOptSlider : public KSaneOption +{ + Q_OBJECT + +public: + KSaneOptSlider(const SANE_Handle handle, const int index); + + void createWidget(QWidget *parent); + + void readValue(); + void readOption(); + + bool getMinValue(float &max); + bool getMaxValue(float &max); + bool getValue(float &val); + bool setValue(float val); + bool getValue(QString &val); + bool setValue(const QString &val); + bool hasGui() {return true;} + + Q_SIGNALS: + void fValueRead(float); + +private Q_SLOTS: + void sliderChanged(int val); + +private: + LabeledSlider *m_slider; + int m_iVal; +}; + +} // NameSpace KSaneIface + +#endif diff --git a/libksane/libksane/options/ksane_option.cpp b/libksane/libksane/options/ksane_option.cpp new file mode 100644 index 00000000..68eb3262 --- /dev/null +++ b/libksane/libksane/options/ksane_option.cpp @@ -0,0 +1,343 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +// Local includes +#include "ksane_option.h" +#include "ksane_option.moc" + +// KDE includes +#include +#include + +#include "ksane_option_widget.h" + +namespace KSaneIface +{ + +KSaneOption::KSaneOption(const SANE_Handle handle, const int index) + : QObject(), m_handle(handle), m_index(index) +{ + m_widget = 0; + m_data = 0; + readOption(); +} + +KSaneOption::~KSaneOption() +{ + if (m_data) { + free(m_data); + m_data = 0; + } + // delete the frame, just in case if no parent is set + delete m_widget; + m_widget = 0; +} + +void KSaneOption::createWidget(QWidget *parent) +{ + if (!m_widget) { + m_widget = new KSaneOptionWidget(parent, ""); + } + + if (m_optDesc) { + m_widget->setToolTip(i18n(m_optDesc->desc)); + } + + readOption(); + readValue(); +} + +void KSaneOption::readOption() +{ + m_optDesc = sane_get_option_descriptor(m_handle, m_index); + updateVisibility(); +} + +void KSaneOption::updateVisibility() +{ + if (!m_widget) return; + + if (state() == STATE_HIDDEN) { + m_widget->hide(); + } + else { + m_widget->show(); + m_widget->setEnabled(state() == STATE_SHOWN); + } +} + +KSaneOption::KSaneOptWState KSaneOption::state() +{ + if (!m_optDesc) return STATE_HIDDEN; + + if (((m_optDesc->cap & SANE_CAP_SOFT_DETECT) == 0) || + (m_optDesc->cap & SANE_CAP_INACTIVE) || + ((m_optDesc->size == 0) && (optionType(m_optDesc) != TYPE_BUTTON))) + { + return STATE_HIDDEN; + } + else if ((m_optDesc->cap & SANE_CAP_SOFT_SELECT) == 0) { + return STATE_DISABLED; + } + return STATE_SHOWN; +} + +bool KSaneOption::needsPolling() +{ + if (!m_optDesc) return false; + + if ((m_optDesc->cap & SANE_CAP_SOFT_DETECT) && !(m_optDesc->cap & SANE_CAP_SOFT_SELECT)) { + kDebug() << name() << "optDesc->cap =" << m_optDesc->cap; + return true; + } + + return false; +} + +QString KSaneOption::name() +{ + if (m_optDesc == 0) return QString(""); + return QString(m_optDesc->name); +} + +bool KSaneOption::writeData(void *data) +{ + SANE_Status status; + SANE_Int res; + + if (state() == STATE_DISABLED) { + return false; + } + + status = sane_control_option (m_handle, m_index, SANE_ACTION_SET_VALUE, data, &res); + if (status != SANE_STATUS_GOOD) { + kDebug() << m_optDesc->name << "sane_control_option returned:" << sane_strstatus(status); + // write failed. re read the current setting + readValue(); + return false; + } + if ((res & SANE_INFO_INEXACT) && (m_widget != 0)) { + //kDebug() << "write was inexact. Reload value just in case..."; + readValue(); + } + + if (res & SANE_INFO_RELOAD_OPTIONS) { + emit optsNeedReload(); + // optReload reloads also the values + } + else if (res & SANE_INFO_RELOAD_PARAMS) { + // 'else if' because with optReload we force also valReload :) + emit valsNeedReload(); + } + + return true; +} + + +void KSaneOption::readValue() {} + +SANE_Word KSaneOption::toSANE_Word(unsigned char *data) +{ + SANE_Word tmp; + // if __BYTE_ORDER is not defined we get #if 0 == 0 + #if __BYTE_ORDER == __LITTLE_ENDIAN + tmp = (data[0]&0xff); + tmp += ((SANE_Word)(data[1]&0xff))<<8; + tmp += ((SANE_Word)(data[2]&0xff))<<16; + tmp += ((SANE_Word)(data[3]&0xff))<<24; + #else + tmp = (data[3]&0xff); + tmp += ((SANE_Word)(data[2]&0xff))<<8; + tmp += ((SANE_Word)(data[1]&0xff))<<16; + tmp += ((SANE_Word)(data[0]&0xff))<<24; + #endif + return tmp; +} + +void KSaneOption::fromSANE_Word(unsigned char *data, SANE_Word from) +{ + // if __BYTE_ORDER is not defined we get #if 0 == 0 + #if __BYTE_ORDER == __LITTLE_ENDIAN + data[0] = (from & 0x000000FF); + data[1] = (from & 0x0000FF00)>>8; + data[2] = (from & 0x00FF0000)>>16; + data[3] = (from & 0xFF000000)>>24; + #else + data[3] = (from & 0x000000FF); + data[2] = (from & 0x0000FF00)>>8; + data[1] = (from & 0x00FF0000)>>16; + data[0] = (from & 0xFF000000)>>24; + #endif +} + +bool KSaneOption::getMinValue(float &) {return false;} +bool KSaneOption::getMaxValue(float &) {return false;} +bool KSaneOption::getValue(float &) {return false;} +bool KSaneOption::setValue(float) {return false;} +bool KSaneOption::getValue(QString &) {return false;} +bool KSaneOption::setValue(const QString &) {return false;} +int KSaneOption::getUnit() {return m_optDesc->unit;} + +bool KSaneOption::storeCurrentData() +{ + SANE_Status status; + SANE_Int res; + + // check if we can read the value + if (!hasGui()) return false; + if (state() == STATE_HIDDEN) return false; + + // read that current value + if (m_data != 0) free(m_data); + m_data = (unsigned char *)malloc(m_optDesc->size); + status = sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, m_data, &res); + if (status != SANE_STATUS_GOOD) { + kDebug() << m_optDesc->name << "sane_control_option returned" << status; + return false; + } + return true; +} + +bool KSaneOption::restoreSavedData() +{ + // check if we have saved any data + if (m_data == 0) return false; + + // check if we can write the value + if (!hasGui()) return false; + if (state() == STATE_HIDDEN) return false; + if (state() == STATE_DISABLED) return false; + + writeData(m_data); + readValue(); + return true; +} + +KSaneOption::KSaneOptType KSaneOption::optionType(const SANE_Option_Descriptor *optDesc) +{ + if (!optDesc) return TYPE_DETECT_FAIL; + + switch (optDesc->constraint_type) { + case SANE_CONSTRAINT_NONE: + switch(optDesc->type) + { + case SANE_TYPE_BOOL: + return TYPE_CHECKBOX; + case SANE_TYPE_INT: + if (optDesc->size == sizeof(SANE_Word)) return TYPE_SLIDER; + kDebug() << "Can not handle:"<< optDesc->title; + kDebug() << "SANE_CONSTRAINT_NONE && SANE_TYPE_INT"; + kDebug() << "size" << optDesc->size<< "!= sizeof(SANE_Word)"; + break; + case SANE_TYPE_FIXED: + if (optDesc->size == sizeof(SANE_Word)) return TYPE_F_SLIDER; + kDebug() << "Can not handle:"<< optDesc->title; + kDebug() << "SANE_CONSTRAINT_NONE && SANE_TYPE_FIXED"; + kDebug() << "size" << optDesc->size<< "!= sizeof(SANE_Word)"; + break; + case SANE_TYPE_BUTTON: + return TYPE_BUTTON; + case SANE_TYPE_STRING: + return TYPE_ENTRY; + case SANE_TYPE_GROUP: + return TYPE_DETECT_FAIL; + } + break; + case SANE_CONSTRAINT_RANGE: + switch(optDesc->type) { + case SANE_TYPE_BOOL: + return TYPE_CHECKBOX; + case SANE_TYPE_INT: + if (optDesc->size == sizeof(SANE_Word)) return TYPE_SLIDER; + + if ((strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR) == 0) || + (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_R) == 0) || + (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_G) == 0) || + (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_B) == 0)) + { + return TYPE_GAMMA; + } + kDebug() << "Can not handle:"<< optDesc->title; + kDebug() << "SANE_CONSTRAINT_RANGE && SANE_TYPE_INT && !SANE_NAME_GAMMA_VECTOR..."; + kDebug() << "size" << optDesc->size<< "!= sizeof(SANE_Word)"; + break; + case SANE_TYPE_FIXED: + if (optDesc->size == sizeof(SANE_Word)) return TYPE_F_SLIDER; + kDebug() << "Can not handle:"<< optDesc->title; + kDebug() << "SANE_CONSTRAINT_RANGE && SANE_TYPE_FIXED"; + kDebug() << "size" << optDesc->size<< "!= sizeof(SANE_Word)"; + kDebug() << "Analog Gamma vector?"; + break; + case SANE_TYPE_STRING: + kDebug() << "Can not handle:" << optDesc->title; + kDebug() << "SANE_CONSTRAINT_RANGE && SANE_TYPE_STRING"; + return TYPE_DETECT_FAIL; + case SANE_TYPE_BUTTON: + return TYPE_BUTTON; + case SANE_TYPE_GROUP: + return TYPE_DETECT_FAIL; + } + break; + case SANE_CONSTRAINT_WORD_LIST: + case SANE_CONSTRAINT_STRING_LIST: + return TYPE_COMBO; + } + return TYPE_DETECT_FAIL; +} + +KLocalizedString KSaneOption::unitString() +{ + switch(m_optDesc->unit) + { + case SANE_UNIT_NONE: return KLocalizedString(); + case SANE_UNIT_PIXEL: return ki18ncp("SpinBox parameter unit", " Pixel", " Pixels"); + case SANE_UNIT_BIT: return ki18ncp("SpinBox parameter unit", " Bit", " Bits"); + case SANE_UNIT_MM: return ki18nc("SpinBox parameter unit (Millimeter)", " mm"); + case SANE_UNIT_DPI: return ki18nc("SpinBox parameter unit (Dots Per Inch)", " DPI"); + case SANE_UNIT_PERCENT: return ki18nc("SpinBox parameter unit (Percentage)", " %"); + case SANE_UNIT_MICROSECOND: return ki18nc("SpinBox parameter unit (Microseconds)", " µs"); + } + return KLocalizedString(); +} + +QString KSaneOption::unitDoubleString() +{ + switch(m_optDesc->unit) + { + case SANE_UNIT_NONE: return QString(""); + case SANE_UNIT_PIXEL: return i18nc("Double numbers. SpinBox parameter unit", " Pixels"); + case SANE_UNIT_BIT: return i18nc("Double numbers. SpinBox parameter unit", " Bits"); + case SANE_UNIT_MM: return i18nc("Double numbers. SpinBox parameter unit (Millimeter)", " mm"); + case SANE_UNIT_DPI: return i18nc("Double numbers. SpinBox parameter unit (Dots Per Inch)", " DPI"); + case SANE_UNIT_PERCENT: return i18nc("Double numbers. SpinBox parameter unit (Percentage)", " %"); + case SANE_UNIT_MICROSECOND: return i18nc("Double numbers. SpinBox parameter unit (Microseconds)", " µs"); + } + return QString(""); +} + + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/options/ksane_option.h b/libksane/libksane/options/ksane_option.h new file mode 100644 index 00000000..51ec64fa --- /dev/null +++ b/libksane/libksane/options/ksane_option.h @@ -0,0 +1,122 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2009-01-21 + * Description : Sane interface for KDE + * + * Copyright (C) 2009 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPTION_H +#define KSANE_OPTION_H + +// Qt includes +#include + +//KDE includes +#include + +// Sane includes +extern "C" +{ +#include +#include +} + +namespace KSaneIface +{ + +class KSaneOptionWidget; + +class KSaneOption : public QObject +{ + Q_OBJECT + +public: + + typedef enum + { + TYPE_DETECT_FAIL, + TYPE_CHECKBOX, + TYPE_SLIDER, + TYPE_F_SLIDER, + TYPE_COMBO, + TYPE_ENTRY, + TYPE_GAMMA, + TYPE_BUTTON + } KSaneOptType; + + typedef enum + { + STATE_HIDDEN, + STATE_DISABLED, + STATE_SHOWN + } KSaneOptWState; + + KSaneOption(const SANE_Handle handle, const int index); + ~KSaneOption(); + static KSaneOptType optionType(const SANE_Option_Descriptor *optDesc); + + KSaneOptionWidget *widget() {return m_widget;} + virtual bool hasGui() {return false;} + bool needsPolling(); + KSaneOptWState state(); + QString name(); + + virtual void createWidget(QWidget *parent); + + virtual void readOption(); + virtual void readValue(); + + virtual bool getMinValue(float &max); + virtual bool getMaxValue(float &max); + virtual bool getValue(float &val); + virtual bool setValue(float val); + virtual bool getValue(QString &val); + virtual bool setValue(const QString &val); + virtual int getUnit(); + + bool storeCurrentData(); + bool restoreSavedData(); + +Q_SIGNALS: + void optsNeedReload(); + void valsNeedReload(); + +protected: + + SANE_Word toSANE_Word(unsigned char *data); + void fromSANE_Word(unsigned char *data, SANE_Word from); + bool writeData(void *data); + KLocalizedString unitString(); + QString unitDoubleString(); + void updateVisibility(); + + SANE_Handle m_handle; + int m_index; + const SANE_Option_Descriptor *m_optDesc; ///< This pointer is provided by sane + unsigned char *m_data; + KSaneOptionWidget *m_widget; +}; + +} // NameSpace KSaneIface + +#endif // KSANE_OPTION_H diff --git a/libksane/libksane/selectionitem.cpp b/libksane/libksane/selectionitem.cpp new file mode 100644 index 00000000..b7ed1d2c --- /dev/null +++ b/libksane/libksane/selectionitem.cpp @@ -0,0 +1,262 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2008-11-15 +* Description :Selection QGraphicsItem for the image viewer. +* +* Copyright (C) 2008 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ + +#include "selectionitem.h" +#include +#include +#include +#include + +namespace KSaneIface +{ + + +static const qreal selMargin = 4.0; +static const QPointF boundMargin(selMargin,selMargin); +static const qreal addRemMargin = 8.0; +static const QPointF addRemMarginPoint(addRemMargin, addRemMargin); + +struct SelectionItem::Private +{ + QPen penDark; + QPen penLight; + QPen penAddRemFg; + QRectF rect; + qreal maxX; + qreal maxY; + bool hasMaxX; + bool hasMaxY; + bool hasMax; + bool isSaved; + bool showAddRem; + qreal invZoom; + qreal selMargin; + QRectF addRemRect; +}; + + +SelectionItem::SelectionItem(QRectF rect) : QGraphicsItem(), d(new Private) +{ + d->hasMaxX = false; + d->hasMaxY = false; + d->hasMax = false; + setRect(rect); + + d->penDark.setColor(Qt::black); + d->penDark.setStyle(Qt::SolidLine); + d->penLight.setColor(Qt::white); + d->penLight.setStyle(Qt::DashLine); + + // FIXME We should probably use some standard KDE color here and not hard code it + d->penAddRemFg.setColor(Qt::darkGreen); + d->penAddRemFg.setStyle(Qt::SolidLine); + d->penAddRemFg.setWidth(3); + + d->isSaved = false; + d->showAddRem = false; + d->invZoom = 1; + d->selMargin = selMargin; + + d->addRemRect = QRectF(0,0,0,0); +} + +SelectionItem::~SelectionItem() +{ + delete d; +} + +void SelectionItem::saveZoom(qreal zoom) +{ + if (zoom < 0.00001) zoom = 0.00001; + d->invZoom = 1/zoom; + + d->selMargin = selMargin * d->invZoom; + + qreal margin = addRemMargin * d->invZoom; + QPointF pMargin = addRemMarginPoint * d->invZoom; + d->addRemRect = QRectF(d->rect.center()-pMargin, QSizeF(margin*2.0, margin*2.0)); + d->penAddRemFg.setWidthF(3.0 * d->invZoom); +} + +void SelectionItem::setSaved(bool isSaved) +{ + if (isSaved) { + d->penDark.setColor(Qt::darkBlue); + d->penLight.setColor(Qt::red); + d->penAddRemFg.setColor(Qt::darkRed); + d->isSaved = true; + } + else { + d->penDark.setColor(Qt::black); + d->penLight.setColor(Qt::white); + d->penAddRemFg.setColor(Qt::darkGreen); + d->isSaved = false; + } +} + +void SelectionItem::setMaxRight(qreal maxX) +{ + d->maxX = maxX; + d->hasMaxX = true; + if (d->hasMaxY) d->hasMax = true; +} + +void SelectionItem::setMaxBottom(qreal maxY) +{ + d->maxY = maxY; + d->hasMaxY = true; + if (d->hasMaxX) d->hasMax = true; +} + +SelectionItem::Intersects SelectionItem::intersects(QPointF point) +{ + bool oldState = d->showAddRem; + d->showAddRem = false; + + if ((point.x() < (d->rect.left()-d->selMargin)) || + (point.x() > (d->rect.right()+d->selMargin)) || + (point.y() < (d->rect.top()-d->selMargin)) || + (point.y() > (d->rect.bottom()+d->selMargin))) + { + if (oldState != d->showAddRem) update(); + return None; + } + + if (point.x() < (d->rect.left()+d->selMargin)) { + if (oldState != d->showAddRem) update(); + if (point.y() < (d->rect.top()+d->selMargin)) return TopLeft; + if (point.y() > (d->rect.bottom()-d->selMargin)) return BottomLeft; + return Left; + } + + if (point.x() > (d->rect.right()-d->selMargin)) { + if (oldState != d->showAddRem) update(); + if (point.y() < (d->rect.top()+d->selMargin)) return TopRight; + if (point.y() > (d->rect.bottom()-d->selMargin)) return BottomRight; + return Right; + } + + if (point.y() < (d->rect.top()+d->selMargin)) { + if (oldState != d->showAddRem) update(); + return Top; + } + if (point.y() > (d->rect.bottom()-d->selMargin)) { + if (oldState != d->showAddRem) update(); + return Bottom; + } + + d->showAddRem = true; + if (oldState != d->showAddRem) update(); + + if ((point.x() > d->addRemRect.left()) && + (point.x() < d->addRemRect.right()) && + (point.y() > d->addRemRect.top()) && + (point.y() < d->addRemRect.bottom())) + { + return AddRemove; + } + return Move; +} + +void SelectionItem::setRect(QRectF rect) +{ + prepareGeometryChange(); + d->rect = rect; + d->rect = d->rect.normalized(); + if (d->hasMax) { + if (d->rect.top() < 0) d->rect.setTop(0); + if (d->rect.left() < 0) d->rect.setLeft(0); + if (d->rect.right() > d->maxX) d->rect.setRight(d->maxX); + if (d->rect.bottom() > d->maxY) d->rect.setBottom(d->maxY); + } + + // calculate the add/remove rectangle + qreal margin = addRemMargin * d->invZoom; + QPointF pMargin = addRemMarginPoint * d->invZoom; + d->addRemRect = QRectF(d->rect.center()-pMargin, QSizeF(margin*2, margin*2)); +} + +QPointF SelectionItem::fixTranslation(QPointF dp) +{ + if ((d->rect.left() + dp.x()) < 0) dp.setX(-d->rect.left()); + if ((d->rect.top() + dp.y()) < 0) dp.setY(-d->rect.top()); + if ((d->rect.right() + dp.x()) > d->maxX) dp.setX(d->maxX - d->rect.right()); + if ((d->rect.bottom() + dp.y()) > d->maxY) dp.setY(d->maxY - d->rect.bottom()); + return dp; +} + +QRectF SelectionItem::rect() +{ + return d->rect; +} + +QRectF SelectionItem::boundingRect() const +{ + QRectF tmp(d->rect.topLeft()-boundMargin, d->rect.bottomRight()+boundMargin); + if (tmp.top() > d->addRemRect.top()) { + tmp.setTop(d->addRemRect.top()); + } + if (tmp.left() > d->addRemRect.left()) { + tmp.setLeft(d->addRemRect.left()); + } + + if (tmp.bottom() < d->addRemRect.bottom()) { + tmp.setBottom(d->addRemRect.bottom()); + } + + if (tmp.right() < d->addRemRect.right()) { + tmp.setRight(d->addRemRect.right()); + } + + return tmp; +} + +void SelectionItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + painter->setPen(d->penDark); + painter->drawRect(d->rect); + + painter->setPen(d->penLight); + painter->drawRect(d->rect); + + if (d->showAddRem) { + painter->fillRect(d->addRemRect, QBrush(Qt::white)); + QLineF minus(d->addRemRect.left()+3*d->invZoom, d->rect.center().y(), + d->addRemRect.right()-3*d->invZoom, d->rect.center().y()); + painter->setPen(d->penAddRemFg); + + painter->drawLine(minus); + + if (!d->isSaved) { + QLineF plus(d->rect.center().x(), d->addRemRect.top()+3*d->invZoom, + d->rect.center().x(), d->addRemRect.bottom()-3*d->invZoom); + painter->drawLine(plus); + } + } +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/selectionitem.h b/libksane/libksane/selectionitem.h new file mode 100644 index 00000000..17f6ab22 --- /dev/null +++ b/libksane/libksane/selectionitem.h @@ -0,0 +1,82 @@ +/* ============================================================ +* +* This file is part of the KDE project +* +* Date : 2008-11-15 +* Description :Selection QGraphicsItem for the image viewer. +* +* Copyright (C) 2008 by Kare Sars +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) version 3, or any +* later version accepted by the membership of KDE e.V. (or its +* successor approved by the membership of KDE e.V.), which shall +* act as a proxy defined in Section 6 of version 3 of the license. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this program. If not, see . +* +* ============================================================ */ +#ifndef SELECTIONITEM_H +#define SELECTIONITEM_H + +#include +#include + +namespace KSaneIface +{ + +class SelectionItem : public QGraphicsItem +{ + public: + typedef enum + { + None, + Top, + TopRight, + Right, + BottomRight, + Bottom, + BottomLeft, + Left, + TopLeft, + Move, + AddRemove + } Intersects; + + explicit SelectionItem(QRectF rect); + ~SelectionItem(); + + void setMaxRight(qreal maxRight); + void setMaxBottom(qreal maxBottom); + void setSaved(bool isSaved); + + Intersects intersects(QPointF point); + + void saveZoom(qreal zoom); + + void setRect(QRectF rect); + QPointF fixTranslation(QPointF dp); + QRectF rect(); + + public: + // Graphics Item methods + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + private: + struct Private; + Private * const d; +}; + +} // NameSpace KSaneIface + +#endif + diff --git a/libksane/libksane/splittercollapser.cpp b/libksane/libksane/splittercollapser.cpp new file mode 100644 index 00000000..484d8179 --- /dev/null +++ b/libksane/libksane/splittercollapser.cpp @@ -0,0 +1,307 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview: an image viewer +Copyright 2009 Aurélien Gâteau +Copyright 2009 Kåre Sårs + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this program. If not, see . + +*/ +// Self +#include "splittercollapser.moc" + +// Qt +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include + +// Local + +namespace KSaneIface { + + +enum Direction { + LTR = 1 << 0, + RTL = 1 << 1, + Vertical = 1 << 2, + TTB = Vertical + (1 << 0), + BTT = Vertical + (1 << 1) +}; + +const int TIMELINE_DURATION = 500; + +const qreal MINIMUM_OPACITY = 0.3; + +struct ArrowTypes { + ArrowTypes() + : visible(Qt::NoArrow), notVisible(Qt::NoArrow){} + + ArrowTypes(Qt::ArrowType t1, Qt::ArrowType t2) + : visible(t1), notVisible(t2) {} + + Qt::ArrowType visible, + notVisible; + + Qt::ArrowType get(bool isVisible) { + return isVisible ? visible : notVisible; + } +}; + + +struct SplitterCollapserPrivate { + SplitterCollapser* q; + QSplitter* mSplitter; + QWidget* mWidget; + Direction mDirection; + QTimeLine* mOpacityTimeLine; + int mSizeAtCollaps; + + bool isVertical() const { + return mDirection & Vertical; + } + + bool isVisible() const { + bool isVisible = mWidget->isVisible(); + QRect widgetRect = mWidget->geometry(); + if (isVisible) { + QPoint br = widgetRect.bottomRight(); + if ((br.x() <= 0) || (br.y() <=0)) { + isVisible = false; + } + } + return isVisible; + } + + void updatePosition() { + int x, y; + QRect widgetRect = mWidget->geometry(); + int splitterWidth = mSplitter->width(); + int handleWidth = mSplitter->handleWidth(); + int width = q->width(); + + if (!isVertical()) { + // FIXME: Make this configurable + y = 30; + if (mDirection == LTR) { + if (isVisible()) { + x = widgetRect.right() + handleWidth; + } else { + x = 0; + } + } else { // RTL + if (isVisible()) { + x = widgetRect.left() - handleWidth - width; + } else { + x = splitterWidth - handleWidth - width; + } + } + } else { + // FIXME + x = 0; + y = 0; + } + q->move(x, y); + } + + + void updateArrow() { + static QMap arrowForDirection; + if (arrowForDirection.isEmpty()) { + arrowForDirection[LTR] = ArrowTypes(Qt::LeftArrow, Qt::RightArrow); + arrowForDirection[RTL] = ArrowTypes(Qt::RightArrow, Qt::LeftArrow); + arrowForDirection[TTB] = ArrowTypes(Qt::UpArrow, Qt::DownArrow); + arrowForDirection[BTT] = ArrowTypes(Qt::DownArrow, Qt::UpArrow); + } + q->setArrowType(arrowForDirection[mDirection].get(isVisible())); + } + + + void widgetEventFilter(QEvent* event) { + switch (event->type()) { + case QEvent::Resize: + updatePosition(); + updateOpacity(); + break; + + case QEvent::Move: + case QEvent::Show: + case QEvent::Hide: + updatePosition(); + updateOpacity(); + updateArrow(); + break; + + default: + break; + } + } + + + void updateOpacity() { + QPoint pos = q->parentWidget()->mapFromGlobal(QCursor::pos()); + QRect opaqueRect = q->geometry(); + bool opaqueCollapser = opaqueRect.contains(pos); + int frame = mOpacityTimeLine->currentFrame(); + if (opaqueCollapser && frame == mOpacityTimeLine->startFrame()) { + mOpacityTimeLine->setDirection(QTimeLine::Forward); + startTimeLine(); + } else if (!opaqueCollapser && frame == mOpacityTimeLine->endFrame()) { + mOpacityTimeLine->setDirection(QTimeLine::Backward); + startTimeLine(); + } + } + + + void startTimeLine() { + if (mOpacityTimeLine->state() != QTimeLine::Running) { + mOpacityTimeLine->start(); + } + } +}; + + +SplitterCollapser::SplitterCollapser(QSplitter* splitter, QWidget* widget) +: QToolButton(), +d(new SplitterCollapserPrivate) +{ + d->q = this; + + // We do not want our collapser to be added as a regular widget in the + // splitter! + setAttribute(Qt::WA_NoChildEventsForParent); + + d->mOpacityTimeLine = new QTimeLine(TIMELINE_DURATION, this); + d->mOpacityTimeLine->setFrameRange(int(MINIMUM_OPACITY * 1000), 1000); + connect(d->mOpacityTimeLine, SIGNAL(valueChanged(qreal)), SLOT(update())); + + d->mWidget = widget; + d->mWidget->installEventFilter(this); + + qApp->installEventFilter(this); + + d->mSplitter = splitter; + setParent(d->mSplitter); + + if (splitter->indexOf(widget) < splitter->count() / 2) { + d->mDirection = LTR; + } else { + d->mDirection = RTL; + } + if (splitter->orientation() == Qt::Vertical) { + // FIXME: Ugly! + d->mDirection = static_cast(int(d->mDirection) + int(TTB)); + } + + connect(this, SIGNAL(clicked()), SLOT(slotClicked())); + + show(); +} + + +SplitterCollapser::~SplitterCollapser() { + delete d; +} + + +bool SplitterCollapser::eventFilter(QObject* object, QEvent* event) { + if (object == d->mWidget) { + d->widgetEventFilter(event); + } else { /* app */ + if (event->type() == QEvent::MouseMove) { + d->updateOpacity(); + } + } + return false; +} + + +QSize SplitterCollapser::sizeHint() const { + int extent = style()->pixelMetric(QStyle::PM_ScrollBarExtent); + QSize sh(extent * 3 / 4, extent * 240 / 100); + if (d->isVertical()) { + sh.transpose(); + } + return sh; +} + + +void SplitterCollapser::slotClicked() { + QList sizes = d->mSplitter->sizes(); + int index = d->mSplitter->indexOf(d->mWidget); + if (d->isVisible()) { + d->mSizeAtCollaps = sizes[index]; + sizes[index] = 0; + } + else { + if (d->mSizeAtCollaps != 0) { + sizes[index] = d->mSizeAtCollaps; + } + else { + if (d->isVertical()) { + sizes[index] = d->mWidget->sizeHint().height(); + } + else { + sizes[index] = d->mWidget->sizeHint().width(); + } + } + } + d->mSplitter->setSizes(sizes); +} + +void SplitterCollapser::slotCollapse() { + if (d->isVisible()) slotClicked(); + // else do nothing +} + +void SplitterCollapser::slotRestore() { + if (!d->isVisible()) slotClicked(); + // else do nothing +} + +void SplitterCollapser::slotSetCollapsed(bool collapse) { + if (collapse == d->isVisible()) slotClicked(); + // else do nothing +} + +void SplitterCollapser::paintEvent(QPaintEvent*) { + QStylePainter painter(this); + qreal opacity = d->mOpacityTimeLine->currentFrame() / 1000.; + painter.setOpacity(opacity); + + QStyleOptionToolButton opt; + initStyleOption(&opt); + if (d->mDirection == LTR) { + opt.rect.setLeft(-width()); + } else { + opt.rect.setWidth(width() * 2); + } + painter.drawPrimitive(QStyle::PE_PanelButtonTool, opt); + + QStyleOptionToolButton opt2; + initStyleOption(&opt2); + painter.drawControl(QStyle::CE_ToolButtonLabel, opt2); +} + + +} // namespace diff --git a/libksane/libksane/splittercollapser.h b/libksane/libksane/splittercollapser.h new file mode 100644 index 00000000..2c80933e --- /dev/null +++ b/libksane/libksane/splittercollapser.h @@ -0,0 +1,69 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview: an image viewer +Copyright 2009 Aurélien Gâteau + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this program. If not, see . + +*/ +#ifndef SPLITTERCOLLAPSER_H +#define SPLITTERCOLLAPSER_H + +// Qt +#include + +// KDE + +class QSplitter; + +namespace KSaneIface { + + +struct SplitterCollapserPrivate; +/** + * A button which appears on the side of a splitter handle and allows easy + * collapsing of the widget on the opposite side + */ +class SplitterCollapser : public QToolButton { + Q_OBJECT +public: + SplitterCollapser(QSplitter*, QWidget* widget); + ~SplitterCollapser(); + + virtual QSize sizeHint() const; + +public Q_SLOTS: + void slotCollapse(); + void slotRestore(); + void slotSetCollapsed(bool collapsed); + +protected: + virtual bool eventFilter(QObject*, QEvent*); + + virtual void paintEvent(QPaintEvent*); + +private: + SplitterCollapserPrivate* const d; + +private Q_SLOTS: + void slotClicked(); +}; + + +} // namespace + +#endif /* SPLITTERCOLLAPSER_H */ diff --git a/libksane/libksane/version.h.cmake.in b/libksane/libksane/version.h.cmake.in new file mode 100644 index 00000000..982a85f6 --- /dev/null +++ b/libksane/libksane/version.h.cmake.in @@ -0,0 +1,30 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.digikam.org + * + * Date : 2007-02-12 + * Description : Sane interface for KDE + * + * Copyright (C) 2007 by Gilles Caulier + * + * 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, 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. + * + * ============================================================ */ + +#ifndef KSANE_VERSION_H +#define KSANE_VERSION_H + +static const char ksane_version[] = "${KSANE_LIB_VERSION_STRING}"; + +#define KSANE_VERSION ${KSANE_LIB_VERSION_ID} + +#endif // KSANE_VERSION_H diff --git a/libksane/libksane/widgets/gamma_disp.cpp b/libksane/libksane/widgets/gamma_disp.cpp new file mode 100644 index 00000000..cc03e722 --- /dev/null +++ b/libksane/libksane/widgets/gamma_disp.cpp @@ -0,0 +1,90 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2008 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "gamma_disp.h" +#include "gamma_disp.moc" + +// Qt includes +#include + +namespace KSaneIface +{ + +GammaDisp::GammaDisp(QWidget *parent, QVector *tbl) + : QWidget(parent) +{ + gam_tbl = tbl; + gam_color.setRgb(0,0,0); +} + +QSize GammaDisp::minimumSizeHint() const +{ + return QSize(75, 75); +} + +QSize GammaDisp::sizeHint() const +{ + return QSize(75, 75); +} + +void GammaDisp::setColor(const QColor &color) +{ + gam_color = color; +} + +void GammaDisp::resizeEvent (QResizeEvent*) +{ + repaint(); +} + +void GammaDisp::paintEvent(QPaintEvent *) +{ +/* QMemArray rects = event->region().rects(); + for (int i = 0; i < (int)rects.size(); i++) { + bitBlt(this, rects[i].topLeft(), &pixmap, rects[i]); + }*/ + QPointF p1, p2; + QPainter painter(this); + painter.fillRect(rect(), QBrush(Qt::white)); + + double xscale = (double)(size().width()-1) / (double)gam_tbl->size(); + double yscale = (double)(size().height()-1) / (double)gam_tbl->size(); + + painter.setPen(gam_color); + for (int i=0; isize()-1; i++) { + p1.setX(i*xscale); + p1.setY(size().height()- 1 - (gam_tbl->at(i) * yscale)); + + p2.setX((i+1)*xscale); + p2.setY(size().height()- 1 - (gam_tbl->at(i+1) * yscale)); + + painter.drawLine(p1, p2); + } +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/gamma_disp.h b/libksane/libksane/widgets/gamma_disp.h new file mode 100644 index 00000000..ebefff8e --- /dev/null +++ b/libksane/libksane/widgets/gamma_disp.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2008 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef GAMMA_DISP_H +#define GAMMA_DISP_H + +// Qt includes + +#include + +/** + *@author Kåre Särs + * + * This is the widget that displays the gamma table. + */ + +namespace KSaneIface +{ + +class GammaDisp : public QWidget +{ + Q_OBJECT + +public: + + /** + * Create a gamma display. + * \param parent parent widget + */ + GammaDisp(QWidget *parent, QVector *tbl); + ~GammaDisp() {}; + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + void setColor(const QColor &color); + +protected: + + void paintEvent (QPaintEvent *); + void resizeEvent(QResizeEvent *); + +private: + + QVector *gam_tbl; + QColor gam_color; +}; + +} // NameSpace KSaneIface + +#endif // GAMMA_DISP_H + diff --git a/libksane/libksane/widgets/ksane_button.cpp b/libksane/libksane/widgets/ksane_button.cpp new file mode 100644 index 00000000..74f9e9a8 --- /dev/null +++ b/libksane/libksane/widgets/ksane_button.cpp @@ -0,0 +1,51 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Copyright (C) 2008-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "ksane_button.h" +#include "ksane_button.moc" + +// Qt includes +#include + +namespace KSaneIface +{ + +KSaneButton::KSaneButton(QWidget *parent, const QString& ltext) +: KSaneOptionWidget(parent, QString()) +{ + m_button = new QPushButton(ltext, this); + m_layout->addWidget(m_button, 0, 1); + m_layout->addWidget(new QWidget(this), 0, 2); + m_layout->setColumnStretch(1, 0); + m_layout->setColumnStretch(2, 50); + + connect(m_button, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); +} + +KSaneButton::~KSaneButton() +{ +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/ksane_button.h b/libksane/libksane/widgets/ksane_button.h new file mode 100644 index 00000000..6d6ba5d9 --- /dev/null +++ b/libksane/libksane/widgets/ksane_button.h @@ -0,0 +1,67 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Copyright (C) 2008-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_BUTTON_H +#define KSANE_BUTTON_H + +#include "ksane_option_widget.h" + +// Qt includes +#include +#include + +namespace KSaneIface +{ + +/** + *@author Kåre Särs + */ + +/** + * A wrapper for a checkbox + */ +class KSaneButton : public KSaneOptionWidget +{ + Q_OBJECT + +public: + /** + * Create the checkbox. + * + * \param parent parent widget + * \param text is the text describing the checkbox. + */ + KSaneButton(QWidget *parent, const QString& text); + ~KSaneButton(); + +Q_SIGNALS: + void clicked(); + +private: + QPushButton *m_button; +}; + +} // NameSpace KSaneIface + +#endif // KSANE_BUTTON_H diff --git a/libksane/libksane/widgets/ksane_option_widget.cpp b/libksane/libksane/widgets/ksane_option_widget.cpp new file mode 100644 index 00000000..25c48637 --- /dev/null +++ b/libksane/libksane/widgets/ksane_option_widget.cpp @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Description : Base class for option widgets + * + * Copyright (C) 2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "ksane_option_widget.h" +#include "ksane_option_widget.moc" + +// Qt includes +#include +#include + +namespace KSaneIface +{ + +KSaneOptionWidget::KSaneOptionWidget(QWidget *parent, const QString& labelText) +: QWidget(parent) +{ + m_label = new QLabel; + setLabelText(labelText); + + m_layout = new QGridLayout(this); + m_layout->addWidget(m_label, 0, 0, Qt::AlignRight); + m_layout->setColumnStretch(0, 0); + m_layout->setContentsMargins(0,0,0,0); +} + +KSaneOptionWidget::~KSaneOptionWidget() +{ +} + +void KSaneOptionWidget::setLabelText(const QString &text) +{ + if (text.isEmpty()) { + m_label->setText(QString()); + } else { + m_label->setText(i18nc("Label for a scanner option", "%1:", text)); + } +} + + +int KSaneOptionWidget::labelWidthHint() +{ + return m_label->sizeHint().width(); +} + +void KSaneOptionWidget::setLabelWidth(int labelWidth) +{ + m_layout->setColumnMinimumWidth(0, labelWidth); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/ksane_option_widget.h b/libksane/libksane/widgets/ksane_option_widget.h new file mode 100644 index 00000000..a173e163 --- /dev/null +++ b/libksane/libksane/widgets/ksane_option_widget.h @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Description : Base class for option widgets + * + * Copyright (C) 2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef KSANE_OPTION_WIDGET_H +#define KSANE_OPTION_WIDGET_H + +// Qt includes +#include +#include +#include + +namespace KSaneIface +{ + +/** + *@author Kåre Särs + */ + +/** + * A wrapper for a checkbox + */ +class KSaneOptionWidget : public QWidget +{ + Q_OBJECT + +public: + /** + * Create the Wodget. + * \param parent parent widget + * \param Label text. + */ + KSaneOptionWidget(QWidget *parent, const QString &labelText); + ~KSaneOptionWidget(); + + void setLabelText(const QString &text); + + int labelWidthHint(); + void setLabelWidth(int labelWidth); + +protected: + QLabel *m_label; + QGridLayout *m_layout; +}; + +} // NameSpace KSaneIface + +#endif // KSANE_OPTION_WIDGET_H diff --git a/libksane/libksane/widgets/labeled_checkbox.cpp b/libksane/libksane/widgets/labeled_checkbox.cpp new file mode 100644 index 00000000..d8086f46 --- /dev/null +++ b/libksane/libksane/widgets/labeled_checkbox.cpp @@ -0,0 +1,62 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "labeled_checkbox.h" +#include "labeled_checkbox.moc" + +// Qt includes +#include + +namespace KSaneIface +{ + +LabeledCheckbox::LabeledCheckbox(QWidget *parent, const QString& ltext) +: KSaneOptionWidget(parent, QString()) +{ + chbx = new QCheckBox(ltext, this); + m_layout->addWidget(chbx, 0, 1); + m_layout->setColumnStretch(1, 50); + + connect(chbx, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); +} + +LabeledCheckbox::~LabeledCheckbox() +{ +} + +void LabeledCheckbox::setChecked(bool is_checked) +{ + if (is_checked != chbx->isChecked()) chbx->setChecked(is_checked); +} + +bool LabeledCheckbox::isChecked() +{ + return chbx->isChecked(); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_checkbox.h b/libksane/libksane/widgets/labeled_checkbox.h new file mode 100644 index 00000000..f8e57f10 --- /dev/null +++ b/libksane/libksane/widgets/labeled_checkbox.h @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_CHECKBOX_H +#define LABELED_CHECKBOX_H + +#include "ksane_option_widget.h" + +// Qt includes +#include +#include + +namespace KSaneIface +{ + +/** + *@author Kåre Särs + */ + +/** + * A wrapper for a checkbox + */ +class LabeledCheckbox : public KSaneOptionWidget +{ + Q_OBJECT + +public: + + /** + * Create the checkbox. + * + * \param parent parent widget + * \param text is the text describing the checkbox. + */ + LabeledCheckbox(QWidget *parent, const QString& text); + ~LabeledCheckbox(); + void setChecked(bool); + bool isChecked(); + +Q_SIGNALS: + void toggled(bool); + +private: + + QCheckBox *chbx; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_CHECKBOX_H diff --git a/libksane/libksane/widgets/labeled_combo.cpp b/libksane/libksane/widgets/labeled_combo.cpp new file mode 100644 index 00000000..6ac958dd --- /dev/null +++ b/libksane/libksane/widgets/labeled_combo.cpp @@ -0,0 +1,101 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ +#include "labeled_combo.h" +#include "labeled_combo.moc" + +// Qt includes +#include + +// KDE includes +#include +#include + +namespace KSaneIface +{ + +LabeledCombo::LabeledCombo(QWidget *parent, const QString& ltext, const QStringList& list) +: KSaneOptionWidget(parent, ltext) +{ + m_combo = new KComboBox(this); + m_combo->addItems(list); + + m_label->setBuddy(m_combo); + + connect(m_combo, SIGNAL(activated(int)), this, SIGNAL(activated(int))); + + m_layout->addWidget(m_combo, 0, 1); + m_layout->addWidget(new QWidget(this), 0, 2); + m_layout->setColumnStretch(1, 0); + m_layout->setColumnStretch(2, 50); + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); +} + +void LabeledCombo::addItems(const QStringList &list) +{ + m_combo->addItems(list); + + QString tmp; + for (int i=0; icount(); i++) { + tmp = m_combo->itemText(i); + m_combo->setItemData(i, tmp, Qt::ToolTipRole); + } +} + + +void LabeledCombo::setCurrentText(const QString &t) +{ + int i; + for (i=0; icount(); i++) { + if (m_combo->itemText(i) == t) { + m_combo->setCurrentIndex(i); + } + } +} + +QString LabeledCombo::currentText() +{ + return m_combo->currentText(); +} + + +bool LabeledCombo::setIcon(const QIcon &icon, const QString& str) +{ + for (int i=0; i < m_combo->count(); i++) { + if (m_combo->itemText(i) == str) { + m_combo->setItemIcon(i, icon); + return true; + } + } + return false; +} + +void LabeledCombo::setCurrentIndex(int i) +{ + m_combo->setCurrentIndex(i); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_combo.h b/libksane/libksane/widgets/labeled_combo.h new file mode 100644 index 00000000..4600b007 --- /dev/null +++ b/libksane/libksane/widgets/labeled_combo.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_COMBO_H +#define LABELED_COMBO_H + +#include "ksane_option_widget.h" + +// KDE includes +#include + +namespace KSaneIface +{ + +/** + * A label and a combobox. + */ +class LabeledCombo : public KSaneOptionWidget +{ + Q_OBJECT + +public: + /** + * create a label and combobox combination. + * \param parent parent widget + * \param label is the lext for the label + * \param list a stringlist with values the list should contain. + */ + LabeledCombo(QWidget *parent, const QString& label, const QStringList& list); + + +public Q_SLOTS: + + /** + * Add string entries to the combobox + */ + void addItems(const QStringList &list); + + /** + * Remove all string entries + */ + void clear() { m_combo->clear(); } + + /** + * If the given string can be found in the comobox, activate that entry. + * If not, the entry is not changed. + */ + void setCurrentText(const QString &); + + /** + * This function is used to read the current string of the combobox + */ + QString currentText(); + + /** + * set the current item of the combobox. + */ + void setCurrentIndex(int); + + /** + * add an icon for a string in the combobox + * @param icon the icon to set. + * @param str the string for which the pixmap should be set. + */ + bool setIcon(const QIcon& icon, const QString& str); + +Q_SIGNALS: + + void activated(int); + +private: + KComboBox *m_combo; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_COMBO_H diff --git a/libksane/libksane/widgets/labeled_entry.cpp b/libksane/libksane/widgets/labeled_entry.cpp new file mode 100644 index 00000000..e6c164ef --- /dev/null +++ b/libksane/libksane/widgets/labeled_entry.cpp @@ -0,0 +1,81 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "labeled_entry.h" +#include "labeled_entry.moc" + +// Qt includes +#include +#include +#include +#include +#include + +namespace KSaneIface +{ + +LabeledEntry::LabeledEntry(QWidget *parent, const QString& ltext) +: KSaneOptionWidget(parent, ltext) +{ + m_entry = new KLineEdit(this); + m_reset = new QPushButton(this); + m_reset->setText(i18nc("Label for button to reset text in a KLineEdit", "Reset")); + m_set = new QPushButton(this); + m_set->setText(i18nc("Label for button to write text in a KLineEdit to sane", "Set")); + + m_layout->addWidget(m_entry, 1, 0, 1, 2); + m_layout->addWidget(m_reset, 1, 2); + m_layout->addWidget(m_set, 1, 3); + m_layout->setColumnStretch(1, 50); + + connect(m_reset, SIGNAL(clicked()), this, SLOT(resetClicked())); + connect(m_set, SIGNAL(clicked()), this, SLOT(setClicked())); +} + +LabeledEntry::~LabeledEntry() +{ +} + +void LabeledEntry::setText(const QString& text) +{ + m_eText = text; + m_entry->setText(text); +} + +void LabeledEntry::resetClicked() +{ + m_entry->setText(m_eText); +} + +void LabeledEntry::setClicked() +{ + m_eText = m_entry->text(); + emit entryEdited(m_eText); +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_entry.h b/libksane/libksane/widgets/labeled_entry.h new file mode 100644 index 00000000..78aa4a14 --- /dev/null +++ b/libksane/libksane/widgets/labeled_entry.h @@ -0,0 +1,81 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_ENTRY_H +#define LABELED_ENTRY_H + +#include "ksane_option_widget.h" + +/** + *@author Kåre Särs + */ + +class QPushButton; +class KLineEdit; + +namespace KSaneIface +{ + +/** + * A text entry field with a set and reset button + */ +class LabeledEntry : public KSaneOptionWidget +{ + Q_OBJECT + +public: + + /** + * Create the entry. + * + * \param parent parent widget + * \param text is the text describing the entry. + */ + LabeledEntry(QWidget *parent, const QString& text); + ~LabeledEntry(); + void setText(const QString& text); + +private Q_SLOTS: + + void setClicked(); + void resetClicked(); + +Q_SIGNALS: + + void entryEdited(const QString& text); + +private: + + KLineEdit *m_entry; + QPushButton *m_set; + QPushButton *m_reset; + QString m_eText; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_ENTRY_H diff --git a/libksane/libksane/widgets/labeled_fslider.cpp b/libksane/libksane/widgets/labeled_fslider.cpp new file mode 100644 index 00000000..2f2dad15 --- /dev/null +++ b/libksane/libksane/widgets/labeled_fslider.cpp @@ -0,0 +1,176 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "labeled_fslider.h" +#include "labeled_fslider.moc" + +#define FLOAT_MULTIP 32768.0 +#define TO_FLOAT(v) ((float)v / FLOAT_MULTIP) +#define TO_FIX(v) ((int)(v * FLOAT_MULTIP)) + +namespace KSaneIface +{ + +LabeledFSlider::LabeledFSlider(QWidget *parent, const QString& ltext, + float min, float max, float step) +: KSaneOptionWidget(parent, ltext) +{ + int imin = TO_FIX(min); + int imax = TO_FIX(max); + m_istep = TO_FIX(step); + m_fstep = step; + if (m_istep == 0) { + m_istep = 1; + m_fstep = TO_FLOAT(m_istep); + } + + //std::cout << "min=" << min << ", max=" << max << ", m_fstep="<minimum() << " - " << m_spinb->maximum(); + //kDebug() << ") -> (" << min << " - " << max << ")" << std::endl; + int imin=TO_FIX(min); + int imax=TO_FIX(max); + m_slider->setRange(imin, imax); + //std::cout << "fixedmin=" << imin << " fixedmax=" << imax << std::endl; + + m_spinb->setRange(min, max); +} + +void LabeledFSlider::setStep(float step) +{ + m_istep = TO_FIX(step); + m_fstep = step; + if (m_istep == 0) { + m_istep = 1; + m_fstep = TO_FLOAT(m_istep); + } + m_slider->setSingleStep(m_istep); + m_spinb->setSingleStep(m_fstep); + + int decimals=0; + float tmp_step = m_fstep; + while (tmp_step < 1) { + tmp_step *= 10; + decimals++; + if (decimals > 5) break; + } + m_spinb->setDecimals(decimals); +} + +void LabeledFSlider::setValue(float value) +{ + int ivalue = TO_FIX(value); + + if (((value - m_spinb->value()) > m_fstep) || ((m_spinb->value() - value) > m_fstep)) { + m_spinb->setValue(value); + } + else if (ivalue != m_slider->value()) m_slider->setValue(ivalue); +} + +void LabeledFSlider::syncValues(int ivalue) +{ + double value = TO_FLOAT(ivalue); + if (((value - m_spinb->value()) > m_fstep) || ((m_spinb->value() - value) > m_fstep)) { + m_spinb->setValue(value); + } + else if (ivalue != m_slider->value())m_slider->setValue(ivalue); + else emit valueChanged(value); +} + +void LabeledFSlider::syncValues(double value) +{ + int ivalue = TO_FIX(value); + if (((value - m_spinb->value()) > m_fstep) || ((m_spinb->value() - value) > m_fstep)) { + m_spinb->setValue(value); + } + else if (ivalue != m_slider->value())m_slider->setValue(ivalue); + else emit valueChanged((float)value); +} + +void LabeledFSlider::fixValue() +{ + //ensure that the value step is followed also for the m_slider + int rest = (m_slider->value() - m_slider->minimum())%m_istep; + + if (rest != 0) { + if (rest > (m_istep/2)) m_slider->setValue(m_slider->value()+(m_istep-rest)); + else m_slider->setValue(m_slider->value()-rest); + m_spinb->setValue(TO_FLOAT(m_slider->value())); + } +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_fslider.h b/libksane/libksane/widgets/labeled_fslider.h new file mode 100644 index 00000000..2fdb71cc --- /dev/null +++ b/libksane/libksane/widgets/labeled_fslider.h @@ -0,0 +1,110 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_FSLIDER_H +#define LABELED_FSLIDER_H + +#include "ksane_option_widget.h" + +// Qt includes +#include +#include + +/** + *@author Kåre Särs + */ + +namespace KSaneIface +{ + +/** + * A combination of a label a slider and a spinbox. + * The slider is connected to the spinbox so that they have the same value. + */ +class LabeledFSlider : public KSaneOptionWidget +{ + Q_OBJECT + +public: + + /** + * Create the slider. + * + * \param parent parent widget + * \param text is the text describing the slider value. If the text + * contains a '&', a buddy for the slider will be created. + * \param min minimum slider value + * \param max maximum slider value + * \param quant is the step between values. + */ + LabeledFSlider(QWidget *parent, const QString& text, + float min, float max, float st); + ~LabeledFSlider(); + + /** + * \return the slider value. + */ + float value() const {return (float)m_spinb->value();} + float step() const {return m_fstep;} + +public Q_SLOTS: + + /** Set the slider/spinbox value */ + void setValue(float); + void setRange(float, float); + void setStep(float); + /** Set the unit */ + void setSuffix(const QString &text); + +private Q_SLOTS: + + /** + * Sync the values and emit valueChanged() + */ + // FIXME this has to be changes later + void syncValues(int); + void syncValues(double); + void fixValue(); + +Q_SIGNALS: + + /** + * Emit the slider value changes + */ + void valueChanged(float); + +private: + + QSlider *m_slider; + QDoubleSpinBox *m_spinb; + float m_fstep; + int m_istep; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_SFSLIDER_H diff --git a/libksane/libksane/widgets/labeled_gamma.cpp b/libksane/libksane/widgets/labeled_gamma.cpp new file mode 100644 index 00000000..1a4fa24f --- /dev/null +++ b/libksane/libksane/widgets/labeled_gamma.cpp @@ -0,0 +1,199 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "labeled_gamma.h" +#include "labeled_gamma.moc" + +// C++ includes +#include + +// Qt includes +#include + +// KDE includes +#include + +namespace KSaneIface +{ + +LabeledGamma::LabeledGamma(QWidget *parent, const QString& text, int size) +: KSaneOptionWidget(parent, text) +{ + m_bri_slider = new LabeledSlider(this, i18n("Brightness"), -50, 50, 1); + m_bri_slider->setValue(0); + + m_con_slider = new LabeledSlider(this, i18n("Contrast"), -50, 50, 1); + m_con_slider->setValue(0); + + m_gam_slider = new LabeledSlider(this, i18n("Gamma"), 30, 300, 1); + m_gam_slider->setValue(100); + + // Calculate the size of the widgets in the sliders + int labelMax = m_bri_slider->labelWidthHint(); + labelMax = qMax(labelMax, m_con_slider->labelWidthHint()); + labelMax = qMax(labelMax, m_gam_slider->labelWidthHint()); + // set the calculated widths + m_bri_slider->setLabelWidth(labelMax); + m_con_slider->setLabelWidth(labelMax); + m_gam_slider->setLabelWidth(labelMax); + + m_gam_tbl.resize(size); + for (int i=0; i max + + m_gamma_disp = new GammaDisp(this, &m_gam_tbl); + + QGroupBox *groupBox = new QGroupBox(text, this); + QGridLayout *gr_lay = new QGridLayout(groupBox); + + gr_lay->addWidget(m_bri_slider, 0, 0); + gr_lay->addWidget(m_con_slider, 1, 0); + gr_lay->addWidget(m_gam_slider, 2, 0); + gr_lay->addWidget(m_gamma_disp, 0, 1, 3, 1); + + m_label->hide(); + m_layout->addWidget(groupBox, 1, 0, 1,3); + + connect(m_bri_slider, SIGNAL(valueChanged(int)), this, SLOT(calculateGT())); + connect(m_con_slider, SIGNAL(valueChanged(int)), this, SLOT(calculateGT())); + connect(m_gam_slider, SIGNAL(valueChanged(int)), this, SLOT(calculateGT())); +} + +LabeledGamma::~LabeledGamma() +{ +} + +void LabeledGamma::setColor(const QColor &color) +{ + if (m_gamma_disp != 0) { + m_gamma_disp->setColor(color); + } +} + +void LabeledGamma::setValues(int bri, int con, int gam) +{ + m_bri_slider->blockSignals(true); + m_con_slider->blockSignals(true); + m_gam_slider->blockSignals(true); + + m_bri_slider->setValue(bri); + m_con_slider->setValue(con); + m_gam_slider->setValue(gam); + + calculateGT(); + + m_bri_slider->blockSignals(false); + m_con_slider->blockSignals(false); + m_gam_slider->blockSignals(false); +} + +void LabeledGamma::setValues(const QString &values) +{ + m_bri_slider->blockSignals(true); + m_con_slider->blockSignals(true); + m_gam_slider->blockSignals(true); + + QStringList gammaValues; + int bri; + int con; + int gam; + bool ok = true; + + gammaValues = values.split(':'); + bri = gammaValues.at(0).toInt(&ok); + if (ok) con = gammaValues.at(1).toInt(&ok); + if (ok) gam = gammaValues.at(2).toInt(&ok); + + if (ok) { + m_bri_slider->setValue(bri); + m_con_slider->setValue(con); + m_gam_slider->setValue(gam); + calculateGT(); + } + + m_bri_slider->blockSignals(false); + m_con_slider->blockSignals(false); + m_gam_slider->blockSignals(false); +} + + +bool LabeledGamma::getValues(int &bri, int &con, int &gam) +{ + + bri = m_bri_slider->value(); + con = m_con_slider->value(); + gam = m_gam_slider->value(); + return true; +} + +void LabeledGamma::setSize(int size) +{ + m_gam_tbl.resize(size); + for (int i=0; isetValue(0); + m_con_slider->setValue(0); + m_gam_slider->setValue(0); +} + + +void LabeledGamma::calculateGT() +{ + double gam = 100.0/m_gam_slider->value(); + double con = (200.0/(100.0 - m_con_slider->value()))-1; + double half_max = m_max_val/2.0; + double bri = (m_bri_slider->value()/half_max) * m_max_val; + double x; + + for (int i = 0; i m_max_val) x = m_max_val; + if (x < 0) x = 0; + + m_gam_tbl[i] = (int)x; + } + + m_gamma_disp->update(); + emit gammaChanged(m_bri_slider->value(), m_con_slider->value(), m_gam_slider->value()); + emit gammaTableChanged(m_gam_tbl); +} + + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_gamma.h b/libksane/libksane/widgets/labeled_gamma.h new file mode 100644 index 00000000..b3aa8d6b --- /dev/null +++ b/libksane/libksane/widgets/labeled_gamma.h @@ -0,0 +1,93 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_GAMMA_H +#define LABELED_GAMMA_H + +// Local includes +#include "labeled_slider.h" +#include "gamma_disp.h" + +/** + *@author Kåre Särs + */ + +namespace KSaneIface +{ + +/** + * A wrapper for a checkbox + */ +class LabeledGamma : public KSaneOptionWidget +{ + Q_OBJECT + +public: + + /** + * Create the checkbox. + * + * \param parent parent widget + * \param text is the text describing the checkbox. + */ + LabeledGamma(QWidget *parent, const QString& text, int elements); + ~LabeledGamma(); + + void setColor(const QColor &color); + void setSize(int size); + const QVector &gammaTablePtr() { return m_gam_tbl; } + int size() {return (int)(m_max_val+1);} + + bool getValues(int &bri, int &con, int &gam); + +public Q_SLOTS: + void setValues(int bri, int con, int gam); + void setValues(const QString &values); + +private Q_SLOTS: + void calculateGT(); + +Q_SIGNALS: + + void gammaChanged(int bri, int con, int gam); + void gammaTableChanged(const QVector &gamma_tbl); + +private: + + LabeledSlider *m_bri_slider; + LabeledSlider *m_con_slider; + LabeledSlider *m_gam_slider; + + QVector m_gam_tbl; + double m_max_val; + + GammaDisp *m_gamma_disp; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_GAMMA_H diff --git a/libksane/libksane/widgets/labeled_slider.cpp b/libksane/libksane/widgets/labeled_slider.cpp new file mode 100644 index 00000000..7a7ca7ef --- /dev/null +++ b/libksane/libksane/widgets/labeled_slider.cpp @@ -0,0 +1,141 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +// Local includes +#include "labeled_slider.h" +#include "labeled_slider.moc" + +// KDE includes +#include + +// Qt includes +#include +#include + +namespace KSaneIface +{ + +LabeledSlider::LabeledSlider(QWidget *parent, const QString& ltext, + int min, int max, int ste) +: KSaneOptionWidget(parent, ltext) +{ + m_step = ste; + if (m_step == 0) m_step = 1; + + m_slider = new QSlider(this); + m_slider->setOrientation(Qt::Horizontal); + m_slider->setMinimum(min); + m_slider->setMaximum(max); + m_slider->setSingleStep(m_step); + + m_spinb = new KIntSpinBox(this); + m_spinb->setMinimum(min); + m_spinb->setMaximum(max); + m_slider->setSingleStep(m_step); + m_spinb->setValue(max); + //m_spinb->setMinimumWidth(m_spinb->sizeHint().width()+35); + m_spinb->setAlignment(Qt::AlignRight); + m_spinb->setValue(min); + + m_spinb->setValue(min); + m_label->setBuddy(m_spinb); + + connect(m_spinb, SIGNAL(valueChanged(int)), this, SLOT(syncValues(int))); + connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(syncValues(int))); + connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(fixValue())); + + m_layout->addWidget(m_slider, 0, 2); + m_layout->addWidget(m_spinb, 0, 1); + m_layout->setColumnStretch(1, 0); + m_layout->setColumnStretch(2, 50); + +} + +LabeledSlider::~LabeledSlider() +{ +} + +void LabeledSlider::setSuffix(const KLocalizedString &text) +{ + m_spinb->setSuffix(text); +} + +void LabeledSlider::setValue(int value) +{ + if (value != m_slider->value()) m_slider->setValue(value); + else if (value != m_spinb->value()) m_spinb->setValue(value); +} + +void LabeledSlider::setRange(int min, int max) +{ + //std::cout << "min=" << min << ", max=" << max << std::endl; + m_slider->setRange(min, max); + m_spinb->setRange(min, max); +} + +void LabeledSlider::setStep(int st) +{ + m_step = st; + if (m_step == 0) m_step = 1; + m_slider->setSingleStep(m_step); + m_spinb->setSingleStep(m_step); +} + +void LabeledSlider::syncValues(int value) +{ + if (value != m_spinb->value()) m_spinb->setValue(value); + else if (value != m_slider->value()) { + //ensure that the value m_step is followed also for the m_slider + if ((value - m_slider->minimum())%m_step != 0) { + if (value > m_spinb->value()) { + m_slider->setValue(m_slider->value()+(m_step-(value - m_spinb->value()))); + } + else { + m_slider->setValue(m_slider->value()-(m_step-(m_spinb->value() - value))); + } + // this function will be reentered with the signal fom the m_slider + } + else { + m_slider->setValue(value); + } + } + else emit valueChanged(value); +} + +void LabeledSlider::fixValue() +{ + //ensure that the value m_step is followed also for the m_slider + int rest = (m_slider->value() - m_slider->minimum())%m_step; + + if (rest != 0) { + if (rest > (m_step/2)) m_slider->setValue(m_slider->value()+(m_step-rest)); + else m_slider->setValue(m_slider->value()-rest); + m_spinb->setValue(m_slider->value()); + } +} + +} // NameSpace KSaneIface diff --git a/libksane/libksane/widgets/labeled_slider.h b/libksane/libksane/widgets/labeled_slider.h new file mode 100644 index 00000000..f59c925a --- /dev/null +++ b/libksane/libksane/widgets/labeled_slider.h @@ -0,0 +1,104 @@ +/* ============================================================ + * + * This file is part of the KDE project + * + * Date : 2007-09-13 + * Description : Sane interface for KDE + * + * Copyright (C) 2007-2011 by Kare Sars + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * ============================================================ */ + +#ifndef LABELED_SLIDER_H +#define LABELED_SLIDER_H + +#include "ksane_option_widget.h" + +// Qt includes +#include + +/** + *@author Kåre Särs + */ + +class KIntSpinBox; +class KLocalizedString; + +namespace KSaneIface +{ + +/** + * A combination of a label a slider and a spinbox. + * The slider is connected to the spinbox so that they have the same value. + */ +class LabeledSlider : public KSaneOptionWidget +{ + Q_OBJECT + +public: + + /** + * Create the slider. + * + * \param parent parent widget + * \param text is the text describing the slider value. If the text + * contains a '&', a buddy for the slider will be created. + * \param min minimum slider value + * \param max maximum slider value + * \param quant is the step between values. + */ + LabeledSlider(QWidget *parent, const QString& text, + int min, int max, int st); + ~LabeledSlider(); + + int value() const { return( m_slider->value()); } + +public Q_SLOTS: + + /** Set the slider value */ + void setValue(int); + void setRange(int min, int max); + void setStep(int); + /** Set the unit */ + void setSuffix(const KLocalizedString &text); + +private Q_SLOTS: + + /** Sync the values and emit valueChanged() */ + void syncValues(int); + /** Ensure step value is followed */ + void fixValue(); + +Q_SIGNALS: + + /** + * Emit the slider value changes + */ + void valueChanged(int); + +private: + + QSlider *m_slider; + KIntSpinBox *m_spinb; + int m_step; +}; + +} // NameSpace KSaneIface + +#endif // LABELED_SLIDER_H diff --git a/skanlite/.directory b/skanlite/.directory new file mode 100644 index 00000000..f5e9f307 --- /dev/null +++ b/skanlite/.directory @@ -0,0 +1,3 @@ +[Dolphin] +Timestamp=2015,1,1,1,18,3 +Version=3 diff --git a/skanlite/CMakeLists.txt b/skanlite/CMakeLists.txt new file mode 100644 index 00000000..c6973fcc --- /dev/null +++ b/skanlite/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.6) + +project(skanlite) + + +find_package(KDE4 REQUIRED) +include(KDE4Defaults) +include_directories (${KDE4_INCLUDES}) + +find_package(KSane REQUIRED) +find_package(PNG REQUIRED) + +set(SKANLITE_VERSION_MAJOR "1") +set(SKANLITE_VERSION_MINOR "1") +set(SKANLITE_VERSION_STRING "${SKANLITE_VERSION_MAJOR}.${SKANLITE_VERSION_MINOR}") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/version.h) + + +add_subdirectory(src) + diff --git a/skanlite/src/CMakeLists.txt b/skanlite/src/CMakeLists.txt new file mode 100644 index 00000000..e08dc838 --- /dev/null +++ b/skanlite/src/CMakeLists.txt @@ -0,0 +1,14 @@ +include_directories(${KSANE_INCLUDE_DIR}) + +set(skanlite_SRCS main.cpp skanlite.cpp ImageViewer.cpp KSaneImageSaver.cpp SaveLocation.cpp) + +kde4_add_ui_files(skanlite_SRCS settings.ui SaveLocation.ui) + +kde4_add_app_icon(skanlite_SRCS "${KDE4_INSTALL_DIR}/share/icons/oxygen/*/devices/scanner.png") + +kde4_add_executable(skanlite ${skanlite_SRCS}) + +target_link_libraries(skanlite ${KDE4_KIO_LIBS} ${KSANE_LIBRARY} ${PNG_LIBRARY}) + +install(TARGETS skanlite ${INSTALL_TARGETS_DEFAULT_ARGS}) +install( PROGRAMS skanlite.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) diff --git a/skanlite/src/COPYING b/skanlite/src/COPYING new file mode 100644 index 00000000..5185fd3f --- /dev/null +++ b/skanlite/src/COPYING @@ -0,0 +1,346 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/skanlite/src/ImageViewer.cpp b/skanlite/src/ImageViewer.cpp new file mode 100644 index 00000000..868db709 --- /dev/null +++ b/skanlite/src/ImageViewer.cpp @@ -0,0 +1,138 @@ +/* ============================================================ +* Date : 2008-08-26 +* Description : Preview image viewer. +* +* Copyright (C) 2008-2012 by Kåre Särs +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#include "ImageViewer.h" +#include "ImageViewer.moc" + +#include +#include +#include +#include +#include +#include + +#include + +struct ImageViewer::Private +{ + QGraphicsScene *scene; + QImage *img; + + QAction *zoomInAction; + QAction *zoomOutAction; + QAction *zoom100Action; + QAction *zoom2FitAction; +}; + +ImageViewer::ImageViewer(QWidget *parent) : QGraphicsView(parent), d(new Private) +{ + //setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setMouseTracking(true); + + // Init the scene + d->scene = new QGraphicsScene; + setScene(d->scene); + + // create context menu + d->zoomInAction = new QAction(KIcon("zoom-in"), i18n("Zoom In"), this); + connect(d->zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn())); + + d->zoomOutAction = new QAction(KIcon("zoom-out"), i18n("Zoom Out"), this); + connect(d->zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut())); + + d->zoom100Action = new QAction(KIcon("zoom-fit-best"), i18n("Zoom to Actual size"), this); + connect(d->zoom100Action, SIGNAL(triggered()), this, SLOT(zoomActualSize())); + + d->zoom2FitAction = new QAction(KIcon("document-preview"), i18n("Zoom to Fit"), this); + connect(d->zoom2FitAction, SIGNAL(triggered()), this, SLOT(zoom2Fit())); + + addAction(d->zoomInAction); + addAction(d->zoomOutAction); + addAction(d->zoom100Action); + addAction(d->zoom2FitAction); + setContextMenuPolicy(Qt::ActionsContextMenu); +} + +// ------------------------------------------------------------------------ +ImageViewer::~ImageViewer() +{ + delete d; +} + +// ------------------------------------------------------------------------ +void ImageViewer::setQImage(QImage *img) +{ + if (img == 0) return; + + d->img = img; + d->scene->setSceneRect(0, 0, img->width(), img->height()); +} + +// ------------------------------------------------------------------------ +void ImageViewer::drawBackground(QPainter *painter, const QRectF &rect) +{ + painter->fillRect(rect, QColor(0x70, 0x70, 0x70)); + painter->drawImage(rect, *d->img, rect); +} + +// ------------------------------------------------------------------------ +void ImageViewer::zoomIn() +{ + scale(1.5, 1.5); +} + +// ------------------------------------------------------------------------ +void ImageViewer::zoomOut() +{ + scale(1.0 / 1.5, 1.0 / 1.5); +} + + +// ------------------------------------------------------------------------ +void ImageViewer::zoomActualSize() +{ + setMatrix(QMatrix()); +} + +// ------------------------------------------------------------------------ +void ImageViewer::zoom2Fit() +{ + fitInView(d->img->rect(), Qt::KeepAspectRatio); +} + +// ------------------------------------------------------------------------ +void ImageViewer::wheelEvent(QWheelEvent *e) +{ + if(e->modifiers() == Qt::ControlModifier) { + if(e->delta() > 0) { + zoomIn(); + } else { + zoomOut(); + } + } else { + QGraphicsView::wheelEvent(e); + } +} + diff --git a/skanlite/src/ImageViewer.h b/skanlite/src/ImageViewer.h new file mode 100644 index 00000000..890ca989 --- /dev/null +++ b/skanlite/src/ImageViewer.h @@ -0,0 +1,58 @@ +/* ============================================================ +* Date : 2009-08-26 +* Description : Preview image viewer. +* +* Copyright (C) 2008-2012 by Kåre Särs +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#ifndef IMAGE_VIEWER_H +#define IMAGE_VIEWER_H + +#include +#include + +class ImageViewer : public QGraphicsView +{ + Q_OBJECT + public: + ImageViewer(QWidget *parent = 0); + ~ImageViewer(); + + void setQImage(QImage *img); + + public Q_SLOTS: + void zoomIn(); + void zoomOut(); + void zoom2Fit(); + void zoomActualSize(); + + protected: + void wheelEvent(QWheelEvent *e); + void drawBackground(QPainter *painter, const QRectF &rect); + + private: + struct Private; + Private * const d; + +}; + +#endif + + diff --git a/skanlite/src/KSaneImageSaver.cpp b/skanlite/src/KSaneImageSaver.cpp new file mode 100644 index 00000000..c8729322 --- /dev/null +++ b/skanlite/src/KSaneImageSaver.cpp @@ -0,0 +1,236 @@ +/* ============================================================ +* Date : 2010-07-02 +* Description : Image saver class for libksane image data. +* +* Copyright (C) 2010-2012 by Kåre Särs +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#include "KSaneImageSaver.h" + +#include + +#include +#include + + +struct KSaneImageSaver::Private +{ + enum ImageType { + ImageTypePNG, + ImageTypeTIFF + }; + + bool m_savedOk; + QMutex m_runMutex; + KSaneImageSaver *q; + + QString m_name; + QByteArray m_data; + int m_width; + int m_height; + int m_format; + ImageType m_type; + + bool savePng(); + bool saveTiff(); +}; + +// ------------------------------------------------------------------------ +KSaneImageSaver::KSaneImageSaver(QObject *parent) : QThread(parent), d(new Private) +{ + d->q = this; +} + +// ------------------------------------------------------------------------ +KSaneImageSaver::~KSaneImageSaver() +{ + delete d; +} + +bool KSaneImageSaver::savePng(const QString &name, const QByteArray &data, int width, int height, int format) +{ + if (!d->m_runMutex.tryLock()) return false; + + d->m_name = name; + d->m_data = data; + d->m_width = width; + d->m_height = height; + d->m_format = format; + d->m_type = Private::ImageTypePNG; + + start(); + return true; +} + +bool KSaneImageSaver::savePngSync(const QString &name, const QByteArray &data, int width, int height, int format) +{ + if (!savePng(name, data, width, height, format)) { + kDebug() << "fail"; + return false; + } + wait(); + return d->m_savedOk; +} + +bool KSaneImageSaver::saveTiff(const QString &name, const QByteArray &data, int width, int height, int format) +{ + if (!d->m_runMutex.tryLock()) return false; + + d->m_name = name; + d->m_data = data; + d->m_width = width; + d->m_height = height; + d->m_format = format; + d->m_type = Private::ImageTypeTIFF; + + kDebug() << "saving Tiff images is not yet supported"; + d->m_runMutex.unlock(); + return false; +} + +bool KSaneImageSaver::saveTiffSync(const QString &name, const QByteArray &data, int width, int height, int format) +{ + if (!saveTiff(name, data, width, height, format)) { + return false; + } + wait(); + return d->m_savedOk; +} + +void KSaneImageSaver::run() +{ + if (d->m_type == Private::ImageTypeTIFF) { + d->m_savedOk = d->saveTiff(); + emit imageSaved(d->m_savedOk); + } + else { + d->m_savedOk = d->savePng(); + emit imageSaved(d->m_savedOk); + } + d->m_runMutex.unlock(); +} + +bool KSaneImageSaver::Private::saveTiff() +{ + return false; +} + +bool KSaneImageSaver::Private::savePng() +{ + FILE *file; + png_structp png_ptr; + png_infop info_ptr; + png_color_8 sig_bit; + png_bytep row_ptr; + int bytesPerPixel; + + // open the file + file = fopen(qPrintable(m_name), "wb"); + if (!file) return false; + + // create the png struct + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + fclose(file); + return false; + } + + // create the image information srtuct + info_ptr = png_create_info_struct(png_ptr); + if (!png_ptr) { + fclose(file); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return false; + } + + // initialize IO + png_init_io(png_ptr, file); + + // set the image attributes + switch ((KSaneIface::KSaneWidget::ImageFormat)m_format) + { + case KSaneIface::KSaneWidget::FormatGrayScale16: + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 16, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + sig_bit.gray = 16; + bytesPerPixel = 2; + break; + case KSaneIface::KSaneWidget::FormatRGB_16_C: + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 16, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + sig_bit.red = 16; + sig_bit.green = 16; + sig_bit.blue = 16; + bytesPerPixel = 6; + break; + default: + fclose(file); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return false; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + /* Optionally write comments into the image */ +// text_ptr[0].key = "Title"; +// text_ptr[0].text = "Mona Lisa"; +// text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; +// text_ptr[1].key = "Author"; +// text_ptr[1].text = "Leonardo DaVinci"; +// text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; +// text_ptr[2].key = "Description"; +// text_ptr[2].text = ""; +// text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; +// png_set_text(png_ptr, info_ptr, text_ptr, 2); + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + //png_set_shift(png_ptr, &sig_bit); + //png_set_packing(png_ptr); + + png_set_compression_level(png_ptr, 9); + + // This is not nice :( swap bytes in the 16 bit color.... + char tmp; + // Make sure we have a buffer size that is divisible by 2 + int dataSize = m_data.size(); + if ((dataSize % 2) > 0) dataSize--; + for (int i=0; i +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#ifndef KSaneImageSaver_h +#define KSaneImageSaver_h + +#include + +#include + +class KSaneImageSaver : public QThread +{ + Q_OBJECT + public: + KSaneImageSaver(QObject *parent = 0); + ~KSaneImageSaver(); + + bool savePng(const QString &name, const QByteArray &data, int width, int height, int format); + + bool savePngSync(const QString &name, const QByteArray &data, int width, int height, int format); + + bool saveTiff(const QString &name, const QByteArray &data, int width, int height, int format); + + bool saveTiffSync(const QString &name, const QByteArray &data, int width, int height, int format); + + Q_SIGNALS: + void imageSaved(bool success); + + protected: + void run(); + + private: + struct Private; + Private * const d; + +}; + +#endif + + diff --git a/skanlite/src/Messages.sh b/skanlite/src/Messages.sh new file mode 100755 index 00000000..e8407e2f --- /dev/null +++ b/skanlite/src/Messages.sh @@ -0,0 +1,3 @@ +$EXTRACTRC `find . -name \*.ui` >> rc.cpp +$XGETTEXT *.cpp -o $podir/skanlite.pot +rm -f rc.cpp diff --git a/skanlite/src/SaveLocation.cpp b/skanlite/src/SaveLocation.cpp new file mode 100644 index 00000000..c6e01969 --- /dev/null +++ b/skanlite/src/SaveLocation.cpp @@ -0,0 +1,65 @@ +/* ============================================================ +* Date : 2010-07-07 +* Description : Save location settings dialog. +* +* Copyright (C) 2010-2012 by Kare Sars +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#include "SaveLocation.h" +#include "SaveLocation.moc" + +#include +#include + +SaveLocation::SaveLocation(QWidget *parent) : KDialog(parent) +{ + QWidget *container = new QWidget(this); + setupUi(container); + setMainWidget(container); + connect(u_saveDirLEdit, SIGNAL(textChanged(QString)), this, SLOT(update())); + connect(u_imgPrefix, SIGNAL(textChanged(QString)), this, SLOT(update())); + connect(u_imgFormat, SIGNAL(activated(QString)), this, SLOT(update())); + connect(u_numStartFrom, SIGNAL(valueChanged(int)), this, SLOT(update())); + connect(u_getDirButton, SIGNAL(clicked()), this, SLOT(getDir())); +} + +// ------------------------------------------------------------------------ +SaveLocation::~SaveLocation() +{ +} + +// ------------------------------------------------------------------------ +void SaveLocation::update() +{ + if (sender() != u_numStartFrom) { + u_numStartFrom->setValue(1); // Reset the counter whenever the directory or the prefix is changed + } + QString name = QString("%1%2.%3").arg(u_imgPrefix->text()).arg(u_numStartFrom->value(), 4, 10, QLatin1Char('0')).arg(u_imgFormat->currentText()); + u_resultValue->setText(QFileInfo(u_saveDirLEdit->text(), name).absoluteFilePath()); +} + +// ------------------------------------------------------------------------ +void SaveLocation::getDir(void) +{ + QString newDir = KFileDialog::getExistingDirectory(u_saveDirLEdit->text()); + if (!newDir.isEmpty()) { + u_saveDirLEdit->setText(newDir); + } +} diff --git a/skanlite/src/SaveLocation.h b/skanlite/src/SaveLocation.h new file mode 100644 index 00000000..6043b4b9 --- /dev/null +++ b/skanlite/src/SaveLocation.h @@ -0,0 +1,49 @@ +/* ============================================================ + * Date : 2010-07-07 + * Description : Save location settings dialog. + * + * Copyright (C) 2008-2012 by Kåre Särs + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see + * + * ============================================================ */ + +#ifndef SAVE_LOCATION_H +#define SAVE_LOCATION_H + +#include "ui_SaveLocation.h" + +#include + +#include + +class SaveLocation : public KDialog, public Ui_SaveLocation +{ + Q_OBJECT +public: + SaveLocation(QWidget *parent = 0); + ~SaveLocation(); + +private Q_SLOTS: + void update(); + void getDir(); + +}; + +#endif + + diff --git a/skanlite/src/SaveLocation.ui b/skanlite/src/SaveLocation.ui new file mode 100644 index 00000000..b4e37de9 --- /dev/null +++ b/skanlite/src/SaveLocation.ui @@ -0,0 +1,123 @@ + + + SaveLocation + + + + 0 + 0 + 347 + 110 + + + + Save Location + + + + QFormLayout::ExpandingFieldsGrow + + + + + Save Location: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + 0 + 0 + + + + ... + + + + + + + + + Name & Format: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + ###. + + + + + + + + + + + + /home/joe/example.png + + + + + + + Example: + + + + + + + Start numbering from: + + + + + + + 1 + + + 999999 + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + +
diff --git a/skanlite/src/TODO b/skanlite/src/TODO new file mode 100644 index 00000000..4a6fcfe6 --- /dev/null +++ b/skanlite/src/TODO @@ -0,0 +1,4 @@ +-Make the final image dialog image zoomable +-Add scan profiles (settings/options) +-Start the file number scanning from a specified number or previously saved. +-Add a copy/print mode. \ No newline at end of file diff --git a/skanlite/src/main.cpp b/skanlite/src/main.cpp new file mode 100644 index 00000000..6d3df94b --- /dev/null +++ b/skanlite/src/main.cpp @@ -0,0 +1,87 @@ +/* ============================================================ +* +* Copyright (C) 2007-2012 by Kåre Särs +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ +#include +#include +#include +#include + +#include "skanlite.h" +#include "version.h" + +int main(int argc, char *argv[]) +{ + // about data + KAboutData aboutData("Skanlite", "skanlite", ki18n("Skanlite"), skanlite_version, + ki18n("This is a scanning application for KDE based on libksane."), + KAboutData::License_GPL, + ki18n("(C) 2008-2014 Kåre Särs")); + + aboutData.addAuthor(ki18n("Kåre Särs"), + ki18n("developer"), + "kare.sars@iki.fi", 0); + + aboutData.addAuthor(ki18n("Arseniy Lartsev"), + ki18n("contributor"), + 0, 0); + + aboutData.addCredit(ki18n("Gilles Caulier"), + ki18n("Importing libksane to extragear"), + 0, 0); + + aboutData.addCredit(ki18n("Anne-Marie Mahfouf"), + ki18n("Writing the user manual"), + 0, 0); + + aboutData.addCredit(ki18n("Laurent Montel"), + ki18n("Importing libksane to extragear"), + 0, 0); + + aboutData.addCredit(ki18n("Chusslove Illich"), + ki18n("Help with translations"), + 0, 0); + + aboutData.addCredit(ki18n("Albert Astals Cid"), + ki18n("Help with translations"), + 0, 0); + + aboutData.setProgramIconName("scanner"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("d ", ki18n("Sane scanner device name.")); + KCmdLineArgs::addCmdLineOptions(options); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + QString device = args->getOption("d"); + + KApplication app; + + Skanlite *skanlite = new Skanlite(device, 0); + + skanlite->show(); + + QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + + return app.exec(); +} + diff --git a/skanlite/src/settings.ui b/skanlite/src/settings.ui new file mode 100644 index 00000000..ac7842bf --- /dev/null +++ b/skanlite/src/settings.ui @@ -0,0 +1,412 @@ + + + SkanliteSettings + + + + 0 + 0 + 436 + 316 + + + + Settings + + + + + + Image saving + + + + + + Preview before saving: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + showB4Save + + + + + + + + + + + + + + Save mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + saveModeCB + + + + + + + + Open the save dialog for every image + + + + + Open the save dialog for the first image only + + + + + + + + Qt::Horizontal + + + + + + + Save Location: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + saveDirLEdit + + + + + + + + + + + 0 + 0 + + + + ... + + + + + + + Name && Format: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + imgPrefix + + + + + + + + + Image + + + + + + + ###. + + + + + + + + + + + + Specify save quality: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + setQuality + + + + + + + + + + + + + + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 6 + + + 0 + + + + + 100 + + + 85 + + + 85 + + + Qt::Horizontal + + + + + + + % + + + 100 + + + 85 + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + + General + + + + + + Set preview resolution (DPI) + + + + + + + false + + + true + + + + 50 + + + + + 75 + + + + + 100 + + + + + 150 + + + + + 300 + + + + + 600 + + + + + + + + Disable automatic selections + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Revert scanner options to default values + + + + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + + + setQuality + toggled(bool) + imgQualityFrame + setEnabled(bool) + + + 144 + 172 + + + 365 + 173 + + + + + horizontalSlider + valueChanged(int) + imgQuality + setValue(int) + + + 303 + 172 + + + 365 + 173 + + + + + imgQuality + valueChanged(int) + horizontalSlider + setValue(int) + + + 365 + 173 + + + 303 + 172 + + + + + setPreviewDPI + toggled(bool) + previewDPI + setEnabled(bool) + + + 130 + 14 + + + 176 + 14 + + + + +
diff --git a/skanlite/src/skanlite.cpp b/skanlite/src/skanlite.cpp new file mode 100644 index 00000000..c8f64367 --- /dev/null +++ b/skanlite/src/skanlite.cpp @@ -0,0 +1,546 @@ +/* ============================================================ +* +* Copyright (C) 2007-2012 by Kåre Särs +* Copyright (C) 2009 by Arseniy Lartsev +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see +* +* ============================================================ */ + +#include "skanlite.h" +#include "skanlite.moc" + +#include "KSaneImageSaver.h" +#include "SaveLocation.h" + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +Skanlite::Skanlite(const QString &device, QWidget *parent) + : KDialog(parent) +{ + setAttribute(Qt::WA_DeleteOnClose); + + setButtons(KDialog::Help | KDialog::User2 | KDialog::User1 | KDialog::Close); + + setButtonText(KDialog::User1, i18n("Settings")); + setButtonIcon(KDialog::User1, KIcon("configure")); + setButtonText(KDialog::User2, i18n("About")); + setHelp("index", "skanlite"); + + m_firstImage = true; + + m_ksanew = new KSaneIface::KSaneWidget(this); + connect(m_ksanew, SIGNAL(imageReady(QByteArray &, int, int, int, int)), + this, SLOT(imageReady(QByteArray &, int, int, int, int))); + connect(m_ksanew, SIGNAL(availableDevices(QList)), + this, SLOT(availableDevices(QList))); + connect(m_ksanew, SIGNAL(userMessage(int, QString)), + this, SLOT(alertUser(int, QString))); + connect(m_ksanew, SIGNAL(buttonPressed(QString, QString, bool)), + this, SLOT(buttonPressed(QString, QString, bool))); + + setMainWidget(m_ksanew); + + m_ksanew->initGetDeviceList(); + + // read the size here... + KConfigGroup window(KGlobal::config(), "Window"); + QSize rect = window.readEntry("Geometry", QSize(740,400)); + resize(rect); + + connect (this, SIGNAL(closeClicked()), this, SLOT(saveWindowSize())); + connect (this, SIGNAL(closeClicked()), this, SLOT(saveScannerOptions())); + connect (this, SIGNAL(user1Clicked()), this, SLOT(showSettingsDialog())); + connect (this, SIGNAL(user2Clicked()), this, SLOT(showAboutDialog())); + + // Create the settings dialog + m_settingsDialog = new KDialog(this); + m_settingsDialog->setButtons(KDialog::Ok | KDialog::Cancel); + + QWidget *settingsWidget = new QWidget(m_settingsDialog); + m_settingsUi.setupUi(settingsWidget); + m_settingsUi.revertOptions->setIcon(KIcon("edit-undo")); + m_saveLocation = new SaveLocation(this); + + // add the supported image types + m_filterList = KImageIO::mimeTypes(KImageIO::Writing); + // Put first class citizens at first place + m_filterList.removeAll("image/jpeg"); + m_filterList.removeAll("image/tiff"); + m_filterList.removeAll("image/png"); + m_filterList.insert(0, "image/png"); + m_filterList.insert(1, "image/jpeg"); + m_filterList.insert(2, "image/tiff"); + + m_filter16BitList << "image/png"; + //m_filter16BitList << "image/tiff"; + + QString mime; + QStringList type; + foreach (mime , m_filterList) { + type = KImageIO::typeForMime(mime); + if (type.size() > 0) { + m_typeList << type.first(); + } + } + m_settingsUi.imgFormat->addItems(m_typeList); + m_saveLocation->u_imgFormat->addItems(m_typeList); + + m_settingsDialog->setMainWidget(settingsWidget); + m_settingsDialog->setWindowTitle(i18n("Skanlite Settings")); + + + connect(m_settingsUi.getDirButton, SIGNAL(clicked()), this, SLOT(getDir())); + connect(m_settingsUi.revertOptions, SIGNAL(clicked()), this, SLOT(defaultScannerOptions())); + readSettings(); + + // default directory for the save dialog + m_saveLocation->u_saveDirLEdit->setText(m_settingsUi.saveDirLEdit->text()); + m_saveLocation->u_imgPrefix->setText(m_settingsUi.imgPrefix->text()); + m_saveLocation->u_imgFormat->setCurrentItem(m_settingsUi.imgFormat->currentText()); + + // open the scan device + if (m_ksanew->openDevice(device) == false) { + QString dev = m_ksanew->selectDevice(0); + if (dev.isEmpty()) { + // either no scanner was found or then cancel was pressed. + exit(0); + } + if (m_ksanew->openDevice(dev) == false) { + // could not open a scanner + KMessageBox::sorry(0, i18n("Opening the selected scanner failed.")); + exit(1); + } + else { + setWindowTitle(i18nc("@title:window %1 = scanner maker, %2 = scanner model", "%1 %2 - Skanlite", m_ksanew->make(), m_ksanew->model())); + m_deviceName = QString("%1:%2").arg(m_ksanew->make()).arg(m_ksanew->model()); + } + } + else { + setWindowTitle(i18nc("@title:window %1 = scanner device", "%1 - Skanlite", device)); + m_deviceName = device; + } + + addAction(KStandardAction::quit(qApp, SLOT(quit()), this)); + + // prepare the Show Image Dialog + m_showImgDialog = new KDialog(this); + m_showImgDialog->setButtons(KDialog::User1 | KDialog::Close); + m_showImgDialog->setButtonText(KDialog::User1, i18n("Save")); + m_showImgDialog->setButtonIcon(KDialog::User1, KIcon("document-save")); + m_showImgDialog->setDefaultButton(KDialog::User1); + m_showImgDialog->resize(640, 480); + m_showImgDialog->setMainWidget(&m_imageViewer); + connect(m_showImgDialog, SIGNAL(user1Clicked()), this, SLOT(saveImage())); + + + // prepare the save dialog + m_saveDialog = new KFileDialog(m_settingsUi.saveDirLEdit->text(), QString(), this); + m_saveDialog->setOperationMode(KFileDialog::Saving); + m_saveDialog->setMode(KFile::File); + m_saveDialog->setCaption(i18n("New Image File Name")); + + // save the default sane options for later use + m_ksanew->getOptVals(m_defaultScanOpts); + + // load saved options + loadScannerOptions(); + + m_ksanew->initGetDeviceList(); + + m_firstImage = true; +} + +//************************************************************ +void Skanlite::closeEvent(QCloseEvent *event) +{ + saveWindowSize(); + saveScannerOptions(); + event->accept(); +} + +//************************************************************ +void Skanlite::saveWindowSize() +{ + KConfigGroup window(KGlobal::config(), "Window"); + window.writeEntry("Geometry", size()); + window.sync(); +} +// Pops up message box similar to what perror() would print +//************************************************************ +static void perrorMessageBox(const QString &text) +{ + if (errno != 0) { + KMessageBox::sorry(0, i18n("%1: %2", text, QString::fromLocal8Bit(strerror(errno)))); + } + else { + KMessageBox::sorry(0, text); + } +} + +//************************************************************ +void Skanlite::readSettings(void) +{ + // enable the widgets to allow modifying + m_settingsUi.setQuality->setChecked(true); + m_settingsUi.setPreviewDPI->setChecked(true); + + // read the saved parameters + KConfigGroup saving(KGlobal::config(), "Image Saving"); + m_settingsUi.saveModeCB->setCurrentIndex(saving.readEntry("SaveMode", (int)SaveModeManual)); + if (m_settingsUi.saveModeCB->currentIndex() != SaveModeAskFirst) m_firstImage = false; + m_settingsUi.saveDirLEdit->setText(saving.readEntry("Location", QDir::homePath())); + m_settingsUi.imgPrefix->setText(saving.readEntry("NamePrefix", i18nc("prefix for auto naming", "Image-"))); + m_settingsUi.imgFormat->setCurrentItem(saving.readEntry("ImgFormat", "png")); + m_settingsUi.imgQuality->setValue(saving.readEntry("ImgQuality", 90)); + m_settingsUi.setQuality->setChecked(saving.readEntry("SetQuality", false)); + m_settingsUi.showB4Save->setChecked(saving.readEntry("ShowBeforeSave", true)); + + KConfigGroup general(KGlobal::config(), "General"); + m_settingsUi.previewDPI->setCurrentItem(general.readEntry("PreviewDPI", "100"), true); + m_settingsUi.setPreviewDPI->setChecked(general.readEntry("SetPreviewDPI", false)); + if (m_settingsUi.setPreviewDPI->isChecked()) { + m_ksanew->setPreviewResolution(m_settingsUi.previewDPI->currentText().toFloat()); + } + else { + m_ksanew->setPreviewResolution(0.0); + } + m_settingsUi.u_disableSelections->setChecked(general.readEntry("DisableAutoSelection", false)); + m_ksanew->enableAutoSelect(!m_settingsUi.u_disableSelections->isChecked()); +} + +//************************************************************ +void Skanlite::showSettingsDialog(void) +{ + readSettings(); + + // show the dialog + if (m_settingsDialog->exec()) { + // save the settings + KConfigGroup saving(KGlobal::config(), "Image Saving"); + saving.writeEntry("SaveMode", m_settingsUi.saveModeCB->currentIndex()); + saving.writeEntry("Location", m_settingsUi.saveDirLEdit->text()); + saving.writeEntry("NamePrefix", m_settingsUi.imgPrefix->text()); + saving.writeEntry("ImgFormat", m_settingsUi.imgFormat->currentText()); + saving.writeEntry("SetQuality", m_settingsUi.setQuality->isChecked()); + saving.writeEntry("ImgQuality", m_settingsUi.imgQuality->value()); + saving.writeEntry("ShowBeforeSave", m_settingsUi.showB4Save->isChecked()); + saving.sync(); + + KConfigGroup general(KGlobal::config(), "General"); + general.writeEntry("PreviewDPI", m_settingsUi.previewDPI->currentText()); + general.writeEntry("SetPreviewDPI", m_settingsUi.setPreviewDPI->isChecked()); + general.writeEntry("DisableAutoSelection", m_settingsUi.u_disableSelections->isChecked()); + general.sync(); + + // the previewDPI has to be set here + if (m_settingsUi.setPreviewDPI->isChecked()) { + m_ksanew->setPreviewResolution(m_settingsUi.previewDPI->currentText().toFloat()); + } + else { + // 0.0 means default value. + m_ksanew->setPreviewResolution(0.0); + } + m_ksanew->enableAutoSelect(!m_settingsUi.u_disableSelections->isChecked()); + + // pressing OK in the settings dialog means use those settings. + m_saveLocation->u_saveDirLEdit->setText(m_settingsUi.saveDirLEdit->text()); + m_saveLocation->u_imgPrefix->setText(m_settingsUi.imgPrefix->text()); + m_saveLocation->u_imgFormat->setCurrentItem(m_settingsUi.imgFormat->currentText()); + + m_firstImage = true; + } + else { + //Forget Changes + readSettings(); + } +} + + +//************************************************************ +void Skanlite::imageReady(QByteArray &data, int w, int h, int bpl, int f) +{ + // save the image data + m_data = data; + m_width = w; + m_height = h; + m_bytesPerLine = bpl; + m_format = f; + + if (m_settingsUi.showB4Save->isChecked() == true) { + /* copy the image data into m_img and show it*/ + m_img = m_ksanew->toQImageSilent(data, w, h, bpl, (KSaneIface::KSaneWidget::ImageFormat)f); + m_imageViewer.setQImage(&m_img); + m_imageViewer.zoom2Fit(); + m_showImgDialog->setDefaultButton(KDialog::User1); + m_showImgDialog->exec(); + // save has been done as a result of save or then we got cancel + } + else { + m_img = QImage(); // clear the image to ensure we save the correct one. + saveImage(); + } +} + +//************************************************************ +void Skanlite::saveImage() +{ + // ask the first time if we are in "ask on first" mode + if ((m_settingsUi.saveModeCB->currentIndex() == SaveModeAskFirst) && m_firstImage) { + if (m_saveLocation->exec() != KFileDialog::Accepted) return; + m_firstImage = false; + } + + QString dir = m_saveLocation->u_saveDirLEdit->text(); + QString prefix = m_saveLocation->u_imgPrefix->text(); + QString type = m_saveLocation->u_imgFormat->currentText().toLower(); + int fileNumber = m_saveLocation->u_numStartFrom->value(); + QStringList filterList = m_filterList; + if ((m_format==KSaneIface::KSaneWidget::FormatRGB_16_C) || + (m_format==KSaneIface::KSaneWidget::FormatGrayScale16)) + { + filterList = m_filter16BitList; + if (type != "png") { + type = "png"; + KMessageBox::information(this, i18n("The image will be saved in the PNG format, as Skanlite only supports saving 16 bit color images in the PNG format.")); + } + } + + + // find next available file name for name suggestion + KUrl fileUrl; + QString fname; + for (int i=fileNumber; i<=m_saveLocation->u_numStartFrom->maximum(); ++i) { + fname = QString("%1%2.%3") + .arg(prefix) + .arg(i, 4, 10, QChar('0')) + .arg(type); + + fileUrl = KUrl(QString("%1/%2").arg(dir).arg(fname)); + if (fileUrl.isLocalFile()) { + if (!QFileInfo(fileUrl.toLocalFile()).exists()) { + break; + } + } + else { + if (!KIO::NetAccess::exists(fileUrl, true, this)) { + break; + } + } + } + + if (m_settingsUi.saveModeCB->currentIndex() == SaveModeManual) { + // ask for a filename if requested. + m_saveDialog->setSelection(fileUrl.url()); + m_saveDialog->setMimeFilter(filterList, "image/"+type); + + do { + if (m_saveDialog->exec() != KFileDialog::Accepted) return; + + fileUrl = m_saveDialog->selectedUrl(); + //kDebug() << "-----Save-----" << fname; + + if (KIO::NetAccess::exists(fileUrl, true, this)) { + if (KMessageBox::warningContinueCancel(this, + i18n("Do you want to overwrite \"%1\"?", fileUrl.fileName()), + QString(), + KGuiItem(i18n("Overwrite")), + KStandardGuiItem::cancel(), + QString("editorWindowSaveOverwrite") + ) == KMessageBox::Continue) + { + break; + } + } + else { + break; + } + } while (1); + } + + m_firstImage = false; + + // Get the quality + int quality = -1; + if (m_settingsUi.setQuality->isChecked()) { + quality = m_settingsUi.imgQuality->value(); + } + + QFileInfo fileInfo(fileUrl.pathOrUrl()); + + //kDebug() << "suffix" << fileInfo.suffix() << "localFile" << fileUrl.pathOrUrl(); + fname = fileUrl.pathOrUrl(); + KTemporaryFile tmp; + if (!fileUrl.isLocalFile()) { + tmp.setSuffix('.'+fileInfo.suffix()); + tmp.open(); + fname = tmp.fileName(); + tmp.close(); // we just want the filename + } + + // Save + if ((m_format==KSaneIface::KSaneWidget::FormatRGB_16_C) || + (m_format==KSaneIface::KSaneWidget::FormatGrayScale16)) + { + KSaneImageSaver saver; + if (saver.savePngSync(fname, m_data, m_width, m_height, m_format)) { + m_showImgDialog->close(); // closing the window if it is closed should not be a problem. + } + else { + perrorMessageBox(i18n("Failed to save image")); + } + } + else { + // create the image if needed. + if (m_img.width() < 1) { + m_img = m_ksanew->toQImage(m_data, m_width, m_height, m_bytesPerLine, (KSaneIface::KSaneWidget::ImageFormat)m_format); + } + if (m_img.save(fname, 0, quality)) { + m_showImgDialog->close(); // calling close() on a closed window does nothing. + } + else { + perrorMessageBox(i18n("Failed to save image")); + } + } + + if (!fileUrl.isLocalFile()) { + if (!KIO::NetAccess::upload( fname, fileUrl, this )) { + KMessageBox::sorry(0, i18n("Failed to upload image")); + } + } + + // Save the file base name without number + QString baseName = fileInfo.completeBaseName(); + while ((baseName.size() > 1) && (baseName[baseName.size()-1].isNumber())) { + baseName.remove(baseName.size()-1, 1); + } + m_saveLocation->u_imgPrefix->setText(baseName); + + // Save the number + QString fileNumStr = fileInfo.completeBaseName(); + fileNumStr.remove(baseName); + fileNumber = fileNumStr.toInt(); + if (fileNumber) { + m_saveLocation->u_numStartFrom->setValue(fileNumber+1); + } + + if (m_settingsUi.saveModeCB->currentIndex() == SaveModeManual) { + // Save last used dir, prefix and suffix. + m_saveLocation->u_saveDirLEdit->setText(fileUrl.upUrl().pathOrUrl()); + m_saveLocation->u_imgFormat->setCurrentItem(fileInfo.suffix()); + } +} + + +//************************************************************ +void Skanlite::getDir(void) +{ + QString dir = KFileDialog::getExistingDirectory(KUrl(m_settingsUi.saveDirLEdit->text())); + if (!dir.isEmpty()) { + m_settingsUi.saveDirLEdit->setText(dir); + } +} + +//************************************************************ +void Skanlite::showAboutDialog(void) +{ + KAboutApplicationDialog(KGlobal::mainComponent().aboutData(), 0).exec(); +} + +//************************************************************ +void Skanlite::saveScannerOptions() +{ + KConfigGroup saving(KGlobal::config(), "Image Saving"); + saving.writeEntry("NumberStartsFrom", m_saveLocation->u_numStartFrom->value()); + + if (!m_ksanew) return; + + KConfigGroup options(KGlobal::config(), QString("Options For %1").arg(m_deviceName)); + QMap opts; + m_ksanew->getOptVals(opts); + QMap::const_iterator it = opts.constBegin(); + while (it != opts.constEnd()) { + options.writeEntry(it.key(), it.value()); + ++it; + } + options.sync(); +} + +//************************************************************ +void Skanlite::defaultScannerOptions() +{ + if (!m_ksanew) return; + + m_ksanew->setOptVals(m_defaultScanOpts); +} + +//************************************************************ +void Skanlite::loadScannerOptions() +{ + KConfigGroup saving(KGlobal::config(), "Image Saving"); + m_saveLocation->u_numStartFrom->setValue(saving.readEntry("NumberStartsFrom", 1)); + + if (!m_ksanew) return; + + KConfigGroup scannerOptions(KGlobal::config(), QString("Options For %1").arg(m_deviceName)); + m_ksanew->setOptVals(scannerOptions.entryMap()); +} + +//************************************************************ +void Skanlite::availableDevices(const QList &deviceList) +{ + for (int i=0; i + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see + * + * ============================================================ */ + +#ifndef Skanlite_h +#define Skanlite_h + +#include +#include + +#include "ui_settings.h" +#include "ImageViewer.h" + +class KFileDialog; +class SaveLocation; + +using namespace KSaneIface; + +class Skanlite : public KDialog +{ + Q_OBJECT + + public: + explicit Skanlite(const QString& device, QWidget *parent = 0); + + private: + // Order of items in save mode combo-box + enum SaveMode { + SaveModeManual = 0, + SaveModeAskFirst = 1, + }; + + void readSettings(); + void doSaveImage(bool askFilename = true); + void loadScannerOptions(); + + private Q_SLOTS: + void showSettingsDialog(); + void getDir(); + void imageReady(QByteArray &, int, int, int, int); + void saveImage(); + void showAboutDialog(); + void saveWindowSize(); + + void saveScannerOptions(); + void defaultScannerOptions(); + + void availableDevices(const QList &deviceList); + + void alertUser(int type, const QString &strStatus); + void buttonPressed(const QString &optionName, const QString &optionLabel, bool pressed); + + protected: + void closeEvent(QCloseEvent *event); + + private: + KSaneWidget *m_ksanew; + Ui::SkanliteSettings m_settingsUi; + KDialog *m_settingsDialog; + KDialog *m_showImgDialog; + KFileDialog *m_saveDialog; + SaveLocation *m_saveLocation; + QString m_deviceName; + QMap m_defaultScanOpts; + QImage m_img; + QByteArray m_data; + int m_width; + int m_height; + int m_bytesPerLine; + int m_format; + + ImageViewer m_imageViewer; + QStringList m_filterList; + QStringList m_filter16BitList; + QStringList m_typeList; + bool m_firstImage; +}; + + +#endif + diff --git a/skanlite/src/version.h.cmake b/skanlite/src/version.h.cmake new file mode 100644 index 00000000..3694480d --- /dev/null +++ b/skanlite/src/version.h.cmake @@ -0,0 +1,24 @@ +/* ============================================================ + * + * This file is a part of the Skanlite project + * + * Copyright (C) 2012 by Kåre Särs + * + * 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, 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. + * + * ============================================================ */ + +#ifndef SKANLITE_VERSION_H +#define SKANLITE_VERSION_H + +static const char skanlite_version[] = "${SKANLITE_VERSION_STRING}"; + +#endif