diff --git a/3rdparty/ext_frameworks/CMakeLists.txt b/3rdparty/ext_frameworks/CMakeLists.txt
index 2de72b7378..c4307181d9 100644
--- a/3rdparty/ext_frameworks/CMakeLists.txt
+++ b/3rdparty/ext_frameworks/CMakeLists.txt
@@ -1,243 +1,243 @@
SET(EXTPREFIX_frameworks "${EXTPREFIX}" )
#
# All needed frameworks:
#
# Config
# WidgetsAddons
# Completion
# CoreAddons
# GuiAddons
# I18n
# ItemModels
# ItemViews
# WindowSystem
# kimageformats
# On Linux:
# KCrash
ExternalProject_Add(
ext_extra_cmake_modules
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/extra-cmake-modules-5.64.0.zip
URL_MD5 e8fa4bba6a534feb9d9e39db036923da
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/ecm_install_to_share.diff
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
)
ExternalProject_Add(
ext_kconfig
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kconfig-5.64.0.zip
URL_MD5 52858f7fdcd17d0c5680acf96dcaae9a
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/kconfig.diff
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
-DKCONFIG_USE_DBUS=off
UPDATE_COMMAND ""
DEPENDS ext_extra_cmake_modules
)
ExternalProject_Add(
ext_karchive
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
- URL https://download.kde.org/stable/frameworks/5.64/karchive-5.64.0.zip
+ URL https://download.kde.org/stable/frameworks/5.64/karchive-5.64.0.zip
URL_MD5 26c7f89bfde97bc85f887f81a2d0f648
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/karchive.diff
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_extra_cmake_modules
)
ExternalProject_Add(
ext_kwidgetsaddons
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kwidgetsaddons-5.64.0.zip
URL_MD5 d6578f8b5b4bf19fddb8c16918ec0117
INSTALL_DIR ${EXTPREFIX_frameworks}
# PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/kwidgetsaddons.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kconfig
)
ExternalProject_Add(
ext_kcompletion
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kcompletion-5.64.0.zip
URL_MD5 21fef280c2580da83df289707326d42a
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kwidgetsaddons
)
ExternalProject_Add(
ext_kcoreaddons
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kcoreaddons-5.64.0.zip
URL_MD5 670a74cda110da89d1a7b0fd832fca42
INSTALL_DIR ${EXTPREFIX_frameworks}
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/desktoptojson.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kcompletion
)
ExternalProject_Add(
ext_kguiaddons
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kguiaddons-5.64.0.zip
URL_MD5 565dcb39e812463100dddaf3f02bd2a0
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kcoreaddons
)
if(APPLE)
ExternalProject_Add(
ext_ki18n
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/ki18n-5.64.0.zip
URL_MD5 75a86675bf2b352b53cbcaece956b486
INSTALL_DIR ${EXTPREFIX_frameworks}
PATCH_COMMAND COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/ki18n-appdatalocation.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kguiaddons ext_gettext
)
else()
ExternalProject_Add(
ext_ki18n
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/ki18n-5.64.0.zip
URL_MD5 75a86675bf2b352b53cbcaece956b486
INSTALL_DIR ${EXTPREFIX_frameworks}
PATCH_COMMAND COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/ki18n-appdatalocation.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kguiaddons
)
endif()
ExternalProject_Add(
ext_kitemmodels
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kitemmodels-5.64.0.zip
URL_MD5 e561031cafe7af08de3c62f01fa154b2
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_ki18n
)
ExternalProject_Add(
ext_kitemviews
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kitemviews-5.64.0.zip
URL_MD5 bbd20e563e3f3cbc80252ba89d27962c
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kitemmodels
)
ExternalProject_Add(
ext_kimageformats
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kimageformats-5.64.0.zip
URL_MD5 744090cf90ddde84f51dcabd167dd607
INSTALL_DIR ${EXTPREFIX_frameworks}
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/kimageformats.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/disable_exr.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
- DEPENDS ext_kitemviews
+ DEPENDS ext_karchive ext_kitemviews
)
ExternalProject_Add(
ext_kwindowsystem
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kwindowsystem-5.64.0.zip
URL_MD5 4e2819edb9d029ff33791d691637065a
INSTALL_DIR ${EXTPREFIX_frameworks}
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/kwindowsystem-x11.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kimageformats
)
ExternalProject_Add(
ext_kcrash
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.kde.org/stable/frameworks/5.64/kcrash-5.64.0.zip
URL_MD5 2d4d9c074c2e1d19804618d3f291a568
INSTALL_DIR ${EXTPREFIX_frameworks}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_frameworks}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
-DCMAKE_SYSTEM_PREFIX_PATH=${EXTPREFIX}
-DBUILD_TESTING=false
UPDATE_COMMAND ""
DEPENDS ext_kwindowsystem
)
diff --git a/krita/krita.action b/krita/krita.action
index ae429d1c50..dac03247d6 100644
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -1,3598 +1,3578 @@
General
Open Resources Folder
Opens a file browser at the location Krita saves resources such as brushes to.
Opens a file browser at the location Krita saves resources such as brushes to.
Open Resources Folder
0
0
false
C&ascade
Cascade
Cascade
10
0
false
&Tile
Tile
Tile
10
0
false
Create Resource Bundle...
Create Resource Bundle
Create Resource Bundle
0
0
false
Show File Toolbar
Show File Toolbar
Show File Toolbar
false
Show color selector
Show color selector
Show color selector
Shift+I
false
Show MyPaint shade selector
Show MyPaint shade selector
Show MyPaint shade selector
Shift+M
false
Show minimal shade selector
Show minimal shade selector
Show minimal shade selector
Shift+N
false
Show color history
Show color history
Show color history
H
false
Show common colors
Show common colors
Show common colors
U
false
Show Tool Options
Show Tool Options
Show Tool Options
\
false
Show Brush Editor
Show Brush Editor
Show Brush Editor
F5
false
Show Brush Presets
Show Brush Presets
Show Brush Presets
F6
false
Toggle Tablet Debugger
Toggle Tablet Debugger
Toggle Tablet Debugger
0
0
Ctrl+Shift+T
false
Show Krita log for bug reports.
Show Krita log for bug reports.
Show Krita log for bug reports.
false
Show system information for bug reports.
Show system information for bug reports.
Show system information for bug reports.
false
Rename Composition...
Rename Composition
Rename Composition
0
0
false
Update Composition
Update Composition
Update Composition
0
0
false
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
1
0
true
&Invert Selection
Invert current selection
Invert Selection
10000000000
100
Ctrl+Shift+I
false
Create Snapshot
Create Snapshot
1
0
false
Switch to Selected Snapshot
Switch to selected snapshot
1
0
false
Remove Selected Snapshot
Remove Selected Snapshot
1
0
false
Painting
lightness-increase
Make brush color lighter
Make brush color lighter
Make brush color lighter
0
0
L
false
lightness-decrease
Make brush color darker
Make brush color darker
Make brush color darker
0
0
K
false
Make brush color more saturated
Make brush color more saturated
Make brush color more saturated
false
Make brush color more desaturated
Make brush color more desaturated
Make brush color more desaturated
false
Shift brush color hue clockwise
Shift brush color hue clockwise
Shift brush color hue clockwise
false
Shift brush color hue counter-clockwise
Shift brush color hue counter-clockwise
Shift brush color hue counter-clockwise
false
Make brush color more red
Make brush color more red
Make brush color more red
false
Make brush color more green
Make brush color more green
Make brush color more green
false
Make brush color more blue
Make brush color more blue
Make brush color more blue
false
Make brush color more yellow
Make brush color more yellow
Make brush color more yellow
false
opacity-increase
Increase opacity
Increase opacity
Increase opacity
0
0
O
false
opacity-decrease
Decrease opacity
Decrease opacity
Decrease opacity
0
0
I
false
draw-eraser
Set eraser mode
Set eraser mode
Set eraser mode
10000
0
E
true
view-refresh
Reload Original Preset
Reload Original Preset
Reload Original Preset
10000
false
transparency-unlocked
Preserve Alpha
Preserve Alpha
Preserve Alpha
10000
true
transform_icons_penPressure
Use Pen Pressure
Use Pen Pressure
Use Pen Pressure
10000
true
symmetry-horizontal
Horizontal Mirror Tool
Horizontal Mirror Tool
Horizontal Mirror Tool
0
true
symmetry-vertical
Vertical Mirror Tool
Vertical Mirror Tool
Vertical Mirror Tool
0
true
Hide Mirror X Line
Hide Mirror X Line
Hide Mirror X Line
10000
true
Hide Mirror Y Line
Hide Mirror Y Line
Hide Mirror Y Line
10000
true
Lock
Lock X Line
Lock X Line
10000
true
Lock Y Line
Lock Y Line
Lock Y Line
10000
true
Move to Canvas Center X
Move to Canvas Center X
Move to Canvas Center X
10000
false
Move to Canvas Center Y
Move to Canvas Center Y
Move to Canvas Center Y
10000
false
&Toggle Selection Display Mode
Toggle Selection Display Mode
Toggle Selection Display Mode
0
0
false
Next Favourite Preset
Next Favourite Preset
Next Favourite Preset
,
false
Previous Favourite Preset
Previous Favourite Preset
Previous Favourite Preset
.
false
preset-switcher
Switch to Previous Preset
Switch to Previous Preset
Switch to Previous Preset
/
false
Hide Brushes and Stuff Toolbar
Hide Brushes and Stuff Toolbar
Hide Brushes and Stuff Toolbar
true
Reset Foreground and Background Color
Reset Foreground and Background Color
Reset Foreground and Background Color
D
false
Swap Foreground and Background Color
Swap Foreground and Background Color
Swap Foreground and Background Color
X
false
Selection Mode: Add
Selection Mode: Add
Selection Mode: Add
A
false
Selection Mode: Subtract
Selection Mode: Subtract
Selection Mode: Subtract
S
false
Selection Mode: Intersect
Selection Mode: Intersect
Selection Mode: Intersect
false
Selection Mode: Replace
Selection Mode: Replace
Selection Mode: Replace
R
false
smoothing-weighted
Brush Smoothing: Weighted
Brush Smoothing: Weighted
Brush Smoothing: Weighted
false
smoothing-no
Brush Smoothing: Disabled
Brush Smoothing: Disabled
Brush Smoothing: Disabled
false
smoothing-stabilizer
Brush Smoothing: Stabilizer
Brush Smoothing: Stabilizer
Brush Smoothing: Stabilizer
false
brushsize-decrease
Decrease Brush Size
Decrease Brush Size
Decrease Brush Size
0
0
[
false
smoothing-basic
Brush Smoothing: Basic
Brush Smoothing: Basic
Brush Smoothing: Basic
false
brushsize-increase
Increase Brush Size
Increase Brush Size
Increase Brush Size
0
0
]
false
Toggle Snap To Assistants
Toggle Snap to Assistants
ToggleAssistant
Ctrl+Shift+L
true
Undo Polygon Selection Points
Undo Polygon Selection Points
Undo Polygon Selection Points
Shift+Z
false
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
10000
1
Ctrl+Shift+Backspace
false
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
10000
1
Ctrl+Backspace
false
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
10000
1
false
Convert &to Shape
Convert to Shape
Convert to Shape
10000000000
0
false
&Show Global Selection Mask
Shows global selection as a usual selection mask in <interface>Layers</interface> docker
Show Global Selection Mask
100000
100
true
Filters
color-to-alpha
&Color to Alpha...
Color to Alpha
Color to Alpha
10000
0
false
&Top Edge Detection
Top Edge Detection
Top Edge Detection
10000
0
false
&Index Colors...
Index Colors
Index Colors
10000
0
false
Emboss Horizontal &Only
Emboss Horizontal Only
Emboss Horizontal Only
10000
0
false
D&odge
Dodge
Dodge
10000
0
false
&Sharpen
Sharpen
Sharpen
10000
0
false
B&urn
Burn
Burn
10000
0
false
&Mean Removal
Mean Removal
Mean Removal
10000
0
false
&Gaussian Blur...
Gaussian Blur
Gaussian Blur
10000
0
false
Emboss &in All Directions
Emboss in All Directions
Emboss in All Directions
10000
0
false
&Small Tiles...
Small Tiles
Small Tiles
10000
0
false
&Levels...
Levels
Levels
10000
0
Ctrl+L
false
&Sobel...
Sobel
Sobel
10000
0
false
&Wave...
Wave
Wave
10000
0
false
&Motion Blur...
Motion Blur
Motion Blur
10000
0
false
&Invert
Invert
Invert
10000
0
Ctrl+I
false
&Color Adjustment curves...
Color Adjustment curves
Color Adjustment curves
10000
0
Ctrl+M
false
Pi&xelize...
Pixelize
Pixelize
10000
0
false
Emboss (&Laplacian)
Emboss (Laplacian)
Emboss (Laplacian)
10000
0
false
&Left Edge Detection
Left Edge Detection
Left Edge Detection
10000
0
false
&Blur...
Blur
Blur
10000
0
false
&Raindrops...
Raindrops
Raindrops
10000
0
false
&Bottom Edge Detection
Bottom Edge Detection
Bottom Edge Detection
10000
0
false
&Random Noise...
Random Noise
Random Noise
10000
0
false
&Brightness/Contrast curve...
Brightness/Contrast curve
Brightness/Contrast curve
10000
0
false
Colo&r Balance...
Color Balance
Color Balance
10000
0
Ctrl+B
false
&Phong Bumpmap...
Phong Bumpmap
Phong Bumpmap
10000
0
false
&Desaturate
Desaturate
Desaturate
10000
0
Ctrl+Shift+U
false
Color &Transfer...
Color Transfer
Color Transfer
10000
0
false
Emboss &Vertical Only
Emboss Vertical Only
Emboss Vertical Only
10000
0
false
&Lens Blur...
Lens Blur
Lens Blur
10000
0
false
M&inimize Channel
Minimize Channel
Minimize Channel
10000
0
false
M&aximize Channel
Maximize Channel
Maximize Channel
10000
0
false
&Oilpaint...
Oilpaint
Oilpaint
10000
0
false
&Right Edge Detection
Right Edge Detection
Right Edge Detection
10000
0
false
&Auto Contrast
Auto Contrast
Auto Contrast
10000
0
false
&Round Corners...
Round Corners
Round Corners
10000
0
false
&Unsharp Mask...
Unsharp Mask
Unsharp Mask
10000
0
false
&Emboss with Variable Depth...
Emboss with Variable Depth
Emboss with Variable Depth
10000
0
false
Emboss &Horizontal && Vertical
Emboss Horizontal & Vertical
Emboss Horizontal & Vertical
10000
0
false
Random &Pick...
Random Pick
Random Pick
10000
0
false
&Gaussian Noise Reduction...
Gaussian Noise Reduction
Gaussian Noise Reduction
10000
0
false
&Posterize...
Posterize
Posterize
10000
0
false
&Wavelet Noise Reducer...
Wavelet Noise Reducer
Wavelet Noise Reducer
10000
0
false
&HSV Adjustment...
HSV Adjustment
HSV Adjustment
10000
0
Ctrl+U
false
Tool Shortcuts
Dynamic Brush Tool
Dynamic Brush Tool
Dynamic Brush Tool
false
Rectangle Tool
Rectangle Tool
Rectangle Tool
false
Multibrush Tool
Multibrush Tool
Multibrush Tool
Q
false
Colorize Mask Tool
Colorize Mask Tool
Colorize Mask Tool
Smart Patch Tool
Smart Patch Tool
Smart Patch Tool
Pan Tool
Pan Tool
Pan Tool
Select Shapes Tool
Select Shapes Tool
Select Shapes Tool
false
Color Picker
Select a color from the image or current layer
Select a color from the image or current layer
P
false
-
-
- Outline Selection Tool
-
- Outline Selection Tool
- Outline Selection Tool
-
- false
-
-
Fill Tool
Fill a contiguous area of color with a color, or fill a selection.
Fill a contiguous area of color with a color, or fill a selection.
F
false
Line Tool
Line Tool
Line Tool
false
Ellipse Tool
Ellipse Tool
Ellipse Tool
false
Freehand Brush Tool
Freehand Brush Tool
Freehand Brush Tool
B
false
Create object
Create object
Create object
false
Pattern editing
Pattern editing
Pattern editing
false
Review
Review
Review
false
Draw a gradient.
Draw a gradient.
Draw a gradient.
G
false
Measurement Tool
Measure the distance between two points
Measure the distance between two points
false
Move Tool
Move a layer
Move a layer
T
false
Vector Image Tool
Vector Image (EMF/WMF/SVM/SVG) tool
Vector Image (EMF/WMF/SVM/SVG) tool
false
Calligraphy
Calligraphy
Calligraphy
false
Edit Shapes Tool
Edit Shapes Tool
Edit Shapes Tool
false
Zoom Tool
Zoom Tool
Zoom Tool
false
-
-
- Assistant Tool
-
- Assistant Tool
- Assistant Tool
-
- false
-
-
Gradient Editing Tool
Gradient editing
Gradient editing
false
Reference Images Tool
Reference Images Tool
Reference Images Tool
false
Blending Modes
Select Normal Blending Mode
Select Normal Blending Mode
Select Normal Blending Mode
0
0
Alt+Shift+N
false
Select Dissolve Blending Mode
Select Dissolve Blending Mode
Select Dissolve Blending Mode
0
0
Alt+Shift+I
false
Select Behind Blending Mode
Select Behind Blending Mode
Select Behind Blending Mode
0
0
Alt+Shift+Q
false
Select Clear Blending Mode
Select Clear Blending Mode
Select Clear Blending Mode
0
0
Alt+Shift+R
false
Select Darken Blending Mode
Select Darken Blending Mode
Select Darken Blending Mode
0
0
Alt+Shift+K
false
Select Multiply Blending Mode
Select Multiply Blending Mode
Select Multiply Blending Mode
0
0
Alt+Shift+M
false
Select Color Burn Blending Mode
Select Color Burn Blending Mode
Select Color Burn Blending Mode
0
0
Alt+Shift+B
false
Select Linear Burn Blending Mode
Select Linear Burn Blending Mode
Select Linear Burn Blending Mode
0
0
Alt+Shift+A
false
Select Lighten Blending Mode
Select Lighten Blending Mode
Select Lighten Blending Mode
0
0
Alt+Shift+G
false
Select Screen Blending Mode
Select Screen Blending Mode
Select Screen Blending Mode
0
0
Alt+Shift+S
false
Select Color Dodge Blending Mode
Select Color Dodge Blending Mode
Select Color Dodge Blending Mode
0
0
Alt+Shift+D
false
Select Linear Dodge Blending Mode
Select Linear Dodge Blending Mode
Select Linear Dodge Blending Mode
0
0
Alt+Shift+W
false
Select Overlay Blending Mode
Select Overlay Blending Mode
Select Overlay Blending Mode
0
0
Alt+Shift+O
false
Select Hard Overlay Blending Mode
Select Hard Overlay Blending Mode
Select Hard Overlay Blending Mode
0
0
Alt+Shift+P
false
Select Soft Light Blending Mode
Select Soft Light Blending Mode
Select Soft Light Blending Mode
0
0
Alt+Shift+F
false
Select Hard Light Blending Mode
Select Hard Light Blending Mode
Select Hard Light Blending Mode
0
0
Alt+Shift+H
false
Select Vivid Light Blending Mode
Select Vivid Light Blending Mode
Select Vivid Light Blending Mode
0
0
Alt+Shift+V
false
Select Linear Light Blending Mode
Select Linear Light Blending Mode
Select Linear Light Blending Mode
0
0
Alt+Shift+J
false
Select Pin Light Blending Mode
Select Pin Light Blending Mode
Select Pin Light Blending Mode
0
0
Alt+Shift+Z
false
Select Hard Mix Blending Mode
Select Hard Mix Blending Mode
Select Hard Mix Blending Mode
0
0
Alt+Shift+L
false
Select Difference Blending Mode
Select Difference Blending Mode
Select Difference Blending Mode
0
0
Alt+Shift+E
false
Select Exclusion Blending Mode
Select Exclusion Blending Mode
Select Exclusion Blending Mode
0
0
Alt+Shift+X
false
Select Hue Blending Mode
Select Hue Blending Mode
Select Hue Blending Mode
0
0
Alt+Shift+U
false
Select Saturation Blending Mode
Select Saturation Blending Mode
Select Saturation Blending Mode
0
0
Alt+Shift+T
false
Select Color Blending Mode
Select Color Blending Mode
Select Color Blending Mode
0
0
Alt+Shift+C
false
Select Luminosity Blending Mode
Select Luminosity Blending Mode
Select Luminosity Blending Mode
0
0
Alt+Shift+Y
false
Animation
prevframe
Previous frame
Move to previous frame
Move to previous frame
1
0
false
nextframe
Next frame
Move to next frame
Move to next frame
1
0
false
animation_play
Play / pause animation
Play / pause animation
Play / pause animation
1
0
false
animation_stop
Stop animation
Stop animation
Stop animation
1
0
false
addblankframe
Create Blank Frame
Add blank frame
Add blank frame
100000
0
false
addduplicateframe
Create Duplicate Frame
Add duplicate frame
Add duplicate frame
100000
0
false
Toggle onion skin
Toggle onion skin
Toggle onion skin
100000
0
false
Previous Keyframe
false
Next Keyframe
false
First Frame
false
Last Frame
false
Auto Frame Mode
true
dropframe
Drop Frames
Enable to preserve playback timing.
true
Pin to Timeline
If checked, layer becomes pinned to the timeline, making it visible even when inactive.
true
Insert Keyframe Left
Insert keyframes to the left of selection, moving the tail of animation to the right.
100000
0
false
Insert Keyframe Right
Insert keyframes to the right of selection, moving the tail of animation to the right.
100000
0
false
Insert Multiple Keyframes
Insert several keyframes based on user parameters.
100000
0
false
Remove Frame and Pull
Remove keyframes moving the tail of animation to the left
100000
0
false
deletekeyframe
Remove Keyframe
Remove keyframes without moving anything around
100000
0
false
Insert Column Left
Insert column to the left of selection, moving the tail of animation to the right
100000
0
false
Insert Column Right
Insert column to the right of selection, moving the tail of animation to the right
100000
0
false
Insert Multiple Columns
Insert several columns based on user parameters.
100000
0
false
Remove Column and Pull
Remove columns moving the tail of animation to the left
100000
0
false
Remove Column
Remove columns without moving anything around
100000
0
false
Insert Hold Frame
Insert a hold frame after every keyframe
100000
0
false
Insert Multiple Hold Frames
Insert N hold frames after every keyframe
100000
0
false
Remove Hold Frame
Remove a hold frame after every keyframe
100000
0
false
Remove Multiple Hold Frames
Remove N hold frames after every keyframe
100000
0
false
Insert Hold Column
Insert a hold column into the frame at the current position
100000
0
false
Insert Multiple Hold Columns
Insert N hold columns into the frame at the current position
100000
0
false
Remove Hold Column
Remove a hold column from the frame at the current position
100000
0
false
Remove Multiple Hold Columns
Remove N hold columns from the frame at the current position
100000
0
false
Add opacity keyframe
Adds keyframe to control layer opacity
100000
0
false
Remove opacity keyframe
Removes keyframe to control layer opacity
100000
0
false
Mirror Frames
Mirror frames' position
100000
0
false
Mirror Columns
Mirror columns' position
100000
0
false
Copy to Clipboard
Copy frames to clipboard
100000
0
false
Cut to Clipboard
Cut frames to clipboard
100000
0
false
Paste from Clipboard
Paste frames from clipboard
100000
0
false
Copy Columns to Clipboard
Copy columns to clipboard
100000
0
false
Cut Columns to Clipboard
Cut columns to clipboard
100000
0
false
Paste Columns from Clipboard
Paste columns from clipboard
100000
0
false
Set Start Time
100000
0
false
Set End Time
100000
0
false
Update Playback Range
100000
0
false
Layers
Activate next layer
Activate next layer
Activate next layer
1000
0
PgUp
false
Activate next sibling layer, skipping over groups.
Activate next sibling layer
Activate next sibling layer
1000
0
false
Activate previous layer
Activate previous layer
Activate previous layer
1000
0
PgDown
false
Activate previous sibling layer, skipping over groups.
Activate previous sibling layer
Activate previous sibling layer
1000
0
false
Activate previously selected layer
Activate previously selected layer
Activate previously selected layer
1000
0
;
false
groupLayer
&Group Layer
Group Layer
Group Layer
1000
0
false
cloneLayer
&Clone Layer
Clone Layer
Clone Layer
1000
0
false
vectorLayer
&Vector Layer
Vector Layer
Vector Layer
1000
0
false
filterLayer
&Filter Layer...
Filter Layer
Filter Layer
1000
0
false
fillLayer
&Fill Layer...
Fill Layer
Fill Layer
1000
0
false
fileLayer
&File Layer...
File Layer
File Layer
1000
0
false
transparencyMask
&Transparency Mask
Transparency Mask
Transparency Mask
100000
0
false
filterMask
&Filter Mask...
Filter Mask
Filter Mask
100000
0
false
filterMask
&Colorize Mask
Colorize Mask
Colorize Mask
100000
0
false
transformMask
&Transform Mask...
Transform Mask
Transform Mask
100000
0
false
selectionMask
&Local Selection
Local Selection
Local Selection
100000
0
false
view-filter
&Isolate Active Layer
Isolate Active Layer
Isolate Active Layer
1000
0
true
layer-locked
&Toggle layer lock
Toggle layer lock
Toggle layer lock
1000
0
false
visible
Toggle layer &visibility
Toggle layer visibility
Toggle layer visibility
1000
0
false
transparency-locked
Toggle layer &alpha
Toggle layer alpha
Toggle layer alpha
1000
0
false
transparency-enabled
Toggle layer alpha &inheritance
Toggle layer alpha inheritance
Toggle layer alpha inheritance
1000
0
false
paintLayer
&Paint Layer
Paint Layer
Paint Layer
1000
0
Insert
false
&New Layer From Visible
New layer from visible
New layer from visible
1000
0
false
duplicatelayer
&Duplicate Layer or Mask
Duplicate Layer or Mask
Duplicate Layer or Mask
1000
0
Ctrl+J
false
&Cut Selection to New Layer
Cut Selection to New Layer
Cut Selection to New Layer
100000000
1
Ctrl+Shift+J
false
Copy &Selection to New Layer
Copy Selection to New Layer
Copy Selection to New Layer
100000000
0
Ctrl+Alt+J
false
Copy Layer
Copy layer to clipboard
Copy layer to clipboard
1000
0
false
Cut Layer
Cut layer to clipboard
Cut layer to clipboard
1000
0
false
Paste Layer
Paste layer from clipboard
Paste layer from clipboard
1000
0
false
Quick Group
Create a group layer containing selected layers
Quick Group
1000
0
Ctrl+G
false
Quick Ungroup
Remove grouping of the layers or remove one layer out of the group
Quick Ungroup
100000
0
Ctrl+Alt+G
false
Quick Clipping Group
Group selected layers and add a layer with clipped alpha channel
Quick Clipping Group
100000
0
Ctrl+Shift+G
false
All Layers
Select all layers
Select all layers
10000
0
false
Visible Layers
Select all visible layers
Select all visible layers
10000
0
false
Locked Layers
Select all locked layers
Select all locked layers
10000
0
false
Invisible Layers
Select all invisible layers
Select all invisible layers
10000
0
false
Unlocked Layers
Select all unlocked layers
Select all unlocked layers
10000
0
false
document-save
&Save Layer/Mask...
Save Layer/Mask
Save Layer/Mask
1000
0
false
document-save
Save Vector Layer as SVG...
Save Vector Layer as SVG
Save Vector Layer as SVG
1000
0
false
document-save
Save &Group Layers...
Save Group Layers
Save Group Layers
100000
0
false
Convert group to &animated layer
Convert child layers into animation frames
Convert child layers into animation frames
100000
0
false
Convert to &animated layer
Convert layer into animation frames
Convert layer into animation frames
100000
0
false
fileLayer
to &File Layer
Saves out the layers into a new image and then references that image.
Convert to File Layer
100000
0
false
I&mport Layer...
Import Layer
Import Layer
100000
0
false
paintLayer
&as Paint Layer...
as Paint Layer
as Paint Layer
1000
0
false
transparencyMask
as &Transparency Mask...
as Transparency Mask
as Transparency Mask
1000
0
false
filterMask
as &Filter Mask...
as Filter Mask
as Filter Mask
1000
0
false
selectionMask
as &Selection Mask...
as Selection Mask
as Selection Mask
1000
0
false
paintLayer
to &Paint Layer
to Paint Layer
to Paint Layer
1000
0
false
transparencyMask
to &Transparency Mask
to Transparency Mask
to Transparency Mask
1000
0
false
filterMask
to &Filter Mask...
to Filter Mask
to Filter Mask
1000
0
false
selectionMask
to &Selection Mask
to Selection Mask
to Selection Mask
1000
0
false
transparencyMask
&Alpha into Mask
Alpha into Mask
Alpha into Mask
100000
10
false
transparency-enabled
&Write as Alpha
Write as Alpha
Write as Alpha
1000000
1
false
document-save
&Save Merged...
Save Merged
Save Merged
1000000
0
false
split-layer
Split Layer...
Split Layer
Split Layer
1000
0
false
Wavelet Decompose ...
Wavelet Decompose
Wavelet Decompose
1000
1
false
symmetry-horizontal
Mirror Layer Hori&zontally
Mirror Layer Horizontally
Mirror Layer Horizontally
1000
1
false
symmetry-vertical
Mirror Layer &Vertically
Mirror Layer Vertically
Mirror Layer Vertically
1000
1
false
&Rotate Layer...
Rotate Layer
Rotate Layer
1000
1
false
object-rotate-right
Rotate &Layer 90° to the Right
Rotate Layer 90° to the Right
Rotate Layer 90° to the Right
1000
1
false
object-rotate-left
Rotate Layer &90° to the Left
Rotate Layer 90° to the Left
Rotate Layer 90° to the Left
1000
1
false
Rotate Layer &180°
Rotate Layer 180°
Rotate Layer 180°
1000
1
false
Scale &Layer to new Size...
Scale Layer to new Size
Scale Layer to new Size
100000
1
false
&Shear Layer...
Shear Layer
Shear Layer
1000
1
false
symmetry-horizontal
Mirror All Layers Hori&zontally
Mirror All Layers Horizontally
Mirror All Layers Horizontally
1000
1
false
symmetry-vertical
Mirror All Layers &Vertically
Mirror All Layers Vertically
Mirror All Layers Vertically
1000
1
false
&Rotate All Layers...
Rotate All Layers
Rotate All Layers
1000
1
false
object-rotate-right
Rotate All &Layers 90° to the Right
Rotate All Layers 90° to the Right
Rotate All Layers 90° to the Right
1000
1
false
object-rotate-left
Rotate All Layers &90° to the Left
Rotate All Layers 90° to the Left
Rotate All Layers 90° to the Left
1000
1
false
Rotate All Layers &180°
Rotate All Layers 180°
Rotate All Layers 180°
1000
1
false
Scale All &Layers to new Size...
Scale All Layers to new Size
Scale All Layers to new Size
100000
1
false
&Shear All Layers...
Shear All Layers
Shear All Layers
1000
1
false
&Offset Layer...
Offset Layer
Offset Layer
100000
1
false
Clones &Array...
Clones Array
Clones Array
100000
0
false
&Edit metadata...
Edit metadata
Edit metadata
100000
1
false
&Histogram...
Histogram
Histogram
100000
0
false
&Convert Layer Color Space...
Convert Layer Color Space
Convert Layer Color Space
100000
1
false
merge-layer-below
&Merge with Layer Below
Merge with Layer Below
Merge with Layer Below
100000
0
Ctrl+E
false
&Flatten Layer
Flatten Layer
Flatten Layer
100000
0
false
Ras&terize Layer
Rasterize Layer
Rasterize Layer
10000000
1
false
Flatten ima&ge
Flatten image
Flatten image
100000
0
Ctrl+Shift+E
false
La&yer Style...
Layer Style
Layer Style
100000
1
false
Move into previous group
Move into previous group
Move into previous group
0
0
false
Move into next group
Move into next group
Move into next group
0
0
false
Rename current layer
Rename current layer
Rename current layer
100000
0
F2
false
deletelayer
&Remove Layer
Remove Layer
Remove Layer
1000
1
Shift+Delete
false
arrowupblr
Move Layer or Mask Up
Move Layer or Mask Up
Ctrl+PgUp
false
arrowdown
Move Layer or Mask Down
Move Layer or Mask Down
Ctrl+PgDown
false
properties
&Properties...
Properties
Properties
1000
1
F3
false
Set Copy F&rom...
Set the source for the selected clone layer(s).
Set Copy From
1000
1
false
diff --git a/libs/flake/KoSnapProxy.cpp b/libs/flake/KoSnapProxy.cpp
index bd7a3c3e3b..e48a324c35 100644
--- a/libs/flake/KoSnapProxy.cpp
+++ b/libs/flake/KoSnapProxy.cpp
@@ -1,187 +1,189 @@
/* This file is part of the KDE project
* Copyright (C) 2008-2009 Jan Hambrecht
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoSnapProxy.h"
#include "KoSnapGuide.h"
#include "KoCanvasBase.h"
#include "KoShapeManager.h"
#include "KoPathShape.h"
#include "KoPathPoint.h"
#include
+#include
KoSnapProxy::KoSnapProxy(KoSnapGuide * snapGuide)
: m_snapGuide(snapGuide)
{
}
QList KoSnapProxy::pointsInRect(const QRectF &rect, bool omitEditedShape)
{
QList points;
QList shapes = shapesInRect(rect, omitEditedShape);
Q_FOREACH (KoShape * shape, shapes) {
Q_FOREACH (const QPointF & point, pointsFromShape(shape)) {
if (rect.contains(point))
points.append(point);
}
}
return points;
}
QList KoSnapProxy::shapesInRect(const QRectF &rect, bool omitEditedShape)
{
QList shapes = m_snapGuide->canvas()->shapeManager()->shapesAt(rect);
Q_FOREACH (KoShape * shape, m_snapGuide->ignoredShapes()) {
const int index = shapes.indexOf(shape);
if (index >= 0) {
shapes.removeAt(index);
}
}
if (omitEditedShape) {
Q_FOREACH (KoPathPoint *point, m_snapGuide->ignoredPathPoints()) {
const int index = shapes.indexOf(point->parent());
if (index >= 0) {
shapes.removeAt(index);
}
}
}
if (!omitEditedShape && m_snapGuide->additionalEditedShape()) {
QRectF bound = m_snapGuide->additionalEditedShape()->boundingRect();
if (rect.intersects(bound) || rect.contains(bound))
shapes.append(m_snapGuide->additionalEditedShape());
}
return shapes;
}
QList KoSnapProxy::pointsFromShape(KoShape * shape)
{
QList snapPoints;
// no snapping to hidden shapes
if (! shape->isVisible())
return snapPoints;
// return the special snap points of the shape
snapPoints += shape->snapData().snapPoints();
KoPathShape * path = dynamic_cast(shape);
if (path) {
QTransform m = path->absoluteTransformation();
QList ignoredPoints = m_snapGuide->ignoredPathPoints();
int subpathCount = path->subpathCount();
for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
int pointCount = path->subpathPointCount(subpathIndex);
for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
KoPathPoint * p = path->pointByIndex(KoPathPointIndex(subpathIndex, pointIndex));
if (! p || ignoredPoints.contains(p))
continue;
snapPoints.append(m.map(p->point()));
}
}
}
else
{
// add the bounding box corners as default snap points
QRectF bbox = shape->boundingRect();
snapPoints.append(bbox.topLeft());
snapPoints.append(bbox.topRight());
snapPoints.append(bbox.bottomRight());
snapPoints.append(bbox.bottomLeft());
}
return snapPoints;
}
QList KoSnapProxy::segmentsInRect(const QRectF &rect, bool omitEditedShape)
{
QList shapes = shapesInRect(rect, omitEditedShape);
QList ignoredPoints = m_snapGuide->ignoredPathPoints();
QList segments;
Q_FOREACH (KoShape * shape, shapes) {
QList shapeSegments;
QRectF rectOnShape = shape->documentToShape(rect);
KoPathShape * path = dynamic_cast(shape);
if (path) {
shapeSegments = path->segmentsAt(rectOnShape);
} else {
Q_FOREACH (const KoPathSegment & s, shape->snapData().snapSegments()) {
QRectF controlRect = s.controlPointRect();
if (! rect.intersects(controlRect) && ! controlRect.contains(rect))
continue;
QRectF bound = s.boundingRect();
if (! rect.intersects(bound) && ! bound.contains(rect))
continue;
shapeSegments.append(s);
}
}
QTransform m = shape->absoluteTransformation();
// transform segments to document coordinates
Q_FOREACH (const KoPathSegment & s, shapeSegments) {
if (ignoredPoints.contains(s.first()) || ignoredPoints.contains(s.second()))
continue;
segments.append(s.mapped(m));
}
}
return segments;
}
QList KoSnapProxy::shapes(bool omitEditedShape)
{
QList allShapes = m_snapGuide->canvas()->shapeManager()->shapes();
QList filteredShapes;
QList ignoredShapes = m_snapGuide->ignoredShapes();
// filter all hidden and ignored shapes
Q_FOREACH (KoShape * shape, allShapes) {
if (shape->isVisible() &&
- !ignoredShapes.contains(shape)) {
+ !ignoredShapes.contains(shape) &&
+ !dynamic_cast(shape)) {
filteredShapes.append(shape);
}
}
if (omitEditedShape) {
Q_FOREACH (KoPathPoint *point, m_snapGuide->ignoredPathPoints()) {
const int index = filteredShapes.indexOf(point->parent());
if (index >= 0) {
filteredShapes.removeAt(index);
}
}
}
if (!omitEditedShape && m_snapGuide->additionalEditedShape()) {
filteredShapes.append(m_snapGuide->additionalEditedShape());
}
return filteredShapes;
}
KoCanvasBase * KoSnapProxy::canvas()
{
return m_snapGuide->canvas();
}
diff --git a/libs/image/KisProofingConfiguration.cpp b/libs/image/KisProofingConfiguration.cpp
index 8f4727f46d..1e49b3b205 100644
--- a/libs/image/KisProofingConfiguration.cpp
+++ b/libs/image/KisProofingConfiguration.cpp
@@ -1,36 +1,37 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisProofingConfiguration.h"
KisProofingConfiguration::KisProofingConfiguration()
: intent(KoColorConversionTransformation::IntentAbsoluteColorimetric),
conversionFlags(KoColorConversionTransformation::BlackpointCompensation),
warningColor(KoColor()),
proofingProfile("Chemical proof"),
proofingModel("CMYKA"),
proofingDepth("U8"),
- adaptationState(1.0)
+ adaptationState(1.0),
+ storeSoftproofingInsideImage(false)
{
}
KisProofingConfiguration::~KisProofingConfiguration()
{
}
diff --git a/libs/image/KisProofingConfiguration.h b/libs/image/KisProofingConfiguration.h
index b2f9ce89a9..59e518eea7 100644
--- a/libs/image/KisProofingConfiguration.h
+++ b/libs/image/KisProofingConfiguration.h
@@ -1,30 +1,31 @@
#ifndef KISPROOFINGCONFIGURATION_H
#define KISPROOFINGCONFIGURATION_H
#include "KoColor.h"
#include "KoColorSpace.h"
#include "KoColorConversionTransformation.h"
#include "kritaimage_export.h"
/**
* @brief The KisProofingConfiguration struct
* Little struct that stores the proofing configuration for a given file.
* The actual softproofing and gamutcheck toggles are set in the canvas.
* intet, conversionflags and warning color have default set to them. This
* wasn't possible for profileSpace.
*/
class KRITAIMAGE_EXPORT KisProofingConfiguration {
public:
KisProofingConfiguration();
~KisProofingConfiguration();
KoColorConversionTransformation::Intent intent;
KoColorConversionTransformation::ConversionFlags conversionFlags;
KoColor warningColor;
QString proofingProfile;
QString proofingModel;
QString proofingDepth;
double adaptationState;
+ bool storeSoftproofingInsideImage;
};
#endif // KISPROOFINGCONFIGURATION_H
diff --git a/libs/image/floodfill/kis_scanline_fill.cpp b/libs/image/floodfill/kis_scanline_fill.cpp
index af38c0f2c4..a65204ccca 100644
--- a/libs/image/floodfill/kis_scanline_fill.cpp
+++ b/libs/image/floodfill/kis_scanline_fill.cpp
@@ -1,726 +1,726 @@
/*
* Copyright (c) 2014 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_scanline_fill.h"
#include
#include
#include
#include
#include
#include "kis_image.h"
#include "kis_fill_interval_map.h"
#include "kis_pixel_selection.h"
#include "kis_random_accessor_ng.h"
#include "kis_fill_sanity_checks.h"
template
class CopyToSelection : public BaseClass
{
public:
typedef KisRandomConstAccessorSP SourceAccessorType;
SourceAccessorType createSourceDeviceAccessor(KisPaintDeviceSP device) {
return device->createRandomConstAccessorNG();
}
public:
void setDestinationSelection(KisPaintDeviceSP pixelSelection) {
m_pixelSelection = pixelSelection;
m_it = m_pixelSelection->createRandomAccessorNG();
}
ALWAYS_INLINE void fillPixel(quint8 *dstPtr, quint8 opacity, int x, int y) {
Q_UNUSED(dstPtr);
m_it->moveTo(x, y);
*m_it->rawData() = opacity;
}
private:
KisPaintDeviceSP m_pixelSelection;
KisRandomAccessorSP m_it;
};
template
class FillWithColor : public BaseClass
{
public:
typedef KisRandomAccessorSP SourceAccessorType;
SourceAccessorType createSourceDeviceAccessor(KisPaintDeviceSP device) {
return device->createRandomAccessorNG();
}
public:
FillWithColor() : m_pixelSize(0) {}
void setFillColor(const KoColor &sourceColor) {
m_sourceColor = sourceColor;
m_pixelSize = sourceColor.colorSpace()->pixelSize();
m_data = m_sourceColor.data();
}
ALWAYS_INLINE void fillPixel(quint8 *dstPtr, quint8 opacity, int x, int y) {
Q_UNUSED(x);
Q_UNUSED(y);
if (opacity == MAX_SELECTED) {
memcpy(dstPtr, m_data, m_pixelSize);
}
}
private:
KoColor m_sourceColor;
const quint8 *m_data;
int m_pixelSize;
};
template
class FillWithColorExternal : public BaseClass
{
public:
typedef KisRandomConstAccessorSP SourceAccessorType;
SourceAccessorType createSourceDeviceAccessor(KisPaintDeviceSP device) {
return device->createRandomConstAccessorNG();
}
public:
void setDestinationDevice(KisPaintDeviceSP device) {
m_externalDevice = device;
m_it = m_externalDevice->createRandomAccessorNG();
}
void setFillColor(const KoColor &sourceColor) {
m_sourceColor = sourceColor;
m_pixelSize = sourceColor.colorSpace()->pixelSize();
m_data = m_sourceColor.data();
}
ALWAYS_INLINE void fillPixel(quint8 *dstPtr, quint8 opacity, int x, int y) {
Q_UNUSED(dstPtr);
m_it->moveTo(x, y);
if (opacity == MAX_SELECTED) {
memcpy(m_it->rawData(), m_data, m_pixelSize);
}
}
private:
KisPaintDeviceSP m_externalDevice;
KisRandomAccessorSP m_it;
KoColor m_sourceColor;
const quint8 *m_data {0};
int m_pixelSize {0};
};
class DifferencePolicySlow
{
public:
ALWAYS_INLINE void initDifferences(KisPaintDeviceSP device, const KoColor &srcPixel, int threshold) {
m_colorSpace = device->colorSpace();
m_srcPixel = srcPixel;
m_srcPixelPtr = m_srcPixel.data();
m_threshold = threshold;
}
ALWAYS_INLINE quint8 calculateDifference(quint8* pixelPtr) {
if (m_threshold == 1) {
if (memcmp(m_srcPixelPtr, pixelPtr, m_colorSpace->pixelSize()) == 0) {
return 0;
}
return quint8_MAX;
}
else {
- return m_colorSpace->difference(m_srcPixelPtr, pixelPtr);
+ return m_colorSpace->differenceA(m_srcPixelPtr, pixelPtr);
}
}
private:
const KoColorSpace *m_colorSpace;
KoColor m_srcPixel;
const quint8 *m_srcPixelPtr;
int m_threshold;
};
template
class DifferencePolicyOptimized
{
typedef SrcPixelType HashKeyType;
typedef QHash HashType;
public:
ALWAYS_INLINE void initDifferences(KisPaintDeviceSP device, const KoColor &srcPixel, int threshold) {
m_colorSpace = device->colorSpace();
m_srcPixel = srcPixel;
m_srcPixelPtr = m_srcPixel.data();
m_threshold = threshold;
}
ALWAYS_INLINE quint8 calculateDifference(quint8* pixelPtr) {
HashKeyType key = *reinterpret_cast(pixelPtr);
quint8 result;
typename HashType::iterator it = m_differences.find(key);
if (it != m_differences.end()) {
result = *it;
} else {
if (m_threshold == 1) {
if (memcmp(m_srcPixelPtr, pixelPtr, m_colorSpace->pixelSize()) == 0) {
result = 0;
}
else {
result = quint8_MAX;
}
}
else {
- result = m_colorSpace->difference(m_srcPixelPtr, pixelPtr);
+ result = m_colorSpace->differenceA(m_srcPixelPtr, pixelPtr);
}
m_differences.insert(key, result);
}
return result;
}
private:
HashType m_differences;
const KoColorSpace *m_colorSpace;
KoColor m_srcPixel;
const quint8 *m_srcPixelPtr;
int m_threshold;
};
template class PixelFiller>
class SelectionPolicy : public PixelFiller
{
public:
typename PixelFiller::SourceAccessorType m_srcIt;
public:
SelectionPolicy(KisPaintDeviceSP device, const KoColor &srcPixel, int threshold)
: m_threshold(threshold)
{
this->initDifferences(device, srcPixel, threshold);
m_srcIt = this->createSourceDeviceAccessor(device);
}
ALWAYS_INLINE quint8 calculateOpacity(quint8* pixelPtr) {
quint8 diff = this->calculateDifference(pixelPtr);
if (!useSmoothSelection) {
return diff <= m_threshold ? MAX_SELECTED : MIN_SELECTED;
} else {
quint8 selectionValue = qMax(0, m_threshold - diff);
quint8 result = MIN_SELECTED;
if (selectionValue > 0) {
qreal selectionNorm = qreal(selectionValue) / m_threshold;
result = MAX_SELECTED * selectionNorm;
}
return result;
}
}
private:
int m_threshold;
};
class IsNonNullPolicySlow
{
public:
ALWAYS_INLINE void initDifferences(KisPaintDeviceSP device, const KoColor &srcPixel, int /*threshold*/)
{
Q_UNUSED(srcPixel);
m_pixelSize = device->pixelSize();
m_testPixel.resize(m_pixelSize);
}
ALWAYS_INLINE quint8 calculateDifference(quint8* pixelPtr) {
if (memcmp(m_testPixel.data(), pixelPtr, m_pixelSize) == 0) {
return 0;
}
return quint8_MAX;
}
private:
int m_pixelSize {0};
QByteArray m_testPixel;
};
template
class IsNonNullPolicyOptimized
{
public:
ALWAYS_INLINE void initDifferences(KisPaintDeviceSP device, const KoColor &srcPixel, int /*threshold*/) {
Q_UNUSED(device);
Q_UNUSED(srcPixel);
}
ALWAYS_INLINE quint8 calculateDifference(quint8* pixelPtr) {
SrcPixelType *pixel = reinterpret_cast(pixelPtr);
return *pixel == 0;
}
};
class GroupSplitPolicy
{
public:
typedef KisRandomConstAccessorSP SourceAccessorType;
SourceAccessorType m_srcIt;
public:
GroupSplitPolicy(KisPaintDeviceSP scribbleDevice,
KisPaintDeviceSP groupMapDevice,
qint32 groupIndex,
quint8 referenceValue, int threshold)
: m_threshold(threshold),
m_groupIndex(groupIndex),
m_referenceValue(referenceValue)
{
KIS_SAFE_ASSERT_RECOVER_NOOP(m_groupIndex > 0);
m_srcIt = scribbleDevice->createRandomConstAccessorNG();
m_groupMapIt = groupMapDevice->createRandomAccessorNG();
}
ALWAYS_INLINE quint8 calculateOpacity(quint8* pixelPtr) {
// TODO: either threshold should always be null, or there should be a special
// case for *pixelPtr == 0, which is different from all the other groups,
// whatever the threshold is
int diff = qAbs(int(*pixelPtr) - m_referenceValue);
return diff <= m_threshold ? MAX_SELECTED : MIN_SELECTED;
}
ALWAYS_INLINE void fillPixel(quint8 *dstPtr, quint8 opacity, int x, int y) {
Q_UNUSED(opacity);
// erase the scribble
*dstPtr = 0;
// write group index into the map
m_groupMapIt->moveTo(x, y);
qint32 *groupMapPtr = reinterpret_cast(m_groupMapIt->rawData());
if (*groupMapPtr != 0) {
dbgImage << ppVar(*groupMapPtr) << ppVar(m_groupIndex);
}
KIS_SAFE_ASSERT_RECOVER_NOOP(*groupMapPtr == 0);
*groupMapPtr = m_groupIndex;
}
private:
int m_threshold;
qint32 m_groupIndex;
quint8 m_referenceValue;
KisRandomAccessorSP m_groupMapIt;
};
struct Q_DECL_HIDDEN KisScanlineFill::Private
{
KisPaintDeviceSP device;
QPoint startPoint;
QRect boundingRect;
int threshold;
int rowIncrement;
KisFillIntervalMap backwardMap;
QStack forwardStack;
inline void swapDirection() {
rowIncrement *= -1;
KIS_SAFE_ASSERT_RECOVER_NOOP(forwardStack.isEmpty() &&
"FATAL: the forward stack must be empty "
"on a direction swap");
forwardStack = QStack(backwardMap.fetchAllIntervals(rowIncrement));
backwardMap.clear();
}
};
KisScanlineFill::KisScanlineFill(KisPaintDeviceSP device, const QPoint &startPoint, const QRect &boundingRect)
: m_d(new Private)
{
m_d->device = device;
m_d->startPoint = startPoint;
m_d->boundingRect = boundingRect;
m_d->rowIncrement = 1;
m_d->threshold = 0;
}
KisScanlineFill::~KisScanlineFill()
{
}
void KisScanlineFill::setThreshold(int threshold)
{
m_d->threshold = threshold;
}
template
void KisScanlineFill::extendedPass(KisFillInterval *currentInterval, int srcRow, bool extendRight, T &pixelPolicy)
{
int x;
int endX;
int columnIncrement;
int *intervalBorder;
int *backwardIntervalBorder;
KisFillInterval backwardInterval(currentInterval->start, currentInterval->end, srcRow);
if (extendRight) {
x = currentInterval->end;
endX = m_d->boundingRect.right();
if (x >= endX) return;
columnIncrement = 1;
intervalBorder = ¤tInterval->end;
backwardInterval.start = currentInterval->end + 1;
backwardIntervalBorder = &backwardInterval.end;
} else {
x = currentInterval->start;
endX = m_d->boundingRect.left();
if (x <= endX) return;
columnIncrement = -1;
intervalBorder = ¤tInterval->start;
backwardInterval.end = currentInterval->start - 1;
backwardIntervalBorder = &backwardInterval.start;
}
do {
x += columnIncrement;
pixelPolicy.m_srcIt->moveTo(x, srcRow);
quint8 *pixelPtr = const_cast(pixelPolicy.m_srcIt->rawDataConst()); // TODO: avoid doing const_cast
quint8 opacity = pixelPolicy.calculateOpacity(pixelPtr);
if (opacity) {
*intervalBorder = x;
*backwardIntervalBorder = x;
pixelPolicy.fillPixel(pixelPtr, opacity, x, srcRow);
} else {
break;
}
} while (x != endX);
if (backwardInterval.isValid()) {
m_d->backwardMap.insertInterval(backwardInterval);
}
}
template
void KisScanlineFill::processLine(KisFillInterval interval, const int rowIncrement, T &pixelPolicy)
{
m_d->backwardMap.cropInterval(&interval);
if (!interval.isValid()) return;
int firstX = interval.start;
int lastX = interval.end;
int x = firstX;
int row = interval.row;
int nextRow = row + rowIncrement;
KisFillInterval currentForwardInterval;
int numPixelsLeft = 0;
quint8 *dataPtr = 0;
const int pixelSize = m_d->device->pixelSize();
while(x <= lastX) {
// a bit of optimzation for not calling slow random accessor
// methods too often
if (numPixelsLeft <= 0) {
pixelPolicy.m_srcIt->moveTo(x, row);
numPixelsLeft = pixelPolicy.m_srcIt->numContiguousColumns(x) - 1;
dataPtr = const_cast(pixelPolicy.m_srcIt->rawDataConst());
} else {
numPixelsLeft--;
dataPtr += pixelSize;
}
quint8 *pixelPtr = dataPtr;
quint8 opacity = pixelPolicy.calculateOpacity(pixelPtr);
if (opacity) {
if (!currentForwardInterval.isValid()) {
currentForwardInterval.start = x;
currentForwardInterval.end = x;
currentForwardInterval.row = nextRow;
} else {
currentForwardInterval.end = x;
}
pixelPolicy.fillPixel(pixelPtr, opacity, x, row);
if (x == firstX) {
extendedPass(¤tForwardInterval, row, false, pixelPolicy);
}
if (x == lastX) {
extendedPass(¤tForwardInterval, row, true, pixelPolicy);
}
} else {
if (currentForwardInterval.isValid()) {
m_d->forwardStack.push(currentForwardInterval);
currentForwardInterval.invalidate();
}
}
x++;
}
if (currentForwardInterval.isValid()) {
m_d->forwardStack.push(currentForwardInterval);
}
}
template
void KisScanlineFill::runImpl(T &pixelPolicy)
{
KIS_ASSERT_RECOVER_RETURN(m_d->forwardStack.isEmpty());
KisFillInterval startInterval(m_d->startPoint.x(), m_d->startPoint.x(), m_d->startPoint.y());
m_d->forwardStack.push(startInterval);
/**
* In the end of the first pass we should add an interval
* containing the starting pixel, but directed into the opposite
* direction. We cannot do it in the very beginning because the
* intervals are offset by 1 pixel during every swap operation.
*/
bool firstPass = true;
while (!m_d->forwardStack.isEmpty()) {
while (!m_d->forwardStack.isEmpty()) {
KisFillInterval interval = m_d->forwardStack.pop();
if (interval.row > m_d->boundingRect.bottom() ||
interval.row < m_d->boundingRect.top()) {
continue;
}
processLine(interval, m_d->rowIncrement, pixelPolicy);
}
m_d->swapDirection();
if (firstPass) {
startInterval.row--;
m_d->forwardStack.push(startInterval);
firstPass = false;
}
}
}
void KisScanlineFill::fillColor(const KoColor &originalFillColor)
{
KoColor srcColor(m_d->device->pixel(m_d->startPoint));
KoColor fillColor(originalFillColor);
fillColor.convertTo(m_d->device->colorSpace());
const int pixelSize = m_d->device->pixelSize();
if (pixelSize == 1) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 2) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 4) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 8) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
runImpl(policy);
} else {
SelectionPolicy
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
runImpl(policy);
}
}
void KisScanlineFill::fillColor(const KoColor &originalFillColor, KisPaintDeviceSP externalDevice)
{
KoColor srcColor(m_d->device->pixel(m_d->startPoint));
KoColor fillColor(originalFillColor);
fillColor.convertTo(m_d->device->colorSpace());
const int pixelSize = m_d->device->pixelSize();
if (pixelSize == 1) {
SelectionPolicy, FillWithColorExternal>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationDevice(externalDevice);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 2) {
SelectionPolicy, FillWithColorExternal>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationDevice(externalDevice);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 4) {
SelectionPolicy, FillWithColorExternal>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationDevice(externalDevice);
policy.setFillColor(fillColor);
runImpl(policy);
} else if (pixelSize == 8) {
SelectionPolicy, FillWithColorExternal>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationDevice(externalDevice);
policy.setFillColor(fillColor);
runImpl(policy);
} else {
SelectionPolicy
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationDevice(externalDevice);
policy.setFillColor(fillColor);
runImpl(policy);
}
}
void KisScanlineFill::fillSelection(KisPixelSelectionSP pixelSelection)
{
KoColor srcColor(m_d->device->pixel(m_d->startPoint));
const int pixelSize = m_d->device->pixelSize();
if (pixelSize == 1) {
SelectionPolicy, CopyToSelection>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationSelection(pixelSelection);
runImpl(policy);
} else if (pixelSize == 2) {
SelectionPolicy, CopyToSelection>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationSelection(pixelSelection);
runImpl(policy);
} else if (pixelSize == 4) {
SelectionPolicy, CopyToSelection>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationSelection(pixelSelection);
runImpl(policy);
} else if (pixelSize == 8) {
SelectionPolicy, CopyToSelection>
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationSelection(pixelSelection);
runImpl(policy);
} else {
SelectionPolicy
policy(m_d->device, srcColor, m_d->threshold);
policy.setDestinationSelection(pixelSelection);
runImpl(policy);
}
}
void KisScanlineFill::clearNonZeroComponent()
{
const int pixelSize = m_d->device->pixelSize();
KoColor srcColor(Qt::transparent, m_d->device->colorSpace());
if (pixelSize == 1) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(srcColor);
runImpl(policy);
} else if (pixelSize == 2) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(srcColor);
runImpl(policy);
} else if (pixelSize == 4) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(srcColor);
runImpl(policy);
} else if (pixelSize == 8) {
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(srcColor);
runImpl(policy);
} else {
SelectionPolicy
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(srcColor);
runImpl(policy);
}
}
void KisScanlineFill::fillContiguousGroup(KisPaintDeviceSP groupMapDevice, qint32 groupIndex)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->device->pixelSize() == 1);
KIS_SAFE_ASSERT_RECOVER_RETURN(groupMapDevice->pixelSize() == 4);
const quint8 referenceValue = *m_d->device->pixel(m_d->startPoint).data();
GroupSplitPolicy policy(m_d->device, groupMapDevice, groupIndex, referenceValue, m_d->threshold);
runImpl(policy);
}
void KisScanlineFill::testingProcessLine(const KisFillInterval &processInterval)
{
KoColor srcColor(QColor(0,0,0,0), m_d->device->colorSpace());
KoColor fillColor(QColor(200,200,200,200), m_d->device->colorSpace());
SelectionPolicy, FillWithColor>
policy(m_d->device, srcColor, m_d->threshold);
policy.setFillColor(fillColor);
processLine(processInterval, 1, policy);
}
QVector KisScanlineFill::testingGetForwardIntervals() const
{
return QVector(m_d->forwardStack);
}
KisFillIntervalMap* KisScanlineFill::testingGetBackwardIntervals() const
{
return &m_d->backwardMap;
}
diff --git a/libs/image/kis_asl_layer_style_serializer.cpp b/libs/image/kis_asl_layer_style_serializer.cpp
index 1abcf70d98..5710dd5c22 100644
--- a/libs/image/kis_asl_layer_style_serializer.cpp
+++ b/libs/image/kis_asl_layer_style_serializer.cpp
@@ -1,1272 +1,1272 @@
/*
* Copyright (c) 2015 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_asl_layer_style_serializer.h"
#include
#include
#include
#include
#include
#include
#include "kis_dom_utils.h"
#include "psd.h"
#include "kis_global.h"
#include "asl/kis_asl_reader.h"
#include "asl/kis_asl_xml_parser.h"
#include "asl/kis_asl_writer_utils.h"
#include "asl/kis_asl_xml_writer.h"
#include "asl/kis_asl_writer.h"
#include
using namespace std::placeholders;
KisAslLayerStyleSerializer::KisAslLayerStyleSerializer()
{
}
KisAslLayerStyleSerializer::~KisAslLayerStyleSerializer()
{
}
QVector KisAslLayerStyleSerializer::styles() const
{
return m_stylesVector;
}
void KisAslLayerStyleSerializer::setStyles(const QVector &styles)
{
m_stylesVector = styles;
Q_FOREACH(const KisPSDLayerStyleSP style, styles) {
m_stylesHash.insert(style->psdUuid(), style);
}
m_initialized = true;
}
QHash KisAslLayerStyleSerializer::patterns() const
{
return m_patternsStore;
}
QHash KisAslLayerStyleSerializer::stylesHash()
{
if (m_stylesHash.count() == 0 && m_stylesVector.count() != 0) {
// build the hash
Q_FOREACH(KisPSDLayerStyleSP style, m_stylesVector) {
m_stylesHash.insert(style->psdUuid(), style);
}
}
return m_stylesHash;
}
QString compositeOpToBlendMode(const QString &compositeOp)
{
QString mode = "Nrml";
if (compositeOp == COMPOSITE_OVER) {
mode = "Nrml";
} else if (compositeOp == COMPOSITE_DISSOLVE) {
mode = "Dslv";
} else if (compositeOp == COMPOSITE_DARKEN) {
mode = "Drkn";
} else if (compositeOp == COMPOSITE_MULT) {
mode = "Mltp";
} else if (compositeOp == COMPOSITE_BURN) {
mode = "CBrn";
} else if (compositeOp == COMPOSITE_LINEAR_BURN) {
mode = "linearBurn";
} else if (compositeOp == COMPOSITE_DARKER_COLOR) {
mode = "darkerColor";
} else if (compositeOp == COMPOSITE_LIGHTEN) {
mode = "Lghn";
} else if (compositeOp == COMPOSITE_SCREEN) {
mode = "Scrn";
} else if (compositeOp == COMPOSITE_DODGE) {
mode = "CDdg";
} else if (compositeOp == COMPOSITE_LINEAR_DODGE) {
mode = "linearDodge";
} else if (compositeOp == COMPOSITE_LIGHTER_COLOR) {
mode = "lighterColor";
} else if (compositeOp == COMPOSITE_OVERLAY) {
mode = "Ovrl";
} else if (compositeOp == COMPOSITE_SOFT_LIGHT_PHOTOSHOP) {
mode = "SftL";
} else if (compositeOp == COMPOSITE_HARD_LIGHT) {
mode = "HrdL";
} else if (compositeOp == COMPOSITE_VIVID_LIGHT) {
mode = "vividLight";
} else if (compositeOp == COMPOSITE_LINEAR_LIGHT) {
mode = "linearLight";
} else if (compositeOp == COMPOSITE_PIN_LIGHT) {
mode = "pinLight";
} else if (compositeOp == COMPOSITE_HARD_MIX_PHOTOSHOP) {
mode = "hardMix";
} else if (compositeOp == COMPOSITE_DIFF) {
mode = "Dfrn";
} else if (compositeOp == COMPOSITE_EXCLUSION) {
mode = "Xclu";
} else if (compositeOp == COMPOSITE_SUBTRACT) {
mode = "Sbtr";
} else if (compositeOp == COMPOSITE_DIVIDE) {
mode = "divide";
} else if (compositeOp == COMPOSITE_HUE) {
mode = "H ";
} else if (compositeOp == COMPOSITE_SATURATION) {
mode = "Strt";
} else if (compositeOp == COMPOSITE_COLOR) {
mode = "Clr ";
} else if (compositeOp == COMPOSITE_LUMINIZE) {
mode = "Lmns";
} else {
dbgKrita << "Unknown composite op:" << mode << "Returning \"Nrml\"!";
}
return mode;
}
QString techniqueToString(psd_technique_type technique, const QString &typeId)
{
QString result = "SfBL";
switch (technique) {
case psd_technique_softer:
result = "SfBL";
break;
case psd_technique_precise:
result = "PrBL";
break;
case psd_technique_slope_limit:
result = "Slmt";
break;
}
if (typeId == "BETE" && technique == psd_technique_slope_limit) {
warnKrita << "WARNING: techniqueToString: invalid technique type!" << ppVar(technique) << ppVar(typeId);
}
return result;
}
QString bevelStyleToString(psd_bevel_style style)
{
QString result = "OtrB";
switch (style) {
case psd_bevel_outer_bevel:
result = "OtrB";
break;
case psd_bevel_inner_bevel:
result = "InrB";
break;
case psd_bevel_emboss:
result = "Embs";
break;
case psd_bevel_pillow_emboss:
result = "PlEb";
break;
case psd_bevel_stroke_emboss:
result = "strokeEmboss";
break;
}
return result;
}
QString gradientTypeToString(psd_gradient_style style)
{
QString result = "Lnr ";
switch (style) {
case psd_gradient_style_linear:
result = "Lnr ";
break;
case psd_gradient_style_radial:
result = "Rdl ";
break;
case psd_gradient_style_angle:
result = "Angl";
break;
case psd_gradient_style_reflected:
result = "Rflc";
break;
case psd_gradient_style_diamond:
result = "Dmnd";
break;
}
return result;
}
QString strokePositionToString(psd_stroke_position position)
{
QString result = "OutF";
switch (position) {
case psd_stroke_outside:
result = "OutF";
break;
case psd_stroke_inside:
result = "InsF";
break;
case psd_stroke_center:
result = "CtrF";
break;
}
return result;
}
QString strokeFillTypeToString(psd_fill_type position)
{
QString result = "SClr";
switch (position) {
case psd_fill_solid_color:
result = "SClr";
break;
case psd_fill_gradient:
result = "GrFl";
break;
case psd_fill_pattern:
result = "Ptrn";
break;
}
return result;
}
QVector KisAslLayerStyleSerializer::fetchAllPatterns(KisPSDLayerStyle *style) const
{
QVector allPatterns;
if (style->patternOverlay()->effectEnabled()) {
allPatterns << style->patternOverlay()->pattern();
}
if (style->stroke()->effectEnabled() &&
style->stroke()->fillType() == psd_fill_pattern) {
allPatterns << style->stroke()->pattern();
}
if(style->bevelAndEmboss()->effectEnabled() &&
style->bevelAndEmboss()->textureEnabled()) {
allPatterns << style->bevelAndEmboss()->texturePattern();
}
return allPatterns;
}
QString fetchPatternUuidSafe(KoPatternSP pattern, QHash patternToUuid)
{
if (patternToUuid.contains(pattern)) {
return patternToUuid[pattern];
} else {
warnKrita << "WARNING: the pattern is not present in the Uuid map!";
return "invalid-uuid";
}
}
QDomDocument KisAslLayerStyleSerializer::formXmlDocument() const
{
KIS_ASSERT_RECOVER(!m_stylesVector.isEmpty()) { return QDomDocument(); }
QVector allPatterns;
Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
allPatterns += fetchAllPatterns(style.data());
}
QHash patternToUuidMap;
KisAslXmlWriter w;
if (!allPatterns.isEmpty()) {
w.enterList(ResourceType::Patterns);
Q_FOREACH (KoPatternSP pattern, allPatterns) {
if (pattern) {
if (!patternToUuidMap.contains(pattern)) {
QString uuid = w.writePattern("", pattern);
patternToUuidMap.insert(pattern, uuid);
}
} else {
warnKrita << "WARNING: KisAslLayerStyleSerializer::saveToDevice: saved pattern is null!";
}
}
w.leaveList();
}
Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
w.enterDescriptor("", "", "null");
w.writeText("Nm ", style->name());
w.writeText("Idnt", style->psdUuid());
w.leaveDescriptor();
w.enterDescriptor("", "", "Styl");
w.enterDescriptor("documentMode", "", "documentMode");
w.leaveDescriptor();
w.enterDescriptor("Lefx", "", "Lefx");
w.writeUnitFloat("Scl ", "#Prc", 100);
w.writeBoolean("masterFXSwitch", style->isEnabled());
// Drop Shadow
const psd_layer_effects_drop_shadow *dropShadow = style->dropShadow();
if (dropShadow->effectEnabled()) {
w.enterDescriptor("DrSh", "", "DrSh");
w.writeBoolean("enab", dropShadow->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(dropShadow->blendMode()));
w.writeColor("Clr ", dropShadow->color());
w.writeUnitFloat("Opct", "#Prc", dropShadow->opacity());
w.writeBoolean("uglg", dropShadow->useGlobalLight());
w.writeUnitFloat("lagl", "#Ang", dropShadow->angle());
w.writeUnitFloat("Dstn", "#Pxl", dropShadow->distance());
w.writeUnitFloat("Ckmt", "#Pxl", dropShadow->spread());
w.writeUnitFloat("blur", "#Pxl", dropShadow->size());
w.writeUnitFloat("Nose", "#Prc", dropShadow->noise());
w.writeBoolean("AntA", dropShadow->antiAliased());
// FIXME: save curves
w.writeCurve("TrnS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.writeBoolean("layerConceals", dropShadow->knocksOut());
w.leaveDescriptor();
}
// Inner Shadow
const psd_layer_effects_inner_shadow *innerShadow = style->innerShadow();
if (innerShadow->effectEnabled()) {
w.enterDescriptor("IrSh", "", "IrSh");
w.writeBoolean("enab", innerShadow->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(innerShadow->blendMode()));
w.writeColor("Clr ", innerShadow->color());
w.writeUnitFloat("Opct", "#Prc", innerShadow->opacity());
w.writeBoolean("uglg", innerShadow->useGlobalLight());
w.writeUnitFloat("lagl", "#Ang", innerShadow->angle());
w.writeUnitFloat("Dstn", "#Pxl", innerShadow->distance());
w.writeUnitFloat("Ckmt", "#Pxl", innerShadow->spread());
w.writeUnitFloat("blur", "#Pxl", innerShadow->size());
w.writeUnitFloat("Nose", "#Prc", innerShadow->noise());
w.writeBoolean("AntA", innerShadow->antiAliased());
// FIXME: save curves
w.writeCurve("TrnS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.leaveDescriptor();
}
// Outer Glow
const psd_layer_effects_outer_glow *outerGlow = style->outerGlow();
if (outerGlow->effectEnabled()) {
w.enterDescriptor("OrGl", "", "OrGl");
w.writeBoolean("enab", outerGlow->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(outerGlow->blendMode()));
if (outerGlow->fillType() == psd_fill_gradient && outerGlow->gradient()) {
KoSegmentGradient *segmentGradient = dynamic_cast(outerGlow->gradient().data());
KoStopGradient *stopGradient = dynamic_cast(outerGlow->gradient().data());
if (segmentGradient && segmentGradient->valid()) {
w.writeSegmentGradient("Grad", segmentGradient);
} else if (stopGradient && stopGradient->valid()) {
w.writeStopGradient("Grad", stopGradient);
} else {
warnKrita << "WARNING: OG: Unknown gradient type!";
w.writeColor("Clr ", outerGlow->color());
}
} else {
w.writeColor("Clr ", outerGlow->color());
}
w.writeUnitFloat("Opct", "#Prc", outerGlow->opacity());
w.writeEnum("GlwT", "BETE", techniqueToString(outerGlow->technique(), "BETE"));
w.writeUnitFloat("Ckmt", "#Pxl", outerGlow->spread());
w.writeUnitFloat("blur", "#Pxl", outerGlow->size());
w.writeUnitFloat("Nose", "#Prc", outerGlow->noise());
w.writeUnitFloat("ShdN", "#Prc", outerGlow->jitter());
w.writeBoolean("AntA", outerGlow->antiAliased());
// FIXME: save curves
w.writeCurve("TrnS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.writeUnitFloat("Inpr", "#Prc", outerGlow->range());
w.leaveDescriptor();
}
// Inner Glow
const psd_layer_effects_inner_glow *innerGlow = style->innerGlow();
if (innerGlow->effectEnabled()) {
w.enterDescriptor("IrGl", "", "IrGl");
w.writeBoolean("enab", innerGlow->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(innerGlow->blendMode()));
if (innerGlow->fillType() == psd_fill_gradient && innerGlow->gradient()) {
KoSegmentGradient *segmentGradient = dynamic_cast(innerGlow->gradient().data());
KoStopGradient *stopGradient = dynamic_cast(innerGlow->gradient().data());
if (segmentGradient && innerGlow->gradient()->valid()) {
w.writeSegmentGradient("Grad", segmentGradient);
} else if (stopGradient && innerGlow->gradient()->valid()) {
w.writeStopGradient("Grad", stopGradient);
} else {
warnKrita << "WARNING: IG: Unknown gradient type!";
w.writeColor("Clr ", innerGlow->color());
}
} else {
w.writeColor("Clr ", innerGlow->color());
}
w.writeUnitFloat("Opct", "#Prc", innerGlow->opacity());
w.writeEnum("GlwT", "BETE", techniqueToString(innerGlow->technique(), "BETE"));
w.writeUnitFloat("Ckmt", "#Pxl", innerGlow->spread());
w.writeUnitFloat("blur", "#Pxl", innerGlow->size());
// NOTE: order is swapped in ASL!
w.writeUnitFloat("ShdN", "#Prc", innerGlow->jitter());
w.writeUnitFloat("Nose", "#Prc", innerGlow->noise());
w.writeBoolean("AntA", innerGlow->antiAliased());
w.writeEnum("glwS", "IGSr", innerGlow->source() == psd_glow_center ? "SrcC" : "SrcE");
// FIXME: save curves
w.writeCurve("TrnS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.writeUnitFloat("Inpr", "#Prc", innerGlow->range());
w.leaveDescriptor();
}
// Bevel and Emboss
const psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss();
if (bevelAndEmboss->effectEnabled()) {
w.enterDescriptor("ebbl", "", "ebbl");
w.writeBoolean("enab", bevelAndEmboss->effectEnabled());
w.writeEnum("hglM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->highlightBlendMode()));
w.writeColor("hglC", bevelAndEmboss->highlightColor());
w.writeUnitFloat("hglO", "#Prc", bevelAndEmboss->highlightOpacity());
w.writeEnum("sdwM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->shadowBlendMode()));
w.writeColor("sdwC", bevelAndEmboss->shadowColor());
w.writeUnitFloat("sdwO", "#Prc", bevelAndEmboss->shadowOpacity());
w.writeEnum("bvlT", "bvlT", techniqueToString(bevelAndEmboss->technique(), "bvlT"));
w.writeEnum("bvlS", "BESl", bevelStyleToString(bevelAndEmboss->style()));
w.writeBoolean("uglg", bevelAndEmboss->useGlobalLight());
w.writeUnitFloat("lagl", "#Ang", bevelAndEmboss->angle());
w.writeUnitFloat("Lald", "#Ang", bevelAndEmboss->altitude());
w.writeUnitFloat("srgR", "#Prc", bevelAndEmboss->depth());
w.writeUnitFloat("blur", "#Pxl", bevelAndEmboss->size());
w.writeEnum("bvlD", "BESs", bevelAndEmboss->direction() == psd_direction_up ? "In " : "Out ");
// FIXME: save curves
w.writeCurve("TrnS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.writeBoolean("antialiasGloss", bevelAndEmboss->glossAntiAliased());
w.writeUnitFloat("Sftn", "#Pxl", bevelAndEmboss->soften());
if (bevelAndEmboss->contourEnabled()) {
w.writeBoolean("useShape", bevelAndEmboss->contourEnabled());
// FIXME: save curves
w.writeCurve("MpgS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.writeBoolean("AntA", bevelAndEmboss->antiAliased());
w.writeUnitFloat("Inpr", "#Prc", bevelAndEmboss->contourRange());
}
w.writeBoolean("useTexture", bevelAndEmboss->textureEnabled());
if (bevelAndEmboss->textureEnabled()) {
w.writeBoolean("InvT", bevelAndEmboss->textureInvert());
w.writeBoolean("Algn", bevelAndEmboss->textureAlignWithLayer());
w.writeUnitFloat("Scl ", "#Prc", bevelAndEmboss->textureScale());
w.writeUnitFloat("textureDepth ", "#Prc", bevelAndEmboss->textureDepth());
w.writePatternRef("Ptrn", bevelAndEmboss->texturePattern(), fetchPatternUuidSafe(bevelAndEmboss->texturePattern(), patternToUuidMap));
w.writePhasePoint("phase", bevelAndEmboss->texturePhase());
}
w.leaveDescriptor();
}
// Satin
const psd_layer_effects_satin *satin = style->satin();
if (satin->effectEnabled()) {
w.enterDescriptor("ChFX", "", "ChFX");
w.writeBoolean("enab", satin->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(satin->blendMode()));
w.writeColor("Clr ", satin->color());
w.writeBoolean("AntA", satin->antiAliased());
w.writeBoolean("Invr", satin->invert());
w.writeUnitFloat("Opct", "#Prc", satin->opacity());
w.writeUnitFloat("lagl", "#Ang", satin->angle());
w.writeUnitFloat("Dstn", "#Pxl", satin->distance());
w.writeUnitFloat("blur", "#Pxl", satin->size());
// FIXME: save curves
w.writeCurve("MpgS",
"Linear",
QVector() << QPointF() << QPointF(255, 255));
w.leaveDescriptor();
}
const psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay();
if (colorOverlay->effectEnabled()) {
w.enterDescriptor("SoFi", "", "SoFi");
w.writeBoolean("enab", colorOverlay->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(colorOverlay->blendMode()));
w.writeUnitFloat("Opct", "#Prc", colorOverlay->opacity());
w.writeColor("Clr ", colorOverlay->color());
w.leaveDescriptor();
}
// Gradient Overlay
const psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay();
KoSegmentGradient *segmentGradient = dynamic_cast(gradientOverlay->gradient().data());
KoStopGradient *stopGradient = dynamic_cast(gradientOverlay->gradient().data());
if (gradientOverlay->effectEnabled() && ((segmentGradient && segmentGradient->valid()) || (stopGradient && stopGradient->valid()))) {
w.enterDescriptor("GrFl", "", "GrFl");
w.writeBoolean("enab", gradientOverlay->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(gradientOverlay->blendMode()));
w.writeUnitFloat("Opct", "#Prc", gradientOverlay->opacity());
- if (segmentGradient) {
+ if (segmentGradient && segmentGradient->valid()) {
w.writeSegmentGradient("Grad", segmentGradient);
- } else if (stopGradient) {
+ } else if (stopGradient && stopGradient->valid()) {
w.writeStopGradient("Grad", stopGradient);
}
w.writeUnitFloat("Angl", "#Ang", gradientOverlay->angle());
w.writeEnum("Type", "GrdT", gradientTypeToString(gradientOverlay->style()));
w.writeBoolean("Rvrs", gradientOverlay->reverse());
w.writeBoolean("Algn", gradientOverlay->alignWithLayer());
w.writeUnitFloat("Scl ", "#Prc", gradientOverlay->scale());
w.writeOffsetPoint("Ofst", gradientOverlay->gradientOffset());
// FIXME: Krita doesn't support dithering
w.writeBoolean("Dthr", true/*gradientOverlay->dither()*/);
w.leaveDescriptor();
}
// Pattern Overlay
const psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay();
if (patternOverlay->effectEnabled()) {
w.enterDescriptor("patternFill", "", "patternFill");
w.writeBoolean("enab", patternOverlay->effectEnabled());
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(patternOverlay->blendMode()));
w.writeUnitFloat("Opct", "#Prc", patternOverlay->opacity());
w.writePatternRef("Ptrn", patternOverlay->pattern(), fetchPatternUuidSafe(patternOverlay->pattern(), patternToUuidMap));
w.writeUnitFloat("Scl ", "#Prc", patternOverlay->scale());
w.writeBoolean("Algn", patternOverlay->alignWithLayer());
w.writePhasePoint("phase", patternOverlay->patternPhase());
w.leaveDescriptor();
}
const psd_layer_effects_stroke *stroke = style->stroke();
if (stroke->effectEnabled()) {
w.enterDescriptor("FrFX", "", "FrFX");
w.writeBoolean("enab", stroke->effectEnabled());
w.writeEnum("Styl", "FStl", strokePositionToString(stroke->position()));
w.writeEnum("PntT", "FrFl", strokeFillTypeToString(stroke->fillType()));
w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(stroke->blendMode()));
w.writeUnitFloat("Opct", "#Prc", stroke->opacity());
w.writeUnitFloat("Sz ", "#Pxl", stroke->size());
if (stroke->fillType() == psd_fill_solid_color) {
w.writeColor("Clr ", stroke->color());
}
else if (stroke->fillType() == psd_fill_gradient) {
KoSegmentGradient *segmentGradient = dynamic_cast(stroke->gradient().data());
KoStopGradient *stopGradient = dynamic_cast(stroke->gradient().data());
if (segmentGradient && segmentGradient->valid()) {
w.writeSegmentGradient("Grad", segmentGradient);
} else if (stopGradient && stopGradient->valid()) {
w.writeStopGradient("Grad", stopGradient);
} else {
warnKrita << "WARNING: Stroke: Unknown gradient type!";
w.writeColor("Clr ", stroke->color());
}
w.writeUnitFloat("Angl", "#Ang", stroke->angle());
w.writeEnum("Type", "GrdT", gradientTypeToString(stroke->style()));
w.writeBoolean("Rvrs", stroke->reverse());
w.writeUnitFloat("Scl ", "#Prc", stroke->scale());
w.writeBoolean("Algn", stroke->alignWithLayer());
w.writeOffsetPoint("Ofst", stroke->gradientOffset());
// FIXME: Krita doesn't support dithering
w.writeBoolean("Dthr", true/*stroke->dither()*/);
} else if (stroke->fillType() == psd_fill_pattern) {
w.writePatternRef("Ptrn", stroke->pattern(), fetchPatternUuidSafe(stroke->pattern(), patternToUuidMap));
w.writeUnitFloat("Scl ", "#Prc", stroke->scale());
w.writeBoolean("Lnkd", stroke->alignWithLayer());
w.writePhasePoint("phase", stroke->patternPhase());
}
w.leaveDescriptor();
}
w.leaveDescriptor();
w.leaveDescriptor();
}
return w.document();
}
inline QDomNode findNodeByClassId(const QString &classId, QDomNode parent) {
return KisDomUtils::findElementByAttibute(parent, "node", "classId", classId);
}
void replaceAllChildren(QDomNode src, QDomNode dst)
{
QDomNode node;
do {
node = dst.lastChild();
dst.removeChild(node);
} while(!node.isNull());
node = src.firstChild();
while(!node.isNull()) {
dst.appendChild(node);
node = src.firstChild();
}
src.parentNode().removeChild(src);
}
QDomDocument KisAslLayerStyleSerializer::formPsdXmlDocument() const
{
QDomDocument doc = formXmlDocument();
QDomNode nullNode = findNodeByClassId("null", doc.documentElement());
QDomNode stylNode = findNodeByClassId("Styl", doc.documentElement());
QDomNode lefxNode = findNodeByClassId("Lefx", stylNode);
replaceAllChildren(lefxNode, nullNode);
return doc;
}
void KisAslLayerStyleSerializer::saveToDevice(QIODevice *device)
{
QDomDocument doc = formXmlDocument();
if (doc.isNull()) return ;
KisAslWriter writer;
writer.writeFile(device, doc);
}
void convertAndSetBlendMode(const QString &mode,
boost::function setBlendMode)
{
QString compositeOp = COMPOSITE_OVER;
if (mode == "Nrml") {
compositeOp = COMPOSITE_OVER;
} else if (mode == "Dslv") {
compositeOp = COMPOSITE_DISSOLVE;
} else if (mode == "Drkn") {
compositeOp = COMPOSITE_DARKEN;
} else if (mode == "Mltp") {
compositeOp = COMPOSITE_MULT;
} else if (mode == "CBrn") {
compositeOp = COMPOSITE_BURN;
} else if (mode == "linearBurn") {
compositeOp = COMPOSITE_LINEAR_BURN;
} else if (mode == "darkerColor") {
compositeOp = COMPOSITE_DARKER_COLOR;
} else if (mode == "Lghn") {
compositeOp = COMPOSITE_LIGHTEN;
} else if (mode == "Scrn") {
compositeOp = COMPOSITE_SCREEN;
} else if (mode == "CDdg") {
compositeOp = COMPOSITE_DODGE;
} else if (mode == "linearDodge") {
compositeOp = COMPOSITE_LINEAR_DODGE;
} else if (mode == "lighterColor") {
compositeOp = COMPOSITE_LIGHTER_COLOR;
} else if (mode == "Ovrl") {
compositeOp = COMPOSITE_OVERLAY;
} else if (mode == "SftL") {
compositeOp = COMPOSITE_SOFT_LIGHT_PHOTOSHOP;
} else if (mode == "HrdL") {
compositeOp = COMPOSITE_HARD_LIGHT;
} else if (mode == "vividLight") {
compositeOp = COMPOSITE_VIVID_LIGHT;
} else if (mode == "linearLight") {
compositeOp = COMPOSITE_LINEAR_LIGHT;
} else if (mode == "pinLight") {
compositeOp = COMPOSITE_PIN_LIGHT;
} else if (mode == "hardMix") {
compositeOp = COMPOSITE_HARD_MIX_PHOTOSHOP;
} else if (mode == "Dfrn") {
compositeOp = COMPOSITE_DIFF;
} else if (mode == "Xclu") {
compositeOp = COMPOSITE_EXCLUSION;
} else if (mode == "Sbtr") {
compositeOp = COMPOSITE_SUBTRACT;
} else if (mode == "divide") {
compositeOp = COMPOSITE_DIVIDE;
} else if (mode == "H ") {
compositeOp = COMPOSITE_HUE;
} else if (mode == "Strt") {
compositeOp = COMPOSITE_SATURATION;
} else if (mode == "Clr ") {
compositeOp = COMPOSITE_COLOR;
} else if (mode == "Lmns") {
compositeOp = COMPOSITE_LUMINIZE;
} else {
dbgKrita << "Unknown blending mode:" << mode << "Returning COMPOSITE_OVER!";
}
setBlendMode(compositeOp);
}
void convertAndSetCurve(const QString &name,
const QVector &points,
boost::function setCurveLookupTable)
{
Q_UNUSED(name);
Q_UNUSED(points);
Q_UNUSED(setCurveLookupTable);
warnKrita << "convertAndSetBlendMode:" << "Curve conversion is not implemented yet";
}
template
void convertAndSetEnum(const QString &value,
const QMap map,
boost::function setMappedValue)
{
setMappedValue(map[value]);
}
inline QString _prepaddr(const QString &pref, const QString &addr) {
return pref + addr;
}
#define CONN_TEXT_RADDR(addr, method, object, type) m_catcher.subscribeText(addr, std::bind(&type::method, object, _1))
#define CONN_COLOR(addr, method, object, type, prefix) m_catcher.subscribeColor(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
#define CONN_UNITF(addr, unit, method, object, type, prefix) m_catcher.subscribeUnitFloat(_prepaddr(prefix, addr), unit, std::bind(&type::method, object, _1))
#define CONN_BOOL(addr, method, object, type, prefix) m_catcher.subscribeBoolean(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
#define CONN_POINT(addr, method, object, type, prefix) m_catcher.subscribePoint(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
#define CONN_COMPOSITE_OP(addr, method, object, type, prefix) \
{ \
boost::function setter = \
std::bind(&type::method, object, _1); \
m_catcher.subscribeEnum(_prepaddr(prefix, addr), "BlnM", std::bind(convertAndSetBlendMode, _1, setter)); \
}
#define CONN_CURVE(addr, method, object, type, prefix) \
{ \
boost::function setter = \
std::bind(&type::method, object, _1); \
m_catcher.subscribeCurve(_prepaddr(prefix, addr), std::bind(convertAndSetCurve, _1, _2, setter)); \
}
#define CONN_ENUM(addr, tag, method, map, mapped_type, object, type, prefix) \
{ \
boost::function setter = \
std::bind(&type::method, object, _1); \
m_catcher.subscribeEnum(_prepaddr(prefix, addr), tag, std::bind(convertAndSetEnum, _1, map, setter)); \
}
#define CONN_GRADIENT(addr, method, object, type, prefix) \
{ \
m_catcher.subscribeGradient(_prepaddr(prefix, addr), std::bind(&type::method, object, _1)); \
}
#define CONN_PATTERN(addr, method, object, type, prefix) \
{ \
boost::function setter = \
std::bind(&type::method, object, _1); \
m_catcher.subscribePatternRef(_prepaddr(prefix, addr), std::bind(&KisAslLayerStyleSerializer::assignPatternObject, this, _1, _2, setter)); \
}
void KisAslLayerStyleSerializer::registerPatternObject(const KoPatternSP pattern, const QString& patternUuid) {
if (m_patternsStore.contains(patternUuid)) {
warnKrita << "WARNING: ASL style contains a duplicated pattern!" << ppVar(pattern->name()) << ppVar(m_patternsStore[patternUuid]->name());
} else {
pattern->setFilename(patternUuid + QString("_pattern"));
m_patternsStore.insert(patternUuid, pattern);
}
}
void KisAslLayerStyleSerializer::assignPatternObject(const QString &patternUuid,
const QString &patternName,
boost::function setPattern)
{
Q_UNUSED(patternName);
KoPatternSP pattern = m_patternsStore[patternUuid];
if (!pattern) {
warnKrita << "WARNING: ASL style contains non-existent pattern reference! Searching for uuid: "
<< patternUuid << " (name: " << patternName << ")";
QImage dumbImage(32, 32, QImage::Format_ARGB32);
dumbImage.fill(Qt::red);
KoPatternSP dumbPattern(new KoPattern(dumbImage, "invalid", ""));
registerPatternObject(dumbPattern, patternUuid + QString("_invalid"));
pattern = dumbPattern;
m_isValid = false;
}
setPattern(pattern);
}
class FillStylesCorrector {
public:
static void correct(KisPSDLayerStyle *style) {
correctWithoutPattern(style->outerGlow());
correctWithoutPattern(style->innerGlow());
correctWithPattern(style->stroke());
}
private:
template
static void correctWithPattern(T *config) {
if (config->pattern()) {
config->setFillType(psd_fill_pattern);
} else if (config->gradient()) {
config->setFillType(psd_fill_gradient);
} else {
config->setFillType(psd_fill_solid_color);
}
}
template
static void correctWithoutPattern(T *config) {
if (config->gradient()) {
config->setFillType(psd_fill_gradient);
} else {
config->setFillType(psd_fill_solid_color);
}
}
};
void KisAslLayerStyleSerializer::connectCatcherToStyle(KisPSDLayerStyle *style, const QString &prefix)
{
CONN_TEXT_RADDR("/null/Nm ", setName, style, KisPSDLayerStyle);
CONN_TEXT_RADDR("/null/Idnt", setPsdUuid, style, KisPSDLayerStyle);
CONN_BOOL("/masterFXSwitch", setEnabled, style, KisPSDLayerStyle, prefix);
psd_layer_effects_drop_shadow *dropShadow = style->dropShadow();
CONN_COMPOSITE_OP("/DrSh/Md ", setBlendMode, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_COLOR("/DrSh/Clr ", setColor, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/Opct", "#Prc", setOpacity, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/lagl", "#Ang", setAngle, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/Dstn", "#Pxl", setDistance, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/Ckmt", "#Pxl", setSpread, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/blur", "#Pxl", setSize, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_UNITF("/DrSh/Nose", "#Prc", setNoise, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_BOOL("/DrSh/enab", setEffectEnabled, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_BOOL("/DrSh/uglg", setUseGlobalLight, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_BOOL("/DrSh/AntA", setAntiAliased, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_BOOL("/DrSh/layerConceals", setKnocksOut, dropShadow, psd_layer_effects_drop_shadow, prefix);
CONN_CURVE("/DrSh/TrnS", setContourLookupTable, dropShadow, psd_layer_effects_drop_shadow, prefix);
psd_layer_effects_inner_shadow *innerShadow = style->innerShadow();
CONN_COMPOSITE_OP("/IrSh/Md ", setBlendMode, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_COLOR("/IrSh/Clr ", setColor, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/Opct", "#Prc", setOpacity, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/lagl", "#Ang", setAngle, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/Dstn", "#Pxl", setDistance, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/Ckmt", "#Pxl", setSpread, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/blur", "#Pxl", setSize, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_UNITF("/IrSh/Nose", "#Prc", setNoise, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_BOOL("/IrSh/enab", setEffectEnabled, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_BOOL("/IrSh/uglg", setUseGlobalLight, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_BOOL("/IrSh/AntA", setAntiAliased, innerShadow, psd_layer_effects_inner_shadow, prefix);
CONN_CURVE("/IrSh/TrnS", setContourLookupTable, innerShadow, psd_layer_effects_inner_shadow, prefix);
psd_layer_effects_outer_glow *outerGlow = style->outerGlow();
CONN_COMPOSITE_OP("/OrGl/Md ", setBlendMode, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_COLOR("/OrGl/Clr ", setColor, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/Opct", "#Prc", setOpacity, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/Ckmt", "#Pxl", setSpread, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/blur", "#Pxl", setSize, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/Nose", "#Prc", setNoise, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_BOOL("/OrGl/enab", setEffectEnabled, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_BOOL("/OrGl/AntA", setAntiAliased, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_CURVE("/OrGl/TrnS", setContourLookupTable, outerGlow, psd_layer_effects_outer_glow, prefix);
QMap fillTechniqueMap;
fillTechniqueMap.insert("PrBL", psd_technique_precise);
fillTechniqueMap.insert("SfBL", psd_technique_softer);
CONN_ENUM("/OrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_GRADIENT("/OrGl/Grad", setGradient, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/Inpr", "#Prc", setRange, outerGlow, psd_layer_effects_outer_glow, prefix);
CONN_UNITF("/OrGl/ShdN", "#Prc", setJitter, outerGlow, psd_layer_effects_outer_glow, prefix);
psd_layer_effects_inner_glow *innerGlow = style->innerGlow();
CONN_COMPOSITE_OP("/IrGl/Md ", setBlendMode, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_COLOR("/IrGl/Clr ", setColor, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/Opct", "#Prc", setOpacity, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/Ckmt", "#Pxl", setSpread, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/blur", "#Pxl", setSize, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/Nose", "#Prc", setNoise, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_BOOL("/IrGl/enab", setEffectEnabled, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_BOOL("/IrGl/AntA", setAntiAliased, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_CURVE("/IrGl/TrnS", setContourLookupTable, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_ENUM("/IrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_GRADIENT("/IrGl/Grad", setGradient, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/Inpr", "#Prc", setRange, innerGlow, psd_layer_effects_inner_glow, prefix);
CONN_UNITF("/IrGl/ShdN", "#Prc", setJitter, innerGlow, psd_layer_effects_inner_glow, prefix);
QMap glowSourceMap;
glowSourceMap.insert("SrcC", psd_glow_center);
glowSourceMap.insert("SrcE", psd_glow_edge);
CONN_ENUM("/IrGl/glwS", "IGSr", setSource, glowSourceMap, psd_glow_source, innerGlow, psd_layer_effects_inner_glow, prefix);
psd_layer_effects_satin *satin = style->satin();
CONN_COMPOSITE_OP("/ChFX/Md ", setBlendMode, satin, psd_layer_effects_satin, prefix);
CONN_COLOR("/ChFX/Clr ", setColor, satin, psd_layer_effects_satin, prefix);
CONN_UNITF("/ChFX/Opct", "#Prc", setOpacity, satin, psd_layer_effects_satin, prefix);
CONN_UNITF("/ChFX/lagl", "#Ang", setAngle, satin, psd_layer_effects_satin, prefix);
CONN_UNITF("/ChFX/Dstn", "#Pxl", setDistance, satin, psd_layer_effects_satin, prefix);
CONN_UNITF("/ChFX/blur", "#Pxl", setSize, satin, psd_layer_effects_satin, prefix);
CONN_BOOL("/ChFX/enab", setEffectEnabled, satin, psd_layer_effects_satin, prefix);
CONN_BOOL("/ChFX/AntA", setAntiAliased, satin, psd_layer_effects_satin, prefix);
CONN_BOOL("/ChFX/Invr", setInvert, satin, psd_layer_effects_satin, prefix);
CONN_CURVE("/ChFX/MpgS", setContourLookupTable, satin, psd_layer_effects_satin, prefix);
psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay();
CONN_COMPOSITE_OP("/SoFi/Md ", setBlendMode, colorOverlay, psd_layer_effects_color_overlay, prefix);
CONN_COLOR("/SoFi/Clr ", setColor, colorOverlay, psd_layer_effects_color_overlay, prefix);
CONN_UNITF("/SoFi/Opct", "#Prc", setOpacity, colorOverlay, psd_layer_effects_color_overlay, prefix);
CONN_BOOL("/SoFi/enab", setEffectEnabled, colorOverlay, psd_layer_effects_color_overlay, prefix);
psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay();
CONN_COMPOSITE_OP("/GrFl/Md ", setBlendMode, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_UNITF("/GrFl/Opct", "#Prc", setOpacity, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_UNITF("/GrFl/Scl ", "#Prc", setScale, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_UNITF("/GrFl/Angl", "#Ang", setAngle, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_BOOL("/GrFl/enab", setEffectEnabled, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
// CONN_BOOL("/GrFl/Dthr", setDitherNotImplemented, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_BOOL("/GrFl/Rvrs", setReverse, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_BOOL("/GrFl/Algn", setAlignWithLayer, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_POINT("/GrFl/Ofst", setGradientOffset, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
CONN_GRADIENT("/GrFl/Grad", setGradient, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
QMap gradientStyleMap;
gradientStyleMap.insert("Lnr ", psd_gradient_style_linear);
gradientStyleMap.insert("Rdl ", psd_gradient_style_radial);
gradientStyleMap.insert("Angl", psd_gradient_style_angle);
gradientStyleMap.insert("Rflc", psd_gradient_style_reflected);
gradientStyleMap.insert("Dmnd", psd_gradient_style_diamond);
CONN_ENUM("/GrFl/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay();
CONN_BOOL("/patternFill/enab", setEffectEnabled, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_COMPOSITE_OP("/patternFill/Md ", setBlendMode, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_UNITF("/patternFill/Opct", "#Prc", setOpacity, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_PATTERN("/patternFill/Ptrn", setPattern, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_UNITF("/patternFill/Scl ", "#Prc", setScale, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_BOOL("/patternFill/Algn", setAlignWithLayer, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
CONN_POINT("/patternFill/phase", setPatternPhase, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
psd_layer_effects_stroke *stroke = style->stroke();
CONN_COMPOSITE_OP("/FrFX/Md ", setBlendMode, stroke, psd_layer_effects_stroke, prefix);
CONN_BOOL("/FrFX/enab", setEffectEnabled, stroke, psd_layer_effects_stroke, prefix);
CONN_UNITF("/FrFX/Opct", "#Prc", setOpacity, stroke, psd_layer_effects_stroke, prefix);
CONN_UNITF("/FrFX/Sz ", "#Pxl", setSize, stroke, psd_layer_effects_stroke, prefix);
QMap strokeStyleMap;
strokeStyleMap.insert("OutF", psd_stroke_outside);
strokeStyleMap.insert("InsF", psd_stroke_inside);
strokeStyleMap.insert("CtrF", psd_stroke_center);
CONN_ENUM("/FrFX/Styl", "FStl", setPosition, strokeStyleMap, psd_stroke_position, stroke, psd_layer_effects_stroke, prefix);
QMap strokeFillType;
strokeFillType.insert("SClr", psd_fill_solid_color);
strokeFillType.insert("GrFl", psd_fill_gradient);
strokeFillType.insert("Ptrn", psd_fill_pattern);
CONN_ENUM("/FrFX/PntT", "FrFl", setFillType, strokeFillType, psd_fill_type, stroke, psd_layer_effects_stroke, prefix);
// Color type
CONN_COLOR("/FrFX/Clr ", setColor, stroke, psd_layer_effects_stroke, prefix);
// Gradient Type
CONN_GRADIENT("/FrFX/Grad", setGradient, stroke, psd_layer_effects_stroke, prefix);
CONN_UNITF("/FrFX/Angl", "#Ang", setAngle, stroke, psd_layer_effects_stroke, prefix);
CONN_UNITF("/FrFX/Scl ", "#Prc", setScale, stroke, psd_layer_effects_stroke, prefix);
CONN_ENUM("/FrFX/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, stroke, psd_layer_effects_stroke, prefix);
CONN_BOOL("/FrFX/Rvrs", setReverse, stroke, psd_layer_effects_stroke, prefix);
CONN_BOOL("/FrFX/Algn", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix);
CONN_POINT("/FrFX/Ofst", setGradientOffset, stroke, psd_layer_effects_stroke, prefix);
// CONN_BOOL("/FrFX/Dthr", setDitherNotImplemented, stroke, psd_layer_effects_stroke, prefix);
// Pattern type
CONN_PATTERN("/FrFX/Ptrn", setPattern, stroke, psd_layer_effects_stroke, prefix);
CONN_BOOL("/FrFX/Lnkd", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix); // yes, we share the params...
CONN_POINT("/FrFX/phase", setPatternPhase, stroke, psd_layer_effects_stroke, prefix);
psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss();
CONN_BOOL("/ebbl/enab", setEffectEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_COMPOSITE_OP("/ebbl/hglM", setHighlightBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_COLOR("/ebbl/hglC", setHighlightColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/hglO", "#Prc", setHighlightOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_COMPOSITE_OP("/ebbl/sdwM", setShadowBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_COLOR("/ebbl/sdwC", setShadowColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/sdwO", "#Prc", setShadowOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
QMap bevelTechniqueMap;
bevelTechniqueMap.insert("PrBL", psd_technique_precise);
bevelTechniqueMap.insert("SfBL", psd_technique_softer);
bevelTechniqueMap.insert("Slmt", psd_technique_slope_limit);
CONN_ENUM("/ebbl/bvlT", "bvlT", setTechnique, bevelTechniqueMap, psd_technique_type, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
QMap bevelStyleMap;
bevelStyleMap.insert("OtrB", psd_bevel_outer_bevel);
bevelStyleMap.insert("InrB", psd_bevel_inner_bevel);
bevelStyleMap.insert("Embs", psd_bevel_emboss);
bevelStyleMap.insert("PlEb", psd_bevel_pillow_emboss);
bevelStyleMap.insert("strokeEmboss", psd_bevel_stroke_emboss);
CONN_ENUM("/ebbl/bvlS", "BESl", setStyle, bevelStyleMap, psd_bevel_style, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_BOOL("/ebbl/uglg", setUseGlobalLight, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/lagl", "#Ang", setAngle, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/Lald", "#Ang", setAltitude, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/srgR", "#Prc", setDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/blur", "#Pxl", setSize, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
QMap bevelDirectionMap;
bevelDirectionMap.insert("In ", psd_direction_up);
bevelDirectionMap.insert("Out ", psd_direction_down);
CONN_ENUM("/ebbl/bvlD", "BESs", setDirection, bevelDirectionMap, psd_direction, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_CURVE("/ebbl/TrnS", setContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_BOOL("/ebbl/antialiasGloss", setGlossAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/Sftn", "#Pxl", setSoften, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
// Use shape mode
CONN_BOOL("/ebbl/useShape", setContourEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_CURVE("/ebbl/MpgS", setGlossContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_BOOL("/ebbl/AntA", setAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/Inpr", "#Prc", setContourRange, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
// Use texture mode
CONN_BOOL("/ebbl/useTexture", setTextureEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_BOOL("/ebbl/InvT", setTextureInvert, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_BOOL("/ebbl/Algn", setTextureAlignWithLayer, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/Scl ", "#Prc", setTextureScale, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_UNITF("/ebbl/textureDepth", "#Prc", setTextureDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_PATTERN("/ebbl/Ptrn", setTexturePattern, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
CONN_POINT("/ebbl/phase", setTexturePhase, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
}
void KisAslLayerStyleSerializer::newStyleStarted(bool isPsdStructure)
{
m_stylesVector.append(toQShared(new KisPSDLayerStyle()));
KisPSDLayerStyleSP currentStyleSP = m_stylesVector.last();
KisPSDLayerStyle *currentStyle = currentStyleSP.data();
psd_layer_effects_context *context = currentStyleSP->context();
context->keep_original = 0;
QString prefix = isPsdStructure ? "/null" : "/Styl/Lefx";
connectCatcherToStyle(currentStyle, prefix);
}
bool KisAslLayerStyleSerializer::readFromFile(const QString& filename)
{
QFile file(filename);
if (file.size() == 0) return false;
if (!file.open(QIODevice::ReadOnly)) {
dbgKrita << "Can't open file " << filename;
return false;
}
readFromDevice(&file);
m_initialized = true;
file.close();
return true;
}
void KisAslLayerStyleSerializer::readFromDevice(QIODevice *device)
{
m_stylesVector.clear();
m_catcher.subscribePattern("/patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, false));
KisAslReader reader;
QDomDocument doc = reader.readFile(device);
//dbgKrita << ppVar(doc.toString());
//KisAslObjectCatcher c2;
KisAslXmlParser parser;
parser.parseXML(doc, m_catcher);
// correct all the layer styles
Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
FillStylesCorrector::correct(style.data());
style->setValid(!style->isEmpty());
style->setFilename(style->psdUuid() + QString("_style"));
}
m_initialized = true;
}
void KisAslLayerStyleSerializer::registerPSDPattern(const QDomDocument &doc)
{
KisAslCallbackObjectCatcher catcher;
catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
catcher.subscribePattern("/patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
//KisAslObjectCatcher c2;
KisAslXmlParser parser;
parser.parseXML(doc, catcher);
}
void KisAslLayerStyleSerializer::readFromPSDXML(const QDomDocument &doc)
{
// The caller prepares the document using th efollowing code
//
// KisAslReader reader;
// QDomDocument doc = reader.readLfx2PsdSection(device);
m_stylesVector.clear();
//m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1));
m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, true));
//KisAslObjectCatcher c2;
KisAslXmlParser parser;
parser.parseXML(doc, m_catcher);
// correct all the layer styles
Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
FillStylesCorrector::correct(style.data());
}
}
diff --git a/libs/image/kis_liquify_transform_worker.cpp b/libs/image/kis_liquify_transform_worker.cpp
index e7d171bd43..d03ebc5c65 100644
--- a/libs/image/kis_liquify_transform_worker.cpp
+++ b/libs/image/kis_liquify_transform_worker.cpp
@@ -1,602 +1,608 @@
/*
* Copyright (c) 2014 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_liquify_transform_worker.h"
#include "kis_grid_interpolation_tools.h"
#include "kis_dom_utils.h"
#include "krita_utils.h"
struct Q_DECL_HIDDEN KisLiquifyTransformWorker::Private
{
Private(const QRect &_srcBounds,
KoUpdater *_progress,
int _pixelPrecision)
: srcBounds(_srcBounds),
progress(_progress),
pixelPrecision(_pixelPrecision)
{
}
const QRect srcBounds;
QVector originalPoints;
QVector transformedPoints;
KoUpdater *progress;
int pixelPrecision;
QSize gridSize;
void preparePoints();
struct MapIndexesOp;
template
void processTransformedPixelsBuildUp(ProcessOp op,
const QPointF &base,
qreal sigma);
template
void processTransformedPixelsWash(ProcessOp op,
const QPointF &base,
qreal sigma,
qreal flow);
template
void processTransformedPixels(ProcessOp op,
const QPointF &base,
qreal sigma,
bool useWashMode,
qreal flow);
};
KisLiquifyTransformWorker::KisLiquifyTransformWorker(const QRect &srcBounds,
KoUpdater *progress,
int pixelPrecision)
: m_d(new Private(srcBounds, progress, pixelPrecision))
{
KIS_ASSERT_RECOVER_RETURN(!srcBounds.isEmpty());
// TODO: implement 'progress' stuff
m_d->preparePoints();
}
KisLiquifyTransformWorker::KisLiquifyTransformWorker(const KisLiquifyTransformWorker &rhs)
: m_d(new Private(*rhs.m_d.data()))
{
}
KisLiquifyTransformWorker::~KisLiquifyTransformWorker()
{
}
bool KisLiquifyTransformWorker::operator==(const KisLiquifyTransformWorker &other) const
{
bool result =
m_d->srcBounds == other.m_d->srcBounds &&
m_d->pixelPrecision == other.m_d->pixelPrecision &&
m_d->gridSize == other.m_d->gridSize &&
m_d->originalPoints.size() == other.m_d->originalPoints.size() &&
m_d->transformedPoints.size() == other.m_d->transformedPoints.size();
if (!result) return false;
const qreal eps = 1e-6;
result =
KisAlgebra2D::fuzzyPointCompare(m_d->originalPoints, other.m_d->originalPoints, eps) &&
KisAlgebra2D::fuzzyPointCompare(m_d->transformedPoints, other.m_d->transformedPoints, eps);
return result;
}
+bool KisLiquifyTransformWorker::isIdentity() const
+{
+ const qreal eps = 1e-6;
+ return KisAlgebra2D::fuzzyPointCompare(m_d->originalPoints, m_d->transformedPoints, eps);
+}
+
int KisLiquifyTransformWorker::pointToIndex(const QPoint &cellPt)
{
return GridIterationTools::pointToIndex(cellPt, m_d->gridSize);
}
QSize KisLiquifyTransformWorker::gridSize() const
{
return m_d->gridSize;
}
const QVector& KisLiquifyTransformWorker::originalPoints() const
{
return m_d->originalPoints;
}
QVector& KisLiquifyTransformWorker::transformedPoints()
{
return m_d->transformedPoints;
}
struct AllPointsFetcherOp
{
AllPointsFetcherOp(QRectF srcRect) : m_srcRect(srcRect) {}
inline void processPoint(int col, int row,
int prevCol, int prevRow,
int colIndex, int rowIndex) {
Q_UNUSED(prevCol);
Q_UNUSED(prevRow);
Q_UNUSED(colIndex);
Q_UNUSED(rowIndex);
QPointF pt(col, row);
m_points << pt;
}
inline void nextLine() {
}
QVector m_points;
QRectF m_srcRect;
};
void KisLiquifyTransformWorker::Private::preparePoints()
{
gridSize =
GridIterationTools::calcGridSize(srcBounds, pixelPrecision);
AllPointsFetcherOp pointsOp(srcBounds);
GridIterationTools::processGrid(pointsOp, srcBounds, pixelPrecision);
const int numPoints = pointsOp.m_points.size();
KIS_ASSERT_RECOVER_RETURN(numPoints == gridSize.width() * gridSize.height());
originalPoints = pointsOp.m_points;
transformedPoints = pointsOp.m_points;
}
void KisLiquifyTransformWorker::translate(const QPointF &offset)
{
QVector::iterator it = m_d->transformedPoints.begin();
QVector::iterator end = m_d->transformedPoints.end();
QVector::iterator refIt = m_d->originalPoints.begin();
KIS_ASSERT_RECOVER_RETURN(m_d->originalPoints.size() ==
m_d->transformedPoints.size());
for (; it != end; ++it, ++refIt) {
*it += offset;
*refIt += offset;
}
}
void KisLiquifyTransformWorker::undoPoints(const QPointF &base,
qreal amount,
qreal sigma)
{
const qreal maxDistCoeff = 3.0;
const qreal maxDist = maxDistCoeff * sigma;
QRectF clipRect(base.x() - maxDist, base.y() - maxDist,
2 * maxDist, 2 * maxDist);
QVector::iterator it = m_d->transformedPoints.begin();
QVector::iterator end = m_d->transformedPoints.end();
QVector::iterator refIt = m_d->originalPoints.begin();
KIS_ASSERT_RECOVER_RETURN(m_d->originalPoints.size() ==
m_d->transformedPoints.size());
for (; it != end; ++it, ++refIt) {
if (!clipRect.contains(*it)) continue;
QPointF diff = *it - base;
qreal dist = KisAlgebra2D::norm(diff);
if (dist > maxDist) continue;
qreal lambda = exp(-0.5 * pow2(dist / sigma));
lambda *= amount;
*it = *refIt * lambda + *it * (1.0 - lambda);
}
}
template
void KisLiquifyTransformWorker::Private::
processTransformedPixelsBuildUp(ProcessOp op,
const QPointF &base,
qreal sigma)
{
const qreal maxDist = ProcessOp::maxDistCoeff * sigma;
QRectF clipRect(base.x() - maxDist, base.y() - maxDist,
2 * maxDist, 2 * maxDist);
QVector::iterator it = transformedPoints.begin();
QVector::iterator end = transformedPoints.end();
for (; it != end; ++it) {
if (!clipRect.contains(*it)) continue;
QPointF diff = *it - base;
qreal dist = KisAlgebra2D::norm(diff);
if (dist > maxDist) continue;
const qreal lambda = exp(-0.5 * pow2(dist / sigma));
*it = op(*it, base, diff, lambda);
}
}
template
void KisLiquifyTransformWorker::Private::
processTransformedPixelsWash(ProcessOp op,
const QPointF &base,
qreal sigma,
qreal flow)
{
const qreal maxDist = ProcessOp::maxDistCoeff * sigma;
QRectF clipRect(base.x() - maxDist, base.y() - maxDist,
2 * maxDist, 2 * maxDist);
QVector::iterator it = transformedPoints.begin();
QVector::iterator end = transformedPoints.end();
QVector::iterator refIt = originalPoints.begin();
KIS_ASSERT_RECOVER_RETURN(originalPoints.size() ==
transformedPoints.size());
for (; it != end; ++it, ++refIt) {
if (!clipRect.contains(*it)) continue;
QPointF diff = *refIt - base;
qreal dist = KisAlgebra2D::norm(diff);
if (dist > maxDist) continue;
const qreal lambda = exp(-0.5 * pow2(dist / sigma));
QPointF dstPt = op(*refIt, base, diff, lambda);
if (kisDistance(dstPt, *refIt) > kisDistance(*it, *refIt)) {
*it = (1.0 - flow) * (*it) + flow * dstPt;
}
}
}
template
void KisLiquifyTransformWorker::Private::
processTransformedPixels(ProcessOp op,
const QPointF &base,
qreal sigma,
bool useWashMode,
qreal flow)
{
if (useWashMode) {
processTransformedPixelsWash(op, base, sigma, flow);
} else {
processTransformedPixelsBuildUp(op, base, sigma);
}
}
struct TranslateOp
{
TranslateOp(const QPointF &offset) : m_offset(offset) {}
QPointF operator() (const QPointF &pt,
const QPointF &base,
const QPointF &diff,
qreal lambda)
{
Q_UNUSED(base);
Q_UNUSED(diff);
return pt + lambda * m_offset;
}
static const qreal maxDistCoeff;
QPointF m_offset;
};
const qreal TranslateOp::maxDistCoeff = 3.0;
struct ScaleOp
{
ScaleOp(qreal scale) : m_scale(scale) {}
QPointF operator() (const QPointF &pt,
const QPointF &base,
const QPointF &diff,
qreal lambda)
{
Q_UNUSED(pt);
Q_UNUSED(diff);
return base + (1.0 + m_scale * lambda) * diff;
}
static const qreal maxDistCoeff;
qreal m_scale;
};
const qreal ScaleOp::maxDistCoeff = 3.0;
struct RotateOp
{
RotateOp(qreal angle) : m_angle(angle) {}
QPointF operator() (const QPointF &pt,
const QPointF &base,
const QPointF &diff,
qreal lambda)
{
Q_UNUSED(pt);
const qreal angle = m_angle * lambda;
const qreal sinA = std::sin(angle);
const qreal cosA = std::cos(angle);
qreal x = cosA * diff.x() + sinA * diff.y();
qreal y = -sinA * diff.x() + cosA * diff.y();
return base + QPointF(x, y);
}
static const qreal maxDistCoeff;
qreal m_angle;
};
const qreal RotateOp::maxDistCoeff = 3.0;
void KisLiquifyTransformWorker::translatePoints(const QPointF &base,
const QPointF &offset,
qreal sigma,
bool useWashMode,
qreal flow)
{
TranslateOp op(offset);
m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
}
void KisLiquifyTransformWorker::scalePoints(const QPointF &base,
qreal scale,
qreal sigma,
bool useWashMode,
qreal flow)
{
ScaleOp op(scale);
m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
}
void KisLiquifyTransformWorker::rotatePoints(const QPointF &base,
qreal angle,
qreal sigma,
bool useWashMode,
qreal flow)
{
RotateOp op(angle);
m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
}
struct KisLiquifyTransformWorker::Private::MapIndexesOp {
MapIndexesOp(KisLiquifyTransformWorker::Private *d)
: m_d(d)
{
}
inline QVector calculateMappedIndexes(int col, int row,
int *numExistingPoints) const {
*numExistingPoints = 4;
QVector cellIndexes =
GridIterationTools::calculateCellIndexes(col, row, m_d->gridSize);
return cellIndexes;
}
inline int tryGetValidIndex(const QPoint &cellPt) const {
Q_UNUSED(cellPt);
KIS_ASSERT_RECOVER_NOOP(0 && "Not applicable");
return -1;
}
inline QPointF getSrcPointForce(const QPoint &cellPt) const {
Q_UNUSED(cellPt);
KIS_ASSERT_RECOVER_NOOP(0 && "Not applicable");
return QPointF();
}
inline const QPolygonF srcCropPolygon() const {
KIS_ASSERT_RECOVER_NOOP(0 && "Not applicable");
return QPolygonF();
}
KisLiquifyTransformWorker::Private *m_d;
};
void KisLiquifyTransformWorker::run(KisPaintDeviceSP device)
{
KisPaintDeviceSP srcDev = new KisPaintDevice(*device.data());
device->clear();
using namespace GridIterationTools;
PaintDevicePolygonOp polygonOp(srcDev, device);
Private::MapIndexesOp indexesOp(m_d.data());
iterateThroughGrid(polygonOp, indexesOp,
m_d->gridSize,
m_d->originalPoints,
m_d->transformedPoints);
}
QRect KisLiquifyTransformWorker::approxChangeRect(const QRect &rc)
{
const qreal margin = 0.05;
/**
* Here we just return the full area occupied by the transformed grid.
* We sample grid points for not doing too much work.
*/
const int maxSamplePoints = 200;
const int minStep = 3;
const int step = qMax(minStep, m_d->transformedPoints.size() / maxSamplePoints);
QVector samplePoints;
for (auto it = m_d->transformedPoints.constBegin(); it != m_d->transformedPoints.constEnd(); ++it) {
samplePoints << it->toPoint();
}
QRect resultRect = KisAlgebra2D::approximateRectFromPoints(samplePoints);
return KisAlgebra2D::blowRect(resultRect | rc, margin);
}
QRect KisLiquifyTransformWorker::approxNeedRect(const QRect &rc, const QRect &fullBounds)
{
Q_UNUSED(rc);
return fullBounds;
}
#include
#include
using PointMapFunction = std::function;
PointMapFunction bindPointMapTransform(const QTransform &transform) {
using namespace std::placeholders;
typedef QPointF (QTransform::*MapFuncType)(const QPointF&) const;
return std::bind(static_cast(&QTransform::map), &transform, _1);
}
QImage KisLiquifyTransformWorker::runOnQImage(const QImage &srcImage,
const QPointF &srcImageOffset,
const QTransform &imageToThumbTransform,
QPointF *newOffset)
{
KIS_ASSERT_RECOVER(m_d->originalPoints.size() == m_d->transformedPoints.size()) {
return QImage();
}
KIS_ASSERT_RECOVER(!srcImage.isNull()) {
return QImage();
}
KIS_ASSERT_RECOVER(srcImage.format() == QImage::Format_ARGB32) {
return QImage();
}
QVector originalPointsLocal(m_d->originalPoints);
QVector transformedPointsLocal(m_d->transformedPoints);
PointMapFunction mapFunc = bindPointMapTransform(imageToThumbTransform);
std::transform(originalPointsLocal.begin(), originalPointsLocal.end(),
originalPointsLocal.begin(), mapFunc);
std::transform(transformedPointsLocal.begin(), transformedPointsLocal.end(),
transformedPointsLocal.begin(), mapFunc);
QRectF dstBounds;
Q_FOREACH (const QPointF &pt, transformedPointsLocal) {
KisAlgebra2D::accumulateBounds(pt, &dstBounds);
}
const QRectF srcBounds(srcImageOffset, srcImage.size());
dstBounds |= srcBounds;
QPointF dstQImageOffset = dstBounds.topLeft();
*newOffset = dstQImageOffset;
QRect dstBoundsI = dstBounds.toAlignedRect();
QImage dstImage(dstBoundsI.size(), srcImage.format());
dstImage.fill(0);
GridIterationTools::QImagePolygonOp polygonOp(srcImage, dstImage, srcImageOffset, dstQImageOffset);
Private::MapIndexesOp indexesOp(m_d.data());
GridIterationTools::iterateThroughGrid
(polygonOp, indexesOp,
m_d->gridSize,
originalPointsLocal,
transformedPointsLocal);
return dstImage;
}
void KisLiquifyTransformWorker::toXML(QDomElement *e) const
{
QDomDocument doc = e->ownerDocument();
QDomElement liqEl = doc.createElement("liquify_points");
e->appendChild(liqEl);
KisDomUtils::saveValue(&liqEl, "srcBounds", m_d->srcBounds);
KisDomUtils::saveValue(&liqEl, "originalPoints", m_d->originalPoints);
KisDomUtils::saveValue(&liqEl, "transformedPoints", m_d->transformedPoints);
KisDomUtils::saveValue(&liqEl, "pixelPrecision", m_d->pixelPrecision);
KisDomUtils::saveValue(&liqEl, "gridSize", m_d->gridSize);
}
KisLiquifyTransformWorker* KisLiquifyTransformWorker::fromXML(const QDomElement &e)
{
QDomElement liquifyEl;
QRect srcBounds;
QVector originalPoints;
QVector transformedPoints;
int pixelPrecision;
QSize gridSize;
bool result = false;
result =
KisDomUtils::findOnlyElement(e, "liquify_points", &liquifyEl) &&
KisDomUtils::loadValue(liquifyEl, "srcBounds", &srcBounds) &&
KisDomUtils::loadValue(liquifyEl, "originalPoints", &originalPoints) &&
KisDomUtils::loadValue(liquifyEl, "transformedPoints", &transformedPoints) &&
KisDomUtils::loadValue(liquifyEl, "pixelPrecision", &pixelPrecision) &&
KisDomUtils::loadValue(liquifyEl, "gridSize", &gridSize);
if (!result) {
warnKrita << "WARNING: Failed to load liquify worker from XML";
return new KisLiquifyTransformWorker(QRect(0,0,1024, 1024), 0, 8);
}
KisLiquifyTransformWorker *worker =
new KisLiquifyTransformWorker(srcBounds, 0, pixelPrecision);
const int numPoints = originalPoints.size();
if (numPoints != transformedPoints.size() ||
numPoints != worker->m_d->originalPoints.size() ||
gridSize != worker->m_d->gridSize) {
warnKrita << "WARNING: Inconsistent number of points!";
warnKrita << ppVar(originalPoints.size());
warnKrita << ppVar(transformedPoints.size());
warnKrita << ppVar(gridSize);
warnKrita << ppVar(worker->m_d->originalPoints.size());
warnKrita << ppVar(worker->m_d->transformedPoints.size());
warnKrita << ppVar(worker->m_d->gridSize);
return worker;
}
for (int i = 0; i < numPoints; i++) {
worker->m_d->originalPoints[i] = originalPoints[i];
worker->m_d->transformedPoints[i] = transformedPoints[i];
}
return worker;
}
diff --git a/libs/image/kis_liquify_transform_worker.h b/libs/image/kis_liquify_transform_worker.h
index 83d7ab5016..669533b4bb 100644
--- a/libs/image/kis_liquify_transform_worker.h
+++ b/libs/image/kis_liquify_transform_worker.h
@@ -1,95 +1,97 @@
/*
* Copyright (c) 2014 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_LIQUIFY_TRANSFORM_WORKER_H
#define __KIS_LIQUIFY_TRANSFORM_WORKER_H
#include
#include
#include
#include
class QImage;
class QRect;
class QSize;
class QTransform;
class QDomElement;
class KRITAIMAGE_EXPORT KisLiquifyTransformWorker : boost::equality_comparable
{
public:
KisLiquifyTransformWorker(const QRect &srcBounds,
KoUpdater *progress,
int pixelPrecision = 8);
KisLiquifyTransformWorker(const KisLiquifyTransformWorker &rhs);
~KisLiquifyTransformWorker();
bool operator==(const KisLiquifyTransformWorker &other) const;
+ bool isIdentity() const;
+
int pointToIndex(const QPoint &cellPt);
QSize gridSize() const;
void translatePoints(const QPointF &base,
const QPointF &offset,
qreal sigma,
bool useWashMode,
qreal flow);
void scalePoints(const QPointF &base,
qreal scale,
qreal sigma,
bool useWashMode,
qreal flow);
void rotatePoints(const QPointF &base,
qreal angle,
qreal sigma,
bool useWashMode,
qreal flow);
void undoPoints(const QPointF &base,
qreal amount,
qreal sigma);
const QVector& originalPoints() const;
QVector& transformedPoints();
void run(KisPaintDeviceSP device);
QImage runOnQImage(const QImage &srcImage,
const QPointF &srcImageOffset,
const QTransform &imageToThumbTransform,
QPointF *newOffset);
void toXML(QDomElement *e) const;
static KisLiquifyTransformWorker* fromXML(const QDomElement &e);
void translate(const QPointF &offset);
QRect approxChangeRect(const QRect &rc);
QRect approxNeedRect(const QRect &rc, const QRect &fullBounds);
private:
struct Private;
const QScopedPointer m_d;
};
#endif /* __KIS_LIQUIFY_TRANSFORM_WORKER_H */
diff --git a/libs/image/kis_mask_projection_plane.cpp b/libs/image/kis_mask_projection_plane.cpp
index 50e37434b0..884fea421b 100644
--- a/libs/image/kis_mask_projection_plane.cpp
+++ b/libs/image/kis_mask_projection_plane.cpp
@@ -1,91 +1,93 @@
/*
* Copyright (c) 2015 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_mask_projection_plane.h"
#include
#include
#include
#include "kis_painter.h"
#include "kis_mask.h"
struct KisMaskProjectionPlane::Private
{
KisMask *mask;
};
KisMaskProjectionPlane::KisMaskProjectionPlane(KisMask *mask)
: m_d(new Private)
{
m_d->mask = mask;
}
KisMaskProjectionPlane::~KisMaskProjectionPlane()
{
}
QRect KisMaskProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode)
{
Q_UNUSED(filthyNode);
KIS_ASSERT_RECOVER_NOOP(0 && "KisMaskProjectionPlane::recalculate() is not defined!");
return rect;
}
void KisMaskProjectionPlane::apply(KisPainter *painter, const QRect &rect)
{
Q_UNUSED(painter);
Q_UNUSED(rect);
KIS_ASSERT_RECOVER_NOOP(0 && "KisMaskProjectionPlane::apply() is not defined!");
}
KisPaintDeviceList KisMaskProjectionPlane::getLodCapableDevices() const
{
// masks have no projection
return KisPaintDeviceList();
}
QRect KisMaskProjectionPlane::needRect(const QRect &rect, KisNode::PositionToFilthy pos) const
{
return m_d->mask->needRect(rect, pos);
}
QRect KisMaskProjectionPlane::changeRect(const QRect &rect, KisNode::PositionToFilthy pos) const
{
return m_d->mask->changeRect(rect, pos);
}
QRect KisMaskProjectionPlane::accessRect(const QRect &rect, KisNode::PositionToFilthy pos) const
{
return m_d->mask->accessRect(rect, pos);
}
QRect KisMaskProjectionPlane::needRectForOriginal(const QRect &rect) const
{
return rect;
}
QRect KisMaskProjectionPlane::tightUserVisibleBounds() const
{
- return QRect();
+ // masks don't have any internal rendering subtrees,
+ // so just return the extent of the mask
+ return m_d->mask->extent();
}
diff --git a/libs/pigment/KoColorSpace.h b/libs/pigment/KoColorSpace.h
index dd693420f8..b83fcb4a09 100644
--- a/libs/pigment/KoColorSpace.h
+++ b/libs/pigment/KoColorSpace.h
@@ -1,708 +1,715 @@
/*
* Copyright (c) 2005 Boudewijn Rempt
* Copyright (c) 2006-2007 Cyrille Berger
*
* 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; 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 KOCOLORSPACE_H
#define KOCOLORSPACE_H
#include
#include
#include
#include
#include
#include
#include "KoColorSpaceConstants.h"
#include "KoColorConversionTransformation.h"
#include "KoColorProofingConversionTransformation.h"
#include "KoCompositeOp.h"
#include
#include "kritapigment_export.h"
class QDomDocument;
class QDomElement;
class KoChannelInfo;
class KoColorProfile;
class KoColorTransformation;
class QBitArray;
enum Deletability {
OwnedByRegistryDoNotDelete,
OwnedByRegistryRegistryDeletes,
NotOwnedByRegistry
};
enum ColorSpaceIndependence {
FULLY_INDEPENDENT,
TO_LAB16,
TO_RGBA8,
TO_RGBA16
};
class KoMixColorsOp;
class KoConvolutionOp;
/**
* A KoColorSpace is the definition of a certain color space.
*
* A color model and a color space are two related concepts. A color
* model is more general in that it describes the channels involved and
* how they in broad terms combine to describe a color. Examples are
* RGB, HSV, CMYK.
*
* A color space is more specific in that it also describes exactly how
* the channels are combined. So for each color model there can be a
* number of specific color spaces. So RGB is the model and sRGB,
* adobeRGB, etc are colorspaces.
*
* In Pigment KoColorSpace acts as both a color model and a color space.
* You can think of the class definition as the color model, but the
* instance of the class as representing a colorspace.
*
* A third concept is the profile represented by KoColorProfile. It
* represents the info needed to specialize a color model into a color
* space.
*
* KoColorSpace is an abstract class serving as an interface.
*
* Subclasses implement actual color spaces
* Some subclasses implement only some parts and are named Traits
*
*/
class KRITAPIGMENT_EXPORT KoColorSpace : public boost::equality_comparable
{
friend class KoColorSpaceRegistry;
friend class KoColorSpaceFactory;
protected:
/// Only for use by classes that serve as baseclass for real color spaces
KoColorSpace();
public:
/// Should be called by real color spaces
KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp);
virtual bool operator==(const KoColorSpace& rhs) const;
protected:
virtual ~KoColorSpace();
public:
//========== Gamut and other basic info ===================================//
/*
* @returns QPolygonF with 5*channel samples converted to xyY.
* maybe convert to 3d space in future?
*/
QPolygonF gamutXYY() const;
/*
* @returns a polygon with 5 samples per channel converted to xyY, but unlike
* gamutxyY it focuses on the luminance. This then can be used to visualise
* the approximate trc of a given colorspace.
*/
QPolygonF estimatedTRCXYY() const;
QVector lumaCoefficients() const;
//========== Channels =====================================================//
/// Return a list describing all the channels this color model has. The order
/// of the channels in the list is the order of channels in the pixel. To find
/// out the preferred display position, use KoChannelInfo::displayPosition.
QList channels() const;
/**
* The total number of channels for a single pixel in this color model
*/
virtual quint32 channelCount() const = 0;
/**
* Position of the alpha channel in a pixel
*/
virtual quint32 alphaPos() const = 0;
/**
* The total number of color channels (excludes alpha) for a single
* pixel in this color model.
*/
virtual quint32 colorChannelCount() const = 0;
/**
* returns a QBitArray that contains true for the specified
* channel types:
*
* @param color if true, set all color channels to true
* @param alpha if true, set all alpha channels to true
*
* The order of channels is the colorspace descriptive order,
* not the pixel order.
*/
QBitArray channelFlags(bool color = true, bool alpha = false) const;
/**
* The size in bytes of a single pixel in this color model
*/
virtual quint32 pixelSize() const = 0;
/**
* Return a string with the channel's value suitable for display in the gui.
*/
virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const = 0;
/**
* Return a string with the channel's value with integer
* channels normalised to the floating point range 0 to 1, if
* appropriate.
*/
virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const = 0;
/**
* Return a QVector of floats with channels' values normalized
* to floating point range 0 to 1.
*/
virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const = 0;
/**
* Write in the pixel the value from the normalized vector.
*/
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const = 0;
/**
* Convert the value of the channel at the specified position into
* an 8-bit value. The position is not the number of bytes, but
* the position of the channel as defined in the channel info list.
*/
virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelPos) const = 0;
/**
* Set dstPixel to the pixel containing only the given channel of srcPixel. The remaining channels
* should be set to whatever makes sense for 'empty' channels of this color space,
* with the intent being that the pixel should look like it only has the given channel.
*/
virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const = 0;
//========== Identification ===============================================//
/**
* ID for use in files and internally: unchanging name. As the id must be unique
* it is usually the concatenation of the id of the color model and of the color
* depth, for instance "RGBA8" or "CMYKA16" or "XYZA32f".
*/
QString id() const;
/**
* User visible name which contains the name of the color model and of the color depth.
* For instance "RGBA (8-bits)" or "CMYKA (16-bits)".
*/
QString name() const;
/**
* @return a string that identify the color model (for instance "RGB" or "CMYK" ...)
* @see KoColorModelStandardIds.h
*/
virtual KoID colorModelId() const = 0;
/**
* @return a string that identify the bit depth (for instance "U8" or "F16" ...)
* @see KoColorModelStandardIds.h
*/
virtual KoID colorDepthId() const = 0;
/**
* @return true if the profile given in argument can be used by this color space
*/
virtual bool profileIsCompatible(const KoColorProfile* profile) const = 0;
/**
* If false, images in this colorspace will degrade considerably by
* functions, tools and filters that have the given measure of colorspace
* independence.
*
* @param independence the measure to which this colorspace will suffer
* from the manipulations of the tool or filter asking
* @return false if no degradation will take place, true if degradation will
* take place
*/
virtual bool willDegrade(ColorSpaceIndependence independence) const = 0;
//========== Capabilities =================================================//
/**
* Tests if the colorspace offers the specific composite op.
*/
virtual bool hasCompositeOp(const QString & id) const;
/**
* Returns the list of user-visible composite ops supported by this colorspace.
*/
virtual QList compositeOps() const;
/**
* Retrieve a single composite op from the ones this colorspace offers.
* If the requeste composite op does not exist, COMPOSITE_OVER is returned.
*/
const KoCompositeOp * compositeOp(const QString & id) const;
/**
* add a composite op to this colorspace.
*/
virtual void addCompositeOp(const KoCompositeOp * op);
/**
* Returns true if the colorspace supports channel values outside the
* (normalised) range 0 to 1.
*/
virtual bool hasHighDynamicRange() const = 0;
//========== Display profiles =============================================//
/**
* Return the profile of this color space.
*/
virtual const KoColorProfile * profile() const = 0;
//================= Conversion functions ==================================//
/**
* The fromQColor methods take a given color defined as an RGB QColor
* and fills a byte array with the corresponding color in the
* the colorspace managed by this strategy.
*
* @param color the QColor that will be used to fill dst
* @param dst a pointer to a pixel
* @param profile the optional profile that describes the color values of QColor
*/
virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const = 0;
/**
* The toQColor methods take a byte array that is at least pixelSize() long
* and converts the contents to a QColor, using the given profile as a source
* profile and the optional profile as a destination profile.
*
* @param src a pointer to the source pixel
* @param c the QColor that will be filled with the color at src
* @param profile the optional profile that describes the color in c, for instance the monitor profile
*/
virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const = 0;
/**
* Convert the pixels in data to (8-bit BGRA) QImage using the specified profiles.
*
* @param data A pointer to a contiguous memory region containing width * height pixels
* @param width in pixels
* @param height in pixels
* @param dstProfile destination profile
* @param renderingIntent the rendering intent
* @param conversionFlags conversion flags
*/
virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height,
const KoColorProfile * dstProfile,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
/**
* Convert the specified data to Lab (D50). All colorspaces are guaranteed to support this
*
* @param src the source data
* @param dst the destination data
* @param nPixels the number of source pixels
*/
virtual void toLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const;
/**
* Convert the specified data from Lab (D50). to this colorspace. All colorspaces are
* guaranteed to support this.
*
* @param src the pixels in 16 bit lab format
* @param dst the destination data
* @param nPixels the number of pixels in the array
*/
virtual void fromLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const;
/**
* Convert the specified data to sRGB 16 bits. All colorspaces are guaranteed to support this
*
* @param src the source data
* @param dst the destination data
* @param nPixels the number of source pixels
*/
virtual void toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const;
/**
* Convert the specified data from sRGB 16 bits. to this colorspace. All colorspaces are
* guaranteed to support this.
*
* @param src the pixels in 16 bit rgb format
* @param dst the destination data
* @param nPixels the number of pixels in the array
*/
virtual void fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const;
/**
* Create a color conversion transformation.
*/
virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
/**
* Convert a byte array of srcLen pixels *src to the specified color space
* and put the converted bytes into the prepared byte array *dst.
*
* Returns false if the conversion failed, true if it succeeded
*
* This function is not thread-safe. If you want to apply multiple conversion
* in different threads at the same time, you need to create one color converter
* per-thread using createColorConverter.
*/
virtual bool convertPixelsTo(const quint8 * src,
quint8 * dst, const KoColorSpace * dstColorSpace,
quint32 numPixels,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
virtual KoColorConversionTransformation *createProofingTransform(const KoColorSpace * dstColorSpace,
const KoColorSpace * proofingSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::Intent proofingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags,
quint8 *gamutWarning, double adaptationState) const;
/**
* @brief proofPixelsTo
* @param src source
* @param dst destination
* @param numPixels the amount of pixels.
* @param proofingTransform the intent used for proofing.
* @return
*/
virtual bool proofPixelsTo(const quint8 * src,
quint8 * dst,
quint32 numPixels,
KoColorConversionTransformation *proofingTransform) const;
/**
* Convert @p nPixels pixels in @p src into their human-visible
* visual representation. The channel is shown as grayscale.
*
* Both buffers are in the same color space.
*
* @param src source buffer in (*this) color space
* @param dst destination buffer in the same color space as @p src
* @param nPixels length of the buffers in number of pixels
* @param pixelSize stride of each pixel in the destination buffer
* @param selectedChannelIndex Index of the selected channel.
*/
virtual void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const qint32 selectedChannelIndex) const = 0;
/**
* Convert @p nPixels pixels in @p src into their human-visible
* visual representation. The channels are shown as if other channels were null (or, if Lab, L = 1.0, *a = *b = 0.0).
*
* Both buffers are in the same color space.
*
* @param src source buffer in (*this) color space
* @param dst destination buffer in the same color space as @p src
* @param nPixels length of the buffers in number of pixels
* @param pixelSize stride of each pixel in the destination buffer
* @param selectedChannels Bitmap of selected channels
*/
virtual void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels) const = 0;
//============================== Manipulation functions ==========================//
//
// The manipulation functions have default implementations that _convert_ the pixel
// to a QColor and back. Reimplement these methods in your color strategy!
//
/**
* Get the alpha value of the given pixel, downscaled to an 8-bit value.
*/
virtual quint8 opacityU8(const quint8 * pixel) const = 0;
virtual qreal opacityF(const quint8 * pixel) const = 0;
/**
* Set the alpha channel of the given run of pixels to the given value.
*
* pixels -- a pointer to the pixels that will have their alpha set to this value
* alpha -- a downscaled 8-bit value for opacity
* nPixels -- the number of pixels
*
*/
virtual void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0;
virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const = 0;
/**
* Multiply the alpha channel of the given run of pixels by the given value.
*
* pixels -- a pointer to the pixels that will have their alpha set to this value
* alpha -- a downscaled 8-bit value for opacity
* nPixels -- the number of pixels
*
*/
virtual void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0;
/**
* Applies the specified 8-bit alpha mask to the pixels. We assume that there are just
* as many alpha values as pixels but we do not check this; the alpha values
* are assumed to be 8-bits.
*/
virtual void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0;
/**
* Applies the inverted 8-bit alpha mask to the pixels. We assume that there are just
* as many alpha values as pixels but we do not check this; the alpha values
* are assumed to be 8-bits.
*/
virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0;
/**
* Applies the specified float alpha mask to the pixels. We assume that there are just
* as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0
*/
virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0;
/**
* Applies the inverted specified float alpha mask to the pixels. We assume that there are just
* as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0
*/
virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0;
/**
* Fills \p pixels with specified \p brushColor and then applies inverted brush
* mask specified in \p alpha.
*/
virtual void fillInverseAlphaNormedFloatMaskWithColor(quint8 * pixels, const float * alpha, const quint8 *brushColor, qint32 nPixels) const = 0;
/**
* Fills \p dst with specified \p brushColor and then applies inverted brush
* mask specified in \p brush. Premultiplied red channel of the brush is
* used as an alpha channel for destination pixels.
*
* The equation is:
*
* dstC = colorC;
* dstA = qAlpha(brush) * (255 - qRed(brush)) / 255;
*/
virtual void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const = 0;
/**
* Fills \p dst with specified \p brushColor and then applies inverted brush
* mask specified in \p brush. Inverted red channel of the brush is used
* as lightness of the destination. Alpha channel of the brush is used as
* alpha of the destination.
*
* The equation is:
*
* dstL_hsl = preserveLightness(colorL_hsl, lightFactor);
* dstA = qAlpha(brush);
*
* For details on preserveLightness() formula,
* see KoColorSpacePreserveLightnessUtils.h
*/
virtual void fillGrayBrushWithColorAndLightnessOverlay(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const;
/**
* Create an adjustment object for adjusting the brightness and contrast
* transferValues is a 256 bins array with values from 0 to 0xFFFF
* This function is thread-safe, but you need to create one KoColorTransformation per thread.
*/
virtual KoColorTransformation *createBrightnessContrastAdjustment(const quint16 *transferValues) const = 0;
/**
* Create an adjustment object for adjusting individual channels
* transferValues is an array of colorChannelCount number of 256 bins array with values from 0 to 0xFFFF
* This function is thread-safe, but you need to create one KoColorTransformation per thread.
*
* The layout of the channels must be the following:
*
* 0..N-2 - color channels of the pixel;
* N-1 - alpha channel of the pixel (if exists)
*/
virtual KoColorTransformation *createPerChannelAdjustment(const quint16 * const* transferValues) const = 0;
/**
* Darken all color channels with the given amount. If compensate is true,
* the compensation factor will be used to limit the darkening.
*
*/
virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const = 0;
/**
* Invert color channels of the given pixels
* This function is thread-safe, but you need to create one KoColorTransformation per thread.
*/
virtual KoColorTransformation *createInvertTransformation() const = 0;
/**
* Get the difference between 2 colors, normalized in the range (0,255). Only completely
* opaque and completely transparent are taken into account when computing the difference;
* other transparency levels are not regarded when finding the difference.
+ *
+ * Completely transparent pixels are treated as if they are completely
+ * different from any non-transparent pixels.
*/
virtual quint8 difference(const quint8* src1, const quint8* src2) const = 0;
/**
* Get the difference between 2 colors, normalized in the range (0,255). This function
* takes the Alpha channel of the pixel into account. Alpha channel has the same
* weight as Lightness channel.
+ *
+ * Completely transparent pixels are treated as if their color channels are
+ * the same as ones of the other pixel. In other words, only alpha channel
+ * difference is compared.
*/
virtual quint8 differenceA(const quint8* src1, const quint8* src2) const = 0;
/**
* @return the mix color operation of this colorspace (do not delete it locally, it's deleted by the colorspace).
*/
virtual KoMixColorsOp* mixColorsOp() const;
/**
* @return the convolution operation of this colorspace (do not delete it locally, it's deleted by the colorspace).
*/
virtual KoConvolutionOp* convolutionOp() const;
/**
* Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible
*/
virtual quint8 intensity8(const quint8 * src) const = 0;
/*
*increase luminosity by step
*/
virtual void increaseLuminosity(quint8 * pixel, qreal step) const;
virtual void decreaseLuminosity(quint8 * pixel, qreal step) const;
virtual void increaseSaturation(quint8 * pixel, qreal step) const;
virtual void decreaseSaturation(quint8 * pixel, qreal step) const;
virtual void increaseHue(quint8 * pixel, qreal step) const;
virtual void decreaseHue(quint8 * pixel, qreal step) const;
virtual void increaseRed(quint8 * pixel, qreal step) const;
virtual void increaseGreen(quint8 * pixel, qreal step) const;
virtual void increaseBlue(quint8 * pixel, qreal step) const;
virtual void increaseYellow(quint8 * pixel, qreal step) const;
virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const = 0;
virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const = 0;
virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const = 0;
virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const = 0;
/**
* Compose two arrays of pixels together. If source and target
* are not the same color model, the source pixels will be
* converted to the target model. We're "dst" -- "dst" pixels are always in _this_
* colorspace.
*
* @param srcSpace the colorspace of the source pixels that will be composited onto "us"
* @param params the information needed for blitting e.g. the source and destination pixel data,
* the opacity and flow, ...
* @param op the composition operator to use, e.g. COPY_OVER
* @param renderingIntent the rendering intent
* @param conversionFlags the conversion flags.
*
*/
virtual void bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
/**
* Serialize this color following Create's swatch color specification available
* at https://web.archive.org/web/20110826002520/http://create.freedesktop.org/wiki/Swatches_-_colour_file_format/Draft
*
* This function doesn't create the \ element but rather the \,
* \, \ ... elements. It is assumed that colorElt is the \
* element.
*
* @param pixel buffer to serialized
* @param colorElt root element for the serialization, it is assumed that this
* element is \
* @param doc is the document containing colorElt
*/
virtual void colorToXML(const quint8* pixel, QDomDocument& doc, QDomElement& colorElt) const = 0;
/**
* Unserialize a color following Create's swatch color specification available
* at https://web.archive.org/web/20110826002520/http://create.freedesktop.org/wiki/Swatches_-_colour_file_format/Draft
*
* @param pixel buffer where the color will be unserialized
* @param elt the element to unserialize (\, \, \)
* @return the unserialize color, or an empty color object if the function failed
* to unserialize the color
*/
virtual void colorFromXML(quint8* pixel, const QDomElement& elt) const = 0;
KoColorTransformation* createColorTransformation(const QString & id, const QHash & parameters) const;
protected:
/**
* Use this function in the constructor of your colorspace to add the information about a channel.
* @param ci a pointer to the information about a channel
*/
virtual void addChannel(KoChannelInfo * ci);
const KoColorConversionTransformation* toLabA16Converter() const;
const KoColorConversionTransformation* fromLabA16Converter() const;
const KoColorConversionTransformation* toRgbA16Converter() const;
const KoColorConversionTransformation* fromRgbA16Converter() const;
/**
* Returns the thread-local conversion cache. If it doesn't exist
* yet, it is created. If it is currently too small, it is resized.
*/
QVector * threadLocalConversionCache(quint32 size) const;
/**
* This function defines the behavior of the bitBlt function
* when the composition of pixels in different colorspaces is
* requested, that is in case:
*
* srcCS == any
* dstCS == this
*
* 1) preferCompositionInSourceColorSpace() == false,
*
* the source pixels are first converted to *this color space
* and then composition is performed.
*
* 2) preferCompositionInSourceColorSpace() == true,
*
* the destination pixels are first converted into *srcCS color
* space, then the composition is done, and the result is finally
* converted into *this colorspace.
*
* This is used by alpha8() color space mostly, because it has
* weaker representation of the color, so the composition
* should be done in CS with richer functionality.
*/
virtual bool preferCompositionInSourceColorSpace() const;
struct Private;
Private * const d;
};
inline QDebug operator<<(QDebug dbg, const KoColorSpace *cs)
{
if (cs) {
dbg.nospace() << cs->name() << " (" << cs->colorModelId().id() << "," << cs->colorDepthId().id() << " )";
} else {
dbg.nospace() << "0x0";
}
return dbg.space();
}
#endif // KOCOLORSPACE_H
diff --git a/libs/psd/asl/kis_asl_xml_parser.cpp b/libs/psd/asl/kis_asl_xml_parser.cpp
index 47c35575e5..65e7634957 100644
--- a/libs/psd/asl/kis_asl_xml_parser.cpp
+++ b/libs/psd/asl/kis_asl_xml_parser.cpp
@@ -1,558 +1,580 @@
/*
* Copyright (c) 2015 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_asl_xml_parser.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_dom_utils.h"
#include "kis_debug.h"
#include "psd_utils.h"
#include "psd.h"
#include "compression.h"
#include "kis_asl_object_catcher.h"
namespace Private {
void parseElement(const QDomElement &el,
const QString &parentPath,
KisAslObjectCatcher &catcher);
class CurveObjectCatcher : public KisAslObjectCatcher
{
public:
void addText(const QString &path, const QString &value) override {
if (path == "/Nm ") {
m_name = value;
} else {
warnKrita << "XML (ASL): failed to parse curve object" << path << value;
}
}
void addPoint(const QString &path, const QPointF &value) override {
if (!m_arrayMode) {
warnKrita << "XML (ASL): failed to parse curve object (array fault)" << path << value << ppVar(m_arrayMode);
}
m_points.append(value);
}
public:
QVector m_points;
QString m_name;
};
QColor parseRGBColorObject(QDomElement parent)
{
QColor color(Qt::black);
QDomNode child = parent.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type != "Double") {
warnKrita << "Unknown color component type:" << ppVar(type) << ppVar(key);
return Qt::red;
}
double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
if (key == "Rd ") {
color.setRed(value);
} else if (key == "Grn ") {
color.setGreen(value);
} else if (key == "Bl ") {
color.setBlue(value);
} else {
warnKrita << "Unknown color key value:" << ppVar(key);
return Qt::red;
}
child = child.nextSibling();
}
return color;
}
void parseColorStopsList(QDomElement parent,
QVector &startLocations,
QVector &middleOffsets,
QVector &colors)
{
QDomNode child = parent.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
QString classId = childEl.attribute("classId", "");
if (type == "Descriptor" && classId == "Clrt") {
// sorry for naming...
QDomNode child = childEl.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
QString classId = childEl.attribute("classId", "");
if (type == "Integer" && key == "Lctn") {
int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
startLocations.append(qreal(value) / 4096.0);
} else if (type == "Integer" && key == "Mdpn") {
int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
middleOffsets.append(qreal(value) / 100.0);
} else if (type == "Descriptor" && key == "Clr ") {
colors.append(parseRGBColorObject(childEl));
} else if (type == "Enum" && key == "Type") {
QString typeId = childEl.attribute("typeId", "");
if (typeId != "Clry") {
warnKrita << "WARNING: Invalid typeId of a gradient stop type" << typeId;
}
QString value = childEl.attribute("value", "");
if (value == "BckC" || value == "FrgC") {
warnKrita << "WARNING: Using foreground/background colors in ASL gradients is not yet supported";
}
}
child = child.nextSibling();
}
} else {
warnKrita << "WARNING: Unrecognized object in color stops list" << ppVar(type) << ppVar(key) << ppVar(classId);
}
child = child.nextSibling();
}
}
void parseTransparencyStopsList(QDomElement parent,
QVector &startLocations,
QVector &middleOffsets,
QVector &transparencies)
{
QDomNode child = parent.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
QString classId = childEl.attribute("classId", "");
if (type == "Descriptor" && classId == "TrnS") {
// sorry for naming again...
QDomNode child = childEl.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type == "Integer" && key == "Lctn") {
int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
startLocations.append(qreal(value) / 4096.0);
} else if (type == "Integer" && key == "Mdpn") {
int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
middleOffsets.append(qreal(value) / 100.0);
} else if (type == "UnitFloat" && key == "Opct") {
QString unit = childEl.attribute("unit", "");
if (unit != "#Prc") {
warnKrita << "WARNING: Invalid unit of a gradient stop transparency" << unit;
}
qreal value = KisDomUtils::toDouble(childEl.attribute("value", "100"));
transparencies.append(value / 100.0);
}
child = child.nextSibling();
}
} else {
warnKrita << "WARNING: Unrecognized object in transparency stops list" << ppVar(type) << ppVar(key) << ppVar(classId);
}
child = child.nextSibling();
}
}
inline QString buildPath(const QString &parent, const QString &key) {
return parent + "/" + key;
}
bool tryParseDescriptor(const QDomElement &el,
const QString &path,
const QString &classId,
KisAslObjectCatcher &catcher)
{
bool retval = true;
if (classId == "null") {
catcher.newStyleStarted();
// here we just notify that a new style is started, we haven't
// processed the whole block yet, so return false.
retval = false;
} else if (classId == "RGBC") {
catcher.addColor(path, parseRGBColorObject(el));
} else if (classId == "ShpC") {
CurveObjectCatcher curveCatcher;
QDomNode child = el.firstChild();
while (!child.isNull()) {
parseElement(child.toElement(), "", curveCatcher);
child = child.nextSibling();
}
catcher.addCurve(path, curveCatcher.m_name, curveCatcher.m_points);
} else if (classId == "CrPt") {
QPointF point;
QDomNode child = el.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type == "Boolean" && key == "Cnty") {
warnKrita << "WARNING: tryParseDescriptor: The points of the curve object contain \'Cnty\' flag which is unsupported by Krita";
warnKrita << " " << ppVar(type) << ppVar(key) << ppVar(path);
child = child.nextSibling();
continue;
}
if (type != "Double") {
warnKrita << "Unknown point component type:" << ppVar(type) << ppVar(key) << ppVar(path);
return false;
}
double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
if (key == "Hrzn") {
point.setX(value);
} else if (key == "Vrtc") {
point.setY(value);
} else {
warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path);
return false;
}
child = child.nextSibling();
}
catcher.addPoint(path, point);
} else if (classId == "Pnt ") {
QPointF point;
QDomNode child = el.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
QString unit = childEl.attribute("unit", "");
if (type != "Double" && !(type == "UnitFloat" && unit == "#Prc")) {
warnKrita << "Unknown point component type:" << ppVar(unit) << ppVar(type) << ppVar(key) << ppVar(path);
return false;
}
double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
if (key == "Hrzn") {
point.setX(value);
} else if (key == "Vrtc") {
point.setY(value);
} else {
warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path);
return false;
}
child = child.nextSibling();
}
catcher.addPoint(path, point);
} else if (classId == "KisPattern") {
QByteArray patternData;
QString patternUuid;
QDomNode child = el.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type == "Text" && key == "Idnt") {
patternUuid = childEl.attribute("value", "");
}
if (type == "KisPatternData" && key == "Data") {
QDomNode dataNode = child.firstChild();
if (!dataNode.isCDATASection()) {
warnKrita << "WARNING: failed to parse KisPatternData XML section!";
continue;
}
QDomCDATASection dataSection = dataNode.toCDATASection();
QByteArray data = dataSection.data().toLatin1();
data = QByteArray::fromBase64(data);
data = qUncompress(data);
if (data.isEmpty()) {
warnKrita << "WARNING: failed to parse KisPatternData XML section!";
continue;
}
patternData = data;
}
child = child.nextSibling();
}
if (!patternUuid.isEmpty() && !patternData.isEmpty()) {
QString fileName = QString("%1.pat").arg(patternUuid);
QSharedPointer pattern(new KoPattern(fileName));
QBuffer buffer(&patternData);
buffer.open(QIODevice::ReadOnly);
pattern->loadPatFromDevice(&buffer);
catcher.addPattern(path, pattern, patternUuid);
} else {
warnKrita << "WARNING: failed to load KisPattern XML section!" << ppVar(patternUuid);
}
} else if (classId == "Ptrn") { // reference to an existing pattern
QString patternUuid;
QString patternName;
QDomNode child = el.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type == "Text" && key == "Idnt") {
patternUuid = childEl.attribute("value", "");
} else if (type == "Text" && key == "Nm ") {
patternName = childEl.attribute("value", "");
} else {
warnKrita << "WARNING: unrecognized pattern-ref section key:" << ppVar(type) << ppVar(key);
}
child = child.nextSibling();
}
catcher.addPatternRef(path, patternUuid, patternName);
} else if (classId == "Grdn") {
QString gradientName;
qreal gradientSmoothness = 100.0;
QVector startLocations;
QVector middleOffsets;
QVector colors;
QVector transpStartLocations;
QVector transpMiddleOffsets;
QVector transparencies;
QDomNode child = el.firstChild();
while (!child.isNull()) {
QDomElement childEl = child.toElement();
QString type = childEl.attribute("type", "");
QString key = childEl.attribute("key", "");
if (type == "Text" && key == "Nm ") {
gradientName = childEl.attribute("value", "");
} else if (type == "Enum" && key == "GrdF") {
QString typeId = childEl.attribute("typeId", "");
QString value = childEl.attribute("value", "");
if (typeId != "GrdF" || value != "CstS") {
warnKrita << "WARNING: Unsupported gradient type (porbably, noise-based):" << value;
return true;
}
} else if (type == "Double" && key == "Intr") {
double value = KisDomUtils::toDouble(childEl.attribute("value", "4096"));
gradientSmoothness = 100.0 * value / 4096.0;
} else if (type == "List" && key == "Clrs") {
parseColorStopsList(childEl, startLocations, middleOffsets, colors);
} else if (type == "List" && key == "Trns") {
parseTransparencyStopsList(childEl, transpStartLocations, transpMiddleOffsets, transparencies);
}
child = child.nextSibling();
}
- if (colors.size() < 2) {
- warnKrita << "WARNING: ASL gradient has too few stops" << ppVar(colors.size());
+
+ if (colors.size() < transparencies.size()) {
+ const QColor lastColor = !colors.isEmpty() ? colors.last() : QColor(Qt::black);
+ while (colors.size() != transparencies.size()) {
+ const int index = colors.size();
+ colors.append(lastColor);
+ startLocations.append(transpStartLocations[index]);
+ middleOffsets.append(transpMiddleOffsets[index]);
+ }
}
- if (colors.size() != transparencies.size()) {
- warnKrita << "WARNING: ASL gradient has inconsistent number of transparency stops. Dropping transparency..." << ppVar(colors.size()) << ppVar(transparencies.size());
- transparencies.resize(colors.size());
- for (int i = 0; i < colors.size(); i++) {
- transparencies[i] = 1.0;
+ if (colors.size() > transparencies.size()) {
+ const qreal lastTransparency = !transparencies.isEmpty() ? transparencies.last() : 1.0;
+ while (colors.size() != transparencies.size()) {
+ const int index = transparencies.size();
+ transparencies.append(lastTransparency);
+ transpStartLocations.append(startLocations[index]);
+ transpMiddleOffsets.append(middleOffsets[index]);
}
}
+ if (colors.size() == 1) {
+ colors.append(colors.last());
+ startLocations.append(1.0);
+ middleOffsets.append(0.5);
+
+ transparencies.append(transparencies.last());
+ transpStartLocations.append(1.0);
+ transpMiddleOffsets.append(0.5);
+ }
+
QString fileName = gradientName + ".ggr";
QSharedPointer gradient(new KoSegmentGradient(fileName));
Q_UNUSED(gradientSmoothness);
gradient->setName(gradientName);
- for (int i = 1; i < colors.size(); i++) {
- QColor startColor = colors[i-1];
- QColor endColor = colors[i];
- startColor.setAlphaF(transparencies[i-1]);
- endColor.setAlphaF(transparencies[i]);
-
- qreal start = startLocations[i-1];
- qreal end = startLocations[i];
- qreal middle = start + middleOffsets[i-1] * (end - start);
-
- gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB,
- start, end, middle,
- startColor,
- endColor);
+ if (colors.size() >= 2) {
+ for (int i = 1; i < colors.size(); i++) {
+ QColor startColor = colors[i-1];
+ QColor endColor = colors[i];
+ startColor.setAlphaF(transparencies[i-1]);
+ endColor.setAlphaF(transparencies[i]);
+
+ qreal start = startLocations[i-1];
+ qreal end = startLocations[i];
+ qreal middle = start + middleOffsets[i-1] * (end - start);
+
+ gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB,
+ start, end, middle,
+ startColor,
+ endColor);
+ }
+ gradient->setValid(true);
+ } else {
+ gradient->setValid(false);
}
- gradient->setValid(true);
-
catcher.addGradient(path, gradient);
} else {
retval = false;
}
return retval;
}
void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher)
{
KIS_ASSERT_RECOVER_RETURN(el.tagName() == "node");
QString type = el.attribute("type", "");
QString key = el.attribute("key", "");
if (type == "Descriptor") {
QString classId = el.attribute("classId", "");
QString containerName = key.isEmpty() ? classId : key;
QString containerPath = buildPath(parentPath, containerName);
if (!tryParseDescriptor(el, containerPath, classId, catcher)) {
QDomNode child = el.firstChild();
while (!child.isNull()) {
parseElement(child.toElement(), containerPath, catcher);
child = child.nextSibling();
}
}
} else if (type == "List") {
catcher.setArrayMode(true);
QString containerName = key;
QString containerPath = buildPath(parentPath, containerName);
QDomNode child = el.firstChild();
while (!child.isNull()) {
parseElement(child.toElement(), containerPath, catcher);
child = child.nextSibling();
}
catcher.setArrayMode(false);
} else if (type == "Double") {
double v = KisDomUtils::toDouble(el.attribute("value", "0"));
catcher.addDouble(buildPath(parentPath, key), v);
} else if (type == "UnitFloat") {
QString unit = el.attribute("unit", "");
double v = KisDomUtils::toDouble(el.attribute("value", "0"));
catcher.addUnitFloat(buildPath(parentPath, key), unit, v);
} else if (type == "Text") {
QString v = el.attribute("value", "");
catcher.addText(buildPath(parentPath, key), v);
} else if (type == "Enum") {
QString v = el.attribute("value", "");
QString typeId = el.attribute("typeId", "");
catcher.addEnum(buildPath(parentPath, key), typeId, v);
} else if (type == "Integer") {
int v = KisDomUtils::toInt(el.attribute("value", "0"));
catcher.addInteger(buildPath(parentPath, key), v);
} else if (type == "Boolean") {
int v = KisDomUtils::toInt(el.attribute("value", "0"));
catcher.addBoolean(buildPath(parentPath, key), v);
} else {
warnKrita << "WARNING: XML (ASL) Unknown element type:" << type << ppVar(parentPath) << ppVar(key);
}
}
} // namespace
void KisAslXmlParser::parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher)
{
QDomElement root = doc.documentElement();
if (root.tagName() != "asl") {
return;
}
QDomNode child = root.firstChild();
while (!child.isNull()) {
Private::parseElement(child.toElement(), "", catcher);
child = child.nextSibling();
}
}
diff --git a/libs/psd/asl/kis_asl_xml_writer.cpp b/libs/psd/asl/kis_asl_xml_writer.cpp
index 7e3323e81a..94743f71b4 100644
--- a/libs/psd/asl/kis_asl_xml_writer.cpp
+++ b/libs/psd/asl/kis_asl_xml_writer.cpp
@@ -1,398 +1,399 @@
/*
* Copyright (c) 2015 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_asl_xml_writer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include