https://wiki.inkscape.org/wiki/api.php?action=feedcontributions&user=Jaspervdg&feedformat=atomInkscape Wiki - User contributions [en]2022-11-28T05:48:57ZUser contributionsMediaWiki 1.36.1https://wiki.inkscape.org/wiki/index.php?title=CompilingUbuntu&diff=85184CompilingUbuntu2012-05-30T17:12:19Z<p>Jaspervdg: /* Hardy(8.04), Intrepid(8.10) and Jaunty(9.04) */</p>
<hr />
<div>== Hardy(8.04), Intrepid(8.10), Jaunty(9.04) and newer ==<br />
=== Consider using stable (recommended for production) ===<br />
This is a short how to build the latest svn version. Please note that SVN version may be buggy and crash often. This is released for people who want to help testing or need the very latest features. If you are not of developer kind, you are suggested to install the stable version from the repositories using Synaptic or from command line:<br />
<br />
<pre><br />
sudo apt-get install inkscape<br />
</pre><br />
<br />
=== Using prebuilt packages (recommended) ===<br />
For Ubuntu there are nightly builds available. <br />
<br />
Get your appropriate repository lines from launchpad (read about [https://help.ubuntu.com/community/Repositories/Ubuntu adding repositories]):<br />
<br />
https://launchpad.net/~inkscape-nightly/+archive/ppa<br />
<br />
<br />
Run following command to update the repository information and install inkscape:<br />
<pre> sudo apt-get update<br />
sudo apt-get install inkscape-devel<br />
</pre><br />
<br />
=== Compiling unstable developement version ===<br />
==== Installing dependencies ====<br />
If you are sure you can face Inkscape being unstable, then please continue reading. First you should install all the [[Tracking Dependencies|dependencies]]. This can be done by:<br />
<br />
<pre><br />
sudo apt-get install build-essential autoconf automake intltool libtool \<br />
libglib2.0-dev libpng12-dev libgc-dev libfreetype6-dev liblcms1-dev \<br />
libgtkmm-2.4-dev libxslt1-dev libboost-dev libpopt-dev libgsl0-dev libaspell-dev<br />
</pre><br />
<br />
Now you should have every dependency you need to build Inkscape.<br />
<br />
===== Additional dependencies =====<br />
If you want to have pdf support you need to install poppler:<br />
<br />
<pre><br />
sudo apt-get install libpoppler-dev libpoppler-glib-dev<br />
</pre><br />
<br />
If you want to have optional features you may need to install some more packages:<br />
<br />
<pre><br />
sudo apt-get install libgnome-vfsmm-2.6-dev libssl-dev libmagick++9-dev libwpg-dev<br />
</pre><br />
<br />
==== Getting source from Bazaar ====<br />
Inkscape now uses Bazaar, please refer to the [[Working with Bazaar]] page for details on how to get the Inkscape source code.<br />
<br />
==== Configuring and Compiling ====<br />
Enter the newly created inkscape directory.<br />
<br />
<pre><br />
cd inkscape<br />
</pre><br />
<br />
As you may have already noticed this folder contains some files with all CAPITAL letters like README, INSTALL, HACKING, COPYING and probably others. These contain the latest information about how to build the program. The README file says that if you have no configure script in the current directory you should run autogen script to create it:<br />
<br />
<pre><br />
./autogen.sh<br />
</pre><br />
<br />
Now run configure script which detects your system variables, installed software etc.:<br />
<br />
<pre><br />
./configure<br />
</pre><br />
<br />
or, if you want to make it install to an alternate location so that you can keep the standard version installed and untouched<br />
<br />
<code><br />
./configure --prefix=/home/''yourname''/opt/local<br />
</code><br />
(replacing "yourname" with your actual directory user name, of course)<br />
''All bug reporting testers may find it useful to install to use --prefix=/home/''yourname''/opt/inkscape-revision-19900 or --prefix=/opt/inkscape-19900 or something similar, replacing the revision number with correct one (this is shown when svn fetching finishes, also can be found in file .svn/entries). This way you can have several versions of inkscape installed at once.''<br />
<br />
If the configure script ends with no error messages, you are the lucky one, all system requirements are met. Run make to compile.<br />
<br />
<pre><br />
make<br />
</pre><br />
<br />
This may take some time, probably hours, depending on your machine's speed. On 1,4Ghz P3M with 512Mb clean build took 100 minutes.<br />
<br />
==== Installing ====<br />
<br />
If you used some --prefix=/... other than /usr, then you may install using usual 'make install' or 'sudo make install', depending on the location.<br />
If the the location prefix was /usr, then "sudo make install" is not recommended, as debian package manager would know nothing about new package. The better alternative is using checkinstall. If checkinstall is not installed, you can install it the usual way "sudo apt-get install checkinstall".<br />
<br />
<pre><br />
sudo checkinstall<br />
</pre><br />
<br />
Happy inkscapeing.<br />
<br />
===== Fix no icons problem =====<br />
<br />
If you run this and you find that you have no tool icons it's because it's looking in the wrong place for them. To fix that you need to make a symbolic link to the correct location. Here is an example:<br />
<br />
<pre><br />
sudo ln -s /usr/share/inkscape /usr/local/share/inkscape<br />
</pre><br />
<br />
==== Update your version ====<br />
<br />
If you want to update your already built inkscape to the very latest version, you need to run following commands in inkscape source directory. Please correct the configure line and use the same installation method as on first install.<br />
<br />
<pre><br />
bzr update<br />
./configure --prefix=/home/''yourname''/opt/local<br />
make<br />
make install<br />
</pre><br />
<br />
== Dapper(6.06) and Edgy(6.10) ==<br />
If you're going to build Inkscape, you'll need to have a full complement of build requirements. This is very easy to do in Ubuntu Dapper and Edgy:<br />
<br />
Note: the libgc-6.7 that is available in Edgy removes the need for the following:<br />
<br />
<pre><br />
sudo apt-get build-dep inkscape<br />
sudo apt-get install liblcms-dev build-essential<br />
echo "deb-src http://ftp.us.debian.org/debian/ unstable main" >> /etc/apt/sources.list<br />
sudo apt-get update<br />
sudo apt-get source libgc-dev<br />
sudo apt-get install fakeroot debhelper<br />
cd libgc*<br />
sudo fakeroot dpkg-buildpackage -uc -us<br />
sudo dpkg -i ../libgc*.deb<br />
</pre><br />
<br />
If you want version 0.44 from Debian Unstable, you can compile it in the same way as libgc above:<br />
<br />
<pre><br />
apt-get source inkscape<br />
cd inkscape*<br />
fakeroot dpkg-buildpackage -uc -us<br />
sudo dpkg -i ../inkscape*.deb<br />
</pre><br />
<br />
To build the SVN snapshots:<br />
<br />
<pre><br />
# Untar and navigate to the inkscape source folder<br />
./configure<br />
make<br />
sudo make install<br />
</pre><br />
<br />
Instead of doing "make install", on Debian-based distributions (such as Ubuntu) it is better to do<br />
<pre><br />
sudo checkinstall<br />
</pre><br />
since checkinstall first builds the .deb package and then installs it, thus making the package system aware of the newly installed inkscape.<br />
If you get the "command not found" message, do<br />
<pre><br />
sudo apt-get install checkinstall<br />
</pre><br />
<br />
<br />
'''Notes:'''<br />
build-dep gets all the dependencies for the version of Inkscape that comes with Ubuntu. We're not building the same version, but most of the dependencies are the same. <br />
<br />
<br />
libcms-dev was required for ./configure to work<br />
<br />
<br />
This was done on a recently installed Dapper (Ubuntu 6.06) system. I built Inkscape version 0.44.<br />
<br />
<br />
<br />
<br />
The following packages are need to compile cvs inkscape under a default Ubuntu Hoary/Breezy/Dapper system:<br />
<pre><br />
apt-get install cvs build-essential intltool libtool libgtkmm-2.4-dev \<br />
libglib2.0-dev libpng12-dev libxslt1-dev libsigc++-2.0-dev libpopt-dev libgc-dev<br />
</pre><br />
<br />
Inkscape requires libgc-6.7.<br />
<br />
Breezy uses 6.4, Dapper uses 6.6, Edgy uses 6.7<br />
<br />
Hoary uses version 6.3, which is provided in the Repos. (Is there somewhere to get a .deb for 6.4?)<br />
<br />
To overwrite libgc-6.3 with libgc-6.4:<br />
Download gc6.4<br />
./configure --prefix=/usr<br />
make<br />
sudo make install<br />
<br />
== Old libgc 6.5 debs for Breezy(5.10) ==<br />
<br />
http://inkscape.modevia.com/ap/libgc-dev_6.5-1_i386.deb<br />
http://inkscape.modevia.com/ap/libgc1_6.5-1_i386.deb<br />
<br />
[[Category:Developer Documentation]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=CompilingUbuntu&diff=85178CompilingUbuntu2012-05-30T17:10:34Z<p>Jaspervdg: /* Installing dependencies */ Added libtool</p>
<hr />
<div>== Hardy(8.04), Intrepid(8.10) and Jaunty(9.04) ==<br />
=== Consider using stable (recommended for production) ===<br />
This is a short how to build the latest svn version. Please note that SVN version may be buggy and crash often. This is released for people who want to help testing or need the very latest features. If you are not of developer kind, you are suggested to install the stable version from the repositories using Synaptic or from command line:<br />
<br />
<pre><br />
sudo apt-get install inkscape<br />
</pre><br />
<br />
=== Using prebuilt packages (recommended) ===<br />
For Ubuntu there are nightly builds available. <br />
<br />
Get your appropriate repository lines from launchpad (read about [https://help.ubuntu.com/community/Repositories/Ubuntu adding repositories]):<br />
<br />
https://launchpad.net/~inkscape-nightly/+archive/ppa<br />
<br />
<br />
Run following command to update the repository information and install inkscape:<br />
<pre> sudo apt-get update<br />
sudo apt-get install inkscape-devel<br />
</pre><br />
<br />
=== Compiling unstable developement version ===<br />
==== Installing dependencies ====<br />
If you are sure you can face Inkscape being unstable, then please continue reading. First you should install all the [[Tracking Dependencies|dependencies]]. This can be done by:<br />
<br />
<pre><br />
sudo apt-get install build-essential autoconf automake intltool libtool \<br />
libglib2.0-dev libpng12-dev libgc-dev libfreetype6-dev liblcms1-dev \<br />
libgtkmm-2.4-dev libxslt1-dev libboost-dev libpopt-dev libgsl0-dev libaspell-dev<br />
</pre><br />
<br />
Now you should have every dependency you need to build Inkscape.<br />
<br />
===== Additional dependencies =====<br />
If you want to have pdf support you need to install poppler:<br />
<br />
<pre><br />
sudo apt-get install libpoppler-dev libpoppler-glib-dev<br />
</pre><br />
<br />
If you want to have optional features you may need to install some more packages:<br />
<br />
<pre><br />
sudo apt-get install libgnome-vfsmm-2.6-dev libssl-dev libmagick++9-dev libwpg-dev<br />
</pre><br />
<br />
==== Getting source from Bazaar ====<br />
Inkscape now uses Bazaar, please refer to the [[Working with Bazaar]] page for details on how to get the Inkscape source code.<br />
<br />
==== Configuring and Compiling ====<br />
Enter the newly created inkscape directory.<br />
<br />
<pre><br />
cd inkscape<br />
</pre><br />
<br />
As you may have already noticed this folder contains some files with all CAPITAL letters like README, INSTALL, HACKING, COPYING and probably others. These contain the latest information about how to build the program. The README file says that if you have no configure script in the current directory you should run autogen script to create it:<br />
<br />
<pre><br />
./autogen.sh<br />
</pre><br />
<br />
Now run configure script which detects your system variables, installed software etc.:<br />
<br />
<pre><br />
./configure<br />
</pre><br />
<br />
or, if you want to make it install to an alternate location so that you can keep the standard version installed and untouched<br />
<br />
<code><br />
./configure --prefix=/home/''yourname''/opt/local<br />
</code><br />
(replacing "yourname" with your actual directory user name, of course)<br />
''All bug reporting testers may find it useful to install to use --prefix=/home/''yourname''/opt/inkscape-revision-19900 or --prefix=/opt/inkscape-19900 or something similar, replacing the revision number with correct one (this is shown when svn fetching finishes, also can be found in file .svn/entries). This way you can have several versions of inkscape installed at once.''<br />
<br />
If the configure script ends with no error messages, you are the lucky one, all system requirements are met. Run make to compile.<br />
<br />
<pre><br />
make<br />
</pre><br />
<br />
This may take some time, probably hours, depending on your machine's speed. On 1,4Ghz P3M with 512Mb clean build took 100 minutes.<br />
<br />
==== Installing ====<br />
<br />
If you used some --prefix=/... other than /usr, then you may install using usual 'make install' or 'sudo make install', depending on the location.<br />
If the the location prefix was /usr, then "sudo make install" is not recommended, as debian package manager would know nothing about new package. The better alternative is using checkinstall. If checkinstall is not installed, you can install it the usual way "sudo apt-get install checkinstall".<br />
<br />
<pre><br />
sudo checkinstall<br />
</pre><br />
<br />
Happy inkscapeing.<br />
<br />
===== Fix no icons problem =====<br />
<br />
If you run this and you find that you have no tool icons it's because it's looking in the wrong place for them. To fix that you need to make a symbolic link to the correct location. Here is an example:<br />
<br />
<pre><br />
sudo ln -s /usr/share/inkscape /usr/local/share/inkscape<br />
</pre><br />
<br />
==== Update your version ====<br />
<br />
If you want to update your already built inkscape to the very latest version, you need to run following commands in inkscape source directory. Please correct the configure line and use the same installation method as on first install.<br />
<br />
<pre><br />
bzr update<br />
./configure --prefix=/home/''yourname''/opt/local<br />
make<br />
make install<br />
</pre><br />
<br />
== Dapper(6.06) and Edgy(6.10) ==<br />
If you're going to build Inkscape, you'll need to have a full complement of build requirements. This is very easy to do in Ubuntu Dapper and Edgy:<br />
<br />
Note: the libgc-6.7 that is available in Edgy removes the need for the following:<br />
<br />
<pre><br />
sudo apt-get build-dep inkscape<br />
sudo apt-get install liblcms-dev build-essential<br />
echo "deb-src http://ftp.us.debian.org/debian/ unstable main" >> /etc/apt/sources.list<br />
sudo apt-get update<br />
sudo apt-get source libgc-dev<br />
sudo apt-get install fakeroot debhelper<br />
cd libgc*<br />
sudo fakeroot dpkg-buildpackage -uc -us<br />
sudo dpkg -i ../libgc*.deb<br />
</pre><br />
<br />
If you want version 0.44 from Debian Unstable, you can compile it in the same way as libgc above:<br />
<br />
<pre><br />
apt-get source inkscape<br />
cd inkscape*<br />
fakeroot dpkg-buildpackage -uc -us<br />
sudo dpkg -i ../inkscape*.deb<br />
</pre><br />
<br />
To build the SVN snapshots:<br />
<br />
<pre><br />
# Untar and navigate to the inkscape source folder<br />
./configure<br />
make<br />
sudo make install<br />
</pre><br />
<br />
Instead of doing "make install", on Debian-based distributions (such as Ubuntu) it is better to do<br />
<pre><br />
sudo checkinstall<br />
</pre><br />
since checkinstall first builds the .deb package and then installs it, thus making the package system aware of the newly installed inkscape.<br />
If you get the "command not found" message, do<br />
<pre><br />
sudo apt-get install checkinstall<br />
</pre><br />
<br />
<br />
'''Notes:'''<br />
build-dep gets all the dependencies for the version of Inkscape that comes with Ubuntu. We're not building the same version, but most of the dependencies are the same. <br />
<br />
<br />
libcms-dev was required for ./configure to work<br />
<br />
<br />
This was done on a recently installed Dapper (Ubuntu 6.06) system. I built Inkscape version 0.44.<br />
<br />
<br />
<br />
<br />
The following packages are need to compile cvs inkscape under a default Ubuntu Hoary/Breezy/Dapper system:<br />
<pre><br />
apt-get install cvs build-essential intltool libtool libgtkmm-2.4-dev \<br />
libglib2.0-dev libpng12-dev libxslt1-dev libsigc++-2.0-dev libpopt-dev libgc-dev<br />
</pre><br />
<br />
Inkscape requires libgc-6.7.<br />
<br />
Breezy uses 6.4, Dapper uses 6.6, Edgy uses 6.7<br />
<br />
Hoary uses version 6.3, which is provided in the Repos. (Is there somewhere to get a .deb for 6.4?)<br />
<br />
To overwrite libgc-6.3 with libgc-6.4:<br />
Download gc6.4<br />
./configure --prefix=/usr<br />
make<br />
sudo make install<br />
<br />
== Old libgc 6.5 debs for Breezy(5.10) ==<br />
<br />
http://inkscape.modevia.com/ap/libgc-dev_6.5-1_i386.deb<br />
http://inkscape.modevia.com/ap/libgc1_6.5-1_i386.deb<br />
<br />
[[Category:Developer Documentation]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=TestingInkscape&diff=78068TestingInkscape2012-02-24T13:35:09Z<p>Jaspervdg: Redirected page to Testing Inkscape</p>
<hr />
<div>#REDIRECT [[Testing Inkscape]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Compiling_Inkscape_on_Windows_32-bit&diff=76622Compiling Inkscape on Windows 32-bit2012-01-11T18:25:39Z<p>Jaspervdg: /* Setting up the build environment */ Changed link to TDM-GCC to point to the page that should always have the latest version.</p>
<hr />
<div>Inkscape was originally written for Linux, but it has been ported to other platforms, including Windows. Since Windows is not POSIX compliant and doesn't have several features useful to developers (like package management), compiling Inkscape on Windows is more tedious than on Linux, but perfectly possible. To make it easier, we have compiled a package that contains all the libraries you need to build Inkscape. This reduces the effort of compiling Inkscape to: download and install 3 programs, download library package, download sourcecode, and you are ready to go.<br />
<br />
==Setting up the build environment==<br />
<br />
To develop Inkscape, you will need the following things:<br />
<br />
* [http://wiki.bazaar.canonical.com/WindowsDownloads Bazaar]<br />
* [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html PuTTY] programs: puttygen.exe and pageant.exe<br />
* [http://tdm-gcc.tdragon.net/download TDM's GCC (MingW)], the 32 bit bundle installer is the safe choice (it's called tdm-gcc-4.something and should be one of the very first options).<br />
* Launchpad account<br />
<br />
In order to build the installer (not needed for most developers):<br />
* [http://sourceforge.net/projects/nsis/files/NSIS%202/2.46/nsis-2.46-setup.exe/download NSIS 2.46]<br />
<br />
<br />
===Install the compiler===<br />
Run the TDM-MinGW installer and install it in a path that doesn't contain spaces, like C:\mingw. If you install it into another path, set the environment variable MINGW_PATH to the TDM-MinGW installation directory, e.g. the one containing <tt>README-tdm-gcc.txt</tt> (right click My Computer -> Properties -> Advanced -> Environment Variables). During the installation, enable the "openmp support" checkbox from the components list or choose to install all packages (option "TDM-GCC recommended, All Packages" in the TDM-GCC (4.5.1) installer).<br />
<br />
If you have an older version of TDM-GCC (older than 4.5.1?), copy the file "\lib\gcc\mingw32\bin\libgomp-1.dll" to "\bin\libgomp-1.dll" (paths relative to your installation directory).<br />
<br />
===Create your Launchpad account===<br />
If you do not have an SSH public/private key pair to identify yourself:<br />
*run the program puttygen.exe to generate an SSH key<br />
*save both its parts.<br />
Log into your Launchpad account, go to your profile page and add the public part of the generated key to the list of SSH keys. Run the program pageant.exe (you can add it to Autorun). A tray icon should appear. Right click it, select "Add Key" and pick the private key file you have just generated from the dialog. Note that you need to repeat this after every login whenever you want to access Launchpad.<br />
<br />
Now set up Bazaar. First tell it who you are, then associate with your Launchpad account. You need to use the account name (e.g. johnq), not the display name.(John Q. Public).<br />
<br />
C:\> bzr whoami "''Your Name'' <''your_real_email@example.com''>"<br />
C:\> bzr launchpad-login ''your_launchpad_account''<br />
<br />
===Install the developer libraries===<br />
Check out Inkscape Devlibs into C:\devlibs. If you check them out elsewhere, set the environment variable DEVLIBS_PATH to the path where they are. Devlibs are a bundle of all the libraries needed to compile Inkscape. If you experience any problems, make sure you have an up to date copy of those libraries and an up to date checkout of Inkscape source. To reduce the size of the download, pass the <tt>--lightweight</tt> parameter.<br />
<br />
C:\> bzr checkout --lightweight lp:inkscape-devlibs devlibs<br />
<br />
To update devlibs:<br />
<br />
C:\devlibs> bzr update<br />
<br />
All Inkscape developers can commit to the devlibs trunk. Advanced information about Devlibs, mainy useful when you want to update them to newly released versions of upstream libraries, is available here: [[Inkscape Devlibs]].<br />
You can see some infomation from [https://launchpad.net/inkscape-devlibs launchpad:inkscape-devlibs] and [http://bazaar.launchpad.net/~inkscape.dev/inkscape-devlibs/trunk/files trunk/files].<br />
<br />
== Obtaining Inkscape source code ==<br />
<br />
You can obtain released Inkscape source from a tarball. Since version 0.47 they are hosted on [https://launchpad.net/inkscape Inkscape's Launchpad page]. There are ready-made installers provided, so there's usually little reason to compile the stable version yourself.<br />
<br />
To obtain cutting edge code, check out Inkscape source from the Bazaar repository. You can also use the TortoiseBZR shell extensions to do this. The recommended way is to first create a shared repository, then check out the Inkscape branch into that shared repository. Using this setup, branching will be a lot faster.<br />
<br />
C:\src\inkscape> bzr init-repo --rich-root<br />
C:\src\inkscape> bzr checkout lp:inkscape trunk<br />
<br />
If you don't want to create any branches, you can skip the shared repository step.<br />
<br />
C:\src> bzr checkout lp:inkscape<br />
<br />
'''IMPORTANT:''' make sure that the path to your Inkscape source checkout does not contain spaces. Unix tools do not like them and you will end up with a lot of error messages about missing files.<br />
<br />
== Building Inkscape ==<br />
<br />
Open the command prompt, navigate to the directory with Inkscape sources. First set up some environmental variables. You only need to do this once per console session.<br />
<br />
C:\src\inkscape\trunk> mingwenv<br />
<br />
Now compile the build tool. Try the second command if the first one fails.<br />
<br />
C:\src\inkscape\trunk> g++ buildtool.cpp -o btool<br />
C:\src\inkscape\trunk> g++ -DNEED_GETTIMEOFDAY buildtool.cpp -o btool<br />
<br />
Finally initiate the compilation. Get a coffee or take your dog out for a walk, because it will take a rather long time.<br />
<br />
C:\src\inkscape\trunk> btool<br />
<br />
Once everything is done, there should be an <tt>inkscape</tt> directory that contains the Inkscape executable and libraries needed to run it.<br />
<br />
== Rebuilding ==<br />
<br />
If you have only changed a few files and want to rebuild, delete the <tt>inkscape</tt> directory and run <tt>btool</tt> again.<br />
<br />
To rebuild from scratch, execute the following sequence of commands:<br />
C:\src\inkscape\trunk> btool clean<br />
C:\src\inkscape\trunk> btool<br />
<br />
== Dealing With Build Errors ==<br />
Feel free to add any questions or answers you have in here;<br />
<br />
'''Q''' - My firewall software (Comodo's Defense+ component or similar) stopped the process continuing to the next step in the build, because I wasn't there to permit an action and it timed out. What can I do?<br />
<br />
'''A1''' - The best thing is to disable stuff like Defense+ (put it in learning mode works) because it will stop any process that is not approved, and building makes new files which can't be approved before they're built. Disabling Comodo's Defense+ does not disable your firewall, either inbound or outbound, but just the part that scans every application for suspicious operations. Other firewalls etc may vary.<br />
<br />
'''A2''' - If that doesn't suit, often you can simply run btool again and wait for Defense+ (or similar) to ask for approval for the process, and it will then continue as normal with the build. But remember that approving all the processes involved in the build process once doesn't mean they will all slip through next time.<br />
<br />
'''A3''' - This is the more complex way to continue, but may help if you have problems with A2. If you know the stage the process was meant to be up to (look at the output in the command windows and compare to the stages in the ''build.xml'' file), you can start again from there.<br />
<br />
You may see something like this in the command window;<br />
=============================<br />
## Target : link : link objects and library to create executable<br />
---- task : rc<br />
============ cmd ============<br />
windres -o build/inkres.o --include-dir=src src/inkscape.rc<br />
=============================<br />
---- task : link<br />
This will likely be followed by an error message. This means you were at the ''link'' stage<br />
<br />
Now simply type;<br />
...>btool ''stage''<br />
Or in this case<br />
...>btool link<br />
And the build will continue from there.<br />
<br />
After this, you will probably have to step through the remaining stages manually, one by one. The stages can include (see build.xml, where each stage is labelled 'target name="''target''"') ''init'', ''touchabout'', ''compile'', ''java'', ''lib'', ''i18n'', ''link'', ''linkinkview'', ''dist'', ''dist-all'', ''clean''. <br />
<br />
<br />
<br />
'''Q''' - How do I rebuild just one ''file.o'' file? For instance if one particular file has gone wrong, or I want to try patching just one part of the code.<br />
<br />
'''A''' - To find the right command for building any particular file in Inkscape, just look in the compile.lst after you have used btool once. Search for the name of the particular file (eg: print.cpp) and you will find the command used to compile it. You'll need to paste this into a text file, remove any carriage reurns and then paste that onto the command line.<br />
<br />
<br />
<br />
'''Q''' - After I patched a file, I left a backup of the old file in the same directory called Copy of{filename}.cpp. The compiler complains about this file when building and stops.<br />
<br />
'''A''' - Do not leave anything with a suffix .cpp in the source directories, apart from the original (or patched) source files. The build tool will try to compile everything ending in .cpp and will complain. If you backup an old file in the same directory before patching, call it {filename}.cpp.old or similar.<br />
<br />
<br />
<br />
'''Q''' - I think I followed the instruction above. What could have caused the compiling error like this for src/extension/internal/pdfinput/pdf-parser.cpp?<br />
<br />
src/extension/internal/pdfinput/pdf-parser.cpp:2248: error: no matching function for call to 'GfxFont::getNextChar(char*&, int&, CharCode*, Unicode [8], int, int*, double*, double*, double*, double*)'<br />
<br />
Same error for line 2297 as well.<br />
<br />
=== For more information ===<br />
There is some old information on building Inkscape with either Mingw on Windows, or a cross-compiler on Linux, at http://inkscape.modevia.com/win32_inkscape_org/win32buildnotes.html<br />
and old files mey be<br />
http://inkscape.modevia.com/win32libs/<br />
== Creating an installer ==<br />
<br />
To create the setup package you need the NSIS installer on your PC. Get that from http://nsis.sf.net .<br />
You have successfully built Inkscape and everything is in the ...\inkscape\ directory.<br />
Open the ...\packaging\win32\inkscape.nsi using the NSIS program and compile the package. Sooo easy :-)<br />
<br />
== Note about Unicode ==<br />
<br />
The GTK stack depends on functions only present in NT-based Windows (2000 and later). Therefore, Inkscape code can assume that Unicode functions from the Windows API (like GetCommandLineW) are always present. Note however that you should use the GLib/GTK functions rather the Windows API whenever possible.<br />
<br />
=See also=<br />
*[[Compiling Inkscape]]<br />
<br />
[[Category:Developer Documentation]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=70537Diffusion Curves2011-06-14T09:09:56Z<p>Jaspervdg: </p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
Or (only a single color per point on the path and no blur):<br />
<br />
<diffusionGradient id="gradient"><br />
<stop ...><br />
...<br />
</diffusionGradient><br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
fill="url(#gradient)" /><br />
<br />
This could lead to an on-canvas interface (using an extended gradient tool) that looks a bit like this:<br />
<br />
[[Image:fudgedDiffCurve.png]]<br />
<br />
Here the "gradient stops" are (necessarily) positioned on the path and represented by the circles. The color inside the circles shows the stop color.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
*Could a diffusion curve have a stop which is not completely opaque? I would find this useful for creating lighting effects over surfaces. --[[User:Pajarico|Pajarico]] 23:11, 15 January 2011 (UTC)<br />
** Yes, it could. In fact, it's quite trivial to do so, as diffusion curves are handled per channel anyway. And it's not too difficult to show that this yields sensible results if you use (premultiplied) alpha. How this behaves in practice remains to be seen, however, but I would expect this to more or less just work. --[[User:Jaspervdg|Jaspervdg]] 08:16, 18 January 2011 (UTC)<br />
<br />
==Links==<br />
*Original paper (and program to edit/view them): http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*Quality issues and using the Analytic Element Method to combat them: http://irs.ub.rug.nl/dbi/4d10adac9b054 (backup: http://home.hccnet.nl/th.v.d.gronde/ThesisJvdGFinal2.pdf)<br />
*Some grid-based implementations: https://code.launchpad.net/~jaspervdg/+junk/diffuselib<br />
*Implementation based on the Analytic Element Method: https://code.launchpad.net/~jaspervdg/+junk/aem-diffusion-curves<br />
*More references: http://www.citeulike.org/user/jaspervdg/tag/diffusion_curves</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Compiling_Inkscape_on_Windows_32-bit&diff=68101Compiling Inkscape on Windows 32-bit2011-03-19T15:31:18Z<p>Jaspervdg: /* Install the compiler */ Switched around workaround for difference in location of libgomp</p>
<hr />
<div>Inkscape was originally written for Linux, but it has been ported to other platforms, including Windows. Since Windows is not POSIX compliant and doesn't have several features useful to developers (like package management), compiling Inkscape on Windows is more tedious than on Linux, but perfectly possible.<br />
<br />
==Setting up the build environment==<br />
<br />
To develop Inkscape, you will need the following things:<br />
<br />
* [http://wiki.bazaar.canonical.com/WindowsDownloads Bazaar]<br />
* [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html PuTTY] programs: puttygen.exe and pageant.exe<br />
* [http://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/tdm-gcc-4.5.1.exe/download TDM-MinGW 4.5.1]<br />
* [http://sourceforge.net/projects/nsis/files/NSIS%202/2.46/nsis-2.46-setup.exe/download NSIS 2.46]<br />
* Launchpad account<br />
<br />
===Install the compiler===<br />
Run the TDM-MinGW installer and install it in a path that doesn't contain spaces, preferably C:\mingw. If you install it into another path, set the environment variable MINGW_PATH to the TDM-MinGW installation directory, e.g. the one containing <tt>README-tdm-gcc.txt</tt> (right click My Computer -> Properties -> Advanced -> Environment Variables). During the installation, enable the "openmp support" checkbox from the components list or choose to install all packages (option "TDM-GCC recommended, All Packages" in the TDM-GCC 4.5.1 installer).<br />
<br />
If you have an older version of TDM-GCC (older than 4.5.1?), copy the file "\lib\gcc\mingw32\bin\libgomp-1.dll" to "\bin\libgomp-1.dll" (paths relative to your installation directory).<br />
<br />
===Create your Launchpad account===<br />
If you do not have an SSH public/private key pair to identify yourself:<br />
*run the program puttygen.exe to generate an SSH key<br />
*save both its parts.<br />
Log into your Launchpad account, go to your profile page and add the public part of the generated key to the list of SSH keys. Run the program pageant.exe (you can add it to Autorun). A tray icon should appear. Right click it, select "Add Key" and pick the private key file you have just generated from the dialog. Note that you need to repeat this after every login whenever you want to access Launchpad.<br />
<br />
Now set up Bazaar. First tell it who you are, then associate with your Launchpad account. You need to use the account name (e.g. johnq), not the display name.(John Q. Public).<br />
<br />
C:\> bzr whoami "''Your Name'' <''your_real_email@example.com''>"<br />
C:\> bzr launchpad-login ''your_launchpad_account''<br />
<br />
===Install the developer libraries===<br />
Check out Inkscape Devlibs into C:\devlibs. If you check them out elsewhere, set the environment variable DEVLIBS_PATH to the path where they are. Devlibs are a bundle of all the libraries needed to compile Inkscape. If you experience any problems, make sure you have an up to date copy of those libraries and an up to date checkout of Inkscape source. To reduce the size of the download, pass the <tt>--lightweight</tt> parameter.<br />
<br />
C:\> bzr checkout --lightweight lp:inkscape-devlibs devlibs<br />
<br />
To update devlibs:<br />
<br />
C:\devlibs> bzr update<br />
<br />
All Inkscape developers can commit to the devlibs trunk. Advanced information about Devlibs, mainy useful when you want to update them to newly released versions of upstream libraries, is available here: [[Inkscape Devlibs]].<br />
You can see some infomation from [https://launchpad.net/inkscape-devlibs launchpad:inkscape-devlibs] and [http://bazaar.launchpad.net/~inkscape.dev/inkscape-devlibs/trunk/files trunk/files].<br />
<br />
== Obtaining Inkscape source code ==<br />
<br />
You can obtain released Inkscape source from a tarball. Since version 0.47 they are hosted on [https://launchpad.net/inkscape Inkscape's Launchpad page]. There are ready-made installers provided, so there's usually little reason to compile the stable version yourself.<br />
<br />
To obtain cutting edge code, check out Inkscape source from the Bazaar repository. You can also use the TortoiseBZR shell extensions to do this. The recommended way is to first create a shared repository, then check out the Inkscape branch into that shared repository. Using this setup, branching will be a lot faster.<br />
<br />
C:\src\inkscape> bzr init-repo --rich-root<br />
C:\src\inkscape> bzr checkout lp:inkscape trunk<br />
<br />
If you don't want to create any branches, you can skip the shared repository step.<br />
<br />
C:\src> bzr checkout lp:inkscape<br />
<br />
'''IMPORTANT:''' make sure that the path to your Inkscape source checkout does not contain spaces. Unix tools do not like them and you will end up with a lot of error messages about missing files.<br />
<br />
== Building Inkscape ==<br />
<br />
Open the command prompt, navigate to the directory with Inkscape sources. First set up some environmental variables. You only need to do this once per console session.<br />
<br />
C:\src\inkscape\trunk> mingwenv<br />
<br />
Now compile the build tool. Try the second command if the first one fails.<br />
<br />
C:\src\inkscape\trunk> g++ buildtool.cpp -o btool<br />
C:\src\inkscape\trunk> g++ -DNEED_GETTIMEOFDAY buildtool.cpp -o btool<br />
<br />
Finally initiate the compilation. Get a coffee or take your dog out for a walk, because it will take a rather long time.<br />
<br />
C:\src\inkscape\trunk> btool<br />
<br />
Once everything is done, there should be an <tt>inkscape</tt> directory that contains the Inkscape executable and libraries needed to run it.<br />
<br />
== Rebuilding ==<br />
<br />
If you have only changed a few files and want to rebuild, delete the <tt>inkscape</tt> directory and run <tt>btool</tt> again.<br />
<br />
To rebuild from scratch, execute the following sequence of commands:<br />
C:\src\inkscape\trunk> btool clean<br />
C:\src\inkscape\trunk> btool<br />
<br />
== Dealing With Build Errors ==<br />
Feel free to add any questions or answers you have in here;<br />
<br />
'''Q''' - My firewall software (Comodo's Defense+ component or similar) stopped the process continuing to the next step in the build, because I wasn't there to permit an action and it timed out. What can I do?<br />
<br />
'''A1''' - The best thing is to disable stuff like Defense+ (put it in learning mode works) because it will stop any process that is not approved, and building makes new files which can't be approved before they're built. Disabling Comodo's Defense+ does not disable your firewall, either inbound or outbound, but just the part that scans every application for suspicious operations. Other firewalls etc may vary.<br />
<br />
'''A2''' - If that doesn't suit, often you can simply run btool again and wait for Defense+ (or similar) to ask for approval for the process, and it will then continue as normal with the build. But remember that approving all the processes involved in the build process once doesn't mean they will all slip through next time.<br />
<br />
'''A3''' - This is the more complex way to continue, but may help if you have problems with A2. If you know the stage the process was meant to be up to (look at the output in the command windows and compare to the stages in the ''build.xml'' file), you can start again from there.<br />
<br />
You may see something like this in the command window;<br />
=============================<br />
## Target : link : link objects and library to create executable<br />
---- task : rc<br />
============ cmd ============<br />
windres -o build/inkres.o --include-dir=src src/inkscape.rc<br />
=============================<br />
---- task : link<br />
This will likely be followed by an error message. This means you were at the ''link'' stage<br />
<br />
Now simply type;<br />
...>btool ''stage''<br />
Or in this case<br />
...>btool link<br />
And the build will continue from there.<br />
<br />
After this, you will probably have to step through the remaining stages manually, one by one. The stages can include (see build.xml, where each stage is labelled 'target name="''target''"') ''init'', ''touchabout'', ''compile'', ''java'', ''lib'', ''i18n'', ''link'', ''linkinkview'', ''dist'', ''dist-all'', ''clean''. <br />
<br />
<br />
<br />
'''Q''' - How do I rebuild just one ''file.o'' file? For instance if one particular file has gone wrong, or I want to try patching just one part of the code.<br />
<br />
'''A''' - To find the right command for building any particular file in Inkscape, just look in the compile.lst after you have used btool once. Search for the name of the particular file (eg: print.cpp) and you will find the command used to compile it. You'll need to paste this into a text file, remove any carriage reurns and then paste that onto the command line.<br />
<br />
<br />
<br />
'''Q''' - After I patched a file, I left a backup of the old file in the same directory called Copy of{filename}.cpp. The compiler complains about this file when building and stops.<br />
<br />
'''A''' - Do not leave anything with a suffix .cpp in the source directories, apart from the original (or patched) source files. The build tool will try to compile everything ending in .cpp and will complain. If you backup an old file in the same directory before patching, call it {filename}.cpp.old or similar.<br />
<br />
<br />
<br />
'''Q''' - I think I followed the instruction above. What could have caused the compiling error like this for src/extension/internal/pdfinput/pdf-parser.cpp?<br />
<br />
src/extension/internal/pdfinput/pdf-parser.cpp:2248: error: no matching function for call to 'GfxFont::getNextChar(char*&, int&, CharCode*, Unicode [8], int, int*, double*, double*, double*, double*)'<br />
<br />
Same error for line 2297 as well.<br />
<br />
=== For more information ===<br />
There is some old information on building Inkscape with either Mingw on Windows, or a cross-compiler on Linux, at http://inkscape.modevia.com/win32_inkscape_org/win32buildnotes.html<br />
and old files mey be<br />
http://inkscape.modevia.com/win32libs/<br />
== Creating an installer ==<br />
<br />
To create the setup package you need the NSIS installer on your PC. Get that from http://nsis.sf.net .<br />
You have successfully built Inkscape and everything is in the ...\inkscape\ directory.<br />
Open the ...\packaging\win32\inkscape.nsi using the NSIS program and compile the package. Sooo easy :-)<br />
<br />
== Note about Unicode ==<br />
<br />
The GTK stack depends on functions only present in NT-based Windows (2000 and later). Therefore, Inkscape code can assume that Unicode functions from the Windows API (like GetCommandLineW) are always present. Note however that you should use the GLib/GTK functions rather the Windows API whenever possible.<br />
<br />
=See also=<br />
*[[Compiling Inkscape]]<br />
<br />
[[Category:Developer Documentation]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=67813Diffusion Curves2011-03-08T08:58:15Z<p>Jaspervdg: Updated links</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
Or (only a single color per point on the path and no blur):<br />
<br />
<diffusionGradient id="gradient"><br />
<stop ...><br />
...<br />
</diffusionGradient><br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
fill="url(#gradient)" /><br />
<br />
This could lead to an on-canvas interface (using an extended gradient tool) that looks a bit like this:<br />
<br />
[[Image:fudgedDiffCurve.png]]<br />
<br />
Here the "gradient stops" are (necessarily) positioned on the path and represented by the circles. The color inside the circles shows the stop color.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
*Could a diffusion curve have a stop which is not completely opaque? I would find this useful for creating lighting effects over surfaces. --[[User:Pajarico|Pajarico]] 23:11, 15 January 2011 (UTC)<br />
** Yes, it could. In fact, it's quite trivial to do so, as diffusion curves are handled per channel anyway. And it's not too difficult to show that this yields sensible results if you use (premultiplied) alpha. How this behaves in practice remains to be seen, however, but I would expect this to more or less just work. --[[User:Jaspervdg|Jaspervdg]] 08:16, 18 January 2011 (UTC)<br />
<br />
==Links==<br />
*Original paper (and program to edit/view them): http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*Quality issues and using the Analytic Element Method to combat them: http://home.hccnet.nl/th.v.d.gronde/ThesisJvdGFinal2.pdf<br />
*Some grid-based implementations: https://code.launchpad.net/~jaspervdg/+junk/diffuselib<br />
*Implementation based on the Analytic Element Method: https://code.launchpad.net/~jaspervdg/+junk/aem-diffusion-curves<br />
*More references: http://www.citeulike.org/user/jaspervdg/tag/diffusion_curves</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=66955Diffusion Curves2011-01-18T08:16:52Z<p>Jaspervdg: /* Questions/Problems */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
Or (only a single color per point on the path and no blur):<br />
<br />
<diffusionGradient id="gradient"><br />
<stop ...><br />
...<br />
</diffusionGradient><br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
fill="url(#gradient)" /><br />
<br />
This could lead to an on-canvas interface (using an extended gradient tool) that looks a bit like this:<br />
<br />
[[Image:fudgedDiffCurve.png]]<br />
<br />
Here the "gradient stops" are (necessarily) positioned on the path and represented by the circles. The color inside the circles shows the stop color.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
*Could a diffusion curve have a stop which is not completely opaque? I would find this useful for creating lighting effects over surfaces. --[[User:Pajarico|Pajarico]] 23:11, 15 January 2011 (UTC)<br />
** Yes, it could. In fact, it's quite trivial to do so, as diffusion curves are handled per channel anyway. And it's not too difficult to show that this yields sensible results if you use (premultiplied) alpha. How this behaves in practice remains to be seen, however, but I would expect this to more or less just work. --[[User:Jaspervdg|Jaspervdg]] 08:16, 18 January 2011 (UTC)<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib<br />
*More references: http://www.citeulike.org/user/jaspervdg/tag/diffusion_curves</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=66229Diffusion Curves2010-12-09T08:40:09Z<p>Jaspervdg: /* Links */ Added citeulike link.</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
Or (only a single color per point on the path and no blur):<br />
<br />
<diffusionGradient id="gradient"><br />
<stop ...><br />
...<br />
</diffusionGradient><br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
fill="url(#gradient)" /><br />
<br />
This could lead to an on-canvas interface (using an extended gradient tool) that looks a bit like this:<br />
<br />
[[Image:fudgedDiffCurve.png]]<br />
<br />
Here the "gradient stops" are (necessarily) positioned on the path and represented by the circles. The color inside the circles shows the stop color.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib<br />
*More references: http://www.citeulike.org/user/jaspervdg/tag/diffusion_curves</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=64993Advanced Gradients2010-10-06T07:02:54Z<p>Jaspervdg: </p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
This page was started as part of the response to [https://bugs.launchpad.net/inkscape/+bug/346681 bug 346681], mainly to provide an alternative for a bitmap fallback.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The two images below show an example as it is rendered by Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
[[Media:LineargradientCT.svg|Download/view LineargradientCT.svg]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The images below show a linear gradient colored with the feDisplacementMap method, rendered by the Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
[[Media:LineargradientDM.svg|Download/view LineargradientDM.svg]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
[[Media:ConicalgradientDMDL.svg|Download/view ConicalgradientDMDL.svg]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
[[Media:ConicalgradientDMRD.svg|Download/view ConicalgradientDMRD.svg]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
[[Media:ConicalgradientDMRD2.svg|Download/view ConicalgradientDMRD2.svg]]<br />
<br />
===Arctan approximation quality===<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
Note that this approximation method corresponds to the approximation [http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm described here] for quadrant 1 (with the roles of x and y reversed, just like in the graph above), scaled by <math>2/\pi</math>:<br />
<br />
<math>\begin{align}<br />
\frac{2}{\pi}\cdot\frac{\pi}{4}\left(1-\frac{y-x}{x+y}\right)&=\frac{1}{2}\left(1-\frac{y-x}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y}{x+y}+\frac{x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y+x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{2x}{x+y}\right)<br />
\\&=\frac{x}{x+y}<br />
\end{align}</math><br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]], as well as [[Diffusion_Curves|this Wiki page]] for information on attempts to make Diffusion Curves suitable for implementation in Inkscape.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=64987Advanced Gradients2010-10-06T07:00:42Z<p>Jaspervdg: </p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
This page was started as part of the response to [https://bugs.launchpad.net/inkscape/+bug/346681 bug 346681], mainly to provide an alternative for a bitmap fallback.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
[[Media:LineargradientCT.svg|Download/view LineargradientCT.svg]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
[[Media:LineargradientDM.svg|Download/view LineargradientDM.svg]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
[[Media:ConicalgradientDMDL.svg|Download/view ConicalgradientDMDL.svg]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
[[Media:ConicalgradientDMRD.svg|Download/view ConicalgradientDMRD.svg]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
[[Media:ConicalgradientDMRD2.svg|Download/view ConicalgradientDMRD2.svg]]<br />
<br />
===Arctan approximation quality===<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
Note that this approximation method corresponds to the approximation [http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm described here] for quadrant 1 (with the roles of x and y reversed, just like in the graph above), scaled by <math>2/\pi</math>:<br />
<br />
<math>\begin{align}<br />
\frac{2}{\pi}\cdot\frac{\pi}{4}\left(1-\frac{y-x}{x+y}\right)&=\frac{1}{2}\left(1-\frac{y-x}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y}{x+y}+\frac{x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y+x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{2x}{x+y}\right)<br />
\\&=\frac{x}{x+y}<br />
\end{align}</math><br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]], as well as [[Diffusion_Curves|this Wiki page]] for information on attempts to make Diffusion Curves suitable for implementation in Inkscape.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=64537Diffusion Curves2010-09-07T14:00:48Z<p>Jaspervdg: /* Representation */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
Or (only a single color per point on the path and no blur):<br />
<br />
<diffusionGradient id="gradient"><br />
<stop ...><br />
...<br />
</diffusionGradient><br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
fill="url(#gradient)" /><br />
<br />
This could lead to an on-canvas interface (using an extended gradient tool) that looks a bit like this:<br />
<br />
[[Image:fudgedDiffCurve.png]]<br />
<br />
Here the "gradient stops" are (necessarily) positioned on the path and represented by the circles. The color inside the circles shows the stop color.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:FudgedDiffCurve.png&diff=64531File:FudgedDiffCurve.png2010-09-07T13:54:51Z<p>Jaspervdg: Description</p>
<hr />
<div>Example of what an interface for editing diffusion curves in Inkscape could look like. Here it is assumed that diffusion curves are handled like just another kind of paint and can be applied using an extended version of the gradient tool. The circles represent "gradient stops", with the stop color in the circle.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:FudgedDiffCurve.png&diff=64525File:FudgedDiffCurve.png2010-09-07T13:52:53Z<p>Jaspervdg: </p>
<hr />
<div></div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=64519Diffusion Curves2010-09-07T10:01:43Z<p>Jaspervdg: </p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent. Or by simply treating diffusion curves as yet another paint server.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers on grids generally use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Storage can be quite bad for curved geometries (because of the number of triangles needed to approximate the curve).<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give a higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
*It might be possible to use the result of a boundary element computation directly and just combine basis functions.<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=SVG_WorkingGroup&diff=62887SVG WorkingGroup2010-06-15T16:12:35Z<p>Jaspervdg: /* Areas of Inkscape Interest */</p>
<hr />
<div>== Inkscape and the SVG Working Group ==<br />
<br />
Inkscape '''can''' influence the future of the SVG standard. This page serves as a gathering point for ideas on how the standard can be improved to the benefit of Inkscape.<br />
<br />
== Inkscape representitive ==<br />
<br />
Tavmjong Bah has joined the SVG Working group as an "Invited Expert" to represent the interests of Inkscape. You can contact him through the developer's mailing list or at tavmjong at free.fr. You can also join the meetings yourself (as several Inkscapers did after LGM2010). See the links below.<br />
<br />
Please add to this page any problems you have found with the existing standard or what you would like to see in a future standard.<br />
<br />
== SVG Working Group Links ==<br />
<br />
=== General ===<br />
<br />
* [http://www.w3.org/Graphics/SVG/WG/wiki/Main_Page Working Group Main Page]<br />
* [http://lists.w3.org/Archives/Public/public-svg-wg/ Public-SVG-WG Mail Archives]<br />
* [http://lists.w3.org/Archives/Public/www-svg/ WWW-SVG Mail Archives] (The true public mailing list).<br />
* [http://www.w3.org/Graphics/SVG/WG/wiki/Meetings Schedule]<br />
<br />
=== Standards ===<br />
<br />
<br />
*[http://www.w3.org/TR/#tr_SVG Complete List]<br />
<br />
==== Completed ====<br />
<br />
* [http://www.w3.org/TR/2003/REC-SVG11-20030114/ SVG 1.1]<br />
* [http://www.w3.org/TR/2008/REC-SVGTiny12-20081222/ SVG Tiny 1.2]<br />
<br />
==== Proposed Standards ====<br />
<br />
*[http://www.w3.org/Graphics/SVG/WG/wiki/Roadmap Roadmap]<br />
<br />
<br />
== Areas of Inkscape Interest ==<br />
<br />
Here are some areas to consider:<br />
<br />
=== Multipage document support ===<br />
<br />
Proposed for SVG 1.2 but dropped.<br />
<br />
=== Standardizing layers ===<br />
<br />
Creating a standard way to indicate layers. Inkscape uses private attributes.<br />
<br />
=== Clones/referencing ===<br />
<br />
Currently there is the use element, but there are also elements (gradients and filters) that have their own "cloning" technique, it could be nice to unify these approaches? In particular, either might benefit from some kind of support for "parameters" (being either numerical/textual values or drawable elements).<br />
<br />
=== (Fancy) paths ===<br />
<br />
* A different notion of "closing" a path is needed, as the current one only operates well in the context of straight lines. For example, instead of having z be a command that draws a straight line to the first vertex in the subpath and closes the path, it could be used in place of the last pair of coordinates in a closed subpath. This would only very slightly complicate parsing while allowing for a much more natural operation in the context of curves. Currently a closed path consisting (conceptually) only of cubic beziers HAS to have at least one "closing" segment, this introduces "double" nodes, is more verbose and makes it impossible to have the exact same marker behaviour in paths consisting of straight lines and paths consisting of curves. (Also see this discussion: http://old.nabble.com/Re:--Lib2geom-devel--Geom::Path-and-boost::ptr_vector-td27535646.html)<br />
* Patterns along paths,<br />
* Vector effects.<br />
* Power stroke.<br />
<br />
=== Gradients ===<br />
<br />
* Diffusion curves.<br />
* Mesh gradients.<br />
<br />
=== SVG fonts ===<br />
<br />
Firefox and IE will not add support for SVG fonts.<br />
<br />
=== Filters ===<br />
<br />
*Increasing bit depth to reduce artifacts.<br />
*The same color space (by default) as the rest of SVG (and only ONE property please). Note that it would make sense to make linearRGB the default everywhere (instead of making filters use sRGB by default as well).<br />
*Margins. (--[[User:Jaspervdg|Jaspervdg]] 13:49, 15 June 2010 (UTC) I would prefer them not to have any attributes for margins. Specifically I think the only property of the filter element that should stay is primitiveUnits.)<br />
*Primitive subregions are (as far as I, Jasper, know) unused and frankly not that useful. As far as I can tell they're mostly meant as an optimization, but a renderer can do that quite easily (and frankly often still has to). If you want a clipping rectangle or something, then just draw a rectangle and use it to clip a result, if you have a smart renderer it will even automagically behave reasonably efficient in such a case.<br />
*Non-pixel-based convolution (based on a Laplace transform instead of the Z-transform basically). E.g. it would be more logical (at least in some cases) to specify that you want the derivative of an image rather than applying the kernel "1 -1"... (Which has to be given a certain resolution to be meaningful, meaning that you currently can't express resolution-independent convolutions.) In fact, it could make sense to simply remove the current feConvolveMatrix, and/or enable it to function in a resolution independent manner.<br />
*Unification of normal compositing, feBlend, feComposite and feMerge. (Like in SVG Compositing? And then exposing that in filters in some way?)<br />
*Is enable-background REALLY necessary? There are other ways to solve the same problem, like referencing an element explicitly or allowing filters (and possibly also use elements) with "parameters". There are certain very cool things you can do with enable-background, but it's quite hard to implement correctly because you need to keep track of where the background is used in order to know which part of an object is actually needed. Other options might be less general w.r.t. accessing the "background", but they might be easier to support and allow for much more interesting effects.<br />
*Reusing filters as primitives. (Essentially allowing macro's.)<br />
*A lot of filters could be "optimized" by a renderer. This would be especially helpful for editors and animation-enabled renderers. It might be good to see if some things could be built in to make this easier. I would avoid explicit flags as much as possible (users either won't use them when they could, or use them all the time, negating their usefulness), but the specification might specify some operations that are explicitly permitted for example (like collapsing two feColorMatrix operations).<br />
<br />
--[[User:Jaspervdg|Jaspervdg]] 16:12, 15 June 2010 (UTC) In general I'd like to stress that SVG filters should (IMO) focus less on a specific implementation and more on the desired effect (and if possible in a "vector-like" way). This makes it less complex to support filters and gives more freedom to an implementation to "do the right thing" in its own way. It's also more friendly towards the user of SVG, as more of the implementation details are hidden. (Obviously it should be possible to implement a filter, but the specification shouldn't prescribe a certain implementation.)<br />
<br />
=== Cacheable portion/layers ===<br />
<br />
*Investigate partial.s cache-ablity</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=SVG_WorkingGroup&diff=62881SVG WorkingGroup2010-06-15T13:49:26Z<p>Jaspervdg: /* Filters */</p>
<hr />
<div>== Inkscape and the SVG Working Group ==<br />
<br />
Inkscape '''can''' influence the future of the SVG standard. This page serves as a gathering point for ideas on how the standard can be improved to the benefit of Inkscape.<br />
<br />
== Inkscape representitive ==<br />
<br />
Tavmjong Bah has joined the SVG Working group as an "Invited Expert" to represent the interests of Inkscape. You can contact him through the developer's mailing list or at tavmjong at free.fr. You can also join the meetings yourself (as several Inkscapers did after LGM2010). See the links below.<br />
<br />
Please add to this page any problems you have found with the existing standard or what you would like to see in a future standard.<br />
<br />
== SVG Working Group Links ==<br />
<br />
=== General ===<br />
<br />
* [http://www.w3.org/Graphics/SVG/WG/wiki/Main_Page Working Group Main Page]<br />
* [http://lists.w3.org/Archives/Public/public-svg-wg/ Public-SVG-WG Mail Archives]<br />
* [http://lists.w3.org/Archives/Public/www-svg/ WWW-SVG Mail Archives] (The true public mailing list).<br />
* [http://www.w3.org/Graphics/SVG/WG/wiki/Meetings Schedule]<br />
<br />
=== Standards ===<br />
<br />
<br />
*[http://www.w3.org/TR/#tr_SVG Complete List]<br />
<br />
==== Completed ====<br />
<br />
* [http://www.w3.org/TR/2003/REC-SVG11-20030114/ SVG 1.1]<br />
* [http://www.w3.org/TR/2008/REC-SVGTiny12-20081222/ SVG Tiny 1.2]<br />
<br />
==== Proposed Standards ====<br />
<br />
*[http://www.w3.org/Graphics/SVG/WG/wiki/Roadmap Roadmap]<br />
<br />
<br />
== Areas of Inkscape Interest ==<br />
<br />
Here are some areas to consider:<br />
<br />
=== Multipage document support ===<br />
<br />
Proposed for SVG 1.2 but dropped.<br />
<br />
=== Standardizing layers ===<br />
<br />
Creating a standard way to indicate layers. Inkscape uses private attributes.<br />
<br />
=== Fancy paths ===<br />
<br />
* Patterns along paths,<br />
* Vector effects.<br />
* Power stroke.<br />
<br />
=== Gradients ===<br />
<br />
* Diffusion curves.<br />
* Mesh gradients.<br />
<br />
=== SVG fonts ===<br />
<br />
Firefox and IE will not add support for SVG fonts.<br />
<br />
=== Filters ===<br />
<br />
*Increasing bit depth to reduce artifacts.<br />
*Margins. (--[[User:Jaspervdg|Jaspervdg]] 13:49, 15 June 2010 (UTC) I would prefer them not to have any attributes for margins.)<br />
<br />
=== Cacheable portion/layers ===<br />
<br />
*Investigate partial.s cache-ablity</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Release_notes/0.48&diff=62743Release notes/0.482010-06-09T13:10:49Z<p>Jaspervdg: /* Notable bug fixes */</p>
<hr />
<div>==Inkscape 0.48==<br />
'''(not released yet - [[AnnouncePlanning048]])'''<br />
<br />
==Release highlights==<br />
<br />
(TODO)<br />
<br />
==Tools==<br />
<br />
===Node Tool===<br />
<br />
During Google Summer of Code 2009, the node tool underwent an extensive rewrite. Along with more maintainable code, it brings several new features.<br />
<br />
; '''Multi-path editing'''<br />
: Any number of paths can be selected for node editing at once.<br />
; '''Improved clippath / mask editing'''<br />
: The clipping path or mask of an object can be edited at the same time as the object. The clip / mask editing buttons in the node tool are now toggle buttons, rather than mode switch buttons. If the object is transformed after applying a clipping path, the clipping path is no longer offset when editing it in the node tool. If the clipping path is a group, all paths in the group can be edited simultaneously.<br />
; '''Improved node join'''<br />
: It is now possible to join nodes from different paths. More than two endnodes can be joined at once—the distances between nodes will be used to determine which nodes to join, with the closest pairs being joined first. When nothing can be joined (less than 2 endnodes in selecion), each selected stretch of nodes will be joined into one node.<br />
; '''Improved segment join'''<br />
: It is now possible to create a segment between endnodes from different paths. More than one segment can be created at once—the distances between nodes will be used to determine which nodes to join with a segment, with the closest pairs being joined first. When nothing can be joined (less than 2 endnodes in selection), each selected stretch of nodes will have its middle nodes removed, leaving only one segment.<br />
; '''Node transforms'''<br />
: It is now possible to transform the nodes using the mouse and transformation handles similar to those in the selector tool. They can be turned on and off using the button in the node toolbar. When the handles are visible, clicking on a selected node will switch between scaling and rotation mode, instead of selecting only that node. You can also use Shift+H to switch the mode. All other operations work normally when transform handles are shown.<br />
; '''Path direction tools'''<br />
: Little harpoons are optionally shown in the middle of each segment, visualizing the direction of the path. This is useful when preparing a guide path for text, setting markers, and debugging extensions and Inkscape itself. The "Reverse" command (Shift+R) reverses the direction of subpaths that have some selected nodes, or all subpaths if the node selection is empty.<br />
; '''Customizable path update'''<br />
: Two new preferences allow you to specify when the path and its outline should be updated. Turning off live update of paths will improve performance for complex drawings.<br />
; '''Improved tips'''<br />
: The tips displayed for nodes and handles are more concise and affected by what modifier keys are pressed.<br />
<br />
For a detailed feature comparison between the old and new tool, see [[GSoC2009 Node Tool Rewrite]].<br />
<br />
===Text Tool===<br />
<br />
The text toolbar has been overhauled with many bug fixes and improvements. One can now directly access a number of text layout parameters:<br />
<br />
*"Line Spacing:" Distance between baselines of adjacent lines.<br />
*"Letter Spacing:" Spacing between letters.<br />
*"Word Spacing:" Spacing between words.<br />
*"Horizontal kerning"<br />
*"Vertical shift"<br />
*"Character rotation" <br />
<br />
In addition, support has been added for superscripts and subscripts.<br />
<br />
<br />
This work was sponsored in part by Inkscape users through LinuxFund.org.<br />
<br />
===Spray Tool===<br />
You first need to select one or several items, then select the Spray Tool. To spray, click on the canvas, then move the mouse or scroll the mouse wheel.<br />
<br />
Three modes are available.<br />
<br />
*''Spray Copy mode :'' each sprayed item is independent from the others.<br />
*''Spray Clone mode :'' each sprayed item is a clone of the selected item. Changing the properties of the original item will affect the clones.<br />
*''Spray Single Path Mode :'' everything you spray is in a single path. You may need to convert your item into a path to make it work properly.<br />
<br />
'''Spray options'''<br />
<br />
*Amount : spray more or less items.<br />
<br />
*Rotation : randomly rotates items around the original rotation value. <br />
*Scale : randomly scales items around the original scale value. <br />
<br />
*Scatter : low values to spray items under the cursor, high values for a more uniform repartition over the spray zone.<br />
*Focus : items are sprayed following a ring. This parameters modifies the radius of the circle. Default at 0 to spray a spot. <br />
<br />
Use keys ↑ and ↓ to control the size of of sprayed items. Use ← and → to set the width of the cursor.<br />
<br />
<br />
The Spray tool is a perfect match for the transforming, duplicating, and deleting modes of the Tweak tool.<br />
<br />
<!--<br />
==Live Path Effects (LPE)==<br />
<br />
===Node tool changes===<br />
The new node tool means slightly different LPE editing too. Such as ...<br />
<br />
===New effects===<br />
<br />
* '''Extrude''' Similar to the Python extension <br />
--><br />
<br />
==Import/Export==<br />
===Improved bitmap image import===<br />
<br />
Bitmaps are now always embedded when pixel data is pasted or dragged into Inkscape's window (for example when copying parts of an image from GIMP). Files with automatically generated names like "inkscape_pasted_image_..." are no longer created in the document directory. When importing or opening bitmap images, a dialog is displayed that asks whether you want to link the image or embed it.<br />
<br />
===New LaTeX export for PDF/EPS/PS===<br />
<br />
Similar to GNUPlot's `epslatex' output terminal and Xfig's combined PDF/LaTeX output, Inkscape can now export graphics to PDF with an accompanying LaTeX file that overlays the text over the PDF when inputted in LaTeX. The image's text is typeset by LaTeX, so for example mathematical expressions are rendered correctly, and all text will be in the font and style of the LaTeX document (even when changing the document's font afterwards).<br />
<br />
''(the following description assumes export to PDF, but will work the same for EPS and PS)''<br />
Two files will be created: a PDF file containing all graphics, without text; and a LaTeX file with the same name, containing all text, and code to include the PDF and overlay the text. To include the exported image in LaTeX, one writes<br />
<br />
\begin{figure} <br />
\centering<br />
\def\svgwidth{\columnwidth} % sets the image width, this is optional<br />
\input{image.tex}<br />
\end{figure}<br />
<br />
A more thorough description of how to use the new feature (and automate the exporting/inclusion of the image in LaTeX) is given in this PDF: [http://wiki.inkscape.org/wiki/images/SVG_in_LaTeX.pdf SVG in LaTeX].<br />
<br />
====From the GUI====<br />
When exporting to PDF/EPS/PS from Inkscape's GUI, the usual dialog pops up after selecting to which PDF/EPS/PS file to export to. In this dialog, you can find the PDF/EPS/PS+LaTeX option.<br />
<br />
====Command line option====<br />
When exporting to PDF/EPS/PS from the command line, adding --export-latex will turn the LaTeX export on. For example<br />
<br />
inkscape image.svg -z -D --export-pdf=image.pdf --export-latex<br />
<br />
===Fixed PDF/EPS/PS export of non-integer sized documents===<br />
The long standing [https://bugs.launchpad.net/inkscape/+bug/168275 bug 168275] has now been fixed. Documents with a non-integer height or width are now correctly exported to PDF, EPS and PS.<br />
<br />
==Extensions==<br />
===New and improved extensions===<br />
<br />
* The new '''Generate from Path > Voronoi Pattern''' extension creates a random pattern of Voronoi cells. The pattern will be accessible from the Fill and Stroke dialog. The pattern can be made to be smooth at the edges by choosing a positive border, or sparse at the edges by using a negative border.<br />
* The new '''Render > Wireframe Sphere''' extension draws the globe as a collection of ellipses representing a sphere's latitude and longitude lines. The number of lines is adjustable, as well as the tilt and rotation. There is an option to hide the lines at the back of the sphere.<br />
* The new '''Render > Barcode - Datamatrix''' extension renders a DataMatrix 2D barcode, as specified in BS ISO/IEC 16022:2006. The number of rows and columns of the DataMatrix is adjustable. If more data is given than can be contained in one DataMatrix, more than one DataMatrix will be produced.<br />
* The new '''Modify Path > Pixelsnap''' extension aligns rectangles and paths to pixel boundaries, to create sharp web and digital graphics.<br />
* The new '''Color > Black and White''' extension turns the selection colors into black and white.<br />
* The new '''Text > Split Text''' extension splits texts into different lines, words or letters.<br />
<!--* The new '''JessyInk''' extension for creating presentations viewable in browsers, See<br />
https://launchpad.net/jessyink --><br />
* The new '''Web > Slicer''' extensions to slice web layouts into multiple images and help the HTML+CSS creation.<br />
* '''Images > Extract Image''': all relative paths (or filenames without path) are now relative to the user's home directory.<br />
* '''Visualize Path > Measure Path''': new option to calculate area.<br />
<br />
<!-- ==Filters== --><br />
<br />
==SVG Support==<br />
<br />
The baseline-shift attribute is now read in and used. The Text toolbar uses the "super" and "sub" values for implementing superscripts and subscripts. At the moment there is no other GUI access to the attribute.<br />
<br />
<!-- ==Editing Aids== --><br />
<br />
==Other features==<br />
<br />
* Arch paper sizes are added in the Document Properties dialog<br />
* Displaying the '''font samples''' in the drop-down list of the Text tool is now optional. In Inkscape Preferences, go to Tools, Text, and uncheck "Show font samples in the drop-down list" if you don't want to see the samples. This will speed up displaying the list the first time you open it<br />
* Items in the File > Open Recent menu, when mouseovered, show tooltips with the full URI of each file in the list. Also, files that are in the list but are missing or unaccessible are automatically hidden<br />
* When a flowed text is truncated (i.e. the frame is too small for the entire text), the frame is shown red, and the statusbar hint includes '''[truncated]'''. You need to resize the frame to see the truncated end of the text. Analogously, if the path of a text-on-path object is too short to display the entire text, the statusbar will report it as '''[truncated]'''<br />
* Clicking the text alignment buttons (Left, Center, Right) on the Text tool's controls bar now does not let the text jump: it stays within the same bounding box as before, only changing the alignment<br />
* The position of text's baseline anchor (the small square) is now dependent of the alignment: for left-aligned text it is, as before, at the left end, for centered text in the middle, and for the right-aligned text it is at the right end of the text's first line (this is for horizontal text; for vertical, it is correspondingly at top, middle, or bottom of the first column). This allows snapping, aligning and distributing of text relative the side to which it's aligned<br />
* Snapping of gradient handles has been improved and now behaves similar to the snapping of all other handles and objects<br />
* When snapping to a bounding box, that bounding box will be shown for a moment (tied to the snap indicator)<br />
* If a new object is being created on the canvas with snapping enabled, then a snap indicator will also be shown for the first point<br />
* There are now options for Margins when resizing a document to a selection or the drawing in Document Properties<br />
* Preferences have been added to allow automatic grouping when setting a Clippath or Mask<br />
* Bitmap copies created using the Make a Bitmap Copy command (Alt+B) are now embedded. Previously they were saved in an automatically generated file and linked<br />
* The file preview size limit (in the File > Open and File > Import dialog box) is now 10 MB (1.3 MB in 0.47)<br />
* Blur, transformation, and layer visibility and opacity support in XAML export<br />
<br />
===Extended input device configuration===<br />
<br />
The stock Input Devices dialog has been replaced with a completely redone version that provides a more useful representation of settings. It also contains a simple area for testing different inputs of different devices.<br />
<br />
Additionally hardware setup itself has been separated from general settings to allow for easier dynamic switching of settings appropriate to the task at hand.<br />
<br />
==User interface==<br />
<br />
===Adaptive UI===<br />
(In progress [[User:JonCruz|JonCruz]])<br />
<br />
===Custom Swatches===<br />
<br />
Custom swatches can be created and used on a per-document basis. An "Auto" color palette will track swatches in the current document and allow them to be set and used. The use is "live" with changes to the swatch being applied automatically to all objects set to it. The swatches can also be gradients and not just simple colors.<br />
<br />
===New cursors in Selector===<br />
<br />
Selector tool has a new mouse cursor (arrow with an open hand) for when your mouse is over a selectable object, and another (arrow with clinched hand) for when you're dragging an object. This improves precision of selection and UI consistency (previously, the mouse cursor over a selectable object was different across platforms, e.g. hand icon on Linux or four-way arrow on Windows).<br />
<br />
===Translations===<br />
<br />
New Farsi translation (in progress).<br />
<br />
==Tutorials==<br />
<br />
* SVG files are now optimized with Scour (filesize reduced by 40%).<br />
* Bitstream Vera fonts replaced with generic sans and serif fonts (solves many font substitution issues).<br />
* New Interpolate tutorial (Help > Tutorials > Inkscape: Interpolate).<br />
* New translations in Farsi, Belarussian and Dutch.<br />
<br />
==Windows port improvements==<br />
<br />
The quality of the Windows port was improved substantially.<br />
<br />
===Command line interface===<br />
<br />
Command line functionality on Windows is now on par with Unix.<br />
<br />
'''Single executable'''<br />
:It's no longer needed to compile Inkscape with special flags or use third-party wrapper executables to see the command line output. Just type "inkscape" (without any extension) in the command prompt. This is made possible by a command-line wrapper named <tt>inkscape.com</tt>.<br />
'''Relative paths'''<br />
:You can now specify relative paths to files in options like <tt>--export-png</tt>. Commands like this will now execute correctly:<br />
C:\svg> inkscape tiger.svgz --export-png=tiger.png<br />
<br />
===Stability improvements===<br />
<br />
Thanks to library updates, Inkscape should no longer randomly crash when editing documents. Most of them were caused by a GDI resource leak in Pango. It will also no longer crash when trying to import a corrupted image.<br />
<br />
===Unicode compatibility===<br />
<br />
Inkscape will now work correctly regardless of installation path. Previously, it was unusable when installed into a directory that contains characters not representable in the system codepage (icons were not shown in the UI, and no language files were found).<br />
<br />
==Notable bug fixes==<br />
<br />
* The 3D tool no longer inserts an inkscape:perspective element into SVG when it is not needed (i.e. when the document has no 3D box objects).<br />
* Wrong clippaths and masks with cyclic recursion (i.e. clippaths or masks that refer to themselves via other clippaths or masks) no longer crash Inkscape.<br />
* Default unit setting for the XY grid is now respected when creating a new grid.<br />
* Pasting Live Path Effect stacks now works. It adds the stack of the copied object to the end of the LPE stack (if present) of the object it is pasted to.<br />
* The accuracy of the bounding box calculation has been significantly improved when converting objects to patterns or markers. This should make it much easier to create patterns where the tiles should 'connect' to each other, e.g. a tile with a plus sign to create a hatched pattern.<br />
* The default font has been changed to ''Sans'', eliminating problems when the former default font, ''Bitstream Vera Sans'', is not available. (''Sans'' is a Pango pseudo-font.)<br />
* The Text toolbar bold and italic/oblique buttons are more likely to work as expected.<br />
* Bitmaps with transparency are now shown (and exported) correctly.<br />
* The emergency save function no longer mangles the file names (which used to make it fail quite often).<br />
<br />
==Known issues==<br />
<br />
==Previous releases==<br />
<br />
* [[ReleaseNotes047]]<br />
* [[ReleaseNotes046]]<br />
* [[ReleaseNotes045]]<br />
* [[ReleaseNotes044]]<br />
* [[ReleaseNotes043]]<br />
* [[ReleaseNotes042]]<br />
* [[ReleaseNotes041]]<br />
* [[ReleaseNotes040]]<br />
* [[ReleaseNotes039]]<br />
* [[ReleaseNotes038]]<br />
* [[ReleaseNotes037]]<br />
* [[ReleaseNotes036]]<br />
* [[ReleaseNotes035]]<br />
<br />
[[Category:Marketing]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62437Diffusion Curves2010-05-30T08:13:31Z<p>Jaspervdg: /* Representation */ Another alternative</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
Instead of defining a group that gets diffused it may also make sense to use subpaths and diffuse those:<br />
<br />
<path d="M 0,0 L 190,190 M 500,500 L 150,0"<br />
leftBoundary="#F00 #00F #F70 #7F0" rightBoundary="#00F #F00 #0F7 #07F"<br />
boundaryBlur="5" diffuse="true" /><br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers either use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62407Diffusion Curves2010-05-29T14:23:17Z<p>Jaspervdg: </p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images (although it's not too bad, the gradients compress ''very'' well).<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers either use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**- A mesh is apparently hard to render in a high quality manner on existing renderers (at least Batik has problems with rendering the triangles precisely).<br />
**Note that other interpolation/approximation schemes can give higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/<br />
*An initial implementation: https://code.launchpad.net/~jaspervdg/+junk/diffuselib</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Talk:NewFromTemplateSpec&diff=62383Talk:NewFromTemplateSpec2010-05-29T12:09:52Z<p>Jaspervdg: /* Notation */</p>
<hr />
<div>==Point on the current template selector==<br />
{|<br />
|<br />
The current system in order to choose a template is deprecated. It's simply a list in the menu (see picture).<br />
# You can't '''parametrize''' templates (width, height, border, ...).<br />
# You can't easily '''add''' new templates.<br />
# You can't '''visualize''' templates before choice.<br />
# The list don't respect any '''order'''.<br />
# Templates are not '''categorized''' (CD, DVD, screen, ...).<br />
# Templates '''names''' don't respect specifications:<br />
#* Some contains '''_''' between words (like icon_16x16).<br />
#* Some templates are in '''french''' (like "Défaut") and others in '''english''' (like "business_card_...").<br />
# Template list is '''too long'''. It can cause problem for netbooks.<br />
# You can't make template be one of your '''favourites''' or "recently used".<br />
# '''Commons templates''' of the "Document properties dialog" '''are not present''' (like A3, B2, US Letter, ...)<br />
# You can't '''choose the units''' for your new drawing.<br />
|<br />
[[File:Template_Selector_0.47.png|300px]]<br />
|}<br />
<br />
[[User:Binnette|Binnette]] 21:54, 4 March 2010 (UTC)<br />
<br />
== About attributes ==<br />
Is it possible to add completely new attributes into a svg file ? like:<br />
<sodipodi:namedview<br />
inkscape:template-name="Web banner 728x90"<br />
inkscape:template-name-fr="Bannière Web 728x90"<br />
inkscape:template-category="Web/Banner"<br />
inkscape:template-description="A banner for a website, size: 728x90 px"<br />
...<br />
/><br />
<br />
Also, is "sodipodi:namedview" the correct markup for template attributes ?<br />
<br />
[[User:Binnette|Binnette]] 10:11, 15 May 2010 (UTC)<br />
<br />
:Yes, it is possible (we use custom attributes quite a lot in Inkscape). But do it with some care. For example, the category attribute will probably be necessary, but possibly you can just use an existing property for some of the others. --[[User:Jaspervdg|Jaspervdg]] 12:07, 29 May 2010 (UTC)<br />
<br />
== Categories names ==<br />
=== Translations ===<br />
Do we have to traduce categories names ? If yes, we can add new attributes in svg files, like :<br />
inkscape:template-category-fr="Fond d'écran"<br />
<br />
See ya [[User:Binnette|Binnette]] 09:52, 15 May 2010 (UTC)<br />
<br />
=== Notation ===<br />
Should we use underscore between words ? like :<br />
inkscape:template-category="Paper_sizes"<br />
or can we simply use:<br />
inkscape:template-category="Paper sizes"<br />
<br />
[[User:Binnette|Binnette]] 09:55, 15 May 2010 (UTC)<br />
<br />
:I'd go with spaces.<br />
<br />
== Keywords ==<br />
I think that keywords are optionals, because they must be traduced in too many languages. And there is categories in order to find templates. Should we use them or not ?<br />
<br />
[[User:Binnette|Binnette]] 09:56, 15 May 2010 (UTC)<br />
<br />
== Currents categories ==<br />
=== Background ===<br />
Is "background" the same category as "Desktop" ? [[User:Binnette|Binnette]] 09:57, 15 May 2010 (UTC)<br />
<br />
=== Defaults ===<br />
"default_mm.svg" and "default_pt.svg" don't respect specifications. Must be "default.mm.svg" and "default.pt.svg". Is it correct ? [[User:Binnette|Binnette]] 09:59, 15 May 2010 (UTC)</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Talk:NewFromTemplateSpec&diff=62377Talk:NewFromTemplateSpec2010-05-29T12:07:28Z<p>Jaspervdg: /* About attributes */</p>
<hr />
<div>==Point on the current template selector==<br />
{|<br />
|<br />
The current system in order to choose a template is deprecated. It's simply a list in the menu (see picture).<br />
# You can't '''parametrize''' templates (width, height, border, ...).<br />
# You can't easily '''add''' new templates.<br />
# You can't '''visualize''' templates before choice.<br />
# The list don't respect any '''order'''.<br />
# Templates are not '''categorized''' (CD, DVD, screen, ...).<br />
# Templates '''names''' don't respect specifications:<br />
#* Some contains '''_''' between words (like icon_16x16).<br />
#* Some templates are in '''french''' (like "Défaut") and others in '''english''' (like "business_card_...").<br />
# Template list is '''too long'''. It can cause problem for netbooks.<br />
# You can't make template be one of your '''favourites''' or "recently used".<br />
# '''Commons templates''' of the "Document properties dialog" '''are not present''' (like A3, B2, US Letter, ...)<br />
# You can't '''choose the units''' for your new drawing.<br />
|<br />
[[File:Template_Selector_0.47.png|300px]]<br />
|}<br />
<br />
[[User:Binnette|Binnette]] 21:54, 4 March 2010 (UTC)<br />
<br />
== About attributes ==<br />
Is it possible to add completely new attributes into a svg file ? like:<br />
<sodipodi:namedview<br />
inkscape:template-name="Web banner 728x90"<br />
inkscape:template-name-fr="Bannière Web 728x90"<br />
inkscape:template-category="Web/Banner"<br />
inkscape:template-description="A banner for a website, size: 728x90 px"<br />
...<br />
/><br />
<br />
Also, is "sodipodi:namedview" the correct markup for template attributes ?<br />
<br />
[[User:Binnette|Binnette]] 10:11, 15 May 2010 (UTC)<br />
<br />
:Yes, it is possible (we use custom attributes quite a lot in Inkscape). But do it with some care. For example, the category attribute will probably be necessary, but possibly you can just use an existing property for some of the others. --[[User:Jaspervdg|Jaspervdg]] 12:07, 29 May 2010 (UTC)<br />
<br />
== Categories names ==<br />
=== Translations ===<br />
Do we have to traduce categories names ? If yes, we can add new attributes in svg files, like :<br />
inkscape:template-category-fr="Fond d'écran"<br />
<br />
See ya [[User:Binnette|Binnette]] 09:52, 15 May 2010 (UTC)<br />
<br />
=== Notation ===<br />
Should we use underscore between words ? like :<br />
inkscape:template-category="Paper_sizes"<br />
or can we simply use:<br />
inkscape:template-category="Paper sizes"<br />
<br />
[[User:Binnette|Binnette]] 09:55, 15 May 2010 (UTC)<br />
<br />
== Keywords ==<br />
I think that keywords are optionals, because they must be traduced in too many languages. And there is categories in order to find templates. Should we use them or not ?<br />
<br />
[[User:Binnette|Binnette]] 09:56, 15 May 2010 (UTC)<br />
<br />
== Currents categories ==<br />
=== Background ===<br />
Is "background" the same category as "Desktop" ? [[User:Binnette|Binnette]] 09:57, 15 May 2010 (UTC)<br />
<br />
=== Defaults ===<br />
"default_mm.svg" and "default_pt.svg" don't respect specifications. Must be "default.mm.svg" and "default.pt.svg". Is it correct ? [[User:Binnette|Binnette]] 09:59, 15 May 2010 (UTC)</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62089Diffusion Curves2010-05-17T16:07:06Z<p>Jaspervdg: /* Converting to SVG */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering.<br />
**+ High quality at a specific resolution.<br />
**- Low quality on zooming in.<br />
**- Also large for simple images.<br />
*Using filters (for example, it should be possible to [[Spatially Varying Blur|simulate spatially varying blur]] by doing multiple blurs and combining the results using weights).<br />
**+ Very low (almost fixed) storage requirements.<br />
**- Diffusion difficult to implement efficiently (fast solvers either use multigrid methods or kernels of spatially varying size).<br />
**- Spatially varying blur is difficult to implement with good quality.<br />
*By solving the Laplace equations on a (Delaunay) triangulation, using barycentric interpolation between the vertices.<br />
**+ Good quality at any resolution.<br />
**+ Storage scales directly with the complexity of the image.<br />
**- Needs "add" (and "in") compositing, which is only available in filters in SVG 1.1 (it is also available in [http://www.w3.org/TR/SVGCompositing/ SVG Compositing]).<br />
**Note that other interpolation/approximation schemes can give higher quality result but are also harder to use in the solver (as well as in the resulting SVG).<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62083Diffusion Curves2010-05-17T15:44:02Z<p>Jaspervdg: /* Mathematical Definition */ Alternative formulations</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
Alternatively diffusion curves can be seen as minimizing the integral (over the entire image) of the squared gradient magnitude, with color constraints at certain points. This is convenient when using a representation based on triangles with barycentric interpolation (as this yields a piecewise linear function the Laplacian is zero everywhere, except on the boundaries).<br />
<br />
It might also be convenient to use an alternative method for incorporating blur, as simulating a spatially varying blur is not easy. One method might be to use an equation based on the heat equation which can be used for doing a spatially varying blur (<math>C</math> represents the color constraints):<br />
<br />
<math>\begin{align}<br />
\gamma\frac{\partial}{\partial t}y&=\nabla\cdot(\beta\nabla y)<br />
\\\gamma(f-C)&=\nabla\cdot(\beta\nabla f)<br />
\\0&=\nabla\cdot(\beta\nabla f)+\gamma(C-f)<br />
\\f&=\arg\min_f \int_{\mathbb{R}^2}\frac{1}{2}\|\beta^{1/2}\nabla f\|^2+(C-\frac{1}{2}f)\gamma f\,dx<br />
\end{align}</math><br />
<br />
Or else the color constraints could be applied using the derivative of the colors over each edge in combination with ''the'' color on the edge (which would be the average of the colors on either side). When blurring an edge the derivative would get smaller (by a factor of <math>1/blurRadius</math> for example).<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering... (Obviously not very appealing.)<br />
*Using filters (for example, it should be possible to simulate spatially varying blur by doing multiple blurs and combining the results using weights).<br />
*By solving the Laplace equations on a Delaunay triangulation or something similar, and using ordinary gradients and/or blurs for the finishing touches or to make it possible to use a coarser grid. (This could give problems in the presence of "curved curves".)<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62071Diffusion Curves2010-05-17T14:55:34Z<p>Jaspervdg: /* Representation */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
The links at the bottom define various features that can be useful for Diffusion Curves. Here the following features are considered:<br />
<br />
* Colors at nodes / gradients defined on paths (on one or both sides of the curve)<br />
<!--* Linking colors (also per side of a curve) --><br />
* Diffusion across boundaries<br />
<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#F00 #00F" rightBoundary="#00F #F00" boundaryBlur="5" /><br />
</g><br />
<br />
Or:<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="url(#redToBlue)" rightBoundary="url(#blueToRed)" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also vary along the path, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering... (Obviously not very appealing.)<br />
*Using filters (for example, it should be possible to simulate spatially varying blur by doing multiple blurs and combining the results using weights).<br />
*By solving the Laplace equations on a Delaunay triangulation or something similar, and using ordinary gradients and/or blurs for the finishing touches or to make it possible to use a coarser grid. (This could give problems in the presence of "curved curves".)<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=62053Diffusion Curves2010-05-17T09:37:38Z<p>Jaspervdg: /* Links */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#redToBlue" rightBoundary="#blueToRed" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also be defined by a gradient, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering... (Obviously not very appealing.)<br />
*Using filters (for example, it should be possible to simulate spatially varying blur by doing multiple blurs and combining the results using weights).<br />
*By solving the Laplace equations on a Delaunay triangulation or something similar, and using ordinary gradients and/or blurs for the finishing touches or to make it possible to use a coarser grid. (This could give problems in the presence of "curved curves".)<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*PhD thesis (including a method for vectorizing Diffusion Curves): http://artis.imag.fr/Publications/2009/Orz09/<br />
*Diffusion constraints: http://artis.inrialpes.fr/Publications/2010/BEDT10/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Spatially_Varying_Blur&diff=61603Spatially Varying Blur2010-04-26T16:26:36Z<p>Jaspervdg: </p>
<hr />
<div>Spatially varying blur can be important for a number of effects, not the least of which is depth-of-field. Unfortunately SVG does not support this directly and we need to make some approximation of the effect.<br />
<br />
One possibility is to do a simple linear interpolation between two blurs, but this tends to give an effective kernel which is only a very poor fit to the true kernel desired, it tends to give a much too sharp result. <br />
<br />
This page looks at possibilities for creating an improved spatially varying blur.<br />
<br />
== L2-minimized fit ==<br />
In general the easiest global error metric to minimize is the l2-norm. This is simply (the root of) the integral of the squared error. Which in this case can be formulated as (<math>g(\sigma)</math> is the kernel of a Gaussian blur with standard deviation <math>\sigma</math>, <math>G(\sigma_a,\sigma_b)</math> is the integral of the product of two kernels, <math>\sigma_1<\sigma<\sigma_2</math> and <math>0<a<1</math>)<br />
<br />
<math>\begin{align}<br />
e(\sigma,\sigma_1,\sigma_2,a)&=\int_{-\infty}^{\infty}\left[g(\sigma)-\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)\right]^2dx<br />
\\&=\int_{-\infty}^{\infty}g(\sigma)^2-2g(\sigma)\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)+\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)^2dx<br />
\\&=G(\sigma,\sigma)-2\left[(1-a)G(\sigma,\sigma_1)+a\,G(\sigma,\sigma_2)\right]+(1-a)^2G(\sigma_1,\sigma_1)+2a(1-a)G(\sigma_1,\sigma_2)+a^2\,G(\sigma_2,\sigma_2)<br />
.\end{align}</math><br />
<br />
Equating the derivative to zero (in order to minimize the quadratic equation in <math>a</math>) we get<br />
<br />
<math>\begin{align}<br />
0&=2\left[G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)\right]-2(1-a)G(\sigma_1,\sigma_1)+2(1-2a)G(\sigma_1,\sigma_2)+2a\,G(\sigma_2,\sigma_2)<br />
\\0&=G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)-G(\sigma_1,\sigma_1)+a\,G(\sigma_1,\sigma_1)+G(\sigma_1,\sigma_2)-2a\,G(\sigma_1,\sigma_2)+a\,G(\sigma_2,\sigma_2)<br />
\\a&=\frac{G(\sigma,\sigma_2)-G(\sigma,\sigma_1)+G(\sigma_1,\sigma_1)-G(\sigma_1,\sigma_2)}{G(\sigma_1,\sigma_1)-2\,G(\sigma_1,\sigma_2)+G(\sigma_2,\sigma_2)}<br />
.\end{align}</math><!-- Verified numerically for s,s1,s2=2,1,3 --><br />
<br />
This uses<br />
<br />
<math>\begin{align}<br />
g(\sigma)&=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-x^2/(2\sigma^2)}<br />
\\G(\sigma_a,\sigma_b)&=\frac{1}{\sqrt{2\pi(\sigma_a^2+\sigma_b^2)}}<br />
.\end{align}</math><br />
<br />
<!-- I think it's probably just best to use feComponentTransfer with type=table<br />
<br />
Filling in and simplifying we get<br />
<br />
<math>\begin{align}<br />
a&=\frac{G(\sigma,\sigma_2)-G(\sigma,\sigma_1)+G(\sigma_1,\sigma_1)-G(\sigma_1,\sigma_2)}{G(\sigma_1,\sigma_1)-2\,G(\sigma_1,\sigma_2)+G(\sigma_2,\sigma_2)}<br />
\\&=\frac{\frac{1}{\sqrt{2\pi(\sigma^2+\sigma_2^2)}}-\frac{1}{\sqrt{2\pi(\sigma^2+\sigma_1^2)}}+\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_1^2)}}-\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_2^2)}}}{\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_1^2)}}-2\,\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_2^2)}}+\frac{1}{\sqrt{2\pi(\sigma_2^2+\sigma_2^2)}}}<br />
\\&=\frac{\frac{1}{\sqrt{\sigma^2+\sigma_2^2}}-\frac{1}{\sqrt{\sigma^2+\sigma_1^2}}+\frac{1}{\sqrt{\sigma_1^2+\sigma_1^2}}-\frac{1}{\sqrt{\sigma_1^2+\sigma_2^2}}}{\frac{1}{\sqrt{\sigma_1^2+\sigma_1^2}}-2\,\frac{1}{\sqrt{\sigma_1^2+\sigma_2^2}}+\frac{1}{\sqrt{\sigma_2^2+\sigma_2^2}}}<br />
.\end{align}</math><br />
--></div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Spatially_Varying_Blur&diff=61585Spatially Varying Blur2010-04-26T11:32:57Z<p>Jaspervdg: </p>
<hr />
<div>Spatially varying blur can be important for a number of effects, not the least of which is depth-of-field. Unfortunately SVG does not support this directly and we need to make some approximation of the effect.<br />
<br />
One possibility is to do a simple linear interpolation between two blurs, but this tends to give an effective kernel which is only a very poor fit to the true kernel desired, it tends to give a much too sharp result. <br />
<br />
This leads to wanting to create a better fitting interpolation between the two blurs.<br />
<br />
== L2-minimized fit ==<br />
In general the easiest global error metric to minimize is the l2-norm. This is simply (the root of) the integral of the squared error. Which in this case can be formulated as (<math>g(\sigma)</math> is the kernel of a Gaussian blur with standard deviation <math>\sigma</math>, <math>G(\sigma_a,\sigma_b)</math> is the integral of the product of two kernels, <math>\sigma_1<\sigma<\sigma_2</math> and <math>0<a<1</math>)<br />
<br />
<math>\begin{align}<br />
e(\sigma,\sigma_1,\sigma_2,a)&=\int_{-\infty}^{\infty}\left[g(\sigma)-\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)\right]^2dx<br />
\\&=\int_{-\infty}^{\infty}g(\sigma)^2-2g(\sigma)\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)+\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)^2dx<br />
\\&=G(\sigma,\sigma)-2\left[(1-a)G(\sigma,\sigma_1)+a\,G(\sigma,\sigma_2)\right]+(1-a)^2G(\sigma_1,\sigma_1)+2a(1-a)G(\sigma_1,\sigma_2)+a^2\,G(\sigma_2,\sigma_2)<br />
.\end{align}</math><br />
<br />
Equating the derivative to zero (in order to minimize the quadratic equation in <math>a</math>) we get<br />
<br />
<math>\begin{align}<br />
0&=2\left[G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)\right]-2(1-a)G(\sigma_1,\sigma_1)+2(1-2a)G(\sigma_1,\sigma_2)+2a\,G(\sigma_2,\sigma_2)<br />
\\0&=G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)-G(\sigma_1,\sigma_1)+a\,G(\sigma_1,\sigma_1)+G(\sigma_1,\sigma_2)-2a\,G(\sigma_1,\sigma_2)+a\,G(\sigma_2,\sigma_2)<br />
\\a&=\frac{G(\sigma,\sigma_2)-G(\sigma,\sigma_1)+G(\sigma_1,\sigma_1)-G(\sigma_1,\sigma_2)}{G(\sigma_1,\sigma_1)-2\,G(\sigma_1,\sigma_2)+G(\sigma_2,\sigma_2)}<br />
.\end{align}</math><!-- Verified numerically for s,s1,s2=2,1,3 --><br />
<br />
This uses<br />
<br />
<math>\begin{align}<br />
g(\sigma)&=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-x^2/(2\sigma^2)}<br />
\\G(\sigma_a,\sigma_b)&=\frac{1}{\sqrt{2\pi(\sigma_a^2+\sigma_b^2)}}<br />
.\end{align}</math><br />
<br />
<!-- I think it's probably just best to use feComponentTransfer with type=table<br />
<br />
Filling in and simplifying we get<br />
<br />
<math>\begin{align}<br />
a&=\frac{G(\sigma,\sigma_2)-G(\sigma,\sigma_1)+G(\sigma_1,\sigma_1)-G(\sigma_1,\sigma_2)}{G(\sigma_1,\sigma_1)-2\,G(\sigma_1,\sigma_2)+G(\sigma_2,\sigma_2)}<br />
\\&=\frac{\frac{1}{\sqrt{2\pi(\sigma^2+\sigma_2^2)}}-\frac{1}{\sqrt{2\pi(\sigma^2+\sigma_1^2)}}+\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_1^2)}}-\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_2^2)}}}{\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_1^2)}}-2\,\frac{1}{\sqrt{2\pi(\sigma_1^2+\sigma_2^2)}}+\frac{1}{\sqrt{2\pi(\sigma_2^2+\sigma_2^2)}}}<br />
\\&=\frac{\frac{1}{\sqrt{\sigma^2+\sigma_2^2}}-\frac{1}{\sqrt{\sigma^2+\sigma_1^2}}+\frac{1}{\sqrt{\sigma_1^2+\sigma_1^2}}-\frac{1}{\sqrt{\sigma_1^2+\sigma_2^2}}}{\frac{1}{\sqrt{\sigma_1^2+\sigma_1^2}}-2\,\frac{1}{\sqrt{\sigma_1^2+\sigma_2^2}}+\frac{1}{\sqrt{\sigma_2^2+\sigma_2^2}}}<br />
.\end{align}</math><br />
--></div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Spatially_Varying_Blur&diff=61537Spatially Varying Blur2010-04-23T12:25:53Z<p>Jaspervdg: Start</p>
<hr />
<div>Spatially varying blur can be important for a number of effects, not the least of which is depth-of-field. Unfortunately SVG does not support this directly and we need to make some approximation of the effect.<br />
<br />
One possibility is to do a simple linear interpolation between two blurs, but this tends to give an effective kernel which is only a very poor fit to the true kernel desired, it tends to give a much too sharp result. <br />
<br />
This leads to wanting to create a better fitting interpolation between the two blurs.<br />
<br />
== L2-minimized fit ==<br />
In general the easiest global error metric to minimize is the l2-norm. This is simply (the root of) the integral of the squared error. Which in this case can be formulated as (<math>g(\sigma)</math> is the kernel of a Gaussian blur with standard deviation <math>\sigma</math>, <math>G(\sigma_a,\sigma_b)</math> is the integral of the product of two kernels, <math>\sigma_1<\sigma<\sigma_2</math> and <math>0<a<1</math>)<br />
<br />
<math>\begin{align}<br />
e(\sigma,\sigma_1,\sigma_2,a)&=\int_{-\infty}^{\infty}\left[g(\sigma)-\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)\right]^2dx<br />
\\&=\int_{-\infty}^{\infty}g(\sigma)^2-2g(\sigma)\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)+\left((1-a)g(\sigma_1)+a\,g(\sigma_2)\right)^2dx<br />
\\&=G(\sigma,\sigma)-2\left[(1-a)G(\sigma,\sigma_1)+a\,G(\sigma,\sigma_2)\right]+(1-a)^2G(\sigma_1,\sigma_1)+2a(1-a)G(\sigma_1,\sigma_2)+a^2\,G(\sigma_2,\sigma_2)<br />
.\end{align}</math><br />
<br />
Equating the derivative to zero (in order to minimize the quadratic equation in <math>a</math>) we get<br />
<br />
<math>\begin{align}<br />
0&=2\left[G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)\right]-2(1-a)G(\sigma_1,\sigma_1)+2(1-2a)G(\sigma_1,\sigma_2)+2a\,G(\sigma_2,\sigma_2)<br />
\\0&=G(\sigma,\sigma_1)-\,G(\sigma,\sigma_2)-G(\sigma_1,\sigma_1)+a\,G(\sigma_1,\sigma_1)+G(\sigma_1,\sigma_2)-2a\,G(\sigma_1,\sigma_2)+a\,G(\sigma_2,\sigma_2)<br />
\\a&=\frac{G(\sigma_1,\sigma_1)-G(\sigma_1,\sigma_2)-(G(\sigma,\sigma_1)-G(\sigma,\sigma_2))}{G(\sigma_1,\sigma_1)-2\,G(\sigma_1,\sigma_2)+G(\sigma_2,\sigma_2)}<br />
.\end{align}</math><!-- Verified numerically for s,s1,s2=2,1,3 --><br />
<br />
For reference:<br />
<br />
<math>g(\sigma)=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-x^2/(2\sigma^2)}</math><br />
<br />
<math>G(\sigma_a,\sigma_b)=\frac{1}{\sqrt{2\pi(\sigma_a^2+\sigma_b^2)}}</math></div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=55453Advanced Gradients2009-12-29T18:03:43Z<p>Jaspervdg: /* More */</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
This page was started as part of the response to [https://bugs.launchpad.net/inkscape/+bug/346681 bug 346681], mainly to provide an alternative for a bitmap fallback.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
===Arctan approximation quality===<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
Note that this approximation method corresponds to the approximation [http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm described here] for quadrant 1 (with the roles of x and y reversed, just like in the graph above), scaled by <math>2/\pi</math>:<br />
<br />
<math>\begin{align}<br />
\frac{2}{\pi}\cdot\frac{\pi}{4}\left(1-\frac{y-x}{x+y}\right)&=\frac{1}{2}\left(1-\frac{y-x}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y}{x+y}+\frac{x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y+x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{2x}{x+y}\right)<br />
\\&=\frac{x}{x+y}<br />
\end{align}</math><br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]], as well as [[Diffusion_Curves|this Wiki page]] for information on attempts to make Diffusion Curves suitable for implementation in Inkscape.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=55395Diffusion Curves2009-12-28T15:30:49Z<p>Jaspervdg: /* Representation */</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#redToBlue" rightBoundary="#blueToRed" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also be defined by a gradient, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
Normally diffusion curves will have infinite extent, but this can be controlled when needed by surrounding a set of curves with a closed path that has an outside boundary which is fully transparent.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering... (Obviously not very appealing.)<br />
*Using filters (for example, it should be possible to simulate spatially varying blur by doing multiple blurs and combining the results using weights).<br />
*By solving the Laplace equations on a Delaunay triangulation or something similar, and using ordinary gradients and/or blurs for the finishing touches or to make it possible to use a coarser grid. (This could give problems in the presence of "curved curves".)<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Diffusion_Curves&diff=55393Diffusion Curves2009-12-28T15:29:08Z<p>Jaspervdg: Created page with '[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the ...'</p>
<hr />
<div>[http://artis.imag.fr/Publications/2008/OBWBTS08/ Diffusion Curves] are a way of specifying very free form gradients. It works by letting colors diffuse from curves, seeding the colors along both sides of the curves using gradients (along the curves). Additionally a varying amount of blur can be applied along the curves. This makes diffusion curves extremely flexible and very interesting to have in Inkscape.<br />
<br />
==Representation==<br />
Diffusion curves could be represented by paths with gradients attached to them, along with an enclosing group that says that the colors should be diffused within that group. For example (don't mind the exact attributes):<br />
<br />
<g diffuse="true"><br />
<path d="M 0,0 L 190,190"<br />
leftBoundary="#redToBlue" rightBoundary="#blueToRed" boundaryBlur="5" /><br />
</g><br />
<br />
Assuming that the two gradients are made to go from #F00 to #00F and vice versa this would roughly look like this (note that this is just a rough approximation):<br />
<br />
[[Image:DiffusionCurveSimulation.png]]<br />
<br />
Note that with diffusion curves the blur itself can also be defined by a gradient, which could be used in the above image to let the edge be sharper in some areas. This is useful for depth of field effects for example.<br />
<br />
==Mathematical Definition==<br />
Diffusion curves are defined as the solution to a Laplace equation (the sum of second partial derivatives is zero) with boundary conditions (the colors on the curves). This is done for both the colors and the blur and then a spatially varying blur is applied to the diffused colors using the diffused blur values.<br />
<br />
==Converting to SVG==<br />
There would be several possible avenues for converting diffusion curves to SVG:<br />
*Bitmap rendering... (Obviously not very appealing.)<br />
*Using filters (for example, it should be possible to simulate spatially varying blur by doing multiple blurs and combining the results using weights).<br />
*By solving the Laplace equations on a Delaunay triangulation or something similar, and using ordinary gradients and/or blurs for the finishing touches or to make it possible to use a coarser grid. (This could give problems in the presence of "curved curves".)<br />
<br />
==Questions/Problems==<br />
*If diffusion curves are indeed represented by paths inside a group, what happens with subgroups or shapes without having gradients defined along their edges?<br />
*What should happen with 2D objects (filled shapes and strokes) in diffusion groups?<br />
**It might actually be interesting to not only set colors and blur values (heat capacity?) along the sides of edges (1D), but also for surfaces (2D). This shouldn't complicate things much. In fact, it might even be slightly easier to handle the 2D case properly (as it is easier to discretize for example).<br />
*It might be interesting to redefine them in some way that unifies the color diffusion and blurring. E.g. currently colors are either to be met exactly or not at all, is it possible to reformulate the problem in such a way that we can restrict colors to varying degrees?<br />
<br />
==Links==<br />
*Original paper: http://artis.imag.fr/Publications/2008/OBWBTS08/<br />
*Faster/better solver: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-solver/<br />
*Application of diffusion curves to texture rendering: http://www.cg.tuwien.ac.at/research/publications/2009/jeschke-09-rendering/</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:DiffusionCurveSimulation.png&diff=55391File:DiffusionCurveSimulation.png2009-12-28T15:07:39Z<p>Jaspervdg: uploaded a new version of "File:DiffusionCurveSimulation.png": Better edges.</p>
<hr />
<div>Example of what a diffusion curve might (roughly) look like.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:DiffusionCurveSimulation.png&diff=55389File:DiffusionCurveSimulation.png2009-12-28T15:01:39Z<p>Jaspervdg: uploaded a new version of "File:DiffusionCurveSimulation.png": Including blur.</p>
<hr />
<div>Example of what a diffusion curve might (roughly) look like.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:DiffusionCurveSimulation.png&diff=55387File:DiffusionCurveSimulation.png2009-12-28T14:55:50Z<p>Jaspervdg: Example of what a diffusion curve might (roughly) look like.</p>
<hr />
<div>Example of what a diffusion curve might (roughly) look like.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Testing_Inkscape&diff=54807Testing Inkscape2009-11-17T10:24:54Z<p>Jaspervdg: /* Rendering tests */</p>
<hr />
<div>== Testing Inkscape ==<br />
<br />
Inkscape is a young project and the emphasis is still on adding features. Nonetheless it is gratifying that the stability of Inkspace has been steadily rising with each release.<br />
<br />
The most important part of 'Testing' is simply to use Inkscape for [[FAQ#Is_Inkscape_ready_for_regular_users_to_use.3F|normal work]] -- confirming that Inkscape has reached this level of maturity, exercise the new features and verify that the application works as expected.<br />
<br />
[http://bugs.launchpad.net/inkscape/ Report a bug] if you find anything that does not behave as it should. A bug report should include at least a step-by-step description of how to trigger the bug and/or a test file that demonstrates the bug (the smaller/more focussed the test file the better).<br />
<br />
? Follow up<br />
<br />
=== Users ===<br />
<br />
The field is wide open. We are keen to receive [http://bugs.launchpad.net/inkscape/ bug reports] and feature requests (in the form of a bug report). These often require analysis, clarification and further action. Anyone can do this.<br />
<br />
Better still would be to provide patches for any part of the application that is not up to the standard you expect - it is confirmation that the project is evolving. Note that serious testing should be done with an 'unstable' build, either one that you made yourself (see [[CompilingInkscape]]), or a snapshot that you have downloaded. We would also like to hear about areas in which we do not have parity with comparable applications. If you find that you are coming up with interesting ideas concerning shortcomings in Inkscape, or plans for its future, get involved with the Inkscape testers group.<br />
<br />
We need people to create and update documentation, online help, tutorials and screen shots. Noting defects in these is a perfectly valid form of testing - we do not want releases to go out with obsolete documentation.<br />
<br />
=== Inkscape Testers ===<br />
<br />
A community of Inkscape testers has grown up which has its own [http://lists.sourceforge.net/lists/listinfo/inkscape-tester mailing list], and it is to be hoped that this will spearhead all work on usability and human factors. This group should be your first port of call for these areas:<br />
<br />
* [[ComplianceTesting]]<br />
* [[RegressionTesting]]<br />
* [[InteroperabilityTesting]]<br />
* [[UsabilityTesting]]<br />
* [[PerformanceTesting]]<br />
* [[HIG compliance]]<br />
<br />
See also [[TestingFramework]].<br />
Note: Bryce? Jon? shouldn't the whole of that page be merged here? Or is it better to have this info in two pieces. IMHO wiki pages should not be made too long.<br />
<br />
=== Rendering tests ===<br />
<br />
In addition, Inkscape has rendering tests that do not necessarily need a developer to create, run and analyze. The actual tests can be found in SVN (see below). Below you can find information on how to run and create these tests yourself.<br />
<br />
<span style="font-size:larger;">See [http://auriga.mine.nu/inkscape/ this list] for up-to-date results.</span><br />
<br />
==== Running rendering tests ====<br />
Apart from running low-level unit tests Inkscape can also be tested on a higher level (also see [[SVG Test Suite Compliance]]. Currently (2008-7-26) there is a rendering test tool (along with a few test cases) in SVN ([https://inkscape.svn.sourceforge.net/svnroot/inkscape/gsoc-testsuite/tester/]) which can be used to partially automate rendering tests.<br />
<br />
To run the rendering tests:<br />
<br />
* If needed, compile tester.cpp using 'g++ -o tester tester.cpp' (there is a precompiled .exe in SVN for Windows users).<br />
* Execute runtests.py. If needed you can specify Inkscape's path and a few other things (execute 'runtests.py --help' to see which options are available).<br />
<br />
Note that by default only a binary comparison between the output and reference files is used, [http://pdiff.sourceforge.net/ perceptualdiff] (or any other comparison tool that returns zero on success and 1 on failure) can be used to aid comparison of images (see the available options of runtests.py). Note that perceptualdiff (1.0.2) had some problems with transparency, these might be solved by now, and if not, there is a patch in its patch tracker.<br />
<br />
To select a subset of tests to perform, specify one or more patterns (with Unix-style wildcards) on the command line. Each pattern is interpreted as specifying a prefix. For example, 'runtest.py bugs' will match any tests whose path relative to the directory with test cases starts with 'bugs' (for example: 'bugsy.svg' or 'bugs/bugXYZ.svg').<br />
<br />
The most common test results are:<br />
* Pass (the output file was matched to a pass reference)<br />
* Fail (the output file was matched to a fail reference)<br />
* New (the output file was not matched to any reference)<br />
* No references (there were no references at all)<br />
<br />
runtests.py puts the output files in a subdirectory 'output' (at the same level as the 'testcases' and 'references' directories).<br />
<br />
==== Creating rendering tests ====<br />
Just put an SVG file in the 'testcases' directory (subdirectories can be used for organizing the tests).<br />
<br />
To add a pass/fail reference, just put it in the corresponding location under references/pass or references/fail. References are matched by prefix, so any reference that has the original name (without its extension) as a prefix is seen as a reference for that file.<br />
<br />
Fail references are used to distinguish between a result that is known wrong and a result that is just (perhaps only slightly) different from the correct rendering. If you are unable to create a pass reference you can even give just a fail reference.<br />
<br />
It is also possible to create an SVG file that should produce the exact same output as a test case but uses simpler (or just different) methods. This practice is suggested in the [http://www.w3.org/Graphics/SVG/Test/svgTest-manual.htm#GeneratingthePNG SVG Conformance Test Plan]. For example, if the test case file is called 'testcases/basic/foo.svg' you could create a "patch" file called 'testcases/basic/foo-patch.svg'. runtests.py would then use Inkscape to create a pass reference file from that (as 'references/pass/basic/foo-patch.svg') and use it as one of the references. (Note that this reference should in general not be committed to SVN.)<br />
<br />
=== Developers ===<br />
<br />
==== Build report ====<br />
There is an 'inkscape build report; which is sent regularly to the inkscape-tester list (and periodically to the developer list, when new problems are seen) that gives a count of warnings spotted in the code.<br />
<br />
* Smoketests<br />
* Defects in the build system<br />
<br />
==== Running unit tests ====<br />
There are now some unit tests which should be performed before checking in. These may take some time to complete, and so this cannot be made a requirement for each build (Test Driven Development), nonetheless everyone is on their honour not to 'break the build' by committing code that does not pass these tests. You can execute them by:<br />
* Linux: Just run 'make check', it will build and run them. It should also work on Mac OS X.<br />
* Windows: Use 'buildtool check' (where buildtool is built using 'g++ -O3 -o buildtool buildtool.cpp) to build and run the unit tests. Alternatively you can use dist-all-check to build everything AND run the unit tests.<br />
<br />
Cxxtests will generate two (more or less equivalent) result files, an XML file and a text file with the extension 'log'. On Linux, those files are located in (buildpath)/src.<br />
<br />
==== Creating unit tests ====<br />
Inkscape uses the [http://cxxtest.sourceforge.net/ CxxTest] framework. To enhance, modify or extend existing unit tests, just edit the existing test file (....-test.h).<br />
<br />
The easiest way to create a new test in a directory which already has some unit tests is to simply copy one of the existing test files, strip it (remove anything specific and rename the class, constructors, etc.) and add some test methods. Take the time to look at the different ASSERT statements CxxTest supports, the TSM_ variants can be especially useful for example when you want to test a lot of different cases. '''Important:''' to make everything build correctly you have to do the following:<br />
* Add the file to the right (already existing) group in the cxxtest target in build.xml<br />
* Append the file to the CXXTEST_TESTSUITES variable in dir/Makefile_insert. Watch the backslashes at the end of the lines. Note that you have to prefix "$(srcdir)/dir/" to your filename, since it is a normal variable not handled by Automake, and you have to use += rather than =, because you're appending to this variable rather than defining it.<br />
<br />
# Do like this:<br />
CXXTEST_TESTSUITES += \<br />
$(srcdir)/dir/first-test.h \<br />
$(srcdir)/dir/second-test.h<br />
<br />
For creating a unit test in a directory which does not have any unit tests yet:<br />
<br />
* Update the Windows build system:<br />
** Add a cxxtestpart group to the cxxtest target in build.xml (just copy and modify an existing one).<br />
** <br />
** Add the corresponding .o file to the exclude list of the lib target in build.xml and to the include list of the linkcxxtests target.<br />
* For Unix, no changes other than adding the file to CXXTEST_TESTSUITES in Makefile_insert are necessary.<br />
<br />
==== Running tests unattended ====<br />
For unit tests this is no problem, just set up something that runs cxxtests and you can use one of the log files it creates to see how it went.<br />
<br />
To be able to run the rendering tests unattended on Windows you have to compile Inkscape as a commandline executable to prevent any CRT runtime error dialog boxes (or something similar) from popping up. On Linux and other Unices, this problem doesn't exist.<br />
<br />
The teststatus.json file that is generated by runtests.py contains all the test results (in [http://www.json.org/ JSON] format). Note that if you only run a subset of the tests this file retains all the information on tests that do not fall into that subset. It also retains old test results. The result codes in this file can be interpreted as in runtests.py (for example, 0, 1 and 2 stand for pass, fail and new, respectively).<br />
<br />
==== Analyzing test coverage ====<br />
To see how well the (unit) tests cover certain parts of the code, or to compare the coverage of rendering tests vs. unit tests, gcov can be used. See [[Profiling]] for more information on how to use gcov and coverage.py (a tool to get some grip on the massive amounts of data gcov can generate).<br />
<br />
[[Category:Help Wanted]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Testing&diff=54805Testing2009-11-17T10:20:55Z<p>Jaspervdg: Redirected page to Testing Inkscape</p>
<hr />
<div>#REDIRECT [[Testing_Inkscape]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=TestingInkscape&diff=54803TestingInkscape2009-11-17T10:19:41Z<p>Jaspervdg: Redirected page to TestingInkscape</p>
<hr />
<div>#REDIRECT [[TestingInkscape]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Testing&diff=54801Testing2009-11-17T10:19:09Z<p>Jaspervdg: Redirected page to TestingInkscape</p>
<hr />
<div>#REDIRECT [[TestingInkscape]]</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52245Advanced Gradients2009-05-08T12:30:27Z<p>Jaspervdg: /* Conical gradient */ Some more info on arctan approximation</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
This page was started as part of the response to [https://bugs.launchpad.net/inkscape/+bug/346681 bug 346681], mainly to provide an alternative for a bitmap fallback.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
===Arctan approximation quality===<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
Note that this approximation method corresponds to the approximation [http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm described here] for quadrant 1 (with the roles of x and y reversed, just like in the graph above), scaled by <math>2/\pi</math>:<br />
<br />
<math>\begin{align}<br />
\frac{2}{\pi}\cdot\frac{\pi}{4}\left(1-\frac{y-x}{x+y}\right)&=\frac{1}{2}\left(1-\frac{y-x}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y}{x+y}+\frac{x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{x+y+x-y}{x+y}\right)<br />
\\&=\frac{1}{2}\left(\frac{2x}{x+y}\right)<br />
\\&=\frac{x}{x+y}<br />
\end{align}</math><br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52243Advanced Gradients2009-05-08T11:09:16Z<p>Jaspervdg: Link to bug.</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
This page was started as part of the response to [https://bugs.launchpad.net/inkscape/+bug/346681 bug 346681], mainly to provide an alternative for a bitmap fallback.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52241Advanced Gradients2009-05-08T11:01:49Z<p>Jaspervdg: /* Formal derivation of feDiffuseLighting method */ Cosine vs. angle can be quite visible.</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but this may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52239Advanced Gradients2009-05-08T09:30:25Z<p>Jaspervdg: /* Spiral gradient */ Math formatting.</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math><br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the <math>[0,1]</math> range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52221Advanced Gradients2009-05-07T16:00:07Z<p>Jaspervdg: /* Conical gradient */ Math formatting.</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as:<br />
<br />
<math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math><br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>2/r</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by the <math>l_1</math> (Manhattan) distance to the center (<math>|x|+|y|</math>) instead of the <math>l_2</math> (Euclidean) distance. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by <math>x</math> divided by the <math>l_2</math> distance to the center (the cosine) or <math>x</math> divided by the <math>l_1</math> distance to the center (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as (setting the center to <math>(0,0)</math> without loss of generality):<br />
<br />
<math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math><br />
<br />
Per the SVG 1.1 specification the surface normal is defined by using a Sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math>.<br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the [0,1] range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=52219Advanced Gradients2009-05-07T15:51:57Z<p>Jaspervdg: /* Separating shape/pattern from color */ Nicer formatting (less detail).</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math>.<br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>\frac{2}{r}</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by <math>|x|+|y|</math> instead of <math>\sqrt{x^2+y^2}</math>. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by a cosine (<math>\frac{x}{\sqrt{x^2+y^2}}</math>) or <math>\frac{x}{|x|+|y|}</math> (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as <math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math> (setting the center to <math>(0,0)</math> without loss of generality). Per the SVG 1.1 specification the surface normal is defined by using a sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math>.<br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the [0,1] range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=50384Advanced Gradients2009-04-17T12:07:26Z<p>Jaspervdg: /* Conical gradient */</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f:\mathbb{R}^2\rightarrow[0,1]</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math>.<br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>\frac{2}{r}</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by <math>|x|+|y|</math> instead of <math>\sqrt{x^2+y^2}</math>. This results in the following (note that this SVG uses the alpha component for computations and apparently Batik has some problems with this):<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
The following graph shows the difference between approximating the angle by a cosine (<math>\frac{x}{\sqrt{x^2+y^2}}</math>) or <math>\frac{x}{|x|+|y|}</math> (note that in this graph the roles of x and y are reversed, as this corresponds better to how angles are normally defined):<br />
<br />
[[Image:AngleApproximationQuality.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as <math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math> (setting the center to <math>(0,0)</math> without loss of generality). Per the SVG 1.1 specification the surface normal is defined by using a sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math>.<br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the [0,1] range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:AngleApproximationQuality.png&diff=50374File:AngleApproximationQuality.png2009-04-17T12:06:32Z<p>Jaspervdg: </p>
<hr />
<div>Graph showing that <math>\frac{y}{|x|+|y|}</math> gives a (much) better estimate of the angle than a sine (<math>\frac{y}{\sqrt{x^2+y^2}}</math>). Note that the blue line is the ideal line.</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=File:AngleApproximationQuality.png&diff=50364File:AngleApproximationQuality.png2009-04-17T12:05:28Z<p>Jaspervdg: Graph showing that <math>\frac{y}{|x|+|y|}</math> gives a (much) better estimate of the angle than a sine (<math>\frac{y}{\sqrt{x^2+y^2}}</math>).</p>
<hr />
<div>Graph showing that <math>\frac{y}{|x|+|y|}</math> gives a (much) better estimate of the angle than a sine (<math>\frac{y}{\sqrt{x^2+y^2}}</math>).</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=50354Advanced Gradients2009-04-17T11:37:41Z<p>Jaspervdg: /* Conical gradient */</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f:\mathbb{R}^2\rightarrow[0,1]</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math>.<br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>\frac{2}{r}</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by <math>|x|+|y|</math> instead of <math>\sqrt{x^2+y^2}</math>. This results in the following:<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as <math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math> (setting the center to <math>(0,0)</math> without loss of generality). Per the SVG 1.1 specification the surface normal is defined by using a sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math>.<br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the [0,1] range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdghttps://wiki.inkscape.org/wiki/index.php?title=Advanced_Gradients&diff=50344Advanced Gradients2009-04-17T11:36:01Z<p>Jaspervdg: /* Conical gradient */</p>
<hr />
<div>There are (apparently) several types of gradients that can be interesting to support, but are not part of the SVG standard. This page is meant to document which gradient types Inkscape may want to support and how these could be simulated.<br />
<br />
==Separating shape/pattern from color==<br />
Any gradient can be defined by a mapping <math>f:\mathbb{R}^2\rightarrow[0,1]</math> from any point in the plane to a value in the range <math>[0,1]</math>, combined with a mapping from the range <math>[0,1]</math> to colors. The former is defined by the type of gradient (and its parameters) and the latter by the gradient stops.<br />
<br />
For each new gradient type it suffices to find a good method of generating <math>f</math> (over all four color channels). The desired colors can then be determined by using an feComponentTransfer filter with the table transfer function type. This allows the gradient to be approximated to any required accuracy. An example for a gradient from red to green to blue to transparent black (assumes we are in a filter definition and an image with <math>f</math> on all four channels is in "f"):<br />
<br />
<feComponentTransfer in="f"><br />
<feFuncR type="table" tableValues="1 0 0 0" /><br />
<feFuncG type="table" tableValues="0 1 0 0" /><br />
<feFuncB type="table" tableValues="0 0 1 0" /><br />
<feFuncA type="table" tableValues="1 1 1 0" /><br />
</feComponentTransfer><br />
<br />
The three images below show an example as it is rendered by the browser, Inkscape and Batik. As can be seen the quality of the gradient is degraded in the top area, where the alpha values are low, likely due to the use of premultiplied alpha. It should be possible to fix this by separating <math>f</math> into an opaque color component and an alpha-only component, applying the component transfer tables separately and then combining them again.<br />
<br />
[[Image:LineargradientCT.svg]]<br />
[[Image:LineargradientCT-Inkscape.png]]<br />
[[Image:LineargradientCT-Batik.png]]<br />
<br />
Alternatively the mapping to colors of the gradient could be done using feDisplacementMap, if <math>f</math> is pre-processed properly. Specifically, the values of <math>f</math> are meant to be interpreted in an absolute sense, while feDisplacementMap uses them as an offset relative to the current position. So if <math>(x1,y1),(x2,y2)</math> defines the bounding box of the object to which the gradient is applied, and a (horizontal) linear gradient is applied to a rectangle using these same coordinates, then the scale parameter should be set in such a way that <math>x1+scale*0.5=x2</math> and <math>x2-scale*0.5=x1</math>, so <math>scale=2(x2-x1)</math>. The x displacement channel should then be set to a channel corresponding to the pre-processed <math>f</math> and the y displacement channel should then be set to some channel that is 0.5 everywhere. An example for the same gradient as above (we are in a defs element, the red channel is assumed to correspond to <math>f</math> and the green channel to one, the bounding box is assumed to be <math>(0,0),(1,1)</math>):<br />
<br />
<g id="symbolstops"><br />
<linearGradient id="gradientstops"><br />
<stop offset="0" stop-color="#f00" /><br />
<stop offset="0.33" stop-color="#0f0" /><br />
<stop offset="0.67" stop-color="#00f" /><br />
<stop offset="1" stop-color="#000" stop-opacity="0" /><br />
</linearGradient><br />
<rect width="150" height="150" fill="url(#gradientstops)" /><br />
</g><br />
<g id="symbolxoffset"><br />
<linearGradient id="gradientxoffset"><br />
<stop offset="0" stop-color="#F00" /><br />
<stop offset="1" stop-color="#000" /><br />
</linearGradient><br />
<rect width="1" height="1" fill="url(#gradientxoffset)" /><br />
</g><br />
<filter ...><br />
...<br />
<feImage xlink:href="#symbolxoffset" result="xoffset" /><br />
<feComposite in="f" in2="xoffset" result="fp" operator="arithmetic" k2="0.5" k3="0.5" /><br />
<feImage xlink:href="#symbolstops" result="stops" /><br />
<feDisplacementMap in="stops" in2="fp" scale="2" xChannelSelector="R" yChannelSelector="G" /><br />
</filter><br />
<br />
This last method has the advantage that there is a more direct correspondence with the gradient stops defined by the user (and does not use an approximation to the gradient as the feComponentTransfer method), but it is obviously also more complex. Also, if the mapping <math>f</math> needs a (non-linear) correction this can directly be taken into account in the feComponentTransfer method. However, the feComponentTransfer method can give a lower quality result if the alpha channel is also part of the gradient (and the viewer uses premultiplied alpha).<br />
<br />
The three images below show a linear gradient colored with the feDisplacementMap method, rendered by the browser, Inkscape and Batik. Clearly this method alleviates the problems with using premultiplied alpha that the feComponentTransfer method has. However, to avoid sampling just outside the defined area the linear gradient has been scaled a bit, and with it <math>f</math> (as this is more precise than scaling <math>f</math> afterwards).<br />
<br />
[[Image:LineargradientDM.svg]]<br />
[[Image:LineargradientDM-Inkscape.png]]<br />
[[Image:LineargradientDM-Batik.png]]<br />
<br />
==Conical gradient==<br />
"A gradient which goes along the circular arc around a center." In other words (ignoring rotations and so on), given a center <math>(cx,cy)</math>, the mapping <math>f</math> is defined as <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\frac{1}{2}</math>.<br />
<br />
One way to mimic a conical gradient is to use a circular gradient to define a conical surface and then use feDiffuseLighting with surfaceScale set to half the radius of the gradient and a distant light source with an elevation of 45 degrees. This doesn't directly result in the right mapping, but it at least shares the property that the pixels on radial lines from the center have the same value. In addition, the generated gradient will be symmetrical, so if this is not wanted the region should be split in two along the symmetry axis.<br />
<br />
Another (arguably simpler) way to achieve the exact same effect would be to again use a radial gradient and approximate a directional derivative using a convolution. The offset should now be 0.5 (0 is the "middle" value) and the divisor should be <math>\frac{2}{r}</math>, assuming the matrix is already properly scaled to truely approximate the gradient.<br />
<br />
The following three images show the feDiffuseLighting method (as Batik does not support feConvolveMatrix with a bias) used with the feDisplacementMap as the result appears in the browser, Inkscape and Batik:<br />
<br />
[[Image:ConicalgradientDMDL.svg]] <br />
[[Image:ConicalgradientDMDL-inkscape.png]]<br />
[[Image:ConicalgradientDMDL-Batik.png]]<br />
<br />
Another method that works both with Inkscape and Batik is to simply compute the cosine directly. This can be done by creating a linear gradient corresponding to the x-coordinate and a radial gradient corresponding to the distance to the center, then computing the reciprocal of the distance function (using feComponentTransfer) and finally multiplying this by the x-coordinate (using appropriate scaling and offset) with feComposite. This has the advantage that no resolution dependent filters are used, but it the precision of the reciprocal is quite low in most (if not all) renderers. Luckily this can, to a great extent, be solved using iterative refinement, resulting in the following images:<br />
<br />
[[Image:ConicalgradientDMRD.svg]] <br />
[[Image:ConicalgradientDMRD-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD-Batik.png]]<br />
<br />
Using the method of multiplying by reciprocal distance we can also define a (much) better approximation to a true conical gradient by dividing by <math>|x|+|y|</math> instead of <math>\sqrt{x^2+y^2}</math>. This results in the following:<br />
<br />
[[Image:ConicalgradientDMRD2.svg]] <br />
[[Image:ConicalgradientDMRD2-Inkscape.png]]<br />
[[Image:ConicalgradientDMRD2-Batik.png]]<br />
<br />
===Formal derivation of feDiffuseLighting method===<br />
To derive the right parameters, first define the (ideal) surface of the cone created by the gradient as <math>Z(x,y)=s-\frac{s}{r}\sqrt{x^2+y^2}</math> (setting the center to <math>(0,0)</math> without loss of generality). Per the SVG 1.1 specification the surface normal is defined by using a sobel filter, however, as this is a reasonable approximation of a directional derivative we use the derivative instead. Specifically, taking the right scale factors into account, the surface normal is defined as:<br />
<br />
<math>\begin{align}<br />
N'_x(x,y)&=-2 \frac{\partial}{\partial x}Z(x,y)<br />
\\&=\frac{2sx}{r\sqrt{x^2+y^2}}<br />
\\N'_y(x,y)&=\frac{2sy}{r\sqrt{x^2+y^2}}<br />
\\N'_z(x,y)&=1<br />
\\N(x,y)&=\frac{N'}{\|N\|}<br />
\end{align}</math><br />
<br />
Assuming a distant (white) light source with a zero azimuth and a diffuse lighting constant of one, the intensity of the resulting image can now be computed as:<br />
<br />
<math>\begin{align}<br />
D(x,y)&=N(x,y)\cdot L(e)<br />
\\&=\frac{1}{\|N'(x,y)\|}\left(\frac{2sx}{r\sqrt{x^2+y^2}}\cos(e)+\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}\sqrt{x^2+y^2}}\left(2sx\cos(e)+r\sqrt{x^2+y^2}\sin(e)\right)<br />
\end{align}</math><br />
<br />
To get a nice gradient we can now demand that <math>D(x,0)</math> is zero for negative <math>x</math> and one for positive <math>x</math> and solve for <math>s</math> and <math>e</math>:<br />
<br />
<math>\begin{align}<br />
D(x,0)&=\frac{1}{\sqrt{4s^2+r^2}|x|}\left(2sx\cos(e)+r|x|\sin(e)\right)<br />
\\&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\mbox{sign}(x)\cos(e)+r\sin(e)\right)<br />
\\D(x_-,0)&=0<br />
\\0&=\frac{1}{\sqrt{4s^2+r^2}}\left(-2s\cos(e)+r\sin(e)\right)<br />
\\2s\cos(e)&=r\sin(e)<br />
\\\frac{\sin(e)}{\cos{e}}&=\frac{2s}{r}<br />
\\e&=\arctan(\frac{2s}{r})<br />
\\D(x_+,0)&=1<br />
\\1&=\frac{1}{\sqrt{4s^2+r^2}}\left(2s\cos(e)+r\sin(e)\right)<br />
\\\sqrt{4s^2+r^2}&=2r\sin(e)<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{r\sqrt{\frac{4s^2}{r^2}+1}}<br />
\\\sqrt{4s^2+r^2}&=\frac{4rs}{\sqrt{\frac{4s^2}+r^2}}<br />
\\4s^2+r^2&=4rs<br />
\\4s^2-4rs+r^2&=0<br />
\\(2s-r)^2&=0<br />
\\s&=\frac{1}{2}r<br />
\\e&=\arctan(1)<br />
\\&=\frac{1}{4}\pi<br />
\end{align}</math><br />
<br />
So surfaceScale should be half of the radius of the radial gradient and the elevation of the light source should be 45 degrees. By filling in this result in <math>D</math> it is apparent that the intensity now corresponds exactly to the cosine of the angle we are really interested in with a conical gradient (scaled and translated to fit in the range <math>[0,1]</math>):<br />
<br />
<math>\begin{align}<br />
D(x,y)&=\frac{1}{\sqrt{4(\frac{1}{2}r)^2+r^2}\sqrt{x^2+y^2}}\left(2\frac{1}{2}rx\cos(\frac{1}{4}\pi)+r\sqrt{x^2+y^2}\sin(\frac{1}{4}\pi)\right)<br />
\\&=\frac{1}{\sqrt{2}\sqrt{x^2+y^2}}\left(x\frac{1}{\sqrt{2}}+\sqrt{x^2+y^2}\frac{1}{\sqrt{2}}\right)<br />
\\&=\frac{x}{2\sqrt{x^2+y^2}}+\frac{1}{2}<br />
\end{align}</math><br />
<br />
For a perfect result it should now be taken into account that we have a cosine and not an angle, but the difference is not very big and it may not always be an issue.<br />
<br />
==Spiral gradient==<br />
Here defined as similar to a conical gradient, but with the mapping <math>f</math> also depending on the distance to the center. Specifically <math>f(x,y)=\frac{1}{2\pi}\arctan(y-cy,x-cx)+\sqrt{(x-cx)^2+(y-cy)^2}\mod 1</math>.<br />
<br />
If a conical gradient can be created then this can be created by simply adding the distance to the center. If needed use can be made of the fact that modular arithmetic is used (that is, a long steep gradient is equivalent to many small, equally steep, gradients).<br />
<br />
To avoid overflow in the mapping it can be scaled by 0.5, allowing two "periods" in the [0,1] range. In this case the mapping to colors should be changed accordingly.<br />
<br />
==More==<br />
Diffusion curves? See [[http://artis.imag.fr/Publications/2008/OBWBTS08/]].</div>Jaspervdg