Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0ec035c02 | |||
| dd04b72a67 | |||
| 9d0ee5010b |
@@ -0,0 +1,43 @@
|
||||
[Buildset]
|
||||
Number of Builditems=1
|
||||
|
||||
[Buildset][Builditem0]
|
||||
Itemname=KMess
|
||||
Itempath=./
|
||||
Projectname=KMess
|
||||
|
||||
[CMake]
|
||||
BuildDirs=./build
|
||||
CMakeDir=/usr/share/cmake/Modules
|
||||
Current CMake binary=cmake
|
||||
CurrentBuildDir=./build
|
||||
CurrentInstallDir=
|
||||
ProjectRootRelative=./
|
||||
|
||||
[Chat Window debug-Run Options]
|
||||
Arguments=--runtest chatwindow
|
||||
Executable=./build/src/kmess
|
||||
Working Directory=./build/src/
|
||||
|
||||
[Contact List debug-Run Options]
|
||||
Arguments=--runtest contactlist
|
||||
Executable=./build/src/kmess
|
||||
Working Directory=./build/src/
|
||||
|
||||
[Debug-Run Options]
|
||||
Executable=./build/src/kmess
|
||||
|
||||
[MakeBuilder]
|
||||
Abort on First Error=false
|
||||
Number Of Jobs=3
|
||||
Run Multiple Jobs=true
|
||||
|
||||
[Project]
|
||||
VersionControlSupport=kdevsubversion
|
||||
|
||||
[Run Options]
|
||||
Run Targets=Chat Window debug,Contact List debug,Debug
|
||||
|
||||
[Veritas]
|
||||
executables=
|
||||
framework=QTest
|
||||
@@ -63,6 +63,9 @@
|
||||
Estonian:
|
||||
|
||||
Jyri Toomessoo <nuubik@hotmail.com>
|
||||
Lauri Võsandi <v6sa@hotmail.com>
|
||||
Mihkel Tõnnov <mihhkel@gmail.com>
|
||||
Rivo Laks <rivolaks@hot.ee>
|
||||
|
||||
Finnish:
|
||||
|
||||
@@ -70,6 +73,7 @@
|
||||
Joonas Niilola <juippis@roskakori.org>
|
||||
Jussi Timperi <jussi.timperi@gmail.com>
|
||||
Antony Hussi <antony.hussi@tranciend.com>
|
||||
Marko Mäkilä <maruchan86@gmail.com>
|
||||
|
||||
French:
|
||||
|
||||
@@ -88,6 +92,7 @@
|
||||
|
||||
Panagiotis Papadopoulos <pano_90@gmx.net>
|
||||
Dimitrios Glentadakis <dglent@gmail.com>
|
||||
George Kiagiadakis <kiagiadakis.george@gmail.com>
|
||||
|
||||
Hungarian:
|
||||
|
||||
@@ -101,6 +106,10 @@
|
||||
Vincenzo Reale <smart2128@baslug.org>
|
||||
Andrea Decorte <adecorte@gmail.com>
|
||||
|
||||
Japanese:
|
||||
|
||||
Daniel E. Moctezuma <shinsen27@gmail.com>
|
||||
|
||||
Korean:
|
||||
|
||||
Park Dong Cheon <pdc@kaist.ac.kr>
|
||||
@@ -119,7 +128,7 @@
|
||||
|
||||
Slovenian:
|
||||
|
||||
Matjaž kaše <kase@g-kabel.si>
|
||||
Matjaž Kaše <kase@g-kabel.si>
|
||||
|
||||
Spanish:
|
||||
|
||||
@@ -131,6 +140,7 @@
|
||||
Juan Pablo González Tognarelli <jotapesan@gmail.com>
|
||||
Alexis Daniel Medina Medina <alexismedina@gmail.com>
|
||||
Manuel Ramírez <elpreto@kde.org.ar>
|
||||
Mauricio Muñoz Lucero <real.mml@gmail.com>
|
||||
|
||||
Swedish:
|
||||
|
||||
@@ -205,6 +215,20 @@
|
||||
Dario Freddi <drf_av@users.sourceforge.net>
|
||||
- Chat history dialog
|
||||
|
||||
Camille Begue <prsieux@gmail.com>
|
||||
- Chat History functionality when disconnected from MSN
|
||||
- Automatic login checkbox on initialview
|
||||
|
||||
David López <grannost@gmail.com>
|
||||
- Nudge button in chat
|
||||
|
||||
Pieterjan Camerlynck <pieterjan.camerlynck@gmail.com>
|
||||
- Roaming Service support
|
||||
|
||||
Anastasios Bourazanis <a.brzns@gmail.com>
|
||||
- Emoticon preview in settings page
|
||||
- Clickable contact properties dialog text
|
||||
|
||||
KMerlin <http://kmerlin.olsd.de/>
|
||||
- Inspiration and assorted code
|
||||
|
||||
@@ -221,6 +245,7 @@
|
||||
|
||||
Amarok
|
||||
- Custom crash handler implementation
|
||||
- System tray icon overlay implementation
|
||||
|
||||
Quassel
|
||||
- KNotify not giving focus bug fix and KWin focus stealing prevention workaround
|
||||
|
||||
@@ -22,7 +22,7 @@ MACRO_LOG_FEATURE( LIBXML2_FOUND "LibXML2" "Libraries used to develop XML-aware
|
||||
* Usually the package names for this library are:
|
||||
on Ubuntu: 'libxml2' and 'libxml2-dev'
|
||||
on openSUSE: 'libxml2' and 'libxml2-devel'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
|
||||
# Check for libxslt
|
||||
FIND_PACKAGE( LibXslt )
|
||||
@@ -32,7 +32,7 @@ MACRO_LOG_FEATURE( LIBXSLT_FOUND "LibXSLT" "A library to transform XML into othe
|
||||
* Usually the package names for this library are:
|
||||
on Ubuntu: 'libxslt' and 'libxslt-dev'
|
||||
on openSUSE: 'libxslt' and 'libxslt-devel'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
|
||||
# Check for qca2
|
||||
FIND_PACKAGE( QCA2 )
|
||||
@@ -43,7 +43,7 @@ MACRO_LOG_FEATURE( QCA2_FOUND "QCA 2" "A cryptographic library written in Qt to
|
||||
on Ubuntu: 'libqca2', 'libqca2-dev' and 'libqca2-plugin-ossl'
|
||||
on openSUSE: 'libqca2' and 'libqca2-devel'
|
||||
on Fedora: 'qca2' and 'qca2-devel'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
|
||||
# As far as I know, it is impossible to find out if the required QCA plugin for OpenSSL is installed:
|
||||
# so we need to ask QCA itself it it's got such a plugin. Pretty darned unportable stuff.
|
||||
@@ -60,7 +60,7 @@ IF( QCA2_FOUND )
|
||||
* This package should have been installed along QCA2: if you have QCA2 installed
|
||||
but still see this message, your distribution probably packages it separately.
|
||||
Ubuntu does this, the package name is 'libqca2-plugin-ossl'.
|
||||
* Please refer to the KMess forum for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess forum for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
ELSE( UNIX )
|
||||
# TODO: Find another *portable* way to detect the OSSL plugin.
|
||||
MESSAGE( STATUS "NOTE: The qca2 OpenSSL can't be detected on this platform yet. Make sure you have it installed." )
|
||||
@@ -78,7 +78,7 @@ IF( WANT_XSCREENSAVER )
|
||||
* Usually the package names for this library are:
|
||||
on Ubuntu: 'libxss-dev'
|
||||
on openSUSE: 'xorg-x11-libs'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
ELSE( X11_FOUND )
|
||||
MESSAGE( STATUS "NOTE: The auto-away feature is not supported on this platform yet." )
|
||||
ENDIF( X11_FOUND )
|
||||
@@ -94,20 +94,15 @@ MACRO_LOG_FEATURE( LIBKONQ_FOUND "LibKonq" "Integration with Konqueror context m
|
||||
* Usually the package names for this library are:
|
||||
on Ubuntu: 'libkonq5' and 'libkonq5-dev'
|
||||
on openSUSE: 'libkonq5' and 'libkonq-devel'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
|
||||
|
||||
# Check for libgif
|
||||
INCLUDE( "cmake/giflib_hack.cmake" )
|
||||
MACRO_OPTIONAL_FIND_PACKAGE( GIF )
|
||||
MACRO_BOOL_TO_01( GIF_FOUND HAVE_LIBGIF )
|
||||
MACRO_LOG_FEATURE( GIF_FOUND "GIF" "Handwriting messages support" "http://sourceforge.net/projects/giflib/" FALSE ""
|
||||
" Optional support to send handwriting messages compatible with Windows Live Messenger.
|
||||
* You will need to install both the library and development packages of the GIF Library, giflib.
|
||||
* Usually the package names for this library are:
|
||||
on Ubuntu: 'libgif4' and 'libgif-dev'
|
||||
on openSUSE: 'giflib' and 'giflib-devel'
|
||||
* Please refer to the KMess board for more info, and specially to this guide: http://www.kmess.org/board/viewtopic.php?t=3100" )
|
||||
|
||||
# Check for libisf-qt
|
||||
MACRO_OPTIONAL_FIND_PACKAGE( IsfQt QUIET )
|
||||
MACRO_LOG_FEATURE( ISFQT_FOUND "LibISF-Qt" "Library to manage Microsoft's Mobile Ink" "http://www.kmess.org/" FALSE ""
|
||||
" Support to send handwriting messages in a format compatible with Windows Live Messenger.
|
||||
In absence of an installed isf-qt version, the bundled version will be compiled.")
|
||||
MACRO_BOOL_TO_01( ISFQT_FOUND HAVE_LIBISFQT ) # For config-kmess.h.in
|
||||
|
||||
# Display the dependency collection results
|
||||
MACRO_DISPLAY_FEATURE_LOG()
|
||||
@@ -119,6 +114,17 @@ MACRO_DISPLAY_FEATURE_LOG()
|
||||
INCLUDE( MacroLibrary )
|
||||
INCLUDE( KDE4Defaults )
|
||||
|
||||
IF( NOT ISFQT_FOUND )
|
||||
# isf-qt is not installed on the system.
|
||||
# use the bundled version.
|
||||
SET( ISFQT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/isf-qt/include )
|
||||
SET( ISFQT_LIBRARIES isf-qt )
|
||||
|
||||
SET( USE_BUNDLED_LIBRARIES ${USE_BUNDLED_LIBRARIES} ISFQT )
|
||||
SET( HAVE_LIBISFQT 1 )
|
||||
SET( ISFQT_FOUND TRUE )
|
||||
ENDIF( NOT ISFQT_FOUND )
|
||||
|
||||
ADD_DEFINITIONS( ${QT_DEFINITIONS} ${KDE4_DEFINITIONS} )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${KDE4_INCLUDES} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${LIBXML2_INCLUDE_DIR} )
|
||||
@@ -127,8 +133,8 @@ INCLUDE_DIRECTORIES( ${KDE4_INCLUDES} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${LIBXM
|
||||
#### Define the app version number ####
|
||||
|
||||
# Switch between the following two commands to force using a predefined version number
|
||||
#EXECUTE_PROCESS( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/get-svn-version.sh OUTPUT_VARIABLE KMESS_VERSION )
|
||||
SET( KMESS_VERSION "2.0beta2" )
|
||||
# EXECUTE_PROCESS( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/get-svn-version.sh OUTPUT_VARIABLE KMESS_VERSION )
|
||||
SET( KMESS_VERSION "2.0.1" )
|
||||
|
||||
|
||||
#### Define compiler flags ####
|
||||
@@ -156,7 +162,7 @@ ENDIF( CMAKE_COMPILER_IS_GNUCXX )
|
||||
# - relwithdebinfo (release with debug info)
|
||||
# - minsizerel (minsize release)
|
||||
# Uncomment the next line to always force building in full debug mode
|
||||
SET( CMAKE_BUILD_TYPE debugfull )
|
||||
# SET( CMAKE_BUILD_TYPE debugfull )
|
||||
|
||||
# Enable the KMess debug output when compiling a debug build
|
||||
IF( CMAKE_BUILD_TYPE STREQUAL debugfull OR KMESS_DEBUG_OUTPUT EQUAL 1 )
|
||||
@@ -169,13 +175,6 @@ ENDIF( CMAKE_BUILD_TYPE STREQUAL debugfull OR KMESS_DEBUG_OUTPUT EQUAL 1 )
|
||||
# Change symbol visibility, to obtain clearer KDE backtraces
|
||||
SET( __KDE_HAVE_GCC_VISIBILITY 0 )
|
||||
|
||||
# Set a default value for relocatable binary support
|
||||
IF( KMESS_ENABLE_BINRELOC EQUAL 1 )
|
||||
SET( KMESS_ENABLE_BINRELOC "1" )
|
||||
ELSE( KMESS_ENABLE_BINRELOC EQUAL 1 )
|
||||
SET( KMESS_ENABLE_BINRELOC "0" )
|
||||
ENDIF( KMESS_ENABLE_BINRELOC EQUAL 1 )
|
||||
|
||||
# Disable LikeBack if not needed
|
||||
IF( KMESS_DISABLE_LIKEBACK EQUAL 1 )
|
||||
SET( KMESS_DISABLE_LIKEBACK "1" )
|
||||
@@ -183,13 +182,6 @@ ELSE( KMESS_DISABLE_LIKEBACK EQUAL 1 )
|
||||
SET( KMESS_DISABLE_LIKEBACK "0" )
|
||||
ENDIF( KMESS_DISABLE_LIKEBACK EQUAL 1 )
|
||||
|
||||
|
||||
# Enable the experimental webcam connection if needed
|
||||
IF( NOT DEFINED KMESS_ENABLE_WEBCAM )
|
||||
SET( KMESS_ENABLE_WEBCAM "0" )
|
||||
ENDIF( NOT DEFINED KMESS_ENABLE_WEBCAM )
|
||||
|
||||
|
||||
# Set a default installation path
|
||||
IF( NOT CMAKE_INSTALL_PREFIX )
|
||||
SET( CMAKE_INSTALL_PREFIX "/usr" )
|
||||
@@ -239,10 +231,19 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/config-kmess.h.in ${CMAKE_CURR
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
# continue in directories
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( po )
|
||||
ADD_SUBDIRECTORY( data )
|
||||
ADD_SUBDIRECTORY( doc )
|
||||
ADD_SUBDIRECTORY( src )
|
||||
|
||||
IF( LIBKONQ_FOUND )
|
||||
ADD_SUBDIRECTORY( src/utils/kmess-send )
|
||||
ENDIF( LIBKONQ_FOUND )
|
||||
|
||||
IF( USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
|
||||
ADD_SUBDIRECTORY( contrib/isf-qt )
|
||||
ENDIF( )
|
||||
|
||||
|
||||
# Also add the tests if compiling in development mode
|
||||
IF( CMAKE_BUILD_TYPE STREQUAL debugfull AND KMESS_DEBUG_OUTPUT EQUAL 1 )
|
||||
|
||||
@@ -1,4 +1,649 @@
|
||||
|
||||
--- 2.0.1 released ---
|
||||
|
||||
2009-11-30 (Sjors)
|
||||
* Fixed a bug introduced by the last commit, causing KMess to initially log in
|
||||
with the handle as friendlyname instead of the correct friendlyname at first
|
||||
login to a new account.
|
||||
|
||||
2009-11-29 (Pano)
|
||||
* Merged an updated German translation.
|
||||
* Merged an updated Estonian translation by Lauri Võsandi, Mihkel Tõnnov and Rivo Laks
|
||||
|
||||
2009-11-29 (Valerio)
|
||||
* Fixed missed publishing of the user's friendly name on login.
|
||||
* Fixed notifying the NS server of a friendly name change when a new name is received
|
||||
via Storage Service.
|
||||
|
||||
2009-11-27 (Valerio)
|
||||
* Fixed encoding misinterpretation occurring when retrieving friendly name and personal
|
||||
message from the Storage server.
|
||||
|
||||
2009-11-24 (Valerio)
|
||||
* Fixed friendly name resets upon login.
|
||||
|
||||
2009-11-18 (Pano)
|
||||
* Merged an updated Simplified Chinese translation by Cheng Yang.
|
||||
|
||||
2009-11-16 (Pano)
|
||||
* Merged an updated Spanish translation by Guillermo Arana.
|
||||
|
||||
2009-11-14 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
|
||||
2009-11-12 (Pano)
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-11-12 (Adam)
|
||||
* Rewrite the CMakeLists.txt entry regarding ISF-qt: remove mention of libgif as
|
||||
it serves to be confusing (it suggests that libgif isn't installed when it might be).
|
||||
The ISF-qt CMakeLists will produce a warning if libgif isn't installed.
|
||||
|
||||
2009-11-11 (Pano)
|
||||
* Merged an updated Hungarian translation by Pauli Henrik.
|
||||
|
||||
2009-11-10 (Adam)
|
||||
* Merge a patch by jmsantamaria which corrects KMess linking on binutils-gold.
|
||||
|
||||
2009-11-08 (Ruben)
|
||||
* Fixed Likeback icons install condition.
|
||||
|
||||
2009-11-07 (Pano)
|
||||
* Merged an updated Finnish translation by Marko Mäkilä.
|
||||
* Merged an updated Spanish translation by Guillermo Arana.
|
||||
|
||||
2009-11-05 (Pano)
|
||||
* Merged an updated Dutch translation by Sjors Gielen.
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
|
||||
2009-11-04 (Valerio)
|
||||
* Updated the Italian translation.
|
||||
|
||||
2009-11-03 (Pano)
|
||||
* Merged an updated Brazilian Portuguese translation by Maurício Arozi Moraes.
|
||||
|
||||
2009-11-02 (Pano)
|
||||
* Merged an updated Catalan translation by Adrià Arrufat.
|
||||
* Merged an updated Greek translation by George Kiagiadakis.
|
||||
* Merged an updated Turkish translation by Uğur Çetin.
|
||||
|
||||
2009-11-02 (Adam)
|
||||
* Ensure the height of items in the contact list is sufficient to fully
|
||||
display the contact name and PSM (strings got cut off when people used large
|
||||
KDE font sizes).
|
||||
* Increase the notification unlock timeout to 10 seconds after the last ILN.
|
||||
* Allow the download/upload buttons in the transfer window to expand to show their
|
||||
text. Necessary for translations.
|
||||
* Fix the icon name for "Rename group".
|
||||
|
||||
2009-11-01 (Pano)
|
||||
* Merged an updated Dutch translation by Sjors Gielen.
|
||||
* Merged an updated Spanish translation by Guillermo Arana.
|
||||
* Merged an updated German translation.
|
||||
* Merged an updated Catalan translation by Adrià Arrufat.
|
||||
|
||||
2009-10-31 (Sjors)
|
||||
* Removed eight languages for being utterly incomplete: da, et,
|
||||
ko, nb, sl, sr@latin, sv, th.
|
||||
|
||||
2009-10-30 (Pano)
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-10-28 (Adam)
|
||||
* Correctly display contact handle and dates in text chat logs.
|
||||
* Merge patch by mikkoc to solve DBus query problems on Qt 4.6.
|
||||
|
||||
2009-10-27 (Adam)
|
||||
* One final fix to KDE bug #209960 - missed the chat window.
|
||||
|
||||
2009-10-23 (Sjors)
|
||||
* Fixed .ui file warnings.
|
||||
|
||||
2009-10-23 (Valerio)
|
||||
* Removed duplicated separator line between Chat Window buttons.
|
||||
|
||||
2009-10-23 (Adam)
|
||||
* Store display name on roaming service but do not use it for display (in line with WLM).
|
||||
* Remove duplicate "Show Statusbar" from the list of shortcuts.
|
||||
* Fix updating of display picture with the roaming service.
|
||||
* Change keystrokes for scrolling in chat message view - pgdn/pgup = scroll, alt+pgdn/pgup = fast scroll.
|
||||
Fixes a clash with the text editor which caused the view to scroll when shift+pg selecting text in the editor.
|
||||
|
||||
2009-10-22 (Adam)
|
||||
* Fix build error introduced in r5567. My bad.
|
||||
* Fix a crash bug that was introduced with a previous fix. Previous fix has been reverted pending better solution.
|
||||
* Improve fix for KDE bug #209960.
|
||||
* Stop writing bad "last seen date" and "last message date" values when saving contact list.
|
||||
|
||||
2009-10-21 (Adam)
|
||||
* Cache last display names of contacts; works around an issue where the AddressBook service
|
||||
gives us out of date data.
|
||||
* Fix a bug introduced by r5532.
|
||||
|
||||
2009-10-21 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
|
||||
2009-10-19 (Sjors)
|
||||
* Fixed a 500 kb memory leak that appeared when a login failed.
|
||||
|
||||
2009-10-18 (Pano)
|
||||
* Merged an updated Traditional Chinese translation by Yen-chou Chen.
|
||||
|
||||
2009-10-18 (Adam)
|
||||
* Fix a crash in the roaming service that happened when retrieving a display picture from the server.
|
||||
* Fix bug where auto-login used the wrong password if the user had previously quit kmess whilst having a different
|
||||
account selected in the combo box.
|
||||
|
||||
2009-10-16 (Sjors)
|
||||
* Fixed a performance bug.
|
||||
* Fixed a very annoying crash I've been having for a while. I'm not really
|
||||
happy with the fix, left a comment in the code why.
|
||||
* Removed the nudge button from the small buttons below the chat window,
|
||||
because it is a usability issue that it does something way else than all the
|
||||
other buttons. If we want to re-add it, we need to discuss a better place
|
||||
etc.
|
||||
* Fixed escaping in the RoamingService *again*...
|
||||
|
||||
2009-10-13 (Adam)
|
||||
* Work around KDE bug #209960 that appeared in 4.3.2; caused a crash when closing account settings.
|
||||
|
||||
2009-10-12 (Adam)
|
||||
* Bring 2.0.x in line with trunk when building ISF-qt.
|
||||
|
||||
2009-10-09 (Valerio)
|
||||
* Fixed crash with HTTP connections.
|
||||
|
||||
2009-10-03 (Valerio)
|
||||
* Merged patch by Pieterjan Camerlynck, to add display picture support for the Roaming
|
||||
Service.
|
||||
|
||||
2009-10-03 (Adam)
|
||||
* Fix contact online spam again. Disable notifications when re-connecting to the NS.
|
||||
|
||||
2009-09-30 (Valerio)
|
||||
* Merged patch by Anastasios Bourazanis, to render clickable the text in the Contact
|
||||
Properties dialog.
|
||||
|
||||
2009-09-30 (dazjorz)
|
||||
* Fixed RoamingService class: coding style, disconnections because data
|
||||
wasn't escaped correctly, etc.
|
||||
|
||||
2009-09-30 (Adam)
|
||||
* Commit patch by Anastasios Bourazanis; preview of emoticons in emoticon settings page.
|
||||
* Double-click emoticon to edit instead of single click.
|
||||
* In AddEmoticonDialog, instruct QMovie to cache all frames. Prevents infinite loops if the
|
||||
emoticon file is deleted.
|
||||
* Fix the dreaded "contact online spam" - use a sliding timeout that is reset each time
|
||||
an ILN is received on login.
|
||||
|
||||
2009-09-29 (Valerio)
|
||||
* Fixed the Online notifications. The original issue kindly brought to you by Microsoft®.
|
||||
|
||||
2009-09-14 (Adam)
|
||||
* Fix a crash that occurred when attempting to cancel a drag and drop operation
|
||||
started from the chat window.
|
||||
|
||||
2009-09-12 (Valerio)
|
||||
* Backport from trunk. Connect immediately when performing an auto-login.
|
||||
* Backport from trunk. Added ability to drag-and-drop an image from KSnapshot to
|
||||
a chat, to send it.
|
||||
* Backport from trunk. Made the Transfer Window to pop up in background instead of
|
||||
appearing minimized.
|
||||
|
||||
2009-09-11 (Valerio)
|
||||
* Fixed minimum size of the message editor. Now it can be reduced to one line only.
|
||||
* Made the minimum size of the message editor depending on the current font size.
|
||||
* Simplified a bit the code in the winks widget.
|
||||
* Backport from trunk. Fix cmake check to get KMess version.
|
||||
* Backport from trunk. Fix configure script for MacOS 10.4.
|
||||
* Backport from trunk. Fixed receiving Ink via P2P.
|
||||
* Backport from trunk. Added chat window buttons to quickly change message font and color.
|
||||
* Backport from trunk. Added chat window button to send nudges.
|
||||
* Backport from trunk. Added Roaming Service support,
|
||||
to retrieve friendly name, personal message and display picture from the Live servers.
|
||||
|
||||
2009-09-10 (Adam)
|
||||
* Properly init ISF-qt resources.
|
||||
|
||||
2009-09-10 (Valerio)
|
||||
* Backport from trunk. Added full Ink support, thanks to ISF-Qt.
|
||||
Removed giflib dependency, as it is now managed by ISF-Qt.
|
||||
* Fixed Handwriting button disabling, there was a workaround not needed anymore
|
||||
now that we have isf support.
|
||||
|
||||
2009-09-09 (Valerio)
|
||||
* Added external reference to isf-qt from trunk.
|
||||
|
||||
2009-09-06 (Pano)
|
||||
* Merged an updated French translation by Émeric Dupont (backport from trunk)
|
||||
* Merged an updated Turkish translation by Uğur Çetin (backport from trunk)
|
||||
|
||||
2009-09-02 (Adam)
|
||||
* Backport from trunk. Fix improper scaling of DP in chat window and contact list.
|
||||
|
||||
2009-09-01 (Valerio)
|
||||
* Backport from trunk. Fixed maximum emoticon shortcut length.
|
||||
* Backport from trunk. Do not show the 'close all tabs?' dialog when the KDE
|
||||
session is closing.
|
||||
|
||||
2009-08-17 (Valerio)
|
||||
* Merged an improved patch by Camille Begue, to add a "Log in automatically"
|
||||
check box to the Initial View. Thanks!
|
||||
|
||||
2009-08-16 (Valerio)
|
||||
* Merged an improved patch by Camille Begue, to allow the Chat History
|
||||
dialog to be opened when not connected.
|
||||
|
||||
2009-08-14 (Valerio)
|
||||
* Fixed crash in NetworkWindow when receiving P2P messages shorter than the usual.
|
||||
* Backported Test Server support from trunk.
|
||||
* Backported fix of an overzealousness of the IRC-like commands parser.
|
||||
* Backported removal of in-place editing of emoticons, now it's only done by AddEmoticonDialog.
|
||||
* Backported addition of checking shortcuts of added/edited emoticons for invalid characters.
|
||||
* Fixed some untranslated strings.
|
||||
|
||||
2009-08-10 (Adam)
|
||||
* Fix bug where the smileys in the contact list and friendly name label
|
||||
were not redrawn when the emoticon theme was changed: this fix is not
|
||||
pretty and a much nicer one will be applied for 2.1.
|
||||
|
||||
2009-08-01 (Adam)
|
||||
* Fix bug where the display picture cache was not cleared when the picture
|
||||
changed.
|
||||
* Cache the scaled display picture when painting the contact list. Mitigates
|
||||
the performance hit incurred by using Qt::SmoothTransformation.
|
||||
|
||||
2009-08-01 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
|
||||
2009-07-27 (Adam)
|
||||
* Use smooth pixmap scaling for display pictures in contact list.
|
||||
Check for any serious performance hits.
|
||||
|
||||
2009-07-26 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
|
||||
--- 2.0 released ---
|
||||
|
||||
2009-07-24 (dazjorz)
|
||||
* Fixed bug in cmake/get-svn-version.sh on platforms where builtin echo
|
||||
doesn't understand -n.
|
||||
* Fixed contact list sorting etc issue ONCE AND FOR ALL.
|
||||
|
||||
2009-07-24 (Pano)
|
||||
* Merged an updated German translation.
|
||||
* Merged an updated Simplified Chinese translation by Cheng Yang.
|
||||
|
||||
2009-07-23 (Valerio)
|
||||
* Added a class giving meaningful error messages for unsupported applications.
|
||||
|
||||
2009-07-21 (Pano)
|
||||
* Merged an updated Arabic translation by Ma'moun Diraneyya.
|
||||
|
||||
2009-07-20 (Adam)
|
||||
* Fix KMess crashing when transferring display pictures: note this is a
|
||||
band aid fix and will need to be properly investigated for later releases.
|
||||
|
||||
2009-07-20 (Pano)
|
||||
* Merged an updated Simplified Chinese translation by Cheng Yang.
|
||||
|
||||
2009-07-18 (Valerio)
|
||||
* Further improved the fix for contact list tooltips with RTL languages.
|
||||
|
||||
--- 2.0rc1 released ---
|
||||
|
||||
2009-07-17 (Valerio)
|
||||
* Fixed contact list tooltips with Right-to-Left text layouts.
|
||||
|
||||
2009-07-16 (Pano)
|
||||
* Merged an updated Brazilian Portuguese translation by Maurício Arozi Moraes.
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
* Merged an updated Arabic translation by Ma'moun Diraneyya.
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-07-15 (Pano)
|
||||
* Merged an updated Greek translation by Dimitrios Glentadakis.
|
||||
* Merged an updated Finnish translation by Antoni Hussy.
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-07-14 (Valerio)
|
||||
* Removed BinReloc, AutoPackage, and the other packaging support files.
|
||||
* Removed code which will never be in any 2.0.x release: WebApplication, NetMeeting/GnomeMeeting,
|
||||
audio conversation, SIP, UPNP, Webcam, Roaming, RemoteDesktop.
|
||||
|
||||
2009-07-14 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
* Merged an updated Hungarian translation by Pauli Henrik.
|
||||
|
||||
2009-07-14 (dazjorz)
|
||||
* Removed unused member currentStatus_ from KMess object.
|
||||
* Fixed reconnection resetting the status to the default initial status,
|
||||
instead of the last status before the connection was lost.
|
||||
* Set our new shiny KDE debug number to be the default.
|
||||
|
||||
2009-07-13 (Pano)
|
||||
* Merged an updated Japanese translation by Daniel E. Moctezuma.
|
||||
* Merged an updated German translation.
|
||||
* Merged an updated Catalan translation by Adrià Arrufat.
|
||||
|
||||
2009-07-11 (Pano)
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-07-10 (Valerio)
|
||||
* Added a little more space between the contact properties and their name in the Contact List tooltips.
|
||||
|
||||
2009-07-09 (Valerio)
|
||||
* Improved the looks of elided labels and increased the size of the user's friendly name.
|
||||
|
||||
2009-07-09 (Pano)
|
||||
* Merged an updated Slovak translation by Rastislav Krupanský.
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-07-09 (Adam)
|
||||
* Backport from trunk: fix bug where account would be saved when "Remember Account" was
|
||||
unchecked.
|
||||
|
||||
2009-07-08 (Pano)
|
||||
* Added an Japanese translation by Daniel E. Moctezuma.
|
||||
* Merged an updated Brazilian Portuguese translation by Sergio Rafael Lemke.
|
||||
|
||||
2009-07-07 (Valerio)
|
||||
* Backported from trunk: Fixed account verification and registration links in the Account Settings.
|
||||
|
||||
2009-07-07 (Adam)
|
||||
* Backport fix for artifacts that appear when fading text in the contact list
|
||||
with antialiasing enabled.
|
||||
|
||||
2009-07-07 (Adam)
|
||||
* Backport unknown avatar picture courtesy of archdria.
|
||||
|
||||
2009-07-06 (Pano)
|
||||
* Merged an updated Brazilian Portuguese translation by Maurício Arozi Moraes.
|
||||
|
||||
2009-07-06 (Valerio)
|
||||
* Fix adding a contact which had added the user, resulting in having the new contact
|
||||
appear as not having the user in his/her list.
|
||||
|
||||
2009-07-06 (dazjorz)
|
||||
* Fix logging once and for all, hopefully, and comment about the remaining
|
||||
edge cases I saw.
|
||||
* Made the shadowed hummingbird by Adrià Arrufat (Swiftscythe) an overlay to
|
||||
the user icon, changed the sizes a little.
|
||||
* Updated the 'unknown avatar' another time, a new icon by Adrià :)
|
||||
* Fixed crash in KMess::switchViewToContactList() and cleaned up that method and switchViewToInitialScreen().
|
||||
* Cleaned up a part of KMessView::showContextMenu().
|
||||
|
||||
2009-07-05 (Valerio)
|
||||
* Ensure the chat doesn't scroll when toggling the Chat Window Docks.
|
||||
* Prevent crashing on exit when the LikeBack Bar trieds to move on a window that is
|
||||
already deleted.
|
||||
* Fixed wrong "no internet connection" message in the initial screen when a connection gets
|
||||
established.
|
||||
* Updated Italian translation.
|
||||
* Removed the unused window title from an UI file.
|
||||
|
||||
2009-07-04 (Valerio)
|
||||
* Fixed Contact List's text when using RTL languages.
|
||||
* Improved the Contact Frame appearance: centered the contact's display picture, like the
|
||||
user one is.
|
||||
|
||||
2009-07-01 (Ruben)
|
||||
* DBus adapter is now built from XML (again).
|
||||
|
||||
2009-07-01 (Pano)
|
||||
* Merged an updated Brazilian Portuguese translation by Sergio Rafael Lemke.
|
||||
|
||||
2009-06-30 (Pano)
|
||||
* Merged an updated Dutch translation by Sjors Gielen.
|
||||
* Merged an updated Catalan translation by Adrià Arrufat.
|
||||
|
||||
2009-06-30 (Adam)
|
||||
* Change the icon of chat windows from the hummingbird to "user-identity" and "system-users"
|
||||
for 1-1 and group chats respectively.
|
||||
|
||||
2009-06-30 (dazjorz)
|
||||
* Imported the use of icon overlays from Amarok. Before, either the
|
||||
hummingbird or a status icon would be displayed; now the hummingbird is
|
||||
always displayed and a status icon is displayed as an overlay if possible.
|
||||
* Fixed bug where an invalid XML log file would make the chat history dialog
|
||||
go into an infinite loop.
|
||||
* Fixed some thread issues; now only starting the thread after the documents
|
||||
are given. Still an imperfect fix, if a new contact is chosen this could
|
||||
potentially run into problems if the thread just selects a new document
|
||||
that's currently being added, potentially.
|
||||
* Fixed a crash probably caused by my earlier commit, only showing if full
|
||||
debugging is enabled.
|
||||
* Fixed selectNextFile() to not return the base file if startingNumber is not
|
||||
zero, even if .1.xml doesn't exist and the base file does.
|
||||
* Fixed #494: display size is not limited for notifications. Displays are now
|
||||
limited at 96x96.
|
||||
* Now using 'chronometer' as an icon for the history dialog.
|
||||
* Finally replaced the kmess bag-over-head guy with a new icon. It's not
|
||||
perfect, just quickly hacked together, but it will probably serve until the
|
||||
Oxygen team comes with something better. :)
|
||||
* Moved the overlay code to kmessshared, and used that same method also for
|
||||
an overlay for the chat window, and dialogs like the chat history dialog.
|
||||
|
||||
2009-06-29 (Diederik)
|
||||
* Fix a crash triggered by clients aborting while we're sending data.
|
||||
|
||||
2009-06-28 (Pano)
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-06-25 (Pano)
|
||||
* Merged an updated Dutch translation by Sander Pientka.
|
||||
* Merged an updated Finnish translation by Antoni Hussy.
|
||||
|
||||
2009-06-24 (Adam)
|
||||
* Revert r4901; author names must be wrapped in ki18n() calls.
|
||||
|
||||
2009-06-23 (Adam)
|
||||
* Make the chat history dialog load any log files for a contact even if the base log
|
||||
file doesn't exist.
|
||||
* Remove the magic number for the max log file size; replaced with a static const long
|
||||
in Chat class.
|
||||
* Improve the debug messages in KMessShared::selectNextFile
|
||||
* Fix bug where the base file would always be skipped for chat logging.
|
||||
* Fade group names in contact list.
|
||||
* Prevent wordwrapping of group names in the contact list.
|
||||
* Fix logging bug caused by mishandling of the style tags in chatmessageview.cpp
|
||||
|
||||
2009-06-22 (Adam)
|
||||
* Display emoticons in presence messages.
|
||||
|
||||
2009-06-22 (dazjorz)
|
||||
* Fixed the logging issues people have been having, of logs suddenly
|
||||
disappearing: the log writer no longer clobbers a file when it fails to find
|
||||
the style tags; when an error occurs, the autosaver automatically tries to
|
||||
save to the next new file.
|
||||
* Removed a potential Heisenbug in the chat log writer, where the file would
|
||||
not be truncated if debugging was disabled.
|
||||
|
||||
2009-06-15 (Adam)
|
||||
* Reset cursor position in personal message input to 0 after setting text.
|
||||
* No longer show notice-level MSN errors in the statusbar (print debug message instead).
|
||||
* Fix warning about scaling a null pixmap in kmessviewdelegate.
|
||||
|
||||
2009-06-14 (Adam)
|
||||
* Use QUuid for generating GUIDs in KMessShared. Much easier to understand.
|
||||
* Fix #284 - require minimum 3 digits for generated ID's.
|
||||
* Seed RNG properly with srand() in KMessShared.generateID().
|
||||
* ChatMessageView now contains code to create its own popup menu. This simplifies ChatView and
|
||||
ChatHistoryDialog a little.
|
||||
* Fixed ticket #488 with the change immediately above.
|
||||
|
||||
2009-06-13 (Pano)
|
||||
* Merged an updated Arabic translation by Ma'moun Diraneyya.
|
||||
|
||||
2009-06-12 (Adam)
|
||||
* Add new Q&A's to the docbook for changing DP size in contact list and showing
|
||||
own DP in the chat windows.
|
||||
* Update the doc picture for export contact list.
|
||||
* Added sections to the documentation for the chat history dialog and exporting
|
||||
the contact list
|
||||
* Add Help buttons to the Chat History dialog. Just need to add a section in the
|
||||
docbook for it.
|
||||
* Tiny changes in the export contact list dialog: fix a typo in "Friendlyname" and
|
||||
update to use KMessageBox.
|
||||
* Fixed a tiny spelling error in the docbook.
|
||||
* Help buttons in dialogs now work: they are linked to their respective docbook sections.
|
||||
* Fix #483: do not close the dialog when Help is clicked. Fixed this same issue in the
|
||||
global settings dialog too. TODO: Use KDialog::setHelp() to link the help buttons to
|
||||
their corresponding docbook entries.
|
||||
|
||||
2009-06-12 (dazjorz)
|
||||
* Fixed #484: close-to-tray screenshots don't work with autohidden panels. If
|
||||
the systray is invisible, no screenshot is displayed (reported by a LikeBack
|
||||
user).
|
||||
|
||||
2009-06-11 (Adam)
|
||||
* Enforce maximum size of 96x96 for display pictures in chat windows (reported by pano).
|
||||
|
||||
2009-06-11 (Valerio)
|
||||
* Improved status restoring on reconnection.
|
||||
|
||||
2009-06-10 (Ruben)
|
||||
* Connect immediately on autologin when network status is unknown. Reported by baghera.
|
||||
|
||||
2009-06-09 (Ruben)
|
||||
* Removed LINK_DIRECTORIES from the konqueror plugin's CMakeList. Reported by RealNC.
|
||||
|
||||
2009-06-08 (dazjorz)
|
||||
* Updated the Dutch translation a little more.
|
||||
* Fixed bug where the passwordEdit_ would be cleared when first logging into
|
||||
an account.
|
||||
* Fixed adding emoticon links appearing in the history files. (Old history
|
||||
files will still contain them, as will external HTML log files.)
|
||||
|
||||
2009-06-07 (Pano)
|
||||
* Merged an updated Greek translation by Dimitrios Glentadakis.
|
||||
* Merged an updated Dutch translation by dazjorz.
|
||||
|
||||
2009-06-04 (Ruben)
|
||||
* Fixed disabling Handwriting and Winks buttons. Bug reported by mamoun.
|
||||
* Fixed RTL rendering of contactlist items. Bug reported by mamoun.
|
||||
|
||||
2009-06-01 (dazjorz)
|
||||
* Added .xd to the list of invalid country-code TLD's, and fixed a bug on
|
||||
checking if a tld is valid: only lowercase tld's were listed as invalid, so
|
||||
now calling .toLower() on the tld.
|
||||
|
||||
2009-05-31 (Pano)
|
||||
* Merged an updated Greek translation by Dimitrios Glentadakis.
|
||||
|
||||
2009-05-31 (Ruben)
|
||||
* Don't disable glow effect on contact's picture when he/she is typing.
|
||||
|
||||
2009-05-25 (Pano)
|
||||
* Merged an updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
|
||||
2009-05-24 (Diederik)
|
||||
* Improved the configure script a bit to detect the default install prefix of 'KDE on MacOS'
|
||||
|
||||
2009-05-20 (Pano)
|
||||
* Merged an updated Traditional Chinese translation by Yen-chou Chen.
|
||||
|
||||
2009-05-19 (Pano)
|
||||
* Merged an updated Arabic translation by Ma'moun Diraneyya.
|
||||
|
||||
2009-05-18 (dazjorz)
|
||||
* Fixed kmessview.ui, maketrans broke on it (this does not break string
|
||||
freeze, since that string is untranslatable)
|
||||
|
||||
2009-05-17 (Pano)
|
||||
* Merged an updated German translation.
|
||||
* Merged an updated French translation by Scias.
|
||||
* Merged an updated Hungarian translation by Pauli Henrik.
|
||||
|
||||
2009-05-17 (Valerio)
|
||||
* Fixed displaying labels in the contact list.
|
||||
|
||||
2009-05-17 (Pano)
|
||||
* Merged an updated Brazilian Portuguese translation by Maurício Arozi Moraes.
|
||||
|
||||
2009-05-17 (Adam)
|
||||
* Made the status chooser toolbutton expand to take as much space
|
||||
as it needs to display its caption fully.
|
||||
|
||||
2009-05-16 (Pano)
|
||||
* Merged an updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
* Merged an updated German translation.
|
||||
|
||||
2009-05-16 (Valerio)
|
||||
* Fixed chat and contact list alignment issues when using Right-to-Left languages.
|
||||
* Added a nice fading effect to the contact list items.
|
||||
* Added RTL languages support to the gradientElideLabel widget.
|
||||
* Fixed typing when the Winks widget was chosen, didn't go back to the message editor.
|
||||
* Added tooltips to the winks in the Winks widget.
|
||||
* Moved the contact list's user status icon within the status chooser toolbutton.
|
||||
|
||||
2009-05-16 (Adam)
|
||||
* Created a new GradientElideLabel class that adds a subtle
|
||||
fade effect (as seen in Dolphin) to long labels: this works with rich text
|
||||
and images too. It can stand in the place of any existing label and should
|
||||
perform reasonably well thanks to Qt's compositing framework.
|
||||
* Fixed ContactsWidget and ContactFrame to properly shrink/stretch the labels as necessary.
|
||||
|
||||
2009-05-16 (Pano)
|
||||
* Merged an updated French translation by Scias.
|
||||
|
||||
2009-05-16 (Dario)
|
||||
* Added an error message if the Triple DES Hash could not be computed.
|
||||
Strings are in a I18N_NOOP, remember to translate after freeze.
|
||||
|
||||
2009-05-15 (Valerio)
|
||||
* Changed default values for Plus formatting, it is now enabled by default.
|
||||
* Fixed status reset when reconnecting.
|
||||
* Fixed wrong signal connection in KMessView.
|
||||
* Changed the CMake dependency order to build the KMess-Send plugin last.
|
||||
* Fixed painter warnings in KMessView and improved its initialization order.
|
||||
* Added a possible fix for the rare Chat History Dialog crashes.
|
||||
|
||||
2009-05-15 (dazjorz)
|
||||
* Fixed AccountsManager not correctly updating the password if it changed and
|
||||
was already present in the wallet.
|
||||
* Fixed chat logging if the chat style changed: KMess will now write to a new
|
||||
file instead of not writing a log at all.
|
||||
* Fixed encoding issues with LikeBack again, for users which don't have utf8
|
||||
as their local character set. (this matches with the current LikeBack
|
||||
development version, but will work with the stable version too.)
|
||||
|
||||
2009-05-15 (Pano)
|
||||
* Merged an updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
|
||||
2009-05-15 (Adam)
|
||||
* Fixed a compile bug that only occurred on some KDE installs.
|
||||
|
||||
2009-05-13 (Pano)
|
||||
* Merged an updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
|
||||
2009-05-13 (Adam)
|
||||
* Fixed display of media string when contact signs in via XBox LIVE.
|
||||
* Fixed Ctrl+F not showing the inline find box in a chat window: this was
|
||||
due to KTextEdit consuming the Ctrl+F key sequence.
|
||||
* Fixed bug where the global settings dialog displayed stale data in
|
||||
the accounts list.
|
||||
|
||||
2009-05-12 (Ruben)
|
||||
* Draw feedback bar at the upper left corner when the user has a RTL language.
|
||||
|
||||
2009-05-12 (Valerio)
|
||||
* Fixed broken HTML entities in the emoticon widget's tooltips.
|
||||
* Fixed ETA timer, now it shows up only when the first actual bytes are transferred.
|
||||
* Fixed initial view's logo, it was being cropped when the window was too small.
|
||||
* Removed glow effect from the "show email" link in the Contact List. It was ugly.
|
||||
* Fixed Individuals group, it was being forced visible when it was completely empty like
|
||||
a normal group.
|
||||
* Set a minimum size on the Global Settings dialog's Events page, to allow seeing the
|
||||
events right away (it was too small before).
|
||||
* Moved the user status icon on the right, next to the status chooser.
|
||||
* Removed the "Switching to another server..." login message, as it's useless for most users.
|
||||
* Fixed the looks of the _underline_ _word_ _effect_ in chat.
|
||||
|
||||
2009-05-12 (dazjorz)
|
||||
* Fixed bug if a custom emoticon had a dot plus two letters as a shortcut,
|
||||
causing it to be seen as a geeklink.
|
||||
|
||||
--- 2.0beta2 released ---
|
||||
|
||||
2009-05-10 (dazjorz)
|
||||
@@ -8,6 +653,7 @@
|
||||
* Merged an updated Italian translation by Andrea Decorte.
|
||||
* Merged an updated Finnish translation by Antony Hussi.
|
||||
* Merged an updated Catalan translation by Adrià Arrufat.
|
||||
|
||||
2009-05-10 (Ruben)
|
||||
* Fixed bug in Konqueror plugin. Thanks to Pano.
|
||||
* Added Dutch translation for Konqueror Plugin.
|
||||
@@ -375,6 +1021,7 @@
|
||||
|
||||
2009-04-04 (Pano)
|
||||
* Merged an updated Greek translation by Dimitrios Glentadakis.
|
||||
* Merged an updated Arabic translation by Ma'moun Diraneyya.
|
||||
|
||||
2009-04-03 (dazjorz)
|
||||
* Fixed "invalid read error" from Valgrind in MsnNotificationConnection
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = KMess
|
||||
PROJECT_NUMBER = 2.0-beta2
|
||||
PROJECT_NUMBER = 2.0.1
|
||||
OUTPUT_DIRECTORY = ./apidocs
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
KMess Feature list
|
||||
========================
|
||||
- 2.0.1 -
|
||||
Synchronization of friendly names, personal messages and display pictures with Messenger.
|
||||
Support to send screenshots by dragging and dropping them to a chat.
|
||||
Custom emoticon preview in the settings.
|
||||
Chat window buttons to change message font and color.
|
||||
|
||||
- 2.0 -
|
||||
Support to receive and send Ink (hand-written) messages.
|
||||
Support to send huge messages.
|
||||
|
||||
@@ -1,3 +1,99 @@
|
||||
Changes between KMess 2.0.1 and 2.0:
|
||||
--------------------------------------
|
||||
- added a "Log in automatically" checkbox to the initial view (patch by Camille Begue).
|
||||
- added ability to open the chat history dialog when not connected
|
||||
(patch by Camille Begue).
|
||||
- added Test Server support.
|
||||
- added shortcut checking of added/edited emoticons for invalid characters.
|
||||
- added usage of smooth pixmap scaling for display pictures in the contact list.
|
||||
- added caching of scaled display pictures when painting the contact list.
|
||||
Mitigates performance hit caused by using smooth pixmap scaling.
|
||||
- added full Handwriting support, thanks to the ISF-Qt external library.
|
||||
- added Roaming content support: display picture, friendly name and personal
|
||||
message are now synchronized with those used in Messenger.
|
||||
- added chat window buttons to quickly change message font and color.
|
||||
- added ability to drag-and-drop an image from KSnapshot (or any drag'n'drop-enabled
|
||||
image application) to a chat, to send it.
|
||||
- added preview of emoticons in emoticon settings page.
|
||||
- fixed improper scaling of the display picture in the chat window and contact list.
|
||||
- fixed maximum emoticon shortcut length.
|
||||
- fixed "close all tabs" dialog: Don't show it when the KDE session is closing.
|
||||
- fixed a crash in NetworkWindow when receiving P2P messages shorter than
|
||||
the usual.
|
||||
- fixed an overzealousness of the IRC-like commands parser.
|
||||
- fixed redrawing of emoticons in the contact list and friendly name label,
|
||||
when emoticon theme is changed.
|
||||
- fixed display picture cache clearing, when pictures is changed.
|
||||
- fixed minimum size of the message editor to one line of text.
|
||||
- fixed appearance of the transfers window: it now appears in the background
|
||||
instead of minimized.
|
||||
- fixed occasional crash when canceling a drag and drop operation on the chat window.
|
||||
- fixed contact notifications, which were not shown for contacts going online.
|
||||
- fixed contact notification spam on login.
|
||||
- fixed a crash when connecting with the fallback HTTP connection (used behind
|
||||
firewalls, proxies et cetera).
|
||||
- fixed KDE 4.3.2 bug causing a crash when closing account settings.
|
||||
- fixed losing the friendly name on login.
|
||||
- removed small delay when auto-connecting on startup.
|
||||
- removed in-place editing of emoticons, now it's only done by AddEmoticonDialog.
|
||||
- removed giflib dependency, as it is now required by ISF-Qt.
|
||||
- updated Brazilian Portuguese translation by Maurício Arozi Moraes.
|
||||
- updated Catalan translation by Adrià Arrufat.
|
||||
- updated Dutch translation by Sjors Gielen.
|
||||
- updated Estonian translation by Lauri Võsandi, Mihkel Tõnnov and Rivo Laks.
|
||||
- updated Finnish translation by Marko Mäkilä.
|
||||
- updated French translation by Émeric Dupont.
|
||||
- updated German translation by Panagiotis Papadopoulos.
|
||||
- updated Greek translation by George Kiagiadakis.
|
||||
- updated Hungarian translation by Pauli Henrik.
|
||||
- updated Japanese translation by Daniel E. Moctezuma.
|
||||
- updated Simplified Chinese translation by Cheng Yang.
|
||||
- updated Spanish translation by Guillermo Arana.
|
||||
- updated Turkish translation by Uğur Çetin.
|
||||
|
||||
Changes between KMess 2.0 and 2.0-rc1:
|
||||
--------------------------------------
|
||||
- added back meaningful error messages for unsupported applications.
|
||||
- fixed crashing when transferring display pictures.
|
||||
- fixed a small bug in group sorting.
|
||||
- improved further the RTL languages support.
|
||||
- updated Arabic translation by Ma'moun Diraneyya.
|
||||
- updated German translation by Panagiotis Papadopoulos.
|
||||
- updated Simplified Chinese translation by Cheng Yang.
|
||||
|
||||
Changes between KMess 2.0-rc1 and 2.0-beta2:
|
||||
--------------------------------------
|
||||
- added Japanese translation by Daniel E. Moctezuma.
|
||||
- added display of emoticons in presence messages.
|
||||
- added status restoring on reconnection.
|
||||
- added fading effect for long text labels and the contact list.
|
||||
- changed the image used for unknown display pictures.
|
||||
- changed the application windows icons.
|
||||
- changed the system tray icon with one showing both the bird and the current
|
||||
status.
|
||||
- fixed a crash triggered by clients aborting while we're sending data.
|
||||
- fixed appearance when using right-to-Left languages, like Arabic.
|
||||
- fixed bug preventing temporary accounts to be correctly cleaned up.
|
||||
- fixed file selection errors in chat logging.
|
||||
- fixed newly added contacts appearing as not having added the user in their
|
||||
list.
|
||||
- improved appearance of the contact list when antialiasing is enabled.
|
||||
- removed all experimental features which could not be finished in time.
|
||||
- updated Arabic translation by Ma'moun Diraneyya.
|
||||
- updated Brazilian Portuguese translation by Maurício Arozi Moraes and Sergio
|
||||
Rafael Lemke.
|
||||
- updated Catalan translation by Adrià Arrufat.
|
||||
- updated Finnish translation by Antony Hussi.
|
||||
- updated Dutch translation by Sander Pientka and Sjors Gielen.
|
||||
- updated French translation by Scias.
|
||||
- updated German translation by Panagiotis Papadopoulos.
|
||||
- updated Greek translation by Dimitrios Glentadakis.
|
||||
- updated Hungarian translation by Pauli Henrik.
|
||||
- updated Italian translation by Valerio Pilo.
|
||||
- updated Slovak translation by Rastislav Krupanský.
|
||||
- updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
- updated Simplified Chinese translation by Cheng Yang.
|
||||
- updated Traditional Chinese translation by Yen-chou Chen.
|
||||
|
||||
Changes between KMess 2.0-beta2 and 2.0-beta1:
|
||||
--------------------------------------
|
||||
@@ -38,6 +134,7 @@ Changes between KMess 2.0-beta2 and 2.0-beta1:
|
||||
- updated Greek translation by Dimitrios Glentadakis.
|
||||
- updated Italian translation by Andrea Decorte.
|
||||
- updated Spanish translation by Manuel Ramírez.
|
||||
- updated Spanish translation by Mauricio Muñoz Lucero.
|
||||
- updated Traditional Chinese translation by Yen-chou Chen.
|
||||
- updated Traditional Chinese translation by the Tryneeds-Chinese Translation Platform.
|
||||
|
||||
@@ -52,7 +149,6 @@ Changes between KMess 2.0-beta1 and 2.0-alpha2:
|
||||
- added Likeback support to collect user feedback, ported from Basket of KDE 3.
|
||||
- added support to configure the toolbars and menus in the chat window.
|
||||
- added contact list export dialog.
|
||||
- added close button in the contact list search box.
|
||||
- added context menu to the contact list, to open the contact menu with the left mouse too.
|
||||
- added confirmation dialogs when the menu gets hidden with Ctrl+M.
|
||||
- added confirmation dialogs when deleting custom emoticons.
|
||||
|
||||
@@ -29,7 +29,7 @@ You can help translating KMess!
|
||||
|
||||
This is what you need to do:
|
||||
- Get the latest version of KMess
|
||||
- Install "kbabel" (supplied with "kdesdk")
|
||||
- Install "lokalize" (supplied with "kdesdk")
|
||||
- To create a new translation file, copy "kmess.pot"
|
||||
to a new file named "<your language>.po".
|
||||
- Open the language "po" file, and start translating!
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
# -*-shell-script-*-
|
||||
|
||||
[Meta]
|
||||
RootName: @kmess.sourceforge.net/kmess:$SOFTWAREVERSION
|
||||
DisplayName: KMess
|
||||
ShortName: kmess
|
||||
SoftwareVersion: 2.0beta2
|
||||
Maintainer: The KMess Developers
|
||||
Packager: Diederik van der Boor
|
||||
Summary: MSN Messenger client for KDE
|
||||
URL: http://www.kmess.org/
|
||||
License: GNU General Public License, Version 2
|
||||
AutopackageTarget: 1.0
|
||||
|
||||
|
||||
[Description]
|
||||
A MSN Messenger Client for KDE
|
||||
|
||||
KMess is a MSN Messenger client for Linux. It enables Linux
|
||||
users to chat with friends online who are using MSN Messenger
|
||||
in Windows or Mac OS. The strength of KMess is it's integration
|
||||
with the KDE desktop environment, focus on MSN Messenger specific
|
||||
features and an easy-to-use interface.
|
||||
|
||||
|
||||
[BuildPrepare]
|
||||
# The bogus deps solve our warnings about older distro incompatiblity
|
||||
export APBUILD_BOGUS_DEPS='art_lgpl art_lgpl_2 dl expat fontconfig freetype GL ICE idn kdefx kdesu kwalletclient m nsl png pthread resolv SM util X11 Xcursor Xft Xi Xinerama Xmu Xrandr Xrender'
|
||||
# Xrender is suggested by makeinstaller,
|
||||
# the XScreenSaver stuff can be either in libXss or libXext
|
||||
export APBUILD_STATIC='Xrender Xext Xss'
|
||||
prepareBuild
|
||||
|
||||
|
||||
[BuildUnprepare]
|
||||
unprepareBuild
|
||||
|
||||
|
||||
[Imports]
|
||||
# tells autopackage to include all files created by "make install"
|
||||
# make sure the symlink does not get installed. recreate it during Install
|
||||
find . -name common -type d -o -type l -exec rm -Rf {} \;
|
||||
echo "*" | import
|
||||
|
||||
|
||||
[Prepare]
|
||||
# KDE 4.1 is the minimum requirement for KMess 2
|
||||
require @kde.org/kdelibs 4.1
|
||||
|
||||
# flash and cabextract are used for winks.
|
||||
playWinks="1"
|
||||
|
||||
# test for cabextract
|
||||
outputTest "cabextract"
|
||||
if locateCommand -r "cabextract" "-v"; then
|
||||
outputTestPass
|
||||
else
|
||||
outputTestFail
|
||||
playWinks="0"
|
||||
fi
|
||||
|
||||
# test for flash
|
||||
# paths taken from Konqueror.
|
||||
outputTest "flash player"
|
||||
hasFlash="0"
|
||||
for i in /usr/lib/browser-plugins $HOME/.netscape/plugins /usr/lib64/browser-plugins /usr/local/netscape/plugins /opt/mozilla/plugins /opt/mozilla/lib/plugins /opt/netscape/plugins /opt/netscape/communicator/plugins /usr/lib/netscape/plugins /usr/lib/netscape/plugins-libc5 /usr/lib/netscape/plugins-libc6 /usr/lib/mozilla/plugins /usr/lib64/netscape/plugins /usr/lib64/mozilla/plugins $MOZILLA_HOME/plugins
|
||||
do
|
||||
if [ -e "$i/libflashplayer.so" ]
|
||||
then
|
||||
hasFlash="1"
|
||||
fi
|
||||
done
|
||||
if [ "$hasFlash" -eq "1" ];
|
||||
then
|
||||
outputTestPass
|
||||
else
|
||||
outputTestFail
|
||||
playWinks="0"
|
||||
fi
|
||||
|
||||
# notify user
|
||||
if [ "$playWinks" -eq "0" ];
|
||||
then
|
||||
outputStatus "You need to have cabextract and a flash player installed to play winks"
|
||||
# don't abort, KMess can operate without these deps.
|
||||
fi
|
||||
|
||||
|
||||
[Install]
|
||||
# # force to use the KDE path, workarround for broken distro's
|
||||
# # which don't support XDG/KDE stuff in /usr or /usr/local
|
||||
# test "`id -u`" -eq 0 && export PREFIX="`getKdePrefix`" || true
|
||||
|
||||
outputStatus "Installing application..."
|
||||
installExe bin/*
|
||||
installData share/apps/ share/doc/ share/emoticons/ share/sounds/
|
||||
linkFile --silent "`getKdePrefix`/share/doc/HTML/en/common" "$PREFIX/share/doc/HTML/en/kmess/common"
|
||||
installIcon share/icons/hicolor/ share/icons/locolor/
|
||||
installDesktop "Internet" share/applications/kde/kmess.desktop
|
||||
installLocale share/locale/
|
||||
|
||||
|
||||
[Uninstall]
|
||||
uninstallFromLog
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
/* Define if debug output should be enabled */
|
||||
#define KMESS_DEBUG ${KMESS_ENABLE_DEBUG_OUTPUT}
|
||||
|
||||
/* Define if the Relocatable Binary support should be enable */
|
||||
#define ENABLE_BINRELOC ${KMESS_ENABLE_BINRELOC}
|
||||
|
||||
/* Define the fallback prefix */
|
||||
#define KMESS_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
|
||||
@@ -23,11 +20,5 @@
|
||||
/* Define if LikeBack is not needed */
|
||||
#define KMESS_DISABLE_LIKEBACK ${KMESS_DISABLE_LIKEBACK}
|
||||
|
||||
/* Define if you have KPhone installed (for SIP voice chat) (currently unused) */
|
||||
/* #define HAS_KPHONE 1 */
|
||||
|
||||
/* Define whether to enable MSN webcam support (HIGHLY EXPERIMENTAL) */
|
||||
#define ENABLE_WEBCAM ${KMESS_ENABLE_WEBCAM}
|
||||
|
||||
/* Define whether to enable Ink support (using GIFLib) */
|
||||
#define KMESS_ENABLE_INK ${HAVE_LIBGIF}
|
||||
/* Define whether Ink support is enabled */
|
||||
#define KMESS_ENABLE_INK ${HAVE_LIBISFQT}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
cd `dirname $0`/..
|
||||
|
||||
# second sed expression fixes Mac OS X 10.4
|
||||
appver="`cat kmess.lsm | grep Version: | sed -e 's/[^0-9]\+//' -e 's/Version:\( \)*//'`"
|
||||
appver="`egrep 'SET.*KMESS_VERSION' CMakeLists.txt | sed -e 's/.*"\([^"]*\)".*/\1/'`"
|
||||
date="`date +%Y%m%d`"
|
||||
|
||||
# Make sure we have the right repository
|
||||
if [ ! -f kmess.kdevelop ]; then
|
||||
echo -n "svn (unknown)"
|
||||
/bin/echo -n "svn (unknown)"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Display normal version if subversion is not installed
|
||||
if [ ! -x `which svnversion 2>/dev/null` ]; then
|
||||
echo -n "$appver"
|
||||
/bin/echo -n "$appver"
|
||||
exit
|
||||
fi
|
||||
|
||||
@@ -24,9 +24,9 @@ svnver=`LANG=C svnversion`
|
||||
# see if this is not a repository.
|
||||
if [ "$svnver" = "exported" ]; then
|
||||
if [ -z "$KMESS_VER" ]; then
|
||||
echo -n "$appver";
|
||||
/bin/echo -n "$appver";
|
||||
else
|
||||
echo -n "$KMESS_VER";
|
||||
/bin/echo -n "$KMESS_VER";
|
||||
fi
|
||||
exit;
|
||||
fi
|
||||
|
||||
@@ -25,11 +25,22 @@
|
||||
# Variables
|
||||
#
|
||||
|
||||
# auto-detect default prefix
|
||||
KDE4_PREFIX=""
|
||||
DEFAULT_PREFIX="/usr/local"
|
||||
if type -p kde4-config >/dev/null; then
|
||||
KDE4_PREFIX=`kde4-config --prefix`
|
||||
|
||||
# auto-detect KDE Installation on the Mac.
|
||||
KDE4_CONFIG=""
|
||||
for i in `whereis kde4-config` /opt/local/bin/kde4-config
|
||||
do
|
||||
if [ -x "$i" ]; then
|
||||
KDE4_CONFIG="$i"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# auto-detect default prefix
|
||||
if [ -n "$KDE4_CONFIG" ]; then
|
||||
KDE4_PREFIX=`$KDE4_CONFIG --prefix`
|
||||
DEFAULT_PREFIX="$KDE4_PREFIX"
|
||||
fi
|
||||
|
||||
@@ -39,7 +50,6 @@ BUILD_TYPE="relwithdebinfo"
|
||||
BUILD_DIR="build"
|
||||
REAL_BUILD_DIR=""
|
||||
DEBUG=0
|
||||
BINRELOC=0
|
||||
|
||||
# Globals
|
||||
cd `dirname $0`
|
||||
@@ -71,7 +81,6 @@ Installation directories:
|
||||
|
||||
Optional Features:
|
||||
--enable-debug-output enable debugging output. default=no
|
||||
--enable-binreloc enable binary relocation support. default=no
|
||||
--build-dir=PATH path to store the build files. default: ./build
|
||||
--build-type=TYPE define the build configuration to use, values:
|
||||
release - standard release
|
||||
@@ -96,7 +105,7 @@ After running ./configure, you can type 'make' to build this project.
|
||||
else
|
||||
echo " WARNING:
|
||||
|
||||
kde4-config was not found. Please verify that
|
||||
kde4-config was not found. Please verify that
|
||||
you've installed the KDE 4 development packages!
|
||||
"
|
||||
fi
|
||||
@@ -140,7 +149,6 @@ function run_cmake
|
||||
echo "command: cmake -D CMAKE_INSTALL_PREFIX=$PREFIX \ "
|
||||
echo " -D CMAKE_BUILD_TYPE=$BUILD_TYPE \ "
|
||||
echo " -D KMESS_DEBUG_OUTPUT=$DEBUG \ "
|
||||
echo " -D KMESS_ENABLE_BINRELOC=$BINRELOC \ "
|
||||
echo " "$SRC_DIR" "
|
||||
echo ""
|
||||
|
||||
@@ -148,7 +156,6 @@ function run_cmake
|
||||
cmake -D CMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-D CMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-D KMESS_DEBUG_OUTPUT=$DEBUG \
|
||||
-D KMESS_ENABLE_BINRELOC=$BINRELOC \
|
||||
"$SRC_DIR" \
|
||||
&& cmake_ok || cmake_error
|
||||
}
|
||||
@@ -159,16 +166,11 @@ function cmake_ok
|
||||
# collect all settings
|
||||
local HAS_XSS="no (extension not detected)"
|
||||
local HAS_DEBUG="no (good!)"
|
||||
local HAS_BINRELOC="no (only available on Linux)"
|
||||
|
||||
if [ $DEBUG = "1" ]; then
|
||||
HAS_DEBUG="yes (KMess will be slow!)"
|
||||
fi
|
||||
|
||||
if [ $BINRELOC = "1" ]; then
|
||||
HAS_BINRELOC="yes"
|
||||
fi
|
||||
|
||||
if grep -q '^#define HAVE_XSCREENSAVER 1$' "config-kmess.h"; then
|
||||
HAS_XSS="yes"
|
||||
fi
|
||||
@@ -182,7 +184,6 @@ function cmake_ok
|
||||
# Install prefix: $PREFIX
|
||||
# Auto-away feature: $HAS_XSS
|
||||
# Debugging messages: $HAS_DEBUG
|
||||
# Binary relocatable: $HAS_BINRELOC
|
||||
# Build type: $BUILD_TYPE
|
||||
# Build directory: $BUILD_DIR
|
||||
#
|
||||
@@ -193,7 +194,6 @@ function cmake_ok
|
||||
# cmake -D CMAKE_INSTALL_PREFIX=$PREFIX \\
|
||||
# -D CMAKE_BUILD_TYPE=$BUILD_TYPE \\
|
||||
# -D KMESS_DEBUG_OUTPUT=$DEBUG \\
|
||||
# -D KMESS_ENABLE_BINRELOC=$BINRELOC \\
|
||||
# \"$SRC_DIR\"
|
||||
#
|
||||
" > $makefile
|
||||
@@ -214,7 +214,6 @@ function cmake_ok
|
||||
Install prefix: $PREFIX
|
||||
Auto-away feature: $HAS_XSS
|
||||
Debugging messages: $HAS_DEBUG
|
||||
Binary relocatable: $HAS_BINRELOC
|
||||
Build type: $BUILD_TYPE
|
||||
|
||||
|
||||
@@ -262,7 +261,7 @@ Please run cmake directly, for example:
|
||||
fi
|
||||
|
||||
# Parse the arguments
|
||||
longopts="help,prefix:,build-type:,build-dir:,build-folder:,enable-binreloc,enable-debug-output"
|
||||
longopts="help,prefix:,build-type:,build-dir:,build-folder:,enable-debug-output"
|
||||
TEMP=`getopt --name=configure \
|
||||
--options h \
|
||||
--longoptions "$longopts" -- "$@"`
|
||||
@@ -280,7 +279,6 @@ Please run cmake directly, for example:
|
||||
-h|--help) print_help; exit 0 ;;
|
||||
--prefix) PREFIX=$2; shift 2 ;;
|
||||
--enable-debug-output) DEBUG=1; shift ;;
|
||||
--enable-binreloc) BINRELOC=1; shift ;;
|
||||
--build-type) BUILD_TYPE="$2"; shift 2 ;;
|
||||
--build-dir) BUILD_DIR="$2"; shift 2 ;;
|
||||
--builddir|--build-directory|--build-folder) BUILD_DIR="$2"; shift 2 ;; # be forgiving with small errors.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
LibISF-Qt authors
|
||||
-------------------------
|
||||
|
||||
The developers of this library are:
|
||||
|
||||
- Valerio Pilo <valerio@kmess.org>
|
||||
- Adam Goossens <adam@kmess.org>
|
||||
|
||||
|
||||
Credits
|
||||
-------------------------
|
||||
|
||||
Creating this library would not have been possible without the previous efforts
|
||||
of some great people:
|
||||
|
||||
The tclISF authors:
|
||||
- Ole André Vadla Ravnås (oleavr)
|
||||
- Youness Alaoui (KaKaRoTo)
|
||||
- Boris Faure (billiob)
|
||||
|
||||
The pyISF author:
|
||||
- Kevin Campbell
|
||||
|
||||
We'd also like to thank Microsoft for publishing the file format specifications.
|
||||
@@ -0,0 +1,102 @@
|
||||
PROJECT( isf-qt )
|
||||
CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
|
||||
|
||||
|
||||
#### Main switches ####
|
||||
|
||||
# Define the default build type
|
||||
# Possible values:
|
||||
# - none
|
||||
# - release
|
||||
# - debug
|
||||
# - debugfull (even fewer optimisations)
|
||||
# - relwithdebinfo (release with debug info)
|
||||
# - minsizerel (minimum size release)
|
||||
# Uncomment the next line to force building in full debug mode
|
||||
SET( CMAKE_BUILD_TYPE debugfull )
|
||||
|
||||
# Define the library version number
|
||||
SET( ISFQT_VERSION "0.9" )
|
||||
|
||||
|
||||
#### Inclusions ####
|
||||
|
||||
FIND_PACKAGE( Qt4 REQUIRED )
|
||||
|
||||
ENABLE_TESTING()
|
||||
|
||||
OPTION( WANT_GIF "Enable support for reading and writing Fortified-GIF images" ON )
|
||||
IF( WANT_GIF )
|
||||
MESSAGE( "-- Looking for GifLib" )
|
||||
|
||||
# Apparently, the KDE CMake macros unset a check which is required by giflib.
|
||||
IF( KDE4_FOUND )
|
||||
INCLUDE( "cmake/giflib_hack.cmake" )
|
||||
ENDIF( KDE4_FOUND )
|
||||
|
||||
FIND_PACKAGE( GIF QUIET )
|
||||
|
||||
# At this point, we can be relatively sure that if it's there, it has been found
|
||||
IF( NOT GIF_FOUND )
|
||||
MESSAGE( "-- Looking for GifLib - not found!" )
|
||||
MESSAGE( FATAL_ERROR
|
||||
"Support to read and write Fortified-GIF images is missing.\n"
|
||||
" * You will need to install both the library and development packages of the GIF Library, giflib.\n"
|
||||
" * Usually the package names for this library are:\n"
|
||||
" on Ubuntu: 'libgif4' and 'libgif-dev'\n"
|
||||
" on openSUSE: 'giflib' and 'giflib-devel'\n"
|
||||
" * The project homepage is http://sourceforge.net/projects/giflib/\n" )
|
||||
ELSE()
|
||||
MESSAGE( "-- Looking for GifLib - found" )
|
||||
ENDIF()
|
||||
ELSE( WANT_GIF )
|
||||
MESSAGE( "-- GifLib support disabled" )
|
||||
ENDIF( WANT_GIF )
|
||||
|
||||
# Set the variable for isfqtconfig.h.in
|
||||
IF( WANT_GIF )
|
||||
SET( GIF_ENABLED 1 )
|
||||
ELSE()
|
||||
SET( GIF_ENABLED 0 )
|
||||
ENDIF()
|
||||
|
||||
|
||||
#### Compilation ####
|
||||
|
||||
IF( CMAKE_COMPILER_IS_GNUCXX )
|
||||
SET( CMAKE_CXX_FLAGS_DEBUGFULL
|
||||
"-O0 -g3 -fno-inline -Wall -Woverloaded-virtual -Wsign-compare -Wundef -fvisibility=default" )
|
||||
ENDIF( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} src include )
|
||||
|
||||
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/isfqtconfig.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/isfqtconfig.h )
|
||||
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( tests )
|
||||
|
||||
|
||||
#### Project CMake configuration files creation ####
|
||||
|
||||
# Define the shortcuts for the installation directories
|
||||
SET( INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/isf-qt"
|
||||
CACHE STRING "Directory where the include files will be installed" )
|
||||
SET( LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib"
|
||||
CACHE STRING "Directory where the lib will be installed" )
|
||||
SET( SHARED_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE STRING "Directory where the shared data will be installed" )
|
||||
|
||||
# Prepare the IsfQtConfig.cmake file, which allows other projects to find us
|
||||
CONFIGURE_FILE( cmake/IsfQtConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/IsfQtConfig.cmake" @ONLY )
|
||||
|
||||
|
||||
#### Installation ####
|
||||
|
||||
# Do not install the resources if we're bundling it in KMess
|
||||
IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
|
||||
INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/IsfQtConfig.cmake
|
||||
DESTINATION ${LIB_INSTALL_DIR}/isfqt )
|
||||
INSTALL( FILES cmake/FindIsfQt.cmake
|
||||
DESTINATION ${CMAKE_ROOT}/Modules )
|
||||
ENDIF()
|
||||
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 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.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,270 @@
|
||||
2009-10-03 (Adam)
|
||||
* Remove unused HIMETRIC conversion methods.
|
||||
|
||||
2009-09-11 (Adam)
|
||||
* Improve doxygen comments of InkCanvas.
|
||||
|
||||
2009-09-10 (Valerio)
|
||||
* Do not add twice single-dot strokes in InkCanvas.
|
||||
* Removed a leftover debug message.
|
||||
* Fixed the Drawing copy constructor, which was copying even empty lists.
|
||||
* Fixed Bit Packing compression and the Delta-Delta transform, now the lib
|
||||
works perfectly again.
|
||||
* Fixed argument parsing in test_decode.
|
||||
|
||||
2009-09-10 (Adam)
|
||||
* Don't extract private members in Doxygen output.
|
||||
|
||||
2009-09-09 (Valerio)
|
||||
* Added Fortified GIF read-write support. New optional dependency, giflib.
|
||||
* Added Base64-encoded input/output data support.
|
||||
* Updated the documentation files.
|
||||
* Added Doxygen documentation infrastructure. There still are a lot of errors.
|
||||
* Created proper Doxygen documentation for all classes.
|
||||
* Moved the resource files into the /data/ directory.
|
||||
* Added a proper copy constructor for Drawing.
|
||||
|
||||
2009-09-09 (Adam)
|
||||
* Add draw-eraser.svgz to comply with Oxygen licensing requirements.
|
||||
|
||||
2009-09-08 (Adam)
|
||||
* Make copyright headers standard across all files.
|
||||
* Replace the eraser cursor with draw-eraser.png take from Oxygen 16x16 icon set.
|
||||
|
||||
2009-08-30 (Valerio)
|
||||
* Rewritten the algorithm detection methods.
|
||||
* Changed the names of some internal data classes, and improved their namespaces.
|
||||
* Added a maximum drawing size check, to avoid errors from resulting in 80k by 70k pixel wide
|
||||
drawings.
|
||||
* Moved all algorithms into src/data/algorithms.
|
||||
* Renamed the Gorilla algorithm to "Bit Packing".
|
||||
* Separated the delta-delta transformation methods into their own files.
|
||||
* Added an algorithm to do bit-packing of bytes.
|
||||
* Fixed bug in DataSource, the last bit of data was never read.
|
||||
* Added parsing the GUID table tag and saving the GUIDs into Drawing.
|
||||
* Added parsing of custom tags and decoding their contents.
|
||||
|
||||
2009-08-29 (Valerio)
|
||||
* Fixed skipping unknown custom tags contents.
|
||||
* Changed more method names to adhere to Qt's method naming style.
|
||||
|
||||
2009-08-29 (Adam)
|
||||
* Start qt-ifying the function names ie, "penSize()" instead of "getPenSize()".
|
||||
* Add methods to return pen size, colour and brush type from InkCanvas.
|
||||
* Always write at least one transformation to the stream: if no custom transforms, write the default one.
|
||||
* No longer take ownership of Isf::Drawing instances set with setDrawing().
|
||||
* By default InkCanvas' initial Isf::Drawing instance that is created is no longer allocated
|
||||
with new. This frees us from the concern of "when do we delete this initial reference?".
|
||||
* Rename Isf::InkEdit to Isf::InkCanvas. A better suited name.
|
||||
* When building bundled isf-qt, link statically and do not install any library components.
|
||||
Non-bundled builds a shared library and installs all components.
|
||||
|
||||
2009-08-28 (Adam)
|
||||
* Fix writing of transformation data: write in the correct order and scale the transform values
|
||||
appropriately before writing.
|
||||
* Write TIDX properly when transformations change between strokes.
|
||||
* Properly apply scaling when calculating the bounding rectangle.
|
||||
* Do not use Compress.decode(*) calls as function parameters. The order of parameter
|
||||
evaluation is platform-dependent and hence cannot be relied on.
|
||||
* Properly apply stroke transforms when drawing; scale pen size appropriately.
|
||||
|
||||
2009-08-24 (Adam)
|
||||
* Fix Drawing::getStrokeAtPoint to properly return point strokes.
|
||||
* Prevent strokes from having a bounding rectangle of size 1x1 (otherwise the eraser never hit them)
|
||||
* Tweak the collision distance to give a 25% margin of error (in practice this works well).
|
||||
|
||||
2009-08-23 (Adam)
|
||||
* Add Drawing::getStrokeAtPoint method. Uses Heron's Formula and triangle heights to determine
|
||||
if the cursor is positioned above a stroke. Seems to work quite well and appears to be fast.
|
||||
* Basic eraser support working. Individual strokes can be erased.
|
||||
* InkEdit now shows a custom cursor - a point drawn with the current stroke colour and width.
|
||||
* Drawing now calculates its bounding rectangle as necessary. Calls to finalizeChanges are not
|
||||
necessary anymore.
|
||||
* Remove cropping. Found a better method whereby InkEdit will draw the rendered ISF using the
|
||||
offset provided by the bounding rectangle of Isf::Drawing.
|
||||
* Supply the FitToCurve flag for all strokes. Windows will render them using Bezier smoothing, making
|
||||
them appear nicer.
|
||||
* Upgrade the TestInkEdit application. Supports multiple stroke colours and pen widths.
|
||||
* Remove InkEdit::getImageBytes and replace with InkEdit::getBytes. InkEdit doesn't write to GIF.
|
||||
* Support changing the colour of the InkEdit canvas.
|
||||
* Add a convenience method, InkEdit::save(), that will write the ISF drawing to a given QIODevice.
|
||||
Optionally will write the drawing in base64.
|
||||
|
||||
2009-08-23 (Adam)
|
||||
* Bug fixes in isf-qt: properly assign stroke attributes when changing colour on InkEdit.
|
||||
* Fix a crash that would occur if stroke attributes or transform were null.
|
||||
* Initial version of isf-qt InkEdit committed. Works reasonably well. Not integrated in KMess yet.
|
||||
* Added a cropping property to Isf::Drawing. When true, Drawing::getImage returns a cropped image
|
||||
and getSize returns the cropped size. When false, does the opposite. Necessary for InkEdit to
|
||||
properly support adding strokes to loaded Ink data.
|
||||
* Add a test application for new InkEdit. Can create, save and load Ink data in both raw ISF and
|
||||
ISF-base64 format.
|
||||
* Fix a bug in tagswriter which cause corrupt ISF data if there were no metric blocks.
|
||||
|
||||
2009-08-20 (Valerio)
|
||||
* Implemented writing metric blocks into ISF streams.
|
||||
* Fixed transformation/attributeSet/metrics index writing, now the index tags are written only
|
||||
when necessary.
|
||||
* Removed all user-side required conversions between HiMetric units and pixels. The library
|
||||
now only offers data expressed in pixels.
|
||||
* Fixed a bug in writeHiMetricSize() which prevented ISF streams from being parsed by older
|
||||
Microsoft.Ink libraries, like the one of Windows Messenger.
|
||||
|
||||
2009-08-20 (Adam)
|
||||
* Fix install path of FindIsfQt.cmake.
|
||||
* Don't attempt to install FindIsfQt.cmake if the library is build bundled.
|
||||
|
||||
2009-08-19 (Valerio)
|
||||
* Added DataSource::reset() method to start reading data back from the start.
|
||||
* Added to DataSource some ways to detect errors.
|
||||
* Rewritten the multi-byte encoding tests.
|
||||
* Switched away from QTransform to QMatrix for transformations.
|
||||
* Fixed the write order of transformation values.
|
||||
* Fixed stroke saving. The library should now be able to generate new ink.
|
||||
* Renamed Isf::Parser::isfToDrawing() and Isf::Parser::drawingToIsf()
|
||||
to Isf::Stream::reader() and Isf::Stream::writer() to enhance readability.
|
||||
* Renamed the Isf::PointInfo structure to Isf::AttributeSet, because the old name made no sense.
|
||||
* Added manipulation methods for strokes, transformations and attribute sets.
|
||||
* Fixed compiler warning. Thanks to Émeric Dupont.
|
||||
* Fixed colors in written streams.
|
||||
* Fixed the Scale&Translate transformation once again.
|
||||
* Isf::Drawings are now created on the heap instead of on the stack, to avoid unwanted object
|
||||
deletions.
|
||||
* Added optional parameter to Isf::Drawing::getPixmap() to choose the background color of
|
||||
the created image.
|
||||
* Added a method to compute some useful values before rendering new and changed drawings.
|
||||
* Added a couple stream writer improvements.
|
||||
|
||||
2009-08-14 (Valerio)
|
||||
* Added Drawing::clean() method to reset a drawing without creating a new one.
|
||||
|
||||
2009-08-13 (Valerio)
|
||||
* Added DataSource method to append bit arrays to the data.
|
||||
* Implemented Huffman encoding. Still missing is the algo to select the best encoding index.
|
||||
|
||||
2009-08-07 (Valerio)
|
||||
* Added an AUTHORS file with credits.
|
||||
* Implemented Gorilla compression.
|
||||
* Added stroke writing in the stream writer.
|
||||
* Moved all of Drawing's object lists to pointer lists, to ease comparing their items.
|
||||
|
||||
2009-08-06 (Valerio)
|
||||
* Added Metrics recognization and saving.
|
||||
* Made sense into the property tags: they're now all in the PacketProperty enum.
|
||||
* Added MultiByteCoding utility methods to find out the encoded size of a value.
|
||||
* Changed the installed include files directory to PREFIX/include/isf-qt .
|
||||
* Added a NOTES file with possibly useful stuff.
|
||||
* Added metrics measurement units, found on MSDN.
|
||||
* Added a couple more checks on data.
|
||||
* Moved include isfdrawing.h to isfqtdrawing.h .
|
||||
* Fixed CMake installing bug and added C++ style includes, <IsfQt> and <IsfQtDrawing>.
|
||||
* Fixed name of the drawing-to-isf converting method.
|
||||
* Fixed crash when given an invalid drawing address.
|
||||
|
||||
2009-08-05 (Valerio)
|
||||
* Extended Adam's last fix to the other main drawing properties.
|
||||
* Added maximum stroke pen size value.
|
||||
* Added stroke and drawing bounding box values.
|
||||
* Added adjusting the drawing's bounding box to include thick strokes.
|
||||
* Enabled transformations.
|
||||
* Fixed transform data order, it was inverted for scale+translate transforms.
|
||||
* Fixed destination QPixmap's size, it's now fit for the drawing.
|
||||
* Completed CMake rules, now the library can be installed on the system and
|
||||
other projects can find it.
|
||||
* Improved debugging rules, now debug mode is controlled (again) from CMake
|
||||
and verbose output is configurable.
|
||||
* Fixed the documentation to reflect the name change "libisf" to "isf-qt",
|
||||
and updated it.
|
||||
* Added updated KDevelop3/4 project files.
|
||||
* Changed the library structure:
|
||||
- separated the public interface includes into the /include/ dir
|
||||
- moved all internally used inclusions and data structures into
|
||||
/src/isfqt-internal.h
|
||||
- reorganized the internal files structure
|
||||
- renamed class Tags to TagsParser as there will be a TagWriter (made up name)
|
||||
- Renamed the IsfData class to DataSource as it is at a lower level than ISF.
|
||||
- Moved the ISF parser into a class Parser, found in include/isfqt.h and src/isfqt.cpp
|
||||
* Added a dummy drawing-to-ISF method in class Parser.
|
||||
* Added multibyte encoding methods taking a DataSource.
|
||||
* Added float encoding method and fixed uint encoding method.
|
||||
* Fixed seeking bug in DataSource::append() methods.
|
||||
* Added DataSource::prepend() methods.
|
||||
* Started working on the ISF stream writer.
|
||||
|
||||
2009-08-05 (Adam)
|
||||
* Correct an issue with incorrect colours for strokes.
|
||||
|
||||
2009-08-04 (Adam)
|
||||
* Re-save test ISF data with official Microsoft Ink classes.
|
||||
* Add functions to convert between HiMetric units and pixels.
|
||||
* Antialiasing whilst drawing ISF to QPixmap.
|
||||
* Fix the drawing of ISF data to QPixmap: draw the lines correctly between points.
|
||||
|
||||
2009-08-04 (Valerio)
|
||||
* Fixed endianness problems when retrieving datastream bits with IsfData.
|
||||
* Added a new parameter to IsfData::atEnd() to check if the buffer was all used,
|
||||
including the current byte's bits.
|
||||
* Changed IsfData::seekByteBack() with seekRelative(), which makes more sense.
|
||||
* Added IsfData::skipToNextByte() to discard the current byte's bits and move on
|
||||
to the next byte.
|
||||
* Added Isf::Drawing method getPixmap() to convert a drawing to a QPixmap. Quite raw
|
||||
at the moment, but still.
|
||||
* Moved actual tag parsing into Isf::Drawing::parseTag().
|
||||
* Added a whole lot of tags to Isf::Tags. Now the parser is able to recognize the most
|
||||
useful tags (and mostly make use of their data).
|
||||
* Added a GUID mapping from the ISF specs, I doubt it'll ever be used though.
|
||||
* Added float decoding method to multibytecoding.cpp.
|
||||
* Added new test ISF files - more complex - and sorted all test ISF files by complexity.
|
||||
* Added new test application "test_decode", which displays a parsed ISF file.
|
||||
* Added pressure data recognization.
|
||||
* Added stroke description blocks recognization.
|
||||
* Fixed stroke payload parsing appearing when not needed (and wasting bytes).
|
||||
* Added a set of data structures to hold metrics and to better contain stroke attributes.
|
||||
* Reorganized the code of the Tags namespace, it's now a class with all static members;
|
||||
this simplifies quite a bit the passing of data between that and IsfDrawing.
|
||||
* Fixed bug in the GUID Table tag parser.
|
||||
* Added more compiler flags (and warnings) to ease debugging.
|
||||
* Added the infrastructure to link metrics and transforms data to the strokes.
|
||||
* Finally linked the drawing attributes and stroke info to the strokes' data:
|
||||
libisf-qt is now correctly decoding all tests (except test 6).
|
||||
* Fixed all compiler warnings and improved the debugging output.
|
||||
* Fixed point rendering didn't work when points are made by a line from a point
|
||||
to the same point.
|
||||
* Fixed broken main parser loop, continued forever.
|
||||
|
||||
2009-07-30 (Valerio)
|
||||
* Added IsfData class to read and write bit-by-bit an array of bytes.
|
||||
* Changed all the code to use it instead of plain QByteArrays.
|
||||
* Completed huffman decompression support.
|
||||
* Added algorithm data to help writing gorilla decompression.
|
||||
* Added tests for the IsfData class.
|
||||
* Added tag recognization.
|
||||
* Fixed some IsfData bugs.
|
||||
* Changed default CMake build type to debugfull.
|
||||
* Completed Gorilla decompression support.
|
||||
* Started tag parsing work, made basic analysis methods.
|
||||
* Made the ParserError enum (now IsfError) the library's error enumeration system.
|
||||
* Continued a bit the tag parsing work, added a couple tags and another testfile.
|
||||
|
||||
2009-07-08 (Adam)
|
||||
* Make decode(UInt|Int) take a reference as a position parameter. This
|
||||
reference is then incremented as the integer is decoded.
|
||||
* Re-work tests for IsfDrawing.
|
||||
* Create IsfDrawing::fromIsfData() static method to create a new IsfDrawing
|
||||
instance from a QByteArray containing ISF data.
|
||||
* Begin state matchine for ISF parser.
|
||||
* Add appropriate unit tests for ISF parser.
|
||||
* Added TODO file for libisf to keep track of things.
|
||||
|
||||
2009-06-30 (Adam)
|
||||
* Parse ISF version number properly; add unit tests for it.
|
||||
* Fix CMakeLists.txt to build with debug info by default
|
||||
* Moved format/types.(cpp|h) into the multibytecoding.(cpp|h) classes.
|
||||
Also moved these into libisf/ and deleted format/ directory.
|
||||
* Added Isf::encodeInt to encode a signed integer into multibyte format
|
||||
* Added test cases for the encode/decode functions.
|
||||
* Re-add libisf.h
|
||||
* Fix wrong e-mail addresses in copyright info.
|
||||
* Created a unit test framework for libisf-qt; run using make test
|
||||
* Created IsfDrawing class which will represent an ISF drawing.
|
||||
* Added some rudimentary unit tests for IsfDrawing
|
||||
@@ -0,0 +1,259 @@
|
||||
# Doxyfile 1.5.5-KDevelop
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = ISF-Qt
|
||||
PROJECT_NUMBER = 0.9
|
||||
OUTPUT_DIRECTORY = ./apidocs
|
||||
CREATE_SUBDIRS = YES
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 2
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = YES
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = YES
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = NO
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ./src ./include
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.cpp \
|
||||
*.h \
|
||||
*.dox
|
||||
RECURSIVE = YES
|
||||
EXCLUDE = *.moc \
|
||||
*.moc.cpp \
|
||||
*.moc.h
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = */build*/*
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 4
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER = doc/apidocs_header.html
|
||||
HTML_FOOTER = doc/apidocs_footer.html
|
||||
HTML_STYLESHEET = doc/doxygen.css
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = YES
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE = isf-qt.tag
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = NO
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = YES
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
@@ -0,0 +1,163 @@
|
||||
|
||||
This file contains possibly useful stuff.
|
||||
|
||||
|
||||
|
||||
typedef struct _GUID
|
||||
{
|
||||
unsigned long Data1;
|
||||
unsigned short Data2;
|
||||
unsigned short Data3;
|
||||
unsigned char Data4[ 8 ];
|
||||
} GUID;
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
const GUID name DECLSPEC_HIDDEN; \
|
||||
const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
|
||||
DEFINE_GUID(GUID_LINENUMBER, 0xdbf29f2c, 0x5289, 0x4be8, 0xb3, 0xd8, 0x6e, 0xf6, 0x32, 0x46, 0x25, 0x3e);
|
||||
DEFINE_GUID(GUID_BOXNUMBER, 0x2c243e3a, 0xf733, 0x4eb6, 0xb1, 0xf8, 0xb5, 0xdc, 0x5c, 0x2c, 0x4c, 0xda);
|
||||
DEFINE_GUID(GUID_SEGMENTATION, 0xb3c0fe6c, 0xfb51, 0x4164, 0xba, 0x2f, 0x84, 0x4a, 0xf8, 0xf9, 0x83, 0xda);// {CA6F40DC-5292-452a-91FB-2181C0BEC0DE}
|
||||
DEFINE_GUID(GUID_HOTPOINT, 0xca6f40dc, 0x5292, 0x452a, 0x91, 0xfb, 0x21, 0x81, 0xc0, 0xbe, 0xc0, 0xde);// {BF0EEC4E-4B7D-47a9-8CFA-234DD24BD22A}
|
||||
DEFINE_GUID(GUID_MAX_STROKE_COUNT, 0xbf0eec4e, 0x4b7d, 0x47a9, 0x8c, 0xfa, 0x23, 0x4d, 0xd2, 0x4b, 0xd2, 0x2a);// {7DFE11A7-FB5D-4958-8765-154ADF0D833F}
|
||||
DEFINE_GUID(GUID_CONFIDENCELEVEL, 0x7dfe11a7, 0xfb5d, 0x4958, 0x87, 0x65, 0x15, 0x4a, 0xdf, 0xd, 0x83, 0x3f);// {8CC24B27-30A9-4b96-9056-2D3A90DA0727}
|
||||
DEFINE_GUID(GUID_LINEMETRICS, 0x8cc24b27, 0x30a9, 0x4b96, 0x90, 0x56, 0x2d, 0x3a, 0x90, 0xda, 0x7, 0x27);
|
||||
DEFINE_GUID(GUID_INRANGE, 0xdc00b1af, 0x7321, 0x4ac1, 0x91, 0x88, 0xe3, 0x20, 0x18, 0xeb, 0xb2, 0x3b);
|
||||
DEFINE_GUID(GUID_TOUCH, 0x65c98c60, 0xcd80, 0x447d, 0xb1, 0x29, 0x25, 0xf6, 0xe, 0x1d, 0x80, 0x5b);
|
||||
DEFINE_GUID(GUID_UNTOUCH, 0x378c85bb, 0x7118, 0x491e, 0x85, 0x16, 0xa7, 0x48, 0x2d, 0xb, 0x68, 0x3a);
|
||||
DEFINE_GUID(GUID_TAP, 0x9eaad4, 0xd133, 0x4ed2, 0xb1, 0x2c, 0x89, 0x1f, 0x8e, 0x82, 0x5e, 0x6a);
|
||||
DEFINE_GUID(GUID_QUALITY, 0xb7fe8008, 0x2df6, 0x4e1b, 0x8c, 0x43, 0xf5, 0xf1, 0x6, 0x8, 0x93, 0x2d);
|
||||
DEFINE_GUID(GUID_DATAVALID, 0xaacf46b5, 0xf107, 0x47b0, 0xb5, 0x77, 0xd9, 0x39, 0xc0, 0x53, 0xed, 0x41);
|
||||
DEFINE_GUID(GUID_TRANSDUCERINDEX, 0xa412b445, 0x7818, 0x4c83, 0x84, 0x55, 0x49, 0x29, 0xc8, 0x70, 0x76, 0x3b);
|
||||
DEFINE_GUID(GUID_TABLETFUNCTIONKEYS, 0xff3b8afe, 0x5f06, 0x494d, 0xa4, 0xf8, 0xd3, 0xe2, 0x85, 0xf9, 0x76, 0x30);
|
||||
DEFINE_GUID(GUID_PROGRAMCHANGEKEYS, 0x869c344a, 0x92a1, 0x4b6f, 0xb4, 0xbc, 0x3, 0x96, 0xc6, 0xa9, 0xf6, 0xaf);
|
||||
DEFINE_GUID(GUID_BATTERYSTRENGTH, 0x4ca0a0dc, 0x3549, 0x43f5, 0xa0, 0x32, 0x99, 0xf4, 0xe3, 0x3d, 0xf4, 0x90);
|
||||
DEFINE_GUID(GUID_INVERT, 0xc3aa28c8, 0x806b, 0x490c, 0xa8, 0x4a, 0xa7, 0x7a, 0xe7, 0x27, 0xc7, 0x18);
|
||||
DEFINE_GUID(GUID_BUTTON4,0x844b06d, 0xaa2c, 0x4c66, 0x99, 0x76, 0x88, 0xdd, 0x2a, 0x59, 0xe4, 0xf0);
|
||||
DEFINE_GUID(GUID_BUTTON5,0x944d1340, 0x2549, 0x4905, 0xbd, 0x54, 0x3e, 0xe3, 0x96, 0x3e, 0xe1, 0x57);
|
||||
DEFINE_GUID(GUID_BUTTON6,0xff19bd41, 0xa463, 0x4eaa, 0xaf, 0x10, 0xb5, 0x6, 0x48, 0x79, 0xe5, 0x4b);
|
||||
DEFINE_GUID(GUID_BUTTON7,0xdedaf13c, 0xb7dc, 0x423b, 0xb9, 0x7f, 0xa2, 0xbd, 0x68, 0xa2, 0xfd, 0x3d);
|
||||
DEFINE_GUID(GUID_BUTTON8,0xa6f70e64, 0x3a67, 0x4552, 0xa0, 0xc4, 0x17, 0x38, 0x4e, 0x49, 0x5a, 0x55);
|
||||
DEFINE_GUID(GUID_BUTTON9,0xbf55916c, 0xd6e6, 0x4fd3, 0x94, 0x62, 0x55, 0xd6, 0x9d, 0xb, 0xe7, 0x9c);
|
||||
DEFINE_GUID(GUID_BUTTON10,0x95f1b222, 0x1159, 0x4f9a, 0xb6, 0xe4, 0x6e, 0xde, 0xdf, 0xc7, 0x56, 0x9b);
|
||||
DEFINE_GUID(GUID_BUTTON11,0xf2dff7da, 0xf458, 0x4b61, 0xa2, 0x15, 0x62, 0xd0, 0x56, 0x48, 0x6, 0x53);
|
||||
DEFINE_GUID(GUID_BUTTON12,0x6a860858, 0x9b68, 0x4da6, 0xb3, 0x2a, 0x55, 0xe9, 0xe9, 0x75, 0xbe, 0xeb);
|
||||
DEFINE_GUID(GUID_BUTTON13,0x42ffb4d9, 0x7f95, 0x475e, 0x9c, 0x97, 0x82, 0xa0, 0x2b, 0xdc, 0x7e, 0xb6);
|
||||
DEFINE_GUID(GUID_BUTTON14,0x215008c8, 0xf09d, 0x48d7, 0x95, 0x2e, 0xc, 0x11, 0x8d, 0x6, 0xe8, 0xca);
|
||||
DEFINE_GUID(GUID_BUTTON15, 0xd1d1fa37, 0x1ee0, 0x4015, 0x9c, 0x33, 0x12, 0xcc, 0x42, 0x57, 0x60, 0x1);
|
||||
DEFINE_GUID(GUID_PEN_TIMESTAMP1, 0x413a7d1a, 0xeede, 0x45ce, 0xa4, 0x32, 0x80, 0x88, 0xca, 0x9e, 0x8e, 0x4a);
|
||||
DEFINE_GUID(GUID_PEN_TIMESTAMP2, 0x876c825, 0xcdc, 0x4395, 0xbf, 0x9b, 0x36, 0x7e, 0x69, 0x8a, 0x75, 0x56);
|
||||
DEFINE_GUID(GUID_WIDTH, 0xbaabe94d, 0x2712, 0x48f5, 0xbe, 0x9d, 0x8f, 0x8b, 0x5e, 0xa0, 0x71, 0x1a);
|
||||
DEFINE_GUID(GUID_HEIGHT, 0xe61858d2, 0xe447, 0x4218, 0x9d, 0x3f, 0x18, 0x86, 0x5c, 0x20, 0x3d, 0xf4);
|
||||
DEFINE_GUID(GUID_FINGERCONTACTCONFIDENCE, 0xe706c804, 0x57f0, 0x4f00, 0x8a, 0x0c, 0x85, 0x3d, 0x57, 0x78, 0x9b, 0xe9);
|
||||
DEFINE_GUID(GUID_TEMPID, 0x2585b91, 0x49b, 0x4750, 0x96, 0x15, 0xdf, 0x89, 0x48, 0xab, 0x3c, 0x9c);
|
||||
|
||||
const GUID FAR KNOWN_GUIDS[38] =
|
||||
{
|
||||
{ 0x598a6a8f, 0x52c0, 0x4ba0, { 0x93, 0xaf, 0xaf, 0x35, 0x74, 0x11, 0xa5, 0x61 } },
|
||||
{ 0xb53f9f75, 0x04e0, 0x4498, { 0xa7, 0xee, 0xc3, 0x0d, 0xbb, 0x5a, 0x90, 0x11 } },
|
||||
{ 0x735adb30, 0x0ebb, 0x4788, { 0xa0, 0xe4, 0x0f, 0x31, 0x64, 0x90, 0x05, 0x5d } },
|
||||
{ 0x6e0e07bf, 0xafe7, 0x4cf7, { 0x87, 0xd1, 0xaf, 0x64, 0x46, 0x20, 0x84, 0x18 } },
|
||||
{ 0x436510c5, 0xfed3, 0x45d1, { 0x8b, 0x76, 0x71, 0xd3, 0xea, 0x7a, 0x82, 0x9d } },
|
||||
{ 0x78a81b56, 0x0935, 0x4493, { 0xba, 0xae, 0x00, 0x54, 0x1a, 0x8a, 0x16, 0xc4 } },
|
||||
{ 0x7307502d, 0xf9f4, 0x4e18, { 0xb3, 0xf2, 0x2c, 0xe1, 0xb1, 0xa3, 0x61, 0x0c } },
|
||||
{ 0x6da4488b, 0x5244, 0x41ec, { 0x90, 0x5b, 0x32, 0xd8, 0x9a, 0xb8, 0x08, 0x09 } },
|
||||
{ 0x8b7fefc4, 0x96aa, 0x4bfe, { 0xac, 0x26, 0x8a, 0x5f, 0x0b, 0xe0, 0x7b, 0xf5 } },
|
||||
{ 0xa8d07b3a, 0x8bf0, 0x40b0, { 0x95, 0xa9, 0xb8, 0x0a, 0x6b, 0xb7, 0x87, 0xbf } },
|
||||
{ 0x0e932389, 0x1d77, 0x43af, { 0xac, 0x00, 0x5b, 0x95, 0x0d, 0x6d, 0x4b, 0x2d } },
|
||||
{ 0x029123b4, 0x8828, 0x410b, { 0xb2, 0x50, 0xa0, 0x53, 0x65, 0x95, 0xe5, 0xdc } },
|
||||
{ 0x82dec5c7, 0xf6ba, 0x4906, { 0x89, 0x4f, 0x66, 0xd6, 0x8d, 0xfc, 0x45, 0x6c } },
|
||||
{ 0x0d324960, 0x13b2, 0x41e4, { 0xac, 0xe6, 0x7a, 0xe9, 0xd4, 0x3d, 0x2d, 0x3b } },
|
||||
{ 0x7f7e57b7, 0xbe37, 0x4be1, { 0xa3, 0x56, 0x7a, 0x84, 0x16, 0x0e, 0x18, 0x93 } },
|
||||
{ 0x5d5d5e56, 0x6ba9, 0x4c5b, { 0x9f, 0xb0, 0x85, 0x1c, 0x91, 0x71, 0x4e, 0x56 } },
|
||||
{ 0x6a849980, 0x7c3a, 0x45b7, { 0xaa, 0x82, 0x90, 0xa2, 0x62, 0x95, 0x0e, 0x89 } },
|
||||
{ 0x33c1df83, 0xecdb, 0x44f0, { 0xb9, 0x23, 0xdb, 0xd1, 0xa5, 0xb2, 0x13, 0x6e } },
|
||||
{ 0x5329cda5, 0xfa5b, 0x4ed2, { 0xbb, 0x32, 0x83, 0x46, 0x01, 0x72, 0x44, 0x28 } },
|
||||
{ 0x002df9af, 0xdd8c, 0x4949, { 0xba, 0x46, 0xd6, 0x5e, 0x10, 0x7d, 0x1a, 0x8a } },
|
||||
{ 0x9d32b7ca, 0x1213, 0x4f54, { 0xb7, 0xe4, 0xc9, 0x05, 0x0e, 0xe1, 0x7a, 0x38 } },
|
||||
{ 0xe71caab9, 0x8059, 0x4c0d, { 0xa2, 0xdb, 0x7c, 0x79, 0x54, 0x47, 0x8d, 0x82 } },
|
||||
{ 0x5c0b730a, 0xf394, 0x4961, { 0xa9, 0x33, 0x37, 0xc4, 0x34, 0xf4, 0xb7, 0xeb } },
|
||||
{ 0x2812210f, 0x871e, 0x4d91, { 0x86, 0x07, 0x49, 0x32, 0x7d, 0xdf, 0x0a, 0x9f } },
|
||||
{ 0x8359a0fa, 0x2f44, 0x4de6, { 0x92, 0x81, 0xce, 0x5a, 0x89, 0x9c, 0xf5, 0x8f } },
|
||||
{ 0x4c4642dd, 0x479e, 0x4c66, { 0xb4, 0x40, 0x1f, 0xcd, 0x83, 0x95, 0x8f, 0x00 } },
|
||||
{ 0xce2d9a8a, 0xe58e, 0x40ba, { 0x93, 0xfa, 0x18, 0x9b, 0xb3, 0x90, 0x00, 0xae } },
|
||||
{ 0xc3c7480f, 0x5839, 0x46ef, { 0xa5, 0x66, 0xd8, 0x48, 0x1c, 0x7a, 0xfe, 0xc1 } },
|
||||
{ 0xea2278af, 0xc59d, 0x4ef4, { 0x98, 0x5b, 0xd4, 0xbe, 0x12, 0xdf, 0x22, 0x34 } },
|
||||
{ 0xb8630dc9, 0xcc5c, 0x4c33, { 0x8d, 0xad, 0xb4, 0x7f, 0x62, 0x2b, 0x8c, 0x79 } },
|
||||
{ 0x15e2f8e6, 0x6381, 0x4e8b, { 0xa9, 0x65, 0x01, 0x1f, 0x7d, 0x7f, 0xca, 0x38 } },
|
||||
{ 0x7066fbe4, 0x473e, 0x4675, { 0x9c, 0x25, 0x00, 0x26, 0x82, 0x9b, 0x40, 0x1f } },
|
||||
{ 0xbbc85b9a, 0xade6, 0x4093, { 0xb3, 0xbb, 0x64, 0x1f, 0xa1, 0xd3, 0x7a, 0x1a } },
|
||||
{ 0x039143d3, 0x78cb, 0x449c, { 0xa8, 0xe7, 0x67, 0xd1, 0x88, 0x64, 0xc3, 0x32 } },
|
||||
{ 0x67743782, 0x0ee5, 0x419a, { 0xa1, 0x2b, 0x27, 0x3a, 0x9e, 0xc0, 0x8f, 0x3d } },
|
||||
{ 0xf0720328, 0x663b, 0x418f, { 0x85, 0xa6, 0x95, 0x31, 0xae, 0x3e, 0xcd, 0xfa } },
|
||||
{ 0xa1718cdd, 0x0dac, 0x4095, { 0xa1, 0x81, 0x7b, 0x59, 0xcb, 0x10, 0x6b, 0xfb } },
|
||||
{ 0x810a74d2, 0x6ee2, 0x4e39, { 0x82, 0x5e, 0x6d, 0xef, 0x82, 0x6a, 0xff, 0xc5 } },
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
** InkDrawingAttributes **
|
||||
DISPID_DAHeight = 1
|
||||
DISPID_DAColor
|
||||
DISPID_DAWidth
|
||||
DISPID_DAFitToCurve
|
||||
DISPID_DAIgnorePressure
|
||||
DISPID_DAAntiAliased
|
||||
DISPID_DATransparency
|
||||
DISPID_DARasterOperation
|
||||
DISPID_DAPenTip
|
||||
DISPID_DAClone
|
||||
DISPID_DAExtendedProperties
|
||||
|
||||
|
||||
DISPID_DAFitToCurve
|
||||
DISPID_DAIgnorePressure
|
||||
DISPID_DAAntiAliased
|
||||
DISPID_DARasterOperation
|
||||
DISPID_DAPenTip
|
||||
DISPID_DAClone
|
||||
DISPID_DAExtendedProperties
|
||||
|
||||
|
||||
** InkBoundingBoxMode **
|
||||
IBBM_Default = 0,
|
||||
IBBM_NoCurveFit,
|
||||
IBBM_CurveFit,
|
||||
IBBM_PointsOnly,
|
||||
IBBM_Union
|
||||
|
||||
** InkRasterOperation **
|
||||
IRO_Black = 1,
|
||||
IRO_NotMergePen = 2,
|
||||
IRO_MaskNotPen = 3,
|
||||
IRO_NotCopyPen = 4,
|
||||
IRO_MaskPenNot = 5,
|
||||
IRO_Not = 6,
|
||||
IRO_XOrPen = 7,
|
||||
IRO_NotMaskPen = 8,
|
||||
IRO_MaskPen = 9,
|
||||
IRO_NotXOrPen = 10,
|
||||
IRO_NoOperation = 11,
|
||||
IRO_MergeNotPen = 12,
|
||||
IRO_CopyPen = 13,
|
||||
IRO_MergePenNot = 14,
|
||||
IRO_MergePen = 15,
|
||||
IRO_White = 16
|
||||
|
||||
|
||||
|
||||
If we scale the Ink Space Rect (canvas_) to or from HiMetric and using the metrics,
|
||||
do we get anything useful?
|
||||
- Valerio
|
||||
|
||||
|
||||
|
||||
To save received ISF from Messenger, put this code in src/chat/chatmaster.cpp at line 1324, below "case FORMAT_ISF:" but above the "break;":
|
||||
---
|
||||
QFile file( "~/output.isf" );
|
||||
file.open( QIODevice::WriteOnly );
|
||||
file.write( QByteArray::fromBase64( inkEncodedData ) );
|
||||
file.close();
|
||||
---
|
||||
You probably have to change the file path :P
|
||||
- Valerio
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
About LibISF-Qt:
|
||||
============
|
||||
|
||||
LibISF-Qt is a Qt4 library made to encode and decode Microsoft's
|
||||
Ink Serialized Format (ISF) files.
|
||||
|
||||
Q. What the hell is this?
|
||||
A. It's a library, written in C++/Qt4, to read and write ISF
|
||||
image files.
|
||||
|
||||
Q. How does this library differ from aMSN's or Emesene's?
|
||||
A. It's written with Qt, which makes it easily portable on
|
||||
a lot of different architectures; also Qt's new licensing
|
||||
terms (LGPL) make it possible for everyone to use it
|
||||
easily.
|
||||
The library supports more ISF features than those two,
|
||||
since we've written it using the official specification.
|
||||
Moreover, aMSN's and Emesene's are not distributed by
|
||||
theirselves, ours is.
|
||||
|
||||
Q. What's the status of completion of the library, and which
|
||||
ISF features does/will support?
|
||||
A. Please see the TODO file to have an overview.
|
||||
|
||||
|
||||
|
||||
Compiling and installing:
|
||||
=================
|
||||
|
||||
LibISF-Qt uses CMake, a quick and clean alternative to Autotools.
|
||||
|
||||
First create a new directory within the one which contains this
|
||||
file (we'll have the library built there):
|
||||
$ mkdir build
|
||||
Enter it and run CMake:
|
||||
$ cd build
|
||||
$ cmake -D CMAKE_INSTALL_PREFIX=/usr ..
|
||||
Then, if everything went smoothly, build the library itself:
|
||||
$ make
|
||||
If everything went right again, install it:
|
||||
$ make install
|
||||
Aaand now you're set. :)
|
||||
|
||||
|
||||
|
||||
Documentation:
|
||||
=================
|
||||
|
||||
The ISF format is (albeit poorly*) documented: here's the
|
||||
sources we used.
|
||||
|
||||
- Original Microsoft ISF specification, made open with their
|
||||
Open Specification Promise:
|
||||
http://download.microsoft.com/download/0/B/E/0BE8BDD7-E5E8-422A-ABFD-4342ED7AD886/InkSerializedFormat(ISF)Specification.pdf
|
||||
- Quick explanation of the algorithms and other very useful
|
||||
details:
|
||||
http://synce.org/moin/FormatDocumentation/InkSerializedFormat
|
||||
- Original code from aMSN:
|
||||
https://amsn.svn.sourceforge.net/svnroot/amsn/trunk/amsn/utils/tclISF/src
|
||||
- Original code from emesene:
|
||||
https://emesene.svn.sourceforge.net/svnroot/emesene/trunk/emesene/pyisf
|
||||
|
||||
* = The specification was probably not meant for use by
|
||||
developers wanting to write an alternative implementation;
|
||||
there's a lot of guesswork to be done.
|
||||
|
||||
|
||||
|
||||
Licensing
|
||||
=========
|
||||
|
||||
Only the Oxygen icon, draw-eraser, is released under LGPL 3.0 (see http://www.oxygen-icons.org/). See COPYING_ICONS for full license text.
|
||||
|
||||
The remainder of ISF-qt is released under LGPL2.1. See COPYING for full license text.
|
||||
|
||||
|
||||
More Information
|
||||
================
|
||||
|
||||
For more information about LibISF-Qt, ask us:
|
||||
- forum board at http://www.kmess.org/board/
|
||||
- e-mail at project@kmess.org
|
||||
- IRC at #kmess on irc.freenode.net
|
||||
@@ -0,0 +1,41 @@
|
||||
libISF-Qt (Ink Serialized Format) TODO
|
||||
-----------------------------------
|
||||
|
||||
OUTSTANDING
|
||||
-----------
|
||||
- Bit Packing Byte codec:
|
||||
- Encoding
|
||||
- Bit Packing Word codec:
|
||||
- Encoding
|
||||
- Decoding
|
||||
- Bit Packing Long codec:
|
||||
- Encoding
|
||||
- Decoding
|
||||
- Read and write user-defined custom tags
|
||||
- Interpret, use and write pressure information
|
||||
- Associating text recognized by OCR to the drawn strokes
|
||||
- Modify strokes
|
||||
|
||||
DONE
|
||||
----
|
||||
- State machine:
|
||||
- Parser
|
||||
- Writer
|
||||
- Multibyte values (int,uint,float):
|
||||
- Encoding
|
||||
- Decoding
|
||||
- Huffman codec:
|
||||
- Encoding
|
||||
- Decoding
|
||||
- Bit Packing codec:
|
||||
- Encoding
|
||||
- Decoding
|
||||
- Bit Packing Byte codec:
|
||||
- Decoding
|
||||
- Properly parse generated ISF test data
|
||||
- Generate new ISF data
|
||||
- Parse ISF data from WLM
|
||||
- Add new strokes to an IsfDrawing
|
||||
- Stroke attributes: width, colour, pressure
|
||||
- Export IsfDrawing to raw-isf, isf-base64 and fortified-gif
|
||||
- Delete strokes
|
||||
@@ -0,0 +1,19 @@
|
||||
# Find LibISF-Qt
|
||||
# Find the Ink Serialized Format library and includes
|
||||
# This module defines
|
||||
# ISFQT_FOUND - If false, do not try to use ISF-Qt
|
||||
# ISFQT_INCLUDE_DIR - where to find isfqtdrawing.h and friends
|
||||
# ISFQT_LIBRARIES - the libraries needed to use ISF-Qt
|
||||
# ISFQT_LIBRARY - Where to find the ISF-Qt library (generally not used)
|
||||
|
||||
FIND_PATH( ISFQT_INCLUDE_DIR isfqtdrawing.h /usr/include/isf-qt /usr/local/include/isf-qt )
|
||||
FIND_LIBRARY( ISFQT_LIBRARY NAMES isf-qt PATH /usr/lib /usr/local/lib )
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ISFQT_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE( FindPackageHandleStandardArgs )
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS( ISFQT DEFAULT_MSG ISFQT_LIBRARY ISFQT_INCLUDE_DIR )
|
||||
|
||||
IF( ISFQT_FOUND )
|
||||
SET( ISFQT_LIBRARIES ${ISFQT_LIBRARY} )
|
||||
ENDIF( ISFQT_FOUND )
|
||||
@@ -0,0 +1,14 @@
|
||||
# IsfQtConfig.cmake is generated by CMake from cmake/IsfQtConfig.cmake.in.
|
||||
# Any changed value in this file will be overwritten by CMake.
|
||||
|
||||
# Set the version numbers
|
||||
SET( ISFQT_VERSION @ISFQT_VERSION@ )
|
||||
SET( ISFQT_VERSION_STRING "@ISFQT_VERSION_STRING@" )
|
||||
|
||||
# Set the directories
|
||||
IF( NOT ISFQT_INSTALL_DIR )
|
||||
SET( ISFQT_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@" )
|
||||
ENDIF( NOT ISFQT_INSTALL_DIR )
|
||||
|
||||
SET( ISFQT_INCLUDE_DIR "@INCLUDE_INSTALL_DIR@" )
|
||||
SET( ISFQT_LIBRARY_DIR "@LIB_INSTALL_DIR@" )
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
# This file is included here because the standard FindGIF.cmake file
|
||||
# requires the CHECK_STRUCT_MEMBER macro. It wasn't on my PC, at least, so
|
||||
# I include a copy of the macro here for giflib to use.
|
||||
|
||||
MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
|
||||
SET(_INCLUDE_FILES)
|
||||
FOREACH (it ${_HEADER})
|
||||
SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
|
||||
ENDFOREACH (it)
|
||||
|
||||
SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
|
||||
${_INCLUDE_FILES}
|
||||
int main()
|
||||
{
|
||||
${_STRUCT}* tmp;
|
||||
tmp->${_MEMBER};
|
||||
return 0;
|
||||
}
|
||||
")
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
|
||||
|
||||
ENDMACRO (CHECK_STRUCT_MEMBER)
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* LibISF-Qt configuration file
|
||||
*
|
||||
* The value for these defines is controlled by CMake at configuration time.
|
||||
*/
|
||||
|
||||
// Define the application version
|
||||
#define ISFQT_VERSION "${ISFQT_VERSION}"
|
||||
|
||||
// Define if debug output should be enabled
|
||||
#define ISFQT_DEBUG ${ISFQT_DEBUG_OUTPUT}
|
||||
|
||||
// Define if fortified-GIF support is enabled
|
||||
#define ISFQT_GIF_ENABLED ${GIF_ENABLED}
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>pics/draw-eraser.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
After Width: | Height: | Size: 722 B |
@@ -0,0 +1,16 @@
|
||||
|
||||
<!--#########-->
|
||||
</div>
|
||||
|
||||
<address>
|
||||
<small>Generated on $datetime for $projectname by
|
||||
<a href="http://www.doxygen.org/index.html">
|
||||
<img src="doxygen.png" alt="doxygen" align="middle" border="0">
|
||||
</a>
|
||||
$doxygenversion
|
||||
</small>
|
||||
</address>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<title>$title</title>
|
||||
<link href="$relpath$doxygen.css" rel="stylesheet" type="text/css"></link>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<h1>ISF-Qt developer documentation
|
||||
<img class="logo" src="http://kmess.org/projects/isf-qt/isf-qt-logo.png" width="250" height="110" alt="">
|
||||
</h1>
|
||||
|
||||
<div id="menu">
|
||||
<ul>
|
||||
<li><a href="index.html">Main Page</a></li>
|
||||
<li><a href="modules.html">Modules</a></li>
|
||||
<li><a href="hierarchy.html">Class Hierarchy</a></li>
|
||||
<li><a href="annotated.html">Class List</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<!--#########-->
|
||||
@@ -0,0 +1,393 @@
|
||||
|
||||
/* standard fonts */
|
||||
|
||||
body,
|
||||
td,
|
||||
th {
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
body,
|
||||
td {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: "Courier New", monospace;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
/* main top title */
|
||||
font-size: 140%;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
|
||||
background-color: #99ccff;
|
||||
color: #0071BB;
|
||||
}
|
||||
|
||||
img {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#content h1
|
||||
{
|
||||
/* main content title */
|
||||
text-align: left;
|
||||
font-size: 160%;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
color: #000;
|
||||
padding-bottom: 15px;
|
||||
|
||||
/* center the element too so the float doesn't interfere */
|
||||
position: relative;
|
||||
margin-left: -25%;
|
||||
width: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
|
||||
h2 {
|
||||
/* section title */
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
h2,
|
||||
h2 a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
|
||||
/* center the element too so the float doesn't interfere */
|
||||
position: relative;
|
||||
margin-left: -25%;
|
||||
width: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color: #0000cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
color: #ff0000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
#content li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
|
||||
/* layout of page */
|
||||
|
||||
html,body {
|
||||
background-color: #e6dede;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
background-color: #fff;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 0 10px 5px 10px;
|
||||
}
|
||||
|
||||
|
||||
/* menu and navigation */
|
||||
|
||||
.logo {
|
||||
float: right;
|
||||
display: inline;
|
||||
margin: 0 5px 5px 5px;
|
||||
}
|
||||
|
||||
#menu li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
float: left;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
#menu ul:after {
|
||||
clear: left;
|
||||
display: block;
|
||||
content: '.';
|
||||
line-height: 0%;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
overflow: none;
|
||||
}
|
||||
|
||||
/* for msie \*/
|
||||
* html #menu ul {
|
||||
height: 0.1em;
|
||||
}
|
||||
/* end of msie */
|
||||
|
||||
#menu ul,
|
||||
div.qindex {
|
||||
/* top index */
|
||||
background-color: #99ccff;
|
||||
border-bottom: 1px solid #000;
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
div.nav {
|
||||
/* directory location */
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.nav a.el {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
#menu a,
|
||||
div.qindex a {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
#menu a:hover,
|
||||
div.qindex a:hover {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
div.qindex a.qindexHL {
|
||||
/* highlighted menu option */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* element reference in text. may occur everywhere */
|
||||
|
||||
a.el,
|
||||
a.el:active,
|
||||
a.el:visited { color: #5F2994; }
|
||||
|
||||
a.el {
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.fragment {
|
||||
font-family: monospace
|
||||
}
|
||||
|
||||
pre.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin: 4px 8px 4px 2px;
|
||||
padding: 4px 6px 4px 4px;
|
||||
}
|
||||
|
||||
td.indexkey,
|
||||
td.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
background-color: #C9E2FF;
|
||||
padding: 2px 10px 2px 10px
|
||||
margin: 2px 0px 2px 0px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
td.indexkey {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
TR.memlist {
|
||||
/* separate member list page */
|
||||
background-color: #D6EEFF;
|
||||
}
|
||||
|
||||
/* not encountered
|
||||
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
|
||||
*/
|
||||
|
||||
/* source code highlights */
|
||||
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
|
||||
/* Member description header */
|
||||
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #C9E2FF;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mdRow {
|
||||
padding: 4px 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.md {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.mdname1 {
|
||||
font-weight: bold;
|
||||
color: #602020;
|
||||
}
|
||||
|
||||
td.mdname {
|
||||
/* parameter name in member description */
|
||||
font-weight: bold;
|
||||
color: #602020;
|
||||
}
|
||||
|
||||
.mdPrefix {
|
||||
/* template prefix in member description */
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
|
||||
/* member summary table */
|
||||
|
||||
.mdescLeft,
|
||||
.mdescRight {
|
||||
padding: 0 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #D3E9FF;
|
||||
border: 1px none #E0E0E0;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.memItemLeft,
|
||||
.memTemplItemLeft,
|
||||
.memItemRight,
|
||||
.memTemplItemRight {
|
||||
border-top: 1px solid #868686;
|
||||
background-color: #C9E2FF;
|
||||
font-size: 80%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.memItemLeft,
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
}
|
||||
|
||||
.memItemRight,
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
}
|
||||
|
||||
.memTemplParams {
|
||||
/* template prefix in function list */
|
||||
border-top: 1px solid #868686;
|
||||
background-color: #C9E2FF;
|
||||
font-size: 80%;
|
||||
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
|
||||
/* member sections */
|
||||
|
||||
.memitem {
|
||||
padding-bottom: 2ex;
|
||||
}
|
||||
|
||||
.memproto {
|
||||
border-top: 1px dashed #333;
|
||||
padding: 1ex 4px 0 4px;
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.memproto td {
|
||||
color: #333;
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.memname {
|
||||
white-space: nowrap;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
.memdoc {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.memdoc p:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0.5ex;
|
||||
margin-right: 4em;
|
||||
}
|
||||
|
||||
.memdoc dl,
|
||||
.memdoc dt,
|
||||
.memdoc dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.paramkey {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.paramtype {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: #602020;
|
||||
font-style: italic;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.directory p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1 @@
|
||||
#include "isfinkcanvas.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "isfqt.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "isfqtdrawing.h"
|
||||
@@ -0,0 +1,175 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFINKCANVAS_H
|
||||
#define ISFINKCANVAS_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "isfqt.h"
|
||||
#include "isfqtdrawing.h"
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class InkCanvas
|
||||
* @brief This is a control designed for the drawing and display of Ink.
|
||||
*
|
||||
* InkCanvas is used for drawing and displaying Ink. The currently displayed Ink drawing can be retrieved
|
||||
* or set using the drawing() and setDrawing() methods.
|
||||
*
|
||||
* To set the properties of the current pen, use the setPenColor(), setPenSize() and setPenType() methods.
|
||||
* The supported pen types are outlined in the PenType enumeration documentation.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code
|
||||
* InkCanvas *canvas = new Isf::InkCanvas( this );
|
||||
* canvas->setPenColor( Qt::blue );
|
||||
* canvas->setPenSize( 10 );
|
||||
*
|
||||
* // the pen is now 10 pixels thick and blue.
|
||||
*
|
||||
* canvas->setPenType( EraserPen );
|
||||
*
|
||||
* // now an eraser will be used and strokes can be erased individually.
|
||||
* \endcode
|
||||
*
|
||||
* To return the currently displayed Ink as a QImage, use image(). To return the raw ISF data, suitable
|
||||
* for saving to disk or sending over a network, use bytes().
|
||||
*
|
||||
* To write the ISF data directly to a QIODevice, such as a file, use the save() method.
|
||||
*
|
||||
* Connect to the inkChanged() signal to be notified when the drawing displayed on the canvas changes,
|
||||
* either through strokes being drawn or deleted, or the current drawing being changed.
|
||||
*
|
||||
* @author Adam Goossens (adam@kmess.org)
|
||||
*/
|
||||
class InkCanvas : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public: // public enumerations
|
||||
/**
|
||||
* The various types of pens supported by InkCanvas.
|
||||
*
|
||||
* The DrawingPen is a standard pen for drawing new strokes onto the canvas.
|
||||
* The pen size and color are controlled by setPenSize() and setPenColor().
|
||||
*
|
||||
* The EraserPen is used for erasing individual strokes. Pixel-by-pixel erase is not
|
||||
* yet supported.
|
||||
*/
|
||||
enum PenType
|
||||
{
|
||||
DrawingPen, ///< Used to draw Ink
|
||||
EraserPen ///< Used to erase by stroke
|
||||
};
|
||||
|
||||
public: // public constructors
|
||||
InkCanvas( QWidget *parent = 0 );
|
||||
~InkCanvas();
|
||||
|
||||
public: // public methods
|
||||
QByteArray bytes();
|
||||
Isf::Drawing *drawing();
|
||||
QImage image();
|
||||
bool isEmpty();
|
||||
QColor penColor();
|
||||
int penSize();
|
||||
PenType penType();
|
||||
void save( QIODevice &device, bool base64 = false );
|
||||
void setDrawing( Isf::Drawing *drawing );
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void setCanvasColor( QColor newColor );
|
||||
void setPenColor( QColor newColor );
|
||||
void setPenSize( int pixels );
|
||||
void setPenType( PenType type );
|
||||
|
||||
protected: // protected methods
|
||||
void mousePressEvent( QMouseEvent *event );
|
||||
void mouseMoveEvent( QMouseEvent *event );
|
||||
void mouseReleaseEvent( QMouseEvent *event );
|
||||
void paintEvent( QPaintEvent *event );
|
||||
void resizeEvent( QResizeEvent *event );
|
||||
|
||||
private: // private methods
|
||||
void drawLineTo( const QPoint &endPoint );
|
||||
void clearBuffer();
|
||||
void updateCursor();
|
||||
|
||||
private: // private attributes
|
||||
/// Color of the canvas background
|
||||
QColor canvasColor_;
|
||||
/// Color of current pen
|
||||
QColor color_;
|
||||
/// Cursor pixmap
|
||||
QPixmap cursorPixmap_;
|
||||
/// Current cursor
|
||||
QCursor cursor_;
|
||||
/// It's true if the erase brush was selected
|
||||
bool erasingImage_;
|
||||
/// Current drawing being manipulated
|
||||
Isf::Drawing *drawing_;
|
||||
/// Initial drawing, can be overridden with drawing_
|
||||
Isf::Drawing initialDrawing_;
|
||||
/// Last point where the mouse pointer was released
|
||||
QPoint lastPoint_;
|
||||
/// True if the user is painting
|
||||
bool scribbling_;
|
||||
/// Pen size, in pixels.
|
||||
int penSize_;
|
||||
/// Pen type
|
||||
PenType penType_;
|
||||
/// The current stroke being drawn
|
||||
Isf::Stroke *currentStroke_;
|
||||
/// The pixmap buffer where in progress strokes are drawn
|
||||
QPixmap bufferPixmap_;
|
||||
/// Cache pixmap so the Ink isn't redrawn on every mouse move
|
||||
QPixmap isfCachePixmap_;
|
||||
/// Dirty value used to update isf cache pixmap.
|
||||
bool drawingDirty_;
|
||||
|
||||
signals:
|
||||
/// Emitted when the ink representation is modified (stroke drawn,
|
||||
/// stroke deleted, current drawing changed).
|
||||
void inkChanged();
|
||||
};
|
||||
|
||||
|
||||
|
||||
}; // namespace Isf
|
||||
|
||||
|
||||
|
||||
#endif // ISFINKCANVAS_H
|
||||
@@ -0,0 +1,374 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFQT_H
|
||||
#define ISFQT_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMatrix>
|
||||
#include <QPointF>
|
||||
#include <QRectF>
|
||||
#include <QSizeF>
|
||||
#include <QtGlobal>
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
// Forward declarations
|
||||
class Drawing;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Possible error return values returned by the ISF library.
|
||||
*/
|
||||
enum IsfError
|
||||
{
|
||||
ISF_ERROR_NONE = 0 ///< No error
|
||||
|
||||
/// Stream reader errors
|
||||
, ISF_ERROR_BAD_VERSION ///< Incompatible ISF version
|
||||
, ISF_ERROR_BAD_STREAMSIZE ///< Stream size of ISF data is too small
|
||||
, ISF_ERROR_INVALID_STREAM ///< The stream contains wrong or duplicated tags
|
||||
, ISF_ERROR_INVALID_PAYLOAD ///< A tag's payload was empty
|
||||
, ISF_ERROR_INVALID_BLOCK ///< A block had invalid contents
|
||||
|
||||
/// Other errors
|
||||
, ISF_ERROR_INTERNAL ///< An error within the code has occurred
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of predefined packet properties.
|
||||
*
|
||||
* These are used with strokes and their attributes.
|
||||
* The Metrics structure defines how to interpret these properties.
|
||||
*/
|
||||
enum PacketProperty
|
||||
{
|
||||
KNOWN_GUID_BASE_INDEX = 50
|
||||
, GUID_X = KNOWN_GUID_BASE_INDEX + 0
|
||||
, GUID_Y = KNOWN_GUID_BASE_INDEX + 1
|
||||
, GUID_Z // = et cetera
|
||||
, GUID_PACKET_STATUS
|
||||
, GUID_TIMER_TICK
|
||||
, GUID_SERIAL_NUMBER
|
||||
, GUID_NORMAL_PRESSURE
|
||||
, GUID_TANGENT_PRESSURE
|
||||
, GUID_BUTTON_PRESSURE
|
||||
, GUID_X_TILT_ORIENTATION
|
||||
, GUID_Y_TILT_ORIENTATION // = KNOWN_GUID_BASE_INDEX + 10
|
||||
, GUID_AZIMUTH_ORIENTATION
|
||||
, GUID_ALTITUDE_ORIENTATION
|
||||
, GUID_TWIST_ORIENTATION
|
||||
, GUID_PITCH_ROTATION
|
||||
, GUID_ROLL_ROTATION
|
||||
, GUID_YAW_ROTATION
|
||||
, GUID_PEN_STYLE
|
||||
, GUID_COLORREF
|
||||
, GUID_PEN_WIDTH
|
||||
, GUID_PEN_HEIGHT // = KNOWN_GUID_BASE_INDEX + 20
|
||||
, GUID_PEN_TIP
|
||||
, GUID_DRAWING_FLAGS
|
||||
, GUID_CURSORID
|
||||
, GUID_WORD_ALTERNATES
|
||||
, GUID_CHAR_ALTERNATES
|
||||
, GUID_INKMETRICS
|
||||
, GUID_GUIDE_STRUCTURE
|
||||
, GUID_TIME_STAMP
|
||||
, GUID_LANGUAGE
|
||||
, GUID_TRANSPARENCY // = KNOWN_GUID_BASE_INDEX + 30
|
||||
, GUID_CURVE_FITTING_ERROR
|
||||
, GUID_RECO_LATTICE
|
||||
, GUID_CURSORDOWN
|
||||
, GUID_SECONDARYTIPSWITCH
|
||||
, GUID_BARRELDOWN
|
||||
, GUID_TABLETPICK
|
||||
, GUID_ROP // = KNOWN_GUID_BASE_INDEX + 37
|
||||
, KNOWN_GUID_LAST_INDEX
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Available pen tips.
|
||||
*/
|
||||
enum PenTip
|
||||
{
|
||||
Ball = 0 ///< The pen tip is a circle
|
||||
, Rectangle = 1 ///< The pen tip is a square or a rectangle
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Stroke drawing flags.
|
||||
*/
|
||||
enum StrokeFlag
|
||||
{
|
||||
FitToCurve = 0x0001 ///< Fit the lines between stroke points to Bezier curves
|
||||
, IgnorePressure = 0x0004 ///< Ignore the pressure level for this stroke
|
||||
, IsHighlighter = 0x0100 ///< This stroke is an highlighter stroke
|
||||
, IsRectangle = 0x0200 ///< Meaning unknown
|
||||
};
|
||||
Q_DECLARE_FLAGS( StrokeFlags, StrokeFlag )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( StrokeFlags )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Units used for metric measurements.
|
||||
*
|
||||
* @see http://msdn.microsoft.com/en-us/library/ms840884.aspx
|
||||
*/
|
||||
enum MetricScale
|
||||
{
|
||||
UNIT_UNUSED = -1
|
||||
, UNIT_DEFAULT = 0
|
||||
, UNIT_INCH = 1
|
||||
, UNIT_CENTIMETER = 2
|
||||
, UNIT_DEGREE = 3
|
||||
, UNIT_RADIAN = 4
|
||||
, UNIT_SECOND = 5
|
||||
, UNIT_POUND = 6
|
||||
, UNIT_GRAM = 7
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A single metric.
|
||||
*
|
||||
* It is a set of values representing what kind of values some
|
||||
* type of measurement will assume.
|
||||
*/
|
||||
struct Metric
|
||||
{
|
||||
/// Constructor for invalid metrics
|
||||
Metric()
|
||||
{
|
||||
}
|
||||
/// Initialized constructor
|
||||
Metric( qint64 vMin, qint64 vMax, MetricScale vUnits, float vResolution )
|
||||
: min( vMin )
|
||||
, max( vMax )
|
||||
, units( vUnits )
|
||||
, resolution( vResolution )
|
||||
{
|
||||
}
|
||||
|
||||
/// Minimum value
|
||||
qint64 min;
|
||||
/// Maximum value
|
||||
qint64 max;
|
||||
/// Measurement unit
|
||||
MetricScale units;
|
||||
/// Resolution
|
||||
float resolution;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A table of metrics.
|
||||
*
|
||||
* The default metric values are hard-coded here, different values read from the stream
|
||||
* will override these.
|
||||
*/
|
||||
struct Metrics
|
||||
{
|
||||
/// Constructor
|
||||
Metrics()
|
||||
{
|
||||
items[ GUID_X ] = Metric( 0, 12699, UNIT_CENTIMETER, 1000 );
|
||||
items[ GUID_Y ] = Metric( 0, 9649, UNIT_CENTIMETER, 1000 );
|
||||
items[ GUID_Z ] = Metric( -1023, 1023, UNIT_CENTIMETER, 1000 );
|
||||
items[ GUID_PACKET_STATUS ] = Metric( 0, 1023, UNIT_DEFAULT, 1 );
|
||||
items[ GUID_TIMER_TICK ] = Metric( 0, 1023, UNIT_DEFAULT, 1 );
|
||||
items[ GUID_SERIAL_NUMBER ] = Metric( 0, 1023, UNIT_DEFAULT, 1 );
|
||||
items[ GUID_NORMAL_PRESSURE ] = Metric( 0, 3600, UNIT_DEGREE, 10 );
|
||||
items[ GUID_TANGENT_PRESSURE ] = Metric( 0, 3600, UNIT_DEGREE, 10 );
|
||||
items[ GUID_BUTTON_PRESSURE ] = Metric( 0, 3600, UNIT_DEGREE, 10 );
|
||||
items[ GUID_X_TILT_ORIENTATION ] = Metric( -900, 900, UNIT_DEGREE, 10 );
|
||||
items[ GUID_Y_TILT_ORIENTATION ] = Metric( 0, 3600, UNIT_DEGREE, 10 );
|
||||
items[ GUID_AZIMUTH_ORIENTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
items[ GUID_ALTITUDE_ORIENTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
items[ GUID_TWIST_ORIENTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
items[ GUID_PITCH_ROTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
items[ GUID_ROLL_ROTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
items[ GUID_YAW_ROTATION ] = Metric( -1, -1, UNIT_UNUSED, -1 );
|
||||
}
|
||||
|
||||
/// The list of metrics defined in this table
|
||||
QMap<int,Metric> items;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Drawing attributes for points.
|
||||
*/
|
||||
struct AttributeSet
|
||||
{
|
||||
/// Constructor
|
||||
AttributeSet()
|
||||
: color( Qt::black )
|
||||
, flags( 0x10 ) // Meaning unknown
|
||||
, penSize( 8.f, 8.f ) // Default pen is 8.0 pixels wide
|
||||
{
|
||||
}
|
||||
|
||||
/// The stroke color, optionally with alpha channel
|
||||
QColor color;
|
||||
/// Mask of StrokeFlags, @see StrokeFlags
|
||||
StrokeFlags flags;
|
||||
/// Dimensions of the pencil in pixels
|
||||
QSizeF penSize;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Drawing attributes for strokes.
|
||||
*/
|
||||
struct StrokeInfo
|
||||
{
|
||||
/// Constructor
|
||||
StrokeInfo()
|
||||
: hasPressureData( false )
|
||||
, hasXData( true )
|
||||
, hasYData( true )
|
||||
{
|
||||
}
|
||||
|
||||
/// Whether the stroke contains pressure info or not
|
||||
bool hasPressureData;
|
||||
/// Whether the stroke contains X coordinates or not
|
||||
bool hasXData;
|
||||
/// Whether the stroke contains Y coordinates or not
|
||||
bool hasYData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A single point within a stroke.
|
||||
*/
|
||||
struct Point
|
||||
{
|
||||
/// Empty constructor
|
||||
Point()
|
||||
: position( 0, 0 )
|
||||
, pressureLevel( 0 )
|
||||
{
|
||||
}
|
||||
/// Constructor with point only
|
||||
Point( const QPoint &point )
|
||||
: position( point )
|
||||
, pressureLevel( 0 )
|
||||
{
|
||||
}
|
||||
/// Constructor with point and pressure
|
||||
Point( const QPoint &point, const qint64 pressure )
|
||||
: position( point )
|
||||
, pressureLevel( pressure )
|
||||
{
|
||||
}
|
||||
|
||||
/// coordinates
|
||||
QPoint position;
|
||||
/// Pressure information
|
||||
qint64 pressureLevel;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A pen stroke.
|
||||
*/
|
||||
struct Stroke
|
||||
{
|
||||
/// Constructor
|
||||
Stroke()
|
||||
: attributes( 0 )
|
||||
, info( 0 )
|
||||
, metrics( 0 )
|
||||
, transform( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/// Bounding rectangle of this stroke
|
||||
QRect boundingRect;
|
||||
/// Link to the attributes of this stroke's points, if any
|
||||
AttributeSet *attributes;
|
||||
/// Link to this stroke's attributes, if any
|
||||
StrokeInfo *info;
|
||||
/// Link to this stroke's metrics, if any
|
||||
Metrics *metrics;
|
||||
/// List of points
|
||||
QList<Point> points;
|
||||
/// Link to this stroke's transformation, if any
|
||||
QMatrix *transform;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Conversion factor to convert from HiMetric units to pixels.
|
||||
*/
|
||||
const qreal HiMetricToPixel = 26.4572454037811;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class Stream
|
||||
* @brief The main class of the library.
|
||||
*
|
||||
* This class contains the only methods you need to transform ISF data
|
||||
* into strokes or pictures, and from strokes to ISF data.
|
||||
*/
|
||||
class Stream
|
||||
{
|
||||
|
||||
public: // Public static methods
|
||||
|
||||
static Drawing &reader( const QByteArray &isfData, bool decodeFromBase64 = false );
|
||||
static Drawing &readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64 = false );
|
||||
static bool supportsGif();
|
||||
static QByteArray writer( const Drawing &drawing, bool encodeToBase64 = false );
|
||||
static QByteArray writerGif( const Drawing &drawing, bool encodeToBase64 = false );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,152 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFQTDRAWING_H
|
||||
#define ISFQTDRAWING_H
|
||||
|
||||
#include <IsfQt>
|
||||
|
||||
#include <QMap>
|
||||
#include <QMatrix>
|
||||
#include <QPaintDevice>
|
||||
#include <QUuid>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class QByteArray;
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class Drawing
|
||||
* @brief This is a manipulable representation of an ISF stream.
|
||||
*
|
||||
* This class is a container for the data of ISF (Ink Serialized Format)
|
||||
* drawings. You can manipulate its contents, or create a new one and
|
||||
* fill it, then save it back to ISF format with the Isf::Stream methods.
|
||||
*
|
||||
* @see Isf::Stream
|
||||
* @author Adam Goossens (adam@kmess.org)
|
||||
* @author Valerio Pilo (valerio@kmess.org)
|
||||
*/
|
||||
class Drawing
|
||||
{
|
||||
friend class Stream;
|
||||
friend class TagsParser;
|
||||
friend class TagsWriter;
|
||||
|
||||
public: // public constructors
|
||||
Drawing();
|
||||
Drawing( const Drawing &other );
|
||||
~Drawing();
|
||||
|
||||
public: // public state retrieval methods
|
||||
AttributeSet *attributeSet( quint32 index );
|
||||
const QList<AttributeSet*> attributeSets();
|
||||
QRect boundingRect();
|
||||
void clear();
|
||||
IsfError error() const;
|
||||
bool isNull() const;
|
||||
QPixmap pixmap( const QColor backgroundColor = Qt::white );
|
||||
QSize size();
|
||||
Stroke *stroke( quint32 index );
|
||||
Stroke *strokeAtPoint( const QPoint &point );
|
||||
const QList<Stroke*> strokes();
|
||||
QMatrix *transform( quint32 index );
|
||||
const QList<QMatrix*> transforms();
|
||||
|
||||
public: // public manipulation methods
|
||||
qint32 addAttributeSet( AttributeSet *newAttributeSet );
|
||||
qint32 addStroke( Stroke *newStroke );
|
||||
qint32 addTransform( QMatrix *newTransform );
|
||||
bool deleteAttributeSet( quint32 index );
|
||||
bool deleteStroke( quint32 index );
|
||||
bool deleteStroke( Stroke *stroke ) ;
|
||||
bool deleteTransform( quint32 index );
|
||||
bool setCurrentAttributeSet( AttributeSet *attributeSet );
|
||||
bool setCurrentTransform( QMatrix *transform );
|
||||
|
||||
private: // Private properties
|
||||
/// List of attributes of the points in the drawing
|
||||
QList<AttributeSet*> attributeSets_;
|
||||
/// Bounding rectangle of the drawing
|
||||
QRect boundingRect_;
|
||||
/// Virtual drawing canvas dimensions
|
||||
QRect canvas_;
|
||||
/// Link to the currently used metric data
|
||||
Metrics *currentMetrics_;
|
||||
/// Link to the currently used point info data
|
||||
AttributeSet *currentAttributeSet_;
|
||||
/// Link to the currently used stroke info data
|
||||
StrokeInfo *currentStrokeInfo_;
|
||||
/// Link to the currently used transformation
|
||||
QMatrix *currentTransform_;
|
||||
/// Link to the default metric data
|
||||
Metrics defaultMetrics_;
|
||||
/// Link to the default point info data
|
||||
AttributeSet defaultAttributeSet_;
|
||||
/// Link to the default stroke info data
|
||||
StrokeInfo defaultStrokeInfo_;
|
||||
/// Link to the default transformation
|
||||
QMatrix defaultTransform_;
|
||||
/// Last parsing error (if there is one)
|
||||
IsfError error_;
|
||||
/// List of registered GUIDs
|
||||
QList<QUuid> guids_;
|
||||
/// Whether the drawing contains X coordinates or not
|
||||
bool hasXData_;
|
||||
/// Whether the drawing contains Y coordinates or not
|
||||
bool hasYData_;
|
||||
/// Whether the drawing is invalid or valid
|
||||
bool isNull_;
|
||||
/// Maximum GUID available in the drawing
|
||||
quint64 maxGuid_;
|
||||
/// Maximum thickness of the strokes
|
||||
QSizeF maxPenSize_;
|
||||
/// List of metrics used in the drawing
|
||||
QList<Metrics*> metrics_;
|
||||
/// Pixel size of the drawing
|
||||
QSize size_;
|
||||
/// List of information about the drawing's strokes
|
||||
QList<StrokeInfo*> strokeInfo_;
|
||||
/// List of strokes composing this drawing
|
||||
QList<Stroke*> strokes_;
|
||||
/// Transformation matrices
|
||||
QList<QMatrix*> transforms_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}; // namespace Isf
|
||||
|
||||
|
||||
|
||||
#endif // ISFQTDRAWING_H
|
||||
@@ -0,0 +1,4 @@
|
||||
[Project]
|
||||
Name=isf-qt
|
||||
Manager=KDevCMakeManager
|
||||
VersionControl=
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version = '1.0'?>
|
||||
<kdevelop>
|
||||
<general>
|
||||
<projectmanagement>KDevCustomProject</projectmanagement>
|
||||
<projectdirectory>.</projectdirectory>
|
||||
<absoluteprojectpath>false</absoluteprojectpath>
|
||||
<author>The KMess Development Team</author>
|
||||
<email>project@kmess.org</email>
|
||||
<version>0.1</version>
|
||||
<primarylanguage>C++</primarylanguage>
|
||||
<ignoreparts>
|
||||
<part>kdevtools</part>
|
||||
<part>kdevfileview</part>
|
||||
<part>kdevquickopen</part>
|
||||
<part>kdevabbrev</part>
|
||||
<part>kdevastyle</part>
|
||||
<part>kdevsnippet</part>
|
||||
<part>kdevctags2</part>
|
||||
<part>kdevfilelist</part>
|
||||
<part>kdevscripting</part>
|
||||
<part>kdevbookmarks</part>
|
||||
<part>kdevtexttools</part>
|
||||
<part>kdevdoxygen</part>
|
||||
<part>kdevdistpart</part>
|
||||
<part>kdevregexptest</part>
|
||||
</ignoreparts>
|
||||
<secondaryLanguages/>
|
||||
<projectname>isf-qt</projectname>
|
||||
<description>LibISF-Qt is a library to encode and decode Microsoft's Digital Ink format (Ink Serialized Format).</description>
|
||||
<defaultencoding/>
|
||||
<versioncontrol>kdevsubversion</versioncontrol>
|
||||
</general>
|
||||
<kdevcustomproject>
|
||||
<filelistdirectory>/home/valerio/kmess/trunk/contrib/isf-qt/</filelistdirectory>
|
||||
<run>
|
||||
<mainprogram>/home/valerio/kmess/trunk/contrib/isf-qt/build/tests/test_isfdrawing</mainprogram>
|
||||
<directoryradio>custom</directoryradio>
|
||||
<customdirectory>./build/</customdirectory>
|
||||
<programargs># tests/test1.isf</programargs>
|
||||
<terminal>false</terminal>
|
||||
<autocompile>false</autocompile>
|
||||
<envvars>
|
||||
<envvar value="en-US.UTF-8" name="LANG" />
|
||||
</envvars>
|
||||
<globaldebugarguments># tests/line2.isf</globaldebugarguments>
|
||||
<globalcwd>/home/valerio/kmess/trunk/contrib/isf-qt</globalcwd>
|
||||
<useglobalprogram>false</useglobalprogram>
|
||||
<autoinstall>false</autoinstall>
|
||||
<autokdesu>true</autokdesu>
|
||||
</run>
|
||||
<build>
|
||||
<buildtool>make</buildtool>
|
||||
<builddir>/home/valerio/kmess/trunk/contrib/isf-qt/build/</builddir>
|
||||
</build>
|
||||
<make>
|
||||
<abortonerror>false</abortonerror>
|
||||
<numberofjobs>2</numberofjobs>
|
||||
<dontact>false</dontact>
|
||||
<makebin>make</makebin>
|
||||
<selectedenvironment>default</selectedenvironment>
|
||||
<environments>
|
||||
<default/>
|
||||
</environments>
|
||||
<prio>0</prio>
|
||||
<defaulttarget/>
|
||||
<makeoptions/>
|
||||
</make>
|
||||
<filetypes>
|
||||
<filetype>*.h</filetype>
|
||||
<filetype>*.cpp</filetype>
|
||||
<filetype>CMakeLists.txt</filetype>
|
||||
<filetype>*.ui</filetype>
|
||||
</filetypes>
|
||||
<blacklist>
|
||||
<path>build</path>
|
||||
<path>build/CMakeFiles</path>
|
||||
<path>build/CMakeFiles/CompilerIdCXX</path>
|
||||
<path>build/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp</path>
|
||||
<path>build/isfqtconfig.h</path>
|
||||
<path>build/tests</path>
|
||||
<path>build/tests/decode</path>
|
||||
<path>build/tests/decode/ui_testdecode.h</path>
|
||||
</blacklist>
|
||||
<other>
|
||||
<prio>0</prio>
|
||||
<otherbin/>
|
||||
<defaulttarget/>
|
||||
<otheroptions/>
|
||||
<selectedenvironment>default</selectedenvironment>
|
||||
<environments>
|
||||
<Debug/>
|
||||
<Release/>
|
||||
<default/>
|
||||
</environments>
|
||||
</other>
|
||||
</kdevcustomproject>
|
||||
<kdevfilecreate>
|
||||
<filetypes/>
|
||||
<useglobaltypes>
|
||||
<type ext="ui" />
|
||||
<type ext="cpp" />
|
||||
<type ext="h" />
|
||||
</useglobaltypes>
|
||||
</kdevfilecreate>
|
||||
<kdevdoctreeview>
|
||||
<projectdoc>
|
||||
<userdocDir>html/</userdocDir>
|
||||
<apidocDir>html/</apidocDir>
|
||||
</projectdoc>
|
||||
<ignoreqt_xml/>
|
||||
<ignoredoxygen/>
|
||||
<ignorekdocs/>
|
||||
<ignoretocs/>
|
||||
<ignoredevhelp/>
|
||||
</kdevdoctreeview>
|
||||
<cppsupportpart>
|
||||
<filetemplates>
|
||||
<interfacesuffix>.h</interfacesuffix>
|
||||
<implementationsuffix>.cpp</implementationsuffix>
|
||||
</filetemplates>
|
||||
</cppsupportpart>
|
||||
<kdevcppsupport>
|
||||
<codecompletion>
|
||||
<includeGlobalFunctions>true</includeGlobalFunctions>
|
||||
<includeTypes>true</includeTypes>
|
||||
<includeEnums>true</includeEnums>
|
||||
<includeTypedefs>false</includeTypedefs>
|
||||
<automaticCodeCompletion>true</automaticCodeCompletion>
|
||||
<automaticArgumentsHint>true</automaticArgumentsHint>
|
||||
<automaticHeaderCompletion>true</automaticHeaderCompletion>
|
||||
<codeCompletionDelay>1500</codeCompletionDelay>
|
||||
<argumentsHintDelay>1500</argumentsHintDelay>
|
||||
<headerCompletionDelay>250</headerCompletionDelay>
|
||||
<showOnlyAccessibleItems>false</showOnlyAccessibleItems>
|
||||
<completionBoxItemOrder>0</completionBoxItemOrder>
|
||||
<howEvaluationContextMenu>true</howEvaluationContextMenu>
|
||||
<showCommentWithArgumentHint>true</showCommentWithArgumentHint>
|
||||
<statusBarTypeEvaluation>true</statusBarTypeEvaluation>
|
||||
<namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
|
||||
<processPrimaryTypes>true</processPrimaryTypes>
|
||||
<processFunctionArguments>true</processFunctionArguments>
|
||||
<preProcessAllHeaders>true</preProcessAllHeaders>
|
||||
<parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
|
||||
<resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
|
||||
<alwaysParseInBackground>true</alwaysParseInBackground>
|
||||
<usePermanentCaching>true</usePermanentCaching>
|
||||
<alwaysIncludeNamespaces>true</alwaysIncludeNamespaces>
|
||||
<includePaths>.;</includePaths>
|
||||
</codecompletion>
|
||||
<references/>
|
||||
<qt>
|
||||
<used>true</used>
|
||||
<version>4</version>
|
||||
<includestyle>4</includestyle>
|
||||
<root>/usr/lib/qt3</root>
|
||||
<designerintegration>ExternalDesigner</designerintegration>
|
||||
<qmake>/usr/bin/qmake</qmake>
|
||||
<designer>/usr/bin/designer</designer>
|
||||
<designerpluginpaths/>
|
||||
</qt>
|
||||
<creategettersetter>
|
||||
<prefixGet>get</prefixGet>
|
||||
<prefixSet>set</prefixSet>
|
||||
<prefixVariable/>
|
||||
<parameterName>value</parameterName>
|
||||
<inlineGet>true</inlineGet>
|
||||
<inlineSet>true</inlineSet>
|
||||
</creategettersetter>
|
||||
<splitheadersource>
|
||||
<enabled>false</enabled>
|
||||
<synchronize>true</synchronize>
|
||||
<orientation>Vertical</orientation>
|
||||
</splitheadersource>
|
||||
</kdevcppsupport>
|
||||
<kdevfileview>
|
||||
<groups>
|
||||
<group pattern="CMakeLists.txt;*.cmake;" name="CMake" />
|
||||
<group pattern="*.h;*.hxx" name="Header" />
|
||||
<group pattern="*.cpp;*.c;*.C;*.cxx" name="Sources" />
|
||||
<group pattern="*.ui" name="Qt Designer files" />
|
||||
<hidenonprojectfiles>true</hidenonprojectfiles>
|
||||
<hidenonlocation>false</hidenonlocation>
|
||||
</groups>
|
||||
<tree>
|
||||
<hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>
|
||||
<hidenonprojectfiles>true</hidenonprojectfiles>
|
||||
<showvcsfields>false</showvcsfields>
|
||||
</tree>
|
||||
</kdevfileview>
|
||||
<kdevdebugger>
|
||||
<general>
|
||||
<gdbpath/>
|
||||
<dbgshell/>
|
||||
<configGdbScript/>
|
||||
<runShellScript/>
|
||||
<runGdbScript/>
|
||||
<breakonloadinglibs>true</breakonloadinglibs>
|
||||
<separatetty>false</separatetty>
|
||||
<floatingtoolbar>false</floatingtoolbar>
|
||||
<raiseGDBOnStart>false</raiseGDBOnStart>
|
||||
</general>
|
||||
<display>
|
||||
<staticmembers>false</staticmembers>
|
||||
<demanglenames>true</demanglenames>
|
||||
<outputradix>10</outputradix>
|
||||
</display>
|
||||
</kdevdebugger>
|
||||
<kdevdocumentation>
|
||||
<projectdoc>
|
||||
<docsystem/>
|
||||
<docurl/>
|
||||
<usermanualurl/>
|
||||
</projectdoc>
|
||||
</kdevdocumentation>
|
||||
<ctagspart>
|
||||
<customArguments/>
|
||||
<customTagfilePath>./tags</customTagfilePath>
|
||||
<activeTagsFiles/>
|
||||
</ctagspart>
|
||||
</kdevelop>
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
#### Source files definitions ####
|
||||
|
||||
SET( ISFQT_SOURCES
|
||||
data/algorithms/bitpacking.cpp
|
||||
data/algorithms/bitpacking_byte.cpp
|
||||
data/algorithms/huffman.cpp
|
||||
data/algorithms/deltatransform.cpp
|
||||
data/compression.cpp
|
||||
data/datasource.cpp
|
||||
data/multibytecoding.cpp
|
||||
isfqtdrawing.cpp
|
||||
tagsparser.cpp
|
||||
tagswriter.cpp
|
||||
isfqt.cpp
|
||||
isfinkcanvas.cpp
|
||||
)
|
||||
|
||||
SET( ISFQT_PUBLIC_HEADERS
|
||||
../include/isfqt.h
|
||||
../include/isfqtdrawing.h
|
||||
../include/isfinkcanvas.h
|
||||
../include/IsfQt
|
||||
../include/IsfQtDrawing
|
||||
../include/IsfInkCanvas
|
||||
)
|
||||
|
||||
SET( ISFQT_LIBS
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
)
|
||||
|
||||
SET( ISFQT_RCCS
|
||||
../data/isfqtresources.qrc
|
||||
)
|
||||
|
||||
IF( GIF_FOUND )
|
||||
INCLUDE_DIRECTORIES( ${GIF_INCLUDE_DIR} )
|
||||
SET( ISFQT_LIBS ${ISFQT_LIBS} ${GIF_LIBRARIES} )
|
||||
ENDIF( GIF_FOUND )
|
||||
|
||||
|
||||
#### Compilation ####
|
||||
|
||||
QT4_WRAP_CPP( MOC_SRCS ../include/isfinkcanvas.h )
|
||||
|
||||
QT4_ADD_RESOURCES( ISFQT_RCC_SRCS ${ISFQT_RCCS} )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
# Do not install the library if we're bundling it in KMess
|
||||
IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
|
||||
ADD_LIBRARY( isf-qt SHARED ${ISFQT_SOURCES} ${MOC_SRCS} ${ISFQT_RCC_SRCS} )
|
||||
ELSE()
|
||||
ADD_LIBRARY( isf-qt STATIC ${ISFQT_SOURCES} ${MOC_SRCS} ${ISFQT_RCC_SRCS} )
|
||||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES( isf-qt ${ISFQT_LIBS} )
|
||||
|
||||
SET_TARGET_PROPERTIES( isf-qt PROPERTIES
|
||||
VERSION ${ISFQT_VERSION}
|
||||
SOVERSION ${ISFQT_VERSION} )
|
||||
|
||||
#### Installation ####
|
||||
|
||||
# Do not install the library if we're bundling it in KMess
|
||||
IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
|
||||
INSTALL( TARGETS isf-qt LIBRARY
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" )
|
||||
INSTALL( FILES ${ISFQT_PUBLIC_HEADERS}
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/include/isf-qt" )
|
||||
ENDIF()
|
||||
@@ -0,0 +1,196 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008-2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
#include "bitpacking.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the most appropriate block size for the given data.
|
||||
*
|
||||
* @param data Data to analyze
|
||||
* @return Block size
|
||||
*/
|
||||
quint8 BitPackingAlgorithm::blockSize( const QList<qint64> &data )
|
||||
{
|
||||
quint8 blockSize = 0;
|
||||
qint64 num;
|
||||
|
||||
for( qint32 index = 0; index < data.size(); ++index )
|
||||
{
|
||||
num = data[ index ];
|
||||
|
||||
if( num < 0 )
|
||||
{
|
||||
// We need the positive numbers: the +1 is for the sign bit
|
||||
num += - (num + 1);
|
||||
}
|
||||
|
||||
// Shift right the value by blockSize bits until it becomes zero:
|
||||
// we need to detect the maximum bitwise size required to store
|
||||
// the numbers in the data array.
|
||||
num >>= blockSize;
|
||||
while( num )
|
||||
{
|
||||
++blockSize;
|
||||
num >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The sign bit always takes up a bit
|
||||
++blockSize;
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress data with the Bit Packing algorithm.
|
||||
*
|
||||
* @param encodedData Byte array where to store the compressed data
|
||||
* @param blockSize Block size to use for compression
|
||||
* @param source List of values to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool BitPackingAlgorithm::deflate( QByteArray &encodedData, quint8 blockSize, const QList<qint64> &source )
|
||||
{
|
||||
if( blockSize > 64 )
|
||||
{
|
||||
qWarning() << "A block size of" << blockSize << "is too high!";
|
||||
blockSize = 64; // Fuck it :P
|
||||
}
|
||||
|
||||
quint8 blockSizeLeft; // Remaining bits to encode of the current value
|
||||
quint8 freeBits = 8; // Free bits of the current byte, in LSB order
|
||||
quint8 signMask = 1 << ( blockSize - 1 ); // Mask to add the sign bit
|
||||
|
||||
quint8 byte = 0; // Byte to add to the array
|
||||
qint64 currentValue;
|
||||
|
||||
for( qint64 index = 0; index < source.count(); ++index )
|
||||
{
|
||||
currentValue = source[ index ];
|
||||
|
||||
if( currentValue < 0 )
|
||||
{
|
||||
currentValue |= signMask;
|
||||
}
|
||||
|
||||
blockSizeLeft = blockSize;
|
||||
|
||||
if( freeBits >= blockSizeLeft )
|
||||
{
|
||||
freeBits -= blockSizeLeft;
|
||||
byte |= currentValue << freeBits;
|
||||
|
||||
encodedData.append( byte );
|
||||
|
||||
byte = 0;
|
||||
freeBits = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill the current byte
|
||||
quint64 mask = 0xFFFFFFFF >> ( 32 - blockSizeLeft );
|
||||
byte |= currentValue >> ( blockSizeLeft - freeBits );
|
||||
|
||||
encodedData.append( byte );
|
||||
|
||||
byte = 0;
|
||||
blockSizeLeft -= freeBits;
|
||||
mask >>= freeBits;
|
||||
currentValue &= mask;
|
||||
|
||||
// Then fill all the next bytes required to encode the current value,
|
||||
// except the last one
|
||||
while( blockSizeLeft > 8 )
|
||||
{
|
||||
blockSizeLeft -= 8;
|
||||
encodedData.append( currentValue >> blockSizeLeft );
|
||||
|
||||
mask >>= 8;
|
||||
currentValue &= mask;
|
||||
}
|
||||
|
||||
// Finally, add the last byte
|
||||
freeBits = 8 - blockSizeLeft;
|
||||
encodedData.append( currentValue << freeBits );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decompress data with the Bit Packing algorithm.
|
||||
*
|
||||
* @param source Data source where to read the compressed bytes
|
||||
* @param length Number of items to read
|
||||
* @param blockSize Block size to use for compression
|
||||
* @param decodedData List where to place decompressed values
|
||||
* @return bool
|
||||
*/
|
||||
bool BitPackingAlgorithm::inflate( DataSource &source, quint64 length, quint8 blockSize, QList<qint64> &decodedData )
|
||||
{
|
||||
if( blockSize > 64 )
|
||||
{
|
||||
qWarning() << "A block size of" << blockSize << "is too high!";
|
||||
blockSize = 64; // Fuck it :P
|
||||
}
|
||||
|
||||
if( source.atEnd() )
|
||||
{
|
||||
qWarning() << "Cannot inflate: no more bits available!";
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 value;
|
||||
quint32 index = 0;
|
||||
quint64 signMask = (quint64)( 0xFFFFFFFF * pow( 2, blockSize - 1 ) ) & 0xFFFFFFFF;
|
||||
|
||||
while( index++ < length )
|
||||
{
|
||||
value = source.getBits( blockSize );
|
||||
|
||||
// If the mask matches, the sign bit is set, so ORing value and mask will
|
||||
// set all leftmost bits to 1, making it a real 64bit signed integer
|
||||
if( value & signMask )
|
||||
{
|
||||
value |= signMask;
|
||||
}
|
||||
|
||||
decodedData.append( value );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFCOMPRESSION_BITPACKING_H
|
||||
#define ISFCOMPRESSION_BITPACKING_H
|
||||
|
||||
#include "../datasource.h"
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
namespace BitPackingAlgorithm
|
||||
{
|
||||
|
||||
quint8 blockSize( const QList<qint64> &data );
|
||||
bool deflate( QByteArray &encodedData, quint8 blockSize, const QList<qint64> &source );
|
||||
bool inflate( DataSource &source, quint64 length, quint8 blockSize, QList<qint64> &decodedData );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008-2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
#include "bitpacking_byte.h"
|
||||
#include "bitpacking_table.h"
|
||||
|
||||
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the most appropriate index for the given data.
|
||||
*
|
||||
* @param data Data to analyze
|
||||
* @return Index value
|
||||
*/
|
||||
quint8 BitPackingByteAlgorithm::index( const QList<qint64> &data )
|
||||
{
|
||||
Q_UNUSED( data );
|
||||
|
||||
quint8 index = 0;
|
||||
/*
|
||||
qint64 num;
|
||||
|
||||
for( qint32 index = 0; index < data.size(); ++index )
|
||||
{
|
||||
num = data[ index ];
|
||||
|
||||
if( num < 0 )
|
||||
{
|
||||
// We need the positive numbers: the +1 is for the sign bit
|
||||
num += - (num + 1);
|
||||
}
|
||||
|
||||
// Shift right the value by index bits until it becomes zero:
|
||||
// we need to detect the maximum bitwise size required to store
|
||||
// the numbers in the data array.
|
||||
num >>= index;
|
||||
while( num )
|
||||
{
|
||||
++index;
|
||||
num >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The sign bit always takes up a bit
|
||||
++index;
|
||||
*/
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress data with the Bit Packing algorithm.
|
||||
*
|
||||
* @param encodedData Byte array where to store the compressed data
|
||||
* @param index Index to use for compression
|
||||
* @param source List of values to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool BitPackingByteAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QList<qint64> &source )
|
||||
{
|
||||
Q_UNUSED( encodedData );
|
||||
Q_UNUSED( index );
|
||||
Q_UNUSED( source );
|
||||
|
||||
/*
|
||||
if( blockSize > 64 )
|
||||
{
|
||||
qWarning() << "A block size of" << blockSize << "is too high!";
|
||||
blockSize = 64; // Fuck it :P
|
||||
}
|
||||
|
||||
quint8 blockSizeLeft; // Remaining bits to encode of the current value
|
||||
quint8 freeBits = 8; // Free bits of the current byte, in LSB order
|
||||
quint8 signMask = 1 << ( blockSize - 1 ); // Mask to add the sign bit
|
||||
|
||||
quint8 byte = 0; // Byte to add to the array
|
||||
qint64 currentValue;
|
||||
|
||||
for( qint64 index = 0; index < source.count(); ++index )
|
||||
{
|
||||
currentValue = source[ index ];
|
||||
|
||||
if( currentValue < 0 )
|
||||
{
|
||||
currentValue |= signMask;
|
||||
}
|
||||
|
||||
blockSizeLeft = blockSize;
|
||||
|
||||
if( freeBits >= blockSizeLeft )
|
||||
{
|
||||
freeBits -= blockSizeLeft;
|
||||
byte |= currentValue << freeBits;
|
||||
|
||||
encodedData.append( byte );
|
||||
|
||||
byte = 0;
|
||||
freeBits = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill the current byte
|
||||
quint64 mask = 0xFFFFFFFF >> ( 32 - blockSizeLeft );
|
||||
byte |= currentValue >> ( blockSizeLeft - freeBits );
|
||||
|
||||
encodedData.append( byte );
|
||||
|
||||
byte = 0;
|
||||
blockSizeLeft -= freeBits;
|
||||
mask >>= freeBits;
|
||||
currentValue &= mask;
|
||||
|
||||
// Then fill all the next bytes required to encode the current value,
|
||||
// except the last one
|
||||
while( blockSizeLeft > 8 )
|
||||
{
|
||||
blockSizeLeft -= 8;
|
||||
encodedData.append( currentValue >> blockSizeLeft );
|
||||
|
||||
mask >>= 8;
|
||||
currentValue &= mask;
|
||||
}
|
||||
|
||||
// Finally, add the last byte
|
||||
freeBits = 8 - blockSizeLeft;
|
||||
encodedData.append( currentValue << freeBits );
|
||||
}
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decompress data with the Bit Packing Byte algorithm.
|
||||
*
|
||||
* @param source Data source where to read the compressed bytes
|
||||
* @param length Number of items to read
|
||||
* @param index Index to use for compression
|
||||
* @param decodedData List where to place decompressed values
|
||||
* @return bool
|
||||
*/
|
||||
bool BitPackingByteAlgorithm::inflate( DataSource &source, quint64 length, quint8 index, QList<qint64> &decodedData )
|
||||
{
|
||||
if( index > 24 )
|
||||
{
|
||||
qWarning() << "An index of" << index << "is too high!";
|
||||
index = 24; // Fuck it :P
|
||||
}
|
||||
|
||||
if( source.atEnd() )
|
||||
{
|
||||
qWarning() << "Cannot inflate: no more bits available!";
|
||||
return true;
|
||||
}
|
||||
|
||||
quint8 cBits = BitPackingAlgorithm::bitLookUpTable_[ index ][ CBITS ];
|
||||
// quint8 cPads = BitPackingAlgorithm::bitLookUpTable_[ index ][ CPADS ];
|
||||
quint16 count = ( length * 8 / cBits ); // Number of items in the compressed array
|
||||
|
||||
bool ok;
|
||||
quint64 pos = 0;
|
||||
while( pos++ < count )
|
||||
{
|
||||
quint8 byte = source.getBits( cBits, &ok );
|
||||
|
||||
if( ! ok )
|
||||
{
|
||||
qWarning() << "Decompression failure!";
|
||||
return false;
|
||||
}
|
||||
|
||||
decodedData.append( byte );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFCOMPRESSION_BITPACKING_BYTE_H
|
||||
#define ISFCOMPRESSION_BITPACKING_BYTE_H
|
||||
|
||||
#include "../datasource.h"
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
namespace BitPackingByteAlgorithm
|
||||
{
|
||||
|
||||
quint8 index( const QList<qint64> &data );
|
||||
bool deflate( QByteArray &encodedData, quint8 index, const QList<qint64> &source );
|
||||
bool inflate( DataSource &source, quint64 length, quint8 index, QList<qint64> &decodedData );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFCOMPRESSION_BITPACKING_H
|
||||
#define ISFCOMPRESSION_BITPACKING_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
|
||||
#define CBITS 0
|
||||
#define CPADS 1
|
||||
|
||||
|
||||
namespace Isf {
|
||||
namespace Compress {
|
||||
namespace BitPackingAlgorithm {
|
||||
|
||||
/// Table used to compute the length of bit-packed values and their remainders.
|
||||
quint8 bitLookUpTable_[ 48 ][ 2 ] =
|
||||
{
|
||||
// { cBits, cPads }
|
||||
{ 8, 0 }, // index 0
|
||||
{ 1, 0 },
|
||||
{ 1, 1 },
|
||||
{ 1, 2 },
|
||||
{ 1, 3 },
|
||||
{ 1, 4 },
|
||||
{ 1, 5 },
|
||||
{ 1, 6 },
|
||||
{ 1, 7 },
|
||||
{ 2, 0 },
|
||||
{ 2, 1 }, // index 10
|
||||
{ 2, 2 },
|
||||
{ 2, 3 },
|
||||
{ 3, 0 },
|
||||
{ 3, 1 },
|
||||
{ 3, 2 },
|
||||
{ 4, 0 },
|
||||
{ 4, 1 },
|
||||
{ 5, 0 },
|
||||
{ 5, 1 },
|
||||
{ 6, 0 }, // index 20
|
||||
{ 6, 1 },
|
||||
{ 7, 0 },
|
||||
{ 7, 1 },
|
||||
{ 8, 0 },
|
||||
{ 9, 0 },
|
||||
{ 10, 0 },
|
||||
{ 11, 0 },
|
||||
{ 12, 0 },
|
||||
{ 13, 0 },
|
||||
{ 14, 0 }, // index 30
|
||||
{ 15, 0 },
|
||||
{ 16, 0 },
|
||||
{ 17, 0 },
|
||||
{ 18, 0 },
|
||||
{ 19, 0 },
|
||||
{ 20, 0 },
|
||||
{ 21, 0 },
|
||||
{ 22, 0 },
|
||||
{ 23, 0 },
|
||||
{ 24, 0 }, // index 40
|
||||
{ 25, 0 },
|
||||
{ 26, 0 },
|
||||
{ 27, 0 },
|
||||
{ 28, 0 },
|
||||
{ 29, 0 },
|
||||
{ 30, 0 },
|
||||
{ 31, 0 } // index 47
|
||||
};
|
||||
|
||||
} // Namespace BitPackingAlgorithm
|
||||
} // Namespace Compress
|
||||
} // Namespace Isf
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "deltatransform.h"
|
||||
|
||||
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Perform a delta-delta transformation on data to be deflated.
|
||||
*
|
||||
* @param data Data to transform - the list will be modified.
|
||||
* @return bool
|
||||
*/
|
||||
bool Delta::transform( QList<qint64> &data )
|
||||
{
|
||||
qint64 currentDelta = 0;
|
||||
qint64 previousDelta = 0;
|
||||
|
||||
for( qint64 index = 0; index < data.size(); ++index )
|
||||
{
|
||||
qint64 currentItem = data[ index ];
|
||||
|
||||
data[ index ] = data[ index ] + previousDelta - ( currentDelta * 2 );
|
||||
|
||||
previousDelta = currentDelta;
|
||||
currentDelta = currentItem;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Perform a delta-delta inverse transformation on just-inflated data.
|
||||
*
|
||||
* @param data Data to transform - the list will be modified.
|
||||
* @return bool
|
||||
*/
|
||||
bool Delta::inverseTransform( QList<qint64> &data )
|
||||
{
|
||||
qint64 currentDelta = 0;
|
||||
qint64 previousDelta = 0;
|
||||
|
||||
for( qint64 index = 0; index < data.size(); ++index )
|
||||
{
|
||||
qint64 delta = ( currentDelta * 2 ) - previousDelta + data[ index ];
|
||||
|
||||
previousDelta = currentDelta;
|
||||
currentDelta = delta;
|
||||
|
||||
data[ index ] = delta;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISF_COMPRESS_DELTATRANSFORM_H
|
||||
#define ISF_COMPRESS_DELTATRANSFORM_H
|
||||
|
||||
#include <QList>
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
namespace Delta
|
||||
{
|
||||
|
||||
bool transform( QList<qint64> &data );
|
||||
bool inverseTransform( QList<qint64> &data );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,284 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "huffman.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#define HUFFMAN_BASES_NUM 8
|
||||
#define HUFFMAN_BASE_SIZE 11
|
||||
|
||||
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
/// Bit amounts.
|
||||
const int bitAmounts_[HUFFMAN_BASES_NUM][HUFFMAN_BASE_SIZE] =
|
||||
{
|
||||
{0, 1, 2, 4, 6, 8, 12, 16, 24, 32, -1},
|
||||
{0, 1, 1, 2, 4, 8, 12, 16, 24, 32, -1},
|
||||
{0, 1, 1, 1, 2, 4, 8, 14, 22, 32, -1},
|
||||
{0, 2, 2, 3, 5, 8, 12, 16, 24, 32, -1},
|
||||
{0, 3, 4, 5, 8, 12, 16, 24, 32, -1, -1},
|
||||
{0, 4, 6, 8, 12, 16, 24, 32, -1, -1, -1},
|
||||
{0, 6, 8, 12, 16, 24, 32, -1, -1, -1, -1},
|
||||
{0, 7, 8, 12, 16, 24, 32, -1, -1, -1, -1},
|
||||
};
|
||||
|
||||
|
||||
/// Huffman codec value bases.
|
||||
const int huffmanBases_[HUFFMAN_BASES_NUM][HUFFMAN_BASE_SIZE] =
|
||||
{
|
||||
{0, 1, 2, 4, 12, 44, 172, 2220, 34988, 8423596, -1},
|
||||
{0, 1, 2, 3, 5, 13, 141, 2189, 34957, 8423565, -1},
|
||||
{0, 1, 2, 3, 4, 6, 14, 142, 8334, 2105486, -1},
|
||||
{0, 1, 3, 5, 9, 25, 153, 2201, 34969, 8423577, -1},
|
||||
{0, 1, 5, 13, 29, 157, 2205, 34973, 8423581, -1, -1},
|
||||
{0, 1, 9, 41, 169, 2217, 34985, 8423593, -1, -1, -1},
|
||||
{0, 1, 33, 161, 2209, 34977, 8423585, -1, -1, -1, -1},
|
||||
{0, 1, 65, 193, 2241, 35009, 8423617, -1, -1, -1, -1},
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the most appropriate index for the given data.
|
||||
*
|
||||
* @param data Data to analyze
|
||||
* @return index value
|
||||
*/
|
||||
quint8 HuffmanAlgorithm::index( const QList<qint64> &data )
|
||||
{
|
||||
quint8 index = 0;
|
||||
|
||||
// TODO: Find out what the Huffman index algorithm is
|
||||
Q_UNUSED( data )
|
||||
index = 2;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress data with the Huffman algorithm.
|
||||
*
|
||||
* @param encodedData Byte array where to store the compressed data
|
||||
* @param index Index to use for compression
|
||||
* @param source List of values to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool HuffmanAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QList<qint64> &source )
|
||||
{
|
||||
DataSource output( encodedData );
|
||||
output.skipToNextByte();
|
||||
|
||||
foreach( quint64 value, source )
|
||||
{
|
||||
if( ! deflateValue( output, index, value ) )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Deflating failure for value:" << value;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any leftover bit to the byte array
|
||||
output.flush();
|
||||
|
||||
encodedData = output.data();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress a single value with the Huffman algorithm.
|
||||
*
|
||||
* @param output Data source where to store the compressed value
|
||||
* @param index Index to use for compression
|
||||
* @param value Value to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool HuffmanAlgorithm::deflateValue( DataSource &output, quint8 index, qint64 value )
|
||||
{
|
||||
qint64 temp = value;
|
||||
quint8 requiredBits = 0;
|
||||
QBitArray valueBits;
|
||||
|
||||
// Fill in a bitAmounts local vector
|
||||
QVector<int> bitAmounts;
|
||||
for( int i = 0; i < HUFFMAN_BASE_SIZE; ++i )
|
||||
{
|
||||
if( bitAmounts_[ index ][ i ] == -1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bitAmounts.append( bitAmounts_[ index ][ i ] );
|
||||
}
|
||||
|
||||
// Find the number of bits needed to store this value
|
||||
while( temp )
|
||||
{
|
||||
temp /= 2;
|
||||
++requiredBits;
|
||||
}
|
||||
|
||||
while( ! bitAmounts.count( requiredBits ) )
|
||||
{
|
||||
++requiredBits;
|
||||
}
|
||||
|
||||
qint64 offset = ( value < 0 ) ? -value : +value;
|
||||
|
||||
quint8 prefixLength;
|
||||
for( prefixLength = 1;
|
||||
( prefixLength < HUFFMAN_BASE_SIZE ) && ( offset >= huffmanBases_[ index ][ prefixLength ] ); prefixLength++ )
|
||||
{
|
||||
// Empty loop on purpose
|
||||
}
|
||||
|
||||
|
||||
// Write prefixLength 1s to the stream, then a 0
|
||||
QBitArray bits( prefixLength );
|
||||
bits.fill( true );
|
||||
bits.clearBit( bits.size() - 1 );
|
||||
|
||||
// Write the number using the minimum possible number of bits
|
||||
qint32 size = bitAmounts_[ index ][ prefixLength - 1 ];
|
||||
qint64 mask = ( 1 << ( size - 1 ) ) - 1;
|
||||
|
||||
valueBits.resize( size );
|
||||
offset = ( offset - huffmanBases_[ index ][ prefixLength - 1 ] ) & mask;
|
||||
offset <<= 1;
|
||||
offset |= ( value < 0 ) ? 1 : 0;
|
||||
|
||||
// Copy the resulting offset
|
||||
for( qint64 i = 0; i < size; ++i )
|
||||
{
|
||||
valueBits.setBit( i, offset & ( 1 << ( size - i - 1 ) ) );
|
||||
}
|
||||
|
||||
// Add the bits to the data source
|
||||
output.append( bits );
|
||||
output.append( valueBits );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decompress data with the Huffman algorithm.
|
||||
*
|
||||
* @param source Data source where to read the compressed bytes
|
||||
* @param length Number of items to read
|
||||
* @param index Index to use for compression
|
||||
* @param decodedData List where to place decompressed values
|
||||
* @return bool
|
||||
*/
|
||||
bool HuffmanAlgorithm::inflate( DataSource &source, quint64 length, quint8 index, QList<qint64> &decodedData )
|
||||
{
|
||||
QVector<int> huffmanBases;
|
||||
QVector<int> bitAmounts( HUFFMAN_BASE_SIZE );
|
||||
|
||||
// Initialize the bit amounts vector
|
||||
memcpy( bitAmounts.data(), bitAmounts_[ index ], sizeof(int)*HUFFMAN_BASE_SIZE );
|
||||
|
||||
int base = 1;
|
||||
huffmanBases.append( 0 );
|
||||
|
||||
// Fill up the huffman bases vector
|
||||
for( quint8 i = 0; i < bitAmounts.size(); ++i )
|
||||
{
|
||||
int value = bitAmounts[ i ];
|
||||
|
||||
// The bit amounts sequence ends in -1
|
||||
if( value == -1 )
|
||||
{
|
||||
bitAmounts.resize( i );
|
||||
break;
|
||||
}
|
||||
|
||||
if( value == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
huffmanBases.append( base );
|
||||
base += pow( 2, value - 1 );
|
||||
}
|
||||
|
||||
|
||||
quint32 count = 0;
|
||||
qint64 value = 0;
|
||||
bool bit;
|
||||
|
||||
while( (uint)decodedData.length() < length )
|
||||
{
|
||||
bit = source.getBit();
|
||||
|
||||
if( bit )
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( count == 0 )
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
else if( count < (uint)bitAmounts.size() )
|
||||
{
|
||||
quint64 offset = source.getBits( bitAmounts[ count ] );
|
||||
bool sign = offset & 0x1;
|
||||
offset /= 2;
|
||||
value = huffmanBases[ count ] + offset;
|
||||
value *= ( sign ? -1 : +1 );
|
||||
}
|
||||
else if( count == (uint)bitAmounts.size() )
|
||||
{
|
||||
// TODO: Implement 64-bit data decompression :)
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Unsupported 64-bit value found!";
|
||||
#endif
|
||||
value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Decompression error!";
|
||||
#endif
|
||||
value = 0;
|
||||
}
|
||||
|
||||
decodedData.append( value );
|
||||
count = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFCOMPRESSION_HUFFMAN_H
|
||||
#define ISFCOMPRESSION_HUFFMAN_H
|
||||
|
||||
#include "../datasource.h"
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
namespace HuffmanAlgorithm
|
||||
{
|
||||
|
||||
bool deflate( QByteArray &encodedData, quint8 index, const QList<qint64> &source );
|
||||
bool inflate( DataSource &source, quint64 length, quint8 index, QList<qint64> &decodedData );
|
||||
quint8 index( const QList<qint64> &data );
|
||||
|
||||
// Internal use methods
|
||||
|
||||
bool deflateValue( DataSource &output, quint8 index, qint64 value );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,421 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "compression.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
#include "algorithms/bitpacking.h"
|
||||
#include "algorithms/bitpacking_byte.h"
|
||||
#include "algorithms/huffman.h"
|
||||
#include "algorithms/deltatransform.h"
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decompress packet data.
|
||||
*
|
||||
* The algorithm to use for the decompression is autodetected using
|
||||
* the so-called "algorithm byte" within the compressed data.
|
||||
*
|
||||
* @param source Data Source where to read compressed bytes from
|
||||
* @param length Number of items to decompress
|
||||
* @param decodedData List where to store the decoded values
|
||||
* @return bool
|
||||
*/
|
||||
bool Compress::inflatePacketData( DataSource &source, quint64 length, QList<qint64> &decodedData )
|
||||
{
|
||||
if( source.atEnd() )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Source was at end!";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result;
|
||||
uchar byte = source.getByte();
|
||||
qint16 algorithm = ( byte & AlgorithmMask );
|
||||
quint8 algorithmData = 0;
|
||||
|
||||
// Detect which algorithm to use
|
||||
|
||||
// Use the "best compression" algorithm
|
||||
if( ( algorithm & BestCompression ) == BestCompression )
|
||||
{
|
||||
/* TODO: Not implemented yet. We don't know how ISF actually works here.
|
||||
* According to the specs, both bit packing and Huffman may be used; but
|
||||
* where are the rest of the bits stored? In the next byte?
|
||||
* We need an ISF stream with such a characteristic to be sure.
|
||||
*/
|
||||
qWarning() << "Unknown decompression method!";
|
||||
qDebug() << "[Information - type: best, byte:" << QString::number( source.getByte(), 16 ) << "hex]";
|
||||
return false;
|
||||
}
|
||||
// Use the "default compression" algorithm, which is Huffman
|
||||
else if( ( algorithm & DefaultCompression ) == DefaultCompression
|
||||
|| ( algorithm & Huffman ) == Huffman )
|
||||
{
|
||||
algorithm = Huffman;
|
||||
algorithmData = ( HuffmanMask & byte );
|
||||
}
|
||||
// According to the specs, the only other algorithm for packet data
|
||||
// is generic bit packing.
|
||||
else if( algorithm == BitPacking )
|
||||
{
|
||||
algorithm = BitPacking;
|
||||
algorithmData = ( BitPackingMask & byte );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown algorithm. Throw an error below.
|
||||
algorithm = -1;
|
||||
}
|
||||
|
||||
// Apply the inflation algorithm
|
||||
|
||||
switch( algorithm )
|
||||
{
|
||||
case BitPacking:
|
||||
{
|
||||
// Detect if the data is encoded with delta-delta transformation
|
||||
bool requiresDeltaDeltaTransform = ( BitPackingTransformMask & byte );
|
||||
if( requiresDeltaDeltaTransform )
|
||||
{
|
||||
algorithmData ^= BitPackingTransformMask;
|
||||
}
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "items using the Bit Packing algorithm and a block size of" << algorithmData;
|
||||
#endif
|
||||
|
||||
result = BitPackingAlgorithm::inflate( source, length, algorithmData, decodedData );
|
||||
|
||||
if( result && requiresDeltaDeltaTransform )
|
||||
{
|
||||
result = Delta::inverseTransform( decodedData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Huffman:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "items using the Huffman algorithm and index" << algorithmData;
|
||||
#endif
|
||||
result = HuffmanAlgorithm::inflate( source, length, algorithmData, decodedData );
|
||||
|
||||
// Always delta-inverse-transform data compressed with Huffman
|
||||
if( result )
|
||||
{
|
||||
result = Delta::inverseTransform( decodedData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qWarning() << "Unknown decompression method!";
|
||||
qDebug() << "[Information - type: unknown, byte:" << QString::number( byte, 16 ) << "hex]";
|
||||
|
||||
// Go back to the previous read position
|
||||
source.seekRelative( -1 );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Discard any partially read bytes
|
||||
if( ! source.atEnd() )
|
||||
{
|
||||
source.skipToNextByte();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress packet data.
|
||||
*
|
||||
* The algorithm to use for the decompression is autodetected
|
||||
* by analyzing the data.
|
||||
*
|
||||
* @param encodedData Byte Array where to store the encoded data
|
||||
* @param source List of values to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool Compress::deflatePacketData( QByteArray &encodedData, const QList<qint64> &source )
|
||||
{
|
||||
bool result;
|
||||
|
||||
// TODO Is this really how to detect the algorithm to use?
|
||||
int algorithm;
|
||||
if( source.count() == 1 )
|
||||
{
|
||||
algorithm = BitPacking;
|
||||
}
|
||||
else
|
||||
{
|
||||
algorithm = Huffman;
|
||||
}
|
||||
|
||||
|
||||
switch( algorithm )
|
||||
{
|
||||
case BitPacking:
|
||||
{
|
||||
quint8 blockSize = BitPackingAlgorithm::blockSize( source );
|
||||
|
||||
// Write the data encoding algorithm and block size
|
||||
encodedData.append( blockSize | BitPacking );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Deflating" << source.count() << "items using the bit packing algorithm and a block size of" << blockSize;
|
||||
#endif
|
||||
|
||||
// Deflate the data
|
||||
result = BitPackingAlgorithm::deflate( encodedData, blockSize, source );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case Huffman:
|
||||
{
|
||||
quint8 index = HuffmanAlgorithm::index( source );
|
||||
|
||||
// Write the data encoding algorithm and index
|
||||
encodedData.append( index | Huffman );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Deflating" << source.count() << "items using the Huffman algorithm and index" << index;
|
||||
#endif
|
||||
|
||||
// Deflate the data
|
||||
QList<qint64> list( source );
|
||||
result = Delta::transform( list );
|
||||
|
||||
if( result )
|
||||
{
|
||||
result = HuffmanAlgorithm::deflate( encodedData, index, list );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Encoding algorithm not implemented! (algorithm:" << QString::number( algorithm, 16 ) << ")";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decompress property data.
|
||||
*
|
||||
* The algorithm to use for the decompression is autodetected using
|
||||
* the so-called "algorithm byte" within the compressed data.
|
||||
*
|
||||
* @param source Data Source where to read compressed bytes from
|
||||
* @param length Number of items to decompress
|
||||
* @param decodedData List where to store the decoded values
|
||||
* @return bool
|
||||
*/
|
||||
bool Compress::inflatePropertyData( DataSource &source, quint64 length, QList<qint64> &decodedData )
|
||||
{
|
||||
if( source.atEnd() )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Source was at end!";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result;
|
||||
quint8 byte = source.getByte();
|
||||
qint16 algorithm = ( byte & AlgorithmMask );
|
||||
quint8 algorithmData = 0;
|
||||
|
||||
// Detect which algorithm to use
|
||||
|
||||
// Use the "default compression" algorithm
|
||||
if( ( algorithm & DefaultCompression ) == DefaultCompression )
|
||||
{
|
||||
/* TODO: Not implemented yet. We don't know how ISF actually works here.
|
||||
* According to the specs, any of the 3 bit packing techniques may be used;
|
||||
* but where are the rest of the bits stored? In the next byte?
|
||||
* We need an ISF stream with such a characteristic to be sure.
|
||||
*/
|
||||
qWarning() << "Unknown decompression method!";
|
||||
qDebug() << "[Information - type: default, byte:" << QString::number( source.getByte(), 16 ) << "hex]";
|
||||
return false;
|
||||
}
|
||||
// Use the "best compression" algorithm, which is Huffman
|
||||
else if( ( algorithm & BestCompression ) == BestCompression
|
||||
|| ( algorithm & Huffman ) == Huffman )
|
||||
{
|
||||
algorithm = Huffman;
|
||||
algorithmData = ( HuffmanMask & byte );
|
||||
}
|
||||
else if( ( algorithm & LimpelZiv ) == LimpelZiv )
|
||||
{
|
||||
algorithm = LimpelZiv;
|
||||
}
|
||||
else if( ( algorithm & BitPackingByte ) == BitPackingByte )
|
||||
{
|
||||
algorithm = BitPackingByte;
|
||||
algorithmData = ( BitPackingByteMask & byte );
|
||||
}
|
||||
else if( ( algorithm & BitPackingWord ) == BitPackingWord )
|
||||
{
|
||||
algorithm = BitPackingWord;
|
||||
algorithmData = ( BitPackingWordMask & byte );
|
||||
}
|
||||
else if( ( algorithm & BitPackingLong ) == BitPackingLong )
|
||||
{
|
||||
algorithm = BitPackingLong;
|
||||
algorithmData = ( BitPackingLongMask & byte );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown algorithm. Throw an error below.
|
||||
algorithm = -1;
|
||||
}
|
||||
|
||||
// Apply the deflation algorithm
|
||||
|
||||
switch( algorithm )
|
||||
{
|
||||
case BitPackingByte:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "bytes using the Bit Packing Byte algorithm and an index of" << algorithmData;
|
||||
#endif
|
||||
|
||||
result = BitPackingByteAlgorithm::inflate( source, length, algorithmData, decodedData );
|
||||
break;
|
||||
}
|
||||
|
||||
case BitPackingWord:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "bytes using the Bit Packing Word algorithm and an index of" << algorithmData;
|
||||
#endif
|
||||
|
||||
qWarning() << "Stream data is compressed with non implemented algorithm!";
|
||||
qDebug() << "[Information - algorithm: Bit Packing Word]";
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BitPackingLong:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "bytes using the Bit Packing Long algorithm and an index of" << algorithmData;
|
||||
#endif
|
||||
|
||||
qWarning() << "Stream data is compressed with non implemented algorithm!";
|
||||
qDebug() << "[Information - algorithm: Bit Packing Long]";
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LimpelZiv:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "items using the Limpel-Ziv algorithm and a block size of" << algorithmData;
|
||||
#endif
|
||||
|
||||
qWarning() << "Stream data is compressed with non implemented algorithm!";
|
||||
qDebug() << "[Information - algorithm: Limpel-Ziv]";
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Huffman:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Inflating" << length << "items using the Huffman algorithm and index" << algorithmData;
|
||||
#endif
|
||||
result = HuffmanAlgorithm::inflate( source, length, algorithmData, decodedData );
|
||||
|
||||
// Always delta-inverse-transform data compressed with Huffman
|
||||
if( result )
|
||||
{
|
||||
result = Delta::inverseTransform( decodedData );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qWarning() << "Unknown decompression method!";
|
||||
qDebug() << "[Information - type: unknown, byte:" << QString::number( byte, 16 ) << "hex]";
|
||||
|
||||
// Go back to the previous read position
|
||||
source.seekRelative( -1 );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Discard any partially read bytes
|
||||
if( ! source.atEnd() )
|
||||
{
|
||||
source.skipToNextByte();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compress property data.
|
||||
*
|
||||
* The algorithm to use for the decompression is autodetected
|
||||
* by analyzing the data.
|
||||
*
|
||||
* @todo Implement!
|
||||
* @param encodedData Byte Array where to store the encoded data
|
||||
* @param source List of values to compress
|
||||
* @return bool
|
||||
*/
|
||||
bool Compress::deflatePropertyData( QByteArray &encodedData, const QList<qint64> &source )
|
||||
{
|
||||
Q_UNUSED( encodedData );
|
||||
Q_UNUSED( source );
|
||||
|
||||
bool result = false;
|
||||
|
||||
qWarning() << "Property data saving is not implemented at the moment!";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFCOMPRESSION_H
|
||||
#define ISFCOMPRESSION_H
|
||||
|
||||
#include "datasource.h"
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Algorithm extra data masks.
|
||||
*
|
||||
* These masks are used to obtain the least significant bits which
|
||||
* are useful for the specific algorithm. If an algo takes no
|
||||
* useful bits, the mask is 0.
|
||||
*/
|
||||
enum AlgorithmMasks
|
||||
{
|
||||
AlgorithmMask = 0xF0 ///< Mask used to identify the algorithms
|
||||
, BitPackingMask = 0x3F ///< Mask for bit packing of arbitrary-sized integers
|
||||
, BitPackingTransformMask = 0x20 ///< Mask for delta-delta transformed bit packed data
|
||||
, HuffmanMask = 0x3F ///< Mask for Huffman
|
||||
, BitPackingLongMask = 0x3F ///< Mask for bit packing of 32bit signed integers
|
||||
, BitPackingWordMask = 0x1F ///< Mask for bit packing of 16bit unsigned integers
|
||||
, BitPackingByteMask = 0x1F ///< Mask for bit packing of 8bit unsigned integers
|
||||
, LimpelZivMask = 0x00 ///< Mask for Limpel-Ziv
|
||||
, BestCompressionMask = 0x00 ///< Mask for the best compression algo
|
||||
, DefaultCompressionMask = 0x00 ///< Mask for the default compression algo
|
||||
};
|
||||
|
||||
/**
|
||||
* Compression and decompressions algorithms.
|
||||
*
|
||||
* Bit assignment table for packets (strokes):
|
||||
* ---------------------------
|
||||
* | Algorithm | 7 6 5 4 3 2 1 0 (Bit assignment) |
|
||||
* Bit packing 0 0 D D D D D D
|
||||
* Huffman 1 0 D D D D D D
|
||||
* Default compression 1 1 0 0 X X X X
|
||||
* Best compression 1 1 1 1 X X X X
|
||||
*
|
||||
* Bit assignment table for properties (tags):
|
||||
* ---------------------------
|
||||
* | Algorithm | 7 6 5 4 3 2 1 0 (Bit assignment) |
|
||||
* Bit packing of bytes 0 0 0 D D D D D
|
||||
* Bit packing of words 0 0 1 D D D D D
|
||||
* Bit packing of longs 0 1 D D D D D D
|
||||
* Limpel-Ziv 1 0 1 0 X X X X
|
||||
* Default compression 1 1 0 0 X X X X
|
||||
* Best compression 1 1 1 1 X X X X
|
||||
*
|
||||
* D = Algorithm-specific data
|
||||
* X = Ignored bit
|
||||
*
|
||||
* We use the two most significant bits to identify the algorithms,
|
||||
* because they are guaranteed to not contain algorithm data.
|
||||
*
|
||||
* Also, note that these tables are not identical to the ones in the
|
||||
* specs: we changed them because they differ from our factual
|
||||
* observations (in the specs Huffman is missing, for example).
|
||||
*/
|
||||
enum CommonDataAlgorithms
|
||||
{
|
||||
BestCompression = 0xF0 ///< Best compression algorithm
|
||||
, DefaultCompression = 0xC0 ///< Default compression algorithm (Huffman)
|
||||
, Huffman = 0x80 ///< Huffman encoding
|
||||
};
|
||||
/**
|
||||
* Compression and decompressions algorithms.
|
||||
*
|
||||
* @see CommonDataAlgorithms
|
||||
*/
|
||||
enum PacketDataAlgorithms
|
||||
{
|
||||
BitPacking = 0x00 ///< Bit packing
|
||||
};
|
||||
/**
|
||||
* Compression and decompressions algorithms.
|
||||
*
|
||||
* @see CommonDataAlgorithms
|
||||
*/
|
||||
enum PropertyDataAlgorithms
|
||||
{
|
||||
LimpelZiv = 0xA0 ///< Limpel-Ziv compressionrs
|
||||
, BitPackingLong = 0x40 ///< Bit packing of 32bit signed integers
|
||||
, BitPackingWord = 0x20 ///< Bit packing of 16bit unsigned integers
|
||||
, BitPackingByte = 0x00 ///< Bit packing of 8bit unsigned integers
|
||||
};
|
||||
|
||||
|
||||
bool inflatePacketData( DataSource &source, quint64 length, QList<qint64> &decodedData );
|
||||
bool deflatePacketData( QByteArray &destination, const QList<qint64> &decodedData );
|
||||
|
||||
bool inflatePropertyData( DataSource &source, quint64 length, QList<qint64> &decodedData );
|
||||
bool deflatePropertyData( QByteArray &destination, const QList<qint64> &decodedData );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,722 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "datasource.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
using namespace Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Empty constructor.
|
||||
*/
|
||||
DataSource::DataSource()
|
||||
: currentBitIndex_( 8 ) // Invalid position in the current byte
|
||||
{
|
||||
buffer_.open( QBuffer::ReadWrite );
|
||||
|
||||
currentByte_.resize( 8 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param data Byte array to copy and use as data source
|
||||
*/
|
||||
DataSource::DataSource( const QByteArray &data )
|
||||
: currentBitIndex_( 8 )
|
||||
{
|
||||
buffer_.setData( data );
|
||||
buffer_.open( QBuffer::ReadWrite );
|
||||
buffer_.seek( 0 );
|
||||
|
||||
currentByte_.resize( 8 );
|
||||
|
||||
// Move the first byte of data in the bit array
|
||||
moveByteToBitArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
DataSource::~DataSource()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Insert a byte at the end of the data.
|
||||
*
|
||||
* @param byte The byte to append
|
||||
*/
|
||||
void DataSource::append( char byte )
|
||||
{
|
||||
bool wasEmpty = ( buffer_.size() == 0 );
|
||||
|
||||
if( ! wasEmpty )
|
||||
{
|
||||
buffer_.seek( buffer_.size() );
|
||||
}
|
||||
|
||||
if( buffer_.write( &byte, 1 ) != 1 )
|
||||
{
|
||||
qWarning() << "DataSource::append() - Write failed at buffer position" << buffer_.pos();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the first byte to be read
|
||||
if( wasEmpty )
|
||||
{
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Insert bits at the end of the data.
|
||||
*
|
||||
* @param constBits The list of bits to append
|
||||
*/
|
||||
void DataSource::append( const QBitArray &constBits )
|
||||
{
|
||||
if( constBits.size() == 0 )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Not writing an empty bit array, skipping.";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if( buffer_.size() != 0 )
|
||||
{
|
||||
buffer_.seek( buffer_.size() );
|
||||
}
|
||||
|
||||
quint8 initialPos = 0;
|
||||
quint8 size = constBits.size();
|
||||
|
||||
// If there are unwritten bits, add them to the input bit array
|
||||
if( currentBitIndex_ != 8 )
|
||||
{
|
||||
size += currentBitIndex_;
|
||||
}
|
||||
|
||||
QBitArray bits( size );
|
||||
|
||||
// Copy on the input bit array the current byte then the input bits
|
||||
if( currentBitIndex_ != 8 )
|
||||
{
|
||||
initialPos = currentBitIndex_;
|
||||
for( quint8 idx = 0; idx < currentBitIndex_; ++idx )
|
||||
{
|
||||
bits[ idx ] = currentByte_[ idx ];
|
||||
}
|
||||
}
|
||||
for( quint8 idx = 0; idx < constBits.size(); ++idx )
|
||||
{
|
||||
bits[ idx + initialPos ] = constBits[ idx ];
|
||||
}
|
||||
|
||||
quint8 bit = 7;
|
||||
quint8 byte = 0;
|
||||
QByteArray bytes;
|
||||
quint8 byteWiseSize = bits.size() - ( bits.size() % 8 );
|
||||
|
||||
// Skip writing if there are no full bytes
|
||||
if( byteWiseSize != 0 )
|
||||
{
|
||||
for( quint8 idx = 0; idx < byteWiseSize; ++idx )
|
||||
{
|
||||
byte |= bits[ idx ] << bit;
|
||||
|
||||
// A byte was filled, push it to the bytearray
|
||||
if( bit-- == 0 )
|
||||
{
|
||||
bytes.append( byte );
|
||||
bit = 7;
|
||||
byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the bytes in the buffer
|
||||
if( bytes.size() > 0 && buffer_.write( bytes ) != bytes.size() )
|
||||
{
|
||||
qWarning() << "DataSource::append() - Write failed at buffer position" << buffer_.pos();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move any remaining bits to the current byte
|
||||
quint8 remainingBitSize = ( bits.size() - byteWiseSize );
|
||||
if( remainingBitSize > 0 )
|
||||
{
|
||||
for( currentBitIndex_ = 0; currentBitIndex_ < remainingBitSize; ++currentBitIndex_ )
|
||||
{
|
||||
currentByte_[ currentBitIndex_ ] = bits[ currentBitIndex_ + byteWiseSize ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentByte_.clear();
|
||||
currentByte_.resize( 8 );
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Insert bytes at the end of the data.
|
||||
*
|
||||
* @param bytes The bytes to append
|
||||
*/
|
||||
void DataSource::append( const QByteArray &bytes )
|
||||
{
|
||||
bool wasEmpty = ( buffer_.size() == 0 );
|
||||
|
||||
if( ! wasEmpty )
|
||||
{
|
||||
buffer_.seek( buffer_.size() );
|
||||
}
|
||||
|
||||
if( buffer_.write( bytes ) != bytes.size() )
|
||||
{
|
||||
qWarning() << "DataSource::append() - Write of" << bytes.size() << "bytes failed at buffer position" << buffer_.pos();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the first byte to be read
|
||||
if( wasEmpty )
|
||||
{
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get whether the buffer is finished.
|
||||
*
|
||||
* The buffer is finished (at the end) when there are no more
|
||||
* bytes to read. If the considerBits parameter is set, the
|
||||
* buffer is considered finished when all the bits have been
|
||||
* read.
|
||||
*
|
||||
* @param considerBits Whether to consider the data source as a bits source
|
||||
* @return bool
|
||||
*/
|
||||
bool DataSource::atEnd( bool considerBits ) const
|
||||
{
|
||||
if( considerBits )
|
||||
{
|
||||
// There's no more data only when both the buffer AND all the bits
|
||||
// have been read
|
||||
return buffer_.atEnd() && ( currentBitIndex_ >= 8 );
|
||||
}
|
||||
|
||||
return buffer_.atEnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clear the data buffer.
|
||||
*/
|
||||
void DataSource::clear()
|
||||
{
|
||||
buffer_.close();
|
||||
buffer_.setData( QByteArray() );
|
||||
buffer_.open( QIODevice::ReadWrite );
|
||||
buffer_.seek( 0 );
|
||||
|
||||
currentBitIndex_ = 8;
|
||||
|
||||
currentByte_.clear();
|
||||
currentByte_.resize( 8 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return a reference to the internal data array.
|
||||
*
|
||||
* @return byte array
|
||||
*/
|
||||
const QByteArray &DataSource::data() const
|
||||
{
|
||||
return buffer_.data();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Flush the current byte to the buffer.
|
||||
*
|
||||
* When in bit mode, this method can be used to save less than 8 bits
|
||||
* in the stream. The unsed bits are set to 0.
|
||||
*/
|
||||
void DataSource::flush()
|
||||
{
|
||||
if( currentBitIndex_ >= 8 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
quint8 bit = 7;
|
||||
quint8 byte = 0;
|
||||
for( quint8 index = 0; index < currentBitIndex_; ++index )
|
||||
{
|
||||
byte |= currentByte_[ index ] << bit--;
|
||||
}
|
||||
|
||||
// Write the bytes in the buffer
|
||||
if( buffer_.write( (char*)&byte, 1 ) != 1 )
|
||||
{
|
||||
qWarning() << "DataSource::flush() - Write failed at buffer position" << buffer_.pos();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the index of the current bit.
|
||||
*
|
||||
* @return Current position within the byte we're reading at the moment
|
||||
*/
|
||||
quint8 DataSource::getBitIndex()
|
||||
{
|
||||
return currentBitIndex_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the next bit from the data.
|
||||
*
|
||||
* @param ok If set, it will contain whether the call was successful or not.
|
||||
* @return bool
|
||||
*/
|
||||
bool DataSource::getBit( bool *ok )
|
||||
{
|
||||
if( currentBitIndex_ >= 8 )
|
||||
{
|
||||
// Also check the index again, in case somehow moveByteToBitArray()
|
||||
// fails to move the bit index
|
||||
if( ( ! moveByteToBitArray() ) || currentBitIndex_ >= 8 )
|
||||
{
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_ASSERT( currentBitIndex_ == 0 );
|
||||
}
|
||||
|
||||
Q_ASSERT( currentByte_.size() == 8 );
|
||||
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
++currentBitIndex_;
|
||||
|
||||
return currentByte_.at( currentBitIndex_ - 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the next [amount] bits from the data.
|
||||
*
|
||||
* @param amount Number of bits to read
|
||||
* @param ok If set, it will contain whether the call was successful or not.
|
||||
* @return quint64 with the set of read bits
|
||||
*/
|
||||
quint64 DataSource::getBits( quint8 amount, bool *ok )
|
||||
{
|
||||
if( amount > 64 )
|
||||
{
|
||||
qWarning() << "DataSource:getBits() - Cannot retrieve" << amount << "bits, the maximum is 64 bits!";
|
||||
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
bool gotBitOk = false;
|
||||
quint8 bitIndex = 0;
|
||||
quint64 value = 0;
|
||||
|
||||
while( ! atEnd( true ) && bitIndex < amount )
|
||||
{
|
||||
bool bit = getBit( &gotBitOk );
|
||||
|
||||
if( ! gotBitOk )
|
||||
{
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
if( bit )
|
||||
{
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
value |= 1 << bitIndex;
|
||||
#else
|
||||
value |= 1 << ( amount - bitIndex - 1 );
|
||||
#endif
|
||||
}
|
||||
|
||||
++bitIndex;
|
||||
}
|
||||
|
||||
// If more bits must be read, but are not available, abort
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
if( ( bitIndex < amount ) && atEnd( true ) )
|
||||
{
|
||||
qDebug() << "Unable to read all bits: only" << bitIndex << "of" << amount << "were available.";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Done!
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the next byte from the data
|
||||
*
|
||||
* @param ok If set, it will contain whether the call was successful or not.
|
||||
* @return char
|
||||
*/
|
||||
char DataSource::getByte( bool *ok )
|
||||
{
|
||||
bool gotBitOk;
|
||||
quint8 pos = 0;
|
||||
qint8 byte = 0;
|
||||
|
||||
while( pos < 8 )
|
||||
{
|
||||
bool bit = getBit( &gotBitOk );
|
||||
|
||||
if( ! gotBitOk )
|
||||
{
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
byte |= ( bit << pos++ );
|
||||
#else
|
||||
byte |= ( bit << ( 7 - pos++ ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
// Done!
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the next [amount] bytes from the data.
|
||||
*
|
||||
* @param amount Number of bytes to read
|
||||
* @param ok If set, it will contain whether the call was successful or not.
|
||||
* @return byte array of read bytes
|
||||
*/
|
||||
QByteArray DataSource::getBytes( quint8 amount, bool *ok )
|
||||
{
|
||||
QByteArray bytes;
|
||||
bool gotByteOk;
|
||||
quint8 index = 0;
|
||||
|
||||
while( ! atEnd() && index < amount )
|
||||
{
|
||||
quint8 byte = getByte( &gotByteOk );
|
||||
|
||||
if( ! gotByteOk )
|
||||
{
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bytes.append( byte );
|
||||
++index;
|
||||
}
|
||||
|
||||
// Done!
|
||||
if( ok != 0 )
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Move a byte from the buffer into the 'current byte' bit array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool DataSource::moveByteToBitArray()
|
||||
{
|
||||
quint8 byte = 0;
|
||||
|
||||
if( buffer_.size() == 0 )
|
||||
{
|
||||
qWarning() << "DataSource:moveByteToBitArray() - The buffer is empty!";
|
||||
currentByte_.clear();
|
||||
currentBitIndex_ = 8;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( buffer_.atEnd() )
|
||||
{
|
||||
qWarning() << "DataSource:moveByteToBitArray() - The buffer was completely parsed!";
|
||||
currentByte_.clear();
|
||||
currentBitIndex_ = 8;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( buffer_.getChar( (char*)&byte ) != 1 )
|
||||
{
|
||||
qWarning() << "DataSource::moveByteToBitArray() - Read failed at buffer position" << buffer_.pos();
|
||||
return false;
|
||||
}
|
||||
|
||||
for( qint8 i = 0; i < 8; i++ )
|
||||
{
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
currentByte_.setBit( i, byte & ( 1 << i ) );
|
||||
#else
|
||||
currentByte_.setBit( 7 - i, byte & ( 1 << i ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
currentBitIndex_ = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the current position within the internal data buffer.
|
||||
*
|
||||
* @return qint64
|
||||
*/
|
||||
qint64 DataSource::pos() const
|
||||
{
|
||||
return buffer_.pos();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Insert a byte at the beginning of the data.
|
||||
*
|
||||
* @param byte Byte to add
|
||||
*/
|
||||
void DataSource::prepend( char byte )
|
||||
{
|
||||
buffer_.buffer().prepend( byte );
|
||||
|
||||
bool wasAtBeginning = ( buffer_.pos() == 0 );
|
||||
|
||||
seekRelative( 1 );
|
||||
|
||||
if( wasAtBeginning )
|
||||
{
|
||||
moveByteToBitArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Insert bytes at the beginning of the data.
|
||||
*
|
||||
* @param bytes Bytes to add
|
||||
*/
|
||||
void DataSource::prepend( const QByteArray &bytes )
|
||||
{
|
||||
buffer_.buffer().prepend( bytes );
|
||||
|
||||
bool wasAtBeginning = ( buffer_.pos() == 0 );
|
||||
|
||||
seekRelative( bytes.size() );
|
||||
|
||||
if( wasAtBeginning )
|
||||
{
|
||||
moveByteToBitArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
/**
|
||||
* Return to the start of the buffer.
|
||||
*/
|
||||
void DataSource::reset()
|
||||
{
|
||||
buffer_.reset();
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
/**
|
||||
* Seek back and forth in the stream.
|
||||
*
|
||||
* A negative pos will move backwards within the stream.
|
||||
*
|
||||
* @param pos Relative position where to move
|
||||
*/
|
||||
void DataSource::seekRelative( int pos )
|
||||
{
|
||||
if( pos < 0 && buffer_.pos() <= 0 )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qWarning() << "Cannot seek back!";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if( pos > 0 && ( buffer_.size() - buffer_.pos() ) < pos )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qWarning() << "Cannot seek forward!";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_.seek( buffer_.pos() + pos );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Replace the data byte array with another.
|
||||
*
|
||||
* @param data New array to copy and use as the data source
|
||||
*/
|
||||
void DataSource::setData( const QByteArray &data )
|
||||
{
|
||||
buffer_.close();
|
||||
buffer_.setData( data );
|
||||
buffer_.open( QIODevice::ReadWrite );
|
||||
buffer_.seek( 0 );
|
||||
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skip the rest of the current byte and read the next one.
|
||||
*
|
||||
* When using the data source in bit mode, this skips the
|
||||
* bits remaining in the current byte and prepares to read
|
||||
* the next byte.
|
||||
*/
|
||||
void DataSource::skipToNextByte()
|
||||
{
|
||||
if( currentBitIndex_ == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
moveByteToBitArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skip the rest of the current byte and read the previous one.
|
||||
*
|
||||
* When using the data source in bit mode, this skips the
|
||||
* bits remaining in the current byte and prepares to read
|
||||
* the next byte.
|
||||
*/
|
||||
void DataSource::skipToPrevByte()
|
||||
{
|
||||
currentBitIndex_ = 8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
/**
|
||||
* Get the size of the data.
|
||||
*
|
||||
* @return qint64
|
||||
*/
|
||||
qint64 DataSource::size() const
|
||||
{
|
||||
return buffer_.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef DATASOURCE_H
|
||||
#define DATASOURCE_H
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QBuffer>
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
/**
|
||||
* @class DataSource
|
||||
* @brief Class to handle a QBuffer at the bit level.
|
||||
*
|
||||
* You can use this class in two ways: first, reading and writing bytes
|
||||
* normally. Second, reading and writing individual bits.
|
||||
*
|
||||
* Warning: Mixing up the usage modes is not very well tested!
|
||||
*/
|
||||
class DataSource
|
||||
{
|
||||
|
||||
public: // Public constructors
|
||||
DataSource();
|
||||
DataSource( const QByteArray &data );
|
||||
~DataSource();
|
||||
|
||||
public: // Public status retrieval methods
|
||||
bool atEnd( bool considerBits = false ) const;
|
||||
const QByteArray &data() const;
|
||||
qint64 pos() const;
|
||||
qint64 size() const;
|
||||
|
||||
public: // Public data manipulation methods
|
||||
void append( char byte );
|
||||
void append( const QBitArray &bits );
|
||||
void append( const QByteArray &bytes );
|
||||
void clear();
|
||||
void flush();
|
||||
bool getBit( bool *ok = 0 );
|
||||
quint64 getBits( quint8 amount, bool *ok = 0 );
|
||||
quint8 getBitIndex();
|
||||
char getByte( bool *ok = 0 );
|
||||
QByteArray getBytes( quint8 amount, bool *ok = 0 );
|
||||
void prepend( char byte );
|
||||
void prepend( const QByteArray &bytes );
|
||||
void reset();
|
||||
void setData( const QByteArray &data );
|
||||
void seekRelative( int pos );
|
||||
void skipToNextByte();
|
||||
void skipToPrevByte();
|
||||
|
||||
private: // Private methods
|
||||
bool moveByteToBitArray();
|
||||
|
||||
private: // Private properties
|
||||
/// Main data buffer
|
||||
QBuffer buffer_;
|
||||
/// Current bit within the bit array
|
||||
quint8 currentBitIndex_;
|
||||
/// Current byte
|
||||
QBitArray currentByte_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,358 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "multibytecoding.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes an unsigned integer into a quint64 using multibyte decoding.
|
||||
*
|
||||
* @param source Data Source where to read bytes from
|
||||
* @return quint64
|
||||
*/
|
||||
quint64 Compress::decodeUInt( DataSource &source )
|
||||
{
|
||||
quint8 byte; // Current byte
|
||||
quint8 flag; // Used to find out if there are more bytes to convert
|
||||
quint8 count = 0; // Count of bits read so far
|
||||
quint64 value = 0; // Destination 64-bit value
|
||||
|
||||
do
|
||||
{
|
||||
byte = source.getByte();
|
||||
flag = byte & 0x80;
|
||||
value |= (byte & 0x7F) << count;
|
||||
count += 7;
|
||||
}
|
||||
while( flag );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a signed integer into a qint64 using multibyte decoding.
|
||||
*
|
||||
* @param source Data Source where to read bytes from
|
||||
* @return qint64
|
||||
*/
|
||||
qint64 Compress::decodeInt( DataSource &source )
|
||||
{
|
||||
bool isNegative = false;
|
||||
qint64 value = decodeUInt( source );
|
||||
|
||||
// The least significant bit contains the sign
|
||||
if( value & 0x01 )
|
||||
{
|
||||
isNegative = true;
|
||||
}
|
||||
|
||||
// Remove the sign bit from the raw value
|
||||
value >>= 1;
|
||||
|
||||
// Apply the sign
|
||||
if( isNegative )
|
||||
{
|
||||
value *= -1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a float using multibyte decoding.
|
||||
*
|
||||
* @param source Data Source where to read bytes from
|
||||
* @return float
|
||||
*/
|
||||
float Compress::decodeFloat( DataSource &source )
|
||||
{
|
||||
qint8 index;
|
||||
|
||||
// Union used to decode the float transparently
|
||||
union
|
||||
{
|
||||
float value;
|
||||
uchar bytes[4];
|
||||
} data;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
index = 3;
|
||||
do
|
||||
{
|
||||
data.bytes[ index-- ] = source.getByte();
|
||||
}
|
||||
while( index >= 0 );
|
||||
#else
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
data.bytes[ index++ ] = source.getByte();
|
||||
}
|
||||
while( index <= 3 );
|
||||
#endif
|
||||
|
||||
return data.value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes an unsigned 64-bit integer into a byte array using multibyte encoding.
|
||||
*
|
||||
* @param value The value to encode
|
||||
* @return byte array
|
||||
*/
|
||||
QByteArray Compress::encodeUInt( quint64 value )
|
||||
{
|
||||
quint8 byte;
|
||||
quint8 flag;
|
||||
QByteArray result;
|
||||
|
||||
do
|
||||
{
|
||||
byte = value & 0x7F;
|
||||
value >>= 7;
|
||||
|
||||
flag = ( value == 0 ) ? 0 : 0x80;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
result.prepend( byte | flag );
|
||||
#else
|
||||
result.append( byte | flag );
|
||||
#endif
|
||||
}
|
||||
while( flag );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes an unsigned 64-bit integer into the Data Source using multibyte encoding.
|
||||
*
|
||||
* @param source The data source
|
||||
* @param value The value to encode
|
||||
* @param prepend False (default value) to append the encoded value to the existing data
|
||||
* True to prepend the new value to the existing data
|
||||
*/
|
||||
void Compress::encodeUInt( DataSource &source, quint64 value, bool prepend )
|
||||
{
|
||||
QByteArray result( encodeUInt( value ) );
|
||||
|
||||
if( prepend )
|
||||
{
|
||||
source.prepend( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
source.append( result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a signed 64-bit integer into a byte array using multibyte encoding.
|
||||
*
|
||||
* @param value The value to encode
|
||||
* @return byte array
|
||||
*/
|
||||
QByteArray Compress::encodeInt( qint64 value )
|
||||
{
|
||||
bool isNegative = ( value < 0 );
|
||||
if ( isNegative ) value *= -1;
|
||||
|
||||
value = value << 1;
|
||||
|
||||
QByteArray result( encodeUInt( value ) );
|
||||
|
||||
if ( isNegative )
|
||||
{
|
||||
int pos;
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
pos = result.size() - 1;
|
||||
#else
|
||||
pos = 0;
|
||||
#endif
|
||||
|
||||
result[ pos ] = result[ pos ] | 0x1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a signed 64-bit integer into the Data Source using multibyte encoding.
|
||||
*
|
||||
* @param source The data source
|
||||
* @param value The value to encode
|
||||
* @param prepend False (default value) to append the encoded value to the existing data
|
||||
* True to prepend the new value to the existing data
|
||||
*/
|
||||
void Compress::encodeInt( DataSource &source, qint64 value, bool prepend )
|
||||
{
|
||||
QByteArray result( encodeInt( value ) );
|
||||
|
||||
if( prepend )
|
||||
{
|
||||
source.prepend( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
source.append( result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a floating-point value into a byte array using multibyte encoding.
|
||||
*
|
||||
* @param value The value to encode
|
||||
* @return byte array
|
||||
*/
|
||||
QByteArray Compress::encodeFloat( float value )
|
||||
{
|
||||
qint8 index;
|
||||
QByteArray result;
|
||||
|
||||
// Union used to encode the float transparently
|
||||
union
|
||||
{
|
||||
float number;
|
||||
uchar bytes[4];
|
||||
} data;
|
||||
|
||||
data.number = value;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
index = 3;
|
||||
do
|
||||
{
|
||||
result.append( data.bytes[ index-- ] );
|
||||
}
|
||||
while( index >= 0 );
|
||||
#else
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
result.append( data.bytes[ index++ ] );
|
||||
}
|
||||
while( index <= 3 );
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a floating-point value into the Data Source using multibyte encoding.
|
||||
*
|
||||
* @param source The data source
|
||||
* @param value The value to encode
|
||||
* @param prepend False (default value) to append the encoded value to the existing data
|
||||
* True to prepend the new value to the existing data
|
||||
*/
|
||||
void Compress::encodeFloat( DataSource &source, float value, bool prepend )
|
||||
{
|
||||
QByteArray result( encodeFloat( value ) );
|
||||
|
||||
if( prepend )
|
||||
{
|
||||
source.prepend( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
source.append( result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return how much bytes a certain unsigned value takes up using multi-byte encoding.
|
||||
*
|
||||
* @param value The unsigned value to check
|
||||
* @return Number of bytes required for multi-byte storage of that value
|
||||
*/
|
||||
quint8 Compress::getMultiByteSize( quint64 value )
|
||||
{
|
||||
quint8 bytes = 1;
|
||||
|
||||
while( value )
|
||||
{
|
||||
value >>= 7;
|
||||
|
||||
if( value )
|
||||
{
|
||||
++bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return how much bytes a certain signed value takes up using multi-byte encoding.
|
||||
*
|
||||
* @param value The signed value to check
|
||||
* @return Number of bytes required for multi-byte storage of that value
|
||||
*/
|
||||
quint8 Compress::getMultiByteSize( qint64 value )
|
||||
{
|
||||
quint8 bytes = 1;
|
||||
|
||||
while( value )
|
||||
{
|
||||
value >>= 6;
|
||||
|
||||
if( value )
|
||||
{
|
||||
++bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MULTIBYTECODING_H
|
||||
#define MULTIBYTECODING_H
|
||||
|
||||
#include "datasource.h"
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
namespace Compress
|
||||
{
|
||||
|
||||
quint64 decodeUInt( DataSource &source );
|
||||
qint64 decodeInt( DataSource &source );
|
||||
float decodeFloat( DataSource &source );
|
||||
|
||||
QByteArray encodeUInt( quint64 value );
|
||||
void encodeUInt( DataSource &source, quint64 value, bool prepend = false );
|
||||
|
||||
QByteArray encodeInt( qint64 value );
|
||||
void encodeInt( DataSource &source, qint64 value, bool prepend = false );
|
||||
|
||||
QByteArray encodeFloat( float value );
|
||||
void encodeFloat( DataSource &source, float value, bool prepend = false );
|
||||
|
||||
quint8 getMultiByteSize( quint64 value );
|
||||
quint8 getMultiByteSize( qint64 value );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFQT_GIF_SUPPORT_H
|
||||
#define ISFQT_GIF_SUPPORT_H
|
||||
|
||||
#include <gif_lib.h>
|
||||
|
||||
#define MAX_GIF_BYTE 255
|
||||
|
||||
|
||||
|
||||
// Internal helper function to read GIF data from a byte array
|
||||
int GifReadFromByteArray( GifFileType *gif, GifByteType* bytes, int size )
|
||||
{
|
||||
QBuffer *buffer = (QBuffer*) gif->UserData;
|
||||
return buffer->read( (char*)bytes, size );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Internal helper function to write GIF data into a byte array
|
||||
int GifWriteToByteArray( GifFileType *gif, const GifByteType* bytes, int size )
|
||||
{
|
||||
QBuffer *buffer = (QBuffer*) gif->UserData;
|
||||
return buffer->write( (char*)bytes, size );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
// Define contents of the main page
|
||||
|
||||
/**
|
||||
* @mainpage ISF-Qt - Ink Serialized Format library
|
||||
*
|
||||
* @section about About ISF-Qt
|
||||
*
|
||||
* ISF-Qt is a library, written in C++ with the Qt 4 toolkit, capable of reading
|
||||
* and writing the ISF format. ISF stands for "Ink Serialized Format", and is
|
||||
* the disk serialization format used by the Windows.Ink C# library and by the
|
||||
* TabletPC platform, but also by applications like Windows Live Messenger - which
|
||||
* uses ISF to transfer handwriting messages.
|
||||
*
|
||||
* We had the need to interpret these handwriting messages in the best possible
|
||||
* way, and started to reverse-engineer the format, with the help of existing
|
||||
* (but incomplete) libraries and specifications. What we ended up with is ISF-Qt,
|
||||
* a library which can be used to decode an ISF file or data stream, manage it
|
||||
* and the the strokes which comprise the drawing, and write ISF files/streams.
|
||||
* You can also create new drawings from scratch.
|
||||
*
|
||||
*
|
||||
* @section intro About this documentation
|
||||
* This documentation is written towards developers, to be used
|
||||
* as reference manual when writing code which uses ISF-Qt, or when developing
|
||||
* the library itself.
|
||||
* Please take your time to understand the structure of the library, its classes
|
||||
* and methods.
|
||||
*
|
||||
* Since ISF-Qt is built on top of the Qt 4 library, you will also need to
|
||||
* be familiar with it; more information can be found online at:
|
||||
* - http://doc.trolltech.com/4.3/index.html
|
||||
*/
|
||||
@@ -0,0 +1,763 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include "isfinkcanvas.h"
|
||||
#include "isfqtdrawing.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new InkCanvas widget.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
InkCanvas:: InkCanvas( QWidget *parent )
|
||||
: QWidget( parent )
|
||||
, erasingImage_( false )
|
||||
, drawing_( 0 )
|
||||
, scribbling_( false )
|
||||
, currentStroke_( 0 )
|
||||
, drawingDirty_( true )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "** Created new InkCanvas:" << this << "**";
|
||||
#endif
|
||||
|
||||
setCanvasColor( Qt::white );
|
||||
setPenColor( Qt::black );
|
||||
setPenSize( 4 );
|
||||
|
||||
clear();
|
||||
|
||||
// prepare the buffer
|
||||
clearBuffer();
|
||||
|
||||
// create a custom cursor
|
||||
updateCursor();
|
||||
|
||||
// start with a drawing pen by default.
|
||||
setPenType( DrawingPen );
|
||||
|
||||
setAttribute( Qt::WA_StaticContents );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* There are no members on stack, so it's currently not used.
|
||||
*/
|
||||
InkCanvas::~InkCanvas()
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "** Destroyed InkCanvas:" << this << "**";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a QCursor displayed when the mouse pointer moves over the widget.
|
||||
*
|
||||
* The cursor becomes a point, drawn with the current stroke colour and pen size.
|
||||
*/
|
||||
void InkCanvas::updateCursor()
|
||||
{
|
||||
if ( cursorPixmap_.isNull() )
|
||||
{
|
||||
cursorPixmap_ = QPixmap( QSize( 32, 32 ) );
|
||||
}
|
||||
|
||||
if ( penType_ == EraserPen )
|
||||
{
|
||||
cursorPixmap_ = QPixmap( ":pics/draw-eraser.png" );
|
||||
cursor_ = QCursor( cursorPixmap_, 0, cursorPixmap_.height() );
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorPixmap_.fill( Qt::transparent );
|
||||
|
||||
QPainter painter( &cursorPixmap_ );
|
||||
|
||||
painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true );
|
||||
painter.setPen( QPen( color_, penSize_, Qt::SolidLine, Qt::RoundCap,
|
||||
Qt::RoundJoin ) );
|
||||
|
||||
// now draw a point.
|
||||
painter.drawPoint( QPoint( cursorPixmap_.size().width() / 2, cursorPixmap_.size().height() / 2 ) );
|
||||
|
||||
cursor_ = QCursor( cursorPixmap_ );
|
||||
}
|
||||
|
||||
// create our cursor.
|
||||
setCursor( cursor_ );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the suggested size for the canvas.
|
||||
*
|
||||
* The actual size hint will depend on the size of the drawing on the canvas. By default,
|
||||
* the size hint is 300x300 pixels.
|
||||
*/
|
||||
QSize InkCanvas::sizeHint() const
|
||||
{
|
||||
if ( drawing_->isNull() )
|
||||
{
|
||||
return QSize( 300, 300 );
|
||||
}
|
||||
else
|
||||
{
|
||||
QRect boundingRect = drawing_->boundingRect();
|
||||
boundingRect.setTopLeft( QPoint( 0, 0 ) );
|
||||
return boundingRect.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clears the current image, discarding all drawn strokes.
|
||||
*
|
||||
* Stroke attributes such as pen size, pen type and color are not cleared.
|
||||
*
|
||||
*/
|
||||
void InkCanvas::clear()
|
||||
{
|
||||
if ( drawing_ == 0 )
|
||||
{
|
||||
drawing_ = &initialDrawing_;
|
||||
}
|
||||
|
||||
drawing_->clear();
|
||||
drawingDirty_ = true;
|
||||
|
||||
update();
|
||||
|
||||
emit inkChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change the color of the pen used to draw on the Ink canvas.
|
||||
*
|
||||
* @param newColor The new color for the pen.
|
||||
*/
|
||||
void InkCanvas::setPenColor( QColor newColor )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Setting new pen color:" << newColor.name();
|
||||
#endif
|
||||
|
||||
color_ = newColor;
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change the size of the pen. This value is in pixels.
|
||||
*
|
||||
* @param pixels The size of the pen, in pixels
|
||||
*/
|
||||
void InkCanvas::setPenSize( int pixels )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Setting new pen size:" << pixels;
|
||||
#endif
|
||||
penSize_ = pixels;
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change the pen type.
|
||||
*
|
||||
* Currently, only PenType::EraserPen and PenType::DrawingPen are supported. See the PenType
|
||||
* enum for more information.
|
||||
*
|
||||
* @see PenType
|
||||
* @param type The new pen type
|
||||
*/
|
||||
void InkCanvas::setPenType( PenType type )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Setting new pen type:" << type;
|
||||
#endif
|
||||
|
||||
penType_ = type;
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Draw a line from the current point to an ending point.
|
||||
*
|
||||
* The current point is initially set in mousePressEvent();
|
||||
* then it's set here.
|
||||
*
|
||||
* @see mousePressEvent()
|
||||
* @param endPoint Final point of the line
|
||||
*/
|
||||
void InkCanvas::drawLineTo( const QPoint &endPoint )
|
||||
{
|
||||
if( drawing_ == 0 )
|
||||
{
|
||||
qWarning() << "Uninitialized usage of InkCanvas!";
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the "in progress" strokes on the buffer.
|
||||
QPainter painter( &(bufferPixmap_) );
|
||||
painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true );
|
||||
|
||||
QColor color = color_;
|
||||
if( erasingImage_ )
|
||||
{
|
||||
color = QColor( "white" );
|
||||
}
|
||||
|
||||
painter.setPen( QPen( color, penSize_, Qt::SolidLine, Qt::RoundCap,
|
||||
Qt::RoundJoin ) );
|
||||
|
||||
// QPainter::drawLine() doesn't draw anything if the two points are the same
|
||||
if( lastPoint_ == endPoint )
|
||||
{
|
||||
painter.drawPoint( endPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine( lastPoint_, endPoint );
|
||||
}
|
||||
|
||||
int rad = (1 / 2) + 2;
|
||||
update( QRect( lastPoint_, endPoint ).normalized()
|
||||
.adjusted( -rad, -rad, +rad, +rad ) );
|
||||
|
||||
lastPoint_ = endPoint;
|
||||
|
||||
// Refresh the widget with the new stroke
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get whether the drawing is empty (i.e., contains no strokes).
|
||||
*
|
||||
* @return True if the Ink image is empty, false otherwise
|
||||
*/
|
||||
bool InkCanvas::isEmpty()
|
||||
{
|
||||
return drawing_->isNull();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Start drawing a new stroke.
|
||||
*
|
||||
* Look at mouseMoveEvent() and mouseReleaseEvent() for more
|
||||
* information on how drawing is done.
|
||||
*
|
||||
* This method is usually called by Qt.
|
||||
*
|
||||
* @see mouseMoveEvent()
|
||||
* @see mouseReleaseEvent()
|
||||
* @param event The mouse button press event
|
||||
*/
|
||||
void InkCanvas::mousePressEvent( QMouseEvent *event )
|
||||
{
|
||||
if( drawing_ == 0 )
|
||||
{
|
||||
qWarning() << "Uninitialized usage of InkCanvas!";
|
||||
return;
|
||||
}
|
||||
|
||||
if( event->button() != Qt::LeftButton )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scribbling_ = true;
|
||||
|
||||
if ( penType_ == EraserPen )
|
||||
{
|
||||
// is there a stroke here?
|
||||
QPoint point = event->pos();
|
||||
Stroke *s = drawing_->strokeAtPoint( point );
|
||||
if ( s != 0 )
|
||||
{
|
||||
drawing_->deleteStroke( s );
|
||||
drawingDirty_ = true;
|
||||
update();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lastPoint_ = event->pos();
|
||||
|
||||
// Search if there already is an attributes set compatible with the current one
|
||||
Isf::AttributeSet *reusableAttributeSet = 0;
|
||||
foreach( Isf::AttributeSet *set, drawing_->attributeSets() )
|
||||
{
|
||||
if( abs( (qreal)penSize_ - set->penSize.width() ) < 1.0f
|
||||
&& color_ == set->color )
|
||||
{
|
||||
reusableAttributeSet = set;
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Found an usable ISF attribute set";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If none is found, create a new one
|
||||
if( ! reusableAttributeSet )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Creating new attribute set";
|
||||
#endif
|
||||
reusableAttributeSet = new Isf::AttributeSet;
|
||||
reusableAttributeSet->color = color_;
|
||||
reusableAttributeSet->penSize.setWidth ( (qreal)penSize_ );
|
||||
reusableAttributeSet->penSize.setHeight( (qreal)penSize_ );
|
||||
|
||||
drawing_->addAttributeSet( reusableAttributeSet );
|
||||
}
|
||||
|
||||
// Use it for the next strokes
|
||||
drawing_->setCurrentAttributeSet( reusableAttributeSet );
|
||||
|
||||
// If there already is a stroke, add it
|
||||
if( currentStroke_ )
|
||||
{
|
||||
drawing_->addStroke( currentStroke_ );
|
||||
currentStroke_ = 0;
|
||||
}
|
||||
|
||||
currentStroke_ = new Isf::Stroke;
|
||||
currentStroke_->points.append( Isf::Point( lastPoint_ ) );
|
||||
|
||||
// Draw the initial point
|
||||
drawLineTo( lastPoint_ );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Continue drawing the current stroke.
|
||||
*
|
||||
* As the cursor moves across the canvas we continue drawing the stroke started in
|
||||
* mousePressEvent(). A line is drawn between the last point and the current point
|
||||
* as given by QMouseEvent::pos().
|
||||
*
|
||||
* Once the mouse button is released, drawing ends.
|
||||
*
|
||||
* @see mousePressEvent()
|
||||
* @see mouseReleaseEvent()
|
||||
* @param event The mouse move event
|
||||
*/
|
||||
void InkCanvas::mouseMoveEvent( QMouseEvent *event )
|
||||
{
|
||||
if( ! ( event->buttons() & Qt::LeftButton ) || ! scribbling_ )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( penType_ == EraserPen )
|
||||
{
|
||||
// is there a stroke here?
|
||||
QPoint point = event->pos();
|
||||
Stroke *s = drawing_->strokeAtPoint( point );
|
||||
if ( s != 0 )
|
||||
{
|
||||
drawing_->deleteStroke( s );
|
||||
drawingDirty_ = true;
|
||||
update();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( drawing_ == 0 )
|
||||
{
|
||||
qWarning() << "Uninitialized usage of InkCanvas!";
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint position( event->pos() );
|
||||
|
||||
// Don't add duplicate points. Mainly useful when drawing dots.
|
||||
if( lastPoint_ == position )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
drawLineTo( position );
|
||||
|
||||
if( currentStroke_ == 0 )
|
||||
{
|
||||
#ifdef KMESSDEBUG_INKEDIT_GENERAL
|
||||
qWarning() << "The stroke isn't ready!";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new point to the stroke
|
||||
currentStroke_->points.append( Isf::Point( lastPoint_ ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Finish drawing the current stroke.
|
||||
*
|
||||
* Adds this stroke, with the correct attributes, to the Isf::Drawing strokes collection.
|
||||
*
|
||||
* @see mousePressEvent()
|
||||
* @see mouseMoveEvent()
|
||||
* @param event The mouse release event
|
||||
*/
|
||||
void InkCanvas::mouseReleaseEvent( QMouseEvent *event )
|
||||
{
|
||||
if( drawing_ == 0 )
|
||||
{
|
||||
qWarning() << "Uninitialized usage of InkCanvas!";
|
||||
return;
|
||||
}
|
||||
|
||||
if( event->button() != Qt::LeftButton || ! scribbling_ )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( penType_ == EraserPen )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint position = event->pos();
|
||||
|
||||
// Don't redraw already drawn points or lines
|
||||
if( lastPoint_ != position )
|
||||
{
|
||||
drawLineTo( position );
|
||||
}
|
||||
|
||||
scribbling_ = false;
|
||||
emit inkChanged();
|
||||
|
||||
if( ! currentStroke_ )
|
||||
{
|
||||
#ifdef KMESSDEBUG_INKEDIT_GENERAL
|
||||
qWarning() << "The stroke isn't ready!";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef KMESSDEBUG_INKEDIT_GENERAL
|
||||
qDebug() << "Finishing up stroke";
|
||||
#endif
|
||||
|
||||
// Don't add duplicate points. Mainly useful when drawing dots.
|
||||
if( lastPoint_ != position )
|
||||
{
|
||||
currentStroke_->points.append( Isf::Point( lastPoint_ ) );
|
||||
}
|
||||
|
||||
drawing_->addStroke( currentStroke_ );
|
||||
|
||||
currentStroke_ = 0;
|
||||
|
||||
drawingDirty_ = true;
|
||||
|
||||
// clear the buffer.
|
||||
clearBuffer();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clear the internal pixmap buffer.
|
||||
*
|
||||
* The buffer used to quickly render on the widget painting area
|
||||
* the new and old strokes: every new stroke is saved here.
|
||||
* This allows to avoid repainting all strokes at every paint event.
|
||||
*/
|
||||
void InkCanvas::clearBuffer()
|
||||
{
|
||||
bufferPixmap_ = QPixmap( size() );
|
||||
bufferPixmap_.fill( Qt::transparent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Repaints the ink canvas.
|
||||
*
|
||||
* For performance reasons an internal buffer is used to ensure that
|
||||
* the entire Ink drawing is not re-rendered on each paintEvent call.
|
||||
* This buffer is invalidated only when a stroke is added or removed, the
|
||||
* drawing is changed or the canvas cleared.
|
||||
*
|
||||
*
|
||||
* @param event The paint event from Qt.
|
||||
*/
|
||||
void InkCanvas::paintEvent( QPaintEvent *event )
|
||||
{
|
||||
Q_UNUSED( event );
|
||||
|
||||
QPainter painter( this );
|
||||
|
||||
painter.save();
|
||||
painter.setBrush( QBrush( canvasColor_ ) );
|
||||
painter.drawRect( QRect(-1, -1, width() + 1 , height() + 1 ) );
|
||||
painter.restore();
|
||||
|
||||
if( drawing_ == 0 )
|
||||
{
|
||||
qWarning() << "Uninitialized usage of InkCanvas!";
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the ISF first, then the buffer over the top.
|
||||
// buffer has a transparent background.
|
||||
QPixmap isfPixmap( drawingDirty_
|
||||
? drawing_->pixmap( Qt::transparent )
|
||||
: isfCachePixmap_ );
|
||||
|
||||
if ( drawingDirty_ )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "ISF pixmap cache dirty; re-caching.";
|
||||
#endif
|
||||
isfCachePixmap_ = isfPixmap;
|
||||
drawingDirty_ = false;
|
||||
}
|
||||
|
||||
QRect boundingRect = drawing_->boundingRect();
|
||||
|
||||
// draw the pixmap starting at the boundingRect_ top left corner.
|
||||
painter.drawPixmap( boundingRect.topLeft(), isfPixmap );
|
||||
|
||||
// draw the buffer from 0,0.
|
||||
painter.drawPixmap( QPoint(0, 0), bufferPixmap_ );
|
||||
|
||||
QWidget::paintEvent( event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The widget has changed size, re-draw everything.
|
||||
*
|
||||
* @param event The resizing event.
|
||||
*/
|
||||
void InkCanvas::resizeEvent( QResizeEvent *event )
|
||||
{
|
||||
// need to resize the buffer pixmap.
|
||||
clearBuffer();
|
||||
|
||||
update();
|
||||
|
||||
QWidget::resizeEvent( event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Renders the ink drawing to a QImage and returns it.
|
||||
*
|
||||
* @return A QImage containing the rendered Ink.
|
||||
*/
|
||||
QImage InkCanvas::image()
|
||||
{
|
||||
return drawing_->pixmap().toImage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the current pen color.
|
||||
*
|
||||
* @return The current pen color.
|
||||
*/
|
||||
QColor InkCanvas::penColor()
|
||||
{
|
||||
return color_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the current pen type.
|
||||
*
|
||||
* @return The current pen type.
|
||||
*/
|
||||
int InkCanvas::penSize()
|
||||
{
|
||||
return penSize_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the current pen type.
|
||||
*
|
||||
* See the PenType enum for details.
|
||||
*
|
||||
* @see PenType
|
||||
* @return The current pen type.
|
||||
*/
|
||||
InkCanvas::PenType InkCanvas::penType()
|
||||
{
|
||||
return penType_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the Isf::Drawing instance that the canvas is currently manipulating.
|
||||
*
|
||||
* Beware: if you have not set your own Isf::Drawing instance via setDrawing(), you must not delete
|
||||
* the object that this method returns. In this case this method returns a pointer to an internal
|
||||
* Isf::Drawing instance that must not be deleted. If you have previously used setDrawing() then you
|
||||
* are free to do whatever you like with this pointer.
|
||||
*
|
||||
* \code
|
||||
* InkCanvas *canvas = new InkCanvas( this );
|
||||
*
|
||||
* Isf::Drawing *drawing = canvas->drawing();
|
||||
* delete drawing; // bad! deleting an object internal to InkCanvas.
|
||||
*
|
||||
* canvas->setDrawing( existingIsfDrawingInstance );
|
||||
*
|
||||
* drawing = canvas->drawing();
|
||||
* delete drawing; // good - drawing points to existingIsfDrawingInstance.
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* @see setDrawing()
|
||||
* @return The current Isf::Drawing instance.
|
||||
*/
|
||||
Isf::Drawing *InkCanvas::drawing()
|
||||
{
|
||||
return drawing_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Save the current ISF drawing to a QIODevice.
|
||||
*
|
||||
* If the base64 param is True, then the drawing will be written base64-encoded.
|
||||
* This is helpful for transmission over mediums which are not binary-friendly.
|
||||
*
|
||||
* @param dev The QIODevice to save to.
|
||||
* @param base64 If true, the drawing is written encoded with base64.
|
||||
*/
|
||||
|
||||
void InkCanvas::save( QIODevice &dev, bool base64 )
|
||||
{
|
||||
dev.write( Isf::Stream::writer( *drawing_, base64 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the drawing's ISF representation.
|
||||
*
|
||||
* @return A QByteArray filled with ISF data.
|
||||
*/
|
||||
QByteArray InkCanvas::bytes()
|
||||
{
|
||||
return Isf::Stream::writer( *drawing_ );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the canvas colour (i.e., the background colour of the InkCanvas control)
|
||||
*
|
||||
* Note: this is not saved with the Ink data. This is only used for colouring the canvas.
|
||||
*
|
||||
* @param newColor The new canvas color.
|
||||
*/
|
||||
void InkCanvas::setCanvasColor( QColor newColor )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Setting new canvas color:" << newColor.name();
|
||||
#endif
|
||||
canvasColor_ = newColor;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Changes the currently displayed Ink to the one supplied.
|
||||
*
|
||||
* Note: InkCanvas does not take ownership of Isf::Drawing instances supplied here.
|
||||
* You are still responsible for ensuring they are deleted appropriately.
|
||||
*
|
||||
* @param drawing The new Ink drawing to display.
|
||||
*/
|
||||
void InkCanvas::setDrawing( Isf::Drawing *drawing )
|
||||
{
|
||||
drawing_ = drawing;
|
||||
|
||||
// try to resize of the widget to accommodate the
|
||||
// drawing.
|
||||
QRect boundingRect = drawing_->boundingRect();
|
||||
boundingRect.setTopLeft( QPoint( 0, 0 ) );
|
||||
|
||||
resize( boundingRect.width(), boundingRect.height() );
|
||||
|
||||
drawingDirty_ = true;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ISFQT_INTERNAL_H
|
||||
#define ISFQT_INTERNAL_H
|
||||
|
||||
#include "isfqtconfig.h"
|
||||
|
||||
#include <IsfQt>
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
|
||||
/**
|
||||
* Uncomment this define to enable very verbose debugging output
|
||||
*/
|
||||
#ifdef ISFQT_DEBUG
|
||||
#define ISFQT_DEBUG_VERBOSE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A list of all known ISF tag indexes into the GUID
|
||||
* table
|
||||
*/
|
||||
enum DataTag
|
||||
{
|
||||
TAG_INK_SPACE_RECT = 0
|
||||
, TAG_GUID_TABLE
|
||||
, TAG_DRAW_ATTRS_TABLE
|
||||
, TAG_DRAW_ATTRS_BLOCK
|
||||
, TAG_STROKE_DESC_TABLE
|
||||
, TAG_STROKE_DESC_BLOCK
|
||||
, TAG_BUTTONS
|
||||
, TAG_NO_X
|
||||
, TAG_NO_Y
|
||||
, TAG_DIDX
|
||||
, TAG_STROKE // = 10
|
||||
, TAG_STROKE_PROPERTY_LIST
|
||||
, TAG_POINT_PROPERTY
|
||||
, TAG_SIDX
|
||||
, TAG_COMPRESSION_HEADER
|
||||
, TAG_TRANSFORM_TABLE
|
||||
, TAG_TRANSFORM
|
||||
, TAG_TRANSFORM_ISOTROPIC_SCALE
|
||||
, TAG_TRANSFORM_ANISOTROPIC_SCALE
|
||||
, TAG_TRANSFORM_ROTATE
|
||||
, TAG_TRANSFORM_TRANSLATE // = 20
|
||||
, TAG_TRANSFORM_SCALE_AND_TRANSLATE
|
||||
, TAG_TRANSFORM_QUAD
|
||||
, TAG_TIDX
|
||||
, TAG_METRIC_TABLE
|
||||
, TAG_METRIC_BLOCK
|
||||
, TAG_MIDX
|
||||
, TAG_MANTISSA
|
||||
, TAG_PERSISTENT_FORMAT
|
||||
, TAG_HIMETRIC_SIZE
|
||||
, TAG_STROKE_IDS // = 30
|
||||
, DEFAULT_TAGS_NUMBER = 100
|
||||
, FIRST_CUSTOM_TAG_ID = 100
|
||||
};
|
||||
Q_DECLARE_FLAGS( DataTags, DataTag )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( DataTags )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ISF parser state machine states
|
||||
*/
|
||||
enum ParserState
|
||||
{
|
||||
ISF_PARSER_START = 0, ///< The parser has not read anything from the data yet
|
||||
ISF_PARSER_FINISH, ///< The parser is done
|
||||
ISF_PARSER_STREAMSIZE, ///< The parser is reading the ISF stream size
|
||||
ISF_PARSER_TAG ///< The parser is reading tags from the stream
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Persistent Format version
|
||||
*
|
||||
* @see TagsParser::parsePersistentFormat() for more info.
|
||||
*/
|
||||
const uint ISF_PERSISTENT_FORMAT_VERSION = 65536;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,910 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include "data/datasource.h"
|
||||
#include "data/multibytecoding.h"
|
||||
#include "tagsparser.h"
|
||||
#include "tagswriter.h"
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
|
||||
#if ISFQT_GIF_ENABLED == 1
|
||||
#include "gif-support.h"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
using namespace Compress;
|
||||
|
||||
|
||||
/// Supported ISF version number
|
||||
#define SUPPORTED_ISF_VERSION 0
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a raw ISF data stream into a drawing.
|
||||
*
|
||||
* If the ISF data is invalid, a null Drawing is returned.
|
||||
*
|
||||
* @param rawData Source byte array with an ISF stream
|
||||
* @param decodeFromBase64 Whether the bytes are in the Base64 format and
|
||||
* need to be decoded first
|
||||
* @return an Isf::Drawing, with null contents on error
|
||||
*/
|
||||
Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
|
||||
{
|
||||
// Create a new drawing on the heap to ensure it will keep
|
||||
// living after this method returns
|
||||
Drawing *drawing = new Drawing;
|
||||
DataSource isfData( decodeFromBase64
|
||||
? QByteArray::fromBase64( rawData )
|
||||
: rawData );
|
||||
int size = isfData.size();
|
||||
|
||||
if( size == 0 )
|
||||
{
|
||||
return *drawing;
|
||||
}
|
||||
|
||||
ParserState state = ISF_PARSER_START;
|
||||
|
||||
while( state != ISF_PARSER_FINISH )
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
case ISF_PARSER_START:
|
||||
{
|
||||
// step 1: read ISF version.
|
||||
quint8 version = decodeUInt( isfData );
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Version:" << version;
|
||||
#endif
|
||||
if ( version != SUPPORTED_ISF_VERSION )
|
||||
{
|
||||
drawing->error_ = ISF_ERROR_BAD_VERSION;
|
||||
drawing->isNull_ = true;
|
||||
state = ISF_PARSER_FINISH;
|
||||
}
|
||||
else
|
||||
{
|
||||
// version is OK. find ISF stream size next.
|
||||
state = ISF_PARSER_STREAMSIZE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ISF_PARSER_STREAMSIZE:
|
||||
{
|
||||
// read ISF stream size.
|
||||
// check it matches the length of the data array.
|
||||
quint64 streamSize = decodeUInt( isfData );
|
||||
|
||||
if ( streamSize != (quint64)( isfData.size() - isfData.pos() ) )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Invalid stream size" << streamSize
|
||||
<< ", expected" << ( isfData.size() - isfData.pos() );
|
||||
#endif
|
||||
// streamsize is bad.
|
||||
drawing->error_ = ISF_ERROR_BAD_STREAMSIZE;
|
||||
state = ISF_PARSER_FINISH;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Reading ISF stream of size:" << streamSize << "...";
|
||||
#endif
|
||||
// Validate the drawing
|
||||
drawing->isNull_ = false;
|
||||
|
||||
// Fill up the default properties
|
||||
drawing->currentMetrics_ = &drawing->defaultMetrics_;
|
||||
drawing->currentAttributeSet_ = &drawing->defaultAttributeSet_;
|
||||
drawing->currentStrokeInfo_ = &drawing->defaultStrokeInfo_;
|
||||
drawing->currentTransform_ = &drawing->defaultTransform_;
|
||||
|
||||
// start looking for ISF tags.
|
||||
state = ISF_PARSER_TAG;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// ******************
|
||||
// This is the key point of the state machine. This will continually loop looking for ISF
|
||||
// tags and farming off to the appropriate method.
|
||||
// *******************
|
||||
case ISF_PARSER_TAG:
|
||||
{
|
||||
if( isfData.atEnd() )
|
||||
{
|
||||
state = ISF_PARSER_FINISH;
|
||||
break;
|
||||
}
|
||||
|
||||
QString place( "0x" + QString::number( isfData.pos(), 16 ).toUpper() );
|
||||
quint64 tagIndex = decodeUInt( isfData );
|
||||
|
||||
switch( tagIndex )
|
||||
{
|
||||
case TAG_INK_SPACE_RECT:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_INK_SPACE_RECT";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseInkSpaceRectangle( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_GUID_TABLE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_GUID_TABLE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseGuidTable( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_DRAW_ATTRS_TABLE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_TABLE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseAttributeTable( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_DRAW_ATTRS_BLOCK:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_BLOCK";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseAttributeBlock( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_STROKE_DESC_TABLE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_TABLE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseStrokeDescTable( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_STROKE_DESC_BLOCK:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_BLOCK";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseStrokeDescBlock( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_BUTTONS:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_BUTTONS";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_BUTTONS" );
|
||||
break;
|
||||
|
||||
case TAG_NO_X:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_NO_X";
|
||||
#endif
|
||||
drawing->error_ = ISF_ERROR_NONE;
|
||||
|
||||
drawing->hasXData_ = false;
|
||||
break;
|
||||
|
||||
case TAG_NO_Y:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_NO_Y";
|
||||
#endif
|
||||
drawing->hasYData_ = false;
|
||||
break;
|
||||
|
||||
case TAG_DIDX:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_DIDX";
|
||||
#endif
|
||||
|
||||
quint64 value = decodeUInt( isfData );
|
||||
|
||||
if( value < (uint)drawing->attributeSets_.count() )
|
||||
{
|
||||
drawing->currentAttributeSet_ = drawing->attributeSets_[ value ];
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Next strokes will use drawing attributes #" << value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Invalid drawing attribute ID!";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_STROKE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_STROKE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseStroke( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_STROKE_PROPERTY_LIST:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_STROKE_PROPERTY_LIST";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_STROKE_PROPERTY_LIST" );
|
||||
break;
|
||||
|
||||
case TAG_POINT_PROPERTY:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_POINT_PROPERTY";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_POINT_PROPERTY" );
|
||||
break;
|
||||
|
||||
case TAG_SIDX:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_SIDX";
|
||||
#endif
|
||||
|
||||
quint64 value = decodeUInt( isfData );
|
||||
|
||||
if( value < (uint)drawing->strokeInfo_.count() )
|
||||
{
|
||||
drawing->currentStrokeInfo_ = drawing->strokeInfo_[ value ];
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Next strokes will use stroke info #" << value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Invalid stroke ID!";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_COMPRESSION_HEADER:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_COMPRESSION_HEADER";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_COMPRESSION_HEADER" );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_TABLE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TABLE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformationTable( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_ISOTROPIC_SCALE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ISOTROPIC_SCALE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_ANISOTROPIC_SCALE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ANISOTROPIC_SCALE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_ROTATE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ROTATE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_TRANSLATE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TRANSLATE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_SCALE_AND_TRANSLATE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_SCALE_AND_TRANSLATE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TRANSFORM_QUAD:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_QUAD";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
|
||||
break;
|
||||
|
||||
case TAG_TIDX:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_TIDX";
|
||||
#endif
|
||||
|
||||
quint64 value = decodeUInt( isfData );
|
||||
|
||||
if( value < (uint)drawing->transforms_.count() )
|
||||
{
|
||||
drawing->currentTransform_ = drawing->transforms_[ value ];
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Next strokes will use transform #" << value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Invalid transform ID!";
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_METRIC_TABLE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_METRIC_TABLE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseMetricTable( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_METRIC_BLOCK:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_METRIC_BLOCK";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseMetricBlock( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_MIDX:
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_MIDX";
|
||||
#endif
|
||||
|
||||
quint64 value = decodeUInt( isfData );
|
||||
|
||||
if( value < (uint)drawing->metrics_.count() )
|
||||
{
|
||||
drawing->currentMetrics_ = drawing->metrics_[ value ];
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Next strokes will use metrics #" << value;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qWarning() << "Invalid metrics ID!";
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_MANTISSA:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_MANTISSA";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_MANTISSA" );
|
||||
break;
|
||||
|
||||
case TAG_PERSISTENT_FORMAT:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_PERSISTENT_FORMAT";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parsePersistentFormat( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_HIMETRIC_SIZE:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_HIMETRIC_SIZE";
|
||||
#endif
|
||||
drawing->error_ = TagsParser::parseHiMetricSize( isfData, *drawing );
|
||||
break;
|
||||
|
||||
case TAG_STROKE_IDS:
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_STROKE_IDS";
|
||||
#endif
|
||||
|
||||
drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_STROKE_IDS" );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// If the tagIndex is known from the GUID table, show it differently
|
||||
if( drawing->maxGuid_ > 0
|
||||
&& tagIndex >= DEFAULT_TAGS_NUMBER && tagIndex <= drawing->maxGuid_ )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Got tag (@" << place << "): TAG_CUSTOM:" << tagIndex;
|
||||
#endif
|
||||
TagsParser::parseCustomTag( isfData, *drawing, tagIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
TagsParser::parseUnsupported( isfData, "Unknown " + QString::number( tagIndex ) );
|
||||
}
|
||||
break;
|
||||
|
||||
} // End of tagIndex switch
|
||||
|
||||
if( drawing->error_ != ISF_ERROR_NONE )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qWarning() << "Error in last operation, stopping.";
|
||||
#endif
|
||||
state = ISF_PARSER_FINISH;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Should never arrive here! It's here only to avoid compiler warnings.
|
||||
case ISF_PARSER_FINISH:
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Finished with" << ( drawing->error_ == ISF_ERROR_NONE ? "success" : "error" );
|
||||
qDebug();
|
||||
#endif
|
||||
|
||||
if( drawing->error_ != ISF_ERROR_NONE )
|
||||
{
|
||||
return *drawing;
|
||||
}
|
||||
|
||||
// Perform the last operations on the drawing
|
||||
|
||||
// Adjust the bounding rectangle to include the strokes borders
|
||||
QSize penSize( drawing->maxPenSize_.toSize() );
|
||||
drawing->boundingRect_.adjust( -penSize.width() - 1, -penSize.height() - 1,
|
||||
+penSize.width() + 1, +penSize.height() + 1 );
|
||||
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Drawing bounding rectangle:" << drawing->boundingRect_;
|
||||
qDebug() << "Maximum thickness:" << drawing->maxPenSize_;
|
||||
#endif
|
||||
|
||||
return *drawing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a Fortified-GIF image into a drawing.
|
||||
*
|
||||
* If the GIF image or the ISF data within it are invalid, or if the GIF did not
|
||||
* have any ISF stream within, then a null Drawing is returned.
|
||||
*
|
||||
* Please note that this method does nothing if Isf-Qt is compiled
|
||||
* withous GIF support. Use Stream::supportsGif() to verify whether
|
||||
* GIF was compiled in or not.
|
||||
*
|
||||
* @see supportsGif()
|
||||
* @param gifRawBytes Source byte array with a Fortified GIF image
|
||||
* @param decodeFromBase64 True if the bytes are in the Base64 format and
|
||||
* need to be decoded first
|
||||
* @return an Isf::Drawing, with null contents on error
|
||||
*/
|
||||
Drawing &Stream::readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64 )
|
||||
{
|
||||
QByteArray isfData;
|
||||
|
||||
#if ISFQT_GIF_ENABLED == 1
|
||||
|
||||
QByteArray gifBytes( decodeFromBase64
|
||||
? QByteArray::fromBase64( gifRawBytes )
|
||||
: gifRawBytes );
|
||||
|
||||
/**
|
||||
* With the commented code below, it would all have been so easy, but no!
|
||||
* DGifGetComment is NOT PRESENT IN THE LIBRARY despite being in the giflib
|
||||
* header file. And EGifPutComment is present!
|
||||
* It doesn't work, but hey, at least it's there. (see below)
|
||||
*/
|
||||
/*
|
||||
QBuffer gifData( &gifBytes );
|
||||
gifData.open( QIODevice::ReadOnly );
|
||||
|
||||
// Open the gif file
|
||||
GifFileType *gifImage = DGifOpen( (void*)&gifData, GifReadFromByteArray );
|
||||
if( gifImage != 0 )
|
||||
{
|
||||
DGifGetComment( gifImage, data?? );
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Couldn't initialize GIF library!";
|
||||
}
|
||||
|
||||
DGifCloseFile( gifImage );
|
||||
gifData.close();
|
||||
*/
|
||||
|
||||
// Find the last 'comment' type tag: it should be the last thing in the file...
|
||||
qint32 size = 0;
|
||||
qint32 position = 0;
|
||||
qint32 maxDataPosition = gifBytes.size() - 2; // comment and gif stream ending bytes
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Searching for a stream. Last valid position:" << maxDataPosition;
|
||||
#endif
|
||||
|
||||
while( size == 0 && ( position = gifBytes.lastIndexOf( COMMENT_EXT_FUNC_CODE, position - 1 ) ) >= 0 )
|
||||
{
|
||||
// Skip the comment tag, to have the size byte as current char
|
||||
qint32 lastPosition = position + 1;
|
||||
|
||||
// The next character after the tag can't be an ISF stream start, skip
|
||||
if( gifBytes[ position + 2 ] != '\0' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to read the stream
|
||||
quint8 sizeByte;
|
||||
do
|
||||
{
|
||||
sizeByte = gifBytes[ lastPosition ];
|
||||
|
||||
// Skip the size byte
|
||||
lastPosition++;
|
||||
|
||||
isfData.append( gifBytes.mid( lastPosition, sizeByte ) );
|
||||
lastPosition += sizeByte;
|
||||
}
|
||||
while( sizeByte == MAX_GIF_BYTE && ( lastPosition <= maxDataPosition ) );
|
||||
|
||||
// We found the ISF stream!
|
||||
if( lastPosition == maxDataPosition )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Found an ISF stream of size" << isfData.size();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Stream not found at position:" << position
|
||||
<< "size:" << ( lastPosition - position );
|
||||
#endif
|
||||
isfData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ISFQT_GIF_ENABLED == 1
|
||||
|
||||
return reader( isfData );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return whether the library was built with Fortified GIF support or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool Stream::supportsGif()
|
||||
{
|
||||
return ( ISFQT_GIF_ENABLED == true );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a drawing into a raw ISF data stream.
|
||||
*
|
||||
* The resulting byte array will be empty if the drawing is not valid.
|
||||
*
|
||||
* @param drawing Source drawing
|
||||
* @param encodeToBase64 Whether the converted ISF stream should be
|
||||
* encoded with Base64 or not
|
||||
* @return Byte array with an ISF data stream
|
||||
*/
|
||||
QByteArray Stream::writer( const Drawing &drawing, bool encodeToBase64 )
|
||||
{
|
||||
if( &drawing == 0 || drawing.isNull() || drawing.error() != ISF_ERROR_NONE )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "The drawing was not valid!";
|
||||
#endif
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
DataSource isfData;
|
||||
|
||||
// Write the persistent format tag
|
||||
TagsWriter::addPersistentFormat( isfData, drawing );
|
||||
|
||||
// Write the drawing size
|
||||
TagsWriter::addHiMetricSize( isfData, drawing );
|
||||
|
||||
// Write the attributes
|
||||
TagsWriter::addAttributeTable( isfData, drawing );
|
||||
|
||||
// Write the metrics
|
||||
TagsWriter::addMetricsTable( isfData, drawing );
|
||||
|
||||
// Write the transforms
|
||||
TagsWriter::addTransformationTable( isfData, drawing );
|
||||
|
||||
// Write the strokes
|
||||
TagsWriter::addStrokes( isfData, drawing );
|
||||
|
||||
// Write the stream size (at the start of the stream)
|
||||
encodeUInt( isfData, isfData.size(), true/*prepend*/ );
|
||||
|
||||
// Write the version number (at the start of the stream)
|
||||
encodeUInt( isfData, SUPPORTED_ISF_VERSION, true/*prepend*/ );
|
||||
|
||||
|
||||
// Convert to Base64 if needed
|
||||
if( encodeToBase64 )
|
||||
{
|
||||
return isfData.data().toBase64();
|
||||
}
|
||||
else
|
||||
{
|
||||
return isfData.data();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a drawing into a Fortified-GIF image.
|
||||
*
|
||||
* The resulting byte array will be empty if the drawing is not valid.
|
||||
*
|
||||
* Please note that this method does nothing if Isf-Qt is compiled
|
||||
* withous GIF support. Use Stream::supportsGif() to verify whether
|
||||
* GIF was compiled in or not.
|
||||
*
|
||||
* @see supportsGif()
|
||||
* @param drawing Source drawing
|
||||
* @param encodeToBase64 Whether the converted ISF stream should be
|
||||
* encoded with Base64 or not
|
||||
* @return Byte array with an ISF data stream
|
||||
*/
|
||||
QByteArray Stream::writerGif( const Drawing &drawing, bool encodeToBase64 )
|
||||
{
|
||||
QByteArray imageBytes;
|
||||
|
||||
#if ISFQT_GIF_ENABLED == 1
|
||||
Drawing source( drawing );
|
||||
|
||||
// Get the ISF data stream
|
||||
QByteArray isfData( writer( source ) );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "GIF-Fortifying an ISF stream of size" << isfData.size();
|
||||
#endif
|
||||
|
||||
// Get the ISF pixmap and copy the pixels to an 8bpp image
|
||||
QImage isfImage( source.pixmap().toImage()
|
||||
.convertToFormat( QImage::Format_Indexed8,
|
||||
Qt::ThresholdDither ) );
|
||||
|
||||
// Initialise the gif variables
|
||||
QBuffer gifData;
|
||||
GifFileType *gifImage = NULL;
|
||||
ColorMapObject *cmap = NULL;
|
||||
int height = isfImage.height();
|
||||
int width = isfImage.width();
|
||||
int numColors = 0;
|
||||
bool gifError = true;
|
||||
|
||||
// Convert the image to GIF using libgif
|
||||
|
||||
// Open the gif file
|
||||
gifData.open( QIODevice::WriteOnly );
|
||||
gifImage = EGifOpen( (void*)&gifData, GifWriteToByteArray );
|
||||
if( gifImage == 0 )
|
||||
{
|
||||
qWarning() << "Couldn't initialize gif library!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
// Create the color map
|
||||
numColors = ( isfImage.numColors() << 2 );
|
||||
if( numColors > 256 )
|
||||
{
|
||||
numColors = 256;
|
||||
}
|
||||
|
||||
cmap = MakeMapObject( numColors, NULL );
|
||||
if( cmap == 0 && isfImage.numColors() > 1 )
|
||||
{
|
||||
qWarning() << "Couldn't create map object for gif conversion (colors:" << isfImage.numColors() << ")!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
// Fill in the color map with the colors in the image color table
|
||||
for( int i = 0; i < isfImage.numColors(); ++i )
|
||||
{
|
||||
const QRgb &color( isfImage.color( i ) );
|
||||
cmap->Colors[i].Red = qRed ( color );
|
||||
cmap->Colors[i].Green = qGreen( color );
|
||||
cmap->Colors[i].Blue = qBlue ( color );
|
||||
}
|
||||
|
||||
// Save the file properties
|
||||
if( EGifPutScreenDesc( gifImage, width, height, 8, 0, cmap ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutScreenDesc() failed!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
// Save the image format
|
||||
if( EGifPutImageDesc( gifImage, 0, 0, width, height, 0, NULL ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutImageDesc() failed!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME: If to write the scanlines you use
|
||||
* EGifPutLine( gifImage, isfImage.bits(), isfImage.width() * isfImage.height() )
|
||||
* i.e. convert the complete image in one call, then the resulting image is mangled.
|
||||
* Something is wrong with the width or so, it seems to be off by about two pixels.
|
||||
*/
|
||||
// Write every scanline
|
||||
for( int line = 0; line < height; ++line )
|
||||
{
|
||||
if( EGifPutLine( gifImage, isfImage.scanLine( line ), width ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutLine failed at scanline" << line
|
||||
<< "(height:" << isfImage.height()
|
||||
<< ", width:" << isfImage.width()
|
||||
<< ", bytesperline:" << isfImage.bytesPerLine() << ")";
|
||||
goto writeError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Completing the funny theater that is giflib, EGifPutComment() doesn't
|
||||
* work, or I've overlooked something Extremely Obvious(tm).
|
||||
* Googling didn't help: I rewrote it (from the giflib source) with
|
||||
* Qt.
|
||||
*/
|
||||
/*
|
||||
if( EGifPutComment( gifImage, isfData.constData() ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutComment has failed!";
|
||||
goto writeError;
|
||||
}
|
||||
*/
|
||||
|
||||
// Write the ISF stream into the Comment Extension field
|
||||
if( isfData.size() < MAX_GIF_BYTE )
|
||||
{
|
||||
EGifPutExtension( gifImage, COMMENT_EXT_FUNC_CODE, isfData.size(), isfData.constData() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write the extension
|
||||
if( EGifPutExtensionFirst( gifImage, COMMENT_EXT_FUNC_CODE, MAX_GIF_BYTE, isfData.left( MAX_GIF_BYTE ).data() ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutExtensionFirst failed!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
// The first MAX_GIF_BYTE bytes have been written already
|
||||
quint32 pos = MAX_GIF_BYTE;
|
||||
|
||||
quint32 length = ( isfData.size() - pos );
|
||||
|
||||
// Write all the full data blocks
|
||||
while( length >= MAX_GIF_BYTE )
|
||||
{
|
||||
if( EGifPutExtensionNext( gifImage, 0, MAX_GIF_BYTE, isfData.mid( pos, MAX_GIF_BYTE ).data() ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutExtensionNext failed!";
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
pos += MAX_GIF_BYTE;
|
||||
length -= MAX_GIF_BYTE;
|
||||
}
|
||||
|
||||
// Write the last block
|
||||
if( length > 0 )
|
||||
{
|
||||
if( EGifPutExtensionLast( gifImage, 0, length, isfData.mid( pos, MAX_GIF_BYTE ).data() ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutExtensionLast (n) failed!";
|
||||
goto writeError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( EGifPutExtensionLast( gifImage, 0, 0, 0 ) == GIF_ERROR )
|
||||
{
|
||||
qWarning() << "EGifPutExtensionLast (0) failed!";
|
||||
goto writeError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gifError = false;
|
||||
|
||||
writeError:
|
||||
// Clean up the GIF converter etc
|
||||
EGifCloseFile( gifImage );
|
||||
FreeMapObject( cmap );
|
||||
gifData.close();
|
||||
|
||||
if( gifError )
|
||||
{
|
||||
qWarning() << "GIF error code:" << GifLastError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return the GIF data
|
||||
imageBytes = gifData.data();
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Converted a" << isfData.size() << "bytes Ink to GIF:" << isfImage.height() << "x" << isfImage.width() << "->" << imageBytes.size() << "bytes";
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ISFQT_GIF_ENABLED == 1
|
||||
|
||||
|
||||
// Convert to Base64 if needed
|
||||
if( encodeToBase64 )
|
||||
{
|
||||
return imageBytes.toBase64();
|
||||
}
|
||||
else
|
||||
{
|
||||
return imageBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,969 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include "data/datasource.h"
|
||||
#include "data/multibytecoding.h"
|
||||
#include "tagsparser.h"
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
using namespace Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new empty (null) Drawing instance.
|
||||
*
|
||||
* As soon as you add data, the instance becomes non-NULL.
|
||||
*/
|
||||
Drawing::Drawing()
|
||||
: currentMetrics_( 0 )
|
||||
, currentAttributeSet_( 0 )
|
||||
, currentStrokeInfo_( 0 )
|
||||
, currentTransform_( 0 )
|
||||
, error_( ISF_ERROR_NONE )
|
||||
, hasXData_( true )
|
||||
, hasYData_( true )
|
||||
, isNull_( true )
|
||||
, maxGuid_( 0 )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "** Created new ISF drawing:" << this << "**";
|
||||
#endif
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Construct a copy of an existing Drawing instance.
|
||||
*
|
||||
* @param other The instance to duplicate.
|
||||
*/
|
||||
Drawing::Drawing( const Drawing &other )
|
||||
: boundingRect_( other.boundingRect_ )
|
||||
, canvas_( other.canvas_ )
|
||||
, currentMetrics_( 0 )
|
||||
, currentAttributeSet_( 0 )
|
||||
, currentStrokeInfo_( 0 )
|
||||
, currentTransform_( 0 )
|
||||
, defaultMetrics_( other.defaultMetrics_ )
|
||||
, defaultAttributeSet_( other.defaultAttributeSet_ )
|
||||
, defaultStrokeInfo_( other.defaultStrokeInfo_ )
|
||||
, defaultTransform_( other.defaultTransform_ )
|
||||
, error_( other.error_ )
|
||||
, guids_( other.guids_ )
|
||||
, hasXData_( other.hasXData_ )
|
||||
, hasYData_( other.hasYData_ )
|
||||
, isNull_( other.isNull_ )
|
||||
, maxGuid_( other.maxGuid_ )
|
||||
, maxPenSize_( other.maxPenSize_ )
|
||||
, size_( other.size_ )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "** Copying ISF drawing:" << (void*)&other << "into new:" << this << "**";
|
||||
#endif
|
||||
|
||||
// First: create copies of all the local lists
|
||||
|
||||
foreach( Metrics *metrics, other.metrics_ )
|
||||
{
|
||||
Metrics *newMetrics = new Metrics( *metrics );
|
||||
metrics_.append( newMetrics );
|
||||
|
||||
if( metrics == other.currentMetrics_ )
|
||||
{
|
||||
currentMetrics_ = newMetrics;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( StrokeInfo *strokeInfo, other.strokeInfo_ )
|
||||
{
|
||||
StrokeInfo *newStrokeInfo = new StrokeInfo( *strokeInfo );
|
||||
strokeInfo_.append( newStrokeInfo );
|
||||
|
||||
if( strokeInfo == other.currentStrokeInfo_ )
|
||||
{
|
||||
currentStrokeInfo_ = newStrokeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( QMatrix *transform, other.transforms_ )
|
||||
{
|
||||
QMatrix *newTransform = new QMatrix( *transform );
|
||||
transforms_.append( newTransform );
|
||||
|
||||
if( transform == other.currentTransform_ )
|
||||
{
|
||||
currentTransform_ = newTransform;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( AttributeSet *attributeSet, other.attributeSets_ )
|
||||
{
|
||||
AttributeSet *newAttributeSet = new AttributeSet( *attributeSet );
|
||||
attributeSets_.append( newAttributeSet );
|
||||
|
||||
if( attributeSet == other.currentAttributeSet_ )
|
||||
{
|
||||
currentAttributeSet_ = newAttributeSet;
|
||||
}
|
||||
}
|
||||
|
||||
// Then: clone the strokes. Each stroke is linked to a certain
|
||||
// attribute set, metrics set, etc, so we need to associate the
|
||||
// original stroke's properties to the current one's
|
||||
foreach( Stroke *stroke, other.strokes_ )
|
||||
{
|
||||
Stroke *newStroke = new Stroke( *stroke );
|
||||
strokes_.append( newStroke );
|
||||
|
||||
// Get the indices of the various stroke properties; and
|
||||
// for the new stroke, use the same indices
|
||||
|
||||
// It is probably safe to simply use the same index, since the
|
||||
// lists are copied in order.
|
||||
if( stroke->attributes && other.attributeSets_.count() > 0 )
|
||||
{
|
||||
int otherAttributeSet = other.attributeSets_.indexOf( stroke->attributes );
|
||||
newStroke->attributes = ( otherAttributeSet >= 0 )
|
||||
? attributeSets_.at( otherAttributeSet )
|
||||
: 0;
|
||||
}
|
||||
if( stroke->info && other.strokeInfo_.count() > 0 )
|
||||
{
|
||||
int otherStrokeInfo = other.strokeInfo_.indexOf( stroke->info );
|
||||
newStroke->info = ( otherStrokeInfo >= 0 )
|
||||
? strokeInfo_.at( otherStrokeInfo )
|
||||
: 0;
|
||||
}
|
||||
if( stroke->metrics && other.metrics_.count() > 0 )
|
||||
{
|
||||
int otherMetrics = other.metrics_.indexOf( stroke->metrics );
|
||||
newStroke->metrics = ( otherMetrics >= 0 )
|
||||
? metrics_.at( otherMetrics )
|
||||
: 0;
|
||||
}
|
||||
if( stroke->transform && other.transforms_.count() > 0 )
|
||||
{
|
||||
int otherTransforms = other.transforms_.indexOf( stroke->transform );
|
||||
newStroke->transform = ( otherTransforms >= 0 )
|
||||
? transforms_.at( otherTransforms )
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
Drawing::~Drawing()
|
||||
{
|
||||
qDeleteAll( metrics_ );
|
||||
qDeleteAll( strokeInfo_ );
|
||||
qDeleteAll( strokes_ );
|
||||
qDeleteAll( transforms_ );
|
||||
qDeleteAll( attributeSets_ );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "** Destroyed ISF drawing:" << this << "**";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add new a attribute set to the drawing.
|
||||
*
|
||||
* @param newAttributeSet The attribute set to add
|
||||
* @return Index of the new attribute set or -1 on failure
|
||||
*/
|
||||
qint32 Drawing::addAttributeSet( AttributeSet *newAttributeSet )
|
||||
{
|
||||
if( newAttributeSet == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
isNull_ = false;
|
||||
|
||||
attributeSets_.append( newAttributeSet );
|
||||
|
||||
// This value is used to adjust the drawing borders to include thick strokes
|
||||
if( newAttributeSet->penSize.width() > maxPenSize_.width() )
|
||||
{
|
||||
maxPenSize_.setWidth( newAttributeSet->penSize.width() );
|
||||
}
|
||||
if( newAttributeSet->penSize.height() > maxPenSize_.height() )
|
||||
{
|
||||
maxPenSize_.setHeight( newAttributeSet->penSize.height() );
|
||||
}
|
||||
|
||||
return ( attributeSets_.count() - 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a new stroke to the drawing.
|
||||
*
|
||||
* @param newStroke The stroke to add
|
||||
* @return Index of the new stroke or -1 on failure
|
||||
*/
|
||||
qint32 Drawing::addStroke( Stroke *newStroke )
|
||||
{
|
||||
if( newStroke == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
quint64 numPoints = newStroke->points.count();
|
||||
|
||||
// The polygon is used to determine the stroke's bounding rect
|
||||
QPolygon polygon( numPoints );
|
||||
for( quint64 index = 0; index < numPoints; ++index )
|
||||
{
|
||||
polygon.setPoint( index, newStroke->points.at( index ).position );
|
||||
}
|
||||
|
||||
// assign the attributes to the stroke.
|
||||
newStroke->attributes = currentAttributeSet_;
|
||||
|
||||
// add FitToCurve (Windows will use Bezier smoothing to make the ink look nice)
|
||||
newStroke->attributes->flags |= FitToCurve;
|
||||
|
||||
// set the bounding rectangle.
|
||||
if ( polygon.boundingRect().size() == QSize(1, 1) )
|
||||
{
|
||||
// can't have a 1px by 1px bounding rect - the eraser will never hit it.
|
||||
// make the bounding rectange completely cover the drawn stroke.
|
||||
float penSize = newStroke->attributes->penSize.width();
|
||||
QPoint point = newStroke->points.at( 0 ).position;
|
||||
newStroke->boundingRect = QRect( point.x() - penSize / 2, point.y() - penSize / 2, penSize, penSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
newStroke->boundingRect = polygon.boundingRect();
|
||||
}
|
||||
|
||||
isNull_ = false;
|
||||
strokes_.append( newStroke );
|
||||
|
||||
// force a bounding rectangle update
|
||||
boundingRect_ = QRect();
|
||||
|
||||
return ( strokes_.count() - 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a new transformation to the drawing.
|
||||
*
|
||||
* @param newTransform The transform to add
|
||||
* @return Index of the new transform or -1 on failure
|
||||
*/
|
||||
qint32 Drawing::addTransform( QMatrix *newTransform )
|
||||
{
|
||||
if( newTransform == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
isNull_ = false;
|
||||
transforms_.append( newTransform );
|
||||
|
||||
return ( transforms_.count() - 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clean up the drawing.
|
||||
*
|
||||
* This restores the drawing to its initial state: an empty (null) drawing.
|
||||
*/
|
||||
void Drawing::clear()
|
||||
{
|
||||
// Clean up the internal property lists
|
||||
qDeleteAll( metrics_ );
|
||||
qDeleteAll( strokeInfo_ );
|
||||
qDeleteAll( strokes_ );
|
||||
qDeleteAll( transforms_ );
|
||||
qDeleteAll( attributeSets_ );
|
||||
metrics_ .clear();
|
||||
strokeInfo_ .clear();
|
||||
strokes_ .clear();
|
||||
transforms_ .clear();
|
||||
attributeSets_.clear();
|
||||
|
||||
// Invalidate the current item pointers
|
||||
currentMetrics_ = 0;
|
||||
currentAttributeSet_ = 0;
|
||||
currentStrokeInfo_ = 0;
|
||||
currentTransform_ = 0;
|
||||
|
||||
// Nullify the other properties
|
||||
boundingRect_ = QRect();
|
||||
canvas_ = QRect();
|
||||
error_ = ISF_ERROR_NONE;
|
||||
hasXData_ = true;
|
||||
hasYData_ = true;
|
||||
isNull_ = true;
|
||||
maxGuid_ = 0;
|
||||
maxPenSize_ = QSizeF();
|
||||
size_ = QSize();
|
||||
|
||||
// set the default transform
|
||||
defaultTransform_.scale( 1.f, 1.f );
|
||||
defaultTransform_.translate( .0f, .0f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove an attribute set from the drawing.
|
||||
*
|
||||
* @param index Index of the attribute set to delete
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::deleteAttributeSet( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= attributeSets_.count() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
delete attributeSets_.takeAt( index );
|
||||
|
||||
// re-calculate max pen size
|
||||
foreach( AttributeSet *set, attributeSets_ )
|
||||
{
|
||||
// This value is used to adjust the drawing borders to include thick strokes
|
||||
if( set->penSize.width() > maxPenSize_.width() )
|
||||
{
|
||||
maxPenSize_.setWidth( set->penSize.width() );
|
||||
}
|
||||
if( set->penSize.height() > maxPenSize_.height() )
|
||||
{
|
||||
maxPenSize_.setHeight( set->penSize.height() );
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Max Pen Size:"<<maxPenSize_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove a stroke from the drawing.
|
||||
*
|
||||
* Delete a stroke object from the drawing.
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::deleteStroke( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= strokes_.count() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
delete strokes_.takeAt( index );
|
||||
boundingRect_ = QRect(); // force a recalculation.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delete a stroke object from the drawing.
|
||||
*
|
||||
* @param stroke The stroke to remove.
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::deleteStroke( Stroke *stroke )
|
||||
{
|
||||
if ( ! strokes_.contains( stroke ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return deleteStroke( strokes_.indexOf( stroke ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove a transformation from the drawing.
|
||||
*
|
||||
* @param index Index of the transform to delete
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::deleteTransform( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= transforms_.count() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
delete transforms_.takeAt( index );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the last error that has occurred.
|
||||
*
|
||||
* If nothing went wrong, this returns ISF_ERROR_NONE.
|
||||
*
|
||||
* @return The last ISF error status
|
||||
*/
|
||||
IsfError Drawing::error() const
|
||||
{
|
||||
return error_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an attribute set to manipulate.
|
||||
*
|
||||
* @param index Index of the attribute set to get
|
||||
* @return AttributeSet or 0 if not found
|
||||
*/
|
||||
AttributeSet *Drawing::attributeSet( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= attributeSets_.count() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return attributeSets_.at( index );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the attribute sets.
|
||||
*
|
||||
* @return The list of existing attribute sets
|
||||
*/
|
||||
const QList<AttributeSet*> Drawing::attributeSets()
|
||||
{
|
||||
return attributeSets_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the current bounding rectangle of the drawing.
|
||||
*
|
||||
* The bounding rectangle (or bounding box) is a QRect large enough (and as
|
||||
* small as) to hold all of the strokes in this Drawing instance.
|
||||
*
|
||||
* @return The current bounding box.
|
||||
*/
|
||||
QRect Drawing::boundingRect()
|
||||
{
|
||||
// if the boundingRect_ is invalid, update it.
|
||||
// it becomes invalid after a stroke is added or deleted.
|
||||
if ( boundingRect_ == QRect() )
|
||||
{
|
||||
foreach( Stroke *stroke, strokes_ )
|
||||
{
|
||||
if ( stroke->transform != 0 )
|
||||
{
|
||||
boundingRect_ = boundingRect_.united( stroke->transform->mapRect( stroke->boundingRect ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingRect_ = boundingRect_.united( stroke->boundingRect );
|
||||
}
|
||||
}
|
||||
|
||||
QSize penSize( maxPenSize_.toSize() );
|
||||
boundingRect_.adjust( -penSize.width() - 1, -penSize.height() - 1,
|
||||
+penSize.width() + 1, +penSize.height() + 1 );
|
||||
|
||||
size_ = boundingRect_.size();
|
||||
}
|
||||
|
||||
return boundingRect_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the size of this drawing.
|
||||
*
|
||||
* @return Size of the drawing, in pixels.
|
||||
*/
|
||||
QSize Drawing::size()
|
||||
{
|
||||
return boundingRect().size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Render the drawing into an image.
|
||||
*
|
||||
* If the drawing is empty, the pixmap will be null.
|
||||
* Also note that the maximum renderable size is 2000x2000 pixels: if the strokes
|
||||
* exceed by even one dimension, the pixmap will not be rendered.
|
||||
* This is a security measure, since the pixmaps are allocated by the graphics
|
||||
* system (X on *nix, for example) and a machine could be DoSed with a very large
|
||||
* drawing.
|
||||
*
|
||||
* @param backgroundColor The color used as background in the returned image.
|
||||
* @return The rendered drawing, or a null one on error.
|
||||
*/
|
||||
QPixmap Drawing::pixmap( const QColor backgroundColor )
|
||||
{
|
||||
if ( isNull() )
|
||||
{
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
QSize size_ = size();
|
||||
|
||||
if( size_.width() > 2000 || size_.height() > 2000 )
|
||||
{
|
||||
qWarning() << "Cannot render a drawing so big!";
|
||||
qDebug() << "[Information - Size:" << size_ << "pixels]";
|
||||
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
QPixmap pixmap( size_ );
|
||||
pixmap.fill( backgroundColor );
|
||||
QPainter painter( &pixmap );
|
||||
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Rendering a drawing of size" << size_;
|
||||
#endif
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "The drawing contains" << strokes_.count() << "strokes.";
|
||||
#endif
|
||||
|
||||
// if there are no strokes there's no point going
|
||||
// through the rest of this logic.
|
||||
if ( strokes_.count() == 0 )
|
||||
{
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
painter.setWindow( boundingRect() );
|
||||
painter.setWorldMatrixEnabled( true );
|
||||
painter.setRenderHints( QPainter::Antialiasing
|
||||
| QPainter::SmoothPixmapTransform
|
||||
| QPainter::TextAntialiasing,
|
||||
true );
|
||||
|
||||
QPen pen;
|
||||
pen.setStyle ( Qt::SolidLine );
|
||||
pen.setCapStyle ( Qt::RoundCap );
|
||||
pen.setJoinStyle( Qt::RoundJoin );
|
||||
|
||||
// Keep record of the currently used properties, to avoid re-setting them for each stroke
|
||||
currentMetrics_ = 0;
|
||||
currentAttributeSet_ = 0;
|
||||
currentStrokeInfo_ = 0;
|
||||
currentTransform_ = 0;
|
||||
|
||||
int index = 0;
|
||||
foreach( const Stroke *stroke, strokes_ )
|
||||
{
|
||||
if( currentMetrics_ != stroke->metrics )
|
||||
{
|
||||
currentMetrics_ = stroke->metrics;
|
||||
// TODO need to convert all units somehow?
|
||||
// painter.setSomething( currentMetrics );
|
||||
}
|
||||
if( currentAttributeSet_ != stroke->attributes && stroke->attributes != 0)
|
||||
{
|
||||
currentAttributeSet_ = stroke->attributes;
|
||||
|
||||
pen.setColor( currentAttributeSet_->color );
|
||||
pen.setWidthF( currentAttributeSet_->penSize.width() );
|
||||
painter.setPen( pen );
|
||||
}
|
||||
if( currentStrokeInfo_ != stroke->info )
|
||||
{
|
||||
currentStrokeInfo_ = stroke->info;
|
||||
}
|
||||
if( currentTransform_ != stroke->transform && stroke->transform != 0 )
|
||||
{
|
||||
currentTransform_ = stroke->transform;
|
||||
painter.setWorldTransform( QTransform( *currentTransform_ ), false );
|
||||
|
||||
// the problem with setting the world transform is that it will scale the pen size too.
|
||||
// we don't want that. so we have to artificially beef up the pen size.
|
||||
QPen pen = painter.pen();
|
||||
pen.setWidthF( currentAttributeSet_->penSize.width() / currentTransform_->m22() );
|
||||
painter.setPen( pen );
|
||||
}
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "Rendering stroke" << index << "containing" << stroke->points.count() << "points";
|
||||
qDebug() << "- Stroke color:" << currentAttributeSet_->color.name() << "Pen size:" << pen.widthF();
|
||||
#endif
|
||||
|
||||
if( stroke->points.count() > 1 )
|
||||
{
|
||||
Point lastPoint;
|
||||
foreach( const Point &point, stroke->points )
|
||||
{
|
||||
// qDebug() << "Point:" << point.position;
|
||||
|
||||
if( lastPoint.position.isNull() )
|
||||
{
|
||||
lastPoint = point;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( currentStrokeInfo_->hasPressureData )
|
||||
{
|
||||
// FIXME Ignoring pressure data - need to find out how pressure must be applied
|
||||
// pen.setWidth( pen.widthF() + point.pressureLevel );
|
||||
// painter.setPen( pen );
|
||||
}
|
||||
|
||||
// How nice of QPainter! Lines drawn from and to the same point
|
||||
// won't be drawn at all
|
||||
if( point.position == lastPoint.position )
|
||||
{
|
||||
painter.drawPoint( point.position );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine( lastPoint.position, point.position );
|
||||
}
|
||||
|
||||
lastPoint = point;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Point point = stroke->points.first();
|
||||
if( currentStrokeInfo_->hasPressureData )
|
||||
{
|
||||
// FIXME Ignoring pressure data - need to find out how pressure must be applied
|
||||
// pen.setWidth( pen.widthF() + point.pressureLevel );
|
||||
// painter.setPen( pen );
|
||||
}
|
||||
|
||||
// qDebug() << "Point:" << point.position;
|
||||
painter.drawPoint( point.position );
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
// Draw the stroke number next to each one, for debugging purposes
|
||||
pen.setColor( QColor( Qt::red ) );
|
||||
painter.setPen( pen );
|
||||
painter.drawText( stroke.points.first().position, QString::number( index ) );
|
||||
pen.setColor( currentAttributeSet_->color );
|
||||
painter.setPen( pen );
|
||||
#endif
|
||||
*/
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
painter.end();
|
||||
|
||||
#ifdef ISFQT_DEBUG
|
||||
qDebug() << "Rendering complete.";
|
||||
#endif
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a stroke to manipulate.
|
||||
*
|
||||
* @param index Index of the stroke to get
|
||||
* @return Stroke or 0 if not found
|
||||
*/
|
||||
Stroke *Drawing::stroke( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= strokes_.count() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strokes_.at( index );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the Stroke under a certain point.
|
||||
*
|
||||
* Given a QPoint, return the Stroke object that passes through there.
|
||||
* If no stroke passes through that point, returns NULL.
|
||||
*
|
||||
* If multiple Strokes pass through that point the most recently drawn stroke
|
||||
* will be returned.
|
||||
*
|
||||
* @param point Point to check
|
||||
* @return A Stroke instance or NULL if no Stroke passes through that point.
|
||||
*/
|
||||
Stroke *Drawing::strokeAtPoint( const QPoint &point )
|
||||
{
|
||||
/*
|
||||
Here's how this algorithm works:
|
||||
|
||||
1) Iterate through strokes in reverse order.
|
||||
2) For each stroke, check if the bounding rectangle contains the point where the cursor is.
|
||||
If not, continue to the next stroke. Prevents us checking all the strokes.
|
||||
3) Next, iterate through each pair of points in the stroke. If both of the points fall outside
|
||||
of the searching rectangle around the cursor, skip. Saves us checking hundreds of points when
|
||||
only a few will do.
|
||||
4) a) For each pair of strokes, form a triangle whose points are defined by the two points for the
|
||||
line segment, plus the cursor position.
|
||||
b) Calculate the height of this triangle. To do so, use Heron's Formula plus the formula for the
|
||||
area of any triangle.
|
||||
c) If the cursor is touching the drawn stroke, the height should be less than or equal to the
|
||||
half-width of the pen that drew the stroke.
|
||||
|
||||
For reference (triangle sides a, b, c, height h)
|
||||
Heron's Formula: area = sqrt(s * (s - a) * (s - b) * (s - c) ), where s = semiperimeter = 0.5*(a+b+c)
|
||||
area = 0.5*base*height;
|
||||
thus height = ( 2 * area ) / base.
|
||||
*/
|
||||
|
||||
QListIterator<Stroke *> i( strokes_ );
|
||||
i.toBack();
|
||||
|
||||
while( i.hasPrevious() )
|
||||
{
|
||||
Stroke *s = i.previous();;
|
||||
|
||||
// skip strokes where we're not near.
|
||||
if ( ! s->boundingRect.contains( point ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// what's the pen size of this stroke? That way we have a "fudge factor"
|
||||
AttributeSet *set = s->attributes;
|
||||
float penSize = set->penSize.width();
|
||||
float penHalfSize = penSize / 2;
|
||||
|
||||
// only want points that fall near the cursor. prevents searching unnecessary points.
|
||||
QRect searchRect;
|
||||
|
||||
// search rect must accommodate pen size.
|
||||
// the large the pen size, the bigger our search area has to be.
|
||||
//
|
||||
// minimum search area of 10x10 pixels.
|
||||
if ( penHalfSize > 5 )
|
||||
{
|
||||
// 25% extra room to move.
|
||||
searchRect = QRect( point.x() - penHalfSize * 1.25, point.y() - penHalfSize * 1.25, penHalfSize * 1.25, penHalfSize * 1.25 );
|
||||
}
|
||||
else
|
||||
{
|
||||
searchRect = QRect( point.x() - 5, point.y() - 5, 10, 10 );
|
||||
}
|
||||
|
||||
// special case: a single point (sometimes it'll appear as a single point but
|
||||
// be made up of two).
|
||||
if ( s->points.size() == 1 || s->points.size() == 2 )
|
||||
{
|
||||
QLineF dist = QLineF( QPointF( s->points.at(0).position ), QPointF( point ) );
|
||||
if ( dist.length() <= penHalfSize * 1.25 )
|
||||
{
|
||||
return s;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// multiple points.
|
||||
for( int j = 0; j < s->points.size() - 1; j++)
|
||||
{
|
||||
QPoint p1 = s->points.at(j).position;
|
||||
QPoint p2 = s->points.at(j+1).position;
|
||||
|
||||
if ( ! searchRect.contains( p1 ) && ! searchRect.contains( p2 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QPointF cursorPos = QPointF( point );
|
||||
QLineF base = QLineF( QPointF( p1 ), QPointF( p2 ) );
|
||||
QLineF lineA = QLineF( QPointF( p1 ), cursorPos );
|
||||
QLineF lineC = QLineF( QPointF( p2 ), cursorPos );
|
||||
|
||||
// picture a triangle made up of the two points for the line segment, plus the
|
||||
// cursor position. The height of the triangle is the distance from the cursor point
|
||||
// to the line segment. If the cursor lies on the line, then the height should be less than
|
||||
// or equal to the half-width of the pen that drew the line.
|
||||
//
|
||||
// so, use Heron's Formula to get the area, plus A=0.5*base*height, re-arrange to get height.
|
||||
//
|
||||
// easy!
|
||||
float sp = 0.5*( lineA.length() + base.length() + lineC.length() );
|
||||
float a = lineA.length();
|
||||
float b = base.length();
|
||||
float c = lineC.length();
|
||||
float area = sqrt( sp * (sp - a) * (sp - b) * (sp - c) );
|
||||
|
||||
float height = ( 2 * area ) / b;
|
||||
|
||||
if ( height <= penHalfSize * 1.25 )
|
||||
{
|
||||
// got one
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the strokes.
|
||||
*
|
||||
* @return The list of existing strokes
|
||||
*/
|
||||
const QList<Stroke*> Drawing::strokes()
|
||||
{
|
||||
return strokes_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a transformation to manipulate.
|
||||
*
|
||||
* @param index Index of the transform to get
|
||||
* @return QMatrix or 0 if not found
|
||||
*/
|
||||
QMatrix *Drawing::transform( quint32 index )
|
||||
{
|
||||
if( (qint64)index >= transforms_.count() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return transforms_.at( index );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the transformations.
|
||||
*
|
||||
* @return The list of existing transformations
|
||||
*/
|
||||
const QList<QMatrix*> Drawing::transforms()
|
||||
{
|
||||
return transforms_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this drawing is empty.
|
||||
*
|
||||
* @return True if this is an empty (null) Drawing, false otherwise.
|
||||
*/
|
||||
bool Drawing::isNull() const
|
||||
{
|
||||
return isNull_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change the current attribute set.
|
||||
*
|
||||
* This will change the attribute set which will be applied
|
||||
* to the next strokes.
|
||||
*
|
||||
* @param attributeSet the new attribute set
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::setCurrentAttributeSet( AttributeSet *attributeSet )
|
||||
{
|
||||
if( ! attributeSets_.contains( attributeSet ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentAttributeSet_ = attributeSet;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change the current transformation.
|
||||
*
|
||||
* This will change the transformation which will be applied
|
||||
* to the next strokes.
|
||||
*
|
||||
* @param transform the new transformation
|
||||
* @return bool
|
||||
*/
|
||||
bool Drawing::setCurrentTransform( QMatrix *transform )
|
||||
{
|
||||
if( ! transforms_.contains( transform ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentTransform_ = transform;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGSPARSER_H
|
||||
#define TAGSPARSER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMatrix>
|
||||
#include <QString>
|
||||
|
||||
#include <IsfQt>
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace Compress
|
||||
{
|
||||
class DataSource;
|
||||
}
|
||||
using Compress::DataSource;
|
||||
class Drawing;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The methods in this class can parse the ISF tags data.
|
||||
*
|
||||
* @author Valerio Pilo (valerio@kmess.org)
|
||||
*/
|
||||
class TagsParser
|
||||
{
|
||||
|
||||
public: // Static public methods
|
||||
static IsfError parseCustomTag( DataSource &source, Drawing &drawing, quint64 tagIndex );
|
||||
static IsfError parseGuidTable( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseHiMetricSize( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseInkSpaceRectangle( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseAttributeBlock( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseAttributeTable( DataSource &source, Drawing &drawing );
|
||||
static IsfError parsePersistentFormat( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseMetricBlock( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseMetricTable( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseTransformation( DataSource &source, Drawing &drawing, quint64 transformType );
|
||||
static IsfError parseTransformationTable( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseStroke( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseStrokeDescBlock( DataSource &source, Drawing &drawing );
|
||||
static IsfError parseStrokeDescTable( DataSource &source, Drawing &drawing );
|
||||
|
||||
public: // Static public debugging methods
|
||||
static IsfError parseUnsupported( DataSource &source, const QString &tagName );
|
||||
|
||||
private: // Static private debugging methods
|
||||
static QByteArray analyzePayload( DataSource &source, const QString &tagName );
|
||||
static QByteArray analyzePayload( DataSource &source, const quint64 payloadSize, const QString &message = QString() );
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,588 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tagswriter.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include "data/compression.h"
|
||||
#include "data/datasource.h"
|
||||
#include "data/multibytecoding.h"
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
|
||||
using namespace Isf;
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write the persistent format tag.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addPersistentFormat( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
Q_UNUSED( drawing );
|
||||
|
||||
QByteArray tagContents;
|
||||
|
||||
tagContents.append( encodeUInt( ISF_PERSISTENT_FORMAT_VERSION ) );
|
||||
|
||||
tagContents.prepend( encodeUInt( tagContents.size() ) );
|
||||
tagContents.prepend( encodeUInt( TAG_PERSISTENT_FORMAT ) );
|
||||
|
||||
source.append( tagContents );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Persistent Format version";
|
||||
#endif
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write the drawing dimensions.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addHiMetricSize( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
QByteArray tagContents;
|
||||
|
||||
tagContents.append( encodeInt( drawing.size_.width () ) );
|
||||
tagContents.append( encodeInt( drawing.size_.height() ) );
|
||||
|
||||
encodeUInt( source, TAG_HIMETRIC_SIZE );
|
||||
encodeUInt( source, tagContents.size() );
|
||||
source.append( tagContents );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added drawing dimensions:" << drawing.size_;
|
||||
#endif
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write a table (or a block only) of points attributes.
|
||||
*
|
||||
* If there is only one block, no table is outputted into the stream, just
|
||||
* that block.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
QByteArray blockData;
|
||||
QByteArray tagContents;
|
||||
AttributeSet defaultAttributeSet;
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Adding" << drawing.attributeSets_.count() << "attributes...";
|
||||
quint8 counter = 0;
|
||||
#endif
|
||||
|
||||
foreach( const AttributeSet *info, drawing.attributeSets_ )
|
||||
{
|
||||
// Add the color to the attribute block
|
||||
if( info->color != defaultAttributeSet.color )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_COLORREF ) );
|
||||
|
||||
// Prepare the color value, it needs to be stored in BGR format,
|
||||
// in the 24 least significant bits
|
||||
quint64 value = ( info->color.blue () << 16 )
|
||||
| ( info->color.green() << 8 )
|
||||
| ( info->color.red () << 0 );
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Color:" << info->color.name();
|
||||
#endif
|
||||
blockData.append( encodeUInt( value ) );
|
||||
|
||||
// Add the transparency if needed
|
||||
if( info->color.alpha() < 255 )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_TRANSPARENCY ) );
|
||||
blockData.append( encodeUInt( info->color.alpha() ) );
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Alpha:" << info->color.alpha();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Add the pen size
|
||||
if( info->penSize != defaultAttributeSet.penSize )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_PEN_WIDTH ) );
|
||||
blockData.append( encodeUInt( info->penSize.width() * HiMetricToPixel ) );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Pen width:" << ( info->penSize.width() * HiMetricToPixel );
|
||||
#endif
|
||||
if( info->penSize.width() != info->penSize.height() )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_PEN_HEIGHT ) );
|
||||
blockData.append( encodeUInt( info->penSize.height() * HiMetricToPixel ) );
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Pen height:" << ( info->penSize.height() * HiMetricToPixel );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Add the other drawing flags
|
||||
if( info->flags != defaultAttributeSet.flags )
|
||||
{
|
||||
StrokeFlags flags = info->flags;
|
||||
if( flags & IsRectangle )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_PEN_TIP ) );
|
||||
blockData.append( encodeUInt( 0 ) ); // Value unknown, is the tag enough?
|
||||
flags ^= IsRectangle;
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - isRectangle flag";
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
if( flags & IsHighlighter )
|
||||
{
|
||||
blockData.append( encodeUInt( GUID_ROP ) );
|
||||
blockData.append( QByteArray( 4, '\0' ) ); // Value unknown
|
||||
flags ^= IsHighlighter;
|
||||
}
|
||||
*/
|
||||
|
||||
// Add FitToCurve too for now, as a test
|
||||
flags |= FitToCurve;
|
||||
|
||||
// Copy the other flags as they are
|
||||
blockData.append( encodeUInt( GUID_DRAWING_FLAGS ) );
|
||||
blockData.append( encodeUInt( flags ) );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Flags bitfield:" << flags;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
blockData.prepend( encodeUInt( blockData.size() ) );
|
||||
tagContents.append( blockData );
|
||||
blockData.clear();
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added attribute block #" << ++counter;
|
||||
#endif
|
||||
}
|
||||
|
||||
if( drawing.attributeSets_.count() > 1 )
|
||||
{
|
||||
tagContents.prepend( encodeUInt( tagContents.size() ) );
|
||||
tagContents.prepend( encodeUInt( TAG_DRAW_ATTRS_TABLE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
tagContents.prepend( encodeUInt( TAG_DRAW_ATTRS_BLOCK ) );
|
||||
}
|
||||
|
||||
source.append( tagContents );
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write a table (or a block only) of metrics.
|
||||
*
|
||||
* If there is only one block, no table is outputted into the stream, just
|
||||
* that block.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addMetricsTable( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
QByteArray metricData;
|
||||
QByteArray metricBlockData;
|
||||
QByteArray tagData;
|
||||
Metrics defaultMetrics;
|
||||
Metric *defaultMetric;
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Adding" << drawing.metrics_.count() << "metrics...";
|
||||
quint8 counter = 0;
|
||||
#endif
|
||||
|
||||
foreach( const Metrics *metrics, drawing.metrics_ )
|
||||
{
|
||||
QMapIterator<int,Metric> it( metrics->items );
|
||||
while( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
const quint64 &property = it.key ();
|
||||
const Metric &metric = it.value();
|
||||
|
||||
// Skip metrics which are set to the default
|
||||
defaultMetric = &defaultMetrics.items[ property ];
|
||||
if( defaultMetric->min == metric.min
|
||||
&& defaultMetric->max == metric.max
|
||||
&& defaultMetric->units == metric.units
|
||||
&& defaultMetric->resolution == metric.resolution )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write the metric data
|
||||
metricData.append( encodeInt( metric.min ) );
|
||||
metricData.append( encodeInt( metric.max ) );
|
||||
metricData.append( (uchar) metric.units );
|
||||
metricData.append( encodeFloat( metric.resolution ) );
|
||||
|
||||
// Write how much data is there
|
||||
metricData.prepend( encodeUInt( metricData.size() ) );
|
||||
|
||||
// Write the property ID
|
||||
metricData.prepend( encodeUInt( property ) );
|
||||
|
||||
// Flush the metric
|
||||
metricBlockData.append( metricData );
|
||||
metricData.clear();
|
||||
}
|
||||
|
||||
// Flush the metrics block
|
||||
tagData.append( encodeUInt( metricBlockData.size() ) );
|
||||
tagData.append( metricBlockData );
|
||||
metricBlockData.clear();
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added metrics block #" << ++counter;
|
||||
#endif
|
||||
}
|
||||
|
||||
if( drawing.metrics_.count() > 1 )
|
||||
{
|
||||
tagData.prepend( encodeUInt( TAG_METRIC_TABLE ) );
|
||||
}
|
||||
else if ( drawing.metrics_.count() == 1 )
|
||||
{
|
||||
tagData.prepend( encodeUInt( TAG_METRIC_BLOCK ) );
|
||||
}
|
||||
// else: don't do anything.
|
||||
|
||||
source.append( tagData );
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write a table (or a block only) of transformation matrices.
|
||||
*
|
||||
* If there is only one block, no table is outputted into the stream, just
|
||||
* that block.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addTransformationTable( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
QByteArray blockData;
|
||||
QByteArray tagContents;
|
||||
quint64 transformTag;
|
||||
|
||||
/*
|
||||
* QTransform is too complex for the 2D transformations we need to do;
|
||||
* but QMatrix is too simple: it doesn't 'remember' rotations. So we
|
||||
* save rotations as generic transformations.
|
||||
* Possible solutions:
|
||||
* 1) Create a struct containing the transform matrix data and use
|
||||
* that instead of QMatrices;
|
||||
* 2) Switch (again!) to QTransform and fix the inconsistencies.
|
||||
*/
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Adding" << drawing.transforms_.count() << "transformations...";
|
||||
quint8 counter = 0;
|
||||
#endif
|
||||
|
||||
foreach( const QMatrix *trans, drawing.transforms_ )
|
||||
{
|
||||
/*
|
||||
* All transforms are written backwards because they're stored my most
|
||||
* significant value first.
|
||||
*/
|
||||
|
||||
// Detect translation
|
||||
if( trans->dx() || trans->dy() )
|
||||
{
|
||||
// Detect scaling
|
||||
if( trans->m11() || trans->m22() )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Transform: TAG_TRANSFORM_SCALE_AND_TRANSLATE";
|
||||
qDebug() << " - Transformation details - "
|
||||
<< "Scale X:" << trans->m11()
|
||||
<< "Scale Y:" << trans->m22()
|
||||
<< "Translate X:" << trans->dx()
|
||||
<< "Translate Y:" << trans->dy();
|
||||
#endif
|
||||
transformTag = TAG_TRANSFORM_SCALE_AND_TRANSLATE;
|
||||
blockData.append( encodeFloat( trans->m11() * HiMetricToPixel ) );
|
||||
blockData.append( encodeFloat( trans->m22() * HiMetricToPixel ) );
|
||||
blockData.append( encodeFloat( trans->dx() / trans->m11() ) );
|
||||
blockData.append( encodeFloat( trans->dy() / trans->m22() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Transform: TAG_TRANSFORM_TRANSLATE";
|
||||
qDebug() << " - Transformation details - "
|
||||
<< "Translate X:" << trans->dx()
|
||||
<< "Translate Y:" << trans->dy();
|
||||
#endif
|
||||
transformTag = TAG_TRANSFORM_TRANSLATE;
|
||||
blockData.append( encodeFloat( trans->dx() ) );
|
||||
blockData.append( encodeFloat( trans->dy() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
// Detect scaling
|
||||
if( trans->m11() || trans->m22() )
|
||||
{
|
||||
if( trans->m11() == trans->m22() )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Transform: TAG_TRANSFORM_ISOTROPIC_SCALE";
|
||||
qDebug() << " - Transformation details - "
|
||||
<< "Scale:" << (trans->m11() * HiMetricToPixel);
|
||||
#endif
|
||||
transformTag = TAG_TRANSFORM_ISOTROPIC_SCALE;
|
||||
blockData.append( encodeFloat( trans->m11() * HiMetricToPixel ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Transform: TAG_TRANSFORM_ANISOTROPIC_SCALE";
|
||||
qDebug() << " - Transformation details - "
|
||||
<< "Scale X:" << trans->m11()
|
||||
<< "Scale Y:" << trans->m22();
|
||||
#endif
|
||||
transformTag = TAG_TRANSFORM_ANISOTROPIC_SCALE;
|
||||
blockData.append( encodeFloat( trans->m11() * HiMetricToPixel ) );
|
||||
blockData.append( encodeFloat( trans->m22() * HiMetricToPixel ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << " - Transform: TAG_TRANSFORM";
|
||||
#endif
|
||||
transformTag = TAG_TRANSFORM;
|
||||
blockData.append( encodeFloat( trans->m11() * HiMetricToPixel ) );
|
||||
blockData.append( encodeFloat( .0f ) );
|
||||
blockData.append( encodeFloat( .0f ) );
|
||||
blockData.append( encodeFloat( trans->m22() * HiMetricToPixel ) );
|
||||
blockData.append( encodeFloat( trans->dx () / trans->m11() ) );
|
||||
blockData.append( encodeFloat( trans->dy () / trans->m22() ) );
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Transformation details - "
|
||||
<< "Scale X:" << trans->m11()
|
||||
<< "Shear X:" << trans->m21()
|
||||
<< "Scale Y:" << trans->m22()
|
||||
<< "Shear Y:" << trans->m12()
|
||||
<< "Translate X:" << trans->dx()
|
||||
<< "Translate Y:" << trans->dy();
|
||||
#endif
|
||||
}
|
||||
|
||||
blockData.prepend( encodeUInt( transformTag ) );
|
||||
|
||||
tagContents.append( blockData );
|
||||
blockData.clear();
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added transform #" << ++counter;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if ( drawing.transforms_.size() == 0 )
|
||||
{
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added default transformation";
|
||||
#endif
|
||||
|
||||
// write the default transform.
|
||||
const QMatrix *transform = &drawing.defaultTransform_;
|
||||
tagContents.append( TAG_TRANSFORM_ISOTROPIC_SCALE );
|
||||
tagContents.append( encodeFloat( transform->m11() * HiMetricToPixel ) );
|
||||
}
|
||||
else if ( drawing.transforms_.size() > 1 )
|
||||
{
|
||||
tagContents.prepend( encodeUInt( tagContents.size() ) );
|
||||
tagContents.prepend( encodeUInt( TAG_TRANSFORM_TABLE ) );
|
||||
}
|
||||
|
||||
source.append( tagContents );
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write the strokes.
|
||||
*
|
||||
* @param source Data Source where to write bytes to
|
||||
* @param drawing Drawing from which to obtain the data to write
|
||||
* @return IsfError
|
||||
*/
|
||||
IsfError TagsWriter::addStrokes( DataSource &source, const Drawing &drawing )
|
||||
{
|
||||
QByteArray blockData;
|
||||
QByteArray tagContents;
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Adding" << drawing.strokes_.count() << "strokes...";
|
||||
quint8 counter = 0;
|
||||
#endif
|
||||
|
||||
// Last set of attibutes applied to a stroke
|
||||
Metrics *currentMetrics = 0;
|
||||
AttributeSet *currentAttributeSet = 0;
|
||||
QMatrix *currentTransform = 0;
|
||||
|
||||
foreach( const Stroke *stroke, drawing.strokes_ )
|
||||
{
|
||||
// There is more than one set of metrics, assign each stroke to its own
|
||||
if( drawing.metrics_.count() > 1 )
|
||||
{
|
||||
// Make sure that the first strokes use the first metrics list (write a MIDX only
|
||||
// when needed)
|
||||
if( currentMetrics == 0 )
|
||||
{
|
||||
currentMetrics = drawing.metrics_.first();
|
||||
}
|
||||
|
||||
// Only write a MIDX if this stroke needs different metrics than the last stroke
|
||||
if( currentMetrics != stroke->metrics && stroke->metrics != 0 )
|
||||
{
|
||||
currentMetrics = stroke->metrics;
|
||||
blockData.append( encodeUInt( TAG_MIDX ) );
|
||||
blockData.append( encodeUInt( drawing.metrics_.indexOf( stroke->metrics ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// There is more than one set of attributes, assign each stroke to its own
|
||||
if( drawing.attributeSets_.count() > 1 )
|
||||
{
|
||||
// Make sure that the first strokes use the first attribute set (write a DIDX only
|
||||
// when needed)
|
||||
if( currentAttributeSet == 0 )
|
||||
{
|
||||
currentAttributeSet = drawing.attributeSets_.first();
|
||||
}
|
||||
|
||||
// Only write a DIDX if this stroke needs a different attribute set than the last stroke
|
||||
if( currentAttributeSet != stroke->attributes && stroke->attributes != 0 )
|
||||
{
|
||||
currentAttributeSet = stroke->attributes;
|
||||
blockData.append( encodeUInt( TAG_DIDX ) );
|
||||
blockData.append( encodeUInt( drawing.attributeSets_.indexOf( stroke->attributes ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the first strokes use the first transform (write a TIDX only
|
||||
// when needed)
|
||||
if ( drawing.transforms_.count() > 0 )
|
||||
{
|
||||
if( currentTransform == 0 )
|
||||
{
|
||||
currentTransform = drawing.transforms_.first();
|
||||
}
|
||||
|
||||
// Only write a TIDX if this stroke needs a different transform than the last stroke
|
||||
if( currentTransform != stroke->transform && stroke->transform != 0 )
|
||||
{
|
||||
currentTransform = stroke->transform;
|
||||
blockData.append( encodeUInt( TAG_TIDX ) );
|
||||
blockData.append( encodeUInt( drawing.transforms_.indexOf( stroke->transform ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the index tags
|
||||
if( ! blockData.isEmpty() )
|
||||
{
|
||||
tagContents.append( blockData );
|
||||
blockData.clear();
|
||||
}
|
||||
|
||||
// Write this stroke in the stream
|
||||
|
||||
QList<qint64> xPoints, yPoints;
|
||||
foreach( const Point &point, stroke->points )
|
||||
{
|
||||
xPoints.append( point.position.x() );
|
||||
yPoints.append( point.position.y() );
|
||||
}
|
||||
|
||||
deflatePacketData( blockData, xPoints );
|
||||
deflatePacketData( blockData, yPoints );
|
||||
|
||||
// The stroke is made by tag, then payload size, then number of points, then
|
||||
// the compressed points data
|
||||
blockData.prepend( encodeUInt( stroke->points.count() ) );
|
||||
blockData.prepend( encodeUInt( blockData.size() ) );
|
||||
blockData.prepend( encodeUInt( TAG_STROKE ) );
|
||||
|
||||
tagContents.append( blockData );
|
||||
blockData.clear();
|
||||
|
||||
#ifdef ISFQT_DEBUG_VERBOSE
|
||||
qDebug() << "- Added stroke #" << ++counter;
|
||||
#endif
|
||||
}
|
||||
|
||||
source.append( tagContents );
|
||||
|
||||
return ISF_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGSWRITER_H
|
||||
#define TAGSWRITER_H
|
||||
|
||||
#include <IsfQt>
|
||||
|
||||
|
||||
|
||||
namespace Isf
|
||||
{
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace Compress
|
||||
{
|
||||
class DataSource;
|
||||
}
|
||||
using Compress::DataSource;
|
||||
class Drawing;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The methods in this class can convert data to ISF tags.
|
||||
*
|
||||
* @author Valerio Pilo (valerio@kmess.org)
|
||||
*/
|
||||
class TagsWriter
|
||||
{
|
||||
public: // Static public methods
|
||||
static IsfError addPersistentFormat( DataSource &source, const Drawing &drawing );
|
||||
static IsfError addHiMetricSize( DataSource &source, const Drawing &drawing );
|
||||
static IsfError addAttributeTable( DataSource &source, const Drawing &drawing );
|
||||
static IsfError addMetricsTable( DataSource &source, const Drawing &drawing );
|
||||
static IsfError addTransformationTable( DataSource &source, const Drawing &drawing );
|
||||
static IsfError addStrokes( DataSource &source, const Drawing &drawing );
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
INCLUDE_DIRECTORIES( ${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
SET( CMAKE_EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
MACRO( add_multiple_tests )
|
||||
FOREACH( test ${ARGN} )
|
||||
QT4_AUTOMOC( test_${test}.cpp )
|
||||
ADD_EXECUTABLE( test_${test} test_${test}.cpp )
|
||||
ADD_TEST( libisf-${test} test_${test} )
|
||||
TARGET_LINK_LIBRARIES( test_${test} ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} isf-qt )
|
||||
ENDFOREACH( test )
|
||||
ENDMACRO( add_multiple_tests )
|
||||
|
||||
ADD_MULTIPLE_TESTS(
|
||||
isfdrawing
|
||||
multibyte_coding
|
||||
algorithms
|
||||
)
|
||||
|
||||
|
||||
# Compile the other testing applications
|
||||
ADD_SUBDIRECTORY( decode )
|
||||
ADD_SUBDIRECTORY( inkedit )
|
||||
@@ -0,0 +1,33 @@
|
||||
set( CMAKE_BUILD_TYPE debugfull )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
set( CMAKE_CXX_FLAGS_DEBUGFULL "-O0 -g3 -fno-inline -Wall -Woverloaded-virtual -Wsign-compare -Wundef -fvisibility=default" )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
|
||||
set( TEST_DECODE_SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set( TEST_DECODE_MOC_HEADERS
|
||||
# testdecode.h
|
||||
)
|
||||
|
||||
set( TEST_DECODE_UI
|
||||
testdecode.ui
|
||||
)
|
||||
|
||||
find_package( Qt4 REQUIRED )
|
||||
include( ${QT_USE_FILE} )
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
qt4_wrap_ui( TEST_DECODE_UI_HEADERS ${TEST_DECODE_UI} )
|
||||
qt4_wrap_cpp( TEST_DECODE_MOC_SOURCES ${TEST_DECODE_MOC_HEADERS} )
|
||||
|
||||
add_executable( test_decode
|
||||
${TEST_DECODE_MOC_SOURCES}
|
||||
${TEST_DECODE_SOURCES}
|
||||
${TEST_DECODE_UI_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( test_decode ${QT_QTGUI_LIBRARY} isf-qt )
|
||||
@@ -0,0 +1,192 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Valerio Pilo *
|
||||
* valerio@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "ui_testdecode.h"
|
||||
|
||||
|
||||
|
||||
class TestDecode : public QMainWindow, private Ui::TestDecode
|
||||
{
|
||||
public:
|
||||
|
||||
void test()
|
||||
{
|
||||
bool rewrite = false;
|
||||
QStringList arguments( qApp->arguments() );
|
||||
arguments.removeAt( 0 );
|
||||
|
||||
if( arguments.count() < 1 )
|
||||
{
|
||||
label_->setText( "You must specify the name of an ISF file to test!" );
|
||||
return;
|
||||
}
|
||||
|
||||
int rewriteIndex = arguments.indexOf( "--rewrite" );
|
||||
if( rewriteIndex >= 0 )
|
||||
{
|
||||
rewrite = true;
|
||||
arguments.removeAt( rewriteIndex );
|
||||
}
|
||||
|
||||
const QString fileName( arguments.at( 0 ) );
|
||||
const QByteArray rawData( readTestIsfData( fileName ) );
|
||||
Isf::Drawing drawing;
|
||||
|
||||
// Extract the ISF data from the GIF image
|
||||
if( fileName.contains( ".gif" ) )
|
||||
{
|
||||
qDebug() << "------------------------- Creating drawing from GIF -------------------------";
|
||||
drawing = Isf::Stream::readerGif( rawData );
|
||||
}
|
||||
// Extract the ISF data from the ISF file
|
||||
else
|
||||
{
|
||||
qDebug() << "------------------------- Creating drawing from ISF -------------------------";
|
||||
drawing = Isf::Stream::reader( rawData );
|
||||
}
|
||||
|
||||
if( rewrite )
|
||||
{
|
||||
// change to test GIF or regular streams
|
||||
bool testGif = false;
|
||||
|
||||
if( testGif )
|
||||
{
|
||||
// Test Fortified-GIF r/w
|
||||
qDebug() << "------------------------- Writing drawing to GIF file -------------------------";
|
||||
QByteArray data( Isf::Stream::writerGif( drawing ) );
|
||||
|
||||
qDebug() << "------------------------- Reading GIF back -------------------------";
|
||||
drawing = Isf::Stream::readerGif( data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test regular streams r/w
|
||||
qDebug() << "------------------------- Writing drawing to ISF file -------------------------";
|
||||
QByteArray data2( Isf::Stream::writer( drawing ) );
|
||||
|
||||
qDebug() << "------------------------- Reading ISF back -------------------------";
|
||||
drawing = Isf::Stream::reader( data2 );
|
||||
}
|
||||
}
|
||||
|
||||
if( drawing.isNull() )
|
||||
{
|
||||
label_->setText( "Invalid file contents!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "------------------------- Showing it -------------------------";
|
||||
label_->setPixmap( drawing.pixmap( Qt::transparent ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TestDecode()
|
||||
{
|
||||
QWidget *mainWidget = new QWidget( this );
|
||||
setupUi( mainWidget );
|
||||
setCentralWidget( mainWidget );
|
||||
setWindowTitle( "ISF decoding test" );
|
||||
|
||||
connect( closeButton_, SIGNAL( clicked(QAbstractButton*) ),
|
||||
this, SLOT ( close() ) );
|
||||
|
||||
show();
|
||||
|
||||
test();
|
||||
}
|
||||
|
||||
~TestDecode()
|
||||
{}
|
||||
|
||||
|
||||
|
||||
// read some test raw ISF data from a file on the filesystem and
|
||||
// return it as a QByteArray.
|
||||
QByteArray readTestIsfData( const QString &filename )
|
||||
{
|
||||
QFile file( filename );
|
||||
if ( !file.exists() )
|
||||
{
|
||||
qWarning() << "Test ISF file" << filename << "does not exist.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// read file and convert to qbytearray.
|
||||
if ( !file.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "Failed to open ISF data file" << filename;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// read some test raw ISF data from a file on the filesystem and
|
||||
// return it as a QByteArray.
|
||||
void saveTestIsfData( const QByteArray &data )
|
||||
{
|
||||
static int number = 1;
|
||||
QString fileName( "test" + QString::number( number ) + "." );
|
||||
|
||||
// autodetect if it's a gif or an isf
|
||||
if( data[0] == '\0' )
|
||||
{
|
||||
fileName.append( "isf" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName.append( "gif" );
|
||||
}
|
||||
|
||||
QFile file( fileName );
|
||||
file.open( QIODevice::WriteOnly );
|
||||
file.write( data );
|
||||
file.close();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
QApplication app( argc, argv );
|
||||
|
||||
TestDecode test;
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TestDecode</class>
|
||||
<widget class="QWidget" name="TestDecode">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>314</width>
|
||||
<height>123</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="closeButton_">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,33 @@
|
||||
set( CMAKE_BUILD_TYPE debugfull )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
set( CMAKE_CXX_FLAGS_DEBUGFULL "-O0 -g3 -fno-inline -Wall -Woverloaded-virtual -Wsign-compare -Wundef -fvisibility=default" )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
|
||||
set( TEST_INKEDIT_SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set( TEST_INKEDIT_MOC_HEADERS
|
||||
main.h
|
||||
)
|
||||
|
||||
set( TEST_INKEDIT_UI
|
||||
testinkedit.ui
|
||||
)
|
||||
|
||||
find_package( Qt4 REQUIRED )
|
||||
include( ${QT_USE_FILE} )
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
qt4_wrap_cpp( TEST_INKEDIT_MOC_SOURCES ${TEST_INKEDIT_MOC_HEADERS} )
|
||||
qt4_wrap_ui( TEST_INKEDIT_UI_HEADERS ${TEST_INKEDIT_UI} )
|
||||
|
||||
add_executable( test_inkedit
|
||||
${TEST_INKEDIT_MOC_SOURCES}
|
||||
${TEST_INKEDIT_SOURCES}
|
||||
${TEST_INKEDIT_UI_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( test_inkedit ${QT_QTGUI_LIBRARY} isf-qt )
|
||||
@@ -0,0 +1,193 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QDataStream>
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
|
||||
#include <IsfInkCanvas>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
using namespace Isf;
|
||||
|
||||
TestInkEdit::TestInkEdit()
|
||||
{
|
||||
setupUi( this );
|
||||
connect( cmdSave_, SIGNAL(clicked()), this, SLOT( saveInk() ) );
|
||||
connect( cmdLoad_, SIGNAL(clicked()), this, SLOT( loadInk() ) );
|
||||
connect( cmdClear_, SIGNAL(clicked()), this, SLOT( clearInk() ) );
|
||||
|
||||
connect( cmdStrokeColor_, SIGNAL(clicked()), this, SLOT( chooseColor() ) );
|
||||
connect( cmdCanvasColor_, SIGNAL(clicked()), this, SLOT( chooseColor() ) );
|
||||
|
||||
QButtonGroup *grp = new QButtonGroup( this );
|
||||
grp->addButton( rbDrawing_ );
|
||||
grp->addButton( rbEraser_ );
|
||||
|
||||
connect( grp, SIGNAL( buttonClicked( QAbstractButton * ) ), this, SLOT( penTypeChanged( QAbstractButton * ) ) );
|
||||
|
||||
connect( spinWidth_, SIGNAL( valueChanged( int ) ), editor_, SLOT( setPenSize( int ) ) );
|
||||
|
||||
editor_->setPenSize( spinWidth_->value() );
|
||||
/*
|
||||
setWindowTitle("Ink Edit Test");
|
||||
|
||||
editor_ = new Isf::InkEdit();
|
||||
editor_->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
|
||||
|
||||
sayLabel_ = new QLabel();
|
||||
sayLabel_->setText( "Draw something!" );
|
||||
sayLabel_->setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
|
||||
|
||||
cmdSave_ = new QPushButton();
|
||||
cmdSave_->setText( "Save Ink" );
|
||||
connect( cmdSave_, SIGNAL(clicked()), this, SLOT( saveInk() ) );
|
||||
|
||||
cmdLoad_ = new QPushButton();
|
||||
cmdLoad_->setText( "Load Ink" );
|
||||
connect( cmdLoad_, SIGNAL(clicked()), this, SLOT( loadInk() ) );
|
||||
|
||||
QPushButton *cmdClear_ = new QPushButton();
|
||||
cmdClear_->setText( "Clear Ink" );
|
||||
connect( cmdClear_, SIGNAL(clicked()), this, SLOT( clearInk() ) );
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
QHBoxLayout *strokeBtnLayout = new QHBoxLayout();
|
||||
|
||||
layout->addWidget( sayLabel_ );
|
||||
|
||||
layout->addWidget( editor_ );
|
||||
|
||||
QHBoxLayout *ctlBtnLayout = new QHBoxLayout();
|
||||
ctlBtnLayout->addWidget(cmdSave_);
|
||||
ctlBtnLayout->addWidget(cmdLoad_);
|
||||
ctlBtnLayout->addWidget(cmdClear_);
|
||||
|
||||
layout->addLayout( ctlBtnLayout );
|
||||
|
||||
setLayout( layout );
|
||||
*/
|
||||
}
|
||||
|
||||
TestInkEdit::~TestInkEdit()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void TestInkEdit::chooseColor()
|
||||
{
|
||||
QColor color = QColorDialog::getColor();
|
||||
if ( sender() == cmdStrokeColor_ )
|
||||
{
|
||||
editor_->setPenColor( color );
|
||||
}
|
||||
else
|
||||
{
|
||||
editor_->setCanvasColor( color );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestInkEdit::penTypeChanged( QAbstractButton *button )
|
||||
{
|
||||
if( button == rbDrawing_ )
|
||||
{
|
||||
editor_->setPenType( InkCanvas::DrawingPen );
|
||||
}
|
||||
else
|
||||
{
|
||||
editor_->setPenType( InkCanvas::EraserPen );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestInkEdit::saveInk()
|
||||
{
|
||||
QString filter;
|
||||
QString saveFile = QFileDialog::getSaveFileName( this, "Save Ink", QString(), "Raw ISF (*.isf);;base64-encoded ISF (*.isf64)", &filter );
|
||||
if ( saveFile != QString() )
|
||||
{
|
||||
QFile file(saveFile);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
|
||||
if ( filter.contains("isf64") )
|
||||
{
|
||||
editor_->save( file, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
editor_->save( file );
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
QMessageBox::information(0, "Save complete", "Saved to " + saveFile );
|
||||
}
|
||||
}
|
||||
|
||||
void TestInkEdit::loadInk()
|
||||
{
|
||||
QString filter;
|
||||
QString filename = QFileDialog::getOpenFileName( this, "Open Ink", QString(), "Raw ISF (*.isf);;base64-encoded ISF (*.isf64)", &filter );
|
||||
if ( ! filename.isEmpty() )
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QByteArray data = filter.contains("*.isf64") ? QByteArray::fromBase64( file.readAll() ) : file.readAll();
|
||||
|
||||
file.close();
|
||||
|
||||
// got some ink.
|
||||
Isf::Drawing *drawing = &Isf::Stream::reader(data);
|
||||
|
||||
editor_->setDrawing( drawing );
|
||||
|
||||
editor_->updateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void TestInkEdit::clearInk()
|
||||
{
|
||||
editor_->clear();
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
QApplication app( argc, argv );
|
||||
|
||||
TestInkEdit edit;
|
||||
edit.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include "ui_testinkedit.h"
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QAbstractButton>
|
||||
|
||||
#include <IsfInkCanvas>
|
||||
|
||||
|
||||
class TestInkEdit : public QWidget, public Ui::TestInkEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
TestInkEdit();
|
||||
~TestInkEdit();
|
||||
|
||||
public slots:
|
||||
|
||||
void saveInk();
|
||||
void loadInk();
|
||||
void clearInk();
|
||||
void penTypeChanged( QAbstractButton *button );
|
||||
void chooseColor();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,215 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TestInkEdit</class>
|
||||
<widget class="QWidget" name="TestInkEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>495</width>
|
||||
<height>459</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Ink Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Draw Something!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="Isf::InkCanvas" name="editor_" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="cmdStrokeColor_">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stroke Colour</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cmdCanvasColor_">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Canvas Colour</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stroke Width </p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(Pixels)</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinWidth_">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> pixels</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="penType_">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Pen Type</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbDrawing_">
|
||||
<property name="text">
|
||||
<string>Drawing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbEraser_">
|
||||
<property name="text">
|
||||
<string>Eraser</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cmdSave_">
|
||||
<property name="text">
|
||||
<string>Save Ink</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cmdLoad_">
|
||||
<property name="text">
|
||||
<string>Load Ink</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cmdClear_">
|
||||
<property name="text">
|
||||
<string>Clear Ink</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Isf::InkCanvas</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">IsfInkCanvas</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.*/
|
||||
|
||||
#include "test_algorithms.h"
|
||||
|
||||
#include "data/datasource.h"
|
||||
#include "data/multibytecoding.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
|
||||
using namespace Isf::Compress;
|
||||
|
||||
|
||||
|
||||
void TestAlgorithms::testDataSource()
|
||||
{
|
||||
// Create some bits
|
||||
DataSource data;
|
||||
|
||||
QBitArray bits( 4 );
|
||||
bits.fill( true );
|
||||
for(int i=3;i >= 0; --i )
|
||||
{
|
||||
bits.setBit( i, 0 );
|
||||
data.append( bits );
|
||||
}
|
||||
|
||||
qDebug() << "FINAL RESULT:" << data.data().toHex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
QTEST_MAIN(TestAlgorithms)
|
||||
|
||||
|
||||
|
||||
#include "test_algorithms.moc"
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.*/
|
||||
|
||||
#ifndef TESTALGORITHMS_H
|
||||
#define TESTALGORITHMS_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
||||
|
||||
class TestAlgorithms : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testDataSource();
|
||||
};
|
||||
|
||||
#endif // TESTALGORITHMS_H
|
||||
@@ -0,0 +1,138 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Adam Goossens *
|
||||
* adam@kmess.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This 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 Lesser General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "test_isfdrawing.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <IsfQtDrawing>
|
||||
|
||||
using namespace Isf;
|
||||
|
||||
|
||||
|
||||
TestIsfDrawing::TestIsfDrawing()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestIsfDrawing::emptyConstructor_NullDrawing()
|
||||
{
|
||||
Drawing doc;
|
||||
QCOMPARE(doc.isNull(), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// invalid ISF version numbers should return a null Drawing
|
||||
void TestIsfDrawing::invalidVersion_NullDrawing()
|
||||
{
|
||||
QByteArray data;
|
||||
data.append(0x0B); // isf version 11 - invalid.
|
||||
|
||||
Drawing drawing = Stream::reader( data );
|
||||
QCOMPARE( drawing.isNull(), true );
|
||||
QVERIFY( drawing.error() == ISF_ERROR_BAD_VERSION );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// by default the parser error should be ISF_ERROR_NONE
|
||||
void TestIsfDrawing::parserErrorNoneByDefault()
|
||||
{
|
||||
Drawing drawing;
|
||||
QCOMPARE( drawing.error(), ISF_ERROR_NONE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// an invalid stream size should give a null drawing.
|
||||
void TestIsfDrawing::invalidStreamSize_NullDrawing()
|
||||
{
|
||||
QByteArray data;
|
||||
data.append((char)0x00); // ISF version 1.0.
|
||||
data.append(0x01); // stream size of 1 byte, but only 3 bytes of data.
|
||||
|
||||
Drawing drawing = Stream::reader( data );
|
||||
QCOMPARE( drawing.isNull(), true );
|
||||
QCOMPARE( drawing.error(), ISF_ERROR_BAD_STREAMSIZE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// valid ISF test data should generate a non-null
|
||||
// drawing with the appropriate number of strokes.
|
||||
void TestIsfDrawing::parseValidRawIsfData()
|
||||
{
|
||||
QByteArray data;
|
||||
readTestIsfData( "tests/test1.isf", data );
|
||||
Drawing drawing = Stream::reader( data );
|
||||
QCOMPARE( drawing.isNull(), false );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create a drawing and feed it to the parser
|
||||
void TestIsfDrawing::createDrawing()
|
||||
{
|
||||
qDebug() << "------------------------- Creating drawing from ISF -------------------------";
|
||||
QByteArray data1;
|
||||
readTestIsfData( "tests/test4.isf", data1 );
|
||||
Isf::Drawing drawing1 = Isf::Stream::reader( data1 );
|
||||
|
||||
QCOMPARE( drawing1.isNull(), false );
|
||||
|
||||
qDebug() << "------------------------- Writing drawing to ISF file -------------------------";
|
||||
QByteArray data2( Isf::Stream::writer( drawing1 ) );
|
||||
|
||||
qDebug() << "------------------------- Reading it back -------------------------";
|
||||
Isf::Drawing drawing2 = Isf::Stream::reader( data2 );
|
||||
|
||||
QCOMPARE( drawing2.isNull(), false );
|
||||
|
||||
qDebug() << "Streams size - data1:" << data1.size() << "data2:" << data2.size();
|
||||
QVERIFY( data1.size() == data2.size() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// read some test raw ISF data from a file on the filesystem and
|
||||
// return it as a QByteArray.
|
||||
void TestIsfDrawing::readTestIsfData( const QString &filename, QByteArray &byteArray )
|
||||
{
|
||||
QFile file( filename );
|
||||
QVERIFY( file.exists() );
|
||||
|
||||
// read file and convert to qbytearray.
|
||||
QVERIFY( file.open( QIODevice::ReadOnly ) );
|
||||
|
||||
byteArray = file.readAll();
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
QTEST_MAIN(TestIsfDrawing)
|
||||
|
||||
|
||||
|
||||
#include "test_isfdrawing.moc"
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.*/
|
||||
|
||||
#ifndef TESTISFDRAWING_H
|
||||
#define TESTISFDRAWING_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class TestIsfDrawing : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TestIsfDrawing();
|
||||
void readTestIsfData( const QString &filename, QByteArray &byteArray );
|
||||
|
||||
private slots:
|
||||
void emptyConstructor_NullDrawing();
|
||||
void invalidVersion_NullDrawing();
|
||||
void parserErrorNoneByDefault();
|
||||
void invalidStreamSize_NullDrawing();
|
||||
void parseValidRawIsfData();
|
||||
|
||||
void createDrawing();
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // TESTISFDRAWING_H
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.*/
|
||||
|
||||
#include "test_multibyte_coding.h"
|
||||
|
||||
#include "data/datasource.h"
|
||||
#include "data/multibytecoding.h"
|
||||
|
||||
#include "isfqt-internal.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QByteArray>
|
||||
|
||||
|
||||
void TestMultibyteCoding::testDataSource()
|
||||
{
|
||||
// test the DataSource class
|
||||
|
||||
bool ok;
|
||||
uchar byte;
|
||||
Isf::Compress::DataSource data;
|
||||
|
||||
|
||||
// Read one bit
|
||||
data.append( Q_UINT64_C(0x80) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
QVERIFY( data.getBit() == true );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// Read seven bits
|
||||
data.append( Q_UINT64_C(0xC1) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
byte = 0;
|
||||
for( int i = 0; i < 7; i++ )
|
||||
{
|
||||
bool bit = data.getBit( &ok );
|
||||
QVERIFY( ok );
|
||||
|
||||
byte |= ( bit << ( 7 - i ) ); // Start writing from the 8th bit
|
||||
}
|
||||
QVERIFY( byte == Q_UINT64_C(0xC0) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// Read seven bits, using the method to get multiple bits
|
||||
data.append( Q_UINT64_C(0xC9) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
// bits are for 0xC9:11001001 and for 0x64:01100100 (the least significant bit should be lost)
|
||||
byte = data.getBits( 7, &ok );
|
||||
QVERIFY( ok );
|
||||
|
||||
QVERIFY( byte == Q_UINT64_C(0x64) );
|
||||
|
||||
|
||||
// Read a byte
|
||||
data.clear();
|
||||
data.append( Q_UINT64_C(0x40) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
QVERIFY( data.getByte() == Q_UINT64_C(0x40) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// Read a string (edge case)
|
||||
QByteArray string1( "This is a test string." );
|
||||
data.append( string1 );
|
||||
data.reset(); // To re-read the appended string
|
||||
|
||||
QByteArray string2;
|
||||
for( int i = 0; i < string1.size(); ++i )
|
||||
{
|
||||
string2[ i ] = data.getByte( &ok );
|
||||
QVERIFY( ok );
|
||||
}
|
||||
|
||||
QVERIFY( string1 == string2 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::unsignedEncode()
|
||||
{
|
||||
// test encoding a value that will fit into a single byte.
|
||||
quint64 value = Q_UINT64_C(0x7D);
|
||||
QByteArray result( Isf::Compress::encodeUInt( value ) );
|
||||
|
||||
// expect 1 byte in size
|
||||
QCOMPARE( result.size(), 1 );
|
||||
|
||||
// match the value
|
||||
QVERIFY( (uint)result.at(0) == value );
|
||||
|
||||
// now test the edge case between 1 and 2 bytes for encoding:
|
||||
value = Q_UINT64_C(0x80);
|
||||
// 1000000 = 128 decimal, should get encoded as 2 bytes:
|
||||
// 00000001|10000000
|
||||
result = Isf::Compress::encodeUInt( value );
|
||||
QCOMPARE( result.size(), 2 );
|
||||
QCOMPARE( result.at(0), (char)0x80 );
|
||||
QCOMPARE( result.at(1), (char)0x01 );
|
||||
|
||||
// and finally test a definite multibyte value.
|
||||
value = Q_UINT64_C(0xFFFF); // 11111111 11111111, dec = 65535
|
||||
result = Isf::Compress::encodeUInt( value );
|
||||
QCOMPARE( result.size(), 3 );
|
||||
QCOMPARE( result.at(0), (char)0xFF );
|
||||
QCOMPARE( result.at(1), (char)0xFF );
|
||||
QCOMPARE( result.at(2), (char)0x03 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::unsignedDecode()
|
||||
{
|
||||
quint64 result;
|
||||
|
||||
// test decoding a value that should only get encoded into
|
||||
// a single byte.
|
||||
Isf::Compress::DataSource data;
|
||||
data.append( Q_UINT64_C(0x7D) ); // decimal 125
|
||||
data.reset(); // To re-read the appended bytes
|
||||
|
||||
result = Isf::Compress::decodeUInt( data );
|
||||
|
||||
QVERIFY(result == Q_UINT64_C(0x7D) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// test the edge case...
|
||||
data.append( Q_UINT64_C(0x80) );
|
||||
data.append( Q_UINT64_C(0x01) );
|
||||
data.reset(); // To re-read the appended bytes
|
||||
|
||||
result = Isf::Compress::decodeUInt( data );
|
||||
QVERIFY( result == Q_UINT64_C(0x80) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// test a definite multibyte.
|
||||
data.append( Q_UINT64_C(0xFF) );
|
||||
data.append( Q_UINT64_C(0xFF) );
|
||||
data.append( Q_UINT64_C(0x03) );
|
||||
data.reset(); // To re-read the appended bytes
|
||||
|
||||
result = Isf::Compress::decodeUInt( data );
|
||||
QVERIFY( result == Q_UINT64_C(0xFFFF) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::signedEncode()
|
||||
{
|
||||
// test a value x such that -64 < x < 0.
|
||||
qint64 value = Q_INT64_C(-5);
|
||||
QByteArray result( Isf::Compress::encodeInt( value ) );
|
||||
|
||||
QCOMPARE( result.size(), 1 );
|
||||
QCOMPARE( result.at(0), (char)0x0B ); // -5 encoded.
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::signedDecode()
|
||||
{
|
||||
qint64 result;
|
||||
Isf::Compress::DataSource data;
|
||||
|
||||
// -10 (0xA in hex, shift 1 to left, set sign bit)
|
||||
data.append( (char)((0x0A << 1) | 0x01) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
result = Isf::Compress::decodeInt( data );
|
||||
QVERIFY( result == Q_INT64_C(-10) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// edge case, -64.
|
||||
data.append( Q_INT64_C(0x81) );
|
||||
data.append( Q_INT64_C(0x01) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
result = Isf::Compress::decodeInt( data );
|
||||
QVERIFY( result == Q_INT64_C(-64) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// a positive number, 100
|
||||
data.append( Q_INT64_C(0xC8) );
|
||||
data.append( Q_INT64_C(0x01) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
result = Isf::Compress::decodeInt( data );
|
||||
QVERIFY( result == Q_INT64_C(100) );
|
||||
|
||||
data.clear();
|
||||
|
||||
|
||||
// a decent negative number, -500
|
||||
data.append( Q_INT64_C(0xE9) );
|
||||
data.append( Q_INT64_C(0x07) );
|
||||
data.reset(); // To re-read the appended byte
|
||||
|
||||
result = Isf::Compress::decodeInt( data );
|
||||
QVERIFY( result == Q_INT64_C(-500) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::floatEncode()
|
||||
{
|
||||
QByteArray bytes;
|
||||
|
||||
bytes = Isf::Compress::encodeFloat( -12.345678901f );
|
||||
|
||||
QCOMPARE( bytes.size(), 4 );
|
||||
QCOMPARE( bytes.at(0), (char)0xE7 );
|
||||
QCOMPARE( bytes.at(1), (char)0x87 );
|
||||
QCOMPARE( bytes.at(2), (char)0x45 );
|
||||
QCOMPARE( bytes.at(3), (char)0xC1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestMultibyteCoding::floatDecode()
|
||||
{
|
||||
float result;
|
||||
Isf::Compress::DataSource data;
|
||||
|
||||
data.append( Q_INT64_C(0xE7) );
|
||||
data.append( Q_INT64_C(0x87) );
|
||||
data.append( Q_INT64_C(0x45) );
|
||||
data.append( Q_INT64_C(0xC1) );
|
||||
data.reset(); // To re-read the appended bytes
|
||||
|
||||
result = Isf::Compress::decodeFloat( data );
|
||||
QVERIFY( result == -12.345678901f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
QTEST_MAIN(TestMultibyteCoding)
|
||||
|
||||
|
||||
|
||||
#include "test_multibyte_coding.moc"
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.*/
|
||||
|
||||
#ifndef TESTMULTIBYTECODING_H
|
||||
#define TESTMULTIBYTECODING_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class TestMultibyteCoding : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testDataSource();
|
||||
|
||||
void unsignedEncode();
|
||||
void unsignedDecode();
|
||||
|
||||
void signedEncode();
|
||||
void signedDecode();
|
||||
|
||||
void floatEncode();
|
||||
void floatDecode();
|
||||
};
|
||||
|
||||
#endif // TESTMULTIBYTECODING_H
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -3,13 +3,12 @@ KDE4_INSTALL_ICONS( ${ICON_INSTALL_DIR} )
|
||||
|
||||
SET( KMESS_ICON_INSTALL_DIR ${DATA_INSTALL_DIR}/kmess/icons/hicolor/16x16 )
|
||||
|
||||
|
||||
# If we're compiling in debug mode, also add the LikeBack icons
|
||||
IF( ${KMESS_ENABLE_DEBUG_OUTPUT} EQUAL 1 )
|
||||
# If Likeback is enabled, install the needed icons
|
||||
IF( NOT ${KMESS_DISABLE_LIKEBACK} EQUAL 1 )
|
||||
INSTALL( FILES likeback_bug.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/actions )
|
||||
INSTALL( FILES likeback_dislike.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/actions )
|
||||
INSTALL( FILES likeback_feature.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/actions )
|
||||
INSTALL( FILES likeback_like.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/actions )
|
||||
ENDIF( ${KMESS_ENABLE_DEBUG_OUTPUT} EQUAL 1 )
|
||||
ENDIF( NOT ${KMESS_DISABLE_LIKEBACK} EQUAL 1 )
|
||||
|
||||
INSTALL( FILES gnomemeeting.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/apps )
|
||||
INSTALL( FILES kmess-shadow.png DESTINATION ${KMESS_ICON_INSTALL_DIR}/apps )
|
||||
|
||||
|
Before Width: | Height: | Size: 778 B |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 47 KiB |