summaryrefslogtreecommitdiffstats
path: root/kooka
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /kooka
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kooka')
-rw-r--r--kooka/AUTHORS2
-rw-r--r--kooka/CHANGES158
-rw-r--r--kooka/COPYING339
-rw-r--r--kooka/CREDITS4
-rw-r--r--kooka/INSTALL181
-rw-r--r--kooka/Makefile.am46
-rw-r--r--kooka/README66
-rw-r--r--kooka/README.KADMOS73
-rw-r--r--kooka/TODO26
-rw-r--r--kooka/WARNING28
-rw-r--r--kooka/configure.in.in33
-rw-r--r--kooka/dwmenuaction.cpp72
-rw-r--r--kooka/dwmenuaction.h62
-rw-r--r--kooka/formathelp.h43
-rw-r--r--kooka/imageselectline.cpp105
-rw-r--r--kooka/imageselectline.h66
-rw-r--r--kooka/img_saver.cpp897
-rw-r--r--kooka/img_saver.h208
-rw-r--r--kooka/imgnamecombo.cpp93
-rw-r--r--kooka/imgnamecombo.h57
-rw-r--r--kooka/imgprintdialog.cpp302
-rw-r--r--kooka/imgprintdialog.h89
-rw-r--r--kooka/kadmosocr.cpp432
-rw-r--r--kooka/kadmosocr.h143
-rw-r--r--kooka/kocrbase.cpp368
-rw-r--r--kooka/kocrbase.h158
-rw-r--r--kooka/kocrgocr.cpp201
-rw-r--r--kooka/kocrgocr.h86
-rw-r--r--kooka/kocrkadmos.cpp521
-rw-r--r--kooka/kocrkadmos.h128
-rw-r--r--kooka/kocrocrad.cpp263
-rw-r--r--kooka/kocrocrad.h106
-rw-r--r--kooka/kooka.cpp465
-rw-r--r--kooka/kooka.desktop78
-rw-r--r--kooka/kooka.h141
-rw-r--r--kooka/kookaiface.h13
-rw-r--r--kooka/kookaimage.cpp413
-rw-r--r--kooka/kookaimage.h170
-rw-r--r--kooka/kookaimagemeta.cpp51
-rw-r--r--kooka/kookaimagemeta.h54
-rw-r--r--kooka/kookapref.cpp547
-rw-r--r--kooka/kookapref.h100
-rw-r--r--kooka/kookaprint.cpp410
-rw-r--r--kooka/kookaprint.h95
-rw-r--r--kooka/kookarc121
-rw-r--r--kooka/kookaui.rc62
-rw-r--r--kooka/kookaview.cpp1083
-rw-r--r--kooka/kookaview.h241
-rw-r--r--kooka/ksaneocr.cpp1493
-rw-r--r--kooka/ksaneocr.h285
-rw-r--r--kooka/main.cpp121
-rw-r--r--kooka/ocrresedit.cpp148
-rw-r--r--kooka/ocrresedit.h65
-rw-r--r--kooka/ocrword.cpp157
-rw-r--r--kooka/ocrword.h111
-rw-r--r--kooka/pics/Makefile.am8
-rw-r--r--kooka/pics/gocr.pngbin0 -> 5824 bytes
-rw-r--r--kooka/pics/lockzoom.pngbin0 -> 1185 bytes
-rw-r--r--kooka/pics/mirror-both.pngbin0 -> 471 bytes
-rw-r--r--kooka/pics/mirror-horiz.pngbin0 -> 452 bytes
-rw-r--r--kooka/pics/mirror-vert.pngbin0 -> 480 bytes
-rw-r--r--kooka/pics/newfromselect.pngbin0 -> 287 bytes
-rw-r--r--kooka/pics/ocr-select.pngbin0 -> 899 bytes
-rw-r--r--kooka/pics/ocr.pngbin0 -> 950 bytes
-rw-r--r--kooka/pics/ocrad.pngbin0 -> 244 bytes
-rw-r--r--kooka/pics/scaleorig.pngbin0 -> 656 bytes
-rw-r--r--kooka/pics/scaletoheight.pngbin0 -> 591 bytes
-rw-r--r--kooka/pics/scaletowidth.pngbin0 -> 590 bytes
-rw-r--r--kooka/pics/thumbviewtile.pngbin0 -> 16383 bytes
-rw-r--r--kooka/resource.h94
-rw-r--r--kooka/scanpackager.cpp1261
-rw-r--r--kooka/scanpackager.h167
-rw-r--r--kooka/thumbview.cpp494
-rw-r--r--kooka/thumbview.h153
-rw-r--r--kooka/thumbviewitem.cpp49
-rw-r--r--kooka/thumbviewitem.h60
-rw-r--r--kooka/version.h4
77 files changed, 14070 insertions, 0 deletions
diff --git a/kooka/AUTHORS b/kooka/AUTHORS
new file mode 100644
index 00000000..41f6d7f2
--- /dev/null
+++ b/kooka/AUTHORS
@@ -0,0 +1,2 @@
+Ivan Shvedunov <ivan_iv@rf-hp.npi.msu.su>
+Klaas Freitag <freitag@SuSE.de>
diff --git a/kooka/CHANGES b/kooka/CHANGES
new file mode 100644
index 00000000..0b384de6
--- /dev/null
+++ b/kooka/CHANGES
@@ -0,0 +1,158 @@
+-> Nov. 2000, Klaas Freitag <freitag@suse.de>:
+initial version
+
+- December 2000, Klaas Freitag <freitag@suse.de>:
+
+Added support for calling the external ocr program gocr of Joerg
+Schulenburg and friends. See http://jocr.sourceforge.net for
+details. Mind that still everything is under construction, even if
+there could be some interesting screen hots around.
+
+OCR works best with smaller parts of text scanned black-and-white
+scanned with about 150 dpi.
+
+-> Released version 0.2 on kde.org
+
+- December 2000, Klaas Freitag <freitag@suse.de>:
+
+* Reworked the ocr integration: Nice start- and finish-dialog,
+ animated status image, opening a text editor with the result text
+ via mime mechanism of KDE (KRun). OCR-Parameter get stored via KConfig.
+ OCR may be performed on the entire image or the selection.
+
+* Reworked the save assistant: New layout and fully KDE2-Compliant.
+ Still no new Image format help texts.
+
+* Reworked the startup dialog: Allows to select the scan device from a
+ list of available devices, possible to set the startup scan device
+ 'forever'.
+
+* Resizing of the scan parameters. The scan parameters shell should
+ take as much as space as it needs. It is not longer fix sized now.
+
+* Mirroring in three kinds of the displayed image with toolbar and menubar
+ entries. That needed that the packager is able to handle changes on already
+ saved images.
+
+* Creation of new images from the selection on the image canvas.
+
+- Jan 2001, Klaas Freitag <freitag@suse.de>:
+
+* Rotating of images.
+
+* Opening images in a kde graphic app.
+
+* Proper error messages if a changed image cant be saved.
+
+* drag and drop support: Pull an image from konqueror on the scanpackager !
+ The image wil be importet.
+
+* print support (basic)
+
+* basic configuration support
+
+ ... and losts of other, small bug fixes, unfortunately not mentionend very
+ well here. Sorry for that, I will try to do better.
+
+/* ================================================================================ */
+
+-> Released version 0.3 in kdegraphics/kooka for KDE 2.2
+The released version does actually not have too many new
+
+- July 2001, Klaas Freitag <freitag@suse.de>
+
+* fixed the img_saver-bug that the 'Do not ask again' is not honored.
+ Now it should be, if it is checked, the format-Dialog will not be
+ displayed again.
+
+* added a new section Image saver to the properties dialog
+
+* some changes to the image saver to display the image type (Lineart etc. )
+
+* bugfixes in the image Saver
+
+/* ================================================================================ */
+Nov 2001:
+Added a combo box below kooka's gallery widget. Since the gallery and the
+the preview window are in a tabwidget together, user complained that they
+do not see the directory they are scanning to while working on the preview
+page. The combobox shows the currently selected directory and is always
+visible. The user can use the combo to change the target dir without leaving
+the preview page.
+
+Nov 2001:
+Replaced the old ScanPackager object by a new one based on the new KFileTreeView
+Widget in kdelibs/kfile. Hopefully soon full KURL support and more than one image
+repository.
+
+Nov 2001:
+Moved preview image to a hidden directory under $KDEHOME/share/apps/ScanImages/.previews
+That makes the preview images invisible in the Packager.
+
+/* ================================================================================ */
+
+many bugfixes for KDE 3.0 -> Released Kooka 0.35 for KDE 3.0
+
+Released Kooka 0.36 for KDE 3.0.1
+
+Mai 2002:
+ Added Thumbnail View with Preference Dialog => Kooka Release 0.37
+ Completed About dialog and added the Webpage http://kooka.kde.org
+
+/* ================================================================================ */
+
+For Kooka 0.38: Introduced KDockWidgets to make the GUI configurable to everybodies
+needs.
+
+/* ================================================================================ */
+
+For Kooka 0.39:
+
+* Fixed problem with gocr: gocr always resulted in (PICTURE) - fixed
+ it by changing the save format for images to gocr. This bug happens
+ only with gocr 0.3.5 (and probably higher).
+
+* Renaming images inline reimplemented again.
+
+* exported Gallery Actions to appear in the menu bar again.
+
+* added a progress bar and bugfixes to the thumbview
+
+* added halftoning to the scanservice and thus kooka
+
+* fixed bugs in the resolving of dependencies of scanner parameters.
+
+/* ================================================================================ */
+
+For Kooka 0.40:
+
+* Added Kadmos-Check to configure.in.in
+
+* Changed the Mainwindow to be KParts-Mainwindow,neccessary for using Parts in Kooka
+
+* OCR: Code massive reorganised. More ability to use different ocr engines.
+
+* OCR: Preparation to use Kadmos OCR engine.
+
+* OCR: Result not longer in a separat dialog, but in a editor part.
+
+* Scanpackager uses KookaImage more consequently. That provides meta data where needed
+
+* Improved image viewer from libkscan: Holds zoom settings over images
+
+* image information in status bar.
+
+/* ================================================================================ */
+
+For Kooka 0.41:
+
+* Added support for ocrad OCR software.
+
+* Added image printing tab to the tab dialog, good printing support.
+
+* fixed some bugs with OCR result image handling.
+
+* libkscan: Fixed a cast bug with scan source selection
+
+* Improved support for tiff images, handle images with different x- and y resolution
+ correctly.
diff --git a/kooka/COPYING b/kooka/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/kooka/COPYING
@@ -0,0 +1,339 @@
+ 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
+
+ Appendix: 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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/kooka/CREDITS b/kooka/CREDITS
new file mode 100644
index 00000000..cbb0bf8b
--- /dev/null
+++ b/kooka/CREDITS
@@ -0,0 +1,4 @@
+Kooka and KScan has been derived from the the 1997 work of Ivan
+Shvedunov <ivan_iv@rf-hp.npi.msu.su>, his homepage can be found at
+http://rf-hp.npi.msu.su.
+
diff --git a/kooka/INSTALL b/kooka/INSTALL
new file mode 100644
index 00000000..28fadaa7
--- /dev/null
+++ b/kooka/INSTALL
@@ -0,0 +1,181 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kooka/Makefile.am b/kooka/Makefile.am
new file mode 100644
index 00000000..6fec098e
--- /dev/null
+++ b/kooka/Makefile.am
@@ -0,0 +1,46 @@
+## Makefile.am for kooka
+
+SUBDIRS = pics
+
+bin_PROGRAMS = kooka
+METASOURCES = AUTO
+
+kooka_SOURCES = main.cpp kooka.cpp kookaview.cpp kookapref.cpp \
+ img_saver.cpp ksaneocr.cpp \
+ kookaimage.cpp kookaimagemeta.cpp scanpackager.cpp \
+ imgnamecombo.cpp imageselectline.cpp \
+ thumbview.cpp thumbviewitem.cpp \
+ dwmenuaction.cpp kocrbase.cpp \
+ kocrgocr.cpp kocrkadmos.cpp kadmosocr.cpp ocrword.cpp \
+ ocrresedit.cpp kookaprint.cpp imgprintdialog.cpp \
+ kocrocrad.cpp
+# pagesetup.cpp
+
+kooka_LDADD = $(LIB_KFILE) -lkdeprint -lktexteditor $(LIBTIFF) $(top_builddir)/libkscan/libkscan.la $(KADMOS_LIB) $(LIB_KSPELL)
+kooka_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+INCLUDES = -I$(top_srcdir)/libkscan $(all_includes) $(LIBSANE_INCLUDES) $(KADMOS_INC)
+
+noinst_HEADERS = \
+kookaview.h scanpackager.h \
+img_saver.h ksaneocr.h \
+formathelp.h kooka.h \
+kookaiface.h thumbview.h thumbviewitem.h \
+kookapref.h resource.h \
+imgnamecombo.h imageselectline.h kookaimage.h kookaimagemeta.h \
+kocrbase.h kocrgocr.h kocrkadmos.h \
+kadmosocr.h ocrword.h ocrresedit.h kookaprint.h imgprintdialog.h \
+kocrocrad.h
+
+# pagesetup.h
+
+appdatadir = $(kde_datadir)/kooka
+appdata_DATA = kookaui.rc
+
+kde_conf_DATA = kookarc
+
+xdg_apps_DATA = kooka.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kooka.pot
+
diff --git a/kooka/README b/kooka/README
new file mode 100644
index 00000000..8ae6fa54
--- /dev/null
+++ b/kooka/README
@@ -0,0 +1,66 @@
+Kooka
+=====
+
+Kooka is a raster image scan program for the KDE system.
+
+ PLEASE READ THE FILE "WARNING" FIRST !
+
+It uses the SANE-lib (http://www.sane-project.org/) and the the
+KScan-library which is a KDE module for scanner access.
+
+KScan and Kooka are under construction. Don't expect everything to work
+fine. If you want to help, please send patches to freitag@suse.de.
+
+Features:
+=========
+
+Kooka's main features are:
+
+Scanner Support using SANE:
+- Scanner support using SANE. Kooka _DOES_NOT_ support all features that SANE
+ and its backends offer. It takes a small subset of the available options.
+- Kooka offers a GUI to change the most important scanner options like resolution,
+ mode, threshold etc. These options are generated on the fly, depending on the
+ scanner capabilities.
+- Kooka offers a preview-function and the user can select the scan area interactively
+ or automatically.
+
+Image Storage:
+- Kooka provides an assistant to save your acquired images.
+- Filenames are generated automatically to support multiple scans.
+- Kooka manages the scanned images in a tree view where the user can delete and
+ export images.
+
+Image Manipulation:
+- Kooka provides basic image manipulation functions like rotation, mirroring.
+- Cut images to fit size.
+
+Image Viewing:
+- Scanned images can be viewed by clicking them in the tree view.
+- The viewer has a zoom function.
+
+OCR:
+- Kooka supports Joerg Schulenburg's gocr, an open source program
+ for optical character recognition (OCR). Kooka starts the OCR program
+ and displays its output. Best results with bw-images scanned with ~150 DPI
+- Support for the commercial OCR/ICR package KADMOS of the reRecognition
+ GmbH Kreuzlingen. Please read README.KADMOS for more information.
+
+Problems:
+=========
+
+* Kooka does not yet support all options SANE offers. That will
+improve in the future. However, I don't know if it makes sense to
+support all, even not very common options, some scanners offer. Lets
+see what is necessary and makes sense for the purpose of Kooka.
+
+* Kooka does not yet have a strategy for very large images :(. It uses
+the Qt QImage/QPixmap as is. On some displays, that causes problems.
+
+* Automatic document feeder (ADF) support is not yet working correctly.
+
+----------------------------------------------------------------------
+Klaas Freitag <freitag@suse.de>
+
+$Id$
+
diff --git a/kooka/README.KADMOS b/kooka/README.KADMOS
new file mode 100644
index 00000000..a6242155
--- /dev/null
+++ b/kooka/README.KADMOS
@@ -0,0 +1,73 @@
+Kooka and KADMOS integration
+============================
+
+This file describes how to make Kooka working with the KADMOS OCR/ICR
+engine.
+
+KAMDOS is commercial OCR/ICR software component of the company
+
+ reRecognition GmbH
+ Hafenstr. 50B
+ 8280 Kreuzlingen
+ Switzerland
+ Tel.: +41 71 6780000
+ Fax: +41 71 6780099
+ www.reRecognition.com
+
+and Kooka can be build using the linux version of the component in
+order to achive very good ocr results.
+
+Please contact re Recognition directly if you like to obtain or test
+KADMOS. Note that if you are linking against KADMOS, you loose the
+permission to use the GPL Qt version, so you need a commercial Qt
+version as well.
+
+Configuration
+-------------
+
+As Kooka does not require KADMOS, it is neccessary to configure
+Kooka to use the KADMOS library. This could be done by calling the
+configure script of Kooka's source distribution with following
+parameter:
+./configure --with-kadmos-dir=/where/kadmos.h/resides/
+
+The configure script tries to locate the file kadmos.h in the
+directory that was specified. The KADMOS library is expected in the
+same directory. Build the source after configuring with KADMOS. Kooka
+enables the code to work with KADMOS in the source and links the
+library.
+
+Installation
+------------
+
+KADMOS is linked statically and thus there is no need for special
+installation of the KADMOS library.
+
+Installation of the Classifier Files:
+
+KADMOS needs classifier files for the ocr process which come with
+the KADMOS developer's toolkit. The classifier files need to be installed
+in the KDE application data directory for Kooka in a subdirectory named
+classifiers. If your KDE installation goes to /opt/kde3/, this is for
+example /opt/kde3/share/apps/kooka/classifiers. Kooka picks the
+available classifiers up automatically.
+
+The classifiers are named in the following way:
+
+[fontkind][country/region].rec,
+where fontkinds are
+ttf -> machine print font
+hand -> handprint (isolated)
+norm -> OCR norm font
+
+
+For example the following classifier names are used:
+
+ttfus.rec US machineprint classifiers
+handus.rec US handwriting classifiers
+norm.rec Special OCR character sets, not localized
+
+
+----------------------------------------------------------------------
+Klaas Freitag <freitag@suse.de>
+$Id$
diff --git a/kooka/TODO b/kooka/TODO
new file mode 100644
index 00000000..ce5f3967
--- /dev/null
+++ b/kooka/TODO
@@ -0,0 +1,26 @@
+To be continued:
+
+Object ScanParams:
+- Resizing. On startup, the object comes up in a nearly fixed size, suiting the
+ mustek-backend very well ;) - thats the one I use at home. The cool solution
+ would be if the object 'knows' and tells what size (especially height) it wants
+ to have.
+
+ -> This should be done now. Please check, if it works for other than mustek
+ backends.
+
+Startup:
+
+- Changing the 'Dont ask me on startup'-decision. If the user checks the button
+ in the startup dialog never to ask which scan device to use, it is not possible
+ to revert this decision. Need a page in the Preferences dialog.
+
+OCR:
+
+- The ocr result window does not appear properly on very large result images
+ provided by gocr. Kooka should resize the result image to a reasonable size.
+
+Scan Packager:
+
+- The scan packager needs major rework. Enhancements like metadata in XML etc
+ should be included.
diff --git a/kooka/WARNING b/kooka/WARNING
new file mode 100644
index 00000000..bee996d5
--- /dev/null
+++ b/kooka/WARNING
@@ -0,0 +1,28 @@
+
+Scanning with Kooka and KScan
+=============================
+
+Kooka and KScan use the SANE library to attach to the scanner
+hardware. It cannot be avoided by any library that a program sends
+commands to the scanner which can damage it. Especially very cheap
+scanners sometimes do not have a hardware protection against driving
+the bed to far, which can cause terrible noise and damage :-(
+
+That is why you should be warned running Kooka or the KDE scanservice
+the first time. Even if there were no reportings that something bad
+happens to any scanner models using Kooka yet, but it can not be
+garanteed.
+
+Starting to scan the first time, be sure to sit next to your scanner
+having your hand on the power-off switch. Switch off immediately if
+you hear unexpected noises or if something strange happens.
+
+If you find errors, please dont ask the SANE-people without having
+made sure that your error is _really_ a SANE error. Most probably, you
+found an KScan or Kooka-Error, which should be reported at
+http://bugs.kde.org
+
+
+- Klaas Freitag <freitag@suse.de>
+
+$Id$
diff --git a/kooka/configure.in.in b/kooka/configure.in.in
new file mode 100644
index 00000000..df590f5d
--- /dev/null
+++ b/kooka/configure.in.in
@@ -0,0 +1,33 @@
+dnl AC_SEARCH_LIBS(pgm2asc,Pgm2asc)
+dnl AC_CHECK_LIB(Pgm2asc,pgm2asc)
+dnl should define HAVE_LIBPGM2ASC if available
+
+AC_ARG_WITH([kadmos],
+ [AC_HELP_STRING([--with-kadmos],
+ [Enable the kadmos OCR engine @<:@default=check@:>@])],
+ [], with_kadmos=check)
+
+AC_ARG_WITH([kadmos-dir],
+ AC_HELP_STRING([--with-kadmos-dir],
+ [sets the path to the kadmos engine @<:@default=/usr/local@:>@]),
+ [ac_kadmos_value=$withval], [ac_kadmos_value=/usr/local])
+
+KADMOS_INC=
+KADMOS_LIB=
+
+if test "x$with_kadmos" != xno; then
+ if test -r "$ac_kadmos_value/kadmos.h"; then
+ KADMOS_INC="-I$ac_kadmos_value"
+ KADMOS_LIB="$ac_kadmos_value/librep.a"
+ AC_DEFINE_UNQUOTED(HAVE_KADMOS, 1, [Defines if your system has the kadmos libraries])
+ else
+ AC_MSG_WARN([couldn't find kadmos engine header file under $ac_kadmos_value/kadmos.h])
+ fi
+
+ if test "x$with_kadmos" != xcheck && test -z "$KADMOS_LIB"; then
+ AC_MSG_ERROR([--with-kadmos was given, but test for kadmos failed])
+ fi
+fi
+
+AC_SUBST(KADMOS_LIB)
+AC_SUBST(KADMOS_INC)
diff --git a/kooka/dwmenuaction.cpp b/kooka/dwmenuaction.cpp
new file mode 100644
index 00000000..abe57f23
--- /dev/null
+++ b/kooka/dwmenuaction.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ dwmenuaction.cpp - dockwidget visibility switches to actions
+ -------------------
+ begin : 16.07.2002
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ Based on code from the from Joseph Wenninger (kate project)
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "dwmenuaction.h"
+#include "dwmenuaction.moc"
+//-------------------------------------
+
+dwMenuAction::dwMenuAction( const QString& text, const KShortcut& cut,
+ KDockWidget *dw,QObject* parent,
+ KDockMainWindow *mw, const char* name )
+ :KToggleAction(text,cut,parent,name),m_dw(dw),m_mw(mw)
+{
+ connect(this,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool)));
+ connect(m_dw->dockManager(),SIGNAL(change()),this,SLOT(anDWChanged()));
+ connect(m_dw,SIGNAL(destroyed()),this,SLOT(slotWidgetDestroyed()));
+ setChecked(m_dw->mayBeHide());
+}
+
+
+dwMenuAction::~dwMenuAction(){;}
+
+void dwMenuAction::anDWChanged()
+{
+ if (isChecked() && m_dw->mayBeShow()) setChecked(false);
+ else if ((!isChecked()) && m_dw->mayBeHide()) setChecked(true);
+}
+
+
+void dwMenuAction::slotToggled(bool t)
+{
+
+ if ((!t) && m_dw->mayBeHide() ) m_dw->undock();
+ else
+ if ( t && m_dw->mayBeShow() ) m_mw->makeDockVisible(m_dw);
+
+}
+
+
+void dwMenuAction::slotWidgetDestroyed()
+{
+ unplugAll();
+ deleteLater();
+}
+
+
+/* END */
diff --git a/kooka/dwmenuaction.h b/kooka/dwmenuaction.h
new file mode 100644
index 00000000..9b1698ed
--- /dev/null
+++ b/kooka/dwmenuaction.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ dwmenuaction.h - dockwidget visibility switches to actions
+ -------------------
+ begin : 16.07.2002
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ Based on code from the from Joseph Wenninger (kate project)
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DW_MENU_ACTION
+#define __DW_MENU_ACTION
+#include <kdockwidget.h>
+#include <qstring.h>
+#include <kaction.h>
+
+/**
+ * This class is just a helper class since the KDockWidget classes do not yet
+ * export KActions but only a QPopup-Pointer, which is quite useless in case
+ * you have a xml-file driven gui.
+ * This class provides Actions for show and hide parts of the GUI (dockwidgets)
+ * Maybe that classes can be removed as soon the DockWidget know Actions
+ */
+class dwMenuAction:public KToggleAction
+{
+ Q_OBJECT
+public:
+ dwMenuAction( const QString& text,
+ const KShortcut& cut = KShortcut(),
+ KDockWidget *dw=0, QObject* parent = 0,
+ KDockMainWindow * mw=0, const char* name = 0 );
+ virtual ~dwMenuAction();
+
+private:
+ KDockWidget *m_dw;
+ KDockMainWindow *m_mw;
+protected slots:
+ void slotToggled(bool);
+ void anDWChanged();
+ void slotWidgetDestroyed();
+};
+
+#endif
diff --git a/kooka/formathelp.h b/kooka/formathelp.h
new file mode 100644
index 00000000..7887a240
--- /dev/null
+++ b/kooka/formathelp.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ formathelp.h - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#define HELP_BMP i18n("The <big>bitmap-format</big> is a well known format,\n" \
+ "often used for 256 color images under " \
+ "MS Windows.\n Suitable for color and " \
+ "<bold>lineart-pictures</bold>\n" )
+#define HELP_PNM i18n("Portable Anymap\n" \
+ ""\
+ "" )
+#define HELP_JPG i18n("Jpeg is a high compression,\nquality " \
+ "losing format for color\npictures " \
+ "with many different colors." \
+ "" )
+
+#define HELP_EPS i18n("EPS is Encapsulated Postscript.\n " \
+ "Initially it's a printer definition\n " \
+ "language. Use this format if you\n" \
+ "want to print the image or use\n" \
+ "it with e.g. TeX" )
diff --git a/kooka/imageselectline.cpp b/kooka/imageselectline.cpp
new file mode 100644
index 00000000..f8677f1f
--- /dev/null
+++ b/kooka/imageselectline.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+ imageselectline.cpp - select a background image.
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qbutton.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kurlcombobox.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+#include "imageselectline.h"
+
+/* ############################################################################## */
+
+/*
+ * This widget just combines a label, a combobox holding a path and a select button
+ * together in a row. The button opens a file selector box to pick a file.
+ */
+
+ImageSelectLine::ImageSelectLine( QWidget *parent, const QString& text )
+ : QHBox( parent )
+{
+ setSpacing( 5 );
+ (void) new QLabel( text, this );
+ m_urlCombo = new KURLComboBox( KURLComboBox::Files, this );
+ m_buttFileSelect = new QPushButton( this );
+ m_buttFileSelect->setPixmap( SmallIcon( "fileopen" ) );
+
+ m_urlCombo->setMaxItems(5);
+
+ connect( m_urlCombo, SIGNAL( urlActivated( const KURL& )),
+ this, SLOT( slUrlActivated( const KURL& )));
+
+ connect( m_buttFileSelect, SIGNAL( clicked() ),
+ this, SLOT( slSelectFile()));
+}
+
+void ImageSelectLine::slSelectFile()
+{
+ KURL newUrl;
+ newUrl = KFileDialog::getImageOpenURL();
+
+ QStringList l = m_urlCombo->urls();
+
+ if( ! newUrl.isEmpty())
+ {
+ l.prepend( newUrl.url() );
+ m_urlCombo->setURLs( l );
+ m_currUrl = newUrl;
+ }
+}
+
+void ImageSelectLine::slUrlActivated( const KURL& url )
+{
+ kdDebug(28000) << "Activating url: " << url.url() << endl;
+ m_currUrl = url;
+}
+
+KURL ImageSelectLine::selectedURL() const
+{
+ return m_currUrl;
+}
+
+void ImageSelectLine::setURL( const KURL& url )
+{
+ if( m_urlCombo ) m_urlCombo->setURL( url );
+ m_currUrl = url;
+}
+
+void ImageSelectLine::setURLs( const QStringList& list )
+{
+ if( m_urlCombo ) m_urlCombo->setURLs( list );
+}
+
+#include "imageselectline.moc"
diff --git a/kooka/imageselectline.h b/kooka/imageselectline.h
new file mode 100644
index 00000000..991cb3fd
--- /dev/null
+++ b/kooka/imageselectline.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ imageselectline.h - select a background image.
+ -------------------
+ begin : ?
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMGSELECTLINE_H__
+#define __IMGSELECTLINE_H__
+
+#include <qhbox.h>
+
+/**
+ *
+ */
+
+class KURL;
+class KURLComboBox;
+class QPushButton;
+class QStringList;
+
+class ImageSelectLine:public QHBox
+{
+ Q_OBJECT
+public:
+ ImageSelectLine( QWidget *parent, const QString& text );
+
+ KURL selectedURL() const;
+ void setURL( const KURL& );
+ void setURLs( const QStringList& );
+
+protected slots:
+ void slSelectFile();
+ void slUrlActivated( const KURL& );
+
+private:
+
+ KURL m_currUrl;
+ KURLComboBox *m_urlCombo;
+ QPushButton *m_buttFileSelect;
+
+};
+
+
+#endif
diff --git a/kooka/img_saver.cpp b/kooka/img_saver.cpp
new file mode 100644
index 00000000..1d7cf1d7
--- /dev/null
+++ b/kooka/img_saver.cpp
@@ -0,0 +1,897 @@
+/***************************************************************************
+ img_saver.cpp - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <kimageio.h>
+#include <kseparator.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kio/jobclasses.h>
+#include <kio/file.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <ktempfile.h>
+#include <kinputdialog.h>
+
+#include <qdir.h>
+#include <qlayout.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qmessagebox.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+
+#include "resource.h"
+#include "img_saver.h"
+#include "previewer.h"
+#include "kookaimage.h"
+
+FormatDialog::FormatDialog( QWidget *parent, const QString&, const char *name )
+ :KDialogBase( parent, name, true,
+ /* Tabbed,*/ i18n( "Kooka Save Assistant" ),
+ Ok|Cancel, Ok )
+
+{
+ buildHelp();
+ // readConfig();
+ // QFrame *page = addPage( QString( "Save the image") );
+ QFrame *page = new QFrame( this );
+ page->setFrameStyle( QFrame::Box | QFrame::Sunken );
+ Q_CHECK_PTR( page );
+ setMainWidget( page );
+
+ QVBoxLayout *bigdad = new QVBoxLayout( page, marginHint(), spacingHint());
+ Q_CHECK_PTR(bigdad);
+
+ // some nice words
+ QLabel *l0 = new QLabel( page );
+ Q_CHECK_PTR(l0);
+ l0->setText( i18n( "<B>Save Assistant</B><P>Select an image format to save the scanned image." ));
+ bigdad->addWidget( l0 );
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, page);
+ bigdad->addWidget( sep );
+
+ // Layout-Boxes
+ // QHBoxLayout *hl1= new QHBoxLayout( ); // Caption
+ QHBoxLayout *lhBigMiddle = new QHBoxLayout( spacingHint() ); // Big middle
+ Q_CHECK_PTR(lhBigMiddle);
+ bigdad->addLayout( lhBigMiddle );
+ QVBoxLayout *lvFormatSel = new QVBoxLayout( spacingHint() ); // Selection List
+ Q_CHECK_PTR(lvFormatSel);
+ lhBigMiddle->addLayout( lvFormatSel );
+
+ // Insert Scrolled List for formats
+ QLabel *l1 = new QLabel( page );
+ Q_CHECK_PTR(l1);
+ l1->setText( i18n( "Available image formats:" ));
+
+ lb_format = new QListBox( page, "ListBoxFormats" );
+ Q_CHECK_PTR(lb_format);
+
+#ifdef USE_KIMAGEIO
+ QStringList fo = KImageIO::types();
+#else
+ QStringList fo = QImage::outputFormatList();
+#endif
+ kdDebug(28000) << "#### have " << fo.count() << " image types" << endl;
+ lb_format->insertStringList( fo );
+ connect( lb_format, SIGNAL( highlighted(const QString&)),
+ SLOT( showHelp(const QString&)));
+
+ // Insert label for helptext
+ l_help = new QLabel( page );
+ Q_CHECK_PTR(l_help);
+ l_help->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ l_help->setText( i18n("-No format selected-" ));
+ l_help->setAlignment( AlignVCenter | AlignHCenter );
+ l_help->setMinimumWidth(230);
+
+ // Insert Selbox for subformat
+ l2 = new QLabel( page );
+ Q_CHECK_PTR(l2);
+ l2->setText( i18n( "Select the image sub-format" ));
+ cb_subf = new QComboBox( page, "ComboSubFormat" );
+ Q_CHECK_PTR( cb_subf );
+
+ // Checkbox to store setting
+ cbDontAsk = new QCheckBox(i18n("Don't ask again for the save format if it is defined."),
+ page );
+ Q_CHECK_PTR( cbDontAsk );
+
+ QFrame *hl = new QFrame(page);
+ Q_CHECK_PTR( hl );
+ hl->setFrameStyle( QFrame::HLine|QFrame::Sunken );
+
+ // bigdad->addWidget( l_caption, 1 );
+ lvFormatSel->addWidget( l1, 1 );
+ lvFormatSel->addWidget( lb_format, 6 );
+ lvFormatSel->addWidget( l2, 1 );
+ lvFormatSel->addWidget( cb_subf, 1 );
+
+ lhBigMiddle->addWidget( l_help, 2 );
+ //bigdad->addStretch(1);
+ bigdad->addWidget( hl, 1 );
+ bigdad->addWidget( cbDontAsk , 2 );
+
+ bigdad->activate();
+
+}
+
+void FormatDialog::showHelp( const QString& item )
+{
+ QString helptxt = format_help[ item ];
+
+ if( !helptxt.isEmpty() ) {
+ // Set the hint
+ l_help->setText( helptxt );
+
+ // and check subformats
+ check_subformat( helptxt );
+ } else {
+ l_help->setText( i18n("-no hint available-" ));
+ }
+}
+
+void FormatDialog::check_subformat( const QString & format )
+{
+ // not yet implemented
+ kdDebug(28000) << "This is format in check_subformat: " << format << endl;
+ cb_subf->setEnabled( false );
+ // l2 = Label "select subformat" ->bad name :-|
+ l2->setEnabled( false );
+}
+
+void FormatDialog::setSelectedFormat( QString fo )
+{
+ QListBoxItem *item = lb_format->findItem( fo );
+
+ if( item )
+ {
+ // Select it.
+ lb_format->setSelected( lb_format->index(item), true );
+ }
+}
+
+
+QString FormatDialog::getFormat( ) const
+{
+ int item = lb_format->currentItem();
+
+ if( item > -1 )
+ {
+ const QString f = lb_format->text( item );
+ return( f );
+ }
+ return( "BMP" );
+}
+
+
+QCString FormatDialog::getSubFormat( ) const
+{
+ // Not yet...
+ return( "" );
+}
+
+#include "formathelp.h"
+void FormatDialog::buildHelp( void )
+{
+ format_help.insert( QString::fromLatin1("BMP"), HELP_BMP );
+ format_help.insert( QString::fromLatin1("PNM"), HELP_PNM );
+ format_help.insert( QString::fromLatin1("JPEG"), HELP_JPG );
+ format_help.insert( QString::fromLatin1("JPG"), HELP_JPG );
+ format_help.insert( QString::fromLatin1("EPS"), HELP_EPS );
+}
+
+
+/* ********************************************************************** */
+
+ImgSaver::ImgSaver( QWidget *parent, const KURL dir_name )
+ : QObject( parent )
+{
+
+ if( dir_name.isEmpty() || dir_name.protocol() != "file" )
+ {
+ kdDebug(28000) << "ImageServer initialised with wrong dir " << dir_name.url() << endl;
+ directory = Previewer::galleryRoot();
+ }
+ else
+ {
+ /* A path was given */
+ if( dir_name.protocol() != "file" )
+ {
+ kdDebug(28000) << "ImgSaver: Can only save local image, sorry !" << endl;
+ }
+ else
+ {
+ directory = dir_name.directory(true, false);
+ }
+ }
+
+ kdDebug(28000) << "ImageSaver uses dir <" << directory << endl;
+ createDir( directory );
+ readConfig();
+
+ last_file = "";
+ last_format ="";
+
+}
+
+
+ImgSaver::ImgSaver( QWidget *parent )
+ :QObject( parent )
+{
+ directory = Previewer::galleryRoot();
+ createDir( directory );
+
+ readConfig();
+
+ last_file = "";
+ last_format ="";
+
+}
+
+
+/* Needs a full qualified directory name */
+void ImgSaver::createDir( const QString& dir )
+{
+ KURL url( dir );
+
+ if( ! KIO::NetAccess::exists(url, false, 0) )
+ {
+ kdDebug(28000) << "Wrn: Directory <" << dir << "> does not exist -> try to create !" << endl;
+ // if( mkdir( QFile::encodeName( dir ), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) != 0 )
+ if( KIO::mkdir( KURL(dir)))
+ {
+ KMessageBox::sorry(0, i18n("The folder\n%1\n does not exist and could not be created;\n"
+ "please check the permissions.").arg(dir));
+ }
+ }
+#if 0
+ if( ! fi.isWritable() )
+ {
+ KMessageBox::sorry(0, i18n("The directory\n%1\n is not writeable;\nplease check the permissions.")
+ .arg(dir));
+ }
+#endif
+}
+
+/**
+ * This function asks the user for a filename or creates
+ * one by itself, depending on the settings
+ **/
+ImgSaveStat ImgSaver::saveImage( QImage *image )
+{
+ ImgSaveStat stat;
+ picType imgType;
+
+ if( !image ) return( ISS_ERR_PARAM );
+
+ /* Find out what kind of image it is */
+ if( image->depth() > 8 )
+ {
+ imgType = PT_HICOLOR_IMAGE;
+ }
+ else
+ {
+ if( image->depth() == 1 || image->numColors() == 2 )
+ {
+ kdDebug(28000) << "This is black And White!" << endl;
+ imgType = PT_BW_IMAGE;
+ }
+ else
+ {
+ imgType = PT_COLOR_IMAGE;
+ if( image->allGray() )
+ {
+ imgType = PT_GRAY_IMAGE;
+ }
+ }
+ }
+
+
+ QString format = findFormat( imgType );
+ QString subformat = findSubFormat( format );
+ // Call save-Function with this params
+
+ if( format.isEmpty() )
+ {
+ kdDebug(28000) << "Save canceled by user -> no save !" << endl;
+ return( ISS_SAVE_CANCELED );
+ }
+
+ kdDebug(28000) << "saveImage: Directory is " << directory << endl;
+ QString filename = createFilename( format );
+
+ KConfig *konf = KGlobal::config ();
+ konf->setGroup( OP_FILE_GROUP );
+
+ if( konf->readBoolEntry( OP_ASK_FILENAME, false ) )
+ {
+ bool ok;
+ QString text = KInputDialog::getText( i18n( "Filename" ), i18n("Enter filename:"),
+ filename, &ok );
+
+ if(ok)
+ {
+ filename = text;
+ }
+ }
+
+ QString fi = directory + "/" + filename;
+
+ if( extension(fi).isEmpty() )
+ {
+ if( ! fi.endsWith( "." ) )
+ {
+ fi+= ".";
+ }
+ fi+=format.lower();
+ }
+
+
+ kdDebug(28000) << "saveImage: saving file <" << fi << ">" << endl;
+ stat = save( image, fi, format, subformat );
+
+ return( stat );
+
+}
+
+/**
+ * This member creates a filename for the image to save.
+ * This is done by numbering all existing files and adding
+ * one
+ **/
+QString ImgSaver::createFilename( QString format )
+{
+ if( format.isNull() || format.isEmpty() ) return( 0 );
+
+ QString s = "kscan_*." + format.lower();
+ QDir files( directory, s );
+ long c = 1;
+
+ QString num;
+ num.setNum(c);
+ QString fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
+
+ while( files.exists( fname ) ) {
+ num.setNum(++c);
+ fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
+ }
+
+ return( fname );
+}
+
+/**
+ * This function gets a filename from the parent. The filename must not be relative.
+ **/
+ImgSaveStat ImgSaver::saveImage( QImage *image, const KURL& filename, const QString& imgFormat )
+{
+ QString format = imgFormat;
+
+ /* Check if the filename is local */
+ if( !filename.isLocalFile())
+ {
+ kdDebug(29000) << "ImgSaver: Can only save local image, sorry !" << endl;
+ return( ISS_ERR_PROTOCOL );
+ }
+
+ QString localFilename;
+ localFilename = filename.directory( false, true) + filename.fileName();
+
+ kdDebug(28000) << "saveImage: Saving "<< localFilename << " in format " << format << endl;
+ if( format.isEmpty() )
+ format = "BMP";
+
+ return( save( image, localFilename, format, "" ) );
+}
+
+
+/*
+ * findFormat does all the stuff with the dialog.
+ */
+QString ImgSaver::findFormat( picType type )
+{
+ QString format;
+ KConfig *konf = KGlobal::config ();
+ konf->setGroup( OP_FILE_GROUP );
+
+ if( type == PT_THUMBNAIL )
+ {
+ return( "BMP" );
+ }
+
+ // real images
+ switch( type )
+ {
+ case PT_THUMBNAIL:
+ format = konf->readEntry( OP_FORMAT_THUMBNAIL, "BMP" );
+ kdDebug( 28000) << "Format for Thumbnails: " << format << endl;
+ break;
+ case PT_PREVIEW:
+ format = konf->readEntry( OP_PREVIEW_FORMAT, "BMP" );
+ kdDebug( 28000) << "Format for Preview: " << format << endl;
+ break;
+ case PT_COLOR_IMAGE:
+ format = konf->readEntry( OP_FORMAT_COLOR, "nothing" );
+ kdDebug( 28000 ) << "Format for Color: " << format << endl;
+ break;
+ case PT_GRAY_IMAGE:
+ format = konf->readEntry( OP_FORMAT_GRAY, "nothing" );
+ kdDebug( 28000 ) << "Format for Gray: " << format << endl;
+ break;
+ case PT_BW_IMAGE:
+ format = konf->readEntry( OP_FORMAT_BW, "nothing" );
+ kdDebug( 28000 ) << "Format for BlackAndWhite: " << format << endl;
+ break;
+ case PT_HICOLOR_IMAGE:
+ format = konf->readEntry( OP_FORMAT_HICOLOR, "nothing" );
+ kdDebug( 28000 ) << "Format for HiColorImage: " << format << endl;
+ break;
+ default:
+ format = "nothing";
+ kdDebug( 28000 ) << "ERR: Could not find image type !" << endl;
+
+ break;
+ }
+
+ if( type != PT_PREVIEW ) /* Use always bmp-Default for preview scans */
+ {
+ if( format == "nothing" || ask_for_format )
+ {
+ format = startFormatDialog( type );
+ }
+ }
+ return( format );
+
+}
+
+QString ImgSaver::picTypeAsString( picType type ) const
+{
+ QString res;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ res = i18n( "palleted color image (16 or 24 bit depth)" );
+ break;
+ case PT_GRAY_IMAGE:
+ res = i18n( "palleted gray scale image (16 bit depth)" );
+ break;
+ case PT_BW_IMAGE:
+ res = i18n( "lineart image (black and white, 1 bit depth)" );
+ break;
+ case PT_HICOLOR_IMAGE:
+ res = i18n( "high (or true-) color image, not palleted" );
+ break;
+ default:
+ res = i18n( "Unknown image type" );
+ break;
+ }
+ return( res );
+}
+
+
+QString ImgSaver::startFormatDialog( picType type)
+{
+
+ FormatDialog fd( 0, picTypeAsString( type ), "FormatDialog" );
+
+ // set default values
+ if( type != PT_PREVIEW )
+ {
+ QString defFormat = getFormatForType( type );
+ fd.setSelectedFormat( defFormat );
+ }
+
+ QString format;
+ if( fd.exec() )
+ {
+ format = fd.getFormat();
+ kdDebug(28000) << "Storing to format <" << format << ">" << endl;
+ bool ask = fd.askForFormat();
+ kdDebug(28000)<< "Store askFor is " << ask << endl;
+ storeFormatForType( type, format, ask );
+ subformat = fd.getSubFormat();
+ }
+ return( format );
+}
+
+
+/*
+ * This method returns true if the image format given in format is remembered
+ * for that image type.
+ */
+bool ImgSaver::isRememberedFormat( picType type, QString format ) const
+{
+ if( getFormatForType( type ) == format )
+ {
+ return( true );
+ }
+ else
+ {
+ return( false );
+ }
+
+}
+
+
+
+
+QString ImgSaver::getFormatForType( picType type ) const
+{
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+
+ QString f;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ f = konf->readEntry( OP_FORMAT_COLOR, "BMP" );
+ break;
+ case PT_GRAY_IMAGE:
+ f = konf->readEntry( OP_FORMAT_GRAY, "BMP" );
+ break;
+ case PT_BW_IMAGE:
+ f = konf->readEntry( OP_FORMAT_BW, "BMP" );
+ break;
+ case PT_HICOLOR_IMAGE:
+ f = konf->readEntry( OP_FORMAT_HICOLOR, "BMP" );
+ break;
+ default:
+ f = "BMP";
+ break;
+ }
+ return( f );
+}
+
+
+void ImgSaver::storeFormatForType( picType type, QString format, bool ask )
+{
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+
+ konf->writeEntry( OP_FILE_ASK_FORMAT, ask );
+ ask_for_format = ask;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ konf->writeEntry( OP_FORMAT_COLOR, format );
+ break;
+ case PT_GRAY_IMAGE:
+ konf->writeEntry( OP_FORMAT_GRAY, format );
+ break;
+ case PT_BW_IMAGE:
+ konf->writeEntry( OP_FORMAT_BW, format );
+ break;
+ case PT_HICOLOR_IMAGE:
+ konf->writeEntry( OP_FORMAT_HICOLOR, format );
+ break;
+ default:
+ kdDebug(28000) << "Wrong Type - cant store format setting" << endl;
+ break;
+ }
+ konf->sync();
+}
+
+
+QString ImgSaver::findSubFormat( QString format )
+{
+ kdDebug(28000) << "Searching Subformat for " << format << endl;
+ return( subformat );
+
+}
+
+/**
+ private save() does the work to save the image.
+ the filename must be complete and local.
+**/
+ImgSaveStat ImgSaver::save( QImage *image, const QString &filename,
+ const QString &format,
+ const QString &subformat )
+{
+
+ bool result = false;
+ kdDebug(28000) << "in ImgSaver::save: saving " << filename << endl;
+ if( ! format || !image )
+ {
+ kdDebug(28000) << "ImgSaver ERROR: Wrong parameter Format <" << format << "> or image" << endl;
+ return( ISS_ERR_PARAM );
+ }
+
+ if( image )
+ {
+ // remember the last processed file - only the filename - no path
+ QFileInfo fi( filename );
+ QString dirPath = fi.dirPath();
+ QDir dir = QDir( dirPath );
+
+ if( ! dir.exists() )
+ {
+ /* The dir to save in always should exist, except in the first preview save */
+ kdDebug(28000) << "Creating dir " << dirPath << endl;
+ if( !dir.mkdir( dirPath ) )
+ {
+ kdDebug(28000) << "ERR: Could not create directory" << endl;
+ }
+ }
+
+ if( fi.exists() && !fi.isWritable() )
+ {
+ kdDebug(28000) << "Cant write to file <" << filename << ">, cant save !" << endl;
+ result = false;
+ return( ISS_ERR_PERM );
+ }
+
+ /* Check the format, is it writable ? */
+#ifdef USE_KIMAGEIO
+ if( ! KImageIO::canWrite( format ) )
+ {
+ kdDebug(28000) << "Cant write format <" << format << ">" << endl;
+ result = false;
+ return( ISS_ERR_FORMAT_NO_WRITE );
+ }
+#endif
+ kdDebug(28000) << "ImgSaver: saving image to <" << filename << "> as <" << format << "/" << subformat <<">" << endl;
+
+ result = image->save( filename, format.latin1() );
+
+
+ last_file = fi.absFilePath();
+ last_format = format.latin1();
+ }
+
+ if( result )
+ return( ISS_OK );
+ else {
+ last_file = "";
+ last_format = "";
+ return( ISS_ERR_UNKNOWN );
+ }
+
+}
+
+
+void ImgSaver::readConfig( void )
+{
+
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+ ask_for_format = konf->readBoolEntry( OP_FILE_ASK_FORMAT, true );
+
+ QDir home = QDir::home();
+}
+
+
+
+
+
+QString ImgSaver::errorString( ImgSaveStat stat )
+{
+ QString re;
+
+ switch( stat ) {
+ case ISS_OK: re = i18n( " image save OK " ); break;
+ case ISS_ERR_PERM: re = i18n( " permission error " ); break;
+ case ISS_ERR_FILENAME: re = i18n( " bad filename " ); break;
+ case ISS_ERR_NO_SPACE: re = i18n( " no space on device " ); break;
+ case ISS_ERR_FORMAT_NO_WRITE: re = i18n( " could not write image format " ); break;
+ case ISS_ERR_PROTOCOL: re = i18n( " can not write file using that protocol "); break;
+ case ISS_SAVE_CANCELED: re = i18n( " user canceled saving " ); break;
+ case ISS_ERR_UNKNOWN: re = i18n( " unknown error " ); break;
+ case ISS_ERR_PARAM: re = i18n( " parameter wrong " ); break;
+
+ default: re = "";
+ }
+ return( re );
+
+}
+
+QString ImgSaver::extension( const KURL& url )
+{
+ QString extension = url.fileName();
+
+ int dotPos = extension.findRev( '.' );
+ if( dotPos > 0 )
+ {
+ int len = extension.length();
+ extension = extension.right( len - dotPos -1 );
+ }
+ else
+ {
+ /* No extension was supplied */
+ extension = QString();
+ }
+ return extension;
+}
+
+
+bool ImgSaver::renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt, QWidget *overWidget )
+{
+ /* Check if the provided filename has a extension */
+ QString extTo = extension( toUrl );
+ QString extFrom = extension( fromUrl );
+ KURL targetUrl( toUrl );
+
+ if( extTo.isEmpty() && !extFrom.isEmpty() )
+ {
+ /* Ask if the extension should be added */
+ int result = KMessageBox::Yes;
+ QString fName = toUrl.fileName();
+ if( ! fName.endsWith( "." ) )
+ {
+ fName += ".";
+ }
+ fName += extFrom;
+
+ if( askExt )
+ {
+
+ QString s;
+ s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
+ s += i18n( "That would result in the new filename: %1" ).arg( fName);
+
+ result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
+ i18n("Add Extension"), i18n("Do Not Add"),
+ "AutoAddExtensions" );
+ }
+
+ if( result == KMessageBox::Yes )
+ {
+ targetUrl.setFileName( fName );
+ kdDebug(28000) << "Rename file to " << targetUrl.prettyURL() << endl;
+ }
+ }
+ else if( !extFrom.isEmpty() && extFrom != extTo )
+ {
+ if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
+ (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
+ {
+ /* extensions differ -> TODO */
+ KMessageBox::error( overWidget,
+ i18n("Format changes of images are currently not supported."),
+ i18n("Wrong Extension Found" ));
+ return(false);
+ }
+ }
+
+ bool success = false;
+
+ if( KIO::NetAccess::exists( targetUrl, false,0 ) )
+ {
+ kdDebug(28000)<< "Target already exists - can not copy" << endl;
+ }
+ else
+ {
+ if( KIO::file_move(fromUrl, targetUrl) )
+ {
+ success = true;
+ }
+ }
+ return( success );
+}
+
+
+QString ImgSaver::tempSaveImage( KookaImage *img, const QString& format, int colors )
+{
+
+ KTempFile *tmpFile = new KTempFile( QString(), "."+format.lower());
+ tmpFile->setAutoDelete( false );
+ tmpFile->close();
+
+ KookaImage tmpImg;
+
+ if( colors != -1 && img->numColors() != colors )
+ {
+ // Need to convert image
+ if( colors == 1 || colors == 8 || colors == 24 || colors == 32 )
+ {
+ tmpImg = img->convertDepth( colors );
+ img = &tmpImg;
+ }
+ else
+ {
+ kdDebug(29000) << "ERROR: Wrong color depth requested: " << colors << endl;
+ img = 0;
+ }
+ }
+
+ QString name;
+ if( img )
+ {
+ name = tmpFile->name();
+
+ if( ! img->save( name, format.latin1() ) ) name = QString();
+ }
+ delete tmpFile;
+ return name;
+}
+
+bool ImgSaver::copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget )
+{
+
+ /* Check if the provided filename has a extension */
+ QString extTo = extension( toUrl );
+ QString extFrom = extension( fromUrl );
+ KURL targetUrl( toUrl );
+
+ if( extTo.isEmpty() && !extFrom.isEmpty())
+ {
+ /* Ask if the extension should be added */
+ int result = KMessageBox::Yes;
+ QString fName = toUrl.fileName();
+ if( ! fName.endsWith( "." ))
+ fName += ".";
+ fName += extFrom;
+
+ QString s;
+ s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
+ s += i18n( "That would result in the new filename: %1" ).arg( fName);
+
+ result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
+ i18n("Add Extension"), i18n("Do Not Add"),
+ "AutoAddExtensions" );
+
+ if( result == KMessageBox::Yes )
+ {
+ targetUrl.setFileName( fName );
+ }
+ }
+ else if( !extFrom.isEmpty() && extFrom != extTo )
+ {
+ /* extensions differ -> TODO */
+ if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
+ (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
+ {
+ KMessageBox::error( overWidget, i18n("Format changes of images are currently not supported."),
+ i18n("Wrong Extension Found" ));
+ return(false);
+ }
+ }
+
+ KIO::Job *copyjob = KIO::copy( fromUrl, targetUrl, false );
+
+ return( copyjob ? true : false );
+}
+
+
+/* extension needs to be added */
+
+#include "img_saver.moc"
diff --git a/kooka/img_saver.h b/kooka/img_saver.h
new file mode 100644
index 00000000..f9a29898
--- /dev/null
+++ b/kooka/img_saver.h
@@ -0,0 +1,208 @@
+/***************************************************************************
+ img_saver.h - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMG_SAVER_H__
+#define __IMG_SAVER_H__
+#include <qobject.h>
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qmemarray.h>
+#include <qstring.h>
+#include <qimage.h>
+#include <stdlib.h>
+#include <qdialog.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qlistbox.h>
+#include <qmap.h>
+#include <kdialogbase.h>
+#include <kurl.h>
+
+
+#define OP_FILE_ASK_FORMAT "AskForSaveFormat"
+#define OP_ASK_FILENAME "AskForFilename"
+#define OP_FORMAT_HICOLOR "HiColorSaveFormat"
+#define OP_FORMAT_COLOR "ColorSaveFormat"
+#define OP_FORMAT_GRAY "GraySaveFormat"
+#define OP_FORMAT_BW "BWSaveFormat"
+#define OP_FORMAT_THUMBNAIL "ThumbnailFormat"
+#define OP_PREVIEW_GROUP "ScanPreview"
+#define OP_PREVIEW_FILE "PreviewFile"
+#define OP_PREVIEW_FORMAT "PreviewFormat"
+#define OP_FILE_GROUP "Files"
+
+
+/**
+ * enum ImgSaveStat:
+ * Errorflags for the save. These enums are returned by the
+ * all image save operations and the calling object my display
+ * a human readable Error-Message on this information
+ **/
+typedef enum {
+ ISS_OK, /* Image save OK */
+ ISS_ERR_PERM, /* permission Error */
+ ISS_ERR_FILENAME, /* bad filename */
+ ISS_ERR_NO_SPACE, /* no space on device */
+ ISS_ERR_FORMAT_NO_WRITE, /* Image format can not be written */
+ ISS_ERR_UNKNOWN,
+ ISS_ERR_PARAM, /* Parameter wrong */
+ ISS_ERR_PROTOCOL,
+ ISS_SAVE_CANCELED
+
+} ImgSaveStat;
+
+/**
+ * enum picType:
+ * Specifies the type of the image to save. This is important for
+ * getting the format.
+ **/
+typedef enum {
+ PT_PREVIEW,
+ PT_THUMBNAIL,
+ PT_HICOLOR_IMAGE,
+ PT_COLOR_IMAGE,
+ PT_GRAY_IMAGE,
+ PT_BW_IMAGE,
+ PT_FINISHED
+} picType;
+
+
+class KookaImage;
+/**
+ * Class FormatDialog:
+ * Asks the user for the image-Format and gives help for
+ * selecting it.
+ **/
+
+class FormatDialog:public KDialogBase
+{
+ Q_OBJECT
+public:
+ FormatDialog( QWidget *parent, const QString&, const char * );
+
+
+ QString getFormat( ) const;
+ QCString getSubFormat( ) const;
+ QString errorString( ImgSaveStat stat );
+
+ bool askForFormat( ) const
+ { return( ! cbDontAsk->isChecked()); }
+
+public slots:
+ void setSelectedFormat( QString );
+
+
+protected slots:
+ void showHelp( const QString& item );
+
+private:
+
+ void check_subformat( const QString & format );
+ void buildHelp( void );
+ void readConfig( void );
+
+ QMap<QString, QString> format_help;
+ QComboBox *cb_subf;
+ QListBox *lb_format;
+ QLabel *l_help;
+ QLabel *l2;
+ QCheckBox *cbRemember;
+ QCheckBox *cbDontAsk;
+};
+
+/**
+ * Class ImgSaver:
+ * The main class of this module. It manages all saving of images
+ * in kooka
+ * It asks the user for the img-format if desired, creates thumbnails
+ * and cares for database entries (later ;)
+ **/
+
+class ImgSaver:public QObject {
+ Q_OBJECT
+public:
+ /**
+ * constructor of the image-saver object.
+ * name is the name of a subdirectory of the save directory,
+ * which can be given in dir. If no dir is given, an
+ * dir ~/.ksane is created.
+ * @param dir Name of the save root directory
+ * @param name Name of a subdirectory in the saveroot.
+ **/
+ ImgSaver( QWidget *parent, const KURL );
+ ImgSaver( QWidget *parent );
+
+ QString errorString( ImgSaveStat );
+ /**
+ * returns the name of the last file that was saved by ImgSaver.
+ */
+ QString lastFilename() const { return( last_file ); }
+ KURL lastFileUrl() const { return( KURL(last_file )); }
+ /**
+ * returns the image format of the last saved image.
+ */
+ QCString lastSaveFormat( void ) const { return( last_format ); }
+
+ QString getFormatForType( picType ) const;
+ void storeFormatForType( picType, QString, bool );
+ bool isRememberedFormat( picType type, QString format ) const;
+
+ /* static function that exports a file */
+ static bool copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget=0 );
+ static bool renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt=false, QWidget *overWidget=0 );
+ static QString tempSaveImage( KookaImage *img, const QString& format, int colors = -1 );
+
+ /* static function that returns the extension of an url */
+ static QString extension( const KURL& );
+
+public slots:
+ ImgSaveStat saveImage( QImage *image );
+ ImgSaveStat saveImage( QImage *image, const KURL& filename, const QString& imgFormat );
+
+private:
+ QString picTypeAsString( picType type ) const;
+ QString findFormat( picType type );
+ QString findSubFormat( QString format );
+ void createDir( const QString& );
+
+ ImgSaveStat save( QImage *image, const QString &filename, const QString &format,
+ const QString &subformat );
+ QString createFilename( QString format );
+ void readConfig( void );
+ QString startFormatDialog( picType );
+
+ // QStrList all_formats;
+ QString directory; // dir where the image should be saved
+ QString last_file;
+ QCString subformat;
+ QCString last_format;
+ bool ask_for_format;
+
+ // QDict<QString> formats;
+};
+
+#endif
diff --git a/kooka/imgnamecombo.cpp b/kooka/imgnamecombo.cpp
new file mode 100644
index 00000000..77b59a0d
--- /dev/null
+++ b/kooka/imgnamecombo.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ imgnamecombo.cpp - combobox for image names
+ -------------------
+ begin : Tue Nov 13 2001
+ copyright : (C) 2001 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistview.h>
+
+#include <kcombobox.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kfiletreebranch.h>
+
+#include "imgnamecombo.h"
+#include "img_saver.h"
+
+ImageNameCombo::ImageNameCombo( QWidget *parent )
+ : KComboBox( parent )
+{
+ setInsertionPolicy( QComboBox::AtTop );
+}
+
+ImageNameCombo::~ImageNameCombo()
+{
+
+}
+
+void ImageNameCombo::slotPathRemove( KFileTreeBranch *branch, const QString& relPath )
+{
+ QString path = branch->name() + QString::fromLatin1(" - ") + relPath;
+
+ kdDebug(28000) << "ImageNameCombo: Removing " << path << endl;
+ QString select = currentText();
+
+ if( items.contains( path ))
+ {
+ kdDebug(28000) << "ImageNameCombo: Item exists-> deleting" << endl;
+ items.remove( path );
+ }
+
+ /* */
+ rewriteList( branch, select );
+}
+
+void ImageNameCombo::rewriteList( KFileTreeBranch *branch, const QString& selText )
+{
+ clear();
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it )
+ {
+ insertItem( branch->pixmap(), *it );
+ }
+
+ int index = items.findIndex( selText );
+ setCurrentItem( index );
+}
+
+void ImageNameCombo::slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath )
+{
+ QString newPath;
+
+ newPath = branch->name() + QString::fromLatin1(" - ") + relativPath;
+
+ kdDebug( 28000) << "Inserting " << newPath << " to combobox" << endl;
+
+ setCurrentItem( newPath, true /* insert if missing */ );
+}
+
+/* The End */
+#include "imgnamecombo.moc"
diff --git a/kooka/imgnamecombo.h b/kooka/imgnamecombo.h
new file mode 100644
index 00000000..a577929e
--- /dev/null
+++ b/kooka/imgnamecombo.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ imgnamecombo.h - combobox for image names
+ -------------------
+ begin : Tue Nov 13 2001
+ copyright : (C) 2001 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef IMGNAMECOMBO_H
+#define IMGNAMECOMBO_H
+
+
+#include <kcombobox.h>
+
+/**
+ *@author Klaas Freitag
+*/
+
+class QListViewItem;
+class KFileBranch;
+
+class ImageNameCombo: public KComboBox
+{
+ Q_OBJECT
+public:
+ ImageNameCombo( QWidget* );
+ ~ImageNameCombo();
+
+public slots:
+
+ void slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath );
+ void slotPathRemove( KFileTreeBranch *branch, const QString& relPath );
+private:
+ void rewriteList( KFileTreeBranch *, const QString& selText );
+ QStringList items;
+};
+
+#endif
diff --git a/kooka/imgprintdialog.cpp b/kooka/imgprintdialog.cpp
new file mode 100644
index 00000000..f9aa3930
--- /dev/null
+++ b/kooka/imgprintdialog.cpp
@@ -0,0 +1,302 @@
+/***************************************************************************
+ imgprintdialog.h - Kooka's Image Printing
+ -------------------
+ begin : May 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include "imgprintdialog.h"
+
+#include <klocale.h>
+#include <knuminput.h>
+#include <kdialog.h>
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include "kookaimage.h"
+#include <qvgroupbox.h>
+#include <qpaintdevicemetrics.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <kdebug.h>
+
+#define ID_SCREEN 0
+#define ID_ORIG 1
+#define ID_CUSTOM 2
+#define ID_FIT_PAGE 3
+
+ImgPrintDialog::ImgPrintDialog( KookaImage *img, QWidget *parent, const char* name )
+ : KPrintDialogPage( parent, name ),
+ m_image(img),
+ m_ignoreSignal(false)
+{
+ setTitle(i18n("Image Printing"));
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ // layout->setMargin( KDialog::marginHint() );
+ // layout->setSpacing( KDialog::spacingHint() );
+
+ m_scaleRadios = new QButtonGroup( 2, Qt::Vertical, i18n("Image Print Size"), this );
+ m_scaleRadios->setRadioButtonExclusive(true);
+ connect( m_scaleRadios, SIGNAL(clicked(int)), SLOT(slScaleChanged(int)));
+
+ m_rbScreen = new QRadioButton( i18n("Scale to same size as on screen"),
+ m_scaleRadios );
+ QToolTip::add( m_rbScreen, i18n("Screen scaling. That prints according to the screen resolution."));
+
+ m_scaleRadios->insert( m_rbScreen, ID_SCREEN );
+
+ m_rbOrigSize = new QRadioButton( i18n("Original size (calculate from scan resolution)"),
+ m_scaleRadios );
+ QToolTip::add( m_rbOrigSize,
+ i18n("Calculates the print size from the scan resolution. Enter the scan resolution in the dialog field below." ));
+ m_scaleRadios->insert( m_rbOrigSize, ID_ORIG );
+
+
+ m_rbScale = new QRadioButton( i18n("Scale image to custom dimension"), m_scaleRadios );
+ QToolTip::add( m_rbScale,
+ i18n("Set the print size yourself in the dialog below. The image is centered on the paper."));
+
+ m_scaleRadios->insert( m_rbScale, ID_CUSTOM );
+
+ m_rbFitPage = new QRadioButton( i18n("Scale image to fit to page"), m_scaleRadios );
+ QToolTip::add( m_rbFitPage, i18n("Printout uses maximum space on the selected pager. Aspect ratio is maintained."));
+ m_scaleRadios->insert( m_rbFitPage, ID_FIT_PAGE );
+
+ layout->addWidget( m_scaleRadios );
+
+
+ QHBoxLayout *hbox = new QHBoxLayout( this );
+ layout->addLayout( hbox );
+
+ /** Box for Image Resolutions **/
+ QVGroupBox *group1 = new QVGroupBox( i18n("Resolutions"), this );
+ hbox->addWidget( group1 );
+
+ /* Postscript generation resolution */
+ m_psDraft = new QCheckBox( i18n("Generate low resolution PostScript (fast draft print)"),
+ group1, "cbPostScriptRes" );
+ m_psDraft->setChecked( false );
+
+
+ /* Scan resolution of the image */
+ m_dpi = new KIntNumInput( group1 );
+ m_dpi->setLabel( i18n("Scan resolution (dpi) " ), AlignVCenter );
+ m_dpi->setValue( 300 );
+ m_dpi->setSuffix( i18n(" dpi"));
+
+ /* Label for displaying the screen Resolution */
+ m_screenRes = new QLabel( group1 );
+
+ /** Box for Image Print Size **/
+ QVGroupBox *group = new QVGroupBox( i18n("Image Print Size"), this );
+ hbox->addWidget( group );
+
+ m_sizeW = new KIntNumInput( group );
+ m_sizeW->setLabel( i18n("Image width:"), AlignVCenter );
+ m_sizeW->setSuffix( i18n(" mm"));
+ connect( m_sizeW, SIGNAL(valueChanged(int)), SLOT(slCustomWidthChanged(int)));
+ m_sizeH = new KIntNumInput( m_sizeW, AlignVCenter, group );
+ m_sizeH->setLabel( i18n("Image height:"), AlignVCenter);
+ m_sizeH->setSuffix( i18n(" mm"));
+ connect( m_sizeH, SIGNAL(valueChanged(int)), SLOT(slCustomHeightChanged(int)));
+
+ m_ratio = new QCheckBox( i18n("Maintain aspect ratio"), group, "cbAspectRatio" );
+ m_ratio->setChecked(true);
+
+
+ QWidget *spaceEater = new QWidget( this );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ layout->addWidget( spaceEater );
+
+ /* Set start values */
+ m_rbScreen->setChecked(true);
+ slScaleChanged( ID_SCREEN );
+}
+
+void ImgPrintDialog::setImage( KookaImage *img )
+{
+ if( ! img ) return;
+
+ // TODO: get scan resolution out of the image
+
+}
+
+void ImgPrintDialog::setOptions(const QMap<QString,QString>& opts)
+{
+ // m_autofit->setChecked(opts["app-img-autofit"] == "1");
+ QString scale = opts[OPT_SCALING];
+
+ kdDebug(28000) << "In setOption" << endl;
+
+ if( scale == "scan" )
+ m_rbOrigSize->setChecked(true);
+ else if( scale == "custom" )
+ m_rbScale->setChecked(true);
+ else
+ m_rbScreen->setChecked(true);
+
+ int help = opts[OPT_SCAN_RES].toInt();
+ m_dpi->setValue( help );
+
+ help = opts[OPT_WIDTH].toInt();
+ m_sizeW->setValue( help );
+
+ help = opts[OPT_HEIGHT].toInt();
+ m_sizeH->setValue( help );
+
+ help = opts[OPT_SCREEN_RES].toInt();
+ m_screenRes->setText(i18n( "Screen resolution: %1 dpi").arg(help));
+
+ help = opts[OPT_PSGEN_DRAFT].toInt();
+ m_psDraft->setChecked( help == 1 );
+
+ help = opts[OPT_RATIO].toInt();
+ m_ratio->setChecked( help == 1 );
+
+}
+
+
+void ImgPrintDialog::getOptions(QMap<QString,QString>& opts, bool )
+{
+ // TODO: Check for meaning of include_def !
+ // kdDebug(28000) << "In getOption with include_def: " << include_def << endl;
+
+ QString scale = "screen";
+ if( m_rbOrigSize->isChecked() )
+ scale = "scan";
+ else if( m_rbScale->isChecked() )
+ scale = "custom";
+ else if( m_rbFitPage->isChecked() )
+ scale = "fitpage";
+
+ opts[OPT_SCALING] = scale;
+
+ opts[OPT_SCAN_RES] = QString::number( m_dpi->value() );
+ opts[OPT_WIDTH] = QString::number( m_sizeW->value() );
+ opts[OPT_HEIGHT] = QString::number( m_sizeH->value() );
+ opts[OPT_PSGEN_DRAFT] = QString::number( m_psDraft->isChecked() );
+ opts[OPT_RATIO] = QString::number( m_ratio->isChecked() );
+
+ {
+ QPaintDeviceMetrics metric( this );
+ opts[OPT_SCREEN_RES] = QString::number( metric.logicalDpiX());
+ }
+}
+
+bool ImgPrintDialog::isValid(QString& msg)
+{
+ /* check if scan reso is higher than 0 in case its needed */
+ int id = m_scaleRadios->id( m_scaleRadios->selected());
+ if( id == ID_ORIG && m_dpi->value() == 0 )
+ {
+ msg = i18n("Please specify a scan resolution larger than 0");
+ return false;
+ }
+ else if( id == ID_CUSTOM && (m_sizeW->value() == 0 || m_sizeH->value() == 0 ) )
+ {
+ msg = i18n("For custom printing, a valid size should be specified.\n"
+ "At least one dimension is zero.");
+ }
+
+ return true;
+}
+
+void ImgPrintDialog::slScaleChanged( int id )
+{
+ if( id == ID_SCREEN )
+ {
+ /* disalbe size, scan res. */
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(false);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+ else if( id == ID_ORIG )
+ {
+ /* disable size */
+ m_dpi->setEnabled(true);
+ m_ratio->setEnabled(false);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+ else if( id == ID_CUSTOM )
+ {
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(true);
+ m_sizeW->setEnabled(true);
+ m_sizeH->setEnabled(true);
+ }
+ else if( id == ID_FIT_PAGE )
+ {
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(true);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+}
+
+void ImgPrintDialog::slCustomWidthChanged( int val )
+{
+ if( m_ignoreSignal )
+ {
+ m_ignoreSignal = false;
+ return;
+ }
+
+ /* go out here if scaling is not custom */
+ if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return;
+
+ /* go out here if maintain aspect ration is off */
+ if( ! m_ratio->isChecked() ) return;
+
+ m_ignoreSignal = true;
+ kdDebug(28000) << "Setting value to horizontal size" << endl;
+ m_sizeH->setValue( int( double(val) *
+ double(m_image->height())/double(m_image->width()) ) );
+
+}
+
+void ImgPrintDialog::slCustomHeightChanged( int val )
+{
+ if( m_ignoreSignal )
+ {
+ m_ignoreSignal = false;
+ return;
+ }
+
+ /* go out here if scaling is not custom */
+ if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return;
+
+ /* go out here if maintain aspect ration is off */
+ if( ! m_ratio->isChecked() ) return;
+
+ m_ignoreSignal = true;
+ kdDebug(28000) << "Setting value to vertical size" << endl;
+ m_sizeW->setValue( int( double(val) *
+ double(m_image->width())/double(m_image->height()) ) );
+
+}
+
+#include "imgprintdialog.moc"
diff --git a/kooka/imgprintdialog.h b/kooka/imgprintdialog.h
new file mode 100644
index 00000000..845cc038
--- /dev/null
+++ b/kooka/imgprintdialog.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ imgprintdialog.h - Kooka's Image Printing
+ -------------------
+ begin : May 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMGPRINTDIALOG_H__
+#define __IMGPRINTDIALOG_H__
+
+#include <qmap.h>
+#include <qcheckbox.h>
+#include <kdeprint/kprintdialogpage.h>
+
+#include "kookaimage.h"
+
+#define OPT_SCALING "kde-kooka-scaling"
+#define OPT_SCAN_RES "kde-kooka-scanres"
+#define OPT_SCREEN_RES "kde-kooka-screenres"
+#define OPT_WIDTH "kde-kooka-width"
+#define OPT_HEIGHT "kde-kooka-height"
+#define OPT_PSGEN_DRAFT "kde-kooka-psdraft"
+#define OPT_RATIO "kde-kooka-ratio"
+#define OPT_FITPAGE "kde-kooka-fitpage"
+class QWidget;
+class QString;
+class QLabel;
+class KIntNumInput;
+class KookaImage;
+class QVButtonGroup;
+class QRadioButton;
+class QCheckBox;
+
+class ImgPrintDialog: public KPrintDialogPage
+{
+ Q_OBJECT
+public:
+ ImgPrintDialog( KookaImage *img, QWidget *parent=0L, const char* name=0L );
+
+ void setOptions(const QMap<QString,QString>& opts);
+ void getOptions(QMap<QString,QString>& opts, bool include_def = false);
+ bool isValid(QString& msg);
+
+ void setImage( KookaImage *img );
+
+protected slots:
+ void slScaleChanged( int id );
+ void slCustomWidthChanged(int);
+ void slCustomHeightChanged(int);
+
+private:
+ QButtonGroup *m_scaleRadios;
+ QRadioButton *m_rbOrigSize;
+ QRadioButton *m_rbScale;
+ QRadioButton *m_rbScreen;
+ QRadioButton *m_rbFitPage;
+
+ KIntNumInput *m_sizeW;
+ KIntNumInput *m_sizeH;
+ KIntNumInput *m_dpi;
+
+ QCheckBox *m_psDraft;
+ QCheckBox *m_ratio;
+
+ KookaImage *m_image;
+ QLabel *m_screenRes;
+ bool m_ignoreSignal;
+};
+
+#endif
diff --git a/kooka/kadmosocr.cpp b/kooka/kadmosocr.cpp
new file mode 100644
index 00000000..72f9324b
--- /dev/null
+++ b/kooka/kadmosocr.cpp
@@ -0,0 +1,432 @@
+/***************************************************************************
+ kadmosocr.cpp - Kadmos cpp interface
+ -------------------
+ begin : Fri Jun 30 2000
+
+ (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen
+ Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099
+ Website: www.reRecognition.com E-mail: info@reRecognition.com
+
+ Author: Tamas Nagy (nagy@rerecognition.com)
+ Klaas Freitag <freitag@suse.de>
+ Heike Stuerzenhofecker <heike@freisturz.de>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* Kadmos CPP object oriented interface */
+
+#include <qimage.h>
+#include <qpainter.h>
+#include <qstring.h>
+#include <qrect.h>
+#include <qstringlist.h>
+
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <kdebug.h>
+
+#include "kadmosocr.h"
+#include "ocrword.h"
+
+#ifdef HAVE_KADMOS
+
+using namespace Kadmos;
+
+/* -------------------- CRep -------------------- */
+CRep::CRep()
+ :QObject()
+{
+ memset(&m_RepData, 0, sizeof(m_RepData));
+ m_Error = RE_SUCCESS;
+ m_undetectChar = QChar('_');
+}
+
+CRep::~CRep()
+{
+}
+
+RelGraph* CRep::getGraphKnode(int line, int offset )
+{
+ Kadmos::RepResult *res = getRepResult(line);
+ if( res )
+ return ( &(getRepResult(line)->rel_graph[0])+offset);
+ else
+ return 0L;
+
+}
+
+
+RepResult* CRep::getRepResult(int line)
+{
+ if( line<0 || line >= m_RepData.rep_result_len ) return 0L;
+ return &(m_RepData.rep_result[line]);
+}
+
+RelResult* CRep::getRelResult(int line, RelGraph* graph, int alternative)
+{
+ if( ! ( graph && getRepResult(line))) return 0L;
+ int offset = graph->result_number[alternative];
+ return( &(getRepResult(line)->rel_result[0]) + offset );
+}
+
+
+KADMOS_ERROR CRep::Init(const char* ClassifierFilename)
+{
+ /* prepare RepData structure */
+ m_RepData.init.rel_grid_maxlen = GRID_MAX_LEN;
+ m_RepData.init.rel_graph_maxlen = GRAPH_MAX_LEN;
+ m_RepData.init.rel_result_maxlen = CHAR_MAX_LEN;
+ m_RepData.init.rep_memory_size = LINE_MAX_LEN * sizeof(RepResult) +
+ (long)LINE_MAX_LEN * CHAR_MAX_LEN * (sizeof(RelGraph)+
+ sizeof(RelResult));
+ m_RepData.init.rep_memory = malloc( m_RepData.init.rep_memory_size );
+ if (!m_RepData.init.rep_memory) {
+ CheckError();
+ return m_Error;
+ }
+ strcpy(m_RepData.init.version, INC_KADMOS);
+
+ m_Error = rep_init(&m_RepData, (char*)ClassifierFilename);
+ CheckError();
+ return m_Error;
+}
+
+void CRep::run() // KADMOS_ERROR CRep::Recognize()
+{
+ kdDebug(28000) << "ooo Locked and ocr!" << endl;
+ m_Error = rep_do(&m_RepData);
+ CheckError();
+}
+
+KADMOS_ERROR CRep::End()
+{
+ m_Error = rep_end(&m_RepData);
+ CheckError();
+ return m_Error;
+}
+
+int CRep::GetMaxLine()
+{
+ return m_RepData.rep_result_len;
+}
+
+const char* CRep::RepTextLine(int nLine, unsigned char RejectLevel, int RejectChar, long Format)
+{
+ m_Error = rep_textline(&m_RepData, nLine, m_Line,
+ 2*CHAR_MAX_LEN, RejectLevel, RejectChar, Format);
+ CheckError();
+ return m_Line;
+}
+
+/**
+ * This method handles the given line. It takes repRes and goes through the
+ * kadmos result tree structures recursivly.
+ */
+ocrWordList CRep::getLineWords( int line )
+{
+ ocrWordList repWords;
+ bool ok = true;
+
+ Kadmos::RepResult *repRes = getRepResult(line);
+
+ if( ! repRes )
+ {
+ kdDebug(28000) << "repRes-Pointer is null" << endl;
+ ok = false;
+ }
+
+ if( ok )
+ {
+ int nextKnode=0;
+
+ do
+ {
+ QString resultWord;
+ QRect boundingRect;
+
+ int newNextKnode = nextBestWord( line, nextKnode, resultWord, boundingRect );
+ boundingRect.moveBy( repRes->left, repRes->top );
+
+ ocrWord newWord;
+ newWord = resultWord;
+ newWord.setKnode(nextKnode);
+ newWord.setLine(line);
+ newWord.setRect(boundingRect);
+ repWords.push_back(newWord);
+
+ /* set nextKnode to the next Knode */
+ nextKnode = newNextKnode;
+
+
+ // Alternativen:
+ // partStrings( line, nextKnode, QString()); // fills m_parts - list with alternative words
+ // nextKnode = newNextKnode;
+ // kdDebug(28000) << "NextKnodeWord: " << resultWord << endl;
+ }
+ while( nextKnode > 0 );
+ }
+ return repWords;
+}
+
+
+/* This fills theWord with the next best word and returns the
+ * next knode or 0 if there is no next node
+ */
+int CRep::nextBestWord( int line, int knode, QString& theWord, QRect& brect )
+{
+
+ Kadmos::RelGraph *relg = getGraphKnode( line, knode );
+ // kdDebug(28000) << "GraphKnode is " << knode << endl;
+ int nextKnode = knode;
+
+ while( relg )
+ {
+ Kadmos::RelResult *relr = getRelResult( line, relg, 0 ); // best alternative
+ if( relr )
+ {
+ // kdDebug(28000) << "Leading Blanks: " << relg->leading_blanks <<
+ // " und Knode " << knode << endl;
+ char c = relr->rec_char[0][0];
+ QChar newChar = c;
+ if( c == 0 )
+ {
+ kdDebug(28000) << "Undetected char found !" << endl;
+ newChar = m_undetectChar;
+ }
+
+ if ( (nextKnode != knode) && (relg->leading_blanks > 0))
+ {
+ /* this means the word ends here. */
+ // kdDebug(28000) << "----" << theWord << endl;
+ relg = 0L; /* Leave the loop. */
+ }
+ else
+ {
+ /* append the character */
+ theWord.append(newChar);
+
+ /* save the bounding rect */
+ // kdDebug(28000) << "LEFT: " << relr->left << " TOP: " << relr->top << endl;
+ QRect r( relr->left, relr->top, relr->width, relr->height );
+
+ if( brect.isNull() )
+ {
+ brect = r;
+ }
+ else
+ {
+ brect = brect.unite( r );
+ }
+
+ /* next knode */
+ if( relg->next[0] > 0 )
+ {
+ nextKnode = relg->next[0];
+ relg = getGraphKnode( line, nextKnode );
+ }
+ else
+ {
+ /* end of the line */
+ nextKnode = 0;
+ relg = 0L;
+ }
+ }
+ }
+ }
+ return( nextKnode );
+}
+
+
+
+void CRep::partStrings( int line, int graphKnode, QString soFar )
+{
+ /* The following knodes after a word break */
+ Kadmos::RelGraph *relg = getGraphKnode( line, graphKnode );
+ // kdDebug(28000) << "GraphKnode is " << graphKnode << endl;
+
+ QString theWord="";
+ for( int resNo=0; resNo < SEG_ALT; resNo++ )
+ {
+ // kdDebug(28000) << "Alternative " << resNo << " is " << relg->result_number[resNo] << endl;
+ if( relg->result_number[resNo] == -1 )
+ {
+ /* This means that there is no other alternative. Go out here. */
+ break;
+ }
+
+ Kadmos::RelResult *relr = getRelResult( line, relg, resNo );
+ theWord = QChar(relr->rec_char[0][0]);
+
+ if ( !soFar.isEmpty() && relg->leading_blanks )
+ {
+ /* this means the previous words end. */
+ // TODO: This forgets the alternatives of _this_ first character of the new word.
+
+ kdDebug(28000) << "---- " << soFar << endl;
+ m_parts << soFar;
+ break;
+ }
+ else
+ {
+ /* make a QString from this single char and append it. */
+ soFar += theWord;
+ }
+
+ if( relg->next[resNo] > 0 )
+ {
+ /* There is a follower to this knode. Combine the result list from a recursive call
+ * to this function with the follower knode.
+ */
+ partStrings( line, relg->next[resNo], soFar );
+ }
+ else
+ {
+ /* There is no follower */
+ kdDebug(28000) << "No followers - theWord is " << soFar << endl;
+ m_parts<<soFar;
+ break;
+ }
+ }
+}
+
+
+
+void CRep::drawCharBox( QPixmap *pix, const QRect& r )
+{
+ drawBox( pix, r, QColor( Qt::red ));
+}
+
+void CRep::drawLineBox( QPixmap* pix, const QRect& r )
+{
+ drawBox( pix, r, QColor( Qt::blue ));
+}
+
+void CRep::drawBox( QPixmap* pix, const QRect& r, const QColor& color )
+{
+ QPainter p;
+ p.begin(pix);
+
+ p.setPen( color );
+ p.drawRect(r);
+}
+
+
+
+KADMOS_ERROR CRep::SetImage( const QString file )
+{
+ ReImageHandle image_handle;
+ image_handle = re_readimage(file.latin1(), &m_RepData.image);
+ if( ! image_handle )
+ {
+ kdDebug(28000) << "Can not load input file" << endl;
+ }
+ CheckError();
+ return RE_SUCCESS;
+
+}
+
+KADMOS_ERROR CRep::SetImage(QImage *Image)
+{
+ // memcpy(&m_RepData.image, Image.bits(), Image.numBytes());
+ if( !Image ) return RE_PARAMETERERROR;
+
+ kdDebug(28000) << "Setting image manually." << endl;
+ m_RepData.image.data = (void*)Image->bits();
+ m_RepData.image.imgtype = IMGTYPE_PIXELARRAY;
+ m_RepData.image.width = Image->width();
+ m_RepData.image.height = Image->height();
+ m_RepData.image.bitsperpixel = Image->depth();
+ m_RepData.image.alignment = 1;
+ m_RepData.image.fillorder = FILLORDER_MSB2LSB;
+ // color
+ if( Image->depth() == 1 || (Image->numColors()==2 && Image->depth() == 8) )
+ {
+ m_RepData.image.color=COLOR_BINARY;
+ kdDebug(28000) << "Setting Binary" << endl;
+ } else if( Image->isGrayscale() ) {
+ m_RepData.image.color = COLOR_GRAY;
+ kdDebug(28000) << "Setting GRAY" << endl;
+
+ } else {
+ m_RepData.image.color = COLOR_RGB;
+ kdDebug(28000) << "Setting Color RGB" << endl;
+ }
+ // orientation
+ m_RepData.image.orientation = ORIENTATION_TOPLEFT;
+ m_RepData.image.photometric = PHOTOMETRIC_MINISWHITE;
+ m_RepData.image.resunit = RESUNIT_INCH;
+ m_RepData.image.xresolution = 200;
+ m_RepData.image.yresolution = 200;
+
+ CheckError();
+
+ return RE_SUCCESS;
+}
+
+void CRep::SetNoiseReduction(bool bNoiseReduction)
+{
+ if (bNoiseReduction) {
+ m_RepData.parm.prep |= PREP_AUTO_NOISEREDUCTION;
+ }
+ else {
+ m_RepData.parm.prep &= !PREP_AUTO_NOISEREDUCTION;
+ }
+}
+
+void CRep::SetScaling(bool bScaling)
+{
+ if (bScaling) {
+ m_RepData.parm.prep |= PREP_SCALING;
+ }
+ else {
+ m_RepData.parm.prep &= !PREP_SCALING;
+ }
+}
+
+void CRep::CheckError()
+{
+ if ( kadmosError() )
+ {
+ kdDebug(28000) << "KADMOS ERROR: " << getErrorText() << endl;
+ }
+}
+
+/* returns a QString containing the string describing the kadmos error */
+QString CRep::getErrorText() const
+{
+ re_ErrorText Err;
+ re_GetErrorText(&Err);
+ return QString::fromLocal8Bit( Err.text );
+}
+
+bool CRep::kadmosError()
+{
+ return m_Error != RE_SUCCESS;
+}
+
+#include "kadmosocr.moc"
+
+#endif /* HAVE_KADMOS */
+
+
+// } /* End of Kadmos namespace */
diff --git a/kooka/kadmosocr.h b/kooka/kadmosocr.h
new file mode 100644
index 00000000..12056209
--- /dev/null
+++ b/kooka/kadmosocr.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ kadmosocr.h - Kadmos cpp interface
+ -------------------
+ begin : Fri Jun 30 2000
+
+ (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen
+ Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099
+ Website: www.reRecognition.com E-mail: info@reRecognition.com
+
+ Author: Tamas Nagy (nagy@rerecognition.com)
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KADMOS_OCR_
+#define __KADMOS_OCR_
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include "config.h"
+
+#ifdef HAVE_KADMOS
+/* class declarations */
+class QImage;
+class QPixmap;
+class QColor;
+class QStringList;
+class QRect;
+
+
+class ocrWord;
+class ocrWordList;
+
+namespace Kadmos {
+
+/* include files */
+
+#include "kadmos.h"
+#include <qptrlist.h>
+
+/* ---------------------------------------- REP ---------------------------------------- */
+//! Maximum number of lines in a paragraph
+ const int LINE_MAX_LEN = 100;
+ const int GRID_MAX_LEN = 50; //!< Maximum number of grid elements in a line
+ const int GRAPH_MAX_LEN = 500; //!< Maximum number of graph elements in a line
+ const int CHAR_MAX_LEN = 500; //!< Maximum number of characters in a line
+
+ /* Error handling */
+ const char CPP_ERROR[] = "Kadmos CPP interface error";
+
+ /* ==== CRep ========================================= */
+ class CRep : public QObject
+ {
+ Q_OBJECT
+ public:
+ CRep();
+ virtual ~CRep();
+
+ RepResult* getRepResult(int line=0);
+ RelGraph* getGraphKnode(int line, int offset=0);
+ RelResult* getRelResult(int line, Kadmos::RelGraph* graph, int alternative=0);
+
+
+ /**
+ @param ClassifierFilename is a name of a classifier file (*.rec)
+ */
+ KADMOS_ERROR Init(const char* ClassifierFile);
+
+ virtual void run();
+ virtual bool finished() { return true; }
+ // KADMOS_ERROR Recognize();
+ KADMOS_ERROR End();
+
+ /**
+ @param Image is an image object
+ */
+ KADMOS_ERROR SetImage(QImage* Image);
+ KADMOS_ERROR SetImage( const QString );
+ int GetMaxLine();
+
+ ocrWordList getLineWords( int line );
+
+ const char* RepTextLine(int Line, unsigned char RejectLevel=128,
+ int RejectChar='~', long Format=TEXT_FORMAT_ANSI);
+
+ void analyseLine(int, QPixmap* );
+ /** Enable/disable noise reduction
+ @param TRUE(enable)/FALSE(disable) noise reduction
+ */
+ void SetNoiseReduction(bool bNoiseReduction);
+
+ /** Enable/disable scaling (size normalization)
+  @param TRUE(enable)/FALSE(disable) scaling (size normalization)
+ */
+ void SetScaling(bool bScaling);
+
+ /* draw graphic visualiser into the pixmap pointed to */
+ virtual void drawLineBox( QPixmap*, const QRect& );
+ virtual void drawCharBox( QPixmap*, const QRect& );
+ virtual void drawBox( QPixmap*, const QRect&, const QColor& );
+
+ int nextBestWord( int line, int knode, QString& theWord, QRect& brect );
+
+ /* Error text in QString */
+ QString getErrorText() const;
+ bool kadmosError();
+ private:
+ void partStrings( int line, int graphKnode, QString soFar );
+ void CheckError();
+
+ RepData m_RepData;
+ KADMOS_ERROR m_Error;
+ char m_Line[2*CHAR_MAX_LEN];
+ int m_currLine;
+ QStringList m_parts;
+ QString m_theWord;
+ int m_recurse;
+
+ QChar m_undetectChar;
+ };
+
+} /* End of Kadmos namespace */
+
+#endif /* HAVE KADMOS */
+
+#endif /* header tagging */
diff --git a/kooka/kocrbase.cpp b/kooka/kocrbase.cpp
new file mode 100644
index 00000000..889739e7
--- /dev/null
+++ b/kooka/kocrbase.cpp
@@ -0,0 +1,368 @@
+/***************************************************************************
+ kocrbase.cpp - base dialog for ocr
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <kio/job.h>
+#include <kio/previewjob.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+#include <kactivelabel.h>
+#include <qhbox.h>
+#include <qvbox.h>
+
+#include "resource.h"
+#include "kocrbase.h"
+#include "ksaneocr.h"
+#include "kookaimage.h"
+
+#include <kscanslider.h>
+#include <kstandarddirs.h>
+#include <kfilemetainfo.h>
+#include <ksconfig.h>
+#include <qstringlist.h>
+#include <qcolor.h>
+#include <qgrid.h>
+#include <qsizepolicy.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+
+KOCRBase::KOCRBase( QWidget *parent, KSpellConfig *spellConfig,
+ KDialogBase::DialogType face )
+ :KDialogBase( face, i18n("Optical Character Recognition"),
+ User2|Close|User1, User1, parent,0, false, true,
+ KGuiItem( i18n("Start OCR" ), "launch",
+ i18n("Start the Optical Character Recognition process" )),
+ KGuiItem( i18n("Cancel" ), "stopocr",
+ i18n("Stop the OCR Process" ))),
+ m_animation(0L),
+ m_metaBox(0L),
+ m_imgHBox(0L),
+ m_previewPix(0L),
+ m_currImg(0L),
+ m_spellConfig(spellConfig),
+ m_wantSpellCfg(true),
+ m_userWantsSpellCheck(true),
+ m_cbWantCheck(0L),
+ m_gbSpellOpts(0L)
+{
+ kdDebug(28000) << "OCR Base Dialog!" << endl;
+ // Layout-Boxes
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver gs( konf, CFG_OCR_KSPELL );
+ m_userWantsSpellCheck = konf->readBoolEntry(CFG_WANT_KSPELL, true);
+
+ /* Connect signals which disable the fields and store the configuration */
+ connect( this, SIGNAL( user1Clicked()), this, SLOT( writeConfig()));
+ connect( this, SIGNAL( user1Clicked()), this, SLOT( startOCR() ));
+ connect( this, SIGNAL( user2Clicked()), this, SLOT( stopOCR() ));
+ m_previewSize.setWidth(200);
+ m_previewSize.setHeight(300);
+
+ enableButton( User1, true ); /* start ocr */
+ enableButton( User2, false ); /* Cancel */
+ enableButton( Close, true );
+}
+
+
+KAnimWidget* KOCRBase::getAnimation(QWidget *parent)
+{
+ if( ! m_animation )
+ {
+ m_animation = new KAnimWidget( QString("kde"), 48, parent, "ANIMATION" );
+ }
+ return( m_animation );
+}
+
+EngineError KOCRBase::setupGui()
+{
+ ocrIntro();
+ imgIntro();
+ if( m_wantSpellCfg ) spellCheckIntro();
+
+ return ENG_OK;
+}
+
+void KOCRBase::imgIntro()
+{
+ m_imgPage = addVBoxPage( i18n("Image") );
+ (void) new QLabel( i18n("Image Information"), m_imgPage );
+
+ // Caption - Label and image
+ m_imgHBox = new QHBox( m_imgPage );
+
+ m_imgHBox->setSpacing( KDialog::spacingHint());
+
+ m_previewPix = new QLabel( m_imgHBox );
+ m_previewPix->setPixmap(QPixmap());
+ m_previewPix->setFixedSize(m_previewSize);
+ m_previewPix->setAlignment( Qt::AlignCenter );
+ m_previewPix->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ // m_previewPix->resize(m_previewSize);
+
+ /* See introduceImage where the meta box is filled with data from the
+ * incoming widget.
+ */
+ m_metaBox = new QVBox( m_imgHBox );
+}
+
+/*
+ * This creates a Tab OCR
+ */
+void KOCRBase::ocrIntro( )
+{
+ m_ocrPage = addVBoxPage( i18n("OCR") );
+
+ // Caption - Label and image
+ /* labelstring */
+ (void) new QLabel( i18n("<b>Starting Optical Character Recognition with %1</b><p>").
+ arg( ocrEngineName() ), m_ocrPage );
+ // Find the kadmos logo and display if available
+ KStandardDirs stdDir;
+ QString logo = stdDir.findResource( "data", "kooka/pics/" + ocrEngineLogo() );
+
+ kdDebug(28000)<< "Reading logo " << logo << endl;
+ QPixmap pix;
+ QWidget *pa = m_ocrPage;
+
+ if( pix.load( logo ))
+ {
+ QHBox *hb_cap = new QHBox( m_ocrPage );
+ hb_cap->setSpacing( KDialog::spacingHint());
+
+ QLabel *imgLab = new QLabel( hb_cap );
+ imgLab->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
+ imgLab->setPixmap( pix );
+ pa = hb_cap;
+ }
+
+ (void) new KActiveLabel( ocrEngineDesc(), pa );
+}
+
+
+void KOCRBase::spellCheckIntro()
+{
+ m_spellchkPage = addVBoxPage( i18n("Spell-checking") );
+
+ /* Want the spell checking at all? Checkbox here */
+ QGroupBox *gb1 = new QGroupBox( 1, Qt::Horizontal, i18n("OCR Post Processing"), m_spellchkPage );
+ m_cbWantCheck = new QCheckBox( i18n("Enable spell-checking for validation of the OCR result"),
+ gb1 );
+ /* Spellcheck options */
+ m_gbSpellOpts = new QGroupBox( 1, Qt::Horizontal, i18n("Spell-Check Options"),
+ m_spellchkPage );
+
+ KSpellConfig *sCfg = new KSpellConfig( m_gbSpellOpts, "SPELLCHK", m_spellConfig, false );
+ /* A space eater */
+ QWidget *spaceEater = new QWidget(m_spellchkPage);
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+
+ /* connect toggle button */
+ connect( m_cbWantCheck, SIGNAL(toggled(bool)), this, SLOT(slWantSpellcheck(bool)));
+ m_cbWantCheck->setChecked( m_userWantsSpellCheck );
+ m_gbSpellOpts->setEnabled( m_userWantsSpellCheck );
+ m_spellConfig = sCfg;
+
+ connect( sCfg, SIGNAL(configChanged()),
+ this, SLOT(slSpellConfigChanged()));
+}
+
+void KOCRBase::slSpellConfigChanged()
+{
+ kdDebug(28000) << "Spellcheck config changed" << endl;
+}
+
+
+
+void KOCRBase::stopAnimation()
+{
+ if( m_animation )
+ m_animation->stop();
+}
+
+void KOCRBase::startAnimation()
+{
+ if( m_animation )
+ m_animation->start();
+}
+
+KOCRBase::~KOCRBase()
+{
+
+}
+
+void KOCRBase::introduceImage( KookaImage* img)
+{
+ if( ! (img && img->isFileBound()) ) return;
+ KFileMetaInfo info = img->fileMetaInfo();
+ QStringList groups;
+ if ( info.isValid() )
+ groups = info.preferredGroups();
+
+ delete m_metaBox;
+ m_metaBox = new QVBox( m_imgHBox );
+
+ /* Start to create a preview job for the thumb */
+ KURL::List li(img->url());
+ KIO::Job *m_job = KIO::filePreview(li, m_previewSize.width(),
+ m_previewSize.height());
+
+ if( m_job )
+ {
+ connect( m_job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slPreviewResult( KIO::Job * )));
+ connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
+ SLOT( slGotPreview( const KFileItem*, const QPixmap& ) ));
+ /* KIO::Jo result is called in any way: Success, Failed, Error,
+ * thus connecting the failed is not really necessary.
+ */
+ }
+
+ for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it )
+ {
+ QString theGroup(*it);
+
+ kdDebug(29000) << "handling the group " << theGroup << endl;
+
+ QStringList keys = info.group(theGroup).supportedKeys();
+
+ if( keys.count() > 0 )
+ {
+ // info.groupInfo( theGroup )->translatedName()
+ // FIXME: howto get the translated group name?
+ QLabel *lGroup = new QLabel( theGroup, m_metaBox );
+ lGroup->setBackgroundColor( QColor(gray));
+ lGroup->setMargin( KDialog::spacingHint());
+
+ QGrid *nGrid = new QGrid( 2, m_metaBox );
+ nGrid->setSpacing( KDialog::spacingHint());
+ for ( QStringList::Iterator keyIt = keys.begin(); keyIt != keys.end(); ++keyIt )
+ {
+ KFileMetaInfoItem item = info.item(*keyIt);
+ QString itKey = item.translatedKey();
+ if( itKey.isEmpty() )
+ itKey = item.key();
+ if( ! itKey.isEmpty() )
+ {
+ (void) new QLabel( item.translatedKey() + ": ", nGrid );
+ (void) new QLabel( item.string(), nGrid );
+ kdDebug(29000) << "hasKey " << *keyIt << endl;
+ }
+ }
+ }
+ }
+ QWidget *spaceEater = new QWidget( m_metaBox );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ m_metaBox->show();
+}
+
+void KOCRBase::slPreviewResult(KIO::Job *job )
+{
+ // nothing
+ if( job && job->error() > 0 )
+ {
+ kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl;
+ job->showErrorDialog( 0 );
+ }
+}
+
+void KOCRBase::slGotPreview( const KFileItem*, const QPixmap& newPix )
+{
+ kdDebug(28000) << "Got the preview" << endl;
+ m_previewPix->setPixmap(newPix);
+
+ if( m_previewPix && m_currImg )
+ {
+ m_previewPix->setPixmap(newPix);
+ }
+}
+
+
+void KOCRBase::writeConfig()
+{
+
+}
+
+bool KOCRBase::wantSpellCheck()
+{
+ return m_userWantsSpellCheck;
+}
+
+void KOCRBase::startOCR()
+{
+ /* en- and disable the buttons */
+ kdDebug(28000) << "Base: Starting OCR" << endl;
+
+ enableFields(false);
+ enableButton( User1, false ); /* Start OCR */
+ enableButton( User2, true ); /* Stop OCR */
+ enableButton( Close, true );
+
+ startAnimation();
+}
+
+void KOCRBase::stopOCR()
+{
+ enableFields(true);
+
+ enableButton( User1, true ); /* start ocr */
+ enableButton( User2, false ); /* Cancel */
+ enableButton( Close, true );
+
+ stopAnimation();
+
+}
+
+void KOCRBase::enableFields(bool)
+{
+
+}
+
+void KOCRBase::slWantSpellcheck( bool wantIt )
+{
+ if( m_gbSpellOpts )
+ {
+ m_gbSpellOpts->setEnabled( wantIt );
+ }
+ m_userWantsSpellCheck = wantIt;
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver gs( konf, CFG_OCR_KSPELL );
+ konf->writeEntry( CFG_WANT_KSPELL, wantIt );
+}
+
+/* The End ;) */
+#include "kocrbase.moc"
diff --git a/kooka/kocrbase.h b/kooka/kocrbase.h
new file mode 100644
index 00000000..05987b1d
--- /dev/null
+++ b/kooka/kocrbase.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ kocrbase.h - base dialog for OCR
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOCRBASE_H
+#define KOCRBASE_H
+
+#include <kdialogbase.h>
+#include <kio/previewjob.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+#include <ksconfig.h>
+
+#include "ksaneocr.h"
+/**
+ *@author Klaas Freitag
+ */
+
+
+class KookaImage;
+class QHBox;
+class QVBox;
+class QLabel;
+class QSize;
+class KSpellConfig;
+class QCheckBox;
+class QGroupBox;
+
+class KOCRBase: public KDialogBase
+{
+ Q_OBJECT
+public:
+ KOCRBase( QWidget *, KSpellConfig *spellConfig,
+ KDialogBase::DialogType face = KDialogBase::Plain );
+ ~KOCRBase();
+
+ virtual EngineError setupGui();
+
+ /**
+ * @return the name of the ocr engine
+ */
+ virtual QString ocrEngineName() const { return QString(); }
+
+ /**
+ * @return the filename (without path) of the logo of the ocr engine.
+ * the logo needs to be installed in $KDEDIR/share/apps/kooka/pics
+ */
+ virtual QString ocrEngineLogo() const { return QString(); }
+
+ /**
+ * @return a description string of the ocr engine
+ */
+ virtual QString ocrEngineDesc() const { return QString(); }
+
+ QVBox* ocrPage() const { return m_ocrPage; }
+ QVBox* imagePage() const { return m_imgPage; }
+
+ KSpellConfig* spellConfig() const
+ { return m_spellConfig; }
+
+ bool wantSpellCheck();
+
+public slots:
+ virtual void stopAnimation();
+ virtual void startAnimation();
+
+ virtual void introduceImage( KookaImage* );
+
+ virtual void startOCR();
+ virtual void stopOCR();
+ /**
+ * enable or disable dialog fields. This slot is called when the ocr process starts
+ * with parameter state=false and called again if the gui should accept user input
+ * again after ocr finished with parameter true.
+ */
+ virtual void enableFields(bool state);
+
+protected:
+ /**
+ * This creates a a tab OCR in the dialog and creates a small intro about the
+ * ocr engine used.
+ * It calls the virtual subs ocrEngineName, ocrEngineLogo and ocrEngineDesc which
+ * must return the approbiate values for the engines.
+ * @return a pointer to a VBox in which further elements can be layouted
+ */
+ virtual void ocrIntro();
+
+ /**
+ * This creates a a tab Image Info in the dialog and creates a image description
+ * about the current image to ocr.
+ */
+ virtual void imgIntro();
+
+ /**
+ * This sets up the spellchecking configuration
+ */
+ virtual void spellCheckIntro();
+
+
+protected slots:
+ virtual KAnimWidget* getAnimation(QWidget*);
+ virtual void writeConfig();
+ virtual void slSpellConfigChanged();
+
+ /**
+ * hit if the user toggles the want-spellcheck checkbox
+ */
+ virtual void slWantSpellcheck( bool wantIt );
+
+private slots:
+ virtual void slPreviewResult( KIO::Job* );
+ virtual void slGotPreview( const KFileItem*, const QPixmap& );
+
+private:
+ KAnimWidget *m_animation;
+ QVBox *m_ocrPage;
+ QVBox *m_imgPage;
+ QVBox *m_spellchkPage;
+ QVBox *m_metaBox;
+ QHBox *m_imgHBox;
+ QLabel *m_previewPix;
+ KookaImage *m_currImg;
+
+ KSpellConfig *m_spellConfig;
+ bool m_wantSpellCfg; /* show the spellcheck options? */
+ bool m_userWantsSpellCheck; /* user has enabled/disabled spellcheck */
+ QSize m_previewSize;
+
+ QCheckBox *m_cbWantCheck;
+ QGroupBox *m_gbSpellOpts;
+};
+
+#endif
diff --git a/kooka/kocrgocr.cpp b/kooka/kocrgocr.cpp
new file mode 100644
index 00000000..cfc4c92c
--- /dev/null
+++ b/kooka/kocrgocr.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+ kocrgocr.cpp - GOCR ocr dialog
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+
+#include "resource.h"
+#include "ksaneocr.h" // TODO: Really needed?
+#include "kocrgocr.h"
+#include "kocrgocr.moc"
+#include <kscanslider.h>
+#include "kookaimage.h"
+#include "kookapref.h"
+#include <qvbox.h>
+#include <qhbox.h>
+
+/* defines for konfig-reading */
+
+#define CFG_GOCR_DUSTSIZE "gocrDustSize"
+#define CFG_GOCR_GRAYLEVEL "gocrGrayLevel"
+#define CFG_GOCR_SPACEWIDTH "gocrSpaceWidth"
+
+
+
+KGOCRDialog::KGOCRDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_ocrCmd( QString())
+{
+ kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl;
+ // Layout-Boxes
+}
+
+QString KGOCRDialog::ocrEngineLogo() const
+{
+ return "gocr.png";
+}
+
+QString KGOCRDialog::ocrEngineName() const
+{
+ return i18n("GOCR" );
+}
+
+QString KGOCRDialog::ocrEngineDesc() const
+{
+ return i18n("GOCR is an Open Source project "
+ "for optical character recognition.<P>"
+ "The author of gocr is <B>Joerg Schulenburg</B><BR>"
+ "For more information about gocr see "
+ "<A HREF=http://jocr.sourceforge.net>"
+ "http://jocr.sourceforge.net</A>");
+}
+
+EngineError KGOCRDialog::setupGui()
+{
+ KOCRBase::setupGui();
+
+ QVBox *page = ocrPage();
+ Q_CHECK_PTR( page );
+
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ // Horizontal line
+ // (void) new KSeparator( KSeparator::HLine, page);
+
+ // Entry-Field.
+ QString res = conf->readPathEntry( CFG_GOCR_BINARY, "notFound" );
+ if( res == "notFound" )
+ {
+ res = KookaPreferences::tryFindGocr();
+ if( res.isEmpty() )
+ {
+ /* Popup here telling that the config needs to be called */
+ KMessageBox::sorry( this, i18n( "The path to the gocr binary is not configured yet.\n"
+ "Please go to the Kooka configuration and enter the path manually."),
+ i18n("OCR Software Not Found") );
+ }
+ }
+
+ if( res.isEmpty() )
+ res = i18n("Not found");
+ else
+ m_ocrCmd = res;
+
+ (void) new QLabel( i18n("Using GOCR binary: ") + res, page );
+ (void) new KSeparator( KSeparator::HLine, page);
+
+ QHBox *hb = new QHBox(page);
+ hb->setSpacing( KDialog::spacingHint());
+ QVBox *innerBox = new QVBox( hb );
+ innerBox->setSpacing( KDialog::spacingHint());
+ /* This is for a 'work-in-progress'-Animation */
+ getAnimation(hb);
+
+ /* Slider for OCR-Options */
+ sliderGrayLevel = new KScanSlider( innerBox , i18n("&Gray level"), 0, 254, true, 160 );
+ int numdefault = conf->readNumEntry( CFG_GOCR_GRAYLEVEL, 160 );
+ sliderGrayLevel->slSetSlider( numdefault );
+ QToolTip::add( sliderGrayLevel,
+ i18n( "The numeric value gray pixels are \nconsidered to be black.\n\nDefault is 160"));
+
+ sliderDustSize = new KScanSlider( innerBox, i18n("&Dust size" ), 0, 60, true, 10 );
+ numdefault = conf->readNumEntry( CFG_GOCR_DUSTSIZE, 10 );
+ sliderDustSize->slSetSlider( numdefault );
+ QToolTip::add( sliderDustSize,
+ i18n( "Clusters smaller than this value\nwill be considered to be dust and \nremoved from the image.\n\nDefault is 10"));
+
+ sliderSpace = new KScanSlider( innerBox, i18n( "&Space width" ), 0, 60, true, 0 );
+ numdefault = conf->readNumEntry( CFG_GOCR_SPACEWIDTH, 0 );
+ sliderSpace->slSetSlider( numdefault );
+ QToolTip::add( sliderSpace, i18n("Spacing between characters.\n\nDefault is 0 what means autodetection"));
+
+ return ENG_OK;
+}
+
+void KGOCRDialog::introduceImage( KookaImage *img )
+{
+ if( !img ) return;
+
+ KOCRBase::introduceImage( img );
+
+
+ bool isOn = true;
+
+ if( img->numColors() > 0 && img->numColors() <3 )
+ {
+ kdDebug(29000) << "introduceImage: Have " << img->numColors() << " colors on depth " << img->depth() << endl;
+
+ /* that means it is a black-and-white image. Thus we do not need the GrayLevel slider */
+ isOn = false;
+ }
+
+ if( sliderGrayLevel )
+ sliderGrayLevel->setEnabled( isOn );
+
+}
+
+
+KGOCRDialog::~KGOCRDialog()
+{
+
+}
+
+void KGOCRDialog::writeConfig( void )
+{
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ conf->writeEntry( CFG_GOCR_BINARY, QString(getOCRCmd()));
+ conf->writeEntry( CFG_GOCR_GRAYLEVEL, getGraylevel());
+ conf->writeEntry( CFG_GOCR_DUSTSIZE, getDustsize());
+ conf->writeEntry( CFG_GOCR_SPACEWIDTH, getSpaceWidth());
+}
+
+
+void KGOCRDialog::enableFields(bool b)
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+ sliderGrayLevel->setEnabled( b );
+ sliderDustSize->setEnabled( b );
+ sliderSpace->setEnabled( b );
+}
+
+/* The End ;) */
+
diff --git a/kooka/kocrgocr.h b/kooka/kocrgocr.h
new file mode 100644
index 00000000..619cfedd
--- /dev/null
+++ b/kooka/kocrgocr.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ kocrgocr.h - ocr dialog for GOCR
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCRGOCR_H
+#define KOCRGOCR_H
+
+#include <kdialogbase.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+
+#include "kocrbase.h"
+/**
+ *@author Klaas Freitag
+ */
+
+class KSpellConfig;
+
+class KGOCRDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ KGOCRDialog( QWidget*, KSpellConfig* );
+ ~KGOCRDialog();
+
+ QString getOCRCmd( void ) const
+ { return m_ocrCmd;}
+
+ int getGraylevel( void ) const
+ { return( sliderGrayLevel->value());}
+ int getDustsize( void ) const
+ { return( sliderDustSize->value());}
+ int getSpaceWidth( void ) const
+ { return( sliderSpace->value());}
+
+ EngineError setupGui();
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+public slots:
+ void enableFields(bool);
+ void introduceImage( KookaImage* );
+
+protected:
+ void writeConfig();
+
+
+private:
+
+
+ KScanSlider *sliderGrayLevel;
+ KScanSlider *sliderDustSize;
+ KScanSlider *sliderSpace;
+
+ QString m_ocrCmd;
+};
+
+#endif
diff --git a/kooka/kocrkadmos.cpp b/kooka/kocrkadmos.cpp
new file mode 100644
index 00000000..b4d58244
--- /dev/null
+++ b/kooka/kocrkadmos.cpp
@@ -0,0 +1,521 @@
+/***************************************************************************
+ kocrstartdia.cpp - description
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+#include <qdict.h>
+#include <qdir.h>
+#include <qmap.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+
+#include "resource.h"
+#include "ksaneocr.h" // TODO: Really needed?
+#include "kocrkadmos.h"
+#include "kocrkadmos.moc"
+
+#include <kscanslider.h>
+#include <qcheckbox.h>
+#include <kstandarddirs.h>
+#include <qstringlist.h>
+
+
+/* defines for konfig-reading */
+#define CFG_GROUP_KADMOS "Kadmos"
+#define CFG_KADMOS_CLASSIFIER_PATH "classifierPath"
+#define CFG_KADMOS_CLASSIFIER "classifier"
+
+
+#define CNTRY_CZ i18n( "Czech Republic, Slovakia")
+#define CNTRY_GB i18n( "Great Britain, USA" )
+
+KadmosDialog::KadmosDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_cbNoise(0),
+ m_cbAutoscale(0),
+ m_haveNorm(false)
+{
+ kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl;
+ // Layout-Boxes
+ findClassifiers();
+}
+
+QString KadmosDialog::ocrEngineLogo() const
+{
+ return "kadmoslogo.png";
+}
+
+QString KadmosDialog::ocrEngineName() const
+{
+ return i18n("KADMOS OCR/ICR");
+}
+
+QString KadmosDialog::ocrEngineDesc() const
+{
+ return i18n("This version of Kooka was linked with the <I>KADMOS OCR/ICR engine</I>, a "
+ "commercial engine for optical character recognition.<P>"
+ "Kadmos is a product of <B>re Recognition AG</B><BR>"
+ "For more information about Kadmos OCR see "
+ "<A HREF=http://www.rerecognition.com>"
+ "http://www.rerecognition.com</A>");
+}
+
+
+EngineError KadmosDialog::findClassifiers()
+{
+ findClassifierPath();
+
+ KLocale *locale = KGlobal::locale();
+ QStringList allCountries = locale->allLanguagesTwoAlpha ();
+ for ( QStringList::Iterator it = allCountries.begin();
+ it != allCountries.end(); ++it )
+ {
+ m_longCountry2short[locale->twoAlphaToCountryName(*it)] = *it;
+ }
+ m_longCountry2short[i18n("European Countries")] = "eu";
+ m_longCountry2short[ CNTRY_CZ ] = "cz";
+ m_longCountry2short[ CNTRY_GB ] = "us";
+
+ QStringList lst;
+
+ /* custom Path */
+ if( ! m_customClassifierPath.isEmpty() )
+ {
+ QDir dir( m_customClassifierPath );
+
+ QStringList lst1 = dir.entryList( "ttf*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+
+ lst1 = dir.entryList( "hand*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+
+ lst1 = dir.entryList( "norm*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+ }
+ else
+ {
+ /* standard location */
+ KStandardDirs stdDir;
+ kdDebug(28000) << "Starting to read resource" << endl;
+
+ lst = stdDir.findAllResources( "data",
+ "kooka/classifiers/*.rec",
+ true, /* recursive */
+ true ); /* uniqu */
+ }
+
+
+ /* no go through lst and sort out hand-, ttf- and norm classifier */
+ for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it )
+ {
+ QFileInfo fi( *it);
+ QString name = fi.fileName().lower();
+
+ kdDebug(28000) << "Checking file " << *it << endl;
+
+ if( name.startsWith( "ttf" ) )
+ {
+ QString lang = name.mid(3,2);
+ if( allCountries.contains(lang) )
+ {
+ QString lngCountry = locale->twoAlphaToCountryName(lang);
+ if( lngCountry.isEmpty() )
+ lngCountry = name;
+ m_ttfClassifier << lngCountry;
+ kdDebug(28000) << "ttf: Insert country " << lngCountry << endl;
+ }
+ else if( lang == "cz" )
+ {
+ m_ttfClassifier << CNTRY_CZ;
+ }
+ else if( lang == "us" )
+ {
+ m_ttfClassifier << CNTRY_GB;
+ }
+ else
+ {
+ m_ttfClassifier << name;
+ kdDebug(28000) << "ttf: Unknown country" << endl;
+ }
+ }
+ else if( name.startsWith( "hand" ) )
+ {
+ QString lang = name.mid(4,2);
+ if( allCountries.contains(lang) )
+ {
+ QString lngCountry = locale->twoAlphaToCountryName(lang);
+ if( lngCountry.isEmpty() )
+ lngCountry = name;
+ m_handClassifier << lngCountry;
+ }
+ else if( lang == "cz" )
+ {
+ m_handClassifier << i18n( "Czech Republic, Slovakia");
+ }
+ else if( lang == "us" )
+ {
+ m_handClassifier << i18n( "Great Britain, USA" );
+ }
+ else
+ {
+ kdDebug(28000) << "Hand: Unknown country " << lang << endl;
+ m_handClassifier << name;
+ }
+ }
+ else if( name.startsWith( "norm" ))
+ {
+ m_haveNorm = true;
+ }
+
+ kdDebug(28000) << "Found classifier: " << *it << endl;
+ m_classifierPath << *it;
+ }
+
+ if( m_handClassifier.count()+m_ttfClassifier.count()>0 )
+ {
+ /* There are classifiers */
+ return ENG_OK;
+ }
+ else
+ {
+ /* Classifier are missing */
+ return ENG_DATA_MISSING;
+ }
+}
+
+
+EngineError KadmosDialog::findClassifierPath()
+{
+ KStandardDirs stdDir;
+ EngineError err = ENG_OK;
+
+ KConfig *conf = KGlobal::config ();
+ KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS );
+
+ m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH );
+#if 0
+ if( m_customClassifierPath == "NotFound" )
+ {
+ /* Wants the classifiers from the standard kde paths */
+ KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n"
+ "OCR with KADMOS will not be possible!\n\n"
+ "Change the OCR engine in the preferences dialog."),
+ i18n("Installation Error") );
+ }
+ else
+ {
+ m_classifierPath = customPath;
+ }
+#endif
+ return err;
+
+}
+
+
+EngineError KadmosDialog::setupGui()
+{
+
+ EngineError err = KOCRBase::setupGui();
+
+ // setupPreprocessing( addVBoxPage( i18n("Preprocessing")));
+ // setupSegmentation( addVBoxPage( i18n("Segmentation")));
+ // setupClassification( addVBoxPage( i18n("Classification")));
+
+ /* continue page setup on the first page */
+ QVBox *page = ocrPage();
+
+ // Horizontal line
+ (void) new KSeparator( KSeparator::HLine, page);
+
+ // FIXME: dynamic classifier reading.
+
+ (void) new QLabel( i18n("Please classify the font type and language of the text on the image:"),
+ page );
+ QHBox *locBox = new QHBox( page );
+ m_bbFont = new QButtonGroup(1, Qt::Horizontal, i18n("Font Type Selection"), locBox);
+
+ m_rbMachine = new QRadioButton( i18n("Machine print"), m_bbFont );
+ m_rbHand = new QRadioButton( i18n("Hand writing"), m_bbFont );
+ m_rbNorm = new QRadioButton( i18n("Norm font"), m_bbFont );
+
+ m_gbLang = new QGroupBox(1, Qt::Horizontal, i18n("Country"), locBox);
+
+
+ m_cbLang = new QComboBox( m_gbLang );
+ m_cbLang->setCurrentText( KLocale::defaultCountry() );
+
+ connect( m_bbFont, SIGNAL(clicked(int)), this, SLOT(slFontChanged(int) ));
+ m_rbMachine->setChecked(true);
+
+ /* --- */
+ QHBox *innerBox = new QHBox( page );
+ innerBox->setSpacing( KDialog::spacingHint());
+
+ QButtonGroup *cbGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Modifier"), innerBox );
+ Q_CHECK_PTR(cbGroup);
+
+ m_cbNoise = new QCheckBox( i18n( "Enable automatic noise reduction" ), cbGroup );
+ m_cbAutoscale = new QCheckBox( i18n( "Enable automatic scaling"), cbGroup );
+
+ getAnimation(innerBox);
+ // (void) new QWidget ( page );
+
+ if( err != ENG_OK )
+ {
+ enableFields(false);
+ enableButton(User1, false );
+ }
+
+ if( m_ttfClassifier.count() == 0 )
+ {
+ m_rbMachine->setEnabled(false);
+ }
+ if( m_handClassifier.count() == 0 )
+ {
+ m_rbHand->setEnabled(false);
+ }
+ if( !m_haveNorm )
+ m_rbNorm->setEnabled(false);
+
+ if( (m_ttfClassifier.count() + m_handClassifier.count()) == 0 && ! m_haveNorm )
+ {
+ KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n"
+ "OCR with KADMOS will not be possible!\n\n"
+ "Change the OCR engine in the preferences dialog."),
+ i18n("Installation Error") );
+ err = ENG_BAD_SETUP;
+ }
+ else
+ slFontChanged( 0 ); // Load machine print font language list
+ return err;
+}
+
+void KadmosDialog::slFontChanged( int id )
+{
+ m_cbLang->clear();
+
+ KConfig *conf = KGlobal::config ();
+ KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS );
+
+
+
+ m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH );
+
+ bool enable = true;
+
+ if( id == 0 ) /* Machine Print */
+ {
+ m_cbLang->insertStringList( m_ttfClassifier );
+ }
+ else if( id == 1 ) /* Hand Writing */
+ {
+ m_cbLang->insertStringList( m_handClassifier );
+ }
+ else if( id == 2 ) /* Norm Font */
+ {
+ enable = false;
+ }
+ m_cbLang->setEnabled( enable );
+}
+
+
+void KadmosDialog::setupPreprocessing( QVBox* )
+{
+
+}
+
+void KadmosDialog::setupSegmentation( QVBox* )
+{
+
+}
+
+void KadmosDialog::setupClassification( QVBox* )
+{
+
+}
+/*
+ * returns the complete path of the classifier selected in the
+ * GUI in the parameter path. The result value indicates if there
+ * was one found.
+ */
+
+bool KadmosDialog::getSelClassifier( QString& path ) const
+{
+ QString classifier = getSelClassifierName();
+
+ QString cmplPath;
+ /*
+ * Search the complete path for the classifier file name
+ * returned from the getSelClassifierName method
+ */
+ for ( QStringList::ConstIterator it = m_classifierPath.begin();
+ it != m_classifierPath.end(); ++it )
+ {
+ QFileInfo fi( *it );
+ if( fi.fileName() == classifier )
+ {
+ cmplPath = *it;
+ break;
+ }
+ }
+
+ bool res = true;
+
+ if( cmplPath.isEmpty() )
+ {
+ /* hm, no path was found */
+ kdDebug(28000) << "ERR; The entire path is empty, joking?" << endl;
+ res = false;
+ }
+ else
+ {
+ /* Check if the classifier exists on the HD. If not, return an empty string */
+ QFileInfo fi(cmplPath);
+
+ if( res && ! fi.exists() )
+ {
+ kdDebug(28000) << "Classifier file does not exist" << endl;
+ path = i18n("Classifier file %1 does not exist").arg(classifier);
+ res = false;
+ }
+
+ if( res && ! fi.isReadable() )
+ {
+ kdDebug(28000) << "Classifier file could not be read" << endl;
+ path = i18n("Classifier file %1 is not readable").arg(classifier);
+ res = false;
+ }
+
+ if( res )
+ path = cmplPath;
+ }
+ return res;
+}
+
+QString KadmosDialog::getSelClassifierName() const
+{
+ QButton *butt = m_bbFont->selected();
+
+ QString fType, rType;
+
+ if( butt )
+ {
+ int fontTypeID = m_bbFont->id(butt);
+ if( fontTypeID == 0 )
+ fType = "ttf";
+ else if( fontTypeID == 1 )
+ fType = "hand";
+ else if( fontTypeID == 2 )
+ fType = "norm";
+ else
+ kdDebug(28000) << "ERR: Wrong Font Type ID" << endl;
+ }
+
+ /* Get the long text from the combo box */
+ QString selLang = m_cbLang->currentText();
+ QString trans;
+ if( fType != "norm" && m_longCountry2short.contains( selLang ))
+ {
+ QString langType = m_longCountry2short[selLang];
+ trans = fType+langType+".rec";
+ }
+ else
+ {
+ if( selLang.endsWith( ".rec" ))
+ {
+ /* can be a undetected */
+ trans = selLang;
+ }
+ else if( fType == "norm" )
+ {
+ trans = "norm.rec";
+ }
+ else
+ kdDebug(28000) << "ERROR: Not a valid classifier" << endl;
+ }
+ kdDebug(28000) << "Returning trans. "<< trans << endl;
+ return( trans );
+}
+
+bool KadmosDialog::getAutoScale()
+{
+ return( m_cbAutoscale ? m_cbAutoscale->isChecked() : false );
+}
+
+bool KadmosDialog::getNoiseReduction()
+{
+ return( m_cbNoise ? m_cbNoise->isChecked() : false );
+
+}
+
+KadmosDialog::~KadmosDialog()
+{
+
+}
+
+void KadmosDialog::writeConfig( void )
+{
+
+}
+
+
+void KadmosDialog::enableFields( bool state )
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+ m_cbNoise->setEnabled( state );
+ m_cbAutoscale->setEnabled( state );
+
+ m_bbFont->setEnabled( state );
+ m_gbLang->setEnabled( state );
+}
+
+
+/* The End ;) */
+
diff --git a/kooka/kocrkadmos.h b/kooka/kocrkadmos.h
new file mode 100644
index 00000000..38247cc9
--- /dev/null
+++ b/kooka/kocrkadmos.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ kocrkadmos.h - ocr dialog for KADMOS ocr engine
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCRKADMOS_H
+#define KOCRKADMOS_H
+
+#include <kdialogbase.h>
+#include <qmap.h>
+
+#include "kocrbase.h"
+/**
+ *@author Klaas Freitag
+ */
+
+
+
+class KScanCombo;
+class QWidget;
+class QButtonGroup;
+class KConfig;
+class QCheckBox;
+class KSpellConfig;
+class QRadioButton;
+
+class KadmosClassifier /* Not yet used FIXME */
+{
+public:
+ KadmosClassifier( QString lang, QString filename );
+ QString getCmplFilename() const { return path+filename; }
+ QString getFilename() const { return filename; }
+ QString language() const { return languagesName; }
+
+ void setPath( const QString& p ) { path=p; }
+private:
+
+ QString filename;
+ QString path;
+ QString languagesName;
+};
+
+
+class KadmosDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ KadmosDialog( QWidget *, KSpellConfig *spellConfig );
+ ~KadmosDialog();
+
+ typedef QMap<QString, QString> StrMap;
+
+ EngineError setupGui();
+ bool getAutoScale();
+ bool getNoiseReduction();
+ bool getSelClassifier(QString&) const;
+ QString getSelClassifierName() const;
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+public slots:
+ void enableFields(bool);
+
+protected:
+ void writeConfig();
+
+ void setupPreprocessing( QVBox *box );
+ void setupSegmentation( QVBox *box );
+ void setupClassification( QVBox *box );
+
+ EngineError findClassifiers();
+ EngineError findClassifierPath();
+private slots:
+
+ void slFontChanged( int id );
+
+private:
+ StrMap m_classifierTranslate;
+
+ QCheckBox *m_cbNoise;
+ QCheckBox *m_cbAutoscale;
+ QString m_customClassifierPath;
+
+ QButtonGroup *m_bbFont;
+
+ QRadioButton *m_rbMachine;
+ QRadioButton *m_rbHand;
+ QRadioButton *m_rbNorm;
+
+ QGroupBox *m_gbLang;
+
+ QComboBox *m_cbLang;
+
+ QStringList m_ttfClassifier;
+ QStringList m_handClassifier;
+ QStringList m_classifierPath;
+
+ bool m_haveNorm;
+
+ typedef QMap<QString, QString> StringMap;
+ StringMap m_longCountry2short;
+};
+
+#endif
diff --git a/kooka/kocrocrad.cpp b/kooka/kocrocrad.cpp
new file mode 100644
index 00000000..1ce94f65
--- /dev/null
+++ b/kooka/kocrocrad.cpp
@@ -0,0 +1,263 @@
+/***************************************************************************
+ kocrocrad.cpp - ocrad dialog
+ -------------------
+ begin : Tue Jul 15 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+#include <kurlrequester.h>
+#include <kprocess.h>
+
+#include "resource.h"
+#include "kocrocrad.h"
+#include <kscanslider.h>
+#include "kookaimage.h"
+#include "kookapref.h"
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qcombobox.h>
+
+
+
+ocradDialog::ocradDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_ocrCmd( QString()),
+ m_orfUrlRequester(0L),
+ m_layoutMode(0),
+ m_binaryLabel(0),
+ m_proc(0),
+ m_version(0)
+{
+ kdDebug(28000) << "Starting ocrad-Start-Dialog!" << endl;
+ // Layout-Boxes
+}
+
+QString ocradDialog::ocrEngineLogo() const
+{
+ return "ocrad.png";
+}
+
+QString ocradDialog::ocrEngineName() const
+{
+ return i18n("ocrad" );
+}
+
+QString ocradDialog::ocrEngineDesc() const
+{
+ return i18n("ocrad is a Free Software project "
+ "for optical character recognition.<p>"
+ "The author of ocrad is <b>Antonio Diaz</b><br>"
+ "For more information about ocrad see "
+ "<A HREF=\"http://www.gnu.org/software/ocrad/ocrad.html\">"
+ "http://www.gnu.org/software/ocrad/ocrad.html</A><p>"
+ "Images should be scanned in black/white mode for ocrad.<br>"
+ "Best results are achieved if the characters are at least 20 pixels high.<p>"
+ "Problems arise, as usual, with very bold or very light or broken characters, "
+ "the same with merged character groups.");
+}
+
+
+int ocradDialog::layoutDetectionMode() const
+{
+ return m_layoutMode->currentItem();
+}
+
+EngineError ocradDialog::setupGui()
+{
+ KOCRBase::setupGui();
+
+ QVBox *page = ocrPage();
+ Q_CHECK_PTR( page );
+
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ // Horizontal line
+ // (void) new KSeparator( KSeparator::HLine, page);
+
+ // Entry-Field.
+ QString res = conf->readPathEntry( CFG_OCRAD_BINARY, "notFound" );
+ if( res == "notFound" )
+ {
+ res = KookaPreferences::tryFindBinary("ocrad", CFG_OCRAD_BINARY);
+ if( res.isEmpty() )
+ {
+ /* Popup here telling that the config needs to be called */
+ KMessageBox::sorry( this, i18n( "The path to the ocrad binary is not configured yet.\n"
+ "Please go to the Kooka configuration and enter the path manually."),
+ i18n("OCR Software Not Found") );
+ }
+ }
+
+ if( res.isEmpty() )
+ res = i18n("Not found");
+ else
+ m_ocrCmd = res;
+
+ /** layout detection button **/
+ conf->setGroup( CFG_GROUP_OCRAD );
+ int layoutDetect = conf->readNumEntry( CFG_OCRAD_LAYOUT_DETECTION, 0 );
+ kdDebug(28000) << "Layout detection from config: " << layoutDetect << endl;
+
+ (void) new KSeparator( KSeparator::HLine, page);
+ QHBox *hb1 = new QHBox(page);
+ hb1->setSpacing( KDialog::spacingHint() );
+ (void) new QLabel( i18n("OCRAD layout analysis mode: "), hb1);
+ m_layoutMode = new QComboBox(hb1);
+ m_layoutMode->insertItem(i18n("No Layout Detection"), 0 );
+ m_layoutMode->insertItem(i18n("Column Detection"), 1 );
+ m_layoutMode->insertItem(i18n("Full Layout Detection"), 2);
+ m_layoutMode->setCurrentItem(layoutDetect);
+
+ /** stating the ocrad binary **/
+ (void) new KSeparator( KSeparator::HLine, page);
+ QHBox *hb = new QHBox(page);
+ hb->setSpacing( KDialog::spacingHint());
+
+ m_binaryLabel = new QLabel( i18n("Using ocrad binary: ") + res, hb );
+
+ // retrieve Program version and display
+ version(res);
+
+ getAnimation(hb);
+
+ /* This is for a 'work-in-progress'-Animation */
+
+ return ENG_OK;
+}
+
+void ocradDialog::introduceImage( KookaImage *img )
+{
+ if( !img ) return;
+
+ KOCRBase::introduceImage( img );
+}
+
+
+ocradDialog::~ocradDialog()
+{
+ if( m_proc )
+ delete m_proc;
+}
+
+void ocradDialog::writeConfig( void )
+{
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ conf->writeEntry( CFG_OCRAD_BINARY, QString(getOCRCmd()));
+
+ conf->setGroup( CFG_GROUP_OCRAD );
+ conf->writeEntry( CFG_OCRAD_LAYOUT_DETECTION, m_layoutMode->currentItem());
+}
+
+
+void ocradDialog::enableFields(bool )
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+}
+
+/* Later: Allow interactive loading of orf files
+ * for now, return emty string
+ */
+QString ocradDialog::orfUrl() const
+{
+ if( m_orfUrlRequester )
+ return m_orfUrlRequester->url();
+ else
+ return QString();
+}
+
+void ocradDialog::version( const QString& exe )
+{
+ if( m_proc ) delete m_proc;
+
+ m_proc = new KProcess;
+
+ kdDebug(28000) << "Using " << exe << " as command" << endl;
+ *m_proc << exe;
+ *m_proc << QString("-V");
+
+ connect( m_proc, SIGNAL(receivedStdout(KProcess *, char *, int )),
+ this, SLOT(slReceiveStdIn(KProcess *, char *, int )));
+
+ if( ! m_proc->start( KProcess::NotifyOnExit, KProcess::Stdout ) )
+ {
+ slReceiveStdIn( 0, (char*) "unknown", 7 );
+ }
+}
+
+void ocradDialog::slReceiveStdIn( KProcess*, char *buffer, int buflen)
+{
+ QString vstr = QString::fromUtf8(buffer, buflen);
+
+ kdDebug(28000) << "Got input: "<< buffer << endl;
+
+ QRegExp rx;
+ rx.setPattern("GNU Ocrad version ([\\d\\.]+)");
+ if( rx.search( vstr ) > -1 )
+ {
+ QString vStr = rx.cap(1);
+ vStr.remove(0,2);
+
+ m_version = vStr.toInt();
+ QString v = i18n("Version: ") + rx.cap(1);
+
+ if( m_binaryLabel )
+ {
+ m_binaryLabel->setText(m_binaryLabel->text() + "\n" + v );
+ m_binaryLabel->update();
+ }
+ }
+}
+
+/*
+ * returns the numeric version of the ocrad program. It is queried in the slot
+ * slReceiveStdIn, which parses the output of the ocrad -V call.
+ *
+ * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8
+ */
+int ocradDialog::getNumVersion()
+{
+ return m_version;
+}
+
+#include "kocrocrad.moc"
+
+/* The End ;) */
+
diff --git a/kooka/kocrocrad.h b/kooka/kocrocrad.h
new file mode 100644
index 00000000..d268f403
--- /dev/null
+++ b/kooka/kocrocrad.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kocrocrad.h - ocr dialog for ocrad
+ -------------------
+ begin : Tue Jul 15 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCROCRAD_H
+#define KOCROCRAD_H
+
+#include <kdialogbase.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+
+#include "kocrbase.h"
+
+#define CFG_GROUP_OCRAD "ocrad"
+#define CFG_OCRAD_LAYOUT_DETECTION "layoutDetection"
+#define CFG_OCRAD_EXTRA_ARGUMENTS "extraArguments"
+#define CFG_OCRAD_FORMAT "format"
+#define CFG_OCRAD_CHARSET "charset"
+/**
+ *@author Klaas Freitag
+ */
+
+class KSpellConfig;
+class KURLRequester;
+class KProcess;
+class QLabel;
+class QComboBox;
+
+class ocradDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ ocradDialog( QWidget*, KSpellConfig* );
+ ~ocradDialog();
+
+ QString getOCRCmd( void ) const
+ { return m_ocrCmd;}
+
+ EngineError setupGui();
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+ QString orfUrl() const;
+
+ int layoutDetectionMode() const;
+
+ /**
+ * returns the numeric version of the ocrad program.
+ *
+ * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8
+ */
+ int getNumVersion();
+
+public slots:
+ void enableFields(bool);
+ void introduceImage( KookaImage* );
+
+protected:
+ void writeConfig();
+
+
+private:
+ void version( const QString& exe );
+
+private slots:
+ void slReceiveStdIn( KProcess *proc, char *buffer, int buflen);
+
+private:
+
+ QString m_ocrCmd;
+ KURLRequester *m_orfUrlRequester;
+ QComboBox *m_layoutMode;
+ QLabel *m_binaryLabel;
+ KProcess *m_proc;
+ int m_version;
+};
+
+#endif
diff --git a/kooka/kooka.cpp b/kooka/kooka.cpp
new file mode 100644
index 00000000..3e3d660d
--- /dev/null
+++ b/kooka/kooka.cpp
@@ -0,0 +1,465 @@
+/**************************************************************************
+ kooka.cpp - Main program class
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include "kooka.h"
+#include "kookaview.h"
+#include "resource.h"
+
+#include "kookapref.h"
+#include "imgprintdialog.h"
+
+#include <qlineedit.h>
+#include <qprinter.h>
+#include <qprintdialog.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kmenubar.h>
+#include <kaccel.h>
+#include <kio/netaccess.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kprinter.h>
+#include <kstatusbar.h>
+#include <kurl.h>
+#include <kurlrequesterdlg.h>
+#include <qstrlist.h>
+#include <kedittoolbar.h>
+#include <kmessagebox.h>
+#include <kdockwidget.h>
+#include <kparts/partmanager.h>
+#include <kstdaccel.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <qiconset.h>
+#include <kurldrag.h>
+
+#define DOCK_SIZES "DockSizes"
+
+
+Kooka::Kooka( const QCString& deviceToUse)
+ : KParts::DockMainWindow( 0, "Kooka" ),
+ m_printer(0),
+ m_prefDialogIndex(0)
+{
+ /* Start to create the main view framework */
+ m_view = new KookaView( this, deviceToUse);
+
+ /* Call createGUI on the ocr-result view */
+ setXMLFile( "kookaui.rc", true );
+
+ setAcceptDrops(false); // Waba: Not (yet?) supported
+ KConfig *konf = KGlobal::config ();
+ readDockConfig ( konf, DOCK_SIZES );
+
+ // then, setup our actions
+ setupActions();
+
+ createGUI(0L); // m_view->ocrResultPart());
+ // and a status bar
+ statusBar()->insertItem( QString(), KookaView::StatusTemp );
+ statusBar()->show();
+
+ // allow the view to change the statusbar and caption
+ connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
+ this, SLOT(changeStatusbar(const QString&)));
+ connect(m_view, SIGNAL(signalCleanStatusbar(void)),
+ this, SLOT(cleanStatusbar()));
+ connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
+ this, SLOT(changeCaption(const QString&)));
+
+ changeCaption( i18n( "KDE Scanning" ));
+
+ setAutoSaveSettings( QString::fromLatin1("General Options"),
+ true );
+}
+
+void Kooka::createMyGUI( KParts::Part *part )
+{
+ kdDebug(28000) << "Part changed, Creating gui" << endl;
+ createGUI(part);
+
+}
+
+Kooka::~Kooka()
+{
+ KConfig *konf = KGlobal::config ();
+ m_view->slCloseScanDevice();
+ writeDockConfig ( konf, DOCK_SIZES );
+ delete m_printer;
+}
+
+void Kooka::startup( void )
+{
+ kdDebug(29000) << "Starting startup !" << endl;
+ if( m_view ) m_view->loadStartupImage();
+}
+
+
+void Kooka::setupActions()
+{
+
+ KStdAction::print(this, SLOT(filePrint()), actionCollection());
+ KStdAction::quit(this , SLOT(close()), actionCollection());
+
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()),
+actionCollection());
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()),
+ actionCollection());
+ KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
+
+ m_view->createDockMenu(actionCollection(), this, "settings_show_docks" );
+
+ /* Image Viewer action Toolbar - OCR, Scaling etc. */
+ (void) new KAction(i18n("&OCR Image..."), "ocr", CTRL+Key_O,
+ m_view, SLOT(doOCR()),
+ actionCollection(), "ocrImage" );
+
+ (void) new KAction(i18n("O&CR on Selection..."), "ocr-select", CTRL+Key_C,
+ m_view, SLOT(doOCRonSelection()),
+ actionCollection(), "ocrImageSelect" );
+
+ KAction *act;
+ act = new KAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I,
+ m_view, SLOT( slIVScaleToWidth()),
+ actionCollection(), "scaleToWidth" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H,
+ m_view, SLOT( slIVScaleToHeight()),
+ actionCollection(), "scaleToHeight" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Original &Size"), "scaleorig", CTRL+Key_S,
+ m_view, SLOT( slIVScaleOriginal()),
+ actionCollection(), "scaleOriginal" );
+ m_view->connectViewerAction( act );
+
+#ifdef QICONSET_HONOUR_ON_OFF
+ /* The Toggleaction does not seem to handle the on/off icon from QIconSet */
+ QIconSet lockSet;
+ lockSet.setPixmap(BarIcon("lock") , QIconSet::Automatic, QIconSet::Normal, QIconSet::On );
+ lockSet.setPixmap(BarIcon("unlock"), QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
+ act = new KToggleAction ( i18n("Keep &Zoom Setting"), lockSet, CTRL+Key_Z,
+ actionCollection(), "keepZoom" );
+#else
+ act = new KToggleAction( i18n("Keep &Zoom Setting"), BarIcon("lockzoom"), CTRL+Key_Z,
+ actionCollection(), "keepZoom" );
+#endif
+
+ connect( act, SIGNAL( toggled( bool ) ), m_view->getImageViewer(),
+ SLOT(setKeepZoom(bool)));
+
+ m_view->connectViewerAction( act );
+
+ /* thumbview and gallery actions */
+ act = new KAction(i18n("Set Zoom..."), "viewmag", 0,
+ m_view, SLOT( slIVShowZoomDialog()),
+ actionCollection(), "showZoomDialog" );
+ m_view->connectViewerAction( act );
+
+ (void) new KAction(i18n("Create From Selectio&n"), "crop", CTRL+Key_N,
+ m_view, SLOT( slCreateNewImgFromSelection() ),
+ actionCollection(), "createFromSelection" );
+
+ (void) new KAction(i18n("Mirror Image &Vertically"), "mirror-vert", CTRL+Key_V,
+ this, SLOT( slMirrorVertical() ),
+ actionCollection(), "mirrorVertical" );
+
+ (void) new KAction(i18n("&Mirror Image Horizontally"), "mirror-horiz", CTRL+Key_M,
+ this, SLOT( slMirrorHorizontal() ),
+ actionCollection(), "mirrorHorizontal" );
+
+ (void) new KAction(i18n("Mirror Image &Both Directions"), "mirror-both", CTRL+Key_B,
+ this, SLOT( slMirrorBoth() ),
+ actionCollection(), "mirrorBoth" );
+
+ (void) new KAction(i18n("Open Image in &Graphic Application..."), "fileopen", CTRL+Key_G,
+ m_view, SLOT( slOpenCurrInGraphApp() ),
+ actionCollection(), "openInGraphApp" );
+
+ act = new KAction(i18n("&Rotate Image Clockwise"), "rotate_cw", CTRL+Key_R,
+ this, SLOT( slRotateClockWise() ),
+ actionCollection(), "rotateClockwise" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Rotate Image Counter-Clock&wise"), "rotate_ccw", CTRL+Key_W,
+ this, SLOT( slRotateCounterClockWise() ),
+ actionCollection(), "rotateCounterClockwise" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Rotate Image 180 &Degrees"), "rotate", CTRL+Key_D,
+ this, SLOT( slRotate180() ),
+ actionCollection(), "upsitedown" );
+ m_view->connectViewerAction( act );
+
+ /* Gallery actions */
+ act = new KAction(i18n("&Create Folder..."), "folder_new", 0,
+ m_view->gallery(), SLOT( slotCreateFolder() ),
+ actionCollection(), "foldernew" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Save Image..."), "filesave", 0,
+ m_view->gallery(), SLOT( slotExportFile() ),
+ actionCollection(), "saveImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Import Image..."), "inline_image", 0,
+ m_view->gallery(), SLOT( slotImportFile() ),
+ actionCollection(), "importImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Delete Image"), "edittrash", 0,
+ m_view->gallery(), SLOT( slotDeleteItems() ),
+ actionCollection(), "deleteImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Unload Image"), "fileclose", 0,
+ m_view->gallery(), SLOT( slotUnloadItems() ),
+ actionCollection(), "unloadImage" );
+ m_view->connectGalleryAction( act );
+
+#if 0
+ /* not yet supported actions - coming post 3.1 */
+ (void) new KAction(i18n("&Load Scan Parameters"), "bookmark_add", CTRL+Key_L,
+ m_view, SLOT(slLoadScanParams()),
+ actionCollection(), "loadscanparam" );
+
+ (void) new KAction(i18n("Save &Scan Parameters"), "bookmark_add", CTRL+Key_S,
+ m_view, SLOT(slSaveScanParams()),
+ actionCollection(), "savescanparam" );
+#endif
+
+ (void) new KAction(i18n("Select Scan Device"), "scanner", 0,
+ m_view, SLOT( slSelectDevice()),
+ actionCollection(), "selectsource" );
+
+ (void) new KAction( i18n("Enable All Warnings && Messages"), 0,
+ this, SLOT(slEnableWarnings()),
+ actionCollection(), "enable_msgs");
+
+
+ m_saveOCRTextAction = new KAction( i18n("Save OCR Res&ult Text"), "filesaveas", CTRL+Key_U,
+ m_view, SLOT(slSaveOCRResult()),
+ actionCollection(), "saveOCRResult");
+}
+
+
+void Kooka::saveProperties(KConfig *config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+
+ //if (!m_view->currentURL().isNull())
+ // config->writePathEntry("lastURL", m_view->currentURL());
+ kdDebug(28000) << "In kooka's saveProperties !" << endl;
+ config->setGroup( KOOKA_STATE_GROUP );
+ config->writeEntry( PREFERENCE_DIA_TAB, m_prefDialogIndex );
+ m_view->saveProperties( config );
+}
+
+void Kooka::readProperties(KConfig *config)
+{
+ (void) config;
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+ config->setGroup( KOOKA_STATE_GROUP );
+ m_prefDialogIndex = config->readNumEntry( PREFERENCE_DIA_TAB, 0 );
+ // QString url = config->readPathEntry("lastURL");
+
+}
+
+void Kooka::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+#if 0
+void Kooka::dropEvent(QDropEvent *event)
+{
+ // this is a very simplistic implementation of a drop event. we
+ // will only accept a dropped URL. the Qt dnd code can do *much*
+ // much more, so please read the docs there
+ KURL::List uri;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, uri) && !uri.isEmpty())
+ {
+ // okay, we have a URI.. process it
+ const KURL &url = uri.first();
+ kdDebug(29000) << "Importing URI " << url.url() << endl;
+
+ // TODO: Do something with url
+ // Waba: See also setAcceptDrops() above
+ }
+}
+
+void Kooka::fileNew()
+{
+ // this slot is called whenever the File->New menu is selected,
+ // the New shortcut is pressed (usually CTRL+N) or the New toolbar
+ // button is clicked
+
+ // create a new window
+ (new Kooka)->show();
+}
+
+void Kooka::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+}
+
+void Kooka::fileSave()
+{
+ // this slot is called whenever the File->Save menu is selected,
+ // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
+ // button is clicked
+
+ // save the current file
+}
+
+
+void Kooka::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ QStrList strlist;
+ strlist.append( "BMP" );
+ strlist.append( "JPEG" );
+ FormatDialog fd( 0, "FormatDialog", &strlist );
+ fd.exec();
+
+}
+#endif
+
+void Kooka::filePrint()
+{
+ // this slot is called whenever the File->Print menu is selected,
+ // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
+ // button is clicked
+ m_view->print();
+
+}
+
+void Kooka::optionsShowScanParams()
+{
+ m_view->slSetScanParamsVisible( m_scanParamsAction->isChecked() );
+}
+
+void Kooka::optionsShowPreviewer()
+{
+ m_view->slSetTabWVisible( m_previewerAction->isChecked());
+}
+
+void Kooka::optionsConfigureToolbars()
+{
+ // use the standard toolbar editor
+ saveMainWindowSettings(KGlobal::config(), autoSaveGroup());
+ KEditToolbar dlg(factory());
+ connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(newToolbarConfig()));
+ dlg.exec();
+}
+
+void Kooka::newToolbarConfig()
+{
+ // OK/Apply pressed in the toolbar editor
+ applyMainWindowSettings(KGlobal::config(), autoSaveGroup());
+}
+
+void Kooka::optionsPreferences()
+{
+ // popup some sort of preference dialog, here
+ KookaPreferences dlg;
+ dlg.showPage( m_prefDialogIndex );
+ connect( &dlg, SIGNAL( dataSaved() ), m_view, SLOT(slFreshUpThumbView()));
+
+ if (dlg.exec())
+ {
+ // redo your settings
+ m_prefDialogIndex = dlg.activePageIndex();
+ // m_view->slFreshUpThumbView();
+ }
+}
+
+void Kooka::changeStatusbar(const QString& text)
+{
+ // display the text on the statusbar
+ statusBar()->changeItem( text, KookaView::StatusTemp );
+}
+
+void Kooka::changeCaption(const QString& text)
+{
+ // display the text on the caption
+ setCaption(text);
+}
+
+void Kooka::slMirrorVertical( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorVertical );
+}
+
+void Kooka::slMirrorHorizontal( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorHorizontal );
+}
+
+void Kooka::slMirrorBoth( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorBoth );
+}
+
+void Kooka::slRotateClockWise( void )
+{
+ m_view->slRotateImage( 90 );
+}
+
+void Kooka::slRotateCounterClockWise( void )
+{
+ m_view->slRotateImage( -90 );
+
+}
+
+void Kooka::slRotate180( void )
+{
+ m_view->slRotateImage( 180 );
+}
+
+void Kooka::slEnableWarnings( )
+{
+ KMessageBox::information (this, i18n("All messages and warnings will now be shown."));
+ KMessageBox::enableAllMessages();
+ kapp->config()->reparseConfiguration();
+}
+
+#include "kooka.moc"
diff --git a/kooka/kooka.desktop b/kooka/kooka.desktop
new file mode 100644
index 00000000..19cd3f35
--- /dev/null
+++ b/kooka/kooka.desktop
@@ -0,0 +1,78 @@
+[Desktop Entry]
+Type=Application
+Exec=kooka %i %m %U
+Icon=scanner
+Path=
+Terminal=false
+DocPath=kooka/index.html
+GenericName=Scan & OCR Program
+GenericName[af]=Skandeer & Optiese karakter herkenning Program
+GenericName[ar]=برنامج للمسح الضوئي
+GenericName[bg]=Сканиране
+GenericName[bs]=Program za skeniranje i OCR
+GenericName[ca]=Programa d'escaneig i OCR
+GenericName[cs]=Program pro skenování a OCR
+GenericName[cy]=Rhaglen Sganio ac OCR
+GenericName[da]=Skanne- & OCR-program
+GenericName[de]=Scan- und OCR-Programm
+GenericName[el]=ΠÏόγÏαμμα ΣάÏωσης & OCR
+GenericName[eo]=Bildbitiga programo kaj tekstrekono
+GenericName[es]=OCR y explorador con un escáner
+GenericName[et]=Skaneerimise ja OMT rakendus
+GenericName[eu]=Eskaneatzeko eta OCR programa
+GenericName[fa]=پویش و برنامۀ OCR
+GenericName[fi]=Skannaus- ja tekstintunnistusohjelma
+GenericName[fr]=Numérisation et reconnaissance de caractères
+GenericName[gl]=Programa para escanear e facer OCR
+GenericName[he]=תוכנית סריקה וזיהוי ×ª×•×•×™× ×ופטי
+GenericName[hi]=सà¥à¤•à¥ˆà¤¨ व ऑपà¥à¤Ÿà¤¿à¤•à¤² कैरेकà¥à¤Ÿà¤° रिकॉगà¥à¤¨à¥€à¤¶à¤¨ पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® (OCR)
+GenericName[hr]=Program za skaniranje i OCR
+GenericName[hu]=Lapolvasó
+GenericName[is]=Forrit til að skanna inn myndir
+GenericName[it]=Programma di scansione e OCR
+GenericName[ja]=スキャン & OCR プログラム
+GenericName[kk]=Сканерге Ñ‚Ò¯Ñіру және танып-талдау
+GenericName[km]=កម្មវិធី​ស្កáŸáž“ & OCR
+GenericName[lt]=Skanavimo ir teksto atpažinimo programa
+GenericName[lv]=Skanēšanas un OCR Programma
+GenericName[ms]=Program Imbas & OCR
+GenericName[nb]=Et skanne-og OCR-program
+GenericName[nds]=Inlees- un OTR-Programm
+GenericName[ne]=सà¥à¤•à¥à¤¯à¤¾à¤¨ र OCR कारà¥à¤¯à¤•à¥à¤°à¤®
+GenericName[nl]=Scan- en OCR-programma
+GenericName[nn]=Skanne- og tekstattkjenningsprogram
+GenericName[pl]=Program do skanowania i rozpoznawania pisma
+GenericName[pt]=Programa de Digitalização e OCR
+GenericName[pt_BR]=Um programa de Digitalização & OCR
+GenericName[ro]=Scanare imagini ÅŸi OCR
+GenericName[ru]=Сканирование и раÑпознавание текÑта
+GenericName[sk]=Skenovací program s OCR
+GenericName[sl]=Program za skeniranje in prepoznavanje znakov
+GenericName[sr]=Програм за Ñкенирање и препознавање текÑта
+GenericName[sr@Latn]=Program za skeniranje i prepoznavanje teksta
+GenericName[sv]=Bildläsar- och OCR-program
+GenericName[ta]=வரà¯à®Ÿà¯ & OCR நிரலி
+GenericName[tg]=Барномаи Ñканеронӣ ва шиноÑоии матн
+GenericName[th]=โปรà¹à¸à¸£à¸¡à¸ªà¹à¸à¸™à¸ à¸²à¸žà¹à¸¥à¸° OCR
+GenericName[tr]=Tarayıcı ve karakter tanıma programı
+GenericName[uk]=Програма ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð° Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ñимволів
+GenericName[ven]=U nanga & Mbekanyamushumo ya OCR
+GenericName[wa]=Programe di scanaedje eyet di ricnoxhance di tecse
+GenericName[xh]=Udweliso Lwenkqubo Yemita Yovavanyo
+GenericName[zh_CN]=扫æ和文字识别程åº
+GenericName[zh_HK]=掃æ和文字辦識程å¼
+GenericName[zh_TW]=掃æ和文字辦識程å¼
+GenericName[zu]=Scan & OCR Iprogremu
+Name=Kooka
+Name[ar]=برنامج Kooka
+Name[eo]=Kokao
+Name[hi]=कूका
+Name[is]=Skanni
+Name[ko]=ì¿ ì¹´
+Name[ne]=कोओका
+Name[pa]=ਕੋਕਾ
+Name[ta]=கூகà¯à®•à®¾
+Name[zh_TW]=Kooka 掃æ器
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;
diff --git a/kooka/kooka.h b/kooka/kooka.h
new file mode 100644
index 00000000..66f59e0c
--- /dev/null
+++ b/kooka/kooka.h
@@ -0,0 +1,141 @@
+/**************************************************************************
+ kooka.h - Main program class
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOOKA_H
+#define KOOKA_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <kdockwidget.h>
+#include <kparts/dockmainwindow.h>
+
+#define KOOKA_STATE_GROUP "State"
+#define PREFERENCE_DIA_TAB "PreferencesTab"
+
+class KPrinter;
+class KToggleAction;
+class KActionMenu;
+class KookaView;
+
+/**
+ * This class serves as the main window for Kooka. It handles the
+ * menus, toolbars, and status bars.
+ *
+ * @short Main window class
+ * @author Klaas Freitag <freitag@suse.de>
+ * @version 0.1
+ */
+class Kooka : public KParts::DockMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ Kooka(const QCString& deviceToUse);
+
+ /**
+ * Default Destructor
+ */
+ ~Kooka();
+
+ /**
+ * Startup, loads (at the moment) only the last displayed image
+ **/
+ void startup( void );
+
+
+protected:
+ /**
+ * Overridden virtuals for Qt drag 'n drop (XDND)
+ */
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ // virtual void dropEvent(QDropEvent *event);
+
+ /**
+ * This function is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This function is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+
+private slots:
+
+ void createMyGUI( KParts::Part* );
+
+ void filePrint();
+ /* ImageViewer-Actions */
+
+ void optionsShowScanParams();
+ void optionsShowPreviewer();
+ void optionsConfigureToolbars();
+ void optionsPreferences();
+
+ void changeStatusbar(const QString& text);
+ void cleanStatusbar(void) { changeStatusbar(""); }
+ void changeCaption(const QString& text);
+ void newToolbarConfig();
+
+ // void fileSaveAs();
+
+ void slMirrorVertical( void );
+ void slMirrorHorizontal( void );
+ void slMirrorBoth( void );
+
+ void slRotateClockWise( void );
+ void slRotateCounterClockWise( void );
+ void slRotate180( void );
+
+ void slEnableWarnings();
+
+private:
+ void setupAccel();
+ void setupActions();
+
+private:
+ KookaView *m_view;
+
+ KPrinter *m_printer;
+ KToggleAction *m_scanParamsAction;
+ KToggleAction *m_previewerAction;
+ KActionMenu *m_settingsShowDocks;
+
+ KAction *m_saveOCRTextAction;
+ int m_prefDialogIndex;
+};
+
+#endif // KOOKA_H
diff --git a/kooka/kookaiface.h b/kooka/kookaiface.h
new file mode 100644
index 00000000..ab6fcbee
--- /dev/null
+++ b/kooka/kookaiface.h
@@ -0,0 +1,13 @@
+#ifndef KOOKAIFACE_H
+#define KOOKAIFACE_H
+
+#include <dcopobject.h>
+
+class KookaIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+};
+
+#endif // KOOKAIFACE_H
diff --git a/kooka/kookaimage.cpp b/kooka/kookaimage.cpp
new file mode 100644
index 00000000..4db87728
--- /dev/null
+++ b/kooka/kookaimage.cpp
@@ -0,0 +1,413 @@
+/***************************************************************************
+ kookaimage.cpp - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <kdebug.h>
+#include <kurl.h>
+#include <kfileitem.h>
+
+#include "kookaimage.h"
+#include "config.h"
+#ifdef HAVE_LIBTIFF
+#include <tiffio.h>
+#include <tiff.h>
+#endif
+/**
+ *@author Klaas Freitag
+ */
+
+
+KookaImage::KookaImage( )
+ : QImage(),
+ m_subImages(-1),
+ m_subNo(0),
+ m_parent(0),
+ m_fileBound(false),
+ m_tileCols(0)
+{
+
+}
+
+/* constructor for subimages */
+KookaImage::KookaImage( int subNo, KookaImage *p )
+ : QImage(),
+ m_subImages(-1),
+ m_subNo(subNo),
+ m_parent( p ),
+ m_fileItem(0L),
+ m_fileBound(false),
+ m_tileCols(0)
+{
+ kdDebug(28000) << "Setting subimageNo to " << subNo << endl;
+}
+
+KookaImage& KookaImage::operator=(const KookaImage& img)
+{
+ QImage::operator=(img);
+
+ m_subImages = img.subImagesCount();
+ m_subNo = img.m_subNo;
+ m_parent = img.m_parent;
+ m_url = img.m_url;
+ m_fileItem = img.m_fileItem;
+
+ return *this;
+}
+
+KookaImage& KookaImage::operator=(const QImage& img)
+{
+ QImage::operator=(img);
+ return *this;
+}
+
+KFileItem* KookaImage::fileItem() const
+{
+ return m_fileItem;
+}
+
+void KookaImage::setFileItem( KFileItem* it )
+{
+ m_fileItem = it;
+}
+
+const KFileMetaInfo KookaImage::fileMetaInfo( )
+{
+ QString filename = localFileName( );
+ if( ! filename.isEmpty() )
+ {
+ kdDebug(28000) << "Fetching metainfo for " << filename << endl;
+ const KFileMetaInfo info( filename );
+ return info;
+ }
+ else
+ return KFileMetaInfo();
+}
+
+QString KookaImage::localFileName( ) const
+{
+
+ if( ! m_url.isEmpty() )
+ return( m_url.directory() + "/" + m_url.fileName());
+ else
+ return QString();
+}
+
+bool KookaImage::loadFromUrl( const KURL& url )
+{
+ bool ret = true;
+ m_url = url;
+ QString filename = localFileName( );
+ QString format ( imageFormat( filename ));
+
+ /* if the format was not recogniseable, check the extension, if it is tif, try to read it by
+ * tifflib */
+ if( format.isNull() )
+ {
+ if( filename.endsWith( "tif" ) || filename.endsWith( "tiff" ) ||
+ filename.endsWith( "TIF" ) || filename.endsWith( "TIFF" ) )
+ {
+ format = "tif";
+ kdDebug(28000) << "Setting format to tif by extension" << endl;
+ }
+ }
+
+ kdDebug(28000) << "Image format to load: <" << format << "> from file <" << filename << ">" << endl;
+ bool haveTiff = false;
+
+ if( !m_url.isLocalFile() )
+ {
+ kdDebug(28000)<<"ERROR: Can not laod non-local images -> not yet implemented!" << endl;
+ return false;
+ }
+
+#ifdef HAVE_LIBTIFF
+ TIFF* tif = 0;
+ m_subImages = 0;
+
+ if( format == "tif" ||
+ format == "TIF" ||
+ format == "TIFF" ||
+ format == "tiff" )
+ {
+ /* if it is tiff, check with Tifflib if it is multiple sided */
+ kdDebug(28000) << "Trying to load TIFF!" << endl;
+ tif = TIFFOpen(filename.latin1(), "r");
+ if (tif)
+ {
+ do {
+ m_subImages++;
+ } while (TIFFReadDirectory(tif));
+ kdDebug(28000) << m_subImages << " TIFF-directories found" << endl;
+
+ haveTiff = true;
+ }
+ }
+#endif
+ if( !haveTiff )
+ {
+ /* Qt can only read one image */
+ ret = load(filename);
+ if( ret )
+ {
+ m_subImages = 0;
+ m_subNo = 0;
+ }
+ }
+#ifdef HAVE_LIBTIFF
+ else
+ {
+ loadTiffDir( filename, 0);
+ /* its a tiff, read by tifflib directly */
+ // Find the width and height of the image
+ }
+#endif
+
+ m_fileBound = ret;
+ return( ret );
+}
+
+
+KookaImage::KookaImage( const QImage& img )
+ : QImage( img )
+ /* m_subImages( 1 ) */
+{
+ m_subImages = 0;
+
+ /* Load one QImage, can not be Tiff yet. */
+ kdDebug(28000) << "constructor from other image here " << endl;
+}
+
+
+/* loads the number stored in m_subNo */
+void KookaImage::extractNow()
+{
+ kdDebug(28000) << "extracting a subimage number " << m_subNo << endl;
+
+ KookaImage *parent = parentImage();
+
+ if( parent )
+ {
+ loadTiffDir( parent->localFileName(), m_subNo );
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: No parent defined - can not laod subimage" << endl;
+ }
+}
+
+KURL KookaImage::url() const
+{
+ return m_url;
+}
+
+bool KookaImage::loadTiffDir( const QString& filename, int no )
+{
+#ifdef HAVE_LIBTIFF
+ int imgWidth, imgHeight;
+ TIFF* tif = 0;
+ /* if it is tiff, check with Tifflib if it is multiple sided */
+ kdDebug(28000) << "Trying to load TIFF, subimage number "<< no << endl;
+ tif = TIFFOpen(filename.latin1(), "r");
+ if (!tif)
+ return false;
+
+ if( ! TIFFSetDirectory( tif, no ) )
+ {
+ kdDebug(28000) << "ERR: could not set Directory " << no << endl;
+ TIFFClose(tif);
+ return false;
+ }
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imgWidth);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imgHeight);
+
+
+ /* TODO: load bw-image correctly only 2 bit */
+ // KookaImage tmpImg;
+ create( imgWidth, imgHeight, 32 );
+ if (TIFFReadRGBAImage(tif, imgWidth, imgHeight, (uint32*) bits(),0))
+ {
+ // successfully read. now convert.
+ // reverse red and blue
+ uint32 *data;
+ data = (uint32 *)bits();
+ for( unsigned i = 0; i < unsigned(imgWidth * imgHeight); ++i )
+ {
+ uint32 red = ( 0x00FF0000 & data[i] ) >> 16;
+ uint32 blue = ( 0x000000FF & data[i] ) << 16;
+ data[i] &= 0xFF00FF00;
+ data[i] += red + blue;
+ }
+
+ // reverse image (it's upside down)
+ unsigned h = unsigned(imgHeight);
+ for( unsigned ctr = 0; ctr < h>>1; )
+ {
+ unsigned *line1 = (unsigned *)scanLine( ctr );
+ unsigned *line2 = (unsigned *)scanLine( imgHeight
+ - ( ++ctr ) );
+
+ unsigned w = unsigned(imgWidth);
+ for( unsigned x = 0; x < w; x++ )
+ {
+ int temp = *line1;
+ *line1 = *line2;
+ *line2 = temp;
+ line1++;
+ line2++;
+ }
+ }
+ }
+
+ /* fetch the x- and y-resolutions to adjust images */
+ float xReso, yReso;
+ bool resosFound;
+ resosFound = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xReso );
+ resosFound &= TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yReso );
+ kdDebug(28000)<< "Tiff image: X-Resol.: " << xReso << " and Y-Resol.: " << yReso << endl;
+
+ TIFFClose(tif);
+
+ /* Check now if resolution in x- and y-direction differ. If so, stretch the image
+ * accordingly.
+ */
+ if( resosFound && xReso != yReso )
+ {
+ if( xReso > yReso )
+ {
+ float yScalefactor = xReso / yReso;
+ kdDebug(28000) << "Different resolution x/y, rescaling with factor " << yScalefactor << endl;
+ /* rescale the image */
+ *this = smoothScale( imgWidth, int(imgHeight*yScalefactor), QImage::ScaleFree );
+ }
+ else
+ {
+ /* yReso > xReso */
+ float scalefactor = yReso / xReso;
+ kdDebug(28000) << "Different resolution x/y, rescaling x with factor " << scalefactor << endl;
+ /* rescale the image */
+ *this = smoothScale( int(imgWidth*scalefactor), imgHeight, QImage::ScaleFree );
+
+ }
+ }
+
+#endif
+ return true;
+}
+
+
+int KookaImage::subImagesCount() const
+{
+ return( m_subImages );
+}
+
+KookaImage::~KookaImage()
+{
+
+}
+
+KookaImage* KookaImage::parentImage() const
+{
+ return( m_parent );
+}
+
+bool KookaImage::isSubImage() const
+{
+ return( subImagesCount() );
+}
+
+/*
+ * tiling
+ */
+int KookaImage::cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode )
+{
+ QSize imgSize = size();
+
+ int w = imgSize.width();
+ if( w > maxSize.width() )
+ {
+ // image is wider than paper
+ w = maxSize.width();
+ }
+ int h = imgSize.height();
+ if( h > maxSize.height() )
+ {
+ // image is wider than paper
+ h = maxSize.height();
+ }
+
+ int absX = 0; // absolute x position from where to start print
+ int absY = 0; // on the image, left top corner of the part to print
+ rows = 0;
+
+ while( h ) // Loop over height, cut in vertical direction
+ {
+ rows++;
+ cols = 0;
+ while( w ) // Loop over width, cut in horizontal direction
+ {
+ cols++;
+ m_tileVector.append( QRect( absX, absY, w, h ));
+
+ absX += w+1;
+ w = imgSize.width() - absX;
+
+ // if w < 0, this was the last loop, set w to zero to stop loop
+ if( w < 0 ) w = 0;
+
+ // if > 0 here, a new page is required
+ if( w > 0 )
+ {
+ if( w > maxSize.width() ) w = maxSize.width();
+ }
+ }
+ // Reset the X-values to start on the left border again
+ absX = 0;
+ // start with full width again
+ w = imgSize.width();
+ if( w > maxSize.width() )
+ w = maxSize.width();
+
+ absY += h+1;
+ h = imgSize.height() - absY;
+
+ if( h < 0 ) h = 0; // be sure to meet the break condition
+ if( h > maxSize.height()) h = maxSize.height(); // limit to page height
+ }
+ m_tileCols = cols;
+
+ return m_tileVector.count();
+}
+
+
+
+QRect KookaImage::getTileRect( int rowPos, int colPos ) const
+{
+ int indx = rowPos*m_tileCols+colPos;
+ kdDebug(28000) << "Tile Index: " << indx << endl;
+ const QRect r = m_tileVector[(rowPos)*m_tileCols + colPos];
+
+ return r;
+}
diff --git a/kooka/kookaimage.h b/kooka/kookaimage.h
new file mode 100644
index 00000000..84018d4d
--- /dev/null
+++ b/kooka/kookaimage.h
@@ -0,0 +1,170 @@
+/***************************************************************************
+ kookaimage.h - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+
+#ifndef KOOKAIMAGE_H
+#define KOOKAIMAGE_H
+#include <kurl.h>
+#include <qimage.h>
+#include <qptrlist.h>
+#include <qvaluevector.h>
+#include <qrect.h>
+
+#include <kfilemetainfo.h>
+
+class KFileItem;
+
+/**
+ * @author Klaas Freitag
+ *
+ * class that represents an image, very much as QImage. But this one can contain
+ * multiple pages.
+ */
+
+typedef enum { MaxCut, MediumCut } TileMode;
+
+class KookaImage: public QImage
+{
+public:
+
+ KookaImage( );
+ /**
+ * creating a subimage for a parent image.
+ * @param subNo contains the sequence number of subimages to create.
+ * @param p is the parent image.
+ */
+ KookaImage( int subNo, KookaImage *p );
+ KookaImage( const QImage& img );
+
+ KookaImage& operator=(const KookaImage& );
+ KookaImage& operator=(const QImage& );
+ /**
+ * load an image from a KURL. This method reads the entire file and sets
+ * the values for subimage count.
+ */
+ bool loadFromUrl( const KURL& );
+
+ ~KookaImage();
+
+ /**
+ * the amount of subimages. This is 0 if there are no subimages.
+ */
+ int subImagesCount() const;
+
+ /**
+ * the parent image.
+ */
+ KookaImage* parentImage() const;
+
+ /**
+ * returns true if this is a subimage.
+ */
+ bool isSubImage() const;
+
+ /**
+ * extracts the correct subimage according to the number given in the constructor.
+ */
+ void extractNow();
+
+ KURL url() const;
+ QString localFileName( ) const;
+
+ /**
+ * Set and get the KFileItem of the image. Note that the KFileItem pointer returned
+ * may be zero.
+ */
+ KFileItem* fileItem() const;
+ void setFileItem( KFileItem* );
+
+ /**
+ * @return the KFileMetaInfo
+ **/
+ const KFileMetaInfo fileMetaInfo( );
+
+ /**
+ * set the url of the kooka image. Note that loadFromUrl sets this
+ * url automatically.
+ */
+ void setUrl( const KURL& url )
+ { m_url = url; }
+
+ /**
+ * checks if the image is file bound ie. was loaded from file. If this
+ * method returns false, fileMetaInfo and FileItem are undefined.
+ */
+ bool isFileBound()const { return m_fileBound; }
+
+ /**
+ * Create tiles on the given image. That is just cut the image in parts
+ * while non of the parts is larger than maxSize and store the rect list.
+ * The parameters rows and cols contain the number of rows and cols after
+ * tiling. If both are one, the image is smaller than maxSize, thus the
+ * left-top tile is index 1,1.
+ * Use getTile() to read the QRect list.
+ */
+ int cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode mode = MaxCut );
+
+ /**
+ * read tiles from the tile list. The image needs to be tiled by method
+ * cutToTiles before.
+ */
+ QRect getTileRect( int rowPos, int colPos ) const;
+
+ /**
+ * retrieve the sub number of this image.
+ */
+ int subNumber() const { return m_subNo; }
+
+private:
+ int m_subImages;
+ bool loadTiffDir( const QString&, int );
+
+ /* if subNo is 0, the image is the one and only. If it is larger than 0, the
+ * parent contains the filename */
+ int m_subNo;
+
+ /* In case being a subimage */
+ KookaImage *m_parent;
+ KURL m_url;
+ /* Fileitem if available */
+ KFileItem *m_fileItem;
+ bool m_fileBound;
+
+ QValueVector<QRect> m_tileVector;
+ int m_tileCols; /* number of tile columns */
+};
+
+
+class KookaImageList: public QPtrList<KookaImage>
+{
+public:
+ KookaImageList() {}
+ ~KookaImageList() {}
+};
+
+
+#endif
diff --git a/kooka/kookaimagemeta.cpp b/kooka/kookaimagemeta.cpp
new file mode 100644
index 00000000..7ba1963d
--- /dev/null
+++ b/kooka/kookaimagemeta.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ kookaimage.cpp - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaimagemeta.h"
+
+KookaImageMeta::KookaImageMeta( ) :
+ m_scanResolution(-1),
+ m_scanResolutionY(-1)
+{
+
+}
+
+void KookaImageMeta::setScanResolution( int x, int y)
+{
+ m_scanResolutionY = y;
+ m_scanResolution = x;
+
+}
+
+int KookaImageMeta::getScanResolutionX() const
+{
+ return m_scanResolution;
+}
+
+int KookaImageMeta::getScanResolutionY() const
+{
+ return m_scanResolutionY;
+}
diff --git a/kooka/kookaimagemeta.h b/kooka/kookaimagemeta.h
new file mode 100644
index 00000000..fd269ddd
--- /dev/null
+++ b/kooka/kookaimagemeta.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ kookaimagemeta.h - Kooka's Image Meta Data
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOOKAIMAGEMETA_H
+#define KOOKAIMAGEMETA_H
+
+
+/**
+ * @author Klaas Freitag
+ *
+ */
+
+
+class KookaImageMeta
+{
+public:
+
+ KookaImageMeta( );
+ ~KookaImageMeta() { ;}
+
+ void setScanResolution( int x, int y=-1);
+ int getScanResolutionX() const;
+ int getScanResolutionY() const;
+
+private:
+ int m_scanResolution;
+ int m_scanResolutionY;
+
+};
+
+#endif
diff --git a/kooka/kookapref.cpp b/kooka/kookapref.cpp
new file mode 100644
index 00000000..c5996275
--- /dev/null
+++ b/kooka/kookapref.cpp
@@ -0,0 +1,547 @@
+/***************************************************************************
+ kookapref.cpp - Kookas preferences dialog
+ -------------------
+ begin : Wed Jan 5 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email :
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#include "kookapref.h"
+#include "img_saver.h"
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <knuminput.h>
+#include <kcolorbutton.h>
+#include <kstandarddirs.h>
+
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qvgroupbox.h>
+#include <qgrid.h>
+#include <qcheckbox.h>
+#include <qstringlist.h>
+
+#include <devselector.h>
+#include "config.h"
+#include "thumbview.h"
+#include "imageselectline.h"
+#include "kscanslider.h"
+#include "ksaneocr.h"
+
+#include <kmessagebox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <kurlrequester.h>
+
+KookaPreferences::KookaPreferences()
+ : KDialogBase(IconList, i18n("Preferences"),
+ Help|Default|Ok|Apply|Cancel, Ok )
+{
+ // this is the base class for your preferences dialog. it is now
+ // a Treelist dialog.. but there are a number of other
+ // possibilities (including Tab, Swallow, and just Plain)
+ konf = KGlobal::config ();
+
+ setupStartupPage();
+ setupSaveFormatPage();
+ setupThumbnailPage();
+ setupOCRPage();
+}
+
+void KookaPreferences::setupOCRPage()
+{
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+
+ QFrame *page = addPage( i18n("OCR"), i18n("Optical Character Recognition" ),
+ BarIcon("ocrImage", KIcon::SizeMedium ) );
+
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ bool haveGocr = false;
+ bool haveOcrad = false;
+ bool haveKadmos = false;
+
+ /*
+ * Switch ocr engines
+ */
+ QButtonGroup *engGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Engine to Use"), page );
+ m_gocrBut = new QRadioButton( i18n("GOCR engine") , engGroup );
+ m_kadmosBut = new QRadioButton( i18n("KADMOS engine"), engGroup );
+ m_ocradBut = new QRadioButton( i18n("OCRAD engine"), engGroup );
+ m_kadmosBut->setChecked(false);
+ m_gocrBut->setChecked(false);
+ m_ocradBut->setChecked(false);
+ top->addWidget( engGroup );
+
+ /*
+ * GOCR Option Box
+ */
+ QVGroupBox *gp = new QVGroupBox( i18n("GOCR OCR"), page );
+ m_urlReqGocr = binaryCheckBox( gp, "gocr" );
+ connect( m_urlReqGocr, SIGNAL( textChanged( const QString& )),
+ this, SLOT( slCheckOnGOCR( const QString& )));
+ QString cmdGocr = tryFindBinary( "gocr", CFG_GOCR_BINARY );
+ kdDebug(28000) << "Found gocr command: " << cmdGocr << endl;
+ m_gocrBut->setEnabled(false);
+ if( !cmdGocr.isEmpty() )
+ {
+ /* Found the command */
+ m_urlReqGocr->setURL( cmdGocr );
+ m_gocrBut->setEnabled(true);
+ haveGocr = true;
+ }
+ top->addWidget( gp );
+
+ /*
+ * OCRAD Option Box
+ */
+ gp = new QVGroupBox( i18n("OCRAD OCR"), page );
+ m_urlReqOcrad = binaryCheckBox( gp, "ocrad" );
+ connect( m_urlReqOcrad, SIGNAL( textChanged( const QString& )),
+ this, SLOT( slCheckOnOCRAD( const QString& )));
+ QString cmdOcrad = tryFindBinary( "ocrad", CFG_OCRAD_BINARY );
+ kdDebug(28000) << "Found ocrad command: " << cmdOcrad << endl;
+ m_ocradBut->setEnabled(false);
+ if( !cmdOcrad.isEmpty() )
+ {
+ /* Found the command */
+ m_urlReqOcrad->setURL( cmdOcrad );
+ m_ocradBut->setEnabled(true);
+ haveOcrad = true;
+ }
+ top->addWidget( gp );
+
+ /*
+ * Global Kadmos Options
+ */
+ QVGroupBox *kgp = new QVGroupBox( i18n("KADMOS OCR"), page );
+
+#ifdef HAVE_KADMOS
+ (void) new QLabel( i18n("The KADMOS OCR engine is available"), kgp);
+ m_kadmosBut->setChecked(true);
+ m_kadmosBut->setEnabled(true);
+ haveKadmos = true;
+#else
+ (void) new QLabel( i18n("The KADMOS OCR engine is not available in this version of Kooka"), kgp );
+ m_kadmosBut->setEnabled(false);
+#endif
+ top->addWidget( kgp );
+ QWidget *spaceEater = new QWidget( page );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ top->addWidget( spaceEater );
+
+ /*
+ * Now read the config value CFG_OCR_ENGINE and set the radios to the value if available
+ */
+ QString useEngine = konf->readEntry( CFG_OCR_ENGINE, "ocrad" );
+ if( useEngine != "notFound" )
+ {
+ if( useEngine == "gocr" && haveGocr )
+ {
+ m_gocrBut->setChecked(true);
+ m_prevOCREngine = "gocr";
+ }
+ else if( useEngine == "ocrad" && haveOcrad )
+ {
+ m_ocradBut->setChecked(true);
+ m_prevOCREngine = "ocrad";
+ }
+ else if( useEngine == "kadmos" && haveKadmos )
+ {
+ m_kadmosBut->setChecked(true);
+ m_prevOCREngine = "kadmos";
+ }
+ }
+}
+
+KURLRequester* KookaPreferences::binaryCheckBox( QWidget *parent, const QString& program )
+{
+ QHBox *hbox = new QHBox( parent );
+
+ (void) new QLabel( i18n("Select the %1 binary to use:").arg( program ), hbox );
+ KURLRequester* urlRequester = new KURLRequester( parent );
+ urlRequester->setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly );
+
+ QToolTip::add( urlRequester,
+ i18n( "Enter the path to %1, the optical-character-recognition "
+ "command line tool.").arg(program));
+ return urlRequester;
+}
+
+
+QString KookaPreferences::tryFindGocr( void )
+{
+ return( tryFindBinary( "gocr", CFG_GOCR_BINARY ) );
+}
+
+QString KookaPreferences::tryFindBinary( const QString& bin, const QString& configKey )
+{
+
+ /* First check the config files for an entry */
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup(CFG_GROUP_OCR_DIA);
+ QString res = cfg->readPathEntry( configKey /* CFG_GOCR_BINARY */, "notFound" );
+
+ if( res != "notFound" )
+ {
+ QFileInfo fi( res );
+ if( fi.exists() && fi.isExecutable() && !fi.isDir() && res.contains(bin) )
+ {
+ return res;
+ }
+ }
+
+ res = QString();
+
+ QStringList locations;
+ locations.append( "/usr/bin/" + bin );
+ locations.append( "/bin/" + bin );
+ locations.append( "/usr/X11R6/bin/"+bin );
+ locations.append( "/usr/local/bin/"+bin );
+
+ for ( QStringList::Iterator it = locations.begin(); it != locations.end(); ++it )
+ {
+ QString cmd = *it;
+ kdDebug(28000) << "checking command " << cmd << endl;
+ QFileInfo fi( cmd );
+ if( fi.exists() && fi.isExecutable() && !fi.isDir())
+ {
+ res = cmd;
+ kdDebug(28000) << "found command " << res << endl;
+ break;
+ }
+ }
+
+ return( res );
+}
+
+
+void KookaPreferences::slCheckOnGOCR( const QString& cmd )
+{
+ if( checkOCRBinIntern( cmd, "gocr", false ))
+ {
+ // cmd exists and is executable
+ m_gocrBut->setEnabled( true );
+ }
+ else
+ {
+ m_gocrBut->setEnabled( false );
+ }
+}
+
+void KookaPreferences::slCheckOnOCRAD( const QString& cmd )
+{
+ if( checkOCRBinIntern( cmd, "ocrad", false ))
+ {
+ // cmd exists and is executable
+ m_ocradBut->setEnabled( true );
+ }
+ else
+ {
+ m_ocradBut->setEnabled( false );
+ }
+}
+
+#if 0
+void KookaPreferences::checkOCRBinarySilent( const QString& cmd )
+{
+ // checkOCRBinIntern( cmd, this->sender(), false);
+}
+#endif
+bool KookaPreferences::checkOCRBinIntern( const QString& cmd, const QString& tool, bool show_msg )
+{
+ if( ! cmd.contains( tool )) return false;
+
+ bool ret = true;
+ QFileInfo fi( cmd );
+ if( ! fi.exists() )
+ {
+ if( show_msg )
+ KMessageBox::sorry( this, i18n( "The path does not lead to a valid binary.\n"
+ "Please check your installation and/or install the program."),
+ i18n("OCR Software Not Found") );
+ ret = false;
+ }
+ else
+ {
+ /* File exists, check if not dir and executable */
+ if( fi.isDir() || (! fi.isExecutable()) )
+ {
+ if( show_msg )
+ KMessageBox::sorry( this, i18n( "The program exists, but is not executable.\n"
+ "Please check your installation and/or install the binary properly."),
+ i18n("OCR Software Not Executable") );
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+
+
+void KookaPreferences::setupStartupPage()
+{
+
+ /* startup options */
+ konf->setGroup( GROUP_STARTUP );
+
+ QFrame *page = addPage( i18n("Startup"), i18n("Kooka Startup Preferences" ),
+ BarIcon("gear", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+ /* Description-Label */
+ top->addWidget( new QLabel( i18n("Note that changing these options will affect Kooka's next start!"), page ));
+
+ /* Query for network scanner (Checkbox) */
+ cbNetQuery = new QCheckBox( i18n("Query network for available scanners"),
+ page, "CB_NET_QUERY" );
+ QToolTip::add( cbNetQuery,
+ i18n( "Check this if you want a network query for available scanners.\nNote that this does not mean a query over the entire network but only the stations configured for SANE!" ));
+ cbNetQuery->setChecked( ! (konf->readBoolEntry( STARTUP_ONLY_LOCAL, false )) );
+
+
+ /* Show scanner selection box on startup (Checkbox) */
+ cbShowScannerSelection = new QCheckBox( i18n("Show the scanner selection box on next startup"),
+ page, "CB_SHOW_SELECTION" );
+ QToolTip::add( cbShowScannerSelection,
+ i18n( "Check this if you once checked 'do not show the scanner selection on startup',\nbut you want to see it again." ));
+
+ cbShowScannerSelection->setChecked( !konf->readBoolEntry( STARTUP_SKIP_ASK, false ));
+
+ /* Read startup image on startup (Checkbox) */
+ cbReadStartupImage = new QCheckBox( i18n("Load the last image into the viewer on startup"),
+ page, "CB_LOAD_ON_START" );
+ QToolTip::add( cbReadStartupImage,
+ i18n( "Check this if you want Kooka to load the last selected image into the viewer on startup.\nIf your images are large, that might slow down Kooka's start." ));
+ cbReadStartupImage->setChecked( konf->readBoolEntry( STARTUP_READ_IMAGE, true));
+
+ /* -- */
+
+ top->addWidget( cbNetQuery );
+ top->addWidget( cbShowScannerSelection );
+ top->addWidget( cbReadStartupImage );
+
+ top->addStretch(10);
+
+}
+
+void KookaPreferences::setupSaveFormatPage( )
+{
+ konf->setGroup( OP_FILE_GROUP );
+ QFrame *page = addPage( i18n("Image Saving"), i18n("Configure Image Save Assistant" ),
+ BarIcon("filesave", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ /* Skip the format asking if a format entry exists */
+ cbSkipFormatAsk = new QCheckBox( i18n("Always display image save assistant"),
+ page, "CB_IMGASSIST_QUERY" );
+ cbSkipFormatAsk->setChecked( konf->readBoolEntry( OP_FILE_ASK_FORMAT, true ));
+ QToolTip::add( cbSkipFormatAsk, i18n("Check this if you want to see the image save assistant even if there is a default format for the image type." ));
+ top->addWidget( cbSkipFormatAsk );
+
+ cbFilenameAsk = new QCheckBox( i18n("Ask for filename when saving file"),
+ page, "CB_ASK_FILENAME" );
+ cbFilenameAsk->setChecked( konf->readBoolEntry( OP_ASK_FILENAME, false));
+ QToolTip::add( cbFilenameAsk, i18n("Check this if you want to enter a filename when an image has been scanned." ));
+ top->addWidget( cbFilenameAsk );
+
+
+
+ top->addStretch(10);
+}
+
+void KookaPreferences::setupThumbnailPage()
+{
+ konf->setGroup( THUMB_GROUP );
+
+ QFrame *page = addPage( i18n("Thumbnail View"), i18n("Thumbnail Gallery View" ),
+ BarIcon("thumbnail", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ top->addWidget( new QLabel( i18n("Here you can configure the appearance of the thumbnail view of your scan picture gallery."),page ));
+
+ /* Backgroundimage */
+ KStandardDirs stdDir;
+ QString bgImg = konf->readPathEntry( BG_WALLPAPER );
+ if( bgImg.isEmpty() )
+ bgImg = stdDir.findResource( "data", STD_TILE_IMG );
+
+ /* image file selector */
+ QVGroupBox *hgb1 = new QVGroupBox( i18n("Thumbview Background" ), page );
+ m_tileSelector = new ImageSelectLine( hgb1, i18n("Select background image:"));
+ kdDebug(28000) << "Setting tile url " << bgImg << endl;
+ m_tileSelector->setURL( KURL(bgImg) );
+
+ top->addWidget( hgb1 );
+
+ /* Add the Boxes to configure size, framestyle and background */
+ QVGroupBox *hgb2 = new QVGroupBox( i18n("Thumbnail Size" ), page );
+ QVGroupBox *hgb3 = new QVGroupBox( i18n("Thumbnail Frame" ), page );
+
+ /* Thumbnail size */
+ int w = konf->readNumEntry( PIXMAP_WIDTH, 100);
+ int h = konf->readNumEntry( PIXMAP_HEIGHT, 120 );
+ QGrid *lGrid = new QGrid( 2, hgb2 );
+ lGrid->setSpacing( 2 );
+ QLabel *l1 = new QLabel( i18n("Thumbnail maximum &width:"), lGrid );
+ m_thumbWidth = new KIntNumInput( w, lGrid );
+ m_thumbWidth->setMinValue(1);
+ l1->setBuddy( m_thumbWidth );
+
+ lGrid->setSpacing( 4 );
+ l1 = new QLabel( i18n("Thumbnail maximum &height:"), lGrid );
+ m_thumbHeight = new KIntNumInput( m_thumbWidth, h, lGrid );
+ m_thumbHeight->setMinValue(1);
+ l1->setBuddy( m_thumbHeight );
+
+ /* Frame Stuff */
+ int frameWidth = konf->readNumEntry( THUMB_MARGIN, 3 );
+ QColor col1 = konf->readColorEntry( MARGIN_COLOR1, &(colorGroup().base()));
+ QColor col2 = konf->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground()));
+
+ QGrid *fGrid = new QGrid( 2, hgb3 );
+ fGrid->setSpacing( 2 );
+ l1 = new QLabel(i18n("Thumbnail &frame width:"), fGrid );
+ m_frameWidth = new KIntNumInput( frameWidth, fGrid );
+ m_frameWidth->setMinValue(0);
+ l1->setBuddy( m_frameWidth );
+
+ l1 = new QLabel(i18n("Frame color &1: "), fGrid );
+ m_colButt1 = new KColorButton( col1, fGrid );
+ l1->setBuddy( m_colButt1 );
+
+ l1 = new QLabel(i18n("Frame color &2: "), fGrid );
+ m_colButt2 = new KColorButton( col2, fGrid );
+ l1->setBuddy( m_colButt2 );
+ /* TODO: Gradient type */
+
+ top->addWidget( hgb2, 10);
+ top->addWidget( hgb3, 10);
+ top->addStretch(10);
+
+}
+
+
+void KookaPreferences::slotOk( void )
+{
+ slotApply();
+ accept();
+
+}
+
+
+void KookaPreferences::slotApply( void )
+{
+ /* ** startup options ** */
+
+ /** write the global one, to read from libkscan also */
+ konf->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ bool cbVal = !(cbShowScannerSelection->isChecked());
+ kdDebug(28000) << "Writing for " << STARTUP_SKIP_ASK << ": " << cbVal << endl;
+ konf->writeEntry( STARTUP_SKIP_ASK, cbVal, true, true ); /* global flag goes to kdeglobals */
+
+ /* only search for local (=non-net) scanners ? */
+ konf->writeEntry( STARTUP_ONLY_LOCAL, !cbNetQuery->isChecked(), true, true ); /* global */
+
+ /* Should kooka open the last displayed image in the viewer ? */
+ if( cbReadStartupImage )
+ konf->writeEntry( STARTUP_READ_IMAGE, cbReadStartupImage->isChecked());
+
+ /* ** Image saver option(s) ** */
+ konf->setGroup( OP_FILE_GROUP );
+ bool showFormatAssist = cbSkipFormatAsk->isChecked();
+ konf->writeEntry( OP_FILE_ASK_FORMAT, showFormatAssist );
+ konf->writeEntry( OP_ASK_FILENAME, cbFilenameAsk->isChecked() );
+
+ /* ** Thumbnail options ** */
+ konf->setGroup( THUMB_GROUP );
+ konf->writeEntry( PIXMAP_WIDTH, m_thumbWidth->value() );
+ konf->writeEntry( PIXMAP_HEIGHT, m_thumbHeight->value() );
+ konf->writeEntry( THUMB_MARGIN, m_frameWidth->value() );
+ konf->writeEntry( MARGIN_COLOR1, m_colButt1->color());
+ konf->writeEntry( MARGIN_COLOR2, m_colButt2->color());
+
+ KURL bgUrl = m_tileSelector->selectedURL().url();
+ bgUrl.setProtocol("");
+ kdDebug(28000) << "Writing tile-pixmap " << bgUrl.prettyURL() << endl;
+ konf->writePathEntry( BG_WALLPAPER, bgUrl.url() );
+
+ /* ** OCR Options ** */
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+ QString eng( "gocr" );
+
+ if( m_ocradBut->isChecked() )
+ eng = "ocrad";
+
+ if( m_kadmosBut && m_kadmosBut->isChecked() )
+ eng = "kadmos";
+
+ if( eng != m_prevOCREngine )
+ {
+ // selection of the ocr engine has changed. Popup button.
+ KMessageBox::sorry( this, i18n( "The OCR engine settings were changed.\n"
+ "Note that Kooka needs to be restarted to change the OCR engine."),
+ i18n("OCR Engine Change") );
+ }
+
+ konf->writeEntry(CFG_OCR_ENGINE, eng );
+
+ QString path = m_urlReqGocr->url();
+ if( ! path.isEmpty() )
+ konf->writePathEntry( CFG_GOCR_BINARY, path );
+
+ path = m_urlReqOcrad->url();
+ if( ! path.isEmpty() )
+ konf->writePathEntry( CFG_OCRAD_BINARY, path );
+
+ konf->sync();
+
+ emit dataSaved();
+}
+
+void KookaPreferences::slotDefault( void )
+{
+ cbNetQuery->setChecked( true );
+ cbShowScannerSelection->setChecked( true);
+ cbReadStartupImage->setChecked( true);
+ cbSkipFormatAsk->setChecked( true );
+ KStandardDirs stdDir;
+ QString bgImg = stdDir.findResource( "data", STD_TILE_IMG );
+ m_tileSelector->setURL( KURL(bgImg) );
+ m_thumbWidth->setValue( 100 );
+ m_thumbHeight->setValue( 120 );
+ QColor col1 = QColor( colorGroup().base());
+ QColor col2 = QColor( colorGroup().foreground());
+
+ m_frameWidth->setValue( 3 );
+ m_colButt1->setColor( col1 );
+ m_colButt2->setColor( col2 );
+ m_gocrBut->setChecked(true);
+}
+
+
+
+#include "kookapref.moc"
+
diff --git a/kooka/kookapref.h b/kooka/kookapref.h
new file mode 100644
index 00000000..c5ab34c0
--- /dev/null
+++ b/kooka/kookapref.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ kookapref.h - Preferences
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#ifndef KOOKAPREF_H
+#define KOOKAPREF_H
+
+#include <kdialogbase.h>
+#include <qframe.h>
+
+class KConfig;
+class QLabel;
+class KIntNumInput;
+class KColorButton;
+class ImageSelectLine;
+class KScanEntry;
+class QRadioButton;
+class KURLRequester;
+class QCheckBox;
+
+#define STARTUP_READ_IMAGE "ReadImageOnStart"
+#define CFG_GROUP_OCR_DIA "ocrDialog"
+#define CFG_OCRAD_BINARY "ocradBinary"
+#define CFG_GOCR_BINARY "gocrBinary"
+
+class KookaPreferences : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KookaPreferences();
+ static QString tryFindGocr( void );
+ static QString tryFindBinary( const QString&, const QString& );
+
+public slots:
+ void slotOk( void );
+ void slotApply( void );
+ void slotDefault( void );
+
+private slots:
+ bool checkOCRBinIntern( const QString&, const QString&, bool );
+
+ void slCheckOnGOCR( const QString& );
+ void slCheckOnOCRAD( const QString& );
+
+signals:
+ void dataSaved();
+
+private:
+ void setupStartupPage();
+ void setupSaveFormatPage();
+ void setupThumbnailPage();
+ void setupOCRPage();
+ KURLRequester* binaryCheckBox( QWidget *, const QString& );
+
+ QCheckBox *cbNetQuery;
+ QCheckBox *cbSkipFormatAsk;
+ QCheckBox *cbFilenameAsk;
+ QCheckBox *cbShowScannerSelection;
+ KConfig *konf;
+ QCheckBox *cbReadStartupImage;
+
+ KIntNumInput *m_thumbWidth;
+ KIntNumInput *m_thumbHeight;
+ KIntNumInput *m_frameWidth;
+ ImageSelectLine *m_tileSelector;
+ KColorButton *m_colButt1;
+ KColorButton *m_colButt2;
+
+ KURLRequester *m_urlReqGocr;
+ KURLRequester *m_urlReqOcrad;
+
+ QRadioButton *m_gocrBut;
+ QRadioButton *m_kadmosBut;
+ QRadioButton *m_ocradBut;
+ QString m_prevOCREngine;
+};
+
+
+#endif // KOOKAPREF_H
diff --git a/kooka/kookaprint.cpp b/kooka/kookaprint.cpp
new file mode 100644
index 00000000..6e0554e9
--- /dev/null
+++ b/kooka/kookaprint.cpp
@@ -0,0 +1,410 @@
+/***************************************************************************
+ kookaprint.cpp - Printing from the gallery
+ -------------------
+ begin : Tue May 13 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaprint.h"
+#include "kookaimage.h"
+#include <kprinter.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qfontmetrics.h>
+#include "imgprintdialog.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+KookaPrint::KookaPrint( KPrinter *printer )
+ :QObject(),
+ m_printer(printer),
+ m_extraMarginPercent(10)
+{
+
+}
+
+bool KookaPrint::printImage( KookaImage *img )
+{
+ bool result = true;
+ if( ! m_printer || !img) return false;
+
+ QString psMode = m_printer->option( OPT_PSGEN_DRAFT );
+ kdDebug(28000) << "User setting for quality: " << psMode << endl;
+
+#if 0
+ if( psMode == "1" )
+ m_printer->setResolution( 75 );
+ else
+ m_printer->setResolution( 600 );
+#endif
+
+ /* Create painter _after_ setting Resolution */
+ QPainter painter(m_printer);
+ m_painter = &painter;
+ KookaImage tmpImg;
+ QPoint pt(0, 0); // the top-left corner (image will be centered)
+
+ // We use a QPaintDeviceMetrics to know the actual page size in pixel,
+ // this gives the real painting area
+ QPaintDeviceMetrics printermetrics( m_painter->device() );
+
+ int screenRes = m_printer->option( OPT_SCREEN_RES ).toInt();
+ // int printerRes = printermetrics.logicalDpiX();
+ int printerRes = m_printer->resolution();
+
+ QString scale = m_printer->option( OPT_SCALING );
+
+ int reso = screenRes;
+
+ if( scale == "scan" )
+ {
+ /* Scale to original size */
+ reso = m_printer->option( OPT_SCAN_RES ).toInt();
+ }
+ else if( scale == "custom" )
+ {
+ // kdDebug(28000) << "Not yet implemented: Custom scale" << endl;
+ double userWidthInch = (m_printer->option( OPT_WIDTH ).toDouble() / 25.4 );
+ reso = int( double(img->width()) / userWidthInch );
+
+ kdDebug(28000) << "Custom resolution: " << reso << endl;
+
+ }
+ else if( scale == "fitpage" )
+ {
+ kdDebug(28000) << "Printing using maximum space on page" << endl;
+ printFittingToPage( img );
+ reso = 0; // to skip the printing on this page.
+ }
+
+ /* Scale the image for printing */
+ kdDebug(28000) << "Printer-Resolution: " << printerRes << " and scale-Reso: " << reso << endl;
+ QSize margins = m_printer->margins();
+ kdDebug(28000) << "Printer-Margins left: " << margins.width() << " and top " << margins.height()
+ << endl;
+ if( reso > 0)
+ {
+ double sizeInch = double(img->width()) / double(reso);
+ int newWidth = int(sizeInch * printerRes);
+
+ printerRes = printermetrics.logicalDpiY();
+ sizeInch = double(img->height()) / double(reso);
+ int newHeight = int(sizeInch * printerRes );
+
+ kdDebug(28000) << "Scaling to printer size " << newWidth << " x " << newHeight << endl;
+
+ tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree);
+
+ QSize sz = tmpImg.size(); // the current image size
+ QSize maxOnPage = maxPageSize(); // the maximum space on one side
+
+ int maxRows, maxCols;
+ int subpagesCnt = tmpImg.cutToTiles( maxOnPage, maxRows, maxCols );
+
+ kdDebug(28000) << "Subpages count: " << subpagesCnt <<
+ " Columns:" << maxCols << " Rows:" << maxRows << endl;
+
+ int cnt = 0;
+
+ for( int row = 0; row < maxRows; row++ )
+ {
+ for( int col = 0; col < maxCols; col++ )
+ {
+ const QRect part = tmpImg.getTileRect( row, col );
+ const QSize imgSize = part.size();
+
+ kdDebug(28000) << "Printing part from " << part.x() << "/" << part.y()
+ << " width:"<< part.width() << " and height " << part.height() << endl;
+ QImage tileImg = tmpImg.copy( part );
+
+ m_painter->drawImage( printPosTopLeft(imgSize), tileImg );
+ drawCornerMarker( imgSize, row, col, maxRows, maxCols );
+ cnt++;
+ if( cnt < subpagesCnt )
+ m_printer->newPage();
+ }
+ }
+ }
+
+ m_painter = 0; // no, this is not a memory leak.
+ return result;
+}
+
+void KookaPrint::printFittingToPage(KookaImage *img)
+{
+ if( ! img || ! m_painter ) return;
+
+ KookaImage tmpImg;
+
+ QString psMode = m_printer->option( OPT_RATIO );
+ bool maintainAspect = (psMode == "1");
+
+ QSize s = maxPageSize();
+
+ double wAspect = double(s.width()) / double(img->width());
+ double hAspect = double(s.height()) / double(img->height());
+
+ // take the smaller one.
+ double aspect = wAspect;
+ if( hAspect < wAspect ) aspect = hAspect;
+
+ // default: maintain aspect ratio.
+ int newWidth = int( double( img->width() ) * aspect );
+ int newHeight = int( double( img->height()) * aspect );
+
+ if( ! maintainAspect )
+ {
+ newWidth = int( double( img->width() ) * wAspect );
+ newHeight = int( double( img->height() ) * hAspect );
+ }
+
+ tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree);
+
+ m_painter->drawImage( 0,0, tmpImg );
+
+}
+
+
+void KookaPrint::drawMarkerAroundPoint( const QPoint& p )
+{
+ if( ! m_painter ) return;
+ const int len = 10;
+
+ m_painter->drawLine( p-QPoint(len,0), p+QPoint(len,0));
+ m_painter->drawLine( p-QPoint(0,len), p+QPoint(0,len));
+
+}
+
+
+void KookaPrint::drawCutSign( const QPoint& p, int num, MarkerDirection dir )
+{
+ QBrush saveB = m_painter->brush();
+ int start = 0;
+ const int radius=20;
+
+ QColor brushColor( Qt::red );
+ int toffX=0;
+ int toffY=0;
+ QString numStr = QString::number(num);
+
+ QFontMetrics fm = m_painter->fontMetrics();
+ int textWidth = fm.width( numStr )/2;
+ int textHeight = fm.width( numStr )/2;
+ int textYOff = 0;
+ int textXOff = 0;
+ switch( dir )
+ {
+ case SW:
+ start = -90;
+ brushColor = Qt::green;
+ toffX =-1;
+ toffY = 1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ case NW:
+ start = -180;
+ brushColor = Qt::blue;
+ toffX =-1;
+ toffY =-1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ case NO:
+ start = -270;
+ brushColor = Qt::yellow;
+ toffX = 1;
+ toffY = -1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+
+ break;
+ case SO:
+ start = 0;
+ brushColor = Qt::magenta;
+ toffX = 1;
+ toffY = 1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ default:
+ start = 0;
+ }
+
+ /* to draw around the point p, subtraction of the half radius is needed */
+ int x = p.x()-radius/2;
+ int y = p.y()-radius/2;
+
+ // m_painter->drawRect( x, y, radius, radius ); /* debug !!! */
+ const int tAway = radius*3/4;
+
+ QRect bRect = fm.boundingRect( QString::number(num));
+ int textX = p.x()+ tAway * toffX + textXOff;
+ int textY = p.y()+ tAway * toffY + textYOff;
+
+ // m_painter->drawRect( textX, textY, bRect.width(), bRect.height() );
+ kdDebug(28000) << "Drawing to position " << textX << "/" << textY << endl;
+ m_painter->drawText( textX,
+ textY,
+ QString::number(num));
+ QBrush b( brushColor, NoBrush /* remove this to get debug color*/ );
+
+
+ m_painter->setBrush( b );
+ m_painter->drawPie( x, y, radius, radius, 16*start, -16*90 );
+
+ m_painter->setBrush( saveB );
+}
+
+
+/*
+ * draws the circle and the numbers that indicate the pages to glue to the side
+ */
+void KookaPrint::drawCornerMarker( const QSize& imgSize, int row, int col, int maxRows, int maxCols )
+{
+ QPoint p;
+
+ kdDebug(28000) << "Marker: Row: " << row << " and col " << col <<" from max "
+ << maxRows << "x" << maxCols << endl;
+
+ // Top left.
+ p = printPosTopLeft( imgSize );
+ drawMarkerAroundPoint( p );
+ int indx = maxCols*row+col+1;
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col > 0 )
+ drawCutSign( p, indx-1, SW );
+ if( row > 0 )
+ drawCutSign( p, indx-maxCols, NO );
+
+ if( row > 0 && col > 0 )
+ drawCutSign( p, indx-maxCols-1, NW );
+ }
+
+ // Top Right
+ p = printPosTopRight( imgSize );
+ drawMarkerAroundPoint( p );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col < maxCols-1 )
+ drawCutSign( p, indx+1, SO );
+ if( row > 0 )
+ drawCutSign( p, indx-maxCols, NW );
+ if( row > 0 && col < maxCols-1 )
+ drawCutSign( p, indx-maxCols+1, NO );
+ }
+
+ // Bottom Right
+ p = printPosBottomRight( imgSize );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col < maxCols-1 )
+ drawCutSign( p, indx+1, NO );
+ if( row < maxRows-1 )
+ drawCutSign( p, indx+maxCols, SW );
+ if( row < maxRows -1 && col < maxCols-1 )
+ drawCutSign( p, indx+maxCols, SO );
+ }
+
+ // p += QPoint( 1, 1 );
+ drawMarkerAroundPoint( p ); /* at bottom right */
+
+ /* Bottom left */
+ p = printPosBottomLeft( imgSize );
+ // p += QPoint( -1, 1 );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col > 0 )
+ drawCutSign( p, indx-1, NW );
+ if( row < maxRows-1 )
+ drawCutSign( p, indx+maxCols, SO );
+ if( row < maxRows -1 && col > 0 )
+ drawCutSign( p, indx+maxCols-1, SW );
+ }
+ drawMarkerAroundPoint( p ); /* at bottom left */
+}
+
+QSize KookaPrint::maxPageSize( int extraShrinkPercent ) const
+{
+ if( ! m_painter ) return QSize();
+ QPaintDeviceMetrics printermetrics( m_painter->device() );
+
+ double extraShrink = double(100-extraShrinkPercent)/100.0;
+
+ QSize retSize( printermetrics.width(), printermetrics.height() );
+
+ if( extraShrinkPercent > 0 )
+ retSize = QSize( int(double(printermetrics.width())* extraShrink) ,
+ int(double(printermetrics.height())* extraShrink ));
+ return retSize;
+}
+
+int KookaPrint::extraMarginPix() const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ return int(double(max.width())*double(m_extraMarginPercent) / 100.0 / 2.0);
+}
+
+QPoint KookaPrint::printPosTopLeft( const QSize& imgSize ) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin + (max.width() - imgSize.width())/2,
+ eMargin + (max.height() - imgSize.height())/2 );
+}
+
+QPoint KookaPrint::printPosTopRight(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin + (max.width() - imgSize.width())/2+imgSize.width(),
+ eMargin + (max.height() - imgSize.height())/2 );
+}
+
+QPoint KookaPrint::printPosBottomLeft(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ int eMargin = extraMarginPix();
+ /* take the half extra margin */
+ return QPoint( eMargin+(max.width() - imgSize.width())/2,
+ eMargin+(max.height() - imgSize.height())/2 + imgSize.height() );
+}
+
+QPoint KookaPrint::printPosBottomRight(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin+(max.width() - imgSize.width())/2 + imgSize.width(),
+ eMargin+(max.height() - imgSize.height())/2 + imgSize.height() );
+}
+
+
+
+#include "kookaprint.moc"
diff --git a/kooka/kookaprint.h b/kooka/kookaprint.h
new file mode 100644
index 00000000..5f87d973
--- /dev/null
+++ b/kooka/kookaprint.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ kookaprint.h - Printing from the gallery
+ -------------------
+ begin : Tue May 13 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KOOKA_PRINT_H__
+#define __KOOKA_PRINT_H__
+
+#include <qobject.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <kprinter.h>
+#include <kdeprint/kprintdialogpage.h>
+
+class KookaImage;
+class KPrinter;
+class QPainter;
+class KLineEdit;
+
+
+class ImageSettings : public KPrintDialogPage
+{
+public:
+ void setOptions( const QMap<QString, QString>& opts );
+ void getOptions( QMap<QString, QString>& opts, bool include_def = false );
+ bool isValid( QString& msg );
+
+private:
+ KLineEdit *m_width, *m_height;
+
+};
+
+
+class KookaPrint:public QObject
+{
+ Q_OBJECT
+public:
+ KookaPrint(KPrinter*);
+
+ /**
+ * The top left edge of the required print position
+ */
+ virtual QPoint printPosTopLeft(const QSize&) const;
+ virtual QPoint printPosTopRight(const QSize&) const;
+ virtual QPoint printPosBottomLeft(const QSize&) const;
+ virtual QPoint printPosBottomRight(const QSize&) const;
+
+ virtual int extraMarginPix() const;
+
+ /**
+ * The maximum pixel size of the image (or imagepart) on
+ * the current page
+ */
+ virtual QSize maxPageSize( int extraShrinkPercent = 0 ) const;
+
+public slots:
+
+ bool printImage( KookaImage* );
+ void printFittingToPage(KookaImage *img);
+protected:
+ typedef enum { SW, NW, NO, SO } MarkerDirection;
+
+ virtual void drawMarkerAroundPoint( const QPoint& );
+ virtual void drawCutSign( const QPoint&, int, MarkerDirection );
+ virtual void drawCornerMarker( const QSize&, int, int, int, int );
+
+private:
+
+ KPrinter *m_printer;
+ QPainter *m_painter;
+ int m_extraMarginPercent;
+};
+
+#endif
diff --git a/kooka/kookarc b/kooka/kookarc
new file mode 100644
index 00000000..13875fff
--- /dev/null
+++ b/kooka/kookarc
@@ -0,0 +1,121 @@
+[DockSizes]
+Kookas MainDock,Preview ,Thumbs:first_name=Kookas MainDock,Preview\s
+Kookas MainDock,Preview ,Thumbs:last_name=Thumbs
+Kookas MainDock,Preview ,Thumbs:orientation=0
+Kookas MainDock,Preview ,Thumbs:parent=yes
+Kookas MainDock,Preview ,Thumbs:sepPos=72
+Kookas MainDock,Preview ,Thumbs:stayButton=false
+Kookas MainDock,Preview ,Thumbs:type=GROUP
+Kookas MainDock,Preview :curTab=0
+Kookas MainDock,Preview :parent=yes
+Kookas MainDock,Preview :stayButton=false
+Kookas MainDock,Preview :tabNames=Kookas MainDock,Preview\s
+Kookas MainDock,Preview :type=TAB_GROUP
+Kookas MainDock,Thumbs,Preview :curTab=1
+Kookas MainDock,Thumbs,Preview :parent=yes
+Kookas MainDock,Thumbs,Preview :stayButton=false
+Kookas MainDock,Thumbs,Preview :tabNames=Kookas MainDock,Thumbs,Preview\s
+Kookas MainDock,Thumbs,Preview :type=TAB_GROUP
+Kookas MainDock,Thumbs:curTab=1
+Kookas MainDock,Thumbs:first_name=Kookas MainDock
+Kookas MainDock,Thumbs:last_name=Thumbs
+Kookas MainDock,Thumbs:orientation=0
+Kookas MainDock,Thumbs:parent=yes
+Kookas MainDock,Thumbs:sepPos=54
+Kookas MainDock,Thumbs:stayButton=false
+Kookas MainDock,Thumbs:tabNames=Kookas MainDock,Thumbs
+Kookas MainDock,Thumbs:type=TAB_GROUP
+Kookas MainDock:stayButton=false
+Kookas MainDock:type=DOCK
+Main:Geometry=40,60,980,760
+Main:dock=Kookas MainDock
+Main:view=Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs
+Main:visible=false
+NameList=Kookas MainDock,Thumbs,Scanpackager,Recent,Scan Parameter,Preview ,Kookas MainDock\\,Preview ,Kookas MainDock\\,Preview \\,Thumbs,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter\\,Kookas MainDock\\,Preview \\,Thumbs
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Preview ,Scanpackager,Recent,Scan Parameter
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP
+Preview ,Scanpackager,Recent,Scan Parameter:first_name=Preview ,Scanpackager,Recent
+Preview ,Scanpackager,Recent,Scan Parameter:last_name=Scan Parameter
+Preview ,Scanpackager,Recent,Scan Parameter:orientation=0
+Preview ,Scanpackager,Recent,Scan Parameter:parent=yes
+Preview ,Scanpackager,Recent,Scan Parameter:sepPos=50
+Preview ,Scanpackager,Recent,Scan Parameter:stayButton=false
+Preview ,Scanpackager,Recent,Scan Parameter:type=GROUP
+Preview ,Scanpackager,Recent:first_name=Preview ,Scanpackager
+Preview ,Scanpackager,Recent:last_name=Recent
+Preview ,Scanpackager,Recent:orientation=0
+Preview ,Scanpackager,Recent:parent=yes
+Preview ,Scanpackager,Recent:sepPos=84
+Preview ,Scanpackager,Recent:stayButton=false
+Preview ,Scanpackager,Recent:type=GROUP
+Preview ,Scanpackager:first_name=Preview\s
+Preview ,Scanpackager:last_name=Scanpackager
+Preview ,Scanpackager:orientation=0
+Preview ,Scanpackager:parent=yes
+Preview ,Scanpackager:sepPos=50
+Preview ,Scanpackager:stayButton=false
+Preview ,Scanpackager:type=GROUP
+Preview :stayButton=false
+Preview :type=DOCK
+Recent,Scan Parameter:first_name=Recent
+Recent,Scan Parameter:last_name=Scan Parameter
+Recent,Scan Parameter:orientation=0
+Recent,Scan Parameter:parent=yes
+Recent,Scan Parameter:sepPos=14
+Recent,Scan Parameter:stayButton=false
+Recent,Scan Parameter:type=GROUP
+Recent:stayButton=false
+Recent:type=DOCK
+Scan Parameter:stayButton=false
+Scan Parameter:type=DOCK
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Scanpackager,Preview ,Recent,Scan Parameter
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP
+Scanpackager,Preview ,Recent,Scan Parameter:first_name=Scanpackager,Preview\s
+Scanpackager,Preview ,Recent,Scan Parameter:last_name=Recent,Scan Parameter
+Scanpackager,Preview ,Recent,Scan Parameter:orientation=0
+Scanpackager,Preview ,Recent,Scan Parameter:parent=yes
+Scanpackager,Preview ,Recent,Scan Parameter:sepPos=48
+Scanpackager,Preview ,Recent,Scan Parameter:stayButton=false
+Scanpackager,Preview ,Recent,Scan Parameter:type=GROUP
+Scanpackager,Preview :curTab=0
+Scanpackager,Preview :parent=yes
+Scanpackager,Preview :stayButton=false
+Scanpackager,Preview :tabNames=Scanpackager,Preview\s
+Scanpackager,Preview :type=TAB_GROUP
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:first_name=Scanpackager,Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:last_name=Kookas MainDock,Preview ,Thumbs
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:orientation=1
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:parent=yes
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:sepPos=41
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:stayButton=false
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:type=GROUP
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :first_name=Scanpackager,Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :last_name=Kookas MainDock,Thumbs,Preview\s
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :orientation=1
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :parent=yes
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :sepPos=38
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :stayButton=false
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :type=GROUP
+Scanpackager,Recent,Scan Parameter:first_name=Scanpackager
+Scanpackager,Recent,Scan Parameter:last_name=Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter:orientation=0
+Scanpackager,Recent,Scan Parameter:parent=yes
+Scanpackager,Recent,Scan Parameter:sepPos=42
+Scanpackager,Recent,Scan Parameter:stayButton=false
+Scanpackager,Recent,Scan Parameter:type=GROUP
+Scanpackager:stayButton=false
+Scanpackager:type=DOCK
+Thumbs:stayButton=false
+Thumbs:type=DOCK
+Version=0.0.5
+
diff --git a/kooka/kookaui.rc b/kooka/kookaui.rc
new file mode 100644
index 00000000..77d3cf4e
--- /dev/null
+++ b/kooka/kookaui.rc
@@ -0,0 +1,62 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="Kooka" version="3">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="foldernew"/>
+ <Action name="saveImage"/>
+ <Action name="importImage"/>
+ <Action name="deleteImage"/>
+ <Action name="unloadImage"/>
+ <Action name="saveOCRResult"/>
+ </Menu>
+ <Menu name="imgCanvas"><text>&amp;Image</text>
+ <Action name="openInGraphApp"/>
+ <Separator/>
+ <Action name="ocrImage"/>
+ <Action name="ocrImageSelect"/>
+ <Separator/>
+ <Action name="scaleToWidth"/>
+ <Action name="scaleToHeight"/>
+ <Action name="scaleOriginal"/>
+ <Separator/>
+ <Action name="createFromSelection"/>
+ <Separator/>
+ <Action name="mirrorVertical"/>
+ <Action name="mirrorHorizontal"/>
+ <Action name="mirrorBoth"/>
+ <Separator/>
+ <Action name="rotateClockwise"/>
+ <Action name="rotateCounterClockwise"/>
+ <Action name="upsitedown"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="settings_show_docks" append="show_merge"/>
+ <Action name="enable_msgs" append="save_merge"/>
+ <Separator append="save_merge"/>
+ <Action name="selectsource" append="save_merge"/>
+ <Separator append="save_merge"/>
+ <Action name="loadscanparam" append="save_merge"/>
+ <Action name="savescanparam" append="save_merge"/>
+ </Menu>
+</MenuBar>
+ <ToolBar name="mainToolBar" fullWidth="true">
+ <text>Image Viewer Toolbar</text>
+ <Action name="ocrImage"/>
+ <Action name="ocrImageSelect"/>
+ <Separator/>
+ <Action name="scaleToWidth"/>
+ <Action name="scaleToHeight"/>
+ <Action name="scaleOriginal"/>
+ <Action name="keepZoom"/>
+ <Separator/>
+ <Action name="createFromSelection"/>
+ <Separator/>
+ <Action name="mirrorVertical"/>
+ <Action name="mirrorHorizontal"/>
+ <Action name="mirrorBoth"/>
+ <Separator/>
+ <Action name="rotateClockwise"/>
+ <Action name="rotateCounterClockwise"/>
+ <Action name="upsitedown"/>
+ </ToolBar>
+</kpartgui>
diff --git a/kooka/kookaview.cpp b/kooka/kookaview.cpp
new file mode 100644
index 00000000..f1c1d8d0
--- /dev/null
+++ b/kooka/kookaview.cpp
@@ -0,0 +1,1083 @@
+/***************************************************************************
+ kookaview.cpp - kookas visible stuff
+ -------------------
+ begin : ?
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaview.h"
+#include "resource.h"
+#include "kscandevice.h"
+#include "imgscaninfo.h"
+#include "devselector.h"
+#include "ksaneocr.h"
+#include "img_saver.h"
+#include "kookapref.h"
+#include "imgnamecombo.h"
+#include "thumbview.h"
+#include "dwmenuaction.h"
+#include "kookaimage.h"
+#include "kookaimagemeta.h"
+#include "ocrresedit.h"
+#include "kookaprint.h"
+#include "imgprintdialog.h"
+#if 0
+#include "paramsetdialogs.h"
+#endif
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qstrlist.h>
+#include <qpaintdevice.h>
+#include <qpaintdevicemetrics.h>
+#include <qpopupmenu.h>
+#include <qwidgetstack.h>
+
+#include <kurl.h>
+#include <krun.h>
+#include <kapplication.h>
+#include <kstatusbar.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <ktrader.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <keditcl.h>
+#include <kled.h>
+#include <kcombobox.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kshortcut.h>
+#include <kdockwidget.h>
+#include <qobject.h>
+
+#include <kparts/componentfactory.h>
+#include <qimage.h>
+#include <kpopupmenu.h>
+
+
+#define STARTUP_IMG_SELECTION "SelectedImageOnStartup"
+
+
+KookaView::KookaView( KParts::DockMainWindow *parent, const QCString& deviceToUse)
+ : QObject(),
+ m_ocrResultImg(0),
+ ocrFabric(0),
+ m_mainDock(0),
+ m_dockScanParam(0),
+ m_dockThumbs(0),
+ m_dockPackager(0),
+ m_dockRecent(0),
+ m_dockPreview(0),
+ m_dockOCRText(0),
+ m_mainWindow(parent),
+ m_ocrResEdit(0)
+{
+ KIconLoader *loader = KGlobal::iconLoader();
+ scan_params = 0L;
+ preview_canvas = 0L;
+
+ m_mainDock = parent->createDockWidget( "Kookas MainDock",
+ loader->loadIcon( "folder_image", KIcon::Small ),
+ 0L, i18n("Image Viewer"));
+ m_mainDock->setEnableDocking(KDockWidget::DockNone );
+ m_mainDock->setDockSite( KDockWidget::DockFullSite );
+
+ parent->setView( m_mainDock);
+ parent->setMainDockWidget( m_mainDock);
+
+ img_canvas = new ImageCanvas( m_mainDock );
+ img_canvas->setMinimumSize(100,200);
+ img_canvas->enableContextMenu(true);
+ connect( img_canvas, SIGNAL( imageReadOnly(bool)),
+ this, SLOT(slViewerReadOnly(bool)));
+
+ KPopupMenu *ctxtmenu = static_cast<KPopupMenu*>(img_canvas->contextMenu());
+ if( ctxtmenu )
+ ctxtmenu->insertTitle(i18n("Image View"));
+ m_mainDock->setWidget( img_canvas );
+
+ /** Thumbview **/
+ m_dockThumbs = parent->createDockWidget( "Thumbs",
+ loader->loadIcon( "thumbnail", KIcon::Small ),
+ 0L, i18n("Thumbnails"));
+ m_dockThumbs->setDockSite(KDockWidget::DockFullSite );
+
+ /* thumbnail viewer widget */
+ m_thumbview = new ThumbView( m_dockThumbs);
+ m_dockThumbs->setWidget( m_thumbview );
+
+ m_dockThumbs->manualDock( m_mainDock, // dock target
+ KDockWidget::DockBottom, // dock site
+ 20 ); // relation target/this (in percent)
+
+ /** Packager Dock **/
+ /* A new packager to contain the already scanned images */
+ m_dockPackager = parent->createDockWidget( "Scanpackager",
+ loader->loadIcon( "palette_color", KIcon::Small ),
+ 0L, i18n("Gallery"));
+ m_dockPackager->setDockSite(KDockWidget::DockFullSite);
+ packager = new ScanPackager( m_dockPackager );
+ m_dockPackager->setWidget( packager );
+ m_dockPackager->manualDock( m_mainDock, // dock target
+ KDockWidget::DockLeft, // dock site
+ 30 ); // relation target/this (in percent)
+
+
+ connect( packager, SIGNAL(showThumbnails( KFileTreeViewItem* )),
+ this, SLOT( slShowThumbnails( KFileTreeViewItem* )));
+ connect( m_thumbview, SIGNAL( selectFromThumbnail( const KURL& )),
+ packager, SLOT( slSelectImage(const KURL&)));
+
+ /*
+ * Create a Kombobox that holds the last folders visible even on the preview page
+ */
+ m_dockRecent = parent->createDockWidget( "Recent",
+ loader->loadIcon( "image", KIcon::Small ),
+ 0L, i18n("Gallery Folders"));
+
+ m_dockRecent->setDockSite(KDockWidget::DockFullSite);
+
+ QHBox *recentBox = new QHBox( m_dockRecent );
+ recentBox->setMargin(KDialog::marginHint());
+ QLabel *lab = new QLabel( i18n("Gallery:"), recentBox );
+ lab->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
+ recentFolder = new ImageNameCombo( recentBox );
+
+ m_dockRecent->setWidget( recentBox );
+ m_dockRecent->manualDock( m_dockPackager, // dock target
+ KDockWidget::DockBottom, // dock site
+ 5 ); // relation target/this (in percent)
+
+
+
+ connect( packager, SIGNAL( galleryPathSelected( KFileTreeBranch*, const QString&)),
+ recentFolder, SLOT( slotGalleryPathChanged( KFileTreeBranch*, const QString& )));
+
+ connect( packager, SIGNAL( directoryToRemove( KFileTreeBranch*, const QString&)),
+ recentFolder, SLOT( slotPathRemove( KFileTreeBranch*, const QString& )));
+
+ connect( recentFolder, SIGNAL(activated( const QString& )),
+ packager, SLOT(slotSelectDirectory( const QString& )));
+
+ /* the object from the kscan lib to handle low level scanning */
+ m_dockScanParam = parent->createDockWidget( "Scan Parameter",
+ loader->loadIcon( "folder", KIcon::Small ),
+ 0L, i18n("Scan Parameter"));
+ //
+ m_dockScanParam->setDockSite(KDockWidget::DockFullSite);
+
+ m_dockScanParam->setWidget( 0 ); // later
+ sane = new KScanDevice( m_dockScanParam );
+ Q_CHECK_PTR(sane);
+
+ m_dockScanParam->manualDock( m_dockRecent, // dock target
+ KDockWidget::DockBottom, // dock site
+ 20 ); // relation target/this (in percent)
+ m_dockScanParam->hide();
+
+ /* select the scan device, either user or from config, this creates and assembles
+ * the complete scanner options dialog
+ * scan_params must be zero for that */
+
+ m_dockPreview = parent->createDockWidget( "Preview ",
+ loader->loadIcon( "viewmag", KIcon::Small ),
+ 0L, i18n("Scan Preview"));
+
+ preview_canvas = new Previewer( m_dockPreview );
+ {
+ preview_canvas->setMinimumSize( 100,100);
+
+ /* since the scan_params will be created in slSelectDevice, do the
+ * connections later
+ */
+ }
+ m_dockPreview->setWidget( preview_canvas );
+ m_dockPreview->manualDock( m_mainDock, // dock target
+ KDockWidget::DockCenter, // dock site
+ 100 ); // relation target/this (in percent)
+
+ /* Create a text editor part for ocr results */
+
+ m_dockOCRText = parent->createDockWidget( "OCRResults",
+ loader->loadIcon("edit", KIcon::Small ),
+ 0L, i18n("OCR Result Text"));
+ // m_textEdit
+ m_ocrResEdit = new ocrResEdit( m_dockOCRText );
+
+ if( m_ocrResEdit )
+ {
+ m_dockOCRText->setWidget( m_ocrResEdit ); // m_textEdit->widget() );
+ m_dockOCRText->manualDock( m_dockThumbs, // dock target
+ KDockWidget::DockCenter, // dock site
+ 100 ); // relation target/this (in percent)
+
+ m_ocrResEdit->setTextFormat( Qt::PlainText );
+ m_ocrResEdit->setWordWrap( QTextEdit::NoWrap );
+ // m_dockOCRText->hide();
+ }
+
+ if( slSelectDevice(deviceToUse))
+ {
+ /* Load from config which tab page was selected last time */
+ }
+
+ /* New image created after scanning */
+ connect(sane, SIGNAL(sigNewImage(QImage*,ImgScanInfo*)), this, SLOT(slNewImageScanned(QImage*,ImgScanInfo*)));
+ /* New preview image */
+ connect(sane, SIGNAL(sigNewPreview(QImage*,ImgScanInfo *)), this, SLOT( slNewPreview(QImage*,ImgScanInfo *)));
+
+ connect( sane, SIGNAL( sigScanStart() ), this, SLOT( slScanStart()));
+ connect( sane, SIGNAL( sigScanFinished(KScanStat)), this, SLOT(slScanFinished(KScanStat)));
+ connect( sane, SIGNAL( sigAcquireStart()), this, SLOT( slAcquireStart()));
+ /* Image canvas should show a new document */
+ connect( packager, SIGNAL( showImage( KookaImage* )),
+ this, SLOT( slShowAImage( KookaImage*)));
+
+ connect( packager, SIGNAL( aboutToShowImage(const KURL&)),
+ this, SLOT( slStartLoading( const KURL& )));
+
+ /* Packager unloads the image */
+ connect( packager, SIGNAL( unloadImage( KookaImage* )),
+ this, SLOT( slUnloadAImage( KookaImage*)));
+
+ /* a image changed mostly through a image manipulation method like rotate */
+ connect( packager, SIGNAL( fileChanged( KFileItem* )),
+ m_thumbview, SLOT( slImageChanged( KFileItem* )));
+
+ connect( packager, SIGNAL( fileRenamed( KFileItem*, const KURL& )),
+ m_thumbview, SLOT( slImageRenamed( KFileItem*, const KURL& )));
+
+ connect( packager, SIGNAL( fileDeleted( KFileItem* )),
+ m_thumbview, SLOT( slImageDeleted( KFileItem* )));
+
+
+ packager->openRoots();
+
+ /* Status Bar */
+ KStatusBar *statBar = m_mainWindow->statusBar();
+
+ // statBar->insertItem(QString("1"), SBAR_ZOOM, 0, true );
+ statBar->insertItem( QString("-"), StatusImage, 0, true );
+
+ /* Set a large enough size */
+ int w = statBar->fontMetrics().
+ width(img_canvas->imageInfoString(2000, 2000, 48));
+ kdDebug(28000) << "Fixed size for status bar: " << w << " from string " << img_canvas->imageInfoString(2000, 2000, 48) << endl;
+ statBar->setItemFixed( StatusImage, w );
+
+}
+
+
+KookaView::~KookaView()
+{
+ saveProperties( KGlobal::config () );
+ delete preview_canvas;
+
+ kdDebug(28000)<< "Finished saving config data" << endl;
+}
+
+void KookaView::slViewerReadOnly( bool )
+{
+ /* retrieve actions that could change the image */
+}
+
+
+bool KookaView::slSelectDevice( const QCString& useDevice )
+{
+
+ kdDebug(28000) << "Kookaview: select a device!" << endl;
+ bool haveConnection = false;
+
+ QCString selDevice;
+ /* in case useDevice is the term 'gallery', the user does not want to
+ * connect to a scanner, but only work in gallery mode. Otherwise, try
+ * to read the device to use from config or from a user dialog */
+ if( useDevice != "gallery" )
+ {
+ selDevice = useDevice;
+ if( selDevice.isEmpty())
+ {
+ selDevice = userDeviceSelection();
+ }
+ }
+
+ if( !selDevice.isEmpty() )
+ {
+ kdDebug(28000) << "Opening device " << selDevice << endl;
+
+ if( connectedDevice == selDevice ) {
+ kdDebug( 28000) << "Device " << selDevice << " is already selected!" << endl;
+ return( true );
+ }
+
+ if( scan_params )
+ {
+ /* This deletes the existing scan_params^-object */
+ slCloseScanDevice();
+ }
+
+ /* This connects to the selected scanner */
+ scan_params = new ScanParams( m_dockScanParam );
+ Q_CHECK_PTR(scan_params);
+
+ if( sane->openDevice( selDevice ) == KSCAN_OK )
+ {
+ connect( scan_params, SIGNAL( scanResolutionChanged( int, int )),
+ preview_canvas, SLOT( slNewScanResolutions( int, int )));
+
+ if( ! scan_params->connectDevice( sane ) )
+ {
+ kdDebug(28000) << "Connecting to the scanner failed :( ->TODO" << endl;
+ }
+ else
+ {
+ haveConnection = true;
+ connectedDevice = selDevice;
+
+ /* New Rectangle selection in the preview, now scanimge exists */
+ ImageCanvas *previewCanvas = preview_canvas->getImageCanvas();
+ connect( previewCanvas , SIGNAL( newRect(QRect)),
+ scan_params, SLOT(slCustomScanSize(QRect)));
+ connect( previewCanvas, SIGNAL( noRect()),
+ scan_params, SLOT(slMaximalScanSize()));
+ // connect( scan_params, SIGNAL( scanResolutionChanged( int, int )),
+ // preview_canvas, SLOT( slNewScanResolutions( int, int )));
+ /* load the preview image */
+ if( preview_canvas )
+ {
+ preview_canvas->setPreviewImage( sane->loadPreviewImage() );
+
+ /* Call this after the devic is actually open */
+ preview_canvas->slConnectScanner( sane );
+ }
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "Could not open device <" << selDevice << ">" << endl;
+ scan_params->connectDevice(0);
+ }
+
+ /* show the widget again */
+
+ m_dockScanParam->setWidget( scan_params );
+
+ m_dockScanParam->show();
+ }
+ else
+ {
+ // no devices available or starting in gallery mode
+ if( scan_params )
+ scan_params->connectDevice( 0L );
+ }
+ return( haveConnection );
+}
+
+QCString KookaView::userDeviceSelection( ) const
+{
+ /* Human readable scanner descriptions */
+ QStringList hrbackends;
+
+ /* a list of backends the scan backend knows */
+ QStrList backends = sane->getDevices();
+ QStrListIterator it( backends );
+
+ QCString selDevice;
+ if( backends.count() > 0 )
+ {
+ while( it )
+ {
+ kdDebug( 28000 ) << "Found backend: " << it.current() << endl;
+ hrbackends.append( sane->getScannerName( it.current() ));
+ ++it;
+ }
+
+ /* allow the user to select one */
+ DeviceSelector ds( 0, backends, hrbackends );
+ selDevice = ds.getDeviceFromConfig( );
+
+ if( selDevice.isEmpty() || selDevice.isNull() )
+ {
+ kdDebug(29000) << "selDevice not found - starting selector!" << selDevice << endl;
+ if ( ds.exec() == QDialog::Accepted )
+ {
+ selDevice = ds.getSelectedDevice();
+ }
+ }
+ }
+ return( selDevice );
+}
+
+
+void KookaView::loadStartupImage( void )
+{
+ kdDebug( 28000) << "Starting to load startup image" << endl;
+
+ /* Now set the configured stuff */
+ KConfig *konf = KGlobal::config ();
+ if( konf )
+ {
+ konf->setGroup(GROUP_STARTUP);
+ bool wantReadOnStart = konf->readBoolEntry( STARTUP_READ_IMAGE, true );
+
+ if( wantReadOnStart )
+ {
+ QString startup = konf->readPathEntry( STARTUP_IMG_SELECTION );
+
+ if( !startup.isEmpty() )
+ {
+ kdDebug(28000) << "Loading startup image !" << endl;
+ packager->slSelectImage( KURL(startup) );
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "Do not load startup image due to config value" << endl;
+ }
+ }
+}
+
+
+void KookaView::print()
+{
+ /* For now, print a single file. Later, print multiple images to one page */
+ KookaImage *img = packager->getCurrImage();
+ if ( !img )
+ return;
+ KPrinter printer; // ( true, pMode );
+ printer.setUsePrinterResolution(true);
+ printer.addDialogPage( new ImgPrintDialog( img ));
+
+ if( printer.setup( m_mainWindow, i18n("Print %1").arg(img->localFileName().section('/', -1)) ))
+ {
+ KookaPrint kookaprint( &printer );
+ kookaprint.printImage(img);
+ }
+}
+
+void KookaView::slNewPreview( QImage *new_img, ImgScanInfo * )
+{
+ if( new_img )
+ {
+ if( ! new_img->isNull() )
+ {
+ /* flip preview to front */
+ m_dockPreview->makeDockVisible();
+ }
+ preview_canvas->newImage( new_img );
+ }
+}
+
+
+bool KookaView::ToggleVisibility( int item )
+{
+ QWidget *w = 0;
+ bool ret = false;
+
+ switch( item )
+ {
+ case ID_VIEW_SCANPARAMS:
+ w = scan_params;
+ break;
+ case ID_VIEW_POOL:
+ w = preview_canvas;
+ break;
+ default:
+ w = 0;
+ }
+
+ if( w )
+ {
+ if( w->isVisible() )
+ {
+ w->hide();
+ ret = false;
+ }
+ else
+ {
+ w->show();
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+
+void KookaView::doOCRonSelection( void )
+{
+ emit( signalChangeStatusbar( i18n("Starting OCR on selection" )));
+
+ KookaImage img;
+
+ if( img_canvas->selectedImage(&img) )
+ {
+ startOCR( &img );
+ }
+ emit( signalCleanStatusbar() );
+}
+
+/* Does OCR on the entire picture */
+void KookaView::doOCR( void )
+{
+ emit( signalChangeStatusbar( i18n("Starting OCR on the entire image" )));
+ KookaImage *img = packager->getCurrImage();
+ startOCR( img );
+ emit( signalCleanStatusbar( ));
+}
+
+void KookaView::startOCR( KookaImage *img )
+{
+ if( img && ! img->isNull() )
+ {
+ if( ocrFabric == 0L )
+ {
+ ocrFabric = new KSANEOCR( m_mainDock, KGlobal::config() );
+ ocrFabric->setImageCanvas( img_canvas );
+
+ connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )),
+ m_ocrResEdit, SLOT(setText( const QString& )));
+
+ connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )),
+ m_dockOCRText, SLOT( show() ));
+
+ connect( ocrFabric, SIGNAL( repaintOCRResImage( )),
+ img_canvas, SLOT(repaint()));
+
+ connect( ocrFabric, SIGNAL( clearOCRResultText()),
+ m_ocrResEdit, SLOT(clear()));
+
+ connect( ocrFabric, SIGNAL( updateWord(int, const QString&, const QString& )),
+ m_ocrResEdit, SLOT( slUpdateOCRResult( int, const QString&, const QString& )));
+
+ connect( ocrFabric, SIGNAL( ignoreWord(int, const ocrWord&)),
+ m_ocrResEdit, SLOT( slIgnoreWrongWord( int, const ocrWord& )));
+
+ connect( ocrFabric, SIGNAL( markWordWrong(int, const ocrWord& )),
+ m_ocrResEdit, SLOT( slMarkWordWrong( int, const ocrWord& )));
+
+ connect( ocrFabric, SIGNAL( readOnlyEditor( bool )),
+ m_ocrResEdit, SLOT( setReadOnly( bool )));
+
+ connect( ocrFabric, SIGNAL( selectWord( int, const ocrWord& )),
+ m_ocrResEdit, SLOT( slSelectWord( int, const ocrWord& )));
+
+ }
+
+ Q_CHECK_PTR( ocrFabric );
+ ocrFabric->slSetImage( img );
+
+ if( !ocrFabric->startOCRVisible(m_mainDock) )
+ {
+ KMessageBox::sorry(0, i18n("Could not start OCR-Process.\n"
+ "Probably there is already one running." ));
+
+ }
+ }
+}
+
+
+void KookaView::slOCRResultImage( const QPixmap& pix )
+{
+ kdDebug(28000) << "Showing OCR Result Image" << endl;
+ if( ! img_canvas ) return;
+
+ if( m_ocrResultImg )
+ {
+ img_canvas->newImage(0L);
+ delete m_ocrResultImg;
+ }
+
+ m_ocrResultImg = new QImage();
+ *m_ocrResultImg = pix;
+ img_canvas->newImage( m_ocrResultImg );
+ img_canvas->setReadOnly(true); // ocr result images should be read only.
+}
+
+void KookaView::slScanStart( )
+{
+ kdDebug(28000) << "Scan starts " << endl;
+ if( scan_params )
+ {
+ scan_params->setEnabled( false );
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::red );
+ led->setState( KLed::On );
+ }
+ }
+}
+
+void KookaView::slAcquireStart( )
+{
+ kdDebug(28000) << "Acquire starts " << endl;
+ if( scan_params )
+ {
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ }
+ }
+}
+
+void KookaView::slNewImageScanned( QImage* img, ImgScanInfo* si )
+{
+ KookaImageMeta *meta = new KookaImageMeta;
+ meta->setScanResolution(si->getXResolution(), si->getYResolution());
+ packager->slAddImage(img, meta);
+}
+
+
+
+void KookaView::slScanFinished( KScanStat stat )
+{
+ kdDebug(28000) << "Scan finished with status " << stat << endl;
+ if( scan_params )
+ {
+ scan_params->setEnabled( true );
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ led->setState( KLed::Off );
+ }
+ }
+}
+
+
+void KookaView::slCloseScanDevice( )
+{
+ kdDebug(28000) << "Scanner Device closes down !" << endl;
+ if( scan_params ) {
+ delete scan_params;
+ scan_params = 0;
+ m_dockScanParam->setWidget(0L);
+ m_dockScanParam->hide();
+ }
+
+ sane->slCloseDevice();
+}
+
+void KookaView::slCreateNewImgFromSelection()
+{
+ if( img_canvas->rootImage() )
+ {
+ emit( signalChangeStatusbar( i18n("Create new image from selection" )));
+ QImage img;
+ if( img_canvas->selectedImage( &img ) )
+ {
+ packager->slAddImage( &img );
+ }
+ emit( signalCleanStatusbar( ));
+ }
+
+}
+
+
+void KookaView::slRotateImage(int angle)
+{
+ // QImage *img = (QImage*) img_canvas->rootImage();
+ KookaImage *img = packager->getCurrImage();
+ bool doUpdate = true;
+
+ if( img )
+ {
+ QImage resImg;
+
+ QApplication::setOverrideCursor(waitCursor);
+ switch( angle )
+ {
+ case 90:
+ emit( signalChangeStatusbar( i18n("Rotate image 90 degrees" )));
+ resImg = rotateRight( img );
+ break;
+ case 180:
+ emit( signalChangeStatusbar( i18n("Rotate image 180 degrees" )));
+ resImg = rotate180( img );
+ break;
+ case 270:
+ case -90:
+ emit( signalChangeStatusbar( i18n("Rotate image -90 degrees" )));
+ resImg = rotateLeft( img );
+
+ break;
+ default:
+ kdDebug(28000) << "Not supported yet !" << endl;
+ doUpdate = false;
+
+ break;
+ }
+ QApplication::restoreOverrideCursor();
+
+ /* updateCurrImage does the status-bar cleanup */
+ if( doUpdate )
+ updateCurrImage( resImg );
+ else
+ emit(signalCleanStatusbar());
+ }
+
+}
+
+
+
+void KookaView::slMirrorImage( MirrorType m )
+{
+ const QImage *img = img_canvas->rootImage();
+ bool doUpdate = true;
+
+ if( img )
+ {
+ QImage resImg;
+
+ QApplication::setOverrideCursor(waitCursor);
+ switch( m )
+ {
+ case MirrorVertical:
+ emit( signalChangeStatusbar( i18n("Mirroring image vertically" )));
+ resImg = img->mirror();
+ break;
+ case MirrorHorizontal:
+ emit( signalChangeStatusbar( i18n("Mirroring image horizontally" )));
+ resImg = img->mirror( true, false );
+ break;
+ case MirrorBoth:
+ emit( signalChangeStatusbar( i18n("Mirroring image in both directions" )));
+ resImg = img->mirror( true, true );
+ break;
+ default:
+ kdDebug(28000) << "Mirroring: no way ;)" << endl;
+ doUpdate = false;
+ }
+ QApplication::restoreOverrideCursor();
+
+ /* updateCurrImage does the status-bar cleanup */
+ if( doUpdate )
+ updateCurrImage( resImg );
+ else
+ emit(signalCleanStatusbar());
+
+ // img_canvas->newImage( );
+ }
+}
+
+
+void KookaView::slSaveOCRResult()
+{
+ if( ! m_ocrResEdit ) return;
+ m_ocrResEdit->slSaveText();
+
+}
+
+
+void KookaView::slLoadScanParams( )
+{
+ if( ! sane ) return;
+#if 0
+ /* not yet cooked */
+ LoadSetDialog loadDialog( m_mainDock, sane->shortScannerName(), sane );
+ if( loadDialog.exec())
+ {
+ kdDebug(28000)<< "Executed successfully" << endl;
+ }
+#endif
+}
+
+void KookaView::slSaveScanParams( )
+{
+ if( !sane ) return;
+
+ /* not yet cooked */
+#if 0
+ KScanOptSet optSet( "SaveSet" );
+
+ sane->getCurrentOptions( &optSet );
+ SaveSetDialog dialog( m_mainDock /* this */ , &optSet );
+ if( dialog.exec())
+ {
+ kdDebug(28000)<< "Executed successfully" << endl;
+ QString name = dialog.paramSetName();
+ QString desc = dialog.paramSetDescription();
+ sane->slSaveScanConfigSet( name, desc );
+ }
+#endif
+}
+
+void KookaView::slShowAImage( KookaImage *img )
+{
+ kdDebug(28000) << "Show new Image" << endl;
+ if( img_canvas )
+ {
+ img_canvas->newImage( img );
+ img_canvas->setReadOnly(false);
+ }
+
+ /* tell ocr about */
+ if( ocrFabric )
+ {
+ ocrFabric->slSetImage( img );
+ }
+
+ /* Status Bar */
+ KStatusBar *statBar = m_mainWindow->statusBar();
+ if( img_canvas )
+ statBar->changeItem( img_canvas->imageInfoString(), StatusImage );
+}
+
+void KookaView::slUnloadAImage( KookaImage * )
+{
+ kdDebug(28000) << "Unloading Image" << endl;
+ if( img_canvas )
+ {
+ img_canvas->newImage( 0L );
+ }
+}
+
+
+void KookaView::slShowThumbnails(KFileTreeViewItem *dirKfi, bool forceRedraw )
+{
+ /* If no item is specified, use the current one */
+ if( ! dirKfi )
+ {
+ /* do on the current visible dir */
+ KFileTreeViewItem *kftvi = packager->currentKFileTreeViewItem();
+ if ( !kftvi )
+ {
+ return;
+ }
+
+ if( kftvi->isDir())
+ {
+ dirKfi = kftvi;
+ }
+ else
+ {
+ kftvi = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(kftvi)->parent());
+ dirKfi = kftvi;
+ forceRedraw = true;
+ packager->setSelected( static_cast<QListViewItem*>(dirKfi), true );
+ }
+ }
+
+ kdDebug(28000) << "Showing thumbs for " << dirKfi->url().prettyURL() << endl;
+
+ /* Only do the new thumbview if the old is on another dir */
+ if( m_thumbview && (forceRedraw || m_thumbview->currentDir() != dirKfi->url()) )
+ {
+ m_thumbview->clear();
+ /* Find a list of child KFileItems */
+ if( forceRedraw ) m_thumbview->readSettings();
+
+ KFileItemList fileItemsList;
+
+ QListViewItem * myChild = dirKfi->firstChild();
+ while( myChild )
+ {
+ fileItemsList.append( static_cast<KFileTreeViewItem*>(myChild)->fileItem());
+ myChild = myChild->nextSibling();
+ }
+
+ m_thumbview->slNewFileItems( fileItemsList );
+ m_thumbview->setCurrentDir( dirKfi->url());
+ // m_thumbview->arrangeItemsInGrid();
+ }
+
+}
+
+/* this slot is called when the user clicks on an image in the packager
+ * and loading of the image starts
+ */
+void KookaView::slStartLoading( const KURL& url )
+{
+ emit( signalChangeStatusbar( i18n("Loading %1" ).arg( url.prettyURL() ) ));
+
+ // if( m_stack->visibleWidget() != img_canvas )
+ // {
+ // m_stack->raiseWidget( img_canvas );
+ // }
+
+}
+
+
+void KookaView::updateCurrImage( QImage& img )
+{
+ if( ! img_canvas->readOnly() )
+ {
+ emit( signalChangeStatusbar( i18n("Storing image changes" )));
+ packager->slotCurrentImageChanged( &img );
+ emit( signalCleanStatusbar());
+ }
+ else
+ {
+ emit( signalChangeStatusbar( i18n("Can not save image, it is write protected!")));
+ kdDebug(28000) << "Image is write protected, no saving!" << endl;
+ }
+}
+
+
+void KookaView::saveProperties(KConfig *config)
+{
+ kdDebug(28000) << "Saving Properties for KookaView !" << endl;
+ config->setGroup( GROUP_STARTUP );
+ /* Get with path */
+ config->writePathEntry( STARTUP_IMG_SELECTION, packager->getCurrImageFileName(true));
+
+}
+
+
+void KookaView::slOpenCurrInGraphApp( void )
+{
+ QString file;
+
+ if( packager )
+ {
+ KFileTreeViewItem *ftvi = packager->currentKFileTreeViewItem();
+
+ if( ! ftvi ) return;
+
+ kdDebug(28000) << "Trying to open <" << ftvi->url().prettyURL()<< ">" << endl;
+ KURL::List urllist;
+
+ urllist.append( ftvi->url());
+
+ KRun::displayOpenWithDialog( urllist );
+ }
+}
+
+
+QImage KookaView::rotateLeft( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(-90);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+QImage KookaView::rotateRight( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(+90);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+QImage KookaView::rotate180( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(+180);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+
+
+void KookaView::connectViewerAction( KAction *action )
+{
+ QPopupMenu *popup = img_canvas->contextMenu();
+ kdDebug(29000) << "This is the popup: " << popup << endl;
+ if( popup && action )
+ {
+ action->plug( popup );
+ }
+}
+
+void KookaView::connectGalleryAction( KAction *action )
+{
+ QPopupMenu *popup = packager->contextMenu();
+
+ if( popup && action )
+ {
+ action->plug( popup );
+ }
+}
+
+void KookaView::slFreshUpThumbView()
+{
+ if( m_thumbview )
+ {
+ /* readSettings returns true if something changes */
+ if( m_thumbview->readSettings() )
+ {
+ kdDebug(28000) << "Thumbview-Settings changed, readraw thumbs" << endl;
+ /* new settings */
+ slShowThumbnails(0, true);
+ }
+ }
+}
+
+void KookaView::createDockMenu( KActionCollection *col, KDockMainWindow *mainWin, const char * name )
+{
+ KActionMenu *actionMenu = new KActionMenu( i18n("Tool Views"), "view_icon", col, name );
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Image Viewer"),
+ KShortcut(), m_mainDock, col,
+ mainWin, "dock_viewer" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Preview"),
+ KShortcut(), m_dockPreview, col,
+ mainWin, "dock_preview" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Recent Gallery Folders"),
+ KShortcut(), m_dockRecent, col,
+ mainWin, "dock_recent" ));
+ actionMenu->insert( new dwMenuAction( i18n("Show Gallery"),
+ KShortcut(), m_dockPackager, col,
+ mainWin, "dock_gallery" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Thumbnail Window"),
+ KShortcut(), m_dockThumbs, col,
+ mainWin, "dock_thumbs" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Scan Parameters"),
+ KShortcut(), m_dockScanParam, col,
+ mainWin, "dock_scanparams" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show OCR Results"),
+ KShortcut(), m_dockOCRText, col,
+ mainWin, "dock_ocrResults" ));
+}
+
+
+#include "kookaview.moc"
diff --git a/kooka/kookaview.h b/kooka/kookaview.h
new file mode 100644
index 00000000..a1f7898a
--- /dev/null
+++ b/kooka/kookaview.h
@@ -0,0 +1,241 @@
+/***************************************************************************
+ kookaview.h - Main view
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#ifndef KOOKAVIEW_H
+#define KOOKAVIEW_H
+
+#include <qwidget.h>
+#include <kopenwith.h>
+#include "kookaiface.h"
+#include <kdockwidget.h>
+#include <qtabwidget.h>
+#include <qlayout.h>
+#include <qimage.h>
+#include <qsplitter.h>
+
+#include <kparts/dockmainwindow.h>
+#include <kparts/part.h>
+
+// application specific includes
+#include "kscandevice.h"
+#include "previewer.h"
+#include "scanpackager.h"
+#include "scanparams.h"
+#include "img_canvas.h"
+
+class KDockWidget;
+class QPainter;
+class KSANEOCR;
+class KConfig;
+class KPrinter;
+class KComboBox;
+class KAction;
+class KActionCollection;
+class ThumbView;
+class KookaImage;
+class QPixmap;
+class ocrResEdit;
+/**
+ * This is the main view class for Kooka. Most of the non-menu,
+ * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
+ * here.
+ *
+ * @short Main view
+ * @author Klaas Freitag <freitag@suse.de>
+ * @version 0.1
+ */
+class KookaView : public QObject
+{
+ Q_OBJECT
+public:
+ typedef enum { MirrorVertical, MirrorHorizontal, MirrorBoth } MirrorType;
+ typedef enum { StatusTemp, StatusImage } StatusBarIDs;
+
+ /**
+ * Default constructor
+ */
+ KookaView(KParts::DockMainWindow *parent, const QCString& deviceToUse);
+
+ /**
+ * Destructor
+ */
+ virtual ~KookaView();
+
+ /**
+ * Print this view to any medium -- paper or not
+ */
+ void print( );
+
+ bool ToggleVisibility( int );
+ void loadStartupImage( void );
+ KDockWidget *mainDockWidget( ) { return m_mainDock; }
+
+ void createDockMenu( KActionCollection*, KDockMainWindow *, const char *);
+
+ ScanPackager *gallery() { return packager; }
+
+ // KParts::Part* ocrResultPart() { return m_textEdit; }
+
+ ImageCanvas *getImageViewer() { return img_canvas; }
+public slots:
+ void slShowPreview() { }
+ void slShowPackager() { }
+ void slNewPreview( QImage *, ImgScanInfo * );
+
+ void slSetScanParamsVisible( bool v )
+ { if( v ) scan_params->show(); else scan_params->hide(); }
+ void slSetTabWVisible( bool v )
+ { if( v ) preview_canvas->show(); else preview_canvas->hide(); }
+
+ void doOCR( void );
+ void doOCRonSelection( void );
+
+ void slStartPreview() { if( scan_params ) scan_params->slAcquirePreview(); }
+ void slStartFinalScan() { if( scan_params ) scan_params->slStartScan(); }
+
+ void slCreateNewImgFromSelection( void );
+
+ void slRotateImage( int );
+
+ void slMirrorImage( MirrorType );
+
+ void slIVScaleToWidth( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_WIDTH );}
+ void slIVScaleToHeight( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_HEIGHT );}
+ void slIVScaleOriginal( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_ORIG_SIZE ); }
+ void slIVShowZoomDialog( )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_POP_ZOOM ); }
+
+ void slOpenCurrInGraphApp( void );
+
+ void slSaveOCRResult();
+
+ void slLoadScanParams( );
+ void slSaveScanParams( );
+
+ void slOCRResultImage( const QPixmap& );
+
+ void slShowThumbnails( KFileTreeViewItem *dirKfi = 0, bool forceRedraw=false);
+ void slFreshUpThumbView();
+
+ /**
+ * slot that show the image viewer
+ */
+ void slStartLoading( const KURL& url );
+ /**
+ * starts ocr on the image the parameter is pointing to
+ **/
+ void startOCR( KookaImage* );
+
+ void slCloseScanDevice();
+ void saveProperties( KConfig* );
+
+ /**
+ * slot to select the scanner device. Does all the work with selection
+ * of scanner, disconnection of the old device and connecting the new.
+ */
+ bool slSelectDevice(const QCString& useDevice=QCString());
+
+ void connectViewerAction( KAction *action );
+ void connectGalleryAction( KAction *action );
+
+ void slScanStart();
+ void slScanFinished( KScanStat stat );
+ void slAcquireStart();
+
+
+protected slots:
+
+ void slShowAImage( KookaImage* );
+ void slUnloadAImage( KookaImage* );
+
+ /**
+ * called from the scandevice if a new Image was successfully scanned.
+ * Needs to convert the one-page-QImage to a KookaImage
+ */
+ void slNewImageScanned(QImage*, ImgScanInfo*);
+
+ /**
+ * called if an viewer image was set to read only or back to read write state.
+ */
+ void slViewerReadOnly( bool ro );
+signals:
+ /**
+ * Use this signal to change the content of the statusbar
+ */
+ void signalChangeStatusbar(const QString& text);
+
+ /**
+ * Use this signal to clean up the statusbar
+ */
+ void signalCleanStatusbar( void );
+
+ /**
+ * Use this signal to change the content of the caption
+ */
+ void signalChangeCaption(const QString& text);
+
+private:
+ QImage rotateRight( QImage* );
+ QImage rotateLeft ( QImage* );
+ QImage rotate180 ( QImage* );
+ QCString userDeviceSelection( ) const;
+
+ void updateCurrImage( QImage& ) ;
+
+ ImageCanvas *img_canvas;
+ ThumbView *m_thumbview;
+
+ Previewer *preview_canvas;
+ ScanPackager *packager;
+ ScanParams *scan_params;
+
+ KScanDevice *sane;
+ KComboBox *recentFolder;
+
+ QCString connectedDevice;
+
+ QImage *m_ocrResultImg;
+ int image_pool_id;
+ int preview_id;
+
+ KSANEOCR *ocrFabric;
+
+ KDockWidget *m_mainDock;
+ KDockWidget *m_dockScanParam;
+ KDockWidget *m_dockThumbs;
+ KDockWidget *m_dockPackager;
+ KDockWidget *m_dockRecent;
+ KDockWidget *m_dockPreview;
+ KDockWidget *m_dockOCRText;
+
+ KMainWindow *m_mainWindow;
+
+ ocrResEdit *m_ocrResEdit;
+};
+
+#endif // KOOKAVIEW_H
diff --git a/kooka/ksaneocr.cpp b/kooka/ksaneocr.cpp
new file mode 100644
index 00000000..cf10d682
--- /dev/null
+++ b/kooka/ksaneocr.cpp
@@ -0,0 +1,1493 @@
+/***************************************************************************
+ ksaneocr.cpp - generic ocr
+ -------------------
+ begin : Fri Jun 30 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <ktempfile.h>
+#include <kprocess.h>
+#include <stdlib.h>
+#include <kspell.h>
+#include <kspelldlg.h>
+#include <qfile.h>
+#include <qcolor.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <img_canvas.h>
+
+#include "img_saver.h"
+#include "kadmosocr.h"
+#include "kocrbase.h"
+#include "kocrkadmos.h"
+#include "kocrocrad.h"
+#include "config.h"
+#include "ksaneocr.h"
+#include "kocrgocr.h"
+#include "kookaimage.h"
+#include "kookapref.h"
+#include "ocrword.h"
+
+#include <qtimer.h>
+#include <qregexp.h>
+#include <klocale.h>
+#include <qpaintdevice.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qfileinfo.h>
+
+/*
+ * Thread support is disabled here because the kadmos lib seems not to be
+ * thread save unfortunately. See slotKadmosResult-comments for more information
+ */
+
+KSANEOCR::KSANEOCR( QWidget*, KConfig *cfg ):
+ m_ocrProcessDia(0L),
+ daemon(0L),
+ visibleOCRRunning(false),
+ m_resultImage(0),
+ m_imgCanvas(0L),
+ m_spell(0L),
+ m_wantKSpell(true),
+ m_kspellVisible(true),
+ m_hideDiaWhileSpellcheck(true),
+ m_spellInitialConfig(0L),
+ m_parent(0L),
+ m_ocrCurrLine(0),
+ m_currHighlight(-1),
+ m_applyFilter(false),
+ m_unlinkORF(true)
+{
+ KConfig *konf = KGlobal::config ();
+ m_ocrEngine = OCRAD;
+ m_img = 0L;
+ m_tmpFile = 0L;
+
+ if( cfg )
+ m_hideDiaWhileSpellcheck = cfg->readBoolEntry( HIDE_BASE_DIALOG, true );
+ /*
+ * a initial config is needed as a starting point for the config dialog
+ * but also for ocr without visible dialog.
+ */
+ m_spellInitialConfig = new KSpellConfig( 0L, 0L ,0L, false );
+
+ if( konf )
+ {
+ /* -- ocr dialog information -- */
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+ QString eng = konf->readEntry(CFG_OCR_ENGINE, "ocrad");
+
+ if( eng == "ocrad" )
+ {
+ m_ocrEngine = OCRAD;
+ }
+ else if( eng == "gocr" )
+ {
+ m_ocrEngine = GOCR;
+ }
+#ifdef HAVE_KADMOS
+ else if( eng == QString("kadmos") ) m_ocrEngine = KADMOS;
+#endif
+ kdDebug(28000) << "OCR engine is " << eng << endl;
+
+ m_unlinkORF = konf->readBoolEntry( CFG_OCR_CLEANUP, true );
+ }
+
+ /* resize m_blocks to size 1 since there is at least one block */
+ m_blocks.resize(1);
+
+}
+
+
+KSANEOCR::~KSANEOCR()
+{
+ if( daemon ) {
+ delete( daemon );
+ daemon = 0;
+ }
+ if ( m_tmpFile )
+ {
+ m_tmpFile->setAutoDelete( true );
+ delete m_tmpFile;
+ }
+
+ if( m_resultImage )
+ {
+ delete m_resultImage;
+ m_resultImage = 0;
+ }
+
+ if( m_img ) delete m_img;
+ if( m_spellInitialConfig ) delete m_spellInitialConfig;
+}
+
+/*
+ * This slot is called to introduce a new image, usually if the user clicks on a
+ * new image either in the gallery or on the thumbnailview.
+ */
+void KSANEOCR::slSetImage(KookaImage *img )
+{
+ if( ! img ) return ;
+
+ if( m_img )
+ delete m_img;
+
+ // FIXME: copy all the image is bad.
+ m_img = new KookaImage(*img);
+
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->introduceImage( m_img );
+ }
+
+ m_applyFilter = false;
+}
+
+/*
+ * Request to visualise a line-box in the source image, KADMOS Engine
+ */
+void KSANEOCR::slLineBox( const QRect& )
+{
+ if( ! m_img ) return;
+}
+
+
+/*
+ * starts visual ocr process. Depending on the ocr engine, this function creates
+ * a new dialog, and shows it.
+ */
+bool KSANEOCR::startOCRVisible( QWidget *parent )
+{
+ if( visibleOCRRunning ) return( false );
+ bool res = true;
+
+ m_parent = parent;
+
+ if( m_ocrEngine == GOCR )
+ {
+ m_ocrProcessDia = new KGOCRDialog ( parent, m_spellInitialConfig );
+ }
+ else if( m_ocrEngine == OCRAD )
+ {
+ m_ocrProcessDia = new ocradDialog( parent, m_spellInitialConfig );
+ }
+ else if( m_ocrEngine == KADMOS )
+ {
+#ifdef HAVE_KADMOS
+/*** Kadmos Engine OCR ***/
+ m_ocrProcessDia = new KadmosDialog( parent, m_spellInitialConfig );
+#else
+ KMessageBox::sorry(0, i18n("This version of Kooka was not compiled with KADMOS support.\n"
+ "Please select another OCR engine in Kooka's options dialog."));
+ kdDebug(28000) << "Sorry, this version of Kooka has no KADMOS support" << endl;
+#endif /* HAVE_KADMOS */
+ }
+ else
+ {
+ kdDebug(28000) << "ERR Unknown OCR engine requested!" << endl;
+ }
+
+ /*
+ * this part is independant from the engine again
+ */
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->setupGui();
+
+ m_ocrProcessDia->introduceImage( m_img );
+ visibleOCRRunning = true;
+
+ connect( m_ocrProcessDia, SIGNAL( user1Clicked()), this, SLOT( startOCRProcess() ));
+ connect( m_ocrProcessDia, SIGNAL( closeClicked()), this, SLOT( slotClose() ));
+ connect( m_ocrProcessDia, SIGNAL( user2Clicked()), this, SLOT( slotStopOCR() ));
+ m_ocrProcessDia->show();
+
+ }
+ return( res );
+}
+
+/**
+ * This method should be called by the engine specific finish slots.
+ * It does the not engine dependant cleanups like re-enabling buttons etc.
+ */
+
+void KSANEOCR::finishedOCRVisible( bool success )
+{
+ bool doSpellcheck = m_wantKSpell;
+
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->stopOCR();
+ doSpellcheck = m_ocrProcessDia->wantSpellCheck();
+ }
+
+ if( success )
+ {
+ QString goof = ocrResultText();
+
+ emit newOCRResultText(goof);
+
+ if( m_imgCanvas )
+ {
+ if( m_resultImage != 0 ) delete m_resultImage;
+ kdDebug(28000) << "Result image name: " << m_ocrResultImage << endl;
+ m_resultImage = new QImage( m_ocrResultImage, "BMP" );
+ kdDebug(28000) << "New result image has dimensions: " << m_resultImage->width() << "x" << m_resultImage->height()<< endl;
+ /* The image canvas is non-zero. Set it to our image */
+ m_imgCanvas->newImageHoldZoom( m_resultImage );
+ m_imgCanvas->setReadOnly(true);
+
+ /* now handle double clicks to jump to the word */
+ m_applyFilter=true;
+ }
+
+ /** now it is time to invoke the dictionary if required **/
+ emit readOnlyEditor( false );
+
+ if( doSpellcheck )
+ {
+ m_ocrCurrLine = 0;
+ /*
+ * create a new kspell object, based on the config of the base dialog
+ */
+
+ connect( new KSpell( m_parent, i18n("Kooka OCR Dictionary Check"),
+ this, SLOT( slSpellReady(KSpell*)),
+ m_ocrProcessDia->spellConfig() ),
+ SIGNAL( death()), this, SLOT(slSpellDead()));
+ }
+
+ delete m_ocrProcessDia;
+ m_ocrProcessDia = 0L;
+
+ }
+
+ visibleOCRRunning = false;
+ cleanUpFiles();
+
+
+ kdDebug(28000) << "# ocr finished #" << endl;
+}
+
+/*
+ * starting the spell check on line m_ocrCurrLine if the line exists.
+ * If not, the function returns.
+ */
+void KSANEOCR::startLineSpellCheck()
+{
+ if( m_ocrCurrLine < m_ocrPage.size() )
+ {
+ m_checkStrings = (m_ocrPage[m_ocrCurrLine]).stringList();
+
+ /* In case the checklist is empty, call the result slot immediately */
+ if( m_checkStrings.count() == 0 )
+ {
+ slCheckListDone(false);
+ return;
+ }
+
+ kdDebug(28000)<< "Wordlist (size " << m_ocrPage[m_ocrCurrLine].count() << ", line " << m_ocrCurrLine << "):" << m_checkStrings.join(", ") << endl;
+
+ // if( list.count() > 0 )
+
+ m_spell->checkList( &m_checkStrings, m_kspellVisible );
+ kdDebug(28000)<< "Started!" << endl;
+ /**
+ * This call ends in three slots:
+ * 1. slMisspelling: Hit _before_ the dialog (if any) appears. Time to
+ * mark the wrong word.
+ * 2. slSpellCorrected: Hit if the user decided which word to use.
+ * 3. slCheckListDone: The line is finished. The global counter needs to be
+ * increased and this function needs to be called again.
+ **/
+
+ }
+ else
+ {
+ kdDebug(28000) << k_funcinfo <<" -- no more lines !" << endl;
+ m_spell->cleanUp();
+ }
+}
+
+
+
+/* User Cancel is called when the user does not really start the
+ * ocr but uses the cancel-Button to come out of the Dialog */
+void KSANEOCR::slotClose()
+{
+ kdDebug(28000) << "closing ocr Dialog" << endl;
+ if( daemon && daemon->isRunning() )
+ {
+ kdDebug(28000) << "Still running - Killing daemon with Sig. 9" << endl;
+ daemon->kill(9);
+ }
+ finishedOCRVisible(false);
+}
+
+void KSANEOCR::slotStopOCR()
+{
+ kdDebug(28000) << "closing ocr Dialog" << endl;
+ if( daemon && daemon->isRunning() )
+ {
+ kdDebug(28000) << "Killing daemon with Sig. 9" << endl;
+ daemon->kill(9);
+ // that leads to the process being destroyed.
+ KMessageBox::error(0, i18n("The OCR-process was stopped.") );
+ }
+
+}
+
+void KSANEOCR::startOCRAD( )
+{
+ ocradDialog *ocrDia = static_cast<ocradDialog*>(m_ocrProcessDia);
+
+ m_ocrResultImage = ocrDia->orfUrl();
+ const QString cmd = ocrDia->getOCRCmd();
+
+ // if( m_ocrResultImage.isEmpty() )
+ {
+ /* The url is empty. Start the program to fill up a temp file */
+ m_ocrResultImage = ImgSaver::tempSaveImage( m_img, "BMP", 8 ); // m_tmpFile->name();
+ kdDebug(28000) << "The new image name is <" << m_ocrResultImage << ">" << endl;
+ }
+
+ m_ocrImagePBM = ImgSaver::tempSaveImage( m_img, "PBM", 1 );
+
+ /* temporar file for orf result */
+ KTempFile *tmpOrf = new KTempFile( QString(), ".orf" );
+ tmpOrf->setAutoDelete( false );
+ tmpOrf->close();
+ m_tmpOrfName = QFile::encodeName(tmpOrf->name());
+
+
+ if( daemon )
+ {
+ delete( daemon );
+ daemon = 0;
+ }
+
+ daemon = new KProcess;
+ Q_CHECK_PTR(daemon);
+
+ *daemon << cmd;
+ *daemon << QString("-x");
+ *daemon << m_tmpOrfName; // the orf result file
+ *daemon << QFile::encodeName( m_ocrImagePBM ); // The name of the image
+ *daemon << QString("-l");
+ *daemon << QString::number( ocrDia->layoutDetectionMode());
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver( konf, CFG_GROUP_OCRAD );
+
+ QString format = konf->readEntry( CFG_OCRAD_FORMAT, "utf8");
+ *daemon << QString("-F");
+ *daemon << format;
+
+ QString charset = konf->readEntry( CFG_OCRAD_CHARSET, "iso-8859-15");
+ *daemon << QString("-c");
+ *daemon << charset;
+
+
+ QString addArgs = konf->readEntry( CFG_OCRAD_EXTRA_ARGUMENTS, QString() );
+
+ if( !addArgs.isEmpty() )
+ {
+ kdDebug(28000) << "Setting additional args from config for ocrad: " << addArgs << endl;
+ *daemon << addArgs;
+ }
+
+ m_ocrResultText = "";
+
+ connect(daemon, SIGNAL(processExited(KProcess *)),
+ this, SLOT( ocradExited(KProcess*)));
+ connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)),
+ this, SLOT( ocradStdIn(KProcess*, char*, int)));
+ connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)),
+ this, SLOT( ocradStdErr(KProcess*, char*, int)));
+
+ if (!daemon->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ kdDebug(28000) << "Error starting ocrad-daemon!" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "Start OK" << endl;
+
+ }
+ delete tmpOrf;
+}
+
+
+void KSANEOCR::ocradExited(KProcess* )
+{
+ kdDebug(28000) << "ocrad exit " << endl;
+ QString err;
+ bool parseRes = true;
+
+ if( ! readORF(m_tmpOrfName, err) )
+ {
+ KMessageBox::error( m_parent,
+ i18n("Parsing of the OCR Result File failed:") + err,
+ i18n("Parse Problem"));
+ parseRes = false;
+ }
+ finishedOCRVisible( parseRes );
+
+}
+
+void KSANEOCR::ocradStdErr(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "ocrad says on stderr: " << errorBuffer << endl;
+
+}
+
+void KSANEOCR::ocradStdIn(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "ocrad says on stdin: " << errorBuffer << endl;
+}
+
+
+
+
+/*
+ * This slot is fired if the user clicks on the 'Start' button of the GUI, no
+ * difference which engine is active.
+ */
+void KSANEOCR::startOCRProcess( void )
+{
+ if( ! m_ocrProcessDia ) return;
+
+ /* starting the animation, setting fields disabled */
+ m_ocrProcessDia->startOCR();
+
+ kapp->processEvents();
+ if( m_ocrEngine == OCRAD )
+ {
+ startOCRAD();
+ }
+
+ if( m_ocrEngine == GOCR )
+ {
+ /*
+ * Starting a gocr process
+ */
+
+ KGOCRDialog *gocrDia = static_cast<KGOCRDialog*>(m_ocrProcessDia);
+
+ const QString cmd = gocrDia->getOCRCmd();
+
+ /* Save the image to a temp file */
+
+ /**
+ * Save images formats:
+ * Black&White: PBM
+ * Gray: PGM
+ * Bunt: PPM
+ */
+ QString format;
+ if( m_img->depth() == 1 )
+ format = "PBM";
+ else if( m_img->isGrayscale() )
+ format = "PGM";
+ else
+ format = "PPM";
+
+ QString tmpFile = ImgSaver::tempSaveImage( m_img, format ); // m_tmpFile->name();
+
+ kdDebug(28000) << "Starting GOCR-Command: " << cmd << " on file " << tmpFile
+ << ", format " << format << endl;
+
+ if( daemon ) {
+ delete( daemon );
+ daemon = 0;
+ }
+
+ daemon = new KProcess;
+ Q_CHECK_PTR(daemon);
+ m_ocrResultText = "";
+
+ connect(daemon, SIGNAL(processExited(KProcess *)),
+ this, SLOT( gocrExited(KProcess*)));
+ connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)),
+ this, SLOT( gocrStdIn(KProcess*, char*, int)));
+ connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)),
+ this, SLOT( gocrStdErr(KProcess*, char*, int)));
+
+ QString opt;
+ *daemon << QFile::encodeName(cmd);
+ *daemon << "-x";
+ *daemon << "-";
+ if( !( m_img->numColors() > 0 && m_img->numColors() <3 )) /* not a bw-image */
+ {
+ *daemon << "-l";
+ opt.setNum(gocrDia->getGraylevel());
+ *daemon << opt;
+ }
+ *daemon << "-s";
+ opt.setNum(gocrDia->getSpaceWidth());
+ *daemon << opt;
+ *daemon << "-d";
+ opt.setNum(gocrDia->getDustsize());
+ *daemon << opt;
+
+ // Write an result image
+ *daemon << "-v";
+ *daemon << "32";
+
+ // Unfortunately this is fixed by gocr.
+ m_ocrResultImage = "out30.bmp";
+
+ *daemon << QFile::encodeName(tmpFile);
+
+ m_ocrCurrLine = 0; // Important in gocrStdIn to store the results
+
+ if (!daemon->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ kdDebug(28000) << "Error starting daemon!" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "Start OK" << endl;
+
+ }
+ }
+#ifdef HAVE_KADMOS
+ if( m_ocrEngine == KADMOS )
+ {
+ KadmosDialog *kadDia = static_cast<KadmosDialog*>(m_ocrProcessDia);
+
+ kdDebug(28000) << "Starting Kadmos OCR Engine" << endl;
+
+ QString clasPath; /* target where the clasPath is written in */
+ if( ! kadDia->getSelClassifier( clasPath ) )
+ {
+ KMessageBox::error( m_parent,
+ i18n("The classifier file necessary for OCR cannot be loaded: %1;\n"
+ "OCR with the KADMOS engine is not possible." ).
+ arg(clasPath), i18n("KADMOS Installation Problem"));
+ finishedOCRVisible(false);
+ return;
+ }
+ QCString c = clasPath.latin1();
+
+ kdDebug(28000) << "Using classifier " << c << endl;
+ m_rep.Init( c );
+ if( m_rep.kadmosError() ) /* check if kadmos initialised OK */
+ {
+ KMessageBox::error( m_parent,
+ i18n("The KADMOS OCR system could not be started:\n") +
+ m_rep.getErrorText()+
+ i18n("\nPlease check the configuration." ),
+ i18n("KADMOS Failure") );
+ }
+ else
+ {
+ /** Since initialising succeeded, we start the ocr here **/
+ m_rep.SetNoiseReduction( kadDia->getNoiseReduction() );
+ m_rep.SetScaling( kadDia->getAutoScale() );
+ kdDebug(28000) << "Image size " << m_img->width() << " x " << m_img->height() << endl;
+ kdDebug(28000) << "Image depth " << m_img->depth() << ", colors: " << m_img->numColors() << endl;
+#define USE_KADMOS_FILEOP /* use a save-file for OCR instead of filling the reImage struct manually */
+#ifdef USE_KADMOS_FILEOP
+ m_tmpFile = new KTempFile( QString(), QString("bmp"));
+ m_tmpFile->setAutoDelete( false );
+ m_tmpFile->close();
+ QString tmpFile = m_tmpFile->name();
+ kdDebug() << "Saving to file " << tmpFile << endl;
+ m_img->save( tmpFile, "BMP" );
+ m_rep.SetImage(tmpFile);
+#else
+ m_rep.SetImage(m_img);
+#endif
+ // rep.Recognize();
+ m_rep.run();
+
+ /* Dealing with threads or no threads (using QT_THREAD_SUPPORT to distinguish)
+ * If threads are here, the recognition task is started in its own thread. The gui thread
+ * needs to wait until the recognition thread is finished. Therefore, a timer is fired once
+ * that calls slotKadmosResult and checks if the recognition task is finished. If it is not,
+ * a new one-shot-timer is fired in slotKadmosResult. If it is, the OCR result can be
+ * processed.
+ * In case the system has no threads, the method start of the recognition engine does not
+ * return until it is ready, the user has to live with a non responsive gui while
+ * recognition is performed. The start()-method is implemented as a wrapper to the run()
+ * method of CRep, which does the recognition job. Instead of pulling up a timer, simply
+ * the result slot is called if start()=run() has finished. In the result slot, finished()
+ * is only a dummy always returning true to avoid more preprocessor tags here.
+ * Hope that works ...
+ * It does not :( That is why it is not used here. Maybe some day...
+ */
+ }
+#ifdef QT_THREAD_SUPPORT
+ /* start a timer and wait until it fires. */
+ QTimer::singleShot( 500, this, SLOT( slotKadmosResult() ));
+#else
+ slotKadmosResult();
+#endif
+
+ }
+#endif /* HAVE_KADMOS */
+}
+
+/*
+ * This method is called to check if the kadmos process was already finished, if
+ * thread support is enabled (check for preprocessor variable QT_THREAD_SUPPORT)
+ * The problem is that the kadmos library seems not to be thread stable so thread
+ * support should not be enabled by default. In case threads are enabled, this slot
+ * checks if the KADMOS engine is finished already and if not it fires a timer.
+ */
+
+void KSANEOCR::slotKadmosResult()
+{
+#ifdef HAVE_KADMOS
+ kdDebug(28000) << "check for Recognition finished" << endl;
+
+
+ if( m_rep.finished() )
+ {
+ /* The recognition thread is finished. */
+ kdDebug(28000) << "kadmos is finished." << endl;
+
+ m_ocrResultText = "";
+ if( ! m_rep.kadmosError() )
+ {
+ int lines = m_rep.GetMaxLine();
+ kdDebug(28000) << "Count lines: " << lines << endl;
+ m_ocrPage.clear();
+ m_ocrPage.resize( lines );
+
+ for( int line = 0; line < m_rep.GetMaxLine(); line++ )
+ {
+ // ocrWordList wordList = m_rep.getLineWords(line);
+ /* call an ocr engine independent method to use the spellbook */
+ ocrWordList words = m_rep.getLineWords(line);
+ kdDebug(28000) << "Have " << words.count() << " entries in list" << endl;
+ m_ocrPage[line]=words;
+ }
+
+ /* show results of ocr */
+ m_rep.End();
+ }
+ finishedOCRVisible( !m_rep.kadmosError() );
+
+ }
+ else
+ {
+ /* recognition thread is not yet finished. Wait another half a second. */
+ QTimer::singleShot( 500, this, SLOT( slotKadmosResult() ));
+ /* Never comes here if no threads exist on the system */
+ }
+#endif /* HAVE_KADMOS */
+}
+
+
+
+
+/*
+ *
+ */
+void KSANEOCR::gocrExited(KProcess* d)
+{
+ kdDebug(28000) << "daemonExited start !" << endl;
+
+ /* Now all the text of gocr is in the member m_ocrResultText. This one must
+ * be split up now to m_ocrPage. First break up the lines, resize m_ocrPage
+ * accordingly and than go through every line and create ocrwords for every
+ * word.
+ */
+ QStringList lines = QStringList::split( '\n', m_ocrResultText, true );
+
+ m_ocrPage.clear();
+ m_ocrPage.resize( lines.count() );
+
+ kdDebug(28000) << "RESULT " << m_ocrResultText << " was splitted to lines " << lines.count() << endl;
+
+ unsigned int lineCnt = 0;
+
+ for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
+ {
+ kdDebug(28000) << "Splitting up line " << *it << endl;
+ ocrWordList ocrLine;
+
+ QStringList words = QStringList::split( QRegExp( "\\s+" ), *it, false );
+ for ( QStringList::Iterator itWord = words.begin(); itWord != words.end(); ++itWord )
+ {
+ kdDebug(28000) << "Appending to results: " << *itWord << endl;
+ ocrLine.append( ocrWord( *itWord ));
+ }
+ m_ocrPage[lineCnt] = ocrLine;
+ lineCnt++;
+ }
+ kdDebug(28000) << "Finished to split!" << endl;
+ /* set the result pixmap to the result pix of gocr */
+ if( ! m_resPixmap.load( m_ocrResultImage ) )
+ {
+ kdDebug(28000) << "Can not load result image!" << endl;
+ }
+
+ /* load the gocr result image */
+ if( m_img ) delete m_img;
+ m_img = new KookaImage();
+ m_img->load( "out30.bmp" );
+
+ finishedOCRVisible( d->normalExit() );
+}
+
+/*
+ * A sample orf snippet:
+ *
+ * # Ocr Results File. Created by GNU ocrad version 0.3pre1
+ * total blocks 2
+ * block 1 0 0 560 344
+ * lines 5
+ * line 1 chars 10 height 26
+ * 71 109 17 26;2,'0'1,'o'0
+ * 93 109 15 26;2,'1'1,'l'0
+ * 110 109 18 26;1,'2'0
+ * 131 109 18 26;1,'3'0
+ * 151 109 19 26;1,'4'0
+ * 172 109 17 26;1,'5'0
+ * 193 109 17 26;1,'6'0
+ * 213 108 17 27;1,'7'0
+ * 232 109 18 26;1,'8'0
+ * 253 109 17 26;1,'9'0
+ * line 2 chars 14 height 27
+ *
+ */
+
+bool KSANEOCR::readORF( const QString& fileName, QString& errStr )
+{
+ QFile file( fileName );
+ QRegExp rx;
+ bool error = false;
+
+ /* use a global line number counter here, not the one from the orf. The orf one
+ * starts at 0 for every block, but we want line-no counting page global here.
+ */
+ unsigned int lineNo = 0;
+ int blockCnt = 0;
+ int currBlock = -1;
+
+
+ /* Fetch the numeric version of ocrad */
+ ocradDialog *ocrDia = static_cast<ocradDialog*>(m_ocrProcessDia);
+ int ocradVersion = 0;
+ if( ocrDia )
+ {
+ ocradVersion = ocrDia->getNumVersion();
+ }
+
+ /* clear the ocr result page */
+ m_ocrPage.clear();
+ kdDebug(28000) << "***** starting to analyse orf at " << fileName << " *****" << endl;
+
+ /* some checks on the orf */
+ QFileInfo fi( fileName );
+ if( ! fi.exists() ) {
+ error = true;
+ errStr = i18n("The orf %1 does not exist.").arg(fileName);
+ }
+ if( ! error && ! fi.isReadable() ) {
+ error = true;
+ errStr = i18n("Permission denied on file %1.").arg(fileName);
+ }
+
+
+ if ( !error && file.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &file );
+ QString line;
+ QString recLine; // recognised line
+
+ while ( !stream.atEnd() )
+ {
+ line = stream.readLine().stripWhiteSpace(); // line of text excluding '\n'
+ int len = line.length();
+
+ if( ! line.startsWith( "#" )) // Comments
+ {
+ kdDebug(28000) << "# Line check |" << line << "|" << endl;
+ if( line.startsWith( "total blocks " ) ) // total count fo blocks, must be first line
+ {
+ blockCnt = line.right( len - 13 /* QString("total blocks ").length() */ ).toInt();
+ kdDebug(28000) << "Amount of blocks: " << blockCnt << endl;
+ m_blocks.resize(blockCnt);
+ }
+ else if( line.startsWith( "total text blocks " ))
+ {
+ blockCnt = line.right( len - 18 /* QString("total text blocks ").length() */ ).toInt();
+ kdDebug(28000) << "Amount of blocks (V. 10): " << blockCnt << endl;
+ m_blocks.resize(blockCnt);
+ }
+ else if( line.startsWith( "block ") || line.startsWith( "text block ") )
+ {
+ rx.setPattern("^.*block\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
+ if( rx.search( line ) > -1)
+ {
+ currBlock = (rx.cap(1).toInt())-1;
+ kdDebug(28000) << "Setting current block " << currBlock << endl;
+ QRect r( rx.cap(2).toInt(), rx.cap(3).toInt(), rx.cap(4).toInt(), rx.cap(5).toInt());
+ m_blocks[currBlock] = r;
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Unknown block line: " << line << endl;
+ // Not a killing bug
+ }
+ }
+ else if( line.startsWith( "lines " ))
+ {
+ int lineCnt = line.right( len - 6 /* QString("lines ").length() */).toInt();
+ m_ocrPage.resize(m_ocrPage.size()+lineCnt);
+ kdDebug(28000) << "Resized ocrPage to linecount " << lineCnt << endl;
+ }
+ else if( line.startsWith( "line" ))
+ {
+ // line 5 chars 13 height 20
+ rx.setPattern("^line\\s+(\\d+)\\s+chars\\s+(\\d+)\\s+height\\s+\\d+" );
+ if( rx.search( line )>-1 )
+ {
+ kdDebug(28000) << "RegExp-Result: " << rx.cap(1) << " : " << rx.cap(2) << endl;
+ int charCount = rx.cap(2).toInt();
+ ocrWord word;
+ QRect brect;
+ ocrWordList ocrLine;
+ ocrLine.setBlock(currBlock);
+ /* Loop over all characters in the line. Every char has it's own line
+ * defined in the orf file */
+ kdDebug(28000) << "Found " << charCount << " chars for line " << lineNo << endl;
+
+ for( int c=0; c < charCount && !stream.atEnd(); c++ )
+ {
+ /* Read one line per character */
+ QString charLine = stream.readLine();
+ int semiPos = charLine.find(';');
+ if( semiPos == -1 )
+ {
+ kdDebug(28000) << "invalid line: " << charLine << endl;
+ }
+ else
+ {
+ QString rectStr = charLine.left( semiPos );
+ QString results = charLine.remove(0, semiPos+1 );
+ bool lineErr = false;
+
+ // rectStr contains the rectangle info of for the character
+ // results contains the real result caracter
+
+ // find the amount of alternatives.
+ int altCount = 0;
+ int h = results.find(','); // search the first comma
+ if( h > -1 ) {
+ // kdDebug(28000) << "Results of count search: " << results.left(h) << endl;
+ altCount = results.left(h).toInt();
+ results = results.remove( 0, h+1 ).stripWhiteSpace();
+ } else {
+ lineErr = true;
+ }
+ // kdDebug(28000) << "Results-line after cutting the alter: " << results << endl;
+ QChar detectedChar = UndetectedChar;
+ if( !lineErr )
+ {
+ /* take the first alternative only FIXME */
+ if( altCount > 0 )
+ detectedChar = results[1];
+ // kdDebug(28000) << "Found " << altCount << " alternatives for "
+ // << QString(detectedChar) << endl;
+ }
+
+ /* Analyse the rectangle */
+ if( ! lineErr && detectedChar != ' ' )
+ {
+ // kdDebug(28000) << "STRING: " << rectStr << "<" << endl;
+ rx.setPattern( "(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
+ if( rx.search( rectStr ) != -1 )
+ {
+ /* unite the rectangles */
+ QRect privRect( rx.cap(1).toInt(), rx.cap(2).toInt(),
+ rx.cap(3).toInt(), rx.cap(4).toInt() );
+ word.setRect( word.rect() | privRect );
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Unable to read rect info for char!" << endl;
+ lineErr = true;
+ }
+ }
+
+ if( ! lineErr )
+ {
+ /* store word if finished by a space */
+ if( detectedChar == ' ' )
+ {
+ /* add the block offset to the rect of the word */
+ QRect r = word.rect();
+ if( ocradVersion < 10 )
+ {
+ QRect blockRect = m_blocks[currBlock];
+ r.moveBy( blockRect.x(), blockRect.y());
+ }
+
+ word.setRect( r );
+ ocrLine.append( word );
+ word = ocrWord();
+ }
+ else
+ {
+ word.append( detectedChar );
+ }
+ }
+ }
+ }
+ if( !word.isEmpty() )
+ {
+ /* add the block offset to the rect of the word */
+ QRect r = word.rect();
+ if( ocradVersion < 10 )
+ {
+ QRect blockRect = m_blocks[currBlock];
+ r.moveBy( blockRect.x(), blockRect.y());
+ }
+ word.setRect( r );
+
+ ocrLine.append( word );
+ }
+ if( lineNo < m_ocrPage.size() )
+ {
+ kdDebug(29000) << "Store result line no " << lineNo << "=\"" <<
+ ocrLine.first() << "..." << endl;
+ m_ocrPage[lineNo] = ocrLine;
+ lineNo++;
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: line index overflow: " << lineNo << endl;
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Unknown line found: " << line << endl;
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "Unknown line: " << line << endl;
+ }
+ } /* is a comment? */
+
+ }
+ file.close();
+ }
+ return !error;
+}
+
+
+void KSANEOCR::cleanUpFiles( void )
+{
+ if( m_tmpFile )
+ {
+ delete m_tmpFile;
+ m_tmpFile = 0L;
+ }
+
+ if( ! m_ocrResultImage.isEmpty())
+ {
+ kdDebug(28000) << "Unlinking OCR Result image file!" << endl;
+ unlink(QFile::encodeName(m_ocrResultImage));
+ m_ocrResultImage = QString();
+ }
+
+ if( ! m_ocrImagePBM.isEmpty())
+ {
+ kdDebug(28000) << "Unlinking OCR PBM file!" << endl;
+ unlink( QFile::encodeName(m_ocrImagePBM));
+ m_ocrImagePBM = QString();
+ }
+
+ if( ! m_tmpOrfName.isEmpty() )
+ {
+ if( m_unlinkORF )
+ {
+ unlink(QFile::encodeName(m_tmpOrfName));
+ m_tmpOrfName = QString();
+ }
+ else
+ {
+ kdDebug(28000) << "Do NOT unlink temp orf file " << m_tmpOrfName << endl;
+ }
+ }
+
+ /* Delete the debug images of gocr ;) */
+ unlink( "out20.bmp" );
+}
+
+
+void KSANEOCR::gocrStdErr(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "gocr says: " << errorBuffer << endl;
+
+}
+
+
+void KSANEOCR::gocrStdIn(KProcess*, char* buffer, int buflen)
+{
+ QString aux = QString::fromLocal8Bit(buffer, buflen);
+
+ QRegExp rx( "^\\s*\\d+\\s+\\d+");
+ if( rx.search( aux ) > -1 )
+ {
+ /* calculate ocr progress for gocr */
+ int progress = rx.capturedTexts()[0].toInt();
+ int subProgress = rx.capturedTexts()[1].toInt();
+ // kdDebug(28000) << "Emitting progress: " << progress << endl;
+ emit ocrProgress( progress, subProgress );
+ }
+ else
+ {
+ m_ocrResultText += aux;
+ }
+
+ // kdDebug(28000) << aux << endl;
+
+}
+
+/*
+ * Assemble the result text
+ */
+QString KSANEOCR::ocrResultText()
+{
+ QString res;
+ const QString space(" ");
+
+ /* start from the back and search the original word to replace it */
+ QValueVector<ocrWordList>::iterator pageIt;
+
+ for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt )
+ {
+ /* thats goes over all lines */
+ QValueList<ocrWord>::iterator lineIt;
+ for( lineIt = (*pageIt).begin(); lineIt != (*pageIt).end(); ++lineIt )
+ {
+ res += space + *lineIt;
+ }
+ res += "\n";
+ }
+ kdDebug(28000) << "Returning result String " << res << endl;
+ return res;
+}
+
+
+/* --------------------------------------------------------------------------------
+ * event filter to filter the mouse events to the image viewer
+ */
+
+void KSANEOCR::setImageCanvas( ImageCanvas *canvas )
+{
+ m_imgCanvas = canvas;
+
+ m_imgCanvas->installEventFilter( this );
+}
+
+
+bool KSANEOCR::eventFilter( QObject *object, QEvent *event )
+{
+ QWidget *w = (QWidget*) object;
+
+ if( m_applyFilter && m_imgCanvas && w == m_imgCanvas )
+ {
+ if( event->type() == QEvent::MouseButtonDblClick )
+ {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(event);
+
+ int x = mev->x();
+ int y = mev->y();
+ int scale = m_imgCanvas->getScaleFactor();
+
+ m_imgCanvas->viewportToContents( mev->x(), mev->y(),
+ x, y );
+
+ kdDebug(28000) << "Clicked to " << x << "/" << y << ", scale " << scale << endl;
+ if( scale != 100 )
+ {
+ // Scale is e.g. 50 that means tha the image is only half of size.
+ // thus the clicked coords must be multiplied with 2
+ y = int(double(y)*100/scale);
+ x = int(double(x)*100/scale);
+ }
+ /* now search the word that was clicked on */
+ QValueVector<ocrWordList>::iterator pageIt;
+
+ int line = 0;
+ bool valid = false;
+ ocrWord wordToFind;
+
+ for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt )
+ {
+ QRect r = (*pageIt).wordListRect();
+
+ if( y > r.top() && y < r.bottom() )
+ {
+ kdDebug(28000)<< "It is in between " << r.top() << "/" << r.bottom()
+ << ", line " << line << endl;
+ valid = true;
+ break;
+ }
+ line++;
+ }
+
+ /*
+ * If valid, we have the line into which the user clicked. Now we
+ * have to find out the actual word
+ */
+ if( valid )
+ {
+ valid = false;
+ /* find the word in the line and mark it */
+ ocrWordList words = *pageIt;
+ ocrWordList::iterator wordIt;
+
+ for( wordIt = words.begin(); wordIt != words.end() && !valid; ++wordIt )
+ {
+ QRect r = (*wordIt).rect();
+ if( x > r.left() && x < r.right() )
+ {
+ wordToFind = *wordIt;
+ valid = true;
+ }
+ }
+
+ }
+
+ /*
+ * if valid, the wordToFind contains the correct word now.
+ */
+ if( valid )
+ {
+ kdDebug(28000) << "Found the clicked word " << wordToFind << endl;
+ emit selectWord( line, wordToFind );
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+/* --------------------------------------------------------------------------------
+ * Spellbook support
+ */
+
+
+/*
+ * This slot is hit when the checkWord method of KSpell thinks a word is wrong.
+ * KSpell detects the correction by itself and delivers it in newword here.
+ * To see all alternatives KSpell proposes, slMissspelling must be used.
+ */
+void KSANEOCR::slSpellCorrected( const QString& originalword,
+ const QString& newword,
+ unsigned int pos )
+{
+ kdDebug(28000) << "Corrected: Original Word " << originalword << " was corrected to "
+ << newword << ", pos ist " << pos << endl;
+
+ kdDebug(28000) << "Dialog state is " << m_spell->dlgResult() << endl;
+
+ if( slUpdateWord( m_ocrCurrLine, pos, originalword, newword ) )
+ {
+ if( m_imgCanvas && m_currHighlight > -1 )
+ {
+ if( m_applyFilter )
+ m_imgCanvas->removeHighlight( m_currHighlight );
+ }
+ else
+ {
+ kdDebug(28000) << "No highlighting to remove!" << endl;
+ }
+ }
+
+}
+
+
+void KSANEOCR::slSpellIgnoreWord( const QString& word )
+{
+ ocrWord ignoreOCRWord;
+
+ ignoreOCRWord = ocrWordFromKSpellWord( m_ocrCurrLine, word );
+ if( ! ignoreOCRWord.isEmpty() )
+ {
+ emit ignoreWord( m_ocrCurrLine, ignoreOCRWord );
+
+ if( m_imgCanvas && m_currHighlight > -1 )
+ {
+ m_imgCanvas->removeHighlight( m_currHighlight );
+
+ /* create a new highlight. That will never be removed */
+ QBrush brush;
+ QPen pen( gray, 1 );
+ QRect r = ignoreOCRWord.rect();
+ r.moveBy(0,2); // a bit offset to the top
+
+ if( m_applyFilter )
+ m_imgCanvas->highlight( r, pen, brush );
+ }
+ }
+}
+
+ocrWord KSANEOCR::ocrWordFromKSpellWord( int line, const QString& word )
+{
+ ocrWord resWord;
+ if( lineValid(line) )
+ {
+ ocrWordList words = m_ocrPage[line];
+
+ words.findFuzzyIndex( word, resWord );
+ }
+
+ return resWord;
+}
+
+
+bool KSANEOCR::lineValid( int line )
+{
+ bool ret = false;
+
+ if( line >= 0 && (uint)line < m_ocrPage.count() )
+ ret = true;
+
+ return ret;
+}
+
+void KSANEOCR::slMisspelling( const QString& originalword, const QStringList& suggestions,
+ unsigned int pos )
+{
+ /* for the first try, use the first suggestion */
+ ocrWord s( suggestions.first());
+ kdDebug(28000) << "Misspelled: " << originalword << " at position " << pos << endl;
+
+ int line = m_ocrCurrLine;
+ m_currHighlight = -1;
+
+ // ocrWord resWord = ocrWordFromKSpellWord( line, originalword );
+ ocrWordList words = m_ocrPage[line];
+ ocrWord resWord;
+ kdDebug(28000) << "Size of wordlist (line " << line << "): " << words.count() << endl;
+
+ if( pos < words.count() )
+ {
+ resWord = words[pos];
+ }
+
+ if( ! resWord.isEmpty() )
+ {
+ QBrush brush;
+ brush.setColor( QColor(red)); // , "Dense4Pattern" );
+ brush.setStyle( Qt::Dense4Pattern );
+ QPen pen( red, 2 );
+ QRect r = resWord.rect();
+
+ r.moveBy(0,2); // a bit offset to the top
+
+ if( m_applyFilter )
+ m_currHighlight = m_imgCanvas->highlight( r, pen, brush, true );
+
+ kdDebug(28000) << "Position ist " << r.x() << ", " << r.y() << ", width: "
+ << r.width() << ", height: " << r.height() << endl;
+
+ /* draw a line under the word to check */
+
+ /* copy the source */
+ emit repaintOCRResImage();
+ }
+ else
+ {
+ kdDebug(28000) << "Could not find the ocrword for " << originalword << endl;
+ }
+
+ emit markWordWrong( line, resWord );
+}
+
+/*
+ * This is the global starting point for spell checking of the ocr result.
+ * After the KSpell object was created in method finishedOCRVisible, this
+ * slot is called if the KSpell-object feels itself ready for operation.
+ * Coming into this slot, the spelling starts in a line by line manner
+ */
+void KSANEOCR::slSpellReady( KSpell *spell )
+{
+ m_spell = spell;
+ connect ( m_spell, SIGNAL( misspelling( const QString&, const QStringList&,
+ unsigned int )),
+ this, SLOT( slMisspelling(const QString& ,
+ const QStringList& ,
+ unsigned int )));
+ connect( m_spell, SIGNAL( corrected ( const QString&, const QString&, unsigned int )),
+ this, SLOT( slSpellCorrected( const QString&, const QString&, unsigned int )));
+
+ connect( m_spell, SIGNAL( ignoreword( const QString& )),
+ this, SLOT( slSpellIgnoreWord( const QString& )));
+
+ connect( m_spell, SIGNAL( done(bool)), this, SLOT(slCheckListDone(bool)));
+
+ kdDebug(28000) << "Spellcheck available" << endl;
+
+ if( m_ocrProcessDia && m_hideDiaWhileSpellcheck )
+ m_ocrProcessDia->hide();
+ emit readOnlyEditor( true );
+ startLineSpellCheck();
+}
+
+/**
+ * slot called after either the spellcheck finished or the KSpell object found
+ * out that it does not want to run because of whatever problems came up.
+ * If it is an KSpell-init problem, the m_spell variable is still zero and
+ * Kooka pops up a warning.
+ */
+void KSANEOCR::slSpellDead()
+{
+ if( ! m_spell )
+ {
+ kdDebug(28000) << "Spellcheck NOT available" << endl;
+ /* Spellchecking has not yet been existing, thus there is a base problem with
+ * spellcheck on this system.
+ */
+ KMessageBox::error( m_parent,
+ i18n("Spell-checking cannot be started on this system.\n"
+ "Please check the configuration" ),
+ i18n("Spell-Check") );
+
+ }
+ else
+ {
+ if( m_spell->status() == KSpell::Cleaning )
+ {
+ kdDebug(28000) << "KSpell cleans up" << endl;
+ }
+ else if( m_spell->status() == KSpell::Finished )
+ {
+ kdDebug(28000) << "KSpell finished" << endl;
+ }
+ else if( m_spell->status() == KSpell::Error )
+ {
+ kdDebug(28000) << "KSpell finished with Errors" << endl;
+ }
+ else if( m_spell->status() == KSpell::Crashed )
+ {
+ kdDebug(28000) << "KSpell Chrashed" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "KSpell finished with unknown state!" << endl;
+ }
+
+ /* save the current config */
+ delete m_spell;
+ m_spell = 0L;
+
+ /* reset values */
+ m_checkStrings.clear();
+ m_ocrCurrLine = 0;
+ if( m_imgCanvas && m_currHighlight > -1 )
+ m_imgCanvas->removeHighlight( m_currHighlight );
+
+ }
+ if( m_ocrProcessDia )
+ m_ocrProcessDia->show();
+ emit readOnlyEditor( false );
+}
+
+
+/**
+ * This slot reads the current line from the member m_ocrCurrLine and
+ * writes the corrected wordlist to the member page word lists
+ */
+void KSANEOCR::slCheckListDone(bool)
+{
+
+ /*
+ * nothing needs to be updated here in the texts, because it is already done
+ * in the slSpellCorrected slot
+ */
+
+ /* Check the dialog state here */
+ if( m_spell->dlgResult() == KS_CANCEL ||
+ m_spell->dlgResult() == KS_STOP )
+ {
+ /* stop processing */
+ m_spell->cleanUp();
+ }
+ else
+ {
+ m_ocrCurrLine++;
+ kdDebug(28000) << "Starting spellcheck from CheckListDone" << endl;
+ startLineSpellCheck();
+ }
+}
+
+/**
+ * updates the word at position spellWordIndx in line line to the new word newWord.
+ * The original word was origWord. This slot is called from slSpellCorrected
+ *
+ */
+bool KSANEOCR::slUpdateWord( int line, int spellWordIndx, const QString& origWord,
+ const QString& newWord )
+{
+ bool result = false;
+
+ if( lineValid( line ))
+ {
+ ocrWordList words = m_ocrPage[line];
+ kdDebug(28000) << "Updating word " << origWord << " to " << newWord << endl;
+
+ if( words.updateOCRWord( words[spellWordIndx] /* origWord */, newWord ) ) // searches for the word and updates
+ {
+ result = true;
+ emit updateWord( line, origWord, newWord );
+ }
+ else
+ kdDebug(28000) << "WRN: Update from " << origWord << " to " << newWord << " failed" << endl;
+
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Line " << line << " no not valid!" << endl;
+ }
+ return result;
+}
+
+
+char KSANEOCR::UndetectedChar = '_';
+
+/* -- */
+#include "ksaneocr.moc"
diff --git a/kooka/ksaneocr.h b/kooka/ksaneocr.h
new file mode 100644
index 00000000..425718dc
--- /dev/null
+++ b/kooka/ksaneocr.h
@@ -0,0 +1,285 @@
+/***************************************************************************
+ ksaneocr.h - ocr-engine class
+ -------------------
+ begin : Fri Jun 30 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSANEOCR_H
+#define KSANEOCR_H
+#include <qwidget.h>
+#include <qobject.h>
+
+#include "ocrword.h"
+
+#define CFG_OCR_ENGINE "ocrEngine"
+#define CFG_OCR_CLEANUP "unlinkORF" /* delete orf file? */
+
+#define CFG_OCR_KSPELL "ocrSpellSettings"
+#define CFG_WANT_KSPELL "ocrKSpellEnabled"
+#define CFG_KS_NOROOTAFFIX "KSpell_NoRootAffix"
+#define CFG_KS_RUNTOGETHER "KSpell_RunTogether"
+#define CFG_KS_DICTIONARY "KSpell_Dictionary"
+#define CFG_KS_DICTFROMLIST "KSpell_DictFromList"
+#define CFG_KS_ENCODING "KSpell_Encoding"
+#define CFG_KS_CLIENT "KSpell_Client"
+
+
+#define HIDE_BASE_DIALOG "hideOCRDialogWhileSpellCheck"
+/**
+ *@author Klaas Freitag
+ */
+
+class KOCRBase;
+class KookaImage;
+class KTempFile;
+class KProcess;
+class QRect;
+class QPixmap;
+class QStringList;
+class KSpell;
+class KSpellConfig;
+class ImageCanvas;
+class KConfig;
+// class ocrWord;
+// class ocrPage;
+
+#ifdef HAVE_KADMOS
+#include "kadmosocr.h"
+#endif
+
+/*
+ * Error Classifier the report errors on bad engine setup
+ */
+typedef enum{ ENG_ERROR, ENG_OK, ENG_DATA_MISSING, ENG_BAD_SETUP } EngineError;
+
+class KSANEOCR : public QObject
+{
+ Q_OBJECT
+public:
+ enum OCREngines{ GOCR, OCRAD, KADMOS };
+
+ KSANEOCR( QWidget*, KConfig *);
+ ~KSANEOCR();
+
+ bool startOCRVisible( QWidget* parent=0);
+
+ void finishedOCRVisible( bool );
+
+ /**
+ * checks after a ocr run if the line number exists in the result
+ */
+ bool lineValid( int line );
+
+#ifdef HAVE_KADMOS
+ bool startKadmosOCR();
+#endif
+
+ /**
+ * return the final ocr result
+ */
+
+ QString ocrResultText();
+
+ /**
+ * @return the current spell config.
+ */
+ KSpellConfig* ocrSpellConfig() const
+ { return m_spellInitialConfig; }
+
+
+ /**
+ * Sets an image Canvas that displays the result image of ocr. If this
+ * is set to zero (or never set) no result image is displayed.
+ * The ocr fabric passes a new image to the canvas which is a copy of
+ * the image to ocr.
+ */
+ void setImageCanvas( ImageCanvas* canvas );
+
+signals:
+ void newOCRResultText( const QString& );
+ void clearOCRResultText();
+ void newOCRResultPixmap( const QPixmap& );
+
+ /**
+ * progress of the ocr process. The first integer is the main progress,
+ * the second the sub progress. If there is only on progress, it is the
+ * first parameter, the second is always -1 than.
+ * Both have a range from 0..100.
+ * Note that this signal may not be emitted if the engine does not support
+ * progress.
+ */
+ void ocrProgress(int, int);
+
+ /**
+ * select a word in the editor in line line.
+ */
+ void selectWord( int line, const ocrWord& word );
+
+ /**
+ * signal to indicate that a ocr text must be updated due to better results
+ * retrieved from spell check. The internal ocr data structure is already
+ * updated when this signal is fired.
+ *
+ * @param line the line in which the word must be changed (start at 0)
+ * @param wordFrom the original word
+ * @param wordTo the new word(s).
+ */
+ void updateWord( int line, const QString& wordFrom, const QString& wordTo );
+
+ /**
+ * signal to indicate that word word was ignored by the user. This should result
+ * in a special coloring in the editor.
+ */
+ void ignoreWord( int, const ocrWord& );
+
+ /**
+ * signal that comes if a word is considered to be wrong in the editor.
+ * The word should be marked in any way, e.g. with a signal color.
+ **/
+ void markWordWrong( int, const ocrWord& );
+
+ /**
+ * signal the tells that the result image was modified.
+ */
+ void repaintOCRResImage( );
+
+ /**
+ * indicates that the text editor holding the text that came through
+ * newOCRResultText should be set to readonly or not. Can be connected
+ * to QTextEdit::setReadOnly directly.
+ */
+ void readOnlyEditor( bool );
+
+public slots:
+ void slSetImage( KookaImage* );
+
+ void slLineBox( const QRect& );
+
+protected:
+ /**
+ * Start spell checking on a specific line that is stored in m_ocrCurrLine.
+ * This method starts the spell checking.
+ **/
+ void startLineSpellCheck();
+ ocrWord ocrWordFromKSpellWord( int line, const QString& word );
+
+ /**
+ * Eventhandler to handle the mouse events to the image viewer showing the
+ * ocr result image
+ */
+ bool eventFilter( QObject *object, QEvent *event );
+
+ void startOCRAD();
+protected slots:
+ void slotClose ();
+ void slotStopOCR();
+
+ void slSpellReady( KSpell* );
+ void slSpellDead( );
+ /**
+ * a new list of ocr results of the current ocr process arrived and is available
+ * in the member m_ocrPage[line]
+ */
+ // void gotOCRLine( int line );
+
+ void slMisspelling( const QString& originalword,
+ const QStringList& suggestions,
+ unsigned int pos );
+ void slSpellCorrected( const QString& originalword,
+ const QString& newword,
+ unsigned int pos );
+
+ void slSpellIgnoreWord( const QString& word );
+
+ void slCheckListDone( bool );
+
+ bool slUpdateWord( int line, int spellWordIndx,
+ const QString& origWord,
+ const QString& newWord );
+
+private slots:
+
+ void slotKadmosResult();
+ void startOCRProcess( void );
+ void gocrStdIn(KProcess*, char* buffer, int buflen);
+ void gocrStdErr(KProcess*, char* buffer, int buflen);
+ void gocrExited(KProcess*);
+
+ void ocradStdIn(KProcess*, char* buffer, int buflen);
+ void ocradStdErr(KProcess*, char* buffer, int buflen);
+ void ocradExited(KProcess*);
+
+ /*
+ * reads orf files from a file and fills the result structures
+ * accordingly.
+ */
+ bool readORF( const QString&, QString& );
+
+private:
+ void cleanUpFiles( void );
+
+
+ KOCRBase *m_ocrProcessDia;
+ KProcess *daemon;
+ bool visibleOCRRunning;
+ KTempFile *m_tmpFile;
+
+ KookaImage *m_img;
+ QString m_ocrResultText;
+ QString m_ocrResultImage;
+ QString m_ocrImagePBM;
+ QString m_tmpOrfName;
+ QImage *m_resultImage;
+
+ OCREngines m_ocrEngine;
+ QPixmap m_resPixmap;
+ QPixmap m_storePixmap;
+
+ ImageCanvas *m_imgCanvas;
+
+ KSpell *m_spell;
+ bool m_wantKSpell;
+ bool m_kspellVisible;
+ bool m_hideDiaWhileSpellcheck;
+ KSpellConfig *m_spellInitialConfig;
+
+ /* ValueVector of wordLists for every line of ocr results */
+ ocrBlock m_ocrPage; /* one block contains all lines of the page */
+ QWidget *m_parent;
+ /* current processed line to speed kspell correction */
+ unsigned m_ocrCurrLine;
+ QStringList m_checkStrings;
+
+ int m_currHighlight;
+ bool m_applyFilter;
+
+ bool m_unlinkORF;
+ rectList m_blocks; // dimensions of blocks
+
+ static char UndetectedChar;
+#ifdef HAVE_KADMOS
+ Kadmos::CRep m_rep;
+#endif
+};
+
+#endif
diff --git a/kooka/main.cpp b/kooka/main.cpp
new file mode 100644
index 00000000..086d3ddf
--- /dev/null
+++ b/kooka/main.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Thu Dec 9 20:16:54 MET 1999
+
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qdict.h>
+#include <qpixmap.h>
+
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kimageio.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+#include "kooka.h"
+#include "version.h"
+
+static const char description[] =
+ "Kooka is a KDE application which provides access to scanner hardware\n"
+ "using the SANE library.\n"
+ "Kooka helps you scan, save your image in the correct image format\n"
+ "and perform Optical Character Recognition on it, using gocr, Joerg\n"
+ "Schulenburg's and friends' Open Source ocr program.";
+
+static const char license[] =
+"This program is distributed under the terms of the GPL v2 as publishec by\n"
+"the Free Software Foundation\n\n"
+"As a special exception, permission is given to link this program\n"
+"with any version of the KADMOS ocr/icr engine of reRecognition GmbH,\n"
+"Kreuzlingen and distribute the resulting executable without\n"
+"including the source code for KADMOS in the source distribution.\n\n"
+"As a special exception, permission is given to link this program\n"
+"with any edition of Qt, and distribute the resulting executable,\n"
+"without including the source code for Qt in the source distribution.\n";
+
+
+static KCmdLineOptions options[] =
+{
+ { "d ", I18N_NOOP("The SANE compatible device specification (e.g. umax:/dev/sg0)"), "" },
+ { "g", I18N_NOOP("Gallery mode - do not connect to scanner"), "" },
+ KCmdLineLastOption
+};
+
+
+
+int main( int argc, char *argv[] )
+{
+ KAboutData about("kooka", I18N_NOOP("Kooka"), KOOKA_VERSION, I18N_NOOP(description),
+ KAboutData::License_GPL_V2, "(C) 2000 Klaas Freitag", 0,
+ I18N_NOOP("http://kooka.kde.org"));
+
+ about.addAuthor( "Klaas Freitag", I18N_NOOP("developer"), "freitag@suse.de" );
+ about.addAuthor( "Mat Colton", I18N_NOOP("graphics, web"), "mat@colton.de" );
+ about.setLicenseText( license );
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options ); // Add my own options.
+
+ KApplication app;
+ KGlobal::locale()->insertCatalogue("libkscan");
+ KImageIO::registerFormats();
+ KIconLoader *loader = KGlobal::iconLoader();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ QCString devToUse = args->getOption( "d" );
+ if( args->isSet("g") )
+ {
+ devToUse = "gallery";
+ }
+ kdDebug( 29000) << "DevToUse is " << devToUse << endl;
+
+ if (args->count() == 1)
+ {
+ args->usage();
+ // exit(-1);
+ }
+
+
+ Kooka *kooka = new Kooka(devToUse);
+ app.setMainWidget( kooka );
+
+ KWin::setIcons(kooka->winId(), loader->loadIcon( "scanner", KIcon::Desktop ),
+ loader->loadIcon("scanner", KIcon::Small) );
+
+ kooka->show();
+ app.processEvents();
+ kooka->startup();
+ args->clear();
+ int ret = app.exec();
+
+ return ret;
+
+}
diff --git a/kooka/ocrresedit.cpp b/kooka/ocrresedit.cpp
new file mode 100644
index 00000000..a289a079
--- /dev/null
+++ b/kooka/ocrresedit.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ ocrresedit.cpp - ocr result editor widget
+ -------------------
+ begin : Tue 12 Feb 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include <qcolor.h>
+
+#include "ocrresedit.h"
+#include "ocrword.h"
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+/* -------------------- ocrResEdit -------------------- */
+
+ocrResEdit::ocrResEdit( QWidget *parent )
+ : QTextEdit(parent)
+{
+ m_updateColor.setNamedColor( "SeaGreen");
+ m_ignoreColor.setNamedColor( "CadetBlue4" );
+ m_wrnColor.setNamedColor( "firebrick2" );
+}
+
+
+void ocrResEdit::slMarkWordWrong( int line, const ocrWord& word )
+{
+ // m_textEdit->setSelection( line,
+ slReplaceWord( line, word, word, m_wrnColor );
+}
+
+
+void ocrResEdit::slUpdateOCRResult( int line, const QString& wordFrom,
+ const QString& wordTo )
+{
+ /* the index is quite useless here, since the text could have had been
+ * changed by corrections before. Thus better search the word and update
+ * it.
+ */
+ slReplaceWord( line, wordFrom, wordTo, m_updateColor );
+
+}
+
+
+void ocrResEdit::slIgnoreWrongWord( int line, const ocrWord& word )
+{
+ slReplaceWord( line, word, word, m_ignoreColor );
+}
+
+
+void ocrResEdit::slSelectWord( int line, const ocrWord& word )
+{
+ if( line < paragraphs() )
+ {
+ QString editLine = text(line);
+ int cnt = editLine.contains( word);
+
+ if( cnt > 0 )
+ {
+ int pos = editLine.find(word);
+ setCursorPosition( line, pos );
+ setSelection( line, pos, line, pos + word.length());
+ }
+ }
+}
+
+void ocrResEdit::slReplaceWord( int line, const QString& wordFrom,
+ const QString& wordTo, const QColor& color )
+{
+ kdDebug(28000) << "Updating word " << wordFrom << " in line " << line << endl;
+
+ bool isRO = isReadOnly();
+
+ if( line < paragraphs() )
+ {
+ QString editLine = text(line);
+ int cnt = editLine.contains( wordFrom );
+
+ if( cnt > 0 )
+ {
+ int pos = editLine.find(wordFrom);
+ setSelection( line, pos, line, pos+wordFrom.length());
+
+ QColor saveCol = this->color();
+ setColor( color );
+ if( isRO ) {
+ setReadOnly(false);
+ }
+ insert( wordTo, unsigned (4) );
+ if( isRO ) {
+ setReadOnly( true );
+ }
+ setColor(saveCol);
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Paragraph does not contain word " << wordFrom << endl;
+ }
+
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: editor does not have line " << line << endl;
+ }
+}
+
+
+void ocrResEdit::slSaveText()
+{
+ QString fileName = KFileDialog::getSaveFileName( (QDir::home()).path(),
+ "*.txt",
+ this,
+ i18n("Save OCR Result Text") );
+ if( fileName.isEmpty() )
+ return;
+ QFile file( fileName );
+ if ( file.open( IO_WriteOnly ) )
+ {
+ QTextStream stream( &file );
+ stream << text();
+ file.close();
+ }
+}
+
+#include "ocrresedit.moc"
+/* */
diff --git a/kooka/ocrresedit.h b/kooka/ocrresedit.h
new file mode 100644
index 00000000..6c483db4
--- /dev/null
+++ b/kooka/ocrresedit.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ ocrresedit.h - ocr-result edit widget
+ -------------------
+ begin : Fri 12 Feb 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef _OCR_RESEDIT_
+#define _OCR_RESEDIT_
+
+#include <qtextedit.h>
+
+class QString;
+class QColor;
+class ocrWord;
+
+class ocrResEdit : public QTextEdit
+{
+ Q_OBJECT
+public:
+ ocrResEdit( QWidget *parent );
+
+public slots:
+ void slUpdateOCRResult( int line, const QString& wordFrom,
+ const QString& wordTo );
+
+ void slMarkWordWrong( int line, const ocrWord& word );
+
+ void slIgnoreWrongWord( int line, const ocrWord& word );
+
+ void slSelectWord( int line, const ocrWord& word );
+
+ void slSaveText();
+
+protected slots:
+ void slReplaceWord( int line, const QString& wordFrom,
+ const QString& wordTo, const QColor& color );
+
+private:
+ QColor m_updateColor;
+ QColor m_ignoreColor;
+ QColor m_wrnColor;
+
+};
+
+#endif
diff --git a/kooka/ocrword.cpp b/kooka/ocrword.cpp
new file mode 100644
index 00000000..1bd29f3e
--- /dev/null
+++ b/kooka/ocrword.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+ ocrword.cpp - ocr-result word and wordlist
+ -------------------
+ begin : Fri Jan 10 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include "ocrword.h"
+#include <qrect.h>
+#include <qptrlist.h>
+#include <kdebug.h>
+#include <qregexp.h>
+
+/* -------------------- ocrWord -------------------- */
+ocrWord::ocrWord( const QString& s )
+ : QString(s)
+{
+
+}
+
+ocrWord::ocrWord() : QString()
+{
+
+}
+
+#if 0
+QRect ocrWord::boundingRect()
+{
+ QRect r;
+
+ return r;
+}
+#endif
+
+/* -------------------- CocrWordList ------------------ */
+ocrWordList::ocrWordList()
+ :QValueList<ocrWord>(),
+ m_block(0)
+{
+ // setAutoDelete( true );
+}
+
+QStringList ocrWordList::stringList()
+{
+ QStringList res;
+ QRegExp rx("[,\\.-]");
+ ocrWordList::iterator it;
+
+ for ( it = begin(); it != end(); ++it )
+ {
+#if 0
+ /* Uncommented this to prevent an error that occurs if the lenght of the
+ * spellchecked stringlist and the ocr_page wordlist are not the same length.
+ * For the ocrpage words connected with a dash are one word while the code
+ * below parts them into two. That confuses the replacement code if the user
+ * decided. Solution: KSpell should treat dash-linked words correctly.
+ * We live with the problem here that dashes bring confusion ;-)
+ */
+ if( (*it).contains( rx ) )
+ res += QStringList::split( rx, (*it) );
+ else
+#endif
+ res << *it;
+ }
+ return res;
+
+}
+
+bool ocrWordList::updateOCRWord( const QString& from, const QString& to )
+{
+ ocrWordList::iterator it;
+ bool res = false;
+
+ for( it = begin(); it != end(); ++it )
+ {
+ QString word = (*it);
+ kdDebug(28000) << "updateOCRWord in list: Comparing word " << word << endl;
+ if( word.contains( from, true ) ) // case sensitive search
+ {
+ word.replace( from, to );
+ *it = ocrWord( word );
+ res = true;
+ break;
+ }
+ }
+ return res;
+}
+
+QRect ocrWordList::wordListRect()
+{
+ QRect rect;
+
+ ocrWordList::iterator it;
+
+ for( it = begin(); it != end(); ++it )
+ {
+ rect = rect.unite( (*it).rect() );
+ }
+ return rect;
+}
+
+
+/*
+ * since kspell removes , - | / etc. from words while they remain in the words
+ * in the ocr wordlist.
+ * This search goes through the wordlist and tries to find the words without caring
+ * for special chars. It simply removes all chars from the words that are not alphanumeric.
+ */
+bool ocrWordList::findFuzzyIndex( const QString& word, ocrWord& resWord )
+{
+ ocrWordList::iterator it;
+ bool res = false;
+
+ for( it = begin(); it != end() && !res; ++it )
+ {
+ QString fuzzyword = (*it);
+ fuzzyword.remove( QRegExp( "\\W" )); // Remove all non-word characters.
+ fuzzyword.remove( '_' );
+
+ // kdDebug(28000) << "findFuzzy: Comparing word " << fuzzyword << " which was "
+ // << (*it) << " with " << word << endl;
+ if( fuzzyword == word )
+ {
+ resWord = *it;
+ res = true;
+ }
+ }
+ return res;
+
+}
+
+void ocrWordList::setBlock( int b )
+{
+ m_block = b;
+}
+
+/* */
diff --git a/kooka/ocrword.h b/kooka/ocrword.h
new file mode 100644
index 00000000..606acb9f
--- /dev/null
+++ b/kooka/ocrword.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+ ocrword.h - ocr-result word and wordlist
+ -------------------
+ begin : Fri 10 Jan 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef _OCR_WORD_
+#define _OCR_WORD_
+
+#include <qstringlist.h>
+#include <qvaluevector.h>
+#include <qvaluelist.h>
+#include <qrect.h>
+
+class QString;
+class QRect;
+
+
+/* ==== ocrWord ====================================== */
+class ocrWord : public QString
+{
+public:
+ ocrWord(const QString& s);
+ ocrWord();
+ QStringList getAlternatives()
+ { return m_alternatives; }
+
+ void setAlternatives( const QString& s )
+ { m_alternatives.append(s); }
+
+ // QRect boundingRect();
+
+ void setKnode( int k )
+ { m_startKnode = k; }
+ void setLine( int l )
+ { m_line = l; }
+
+ int getLine() const { return m_line; }
+ int getKnode() const { return m_startKnode; }
+
+ void setRect( const QRect& r )
+ { m_position = r; }
+ QRect rect()
+ { return m_position; }
+
+private:
+ QStringList m_alternatives;
+ int m_startKnode;
+ int m_line;
+ QRect m_position;
+};
+
+/* ==== ocrWordList ====================================== */
+
+/**
+ * This represents a line of words in an ocr'ed document
+ */
+class ocrWordList : public QValueList<ocrWord>
+{
+public:
+ ocrWordList();
+ QStringList stringList();
+
+ bool updateOCRWord( const QString& from, const QString& to );
+
+ bool findFuzzyIndex( const QString& word, ocrWord& resWord );
+
+ QRect wordListRect( );
+
+ void setBlock( int b );
+ int block() const { return m_block; }
+
+private:
+ int m_block;
+};
+
+/**
+ * All lines of a block: A value vector containing as much as entries
+ * as lines are available in a block. Needs to be resized acordingly.
+ */
+typedef QValueVector<ocrWordList> ocrBlock;
+
+/**
+ * Blocks taken together form the page.
+ * Attention: Needs to be resized to the amount of blocks !!
+ */
+typedef QValueVector<ocrBlock> ocrBlockPage;
+
+typedef QValueVector<QRect> rectList;
+
+#endif
diff --git a/kooka/pics/Makefile.am b/kooka/pics/Makefile.am
new file mode 100644
index 00000000..f8f4440b
--- /dev/null
+++ b/kooka/pics/Makefile.am
@@ -0,0 +1,8 @@
+# Add all of your pixmaps here
+pics_DATA = mirror-both.png mirror-horiz.png mirror-vert.png scaletoheight.png \
+ scaletowidth.png scaleorig.png ocr.png ocr-select.png newfromselect.png \
+ thumbviewtile.png gocr.png ocrad.png lockzoom.png
+
+
+# This is where it will all be installed
+picsdir = $(kde_datadir)/kooka/pics
diff --git a/kooka/pics/gocr.png b/kooka/pics/gocr.png
new file mode 100644
index 00000000..575ebea9
--- /dev/null
+++ b/kooka/pics/gocr.png
Binary files differ
diff --git a/kooka/pics/lockzoom.png b/kooka/pics/lockzoom.png
new file mode 100644
index 00000000..dbfa1a7e
--- /dev/null
+++ b/kooka/pics/lockzoom.png
Binary files differ
diff --git a/kooka/pics/mirror-both.png b/kooka/pics/mirror-both.png
new file mode 100644
index 00000000..e275689b
--- /dev/null
+++ b/kooka/pics/mirror-both.png
Binary files differ
diff --git a/kooka/pics/mirror-horiz.png b/kooka/pics/mirror-horiz.png
new file mode 100644
index 00000000..eb537f40
--- /dev/null
+++ b/kooka/pics/mirror-horiz.png
Binary files differ
diff --git a/kooka/pics/mirror-vert.png b/kooka/pics/mirror-vert.png
new file mode 100644
index 00000000..d3c29462
--- /dev/null
+++ b/kooka/pics/mirror-vert.png
Binary files differ
diff --git a/kooka/pics/newfromselect.png b/kooka/pics/newfromselect.png
new file mode 100644
index 00000000..93a75ec8
--- /dev/null
+++ b/kooka/pics/newfromselect.png
Binary files differ
diff --git a/kooka/pics/ocr-select.png b/kooka/pics/ocr-select.png
new file mode 100644
index 00000000..db076898
--- /dev/null
+++ b/kooka/pics/ocr-select.png
Binary files differ
diff --git a/kooka/pics/ocr.png b/kooka/pics/ocr.png
new file mode 100644
index 00000000..c68f0616
--- /dev/null
+++ b/kooka/pics/ocr.png
Binary files differ
diff --git a/kooka/pics/ocrad.png b/kooka/pics/ocrad.png
new file mode 100644
index 00000000..01e41184
--- /dev/null
+++ b/kooka/pics/ocrad.png
Binary files differ
diff --git a/kooka/pics/scaleorig.png b/kooka/pics/scaleorig.png
new file mode 100644
index 00000000..8c696f48
--- /dev/null
+++ b/kooka/pics/scaleorig.png
Binary files differ
diff --git a/kooka/pics/scaletoheight.png b/kooka/pics/scaletoheight.png
new file mode 100644
index 00000000..b84d971b
--- /dev/null
+++ b/kooka/pics/scaletoheight.png
Binary files differ
diff --git a/kooka/pics/scaletowidth.png b/kooka/pics/scaletowidth.png
new file mode 100644
index 00000000..90e33617
--- /dev/null
+++ b/kooka/pics/scaletowidth.png
Binary files differ
diff --git a/kooka/pics/thumbviewtile.png b/kooka/pics/thumbviewtile.png
new file mode 100644
index 00000000..6f806851
--- /dev/null
+++ b/kooka/pics/thumbviewtile.png
Binary files differ
diff --git a/kooka/resource.h b/kooka/resource.h
new file mode 100644
index 00000000..51c9488f
--- /dev/null
+++ b/kooka/resource.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : Thu Dec 9 20:16:54 MET 1999
+
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESSOURCE_H
+#define RESSOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+///////////////////////////////////////////////////////////////////
+// resource.h -- contains macros used for commands
+
+
+///////////////////////////////////////////////////////////////////
+// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES
+
+
+///////////////////////////////////////////////////////////////////
+// File-menu entries
+#define ID_FILE_NEW 10020
+#define ID_FILE_OPEN 10030
+
+#define ID_FILE_SAVE 10050
+#define ID_FILE_SAVE_AS 10060
+#define ID_FILE_CLOSE 10070
+
+#define ID_FILE_PRINT 10080
+
+#define ID_FILE_QUIT 10100
+
+
+///////////////////////////////////////////////////////////////////
+// Edit-menu entries
+#define ID_EDIT_UNDO 11010
+#define ID_EDIT_REDO 11020
+#define ID_EDIT_COPY 11030
+#define ID_EDIT_CUT 11040
+#define ID_EDIT_PASTE 11050
+#define ID_EDIT_SELECT_ALL 11060
+
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_VIEW_TOOLBAR 12010
+#define ID_VIEW_STATUSBAR 12020
+#define ID_VIEW_PREVIEW 12021
+#define ID_VIEW_POOL 12022
+#define ID_VIEW_SCANPARAMS 12023
+
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_SCAN_PREVIEW 13010
+#define ID_SCAN_FINAL 13020
+
+///////////////////////////////////////////////////////////////////
+// Help-menu entries
+#define ID_HELP_ABOUT 1002
+
+///////////////////////////////////////////////////////////////////
+// General application values
+#define IDS_APP_ABOUT "Ksanetest\n Version " VERSION
+
+#define IDS_DEFAULT "Ready."
+
+#endif // RESOURCE_H
+
+
diff --git a/kooka/scanpackager.cpp b/kooka/scanpackager.cpp
new file mode 100644
index 00000000..7af7f151
--- /dev/null
+++ b/kooka/scanpackager.cpp
@@ -0,0 +1,1261 @@
+/***************************************************************************
+ scanpackager.cpp - description
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "scanpackager.h"
+#include "resource.h"
+#include "img_saver.h"
+#include "kookaimage.h"
+#include "kookaimagemeta.h"
+#include "previewer.h"
+#include "devselector.h"
+
+#include <qapplication.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qpopupmenu.h>
+#include <qdict.h>
+#include <qpixmap.h>
+#include <kmessagebox.h>
+#include <qfiledialog.h>
+#include <qstringlist.h>
+#include <qheader.h>
+
+#include <kfiletreeview.h>
+#include <kfiletreeviewitem.h>
+#include <kfiletreebranch.h>
+
+#include <kurldrag.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <kinputdialog.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kio/global.h>
+#include <kio/progressbase.h>
+#include <kio/netaccess.h>
+#include <kio/jobclasses.h>
+#include <kio/file.h>
+#include <kio/job.h>
+
+#define STARTUP_FIRST_START "firstStart"
+
+
+/* ----------------------------------------------------------------------- */
+/* Constructor Scan Packager */
+ScanPackager::ScanPackager( QWidget *parent ) : KFileTreeView( parent )
+{
+ // TODO:
+ setItemsRenameable (true );
+ setDefaultRenameAction( QListView::Reject );
+ addColumn( i18n("Image Name" ));
+ setColumnAlignment( 0, AlignLeft );
+
+ addColumn( i18n("Size") );
+ setColumnAlignment( 1, AlignRight );
+ setColumnAlignment( 2, AlignRight );
+
+ addColumn( i18n("Format" )); setColumnAlignment( 3, AlignRight );
+
+ /* Drag and Drop */
+ setDragEnabled( true );
+ setDropVisualizer(true);
+ setAcceptDrops(true);
+
+ connect( this, SIGNAL(dropped( QWidget*, QDropEvent*, KURL::List&, KURL& )),
+ this, SLOT( slotUrlsDropped( QWidget*, QDropEvent*, KURL::List&, KURL& )));
+
+ kdDebug(28000) << "connected Drop-Signal" << endl;
+ setRenameable ( 0, true );
+ setRenameable ( 1, false );
+ setRenameable ( 2, false );
+ setRenameable ( 3, false );
+
+ setRootIsDecorated( false );
+
+ connect( this, SIGNAL( clicked( QListViewItem*)),
+ SLOT( slClicked(QListViewItem*)));
+
+ connect( this, SIGNAL( rightButtonPressed( QListViewItem *, const QPoint &, int )),
+ SLOT( slShowContextMenue(QListViewItem *, const QPoint &, int )));
+
+ connect( this, SIGNAL(itemRenamed (QListViewItem*, const QString &, int ) ), this,
+ SLOT(slFileRename( QListViewItem*, const QString&, int)));
+
+
+ img_counter = 1;
+ /* Set the current export dir to home */
+ m_currCopyDir = QDir::home().absPath();
+ m_currImportDir = m_currCopyDir;
+
+ /* Preload frequently used icons */
+ KIconLoader *loader = KGlobal::iconLoader();
+ m_floppyPixmap = loader->loadIcon( "3floppy_unmount", KIcon::Small );
+ m_grayPixmap = loader->loadIcon( "palette_gray", KIcon::Small );
+ m_bwPixmap = loader->loadIcon( "palette_lineart", KIcon::Small );
+ m_colorPixmap = loader->loadIcon( "palette_color", KIcon::Small );
+
+ m_startup = true;
+
+ /* create a context menu and set the title */
+ m_contextMenu = new KPopupMenu();
+ static_cast<KPopupMenu*>(m_contextMenu)->insertTitle( i18n( "Gallery" ));
+
+}
+
+void ScanPackager::openRoots()
+{
+ /* standard root always exists, ImgRoot creates it */
+ KURL rootUrl(Previewer::galleryRoot());
+ kdDebug(28000) << "Open standard root " << rootUrl.url() << endl;
+
+ openRoot( rootUrl, true );
+ m_defaultBranch->setOpen(true);
+
+ /* open more configurable image repositories TODO */
+}
+
+KFileTreeBranch* ScanPackager::openRoot( const KURL& root, bool )
+{
+ KIconLoader *loader = KGlobal::iconLoader();
+
+ /* working on the global branch. FIXME */
+ m_defaultBranch = addBranch( root, i18n("Kooka Gallery"),
+ loader->loadIcon( "folder_image", KIcon::Small ),
+ false /* do not showHidden */ );
+
+ // Q_CHECK_PTR( m_defaultBranch );
+ m_defaultBranch->setOpenPixmap( loader->loadIcon( "folder_blue_open", KIcon::Small ));
+
+ setDirOnlyMode( m_defaultBranch, false );
+ m_defaultBranch->setShowExtensions( true ); // false );
+
+ connect( m_defaultBranch, SIGNAL( newTreeViewItems( KFileTreeBranch*, const KFileTreeViewItemList& )),
+ this, SLOT( slotDecorate(KFileTreeBranch*, const KFileTreeViewItemList& )));
+
+ connect( m_defaultBranch, SIGNAL( directoryChildCount( KFileTreeViewItem* , int )),
+ this, SLOT( slotDirCount( KFileTreeViewItem *, int )));
+
+ connect( m_defaultBranch, SIGNAL( deleteItem( KFileItem* )),
+ this, SLOT( slotDeleteFromBranch(KFileItem*)));
+
+ connect( m_defaultBranch, SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, SLOT( slotStartupFinished( KFileTreeViewItem * )));
+
+
+ return( m_defaultBranch );
+}
+
+void ScanPackager::slotStartupFinished( KFileTreeViewItem *it )
+{
+ if( m_startup && (it == m_defaultBranch->root()) )
+ {
+ kdDebug(28000) << "Slot population finished hit!" << endl;
+
+ /* If nothing is selected, select the root. */
+ if( ! currentKFileTreeViewItem() )
+ {
+ (m_defaultBranch->root())->setSelected( true );
+ }
+
+ m_startup = false;
+ }
+}
+
+void ScanPackager::slotDirCount( KFileTreeViewItem* item, int cnt )
+{
+ if( item && item->isDir() )
+ {
+ QString cc = i18n( "one item", "%n items", cnt);
+ item->setText( 1, cc );
+ }
+ else
+ {
+ kdDebug(28000) << "Item is NOT directory - do not set child count!" << endl;
+ }
+}
+
+void ScanPackager::slotDecorate( KFileTreeViewItem* item )
+{
+ if( !item ) return;
+ if( item->isDir())
+ {
+ // done in extra slot.
+ kdDebug(28000) << "Decorating directory!" << endl;
+ }
+ else
+
+ {
+ KFileItem *kfi = item->fileItem();
+
+ KookaImage *img = 0L;
+
+ if( kfi )
+ {
+ img = static_cast<KookaImage*>(kfi->extraData( this ));
+ }
+
+ if( img )
+ {
+
+ /* The image appears to be loaded to memory. */
+ if( img->depth() == 1 )
+ {
+ /* a bw-image */
+ item->setPixmap( 0, m_bwPixmap );
+ }
+ else
+ {
+ if( img->isGrayscale() )
+ {
+ item->setPixmap( 0, m_grayPixmap );
+ }
+ else
+ {
+ item->setPixmap( 0, m_colorPixmap );
+ }
+ }
+
+ /* set image size in pixels */
+ QString t = i18n( "%1 x %2" ).arg( img->width()).arg(img->height());
+ item->setText( 1, t );
+ kdDebug( 28000) << "Image loaded and decorated!" << endl;
+ }
+ else
+ {
+ /* Item is not yet loaded. Display file information */
+ item->setPixmap( 0, m_floppyPixmap );
+ if ( kfi )
+ {
+ item->setText(1, KIO::convertSize( kfi->size() ));
+ }
+ }
+
+ /* Image format */
+ QString format = getImgFormat( item );
+ item->setText( 2, format );
+ }
+
+ // This code is quite similar to m_nextUrlToSelect in KFileTreeView::slotNewTreeViewItems
+ // When scanning a new image, we wait for the KDirLister to notice the new file,
+ // and then we have the KFileTreeViewItem that we need to display the image.
+ if ( ! m_nextUrlToShow.isEmpty() )
+ {
+ if( m_nextUrlToShow.equals(item->url(), true ))
+ {
+ m_nextUrlToShow = KURL(); // do this first to prevent recursion
+ slClicked( item );
+ setCurrentItem(item); // neccessary in case of new file from D&D
+ }
+ }
+}
+
+
+
+
+void ScanPackager::slotDecorate( KFileTreeBranch* branch, const KFileTreeViewItemList& list )
+{
+ (void) branch;
+ kdDebug(28000) << "decorating slot for list !" << endl;
+
+ KFileTreeViewItemListIterator it( list );
+
+ bool end = false;
+ for( ; !end && it.current(); ++it )
+ {
+ KFileTreeViewItem *kftvi = *it;
+ slotDecorate( kftvi );
+ emit fileChanged( kftvi->fileItem() );
+ }
+}
+
+
+
+void ScanPackager::slFileRename( QListViewItem* it, const QString& newStr, int )
+{
+
+ bool success = true;
+ if( !it ) return;
+
+ if( newStr.isEmpty() )
+ success = false;
+
+ KFileTreeViewItem *item = static_cast<KFileTreeViewItem*>(it);
+
+ /* Free memory and imform everybody who is interested. */
+ KURL urlFrom = item->url();
+ KURL urlTo( urlFrom );
+
+ /* clean filename and apply new name */
+ urlTo.setFileName("");
+ urlTo.setFileName(newStr);
+
+ if( success )
+ {
+ if( urlFrom == urlTo )
+ {
+ kdDebug(28000) << "Renaming to same url does not make sense!" << endl;
+ success = false;
+ }
+ else
+ {
+ /* clear selection, because the renamed image comes in through
+ * kdirlister again
+ */
+ slotUnloadItem( item );
+
+ kdDebug(28000) << "Renaming to " << urlTo.prettyURL() <<
+ " from " << urlFrom.prettyURL() << endl;
+
+ /* to urlTo the really used filename is written */
+ setSelected( item, false );
+
+ if( ImgSaver::renameImage( urlFrom, urlTo, false, this ) )
+ {
+ kdDebug(28000) << "renaming OK" << endl;
+ emit fileRenamed( item->fileItem(), urlTo );
+ success=true;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ }
+
+ if( !success )
+ {
+ kdDebug(28000) << "renaming failed" << endl;
+ /* restore the name */
+ item->setText(0, urlFrom.fileName() );
+ setSelected( item, true );
+
+ }
+
+}
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Method that checks if the new filename a user enters while renaming an image is valid.
+ * It checks for a proper extension.
+ */
+QString ScanPackager::buildNewFilename( QString cmplFilename, QString currFormat ) const
+{
+ /* cmplFilename = new name the user wishes.
+ * currFormat = the current format of the image.
+ * if the new filename has a valid extension, which is the same as the
+ * format of the current, fine. A ''-String has to be returned.
+ */
+ QFileInfo fiNew( cmplFilename );
+ QString base = fiNew.baseName();
+ QString newExt = fiNew.extension( false ).lower();
+ QString nowExt = currFormat.lower();
+ QString ext = "";
+
+ kdDebug(28000) << "Filename wanted: "<< cmplFilename << " <"<<newExt<<"> <" << nowExt<<">" <<endl;
+
+ if( newExt.isEmpty() )
+ {
+ /* ok, fine -> return the currFormat-Extension */
+ ext = base + "." + currFormat;
+ }
+ else if( newExt == nowExt )
+ {
+ /* also good, no reason to put another extension */
+ ext = cmplFilename;
+ }
+ else
+ {
+ /* new Ext. differs from the current extension. Later. */
+ KMessageBox::sorry( 0L, i18n( "You entered a file extension that differs from the existing one. That is not yet possible. Converting 'on the fly' is planned for a future release.\n"
+ "Kooka corrects the extension."),
+ i18n("On the Fly Conversion"));
+ ext = base + "." + currFormat;
+ }
+ return( ext );
+}
+
+/* ----------------------------------------------------------------------- */
+/* This method returns the directory of an image or directory.
+ */
+QString ScanPackager::itemDirectory( const KFileTreeViewItem* item, bool relativ ) const
+{
+ if( ! item )
+ {
+ kdDebug(28000) << "ERR: itemDirectory without item" << endl;
+ return QString::null;
+ }
+
+ QString relativUrl= (item->url()).prettyURL();
+
+ if( ! item->isDir() )
+ {
+ // Cut off the filename in case it is not a dir
+ relativUrl.truncate( relativUrl.findRev( '/' )+1);
+ }
+ else
+ {
+ /* add a "/" to the directory if not there */
+ if( ! relativUrl.endsWith( "/" ) )
+ relativUrl.append( "/" );
+ }
+
+ if( relativ )
+ {
+ KFileTreeBranch *branch = item->branch();
+ if( branch )
+ {
+ kdDebug(28000) << "Relativ URL of the file " << relativUrl << endl;
+ QString rootUrl = (branch->rootUrl()).prettyURL(); // directory of branch root
+
+ if( relativUrl.startsWith( rootUrl ))
+ {
+ relativUrl.remove( 0, rootUrl.length() );
+
+ if( relativUrl.isEmpty() ) relativUrl = "/"; // The root
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Item-URL does not start with root url " << rootUrl << endl;
+ }
+ }
+ }
+ return( relativUrl );
+}
+/* ----------------------------------------------------------------------- */
+/* This slot receives a string from the gallery-path combobox shown under the
+ * image gallery. The form of the string coming in here is <branch-name> - <
+ * relativ directory under the branch. Now it is to assemble a complete path
+ * from the data, find out which KFileTreeViewItem is associated with it and
+ * call slClicked with it.
+ */
+
+void ScanPackager::slotSelectDirectory( const QString & dirString )
+{
+ kdDebug(28000) << "Trying to decode directory string " << dirString << endl;
+
+ QString searchFor = QString::fromLatin1(" - ");
+ int pos = dirString.find( searchFor );
+
+ if( pos > -1 )
+ {
+ /* Splitting up the string coming in */
+ QString branchName = dirString.left( pos );
+ QString relPath( dirString );
+
+ relPath = relPath.remove( 0, pos + searchFor.length());
+
+ kdDebug(28000) << "Splitted up to branch <" << branchName << "> and <" << relPath << endl;
+
+ KFileTreeViewItem *kfi = findItem( branchName, relPath );
+
+ if( kfi )
+ {
+ kdDebug(28000) << "got a new item to select !" << endl;
+ ensureItemVisible(kfi);
+ setCurrentItem(kfi);
+ slClicked(kfi); // load thumbnails for this dir etc.
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+/* This slot is called when clicking on an item. */
+void ScanPackager::slClicked( QListViewItem *newItem )
+{
+ KFileTreeViewItem *item = static_cast<KFileTreeViewItem*>(newItem);
+
+ if( item ) // can be 0, when clicking where no item is present
+ {
+ kdDebug(28000) << "Clicked - newItem !" << endl;
+ /* Check if directory, hide image for now, later show a thumb view */
+ if( item->isDir())
+ {
+ kdDebug(28000) << "clicked: Is a directory !" << endl;
+ emit( showImage( 0L ));
+ kdDebug(28000) << "emitting showThumbnails" << endl;
+ }
+ else
+ {
+ /* if not a dir, load the image if necessary. This is done by loadImageForItem,
+ * which is async( TODO ). The image finally arrives in slotImageArrived */
+ QApplication::setOverrideCursor(waitCursor);
+ emit( aboutToShowImage( item->url()));
+ loadImageForItem( item );
+ QApplication::restoreOverrideCursor();
+ }
+
+ /* emit a signal indicating the new directory if there is a new one */
+ QString wholeDir = itemDirectory( item, false ); /* not relativ to root */
+
+ if( currSelectedDir != wholeDir )
+ {
+ currSelectedDir = wholeDir;
+ QString relativUrl = itemDirectory( item, true );
+ kdDebug(28000) << "Emitting " << relativUrl << " as new relative Url" << endl;
+ /* Emit the signal with branch and the relative path */
+ emit( galleryPathSelected( item->branch(), relativUrl ));
+
+ if( item->isDir() )
+ {
+ emit( showThumbnails( item ));
+ }
+ else
+ {
+ emit( showThumbnails( static_cast<KFileTreeViewItem*>(item->parent())));
+ }
+ }
+ else
+ {
+ // kdDebug(28000) << "directory is not new: " << currSelectedDir << endl;
+ }
+ }
+}
+
+void ScanPackager::loadImageForItem( KFileTreeViewItem *item )
+{
+
+ if( ! item ) return;
+ bool result = true;
+
+ KFileItem *kfi = item->fileItem();
+ if( ! kfi ) return;
+
+ KookaImage *img = static_cast<KookaImage*>( kfi->extraData(this));
+
+ if( img )
+ {
+ kdDebug(28000) << "Image already loaded." << endl;
+ /* result is still true, image must be shown. */
+ }
+ else
+ {
+ /* The image needs to be loaded. Possibly it is a multi-page image.
+ * If it is, the kookaImage has a subImageCount larger than one. We
+ * create an subimage-item for every subimage, but do not yet load
+ * them.
+ */
+ KURL url = item->url();
+
+ img = new KookaImage( );
+ if( !img || !img->loadFromUrl( url ) )
+ {
+ kdDebug(28000) << "Loading KookaImage from File failed!" << endl;
+ result = false;
+ }
+ else
+ {
+ /* store the fileitem */
+ img->setFileItem( kfi );
+
+ /* care for subimages, create items for them */
+ kdDebug(28000) << "subImage-count: " << img->subImagesCount() << endl;
+ if( img->subImagesCount() > 1 )
+ {
+ KIconLoader *loader = KGlobal::iconLoader();
+ kdDebug(28000) << "SubImages existing!" << endl;
+
+ /* Start at the image with index 1, that makes one less than are actually in the
+ * image. But image 0 was already created above. */
+ KFileTreeViewItem *prevItem=0;
+ for( int i = 1; i < img->subImagesCount(); i++ )
+ {
+ kdDebug(28000) << "Creating subimage no " << i << endl;
+ KFileItem *newKfi = new KFileItem( *kfi );
+ KFileTreeViewItem *subImgItem = new KFileTreeViewItem( item, newKfi, item->branch());
+
+ if( prevItem )
+ {
+ subImgItem->moveItem( prevItem );
+ }
+ prevItem = subImgItem;
+
+ subImgItem->setPixmap( 0, loader->loadIcon( "editcopy", KIcon::Small ));
+ subImgItem->setText( 0, i18n("Sub-image %1").arg( i ) );
+ KookaImage *subImgImg = new KookaImage( i, img );
+ subImgImg->setFileItem( newKfi );
+ newKfi->setExtraData( (void*) this, (void*) subImgImg );
+ }
+ }
+ }
+ }
+
+
+ if( result && img )
+ {
+ if( img->isSubImage() )
+ {
+ kdDebug(28000) << "it _is_ a subimage" << endl;
+ /* load if not loaded */
+ if( img->isNull())
+ {
+ kdDebug(28000) << "extracting subimage" << endl;
+ img->extractNow();
+ }
+ else
+ {
+ kdDebug(28000) << "Is not a null image" << endl;
+ }
+ }
+ slImageArrived( item, img );
+ }
+}
+
+/* Hit this slot with a file for a kfiletreeviewitem. */
+void ScanPackager::slImageArrived( KFileTreeViewItem *item, KookaImage* image )
+{
+ if( item && image )
+ {
+ /* Associate the image for the Scanpackager-Object. */
+ KFileItem *kfi = item->fileItem();
+ if( kfi )
+ {
+ kfi->setExtraData( (void*) this, (void*) image );
+ }
+ slotDecorate( item );
+ emit( showImage( image ));
+ }
+}
+
+KookaImage* ScanPackager::getCurrImage() const
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ KookaImage *img = 0L;
+
+ if( curr )
+ {
+ KFileItem *kfi = curr->fileItem();
+ if( kfi )
+ {
+ img = static_cast<KookaImage*>(kfi->extraData( this ));
+ }
+ }
+ return(img);
+}
+
+
+QString ScanPackager::getCurrImageFileName( bool withPath = true ) const
+{
+ QString result = "";
+
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr )
+ {
+ kdDebug( 28000) << "getCurrImageFileName: nothing selected !"<< endl;
+ }
+ else
+ {
+ if( withPath )
+ {
+ result = localFileName(curr);
+ }
+ else
+ {
+ KURL url( localFileName(curr));
+ url = curr->url();
+ result = url.fileName();
+ }
+ }
+ return( result );
+}
+
+/* ----------------------------------------------------------------------- */
+QCString ScanPackager::getImgFormat( KFileTreeViewItem* item ) const
+{
+
+ QCString cstr;
+
+ if( !item ) return( cstr );
+#if 0
+ KFileItem *kfi = item->fileItem();
+
+ QString mime = kfi->mimetype();
+#endif
+
+ // TODO find the real extension for use with the filename !
+ // temporarely:
+ QString f = localFileName( item );
+
+ return( QImage::imageFormat( f ));
+
+}
+
+QString ScanPackager::localFileName( KFileTreeViewItem *it ) const
+{
+ if( ! it ) return( QString::null );
+
+ KURL url = it->url();
+
+ QString res;
+
+ if( url.isLocalFile())
+ {
+ res = url.directory( false, true ) + url.fileName();
+ }
+
+ return( res );
+}
+
+/* Called if the image exists but was changed by image manipulation func */
+void ScanPackager::slotCurrentImageChanged( QImage *img )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr )
+ {
+ kdDebug(28000) << "ImageChanged: nothing selected !" << endl;
+ return;
+ }
+
+ /* Do not save directories */
+ if( curr->isDir() ) return;
+
+ /* unload image and free memory */
+ slotUnloadItem( curr );
+
+ const QString filename = localFileName( curr );
+ const QCString format = getImgFormat( curr );
+ ImgSaver saver( this );
+ ImgSaveStat is_stat = ISS_OK;
+ is_stat = saver.saveImage( img, filename, format );
+
+ if( is_stat == ISS_ERR_FORMAT_NO_WRITE )
+ {
+ KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"),
+ i18n("Save Error") );
+ }
+ else if( is_stat == ISS_ERR_PERM )
+ {
+ KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat == ISS_ERR_PROTOCOL )
+ {
+ KMessageBox::sorry( this, i18n( "Cannot save the image, because the file is local.\n"
+ "Kooka will support other protocols later."),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat != ISS_OK )
+ {
+ kdDebug(28000) << "Error while saving existing image !" << endl;
+ }
+
+ if( img && !img->isNull())
+ {
+ emit( imageChanged( curr->fileItem()));
+ KookaImage *newImage = new KookaImage(*img);
+ slImageArrived( curr, newImage );
+ }
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* This slot takes a new scanned Picture and saves it.
+ * It urgently needs to make a deep copy of the image !
+ */
+void ScanPackager::slAddImage( QImage *img, KookaImageMeta* )
+{
+ ImgSaveStat is_stat = ISS_OK;
+ /* Save the image with the help of the ImgSaver */
+ if( ! img ) return;
+
+ /* currently selected item is the directory or a file item */
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+
+ /* Use root if nothing is selected */
+ if( ! curr )
+ {
+ KFileTreeBranch *b = branches().at(0); /* There should be at least one */
+
+ if( b )
+ {
+ curr = findItem( b, i18n( "Incoming/" ) );
+ if( ! curr ) curr = b->root();
+ }
+
+ /* If curr is still undefined, something very tough has happend. Go away here */
+ if( !curr ) return;
+
+ setSelected( curr, true );
+ }
+
+ /* find the directory above the current one */
+
+ KURL dir(itemDirectory( curr ));
+
+ /* Path of curr sel item */
+ ImgSaver img_saver( this, dir );
+
+ is_stat = img_saver.saveImage( img );
+ if( is_stat == ISS_ERR_FORMAT_NO_WRITE )
+ {
+ KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"),
+ i18n("Save Error") );
+ }
+ else if( is_stat == ISS_ERR_PERM )
+ {
+ KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat != ISS_OK )
+ {
+ if( is_stat == ISS_SAVE_CANCELED )
+ {
+ return;
+ }
+ kdDebug(28000) << "ERROR: Saving failed: " << img_saver.errorString( is_stat ) << endl;
+ /* And now ?? */
+ }
+
+ /* Add the new image to the list of new images */
+ KURL lurl = img_saver.lastFileUrl();
+
+ KFileTreeBranchList branchlist = branches();
+ KFileTreeBranch *kookaBranch = branchlist.at(0);
+
+ QString strdir = itemDirectory(curr);
+ if(strdir.endsWith(QString("/"))) strdir.truncate( strdir.length() - 1 );
+ kdDebug(28000) << "Updating directory with " << strdir << endl;
+
+ if( kookaBranch ) kookaBranch->updateDirectory( KURL(strdir) );
+ slotSetNextUrlToSelect( lurl );
+ m_nextUrlToShow = lurl;
+
+ QString s;
+ /* Count amount of children of the father */
+ QListViewItem *paps = curr->parent();
+ if( curr->isDir() ) /* take only father if the is no directory */
+ paps = curr;
+
+ if( paps )
+ {
+ int childcount = paps->childCount();
+ s = i18n("%1 images").arg(childcount);
+ paps->setText( 1, s);
+ setOpen( paps, true );
+ }
+
+}
+
+/* ----------------------------------------------------------------------- */
+/* selects and opens the file with the given name. This is used to restore the
+ * last displayed image by its name.
+ */
+void ScanPackager::slSelectImage( const KURL& name )
+{
+
+ KFileTreeViewItem *found = spFindItem( UrlSearch, name.url() );
+
+ if( found )
+ {
+ kdDebug(28000) << "slSelectImage: Found an item !" << endl;
+ ensureItemVisible( found );
+ setCurrentItem( found );
+ slClicked( found );
+ }
+
+}
+
+
+KFileTreeViewItem *ScanPackager::spFindItem( SearchType type, const QString name, const KFileTreeBranch *branch )
+{
+ /* Prepare a list of branches to go through. If the parameter branch is set, search
+ * only in the parameter branch. If it is zero, search all branches returned by
+ * kfiletreeview.branches()
+ */
+ KFileTreeBranchList branchList;
+
+ if( branch )
+ {
+ branchList.append( branch );
+ }
+ else
+ {
+ branchList = branches();
+ }
+
+
+ KFileTreeBranchIterator it( branchList );
+ KFileItem *kfi = 0L;
+ KFileTreeViewItem *foundItem = 0L;
+
+ /* Leave the loop in case kfi is defined */
+ KFileTreeBranch *branchloop = 0L;
+ for( ; !kfi && it.current(); ++it )
+ {
+ branchloop = *it;
+ KURL url(name);
+ switch( type )
+ {
+ case Dummy:
+ kdDebug(28000) << "Dummy search skipped !" << endl;
+ break;
+ case NameSearch:
+ kdDebug(28000) << "ScanPackager: searching for " << name << endl;
+ kfi = branchloop->findByName( name );
+ break;
+ case UrlSearch:
+ kdDebug(28000) << "ScanPackager: URL search for " << name << endl;
+ kfi = branchloop->find( url );
+ break;
+ default:
+ kdDebug(28000) << "Scanpackager: Wrong search type !" << endl;
+ break;
+ }
+
+ }
+ if( kfi )
+ {
+ foundItem = static_cast<KFileTreeViewItem*>(kfi->extraData(branchloop));
+ kdDebug(28000) << "spFindItem: Success !" << foundItem << endl;
+ }
+ return( foundItem );
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slShowContextMenue(QListViewItem *lvi, const QPoint &p, int col )
+{
+ kdDebug(28000) << "Showing Context Menue" << endl;
+ (void) col;
+
+ KFileTreeViewItem *curr = 0;
+
+ if( lvi )
+ {
+ curr = currentKFileTreeViewItem();
+ if( curr->isDir() )
+ setSelected( curr, true );
+ }
+
+ if( m_contextMenu )
+ {
+ m_contextMenu->exec( p );
+ }
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+void ScanPackager::slotExportFile( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ if( curr->isDir() )
+ {
+ kdDebug(28000) << "Not yet implemented!" << endl;
+ }
+ else
+ {
+ KURL fromUrl( curr->url());
+ QString filter = "*." + getImgFormat(curr).lower();
+ filter += "\n*|" + i18n( "All Files" );
+
+ // initial += fromUrl.filename(false);
+ QString initial = m_currCopyDir + "/";
+ initial += fromUrl.filename(false);
+ KURL fileName = KFileDialog::getSaveURL ( initial,
+ filter, this );
+
+ if ( fileName.isValid() ) // got a file name
+ {
+ if( fromUrl == fileName ) return;
+
+ /* Since it is asynchron, we will never get if it succeeded. */
+ ImgSaver::copyImage( fromUrl, fileName );
+
+ /* remember the filename for the next export */
+ fileName.setFileName( QString());
+ m_currCopyDir = fileName.url( );
+ }
+ }
+}
+
+
+void ScanPackager::slotImportFile()
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ KURL impTarget = curr->url();
+
+ if( ! curr->isDir() )
+ {
+ KFileTreeViewItem *pa = static_cast<KFileTreeViewItem*>(curr->parent());
+ impTarget = pa->url();
+ }
+ kdDebug(28000) << "Importing to " << impTarget.url() << endl;
+
+ KURL impUrl = KFileDialog::getImageOpenURL ( m_currImportDir, this, i18n("Import Image File to Gallery"));
+
+ if( ! impUrl.isEmpty() )
+ {
+ m_currImportDir = impUrl.url();
+ impTarget.addPath( impUrl.fileName()); // append the name of the sourcefile to the path
+ m_nextUrlToShow = impTarget;
+ ImgSaver::copyImage( impUrl, impTarget );
+ }
+}
+
+
+
+void ScanPackager::slotUrlsDropped( QWidget*, QDropEvent* ev, KURL::List& urls, KURL& copyTo )
+{
+ if( !urls.isEmpty() )
+ {
+ kdDebug(28000) << "Kooka drop event!" << endl;
+ // kdDebug(28000) << "Kooka drop event. First src url=" << urls.first() << " copyTo=" << copyTo
+ // << " move=" << ( ev->action() == QDropEvent::Move ) << endl;
+
+ /* first make the last url to copy to the one to select next */
+ if( ! urls.empty() )
+ {
+ KURL nextSel = copyTo;
+ nextSel.addPath( urls.back().fileName(false));
+
+ kdDebug(28000) << "Selecting next url: " << nextSel.url() << endl;
+ m_nextUrlToShow = nextSel;
+ // slotSetNextUrlToSelect( nextSel );
+ }
+
+ if ( ev->action() == QDropEvent::Move )
+ copyjob = KIO::move( urls, copyTo, true );
+ else
+ copyjob = KIO::copy( urls, copyTo, true );
+ }
+}
+
+void ScanPackager::slotCanceled( KIO::Job* )
+{
+ kdDebug(28000) << i18n("Canceled by user") << endl;
+}
+
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotUnloadItems( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ emit( showImage( 0L ));
+ slotUnloadItem( curr );
+}
+
+void ScanPackager::slotUnloadItem( KFileTreeViewItem *curr )
+{
+ if( ! curr ) return;
+
+ if( curr->isDir())
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(curr->firstChild());
+ while( child )
+ {
+ kdDebug(28000) << "Unloading item " << child << endl;
+ slotUnloadItem( child );
+ child = static_cast<KFileTreeViewItem*> (child->nextSibling());
+ }
+ }
+ else
+ {
+ KFileItem *kfi = curr->fileItem();
+ KookaImage *image = static_cast<KookaImage*>(kfi->extraData( this ));
+
+ /* If image is zero, ok, than there is nothing to unload :) */
+ if( image )
+ {
+ if( image->subImagesCount() > 0 )
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(curr->firstChild());
+
+ while( child )
+ {
+ KFileTreeViewItem *nextChild = 0;
+ kdDebug(28000) << "Unloading subimage item " << child << endl;
+ slotUnloadItem( child );
+ nextChild = static_cast<KFileTreeViewItem*> (child->nextSibling());
+ delete child;
+ child = nextChild;
+ }
+ }
+
+ emit( unloadImage( image ));
+ delete image;
+ kfi->removeExtraData( this );
+ slotDecorate( curr );
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotDeleteItems( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ KURL urlToDel = curr->url();
+ QListViewItem *nextToSelect = curr->nextSibling();
+
+ kdDebug(28000) << "Deleting: " << urlToDel.prettyURL() << endl;
+ bool ask = true; /* for later use */
+
+ int result = KMessageBox::Yes;
+
+ KFileItem *item = curr->fileItem();
+ if( ask )
+ {
+ QString s;
+ s = i18n("Do you really want to delete this image?\nIt cannot be restored!" );
+ if( item->isDir() )
+ {
+ s = i18n("Do you really want to delete the folder %1\nand all the images inside?").arg("");
+ }
+ result = KMessageBox::warningContinueCancel(this, s, i18n( "Delete Collection Item"),
+ KStdGuiItem::del(), "AskForDeleteFiles" );
+ }
+
+ /* Since we are currently talking about local files here, NetAccess is OK */
+ if( result == KMessageBox::Continue )
+ {
+ if( KIO::NetAccess::del( urlToDel, 0 ))
+ {
+ if( nextToSelect )
+ setSelected( nextToSelect, true );
+ /* TODO: remove the directory from the imageNameCombobox */
+ if( curr && item->isDir() )
+ {
+ /* The directory needs to be removed from the name combo */
+ emit(directoryToRemove( curr->branch(), itemDirectory( curr, true ) ));
+ }
+
+ }
+ else
+ kdDebug(28000) << "Deleting files failed" << endl;
+
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotCreateFolder( )
+{
+ bool ok;
+ QString folder = KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Please enter a name for the new folder:" ), QString::null,
+ &ok, this );
+
+ if( ok )
+ {
+ /* KIO create folder goes here */
+
+ KFileTreeViewItem *it = currentKFileTreeViewItem();
+ if( it )
+ {
+ KURL url = it->url();
+
+ /* If a directory is selected, the filename needs not to be deleted */
+ if( ! it->isDir())
+ url.setFileName( "" );
+ /* add the folder name from user input */
+ url.addPath( folder );
+ kdDebug(28000) << "Creating folder " << url.prettyURL() << endl;
+
+ /* Since the new directory arrives in the packager in the newItems-slot, we set a
+ * variable urlToSelectOnArrive here. The newItems-slot will honor it and select
+ * the treeviewitem with that url.
+ */
+ slotSetNextUrlToSelect( url );
+
+ if( ! KIO::NetAccess::mkdir( url, 0, -1 ))
+ {
+ kdDebug(28000) << "ERR: creation of " << url.prettyURL() << " failed !" << endl;
+ }
+ else
+ {
+ /* created successfully */
+ /* open the branch if necessary and select the new folder */
+
+ }
+ }
+ }
+}
+
+
+/* ----------------------------------------------------------------------- */
+QString ScanPackager::getImgName( QString name_on_disk )
+{
+ QString s;
+ (void) name_on_disk;
+
+ s = i18n("image %1").arg(img_counter++);
+ return( s );
+}
+
+/* ----------------------------------------------------------------------- */
+ScanPackager::~ScanPackager(){
+ kdDebug(29000) << "Destructor of ScanPackager" << endl;
+
+}
+
+/* called whenever one branch detects a deleted file */
+void ScanPackager::slotDeleteFromBranch( KFileItem* kfi )
+{
+ emit fileDeleted( kfi );
+}
+
+void ScanPackager::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if( ! acceptDrag( e ) )
+ {
+ e->ignore();
+ return;
+ }
+
+ QListViewItem *afterme = 0;
+ QListViewItem *parent = 0;
+
+ findDrop( e->pos(), parent, afterme );
+
+ // "afterme" is 0 when aiming at a directory itself
+ QListViewItem *item = afterme ? afterme : parent;
+
+ if( item )
+ {
+ bool isDir = static_cast<KFileTreeViewItem*> (item)->isDir();
+ if( isDir ) {
+ KFileTreeView::contentsDragMoveEvent( e ); // for the autoopen code
+ return;
+ }
+ }
+ e->acceptAction();
+}
+
+
+#include "scanpackager.moc"
diff --git a/kooka/scanpackager.h b/kooka/scanpackager.h
new file mode 100644
index 00000000..13173050
--- /dev/null
+++ b/kooka/scanpackager.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ scanpackager.h - description
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef SCANPACKAGER_H
+#define SCANPACKAGER_H
+
+#include <qlistview.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qdragobject.h>
+#include <qmap.h>
+#include <klistview.h>
+#include <kio/job.h>
+#include <kio/global.h>
+#include <kio/file.h>
+#include <kfiletreeview.h>
+
+
+/**
+ *@author Klaas Freitag
+ */
+
+class KURL;
+class QPopupMenu;
+class KFileTreeViewItem;
+class KookaImage;
+class KookaImageMeta;
+class KFileTreeBranch;
+
+
+typedef enum{ Dummy, NameSearch, UrlSearch } SearchType;
+
+class JobDescription
+{
+public:
+ enum JobType { NoJob, ImportJob, RenameJob, ExportJob };
+ JobDescription():jobType( NoJob ), kioJob(0L), pitem(0L) {}
+ JobDescription( KIO::Job* kiojob, KFileTreeViewItem *new_item, JobType type ) :
+ jobType(type), kioJob(kiojob), pitem(new_item) {}
+
+ JobType type( void ) { return( jobType ); }
+ KFileTreeViewItem *item( void ) { return( pitem ); }
+ KIO::Job* job( void ){ return( kioJob ); }
+private:
+ JobType jobType;
+ KIO::Job* kioJob;
+ KFileTreeViewItem* pitem;
+};
+
+class ScanPackager : public KFileTreeView
+{
+ Q_OBJECT
+public:
+ ScanPackager( QWidget *parent);
+ ~ScanPackager();
+ virtual QString getImgName( QString name_on_disk );
+
+ QString getCurrImageFileName( bool ) const;
+ KookaImage* getCurrImage() const;
+
+ KFileTreeBranch* openRoot( const KURL&, bool open=false );
+
+ QPopupMenu *contextMenu() const { return m_contextMenu; }
+ void openRoots();
+
+public slots:
+ void slSelectImage( const KURL& );
+ void slAddImage( QImage *img, KookaImageMeta* meta = 0 );
+ void slShowContextMenue(QListViewItem *, const QPoint &, int );
+
+ void slotExportFile( );
+ void slotImportFile();
+ void slotCanceled(KIO::Job*);
+ void slotCurrentImageChanged( QImage* );
+
+ void slotDecorate( KFileTreeViewItem* );
+ void slotDecorate( KFileTreeBranch*, const KFileTreeViewItemList& );
+
+ void slotSelectDirectory( const QString& );
+
+protected:
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+
+protected slots:
+ void slClicked( QListViewItem * );
+ void slFileRename( QListViewItem*, const QString&, int );
+ // void slFilenameChanged( KFileTreeViewItem*, const KURL & );
+ void slImageArrived( KFileTreeViewItem *item, KookaImage* image );
+ void slotCreateFolder( );
+ void slotDeleteItems( );
+ void slotUnloadItems( );
+ void slotUnloadItem( KFileTreeViewItem *curr );
+ void slotDirCount( KFileTreeViewItem *item, int cnt );
+ void slotUrlsDropped( QWidget*, QDropEvent*, KURL::List& urls, KURL& copyTo );
+ void slotDeleteFromBranch( KFileItem* );
+ void slotStartupFinished( KFileTreeViewItem * );
+signals:
+ void showImage ( KookaImage* );
+ void deleteImage( KookaImage* );
+ void unloadImage( KookaImage* );
+ void galleryPathSelected( KFileTreeBranch* branch, const QString& relativPath );
+ void directoryToRemove( KFileTreeBranch *branch, const QString& relativPath );
+ void showThumbnails( KFileTreeViewItem* );
+
+ void aboutToShowImage( const KURL& ); /* starting to load image */
+ void imageChanged( KFileItem* ); /* the image has changed */
+
+ void fileDeleted( KFileItem* );
+ void fileChanged( KFileItem* );
+ void fileRenamed( KFileItem*, const KURL& );
+
+private:
+ QString localFileName( KFileTreeViewItem* it ) const;
+ void loadImageForItem( KFileTreeViewItem* item );
+ QCString getImgFormat( KFileTreeViewItem* item ) const;
+
+ QString buildNewFilename( QString cmplFilename, QString currFormat ) const;
+ KFileTreeViewItem *spFindItem( SearchType type, const QString name, const KFileTreeBranch* branch = 0 );
+ QString itemDirectory( const KFileTreeViewItem*, bool relativ = false ) const;
+
+ // int readDir( QListViewItem *parent, QString dir_to_read );
+ void showContextMenu( QPoint p, bool show_folder = true );
+
+ QString m_currImportDir;
+ QString m_currCopyDir;
+ QString currSelectedDir;
+ KIO::Job *copyjob;
+ int img_counter;
+ QPopupMenu *m_contextMenu;
+
+ // like m_nextUrlToSelect in KFileTreeView but for our own purposes (showing the image)
+ KURL m_nextUrlToShow;
+
+ QPixmap m_floppyPixmap;
+ QPixmap m_grayPixmap;
+ QPixmap m_bwPixmap;
+ QPixmap m_colorPixmap;
+
+ KFileTreeBranch *m_defaultBranch;
+ bool m_startup;
+};
+
+#endif
diff --git a/kooka/thumbview.cpp b/kooka/thumbview.cpp
new file mode 100644
index 00000000..5dfa93b6
--- /dev/null
+++ b/kooka/thumbview.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+ thumbview.cpp - Class to display thumbnailed images
+ -------------------
+ begin : Tue Apr 18 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qpixmap.h>
+#include <qpainter.h>
+
+#include <kio/previewjob.h>
+#include <kdebug.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+#include <kfiletreeviewitem.h>
+#include <kimageeffect.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+
+#include "thumbview.h"
+#include "thumbview.moc"
+
+#include "thumbviewitem.h"
+
+
+
+ThumbView::ThumbView( QWidget *parent, const char *name )
+ : QVBox( parent ),
+ m_iconView(0),
+ m_job(0)
+{
+ setMargin(3);
+ m_pixWidth = 0;
+ m_pixHeight = 0;
+ m_thumbMargin = 5;
+ m_iconView = new KIconView( this, name );
+ m_progress = new KProgress( this );
+ m_progress->hide();
+
+ m_pixWidth = 100;
+ m_pixHeight = 100;
+
+ readSettings();
+
+ m_basePix.resize( QSize( m_pixWidth, m_pixHeight ) );
+ m_basePix.fill(); // fills white per default TODO
+
+
+ m_iconView->setItemsMovable( false );
+
+ slSetBackGround();
+
+ connect( m_iconView, SIGNAL( executed( QIconViewItem* )),
+ this, SLOT( slDoubleClicked( QIconViewItem* )));
+
+ m_pendingJobs.setAutoDelete(false);
+}
+
+ThumbView::~ThumbView()
+{
+ saveConfig();
+}
+
+bool ThumbView::readSettings()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( THUMB_GROUP );
+ bool dirty = false;
+
+ QColor color;
+ color = cfg->readColorEntry( MARGIN_COLOR1, &(colorGroup().base()));
+ if( color != m_marginColor1 )
+ {
+ dirty = true;
+ m_marginColor1 = color;
+ }
+
+ color = cfg->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground()));
+ if( color != m_marginColor2 )
+ {
+ dirty = true;
+ m_marginColor2 = color;
+ }
+
+ int value;
+ bool sizeDirty = false;
+ value = cfg->readNumEntry( THUMB_MARGIN, 5 );
+ if( value != m_thumbMargin )
+ {
+ sizeDirty = true;
+ m_thumbMargin = value;
+ }
+
+ value = cfg->readNumEntry( PIXMAP_WIDTH, 100 );
+ if( value != m_pixWidth || m_pixWidth == 0 )
+ {
+ sizeDirty = true;
+ m_pixWidth = value;
+ }
+
+ value = cfg->readNumEntry( PIXMAP_HEIGHT, 120 );
+ if( value != m_pixHeight || m_pixHeight == 0 )
+ {
+ sizeDirty = true;
+ m_pixHeight = value;
+ }
+
+ if( sizeDirty )
+ {
+ int gX = 2*m_thumbMargin+m_pixWidth+10;
+ int gY = 2*m_thumbMargin+m_pixHeight+10;
+ m_iconView->setGridX(gX);
+ m_iconView->setGridY(gY);
+ kdDebug(28000) << "Setting Grid " << gX << " - " << gY << endl;
+ }
+
+ KStandardDirs stdDir;
+ QString newBgImg = cfg->readEntry( BG_WALLPAPER, stdDir.findResource( "data", STD_TILE_IMG ) );
+
+ if( m_bgImg != newBgImg )
+ {
+ m_bgImg = newBgImg;
+ slSetBackGround();
+ }
+
+ return (sizeDirty || dirty);
+}
+
+void ThumbView::slDoubleClicked( QIconViewItem *qIt )
+{
+ ThumbViewItem *it = static_cast<ThumbViewItem*>( qIt );
+
+ if( it )
+ {
+ const KURL url = it->itemUrl();
+
+ emit( selectFromThumbnail( url ));
+ }
+}
+
+void ThumbView::slSetBackGround( )
+{
+ QPixmap bgPix;
+ if( m_bgImg.isEmpty())
+ {
+ bgPix.resize( QSize(16, 16));
+ bgPix.fill( QPixmap::blue );
+ }
+ else
+ {
+ bgPix.load( m_bgImg );
+ }
+
+ m_iconView->setPaletteBackgroundPixmap ( bgPix );
+ setPaletteBackgroundPixmap ( bgPix );
+
+}
+
+void ThumbView::slImageChanged( KFileItem *kfit )
+{
+ if( ! kfit ) return;
+ // kdDebug(28000) << "changes to one thumbnail!" << endl;
+
+ KURL thumbDir = currentDir();
+ KURL itemUrl = kfit->url();
+
+ /* delete filename */
+ itemUrl.setFileName( QString());
+ if( !itemUrl.equals( thumbDir, true ))
+ {
+ // kdDebug(28000) << "returning, because directory does not match: " << itemUrl.prettyURL() << endl;
+ // kdDebug(28000) << "and my URL: " << thumbDir.prettyURL() << endl;
+ return;
+ }
+
+ if( deleteImage( kfit ))
+ {
+ kdDebug(28000) << "was changed, deleted first!" << endl;
+ }
+ /* Trigger a new reading */
+ KFileItemList li;
+ li.append( kfit );
+ slNewFileItems( li );
+}
+
+void ThumbView::slImageRenamed( KFileItem *kfit, const KURL& newUrl )
+{
+ const KURL url = kfit->url();
+
+ if( kfit->isDir() ) {
+ clear();
+ }
+
+ for ( QIconViewItem *item = m_iconView->firstItem(); item; item = item->nextItem() )
+ {
+ ThumbViewItem *it=static_cast<ThumbViewItem*>( item );
+
+ if( url == it->itemUrl() )
+ {
+ it->setItemUrl( newUrl );
+
+ break;
+ }
+ }
+}
+
+
+void ThumbView::slCheckForUpdate( KFileItem *kfit )
+{
+ if( ! kfit ) return;
+
+ kdDebug(28000) << "Checking for update of thumbview!" << endl;
+
+ KURL searchUrl = kfit->url();
+ bool haveItem = false;
+
+ /* iterate over all icon items and compare urls.
+ * TODO: Check the parent url to avoid iteration over all */
+ for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem;
+ item = item->nextItem() )
+ {
+ if( searchUrl == static_cast<ThumbViewItem*>(item)->itemUrl() )
+ {
+ haveItem = true;
+ }
+ }
+
+ /* if we still do not have the item, it is not in the thumbview. */
+ if( ! haveItem )
+ {
+ KFileItemList kfiList;
+
+ kfiList.append( kfit );
+ slNewFileItems( kfiList );
+ }
+
+}
+
+
+bool ThumbView::deleteImage( KFileItem *kfit )
+{
+ if( ! kfit ) return false;
+
+
+ KURL searchUrl = kfit->url();
+ bool haveItem = false;
+
+ /* iterate over all icon items and compare urls.
+ * TODO: Check the parent url to avoid iteration over all */
+ for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem; item = item->nextItem() )
+ {
+ if( searchUrl == static_cast<ThumbViewItem*>(item)->itemUrl() )
+ {
+ m_iconView->takeItem( item );
+ haveItem = true;
+ }
+ }
+ kdDebug(28000) << "Deleting image from thumbview, result is " << haveItem << endl;
+ return( haveItem );
+}
+
+void ThumbView::slImageDeleted( KFileItem *kfit )
+{
+ deleteImage( kfit );
+
+
+ /*
+ From a mail from Waldo pointing out two probs in Thumbview:
+
+ 1) KDirLister is the owner of the KFileItems it emits, this means
+ that you must watch it's deleteItem() signal vigourously,
+ otherwise you may end up with KFileItems that are already
+ deleted. This burden is propagated to classes that use
+ KDirLister, such as KFileIconView.
+
+ This has a tendency to go wrong in combination with PreviewJob,
+ because it stores a list of KFileItems while running. This has
+ the potential to crash if the fileitems are being deleted
+ during this time. The remedy is to make sure to remove
+ fileitems that get deleted from the PreviewJob with
+ PreviewJob::removeItem.
+
+ */
+ if( m_job ) /* is a job running? Remove the item from it if existing. */
+ {
+ m_job->removeItem( kfit );
+ }
+
+ /* check if it is in the pending list */
+ m_pendingJobs.removeRef(kfit);
+}
+
+
+void ThumbView::slNewFileItems( const KFileItemList& items )
+{
+ kdDebug(28000) << "Creating thumbnails for fileItemList" << endl;
+
+ /* Fill the pending jobs list. */
+ KFileItemListIterator it( items );
+ KFileItem *item = 0;
+ for ( ; (item = it.current()); ++it )
+ {
+ QString filename = item->url().prettyURL();
+ if( item->isDir() )
+ {
+ /* create a dir pixmap */
+ }
+ else
+ {
+ QPixmap p(m_basePix) ;
+ QPixmap mime( item->pixmap(0) );
+
+ if( p.width() > mime.width() && p.height() > mime.height() )
+ {
+ QPainter paint( &p );
+ paint.drawPixmap( (p.width()-mime.width())/2,
+ (p.height()-mime.height())/2,
+ mime );
+ paint.flush();
+ }
+
+ /* Create a new empty preview pixmap and store the pointer to it */
+ ThumbViewItem *newIconViewIt = new ThumbViewItem( m_iconView,
+ item->url().filename(),
+ createPixmap( p ),
+ item );
+
+ newIconViewIt->setItemUrl( item->url() );
+
+ /* tell the file item about the iconView-representation */
+ item->setExtraData( this, newIconViewIt );
+
+ m_pendingJobs.append( item );
+ }
+ }
+
+ /*
+ From a mail from Waldo Bastian pointing out problems with thumbview:
+
+ 2) I think you may end up creating two PreviewJob's in parallel
+ when the slNewFileItems() function is called two times in
+ quick succession. The current code doesn't seem to expect
+ that, given the comment in slPreviewResult(). In the light of
+ 1) it might become fatal since you will not be able to call
+ PreviewJob::removeItem on the proper job. I suggest to queue
+ new items when a job is already running and start a new job
+ once the first one is finished when there are any items left
+ in the queue. Don't forget to delete items from the queue if
+ they get deleted in the mean time.
+
+ The strategy is as follows: In the global list m_pendingJobs
+ the jobs to start are appended. Only if m_job is zero (no job
+ is running) a job is started on the current m_pendingJobs list.
+ The m_pendingJobs list is clear afterwords.
+ */
+
+ if( ! m_job && m_pendingJobs.count() > 0 )
+ {
+ /* Progress-Bar */
+ m_progress->show();
+ m_progress->setTotalSteps(m_pendingJobs.count());
+ m_cntJobsStarted = 0;
+
+ /* start a preview-job */
+ m_job = KIO::filePreview(m_pendingJobs, m_pixWidth, m_pixHeight );
+
+ if( m_job )
+ {
+ connect( m_job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slPreviewResult( KIO::Job * )));
+ connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
+ SLOT( slGotPreview( const KFileItem*, const QPixmap& ) ));
+
+ m_pendingJobs.clear();
+
+ /* KIO::Jo result is called in any way: Success, Failed, Error,
+ * thus connecting the failed is not really necessary.
+ */
+ // connect( job, SIGNAL( failed( const KFileItem* )),
+ // this, SLOT( slotFailed( const KFileItem* ) ));
+
+ }
+ }
+}
+
+
+
+void ThumbView::slGotPreview( const KFileItem* newFileItem, const QPixmap& newPix )
+{
+ if( ! newFileItem ) return;
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>(const_cast<void*>(newFileItem->extraData( this )));
+
+ if( ! item ) return;
+
+ item->setPixmap( createPixmap(newPix) );
+ m_cntJobsStarted+=1;
+
+ m_progress->setProgress(m_cntJobsStarted);
+
+ // kdDebug(28000)<< "jobs-Counter: " << m_cntJobsStarted << endl;
+
+}
+
+void ThumbView::slPreviewResult( KIO::Job *job )
+{
+ if( job && job->error() > 0 )
+ {
+ kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl;
+ job->showErrorDialog( 0 );
+ }
+
+ if( job != m_job )
+ {
+ kdDebug(28000) << "Very obscure: Job finished is not mine!" << endl;
+ }
+ /* finished */
+ kdDebug(28000) << "Thumbnail job finished." << endl;
+ m_cntJobsStarted = 0;
+ m_progress->reset();
+ m_progress->hide();
+ m_job = 0L;
+
+ /* maybe there is a new job to start because of pending items? */
+ if( m_pendingJobs.count() > 0 )
+ {
+ slNewFileItems( KFileItemList() ); /* Call with an empty list */
+ }
+}
+
+
+QPixmap ThumbView::createPixmap( const QPixmap& preview ) const
+{
+ QImage ires = KImageEffect::unbalancedGradient( QSize( 2*m_thumbMargin+ preview.width(),
+ 2*m_thumbMargin+ preview.height()),
+ m_marginColor1, m_marginColor2,
+ KImageEffect::DiagonalGradient );
+
+
+ QPixmap pixRet;
+ pixRet.convertFromImage( ires );
+ QPainter p( &pixRet );
+
+ p.drawPixmap( m_thumbMargin, m_thumbMargin, preview );
+ p.flush();
+ // draw on pixmap
+
+ return( pixRet );
+}
+
+
+void ThumbView::clear()
+{
+ if( m_job )
+ m_job->kill( false /* not silently to get result-signal */ );
+ m_iconView->clear();
+}
+
+
+void ThumbView::saveConfig()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( THUMB_GROUP );
+
+ cfg->writeEntry( MARGIN_COLOR1, m_marginColor1 );
+ cfg->writeEntry( MARGIN_COLOR2, m_marginColor2 );
+ cfg->writeEntry( PIXMAP_WIDTH, m_pixWidth );
+ cfg->writeEntry( PIXMAP_HEIGHT, m_pixHeight );
+ cfg->writeEntry( THUMB_MARGIN, m_thumbMargin );
+
+
+}
diff --git a/kooka/thumbview.h b/kooka/thumbview.h
new file mode 100644
index 00000000..c16afa84
--- /dev/null
+++ b/kooka/thumbview.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+ thumbview.h - Class to display thumbnailed images
+ -------------------
+ begin : Tue Apr 18 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __THUMBVIEW_H__
+#define __THUMBVIEW_H__
+
+#include <qwidget.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qcolor.h>
+#include <qvbox.h>
+
+#include <kiconview.h>
+#include <kurl.h>
+#include <kio/previewjob.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+/* KConfig group definitions */
+#define MARGIN_COLOR1 "MarginColor1"
+#define MARGIN_COLOR2 "MarginColor2"
+#define PIXMAP_WIDTH "pixmapWidth"
+#define PIXMAP_HEIGHT "pixmapHeight"
+#define THUMB_MARGIN "thumbnailMargin"
+#define THUMB_GROUP "thumbnailView"
+#define BG_WALLPAPER "BackGroundTile"
+#define STD_TILE_IMG "kooka/pics/thumbviewtile.png"
+
+class QPixmap;
+class QListViewItem;
+class KProgress;
+class KIO::PreviewJob;
+
+class ThumbView: public QVBox /* KIconView */
+{
+ Q_OBJECT
+
+public:
+
+ ThumbView( QWidget *parent, const char *name=0 );
+ ~ThumbView();
+
+ void setCurrentDir( const KURL& s)
+ { m_currentDir = s; }
+ KURL currentDir( ) const
+ { return m_currentDir; }
+
+ QSize tumbSize( ) const
+ {
+ return( QSize( m_pixWidth, m_pixHeight ));
+ }
+
+ int thumbMargin() const
+ {
+ return m_thumbMargin;
+ }
+public slots:
+ void slSetThumbSize( int w, int h )
+ {
+ m_pixWidth = w;
+ m_pixHeight = h;
+ }
+ void slSetThumbSize( const QSize& s )
+ {
+ m_pixWidth = s.width();
+ m_pixHeight = s.height();
+ }
+
+ void slSetThumbMargin( int m )
+ {
+ m_thumbMargin = m;
+ }
+
+ void slNewFileItems( const KFileItemList& );
+ void slGotPreview( const KFileItem*, const QPixmap& );
+ void slPreviewResult( KIO::Job* );
+
+ /**
+ * This connects to the IconView's executed signal and tells the packager
+ * to select the image
+ */
+ void slDoubleClicked( QIconViewItem* );
+
+ /**
+ * indication that a image changed, needs to be reloaded.
+ */
+ void slImageChanged( KFileItem * );
+ void slImageDeleted( KFileItem * );
+ void slSetBackGround( );
+ void slCheckForUpdate( KFileItem* );
+ bool readSettings();
+ void clear();
+
+ void slImageRenamed( KFileItem*, const KURL& );
+
+protected:
+
+ void saveConfig();
+
+signals:
+ /**
+ * selects a QListViewItem from the thumbnail. This signal only makes
+ * sense if connected to a ScanPackager.
+ */
+ void selectFromThumbnail( const KURL& );
+
+private:
+ QPixmap createPixmap( const QPixmap& ) const;
+
+ bool deleteImage( KFileItem* );
+ KIconView *m_iconView;
+ KProgress *m_progress;
+
+ KURL m_currentDir;
+ QPixmap m_basePix;
+ int m_pixWidth;
+ int m_pixHeight;
+ int m_thumbMargin;
+ QColor m_marginColor1;
+ QColor m_marginColor2;
+ QString m_bgImg;
+ int m_cntJobsStarted;
+ KIO::PreviewJob *m_job;
+
+ KFileItemList m_pendingJobs;
+};
+
+#endif
diff --git a/kooka/thumbviewitem.cpp b/kooka/thumbviewitem.cpp
new file mode 100644
index 00000000..7f2d01f6
--- /dev/null
+++ b/kooka/thumbviewitem.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ thumbviewitem.cpp - Thumbview item class
+ -------------------
+ begin : Tue Apr 24 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+#include "thumbview.h"
+#include "thumbviewitem.h"
+
+ThumbViewItem::ThumbViewItem(QIconView *parent, const QString &text,
+ const QPixmap &pixmap,
+ KFileItem *fi )
+ :KFileIconViewItem( parent, text, pixmap,fi )
+{
+
+}
+
+void ThumbViewItem:: setItemUrl( const KURL& u )
+{
+ m_url = u;
+ setText( m_url.fileName());
+}
+
+
diff --git a/kooka/thumbviewitem.h b/kooka/thumbviewitem.h
new file mode 100644
index 00000000..745c2b25
--- /dev/null
+++ b/kooka/thumbviewitem.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ thumbviewitem.h - Thumbnailview items
+ -------------------
+ begin : Tue Apr 24 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __THUMBVIEWITEM_H__
+#define __THUMBVIEWITEM_H__
+
+#include <kiconview.h>
+#include <kurl.h>
+#include <kio/previewjob.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+class KFileTreeViewItem;
+
+
+class ThumbViewItem: public KFileIconViewItem
+{
+public:
+ ThumbViewItem( QIconView *parent,
+ const QString &text,
+ const QPixmap &pixmap,
+ KFileItem *fi );
+
+ void setItemUrl( const KURL& u );
+
+ KURL itemUrl() const
+ { return m_url; }
+
+private:
+ KURL m_url;
+
+
+};
+
+#endif
diff --git a/kooka/version.h b/kooka/version.h
new file mode 100644
index 00000000..2d9da5f7
--- /dev/null
+++ b/kooka/version.h
@@ -0,0 +1,4 @@
+#ifndef KOOKA_VERSION
+#define KOOKA_VERSION "0.44"
+#endif
+