master 0eaa8c9e8839 cached
53 files
358.9 KB
87.5k tokens
223 symbols
1 requests
Download .txt
Showing preview only (379K chars total). Download the full file or copy to clipboard to get everything.
Repository: otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET
Branch: master
Commit: 0eaa8c9e8839
Files: 53
Total size: 358.9 KB

Directory structure:
gitextract_t5vkdpxu/

├── .gitattributes
├── .gitignore
├── .gitmodules
├── COPYING
├── README.md
├── SvgFileType/
│   ├── BenchmarkScope.cs
│   ├── Export/
│   │   ├── PreviewMode.cs
│   │   ├── PropertyNames.cs
│   │   ├── ScanMode.cs
│   │   └── SvgExport.cs
│   ├── Extensions/
│   │   ├── ControlExtensions.cs
│   │   ├── DocumentExtensions.cs
│   │   ├── StringExtensions.cs
│   │   ├── SurfaceExtensions.cs
│   │   ├── SvgDocumentExtensions.cs
│   │   ├── SvgElementExtensions.cs
│   │   ├── SvgUnitExtensions.cs
│   │   ├── SvgUseExtensions.cs
│   │   ├── SvgViewBoxExtensions.cs
│   │   └── SvgVisualElementExtensions.cs
│   ├── FodyWeavers.xml
│   ├── FodyWeavers.xsd
│   ├── Import/
│   │   ├── Direct2DSvgRenderer.cs
│   │   ├── GdipSvgRenderer.cs
│   │   ├── LayersMode.cs
│   │   ├── MyBaseForm.cs
│   │   ├── MyBaseForm.resx
│   │   ├── ResvgSvgRenderer.cs
│   │   ├── StreamTrackerCancellationTokenSource.cs
│   │   ├── SvgImport.cs
│   │   ├── SvgImportConfig.cs
│   │   ├── SvgImportDialog.Designer.cs
│   │   ├── SvgImportDialog.cs
│   │   ├── SvgImportDialog.resx
│   │   └── SvgRenderer2.cs
│   ├── Localization/
│   │   ├── InjectResourceManager.ps1
│   │   ├── Localize.cs
│   │   ├── SingleAssemblyResourceManager.cs
│   │   ├── StringResources.Designer.cs
│   │   ├── StringResources.resx
│   │   ├── StringResources_de.resx
│   │   ├── StringResources_fr.resx
│   │   ├── StringResources_ru.resx
│   │   └── StringResources_tr.resx
│   ├── Logger.cs
│   ├── Services.cs
│   ├── SvgFileType.cs
│   ├── SvgFileTypeFactory.cs
│   ├── SvgFileTypePlugin.csproj
│   ├── SvgFileTypePluginSupportInfo.cs
│   └── UIHelper.cs
├── SvgFileType.ThirdPartyNotices.txt
└── SvgFileType.sln

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following 
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
# 
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the 
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# DNX
project.lock.json
artifacts/

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml

# TODO: Un-comment the next line if you do not want to checkin 
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config

# Windows Store app package directory
AppPackages/
BundleArtifacts/

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml

# Paket dependency manager
.paket/paket.exe

# FAKE - F# Make
.fake/

# CUSTOM
*.editorconfig
Installer/
SvgFileType/Properties/


================================================
FILE: .gitmodules
================================================
[submodule "resvg.net"]
	path = resvg.net
	url = https://github.com/otuncelli/resvg.net.git
[submodule "PaintDotNet.IndirectUI.Fluent"]
	path = PaintDotNet.IndirectUI.Fluent
	url = https://github.com/otuncelli/PaintDotNet.IndirectUI.Fluent.git
[submodule "BitmapVectorizer"]
	path = BitmapVectorizer
	url = https://github.com/otuncelli/BitmapVectorizer.git


================================================
FILE: COPYING
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

================================================
FILE: README.md
================================================
# ![W3C SVG Logo](https://www.w3.org/Icons/SVG/svg-logo-v.png) Scalable Vector Graphics (SVG) Plugin for Paint.NET 

[![](https://img.shields.io/github/release-pre/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET.svg?style=flat)](https://github.com/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET/releases)
[![](https://img.shields.io/github/downloads/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET/total)](https://github.com/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET/releases)

This is a [paint.net](https://getpaint.net) filetype plugin for loading SVG (Scalable Vector Graphics) and its compressed variant SVGZ files. SVG files can be rendered as a flat image or each element/group on a separate layer. This plugin also provides basic image tracing (raster to vector conversion) functionality which works best with black and white drawings. You may export the tracing result as SVG or Paint.NET Shape.

### Prerequisites
paint.net 5.1 or later

### Download links

Here are the download links for latest release:

Installer[^1] (Recommended) | Manual Installation
--- | ---
:floppy_disk: [SvgFileTypePlugin_setup.exe](https://github.com/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET/releases/latest/download/SvgFileTypePlugin_setup.exe) | :floppy_disk: [SvgFileTypePlugin.zip](https://github.com/otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET/releases/latest/download/SvgFileTypePlugin.zip)

[^1]: The portable version of paint.net is not supported by the installer.

### How to install

:warning: **Note: Before install make sure you don't have any other file type plugin installed handling the same file extensions: .svg, .svgz**

:point_right: To automatically install the plugin perform the following steps:
  * Make sure paint.net is not running.
  * Download and run `SvgFileTypePlugin_setup.exe`
  * Follow the steps of the setup wizard.
	
:point_right: To manually install the plugin perform the following steps:
  * Make sure paint.net is not running.
  * Download and extract `SvgFileTypePlugin.zip`
  * If you're using Classic version of paint.net:
    * Copy the `SvgFileTypePlugin` folder into the `<paint.net>\FileTypes` directory (Default location is `C:\Program Files\paint.net\FileTypes`).
  * If you're using [Microsoft Store version of paint.net](https://www.microsoft.com/store/apps/9NBHCS1LX4R0):
    * Copy the `SvgFileTypePlugin` folder into the `<Documents>\paint.net App Files\FileTypes` directory.
  * Done. You may start paint.net.

================================================
FILE: SvgFileType/BenchmarkScope.cs
================================================
// Copyright 2025 Osman Tunçelli. Allrights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace SvgFileTypePlugin;

internal struct BenchmarkScope : IDisposable
{
    private readonly Stopwatch timer;
    private readonly string? name;
    private int disposed;

    public BenchmarkScope(string? name) : this()
    {
        this.name = name;
    }

    public BenchmarkScope()
    {
        timer = Stopwatch.StartNew();
    }

    public void Dispose()
    {
        if (Interlocked.CompareExchange(ref disposed, 1, 0) == 0)
        {
            StringBuilder sb = new StringBuilder(nameof(BenchmarkScope));
            sb.Append(' ');
            if (name is not null)
            {
                sb.Append($"({name}) ");
            }
            sb.Append($"took {timer.ElapsedMilliseconds} ms.");
            Logger.WriteLine(sb.ToString());
        }
    }
}


================================================
FILE: SvgFileType/Export/PreviewMode.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

namespace SvgFileTypePlugin.Export;

internal enum PreviewMode
{
    Fast,
    Slow
}


================================================
FILE: SvgFileType/Export/PropertyNames.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

namespace SvgFileTypePlugin.Export;

internal enum PropertyNames
{
    Angle,
    BrightnessCutoff,
    Color,
    DiscussionLink,
    Enclose,
    FillColor,
    GitHubLink,
    GreymapScale,
    HighpassFilter,
    Invert,
    LowpassFilter,
    Optimize,
    PdnShape,
    PdnShapeName,
    PreviewMode,
    ScanMode,
    Scale,
    SmoothCorners,
    SuppressSpeckles,
    Tight,
    TurnPolicy
}


================================================
FILE: SvgFileType/Export/ScanMode.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

namespace SvgFileTypePlugin.Export;

internal enum ScanMode
{
    Transparent,
    Opaque
}


================================================
FILE: SvgFileType/Export/SvgExport.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using BitmapVectorizer;
using PaintDotNet;
using PaintDotNet.AppModel;
using PaintDotNet.PropertySystem;
using PaintDotNet.PropertySystem.Extensions;
using SvgFileTypePlugin.Extensions;
using SvgFileTypePlugin.Localization;
using static PaintDotNet.UserBlendOps;

namespace SvgFileTypePlugin.Export;

internal static partial class SvgExport
{
    private static Lazy<string?> ShapesDirectory => new(() =>
    {
        try
        {
            IFileSystemService fss = Services.Get<IFileSystemService>();
            string path = Path.Combine(fss.PerUserAppFilesPath, "Shapes");
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            return path;
        }
        catch
        {
            return null;
        }
    });

    public static string? ShowSaveShapeDialog()
    {
        if (!UIHelper.IsSaveConfigDialogVisible())
        {
            return null;
        }

        return UIHelper.RunOnUIThread(() =>
        {
            using SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = ShapesDirectory.Value;
            sfd.Filter = $"{StringResources.Shape}|*.xaml";
            sfd.OverwritePrompt = true;
            return sfd.ShowDialog() == DialogResult.OK ? sfd.FileName : null;
        });
    }

    private static T ThrowIfOverflow<T>(Func<T> action, string message)
    {
        try
        {
            return action();
        }
        catch (OverflowException ex)
        {
            throw new WarningException(message, ex);
        }
    }

    public static void Export(Surface input, Stream output, PropertyCollection props, ProgressEventHandler progressCallback, string shapePath)
    {
        ArgumentNullException.ThrowIfNull(input);
        ArgumentNullException.ThrowIfNull(output);
        ArgumentNullException.ThrowIfNull(props);
        ArgumentNullException.ThrowIfNull(progressCallback);
        ThrowIfOverflow(() => checked(input.Stride * input.Height), StringResources.CanvasIsTooBig);

#pragma warning disable format // @formatter:off
        ScanMode scanMode                   = props.GetPropertyValue<ScanMode>(PropertyNames.ScanMode);
        PreviewMode previewMode             = props.GetPropertyValue<PreviewMode>(PropertyNames.PreviewMode);
        double brightnessCutoff             = props.GetPropertyValue<double>(PropertyNames.BrightnessCutoff);
        int highpass                        = props.GetPropertyValue<int>(PropertyNames.HighpassFilter);
        int gmScale                         = props.GetPropertyValue<int>(PropertyNames.GreymapScale);
        int lowpass                         = props.GetPropertyValue<int>(PropertyNames.LowpassFilter);
        int turdsize                        = props.GetPropertyValue<int>(PropertyNames.SuppressSpeckles);
        float alphamax                      = props.GetPropertyValue<float>(PropertyNames.SmoothCorners);
        float opttolerance                  = props.GetPropertyValue<float>(PropertyNames.Optimize);
        TurnPolicy turnpolicy               = props.GetPropertyValue<TurnPolicy>(PropertyNames.TurnPolicy);
        int color                           = props.GetPropertyValue<int>(PropertyNames.Color);
        int fillcolor                       = props.GetPropertyValue<int>(PropertyNames.FillColor);
        bool invert                         = props.GetPropertyValue<bool>(PropertyNames.Invert);
        bool tight                          = props.GetPropertyValue<bool>(PropertyNames.Tight);
        bool enclose                        = props.GetPropertyValue<bool>(PropertyNames.Enclose);
        float angle                         = props.GetPropertyValue<float>(PropertyNames.Angle);
        float scale                         = props.GetPropertyValue<float>(PropertyNames.Scale);
        string shapeName                    = props.GetPropertyValue<string>(PropertyNames.PdnShapeName);
#pragma warning restore format // @formatter:on

        PotraceBitmap bm;
        TraceResult? trace;
        ImageInfo imginfo;
        SvgBackEnd backend = new SvgBackEnd
        {
            Color = color,
            ColumnWidth = int.MaxValue
        };
        backend.Rx /= scale;
        backend.Ry /= scale;

        bool isSaveConfigDialogVisible = UIHelper.IsSaveConfigDialogVisible();
        Surface surface;
        const int maxDimForPreview = 1280;

        if (isSaveConfigDialogVisible && previewMode == PreviewMode.Fast && input.Width * input.Height > maxDimForPreview * maxDimForPreview)
        {
            // Preview Only
            // Image downscaled to speed up preview generation.
            double ar = input.Width / (double)input.Height;
            int newWidth = maxDimForPreview;
            int newHeight = maxDimForPreview;
            if (input.Width > input.Height)
            {
                newHeight = (int)Math.Round(maxDimForPreview / ar);
            }
            else
            {
                newWidth = (int)Math.Round(maxDimForPreview * ar);
            }

            surface = new Surface(newWidth, newHeight);
            surface.FitSurface(ResamplingAlgorithm.Cubic, input);
        }
        else
        {
            surface = input.Clone();
        }

        using var _ = surface;
        surface.BlendOnto<NormalBlendOp>(ColorBgra.White);

        using CancellationTokenSource cts = new CancellationTokenSource();
        float full = isSaveConfigDialogVisible ? 90f : 100f;

        CancellationToken cancellationToken = cts.Token;
        if (scanMode == ScanMode.Opaque)
        {
            backend.Opaque = true;
            backend.FillColor = fillcolor;
        }

        if (highpass == 0)
        {
            bm = PotraceBitmap.FromRgbx(surface.Scan0.Pointer, surface.Width, surface.Height, c: brightnessCutoff);
        }
        else
        {
            using Greymap gm = Greymap.FromRgbx(surface.Scan0.Pointer, surface.Width, surface.Height);
            gm.HighPassFilter(lambda: highpass);

            if (lowpass > 0)
            {
                gm.LowPassFilter(lambda: lowpass);
            }

            if (gmScale > 1)
            {
                bm = gm.InterpolateCubicBilevel(gmScale, c: brightnessCutoff);
                backend.Rx *= gmScale;
                backend.Ry *= gmScale;
            }
            else
            {
                bm = gm.Threshold(c: brightnessCutoff);
            }
        }

        using (bm)
        {
            if (invert)
            {
                bm.Invert();
            }

            if (enclose)
            {
                bm.Enclose();
            }

            Progress<ProgressArgs> progress = new Progress<ProgressArgs>((prog) => OnProgress(ConvertProgressValue(prog)));
            trace = bm.Trace(turdsize, turnpolicy, alphamax, opttolerance, progress, cancellationToken);
            imginfo = bm.Info;
            imginfo.Tight = tight;
        }
        imginfo.Angle = angle;
        if (trace is null)
        {
            if (UIHelper.IsSaveConfigDialogVisible())
            {
                return;
            }
            else
            {
                throw new InvalidOperationException(StringResources.NoPath);
            }
        }

        if (isSaveConfigDialogVisible && scanMode == ScanMode.Transparent && shapePath.Length > 0)
        {
            PdnShapeBackEnd pdnbackend = new PdnShapeBackEnd
            {
                ColumnWidth = int.MaxValue,
                DisplayName = shapeName
            };
            using (FileStream shapeStream = File.Open(shapePath, FileMode.Create, FileAccess.Write))
            {
                pdnbackend.Save(shapeStream, trace, imginfo, cancellationToken);
            }

            StringBuilder msg = new StringBuilder();
            msg.AppendFormat(StringResources.ShapeSaved, shapePath);

            if (ShapesDirectory.Value != null && Path.GetDirectoryName(shapePath)?.StartsWith(ShapesDirectory.Value, StringComparison.OrdinalIgnoreCase) == true)
            {
                msg.AppendLine();
                msg.AppendLine();
                msg.AppendLine(StringResources.ShapeSavedRestart);
            }

            UIHelper.RunOnUIThread(() =>
            {
                MessageBox.Show(msg.ToString(), StringResources.ShapeSavedCaption, MessageBoxButtons.OK, MessageBoxIcon.Information);
            });
        }
        backend.Save(output, trace, imginfo, cancellationToken);

        void OnProgress(float prog)
        {
            try
            {
                progressCallback.Invoke(null, new ProgressEventArgs(prog * full));
            }
            catch (OperationCanceledException)
            {
                try
                {
                    cts.Cancel();
                }
                catch (ObjectDisposedException)
                {
                    // ignore
                }
            }
        }
    }

    public static void Export(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback, string shapePath)
    {
        ArgumentNullException.ThrowIfNull(input);
        ArgumentNullException.ThrowIfNull(output);
        ArgumentNullException.ThrowIfNull(token);
        ArgumentNullException.ThrowIfNull(scratchSurface);
        ArgumentNullException.ThrowIfNull(progressCallback);
        ThrowIfOverflow(() => checked(scratchSurface.Stride * scratchSurface.Height), StringResources.CanvasIsTooBig);

        input.Flatten(scratchSurface);
        Export(scratchSurface, output, token.Properties, progressCallback, shapePath);
    }

    private static float ConvertProgressValue(ProgressArgs args)
    {
        float progress = args.Progress * .5f;
        if (args.Level == ProgressLevel.Tracing)
        {
            progress += .5f;
        }
        return progress;
    }
}


================================================
FILE: SvgFileType/Extensions/ControlExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace SvgFileTypePlugin.Extensions;

internal static class ControlExtensions
{
    public static IEnumerable<Control> Descendants(this Control root)
    {
        ArgumentNullException.ThrowIfNull(root);

        foreach (Control control in root.Controls)
        {
            yield return control;
            if (control.HasChildren)
            {
                foreach (Control child in Descendants(control))
                {
                    yield return child;
                }
            }
        }
    }

    public static object? RunOnUIThread<T>(this Control control, T action, params object[] args) where T : Delegate
    {
        ArgumentNullException.ThrowIfNull(control);

        return control.InvokeRequired ? control.Invoke(action, args) : action.DynamicInvoke(args);
    }

    public static object? RunOnUIThread<T>(this Control control, T action) where T : Delegate
    {
        ArgumentNullException.ThrowIfNull(control);

        return control.InvokeRequired ? control.Invoke(action) : action.DynamicInvoke();
    }
}


================================================
FILE: SvgFileType/Extensions/DocumentExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using PaintDotNet;

namespace SvgFileTypePlugin.Extensions;

internal static class DocumentExtensions
{
    public static void SetDpu(this Document doc, double dpuX, double dpuY, MeasurementUnit dpuUnit = MeasurementUnit.Inch)
    {
        ArgumentNullException.ThrowIfNull(doc);

        doc.DpuUnit = dpuUnit;
        doc.DpuX = dpuX;
        doc.DpuY = dpuY;
    }

    public static void SetDpu(this Document doc, double dpu, MeasurementUnit dpuUnit = MeasurementUnit.Inch)
    {
        SetDpu(doc, dpu, dpu, dpuUnit);
    }
}


================================================
FILE: SvgFileType/Extensions/StringExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Text.RegularExpressions;

namespace SvgFileTypePlugin.Extensions;

internal static class StringExtensions
{
    public static string Truncate(this string s, int maxLength, string suffix = "...")
    {
        ArgumentNullException.ThrowIfNull(s);
        ArgumentOutOfRangeException.ThrowIfNegative(maxLength);

        return s.Length > maxLength ? $"{s[..maxLength]}{suffix}" : s;
    }

    public static string SplitIntoLines(this string s, int maximumLineLength)
    {
        ArgumentNullException.ThrowIfNull(s);
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(maximumLineLength);

        return Regex.Replace(s, @"(.{1," + maximumLineLength + @"})(?:\s|$)", "$1\n");
    }
}


================================================
FILE: SvgFileType/Extensions/SurfaceExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using PaintDotNet;

namespace SvgFileTypePlugin.Extensions;

internal static class SurfaceExtensions
{
    public static Document CreateSingleLayerDocument(this Surface surface, bool takeOwnership = false)
    {
        ArgumentNullException.ThrowIfNull(surface);

        Document document = new Document(surface.Width, surface.Height);
        try
        {
            BitmapLayer layer = new BitmapLayer(surface, takeOwnership);
            document.Layers.Add(layer);
        }
        catch
        {
            document.Dispose();
            throw;
        }
        return document;
    }

    public static unsafe bool IsEmpty(this Surface surface)
    {
        ArgumentNullException.ThrowIfNull(surface);

        const int unrollFactor = 4;
        int pixcnt = surface.Width * surface.Height;
        sbyte* ptr = (sbyte*)surface.Scan0.VoidStar;

        if (Avx2.IsSupported && pixcnt >= Vector256<uint>.Count)
        {
            Vector256<sbyte> valphamask = Vector256.Create(
                3, 7, 11, 15, 19, 23, 27, 31,
                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff).AsSByte();
            Vector256<sbyte> zero = Vector256<sbyte>.Zero;
            while (pixcnt >= Vector256<uint>.Count * unrollFactor)
            {
                Vector256<sbyte> v0 = Avx.LoadVector256(ptr);
                Vector256<sbyte> v1 = Avx.LoadVector256(ptr + Vector256<sbyte>.Count);
                Vector256<sbyte> v2 = Avx.LoadVector256(ptr + 2 * Vector256<sbyte>.Count);
                Vector256<sbyte> v3 = Avx.LoadVector256(ptr + 3 * Vector256<sbyte>.Count);

                v0 = Avx2.Shuffle(v0, valphamask);
                v1 = Avx2.Shuffle(v1, valphamask);
                v2 = Avx2.Shuffle(v2, valphamask);
                v3 = Avx2.Shuffle(v3, valphamask);

                v0 = Avx2.CompareGreaterThan(v0, zero);
                v1 = Avx2.CompareGreaterThan(v1, zero);
                v2 = Avx2.CompareGreaterThan(v2, zero);
                v3 = Avx2.CompareGreaterThan(v3, zero);

                int mask = Avx2.MoveMask(v0) | Avx2.MoveMask(v1) | Avx2.MoveMask(v2) | Avx2.MoveMask(v3);
                if (mask != 0)
                {
                    return false;
                }

                ptr += Vector256<sbyte>.Count * unrollFactor;
                pixcnt -= Vector256<uint>.Count * unrollFactor;
            }

            while (pixcnt >= Vector256<sbyte>.Count)
            {
                Vector256<sbyte> v = Avx.LoadVector256(ptr);
                v = Avx2.Shuffle(v, valphamask);
                v = Avx2.CompareGreaterThan(v, zero);
                if (Avx2.MoveMask(v) != 0)
                {
                    return false;
                }
                ptr += Vector256<sbyte>.Count;
                pixcnt -= Vector256<uint>.Count;
            }
        }

        if (Ssse3.IsSupported && pixcnt >= Vector128<uint>.Count)
        {
            Vector128<sbyte> valphamask = Vector128.Create(
                3, 7, 11, 15,
                0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff, 0xff).AsSByte();
            Vector128<sbyte> zero = Vector128<sbyte>.Zero;
            while (pixcnt >= Vector128<uint>.Count * unrollFactor)
            {
                Vector128<sbyte> v0 = Sse2.LoadVector128(ptr);
                Vector128<sbyte> v1 = Sse2.LoadVector128(ptr + Vector128<sbyte>.Count);
                Vector128<sbyte> v2 = Sse2.LoadVector128(ptr + 2 * Vector128<sbyte>.Count);
                Vector128<sbyte> v3 = Sse2.LoadVector128(ptr + 3 * Vector128<sbyte>.Count);

                v0 = Ssse3.Shuffle(v0, valphamask);
                v1 = Ssse3.Shuffle(v1, valphamask);
                v2 = Ssse3.Shuffle(v2, valphamask);
                v3 = Ssse3.Shuffle(v3, valphamask);

                v0 = Sse2.CompareGreaterThan(v0, zero);
                v1 = Sse2.CompareGreaterThan(v1, zero);
                v2 = Sse2.CompareGreaterThan(v2, zero);
                v3 = Sse2.CompareGreaterThan(v3, zero);

                int mask = Sse2.MoveMask(v0) | Sse2.MoveMask(v1) | Sse2.MoveMask(v2) | Sse2.MoveMask(v3);
                if (mask != 0)
                {
                    return false;
                }

                ptr += Vector128<sbyte>.Count * unrollFactor;
                pixcnt -= Vector128<uint>.Count * unrollFactor;
            }

            while (pixcnt >= Vector128<sbyte>.Count)
            {
                Vector128<sbyte> v = Sse2.LoadVector128(ptr);
                v = Ssse3.Shuffle(v, valphamask);
                v = Sse2.CompareGreaterThan(v, zero);
                if (Sse2.MoveMask(v) != 0)
                {
                    return false;
                }
                ptr += Vector128<sbyte>.Count;
                pixcnt -= Vector128<uint>.Count;
            }
        }

        while (pixcnt > 0)
        {
            if (ptr[3] > 0)
            {
                return false;
            }
            ptr += sizeof(uint);
            pixcnt--;
        }

        return true;
    }

    public static void BlendOnto<T>(this Surface surface, ColorBgra backgroundColor) where T : UserBlendOp, new()
    {
        ArgumentNullException.ThrowIfNull(surface);

        using Surface tmp = surface.Clone();
        surface.Fill(backgroundColor);
        T blendOp = new T();
        blendOp.Apply(surface, tmp);
    }
}


================================================
FILE: SvgFileType/Extensions/SvgDocumentExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Drawing;
using Svg;
using SvgFileTypePlugin.Import;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgDocumentExtensions
{
    public static SvgDocument RemoveInvisibleAndNonTextElements(this SvgDocument svg)
    {
        ArgumentNullException.ThrowIfNull(svg);

        SvgFragment clonedFragment = (SvgFragment)svg.Clone();
        clonedFragment.RemoveInvisibleAndNonTextElements();
        SvgDocument clonedDocument = new SvgDocument();
        clonedDocument.Children.Add(clonedFragment);
        return clonedDocument;
    }

    public static IDisposable UseSetRasterDimensions(this SvgDocument svg, SvgImportConfig config)
    {
        ArgumentNullException.ThrowIfNull(svg);
        ArgumentNullException.ThrowIfNull(config);

        SvgAspectRatio origAR = svg.AspectRatio;
        SizeF origSize = svg.GetDimensions();
        SizeF rasterSize = origSize;
        SvgViewBox origViewBox = svg.ViewBox;
        if (origViewBox.IsEmpty() && !origSize.IsEmpty)
        {
            svg.ViewBox = new SvgViewBox(0, 0, origSize.Width, origSize.Height);
        }
        svg.RasterizeDimensions(ref rasterSize, config.RasterWidth, config.RasterHeight);
        svg.Width = new SvgUnit(SvgUnitType.User, rasterSize.Width);
        svg.Height = new SvgUnit(SvgUnitType.User, rasterSize.Height);
        svg.AspectRatio = new SvgAspectRatio(config.PreserveAspectRatio
            ? SvgPreserveAspectRatio.xMinYMin
            : SvgPreserveAspectRatio.none);
        return new DisposableAction(() =>
        {
            // Restore the original values back
            svg.AspectRatio = origAR;
            svg.Width = origSize.Width;
            svg.Height = origSize.Height;
            svg.ViewBox = origViewBox;
        });
    }

    private sealed class DisposableAction : IDisposable
    {
        private Action? _dispose;

        public DisposableAction(Action dispose)
        {
            ArgumentNullException.ThrowIfNull(dispose);

            _dispose = dispose;
        }

        public void Dispose()
        {
            _dispose?.Invoke();
            _dispose = null;
        }
    }
}


================================================
FILE: SvgFileType/Extensions/SvgElementExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Svg;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgElementExtensions
{
    private delegate SvgAttributeCollection AttributesGetterDelegate(SvgElement element);
    private delegate string? ElementNameGetterDelegate(SvgElement element);

    private static readonly AttributesGetterDelegate GetElementAttributes = CreateGetterDelegate<AttributesGetterDelegate>("Attributes");
    private static readonly ElementNameGetterDelegate GetElementName = CreateGetterDelegate<ElementNameGetterDelegate>("ElementName");
    private static readonly XmlWriterSettings WriterSettings = new() { Encoding = Encoding.UTF8 };

    public static string GetName(this SvgElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        return element.GetType().GetCustomAttribute<SvgElementAttribute>()?.ElementName
            ?? GetElementName(element)
            ?? element.GetType().Name;
    }

    public static SvgAttributeCollection GetAttributes(this SvgElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        return GetElementAttributes(element);
    }

    public static void RemoveInvisibleAndNonTextElements(this SvgElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        for (int i = element.Children.Count - 1; i >= 0; i--)
        {
            SvgElement child = element.Children[i];
            if (child is not SvgTextBase && child.Visibility != "visible")
            {
                element.Children.RemoveAt(i);
            }
            else
            {
                child.RemoveInvisibleAndNonTextElements();
            }
        }
    }

    public static string GetXML_QuotedFuncIRIHack(this SvgElement svg)
    {
        ArgumentNullException.ThrowIfNull(svg);

        using InvariantUtf8StringWriter writer = new InvariantUtf8StringWriter();
        using (XmlWriter xmlWriter = new CustomXmlWriter(XmlWriter.Create(writer, WriterSettings)))
        {
            svg.Write(xmlWriter);
            xmlWriter.Flush();
        }
        writer.Flush();
        return writer.ToString();
    }

    public static void WriteXML_QuotedFuncIRIHack(this SvgElement svg, Stream output)
    {
        ArgumentNullException.ThrowIfNull(svg);

        using InvariantUtf8StreamWriter writer = new InvariantUtf8StreamWriter(output);
        using (XmlWriter xmlWriter = new CustomXmlWriter(XmlWriter.Create(writer, WriterSettings)))
        {
            svg.Write(xmlWriter);
            xmlWriter.Flush();
        }
        writer.Flush();
    }

    private static T CreateGetterDelegate<T>(string propertyName) where T : Delegate
    {
        MethodInfo getter = typeof(SvgElement)
            ?.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance)
            ?.GetGetMethod(true)
            ?? throw new MissingMemberException(nameof(SvgElement), propertyName);
        return getter.CreateDelegate<T>();
    }

    #region InvariantUtf8StreamWriter

    private sealed class InvariantUtf8StreamWriter(Stream stream) : StreamWriter(stream, Encoding.UTF8, leaveOpen: true)
    {
        private readonly Stream stream = stream;

        public override Encoding Encoding => Encoding.UTF8;
        public override IFormatProvider FormatProvider => CultureInfo.InvariantCulture;

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                stream.Position = 0;
            }
        }
    }

    #endregion

    #region InvariantUtf8StringWriter

    private sealed class InvariantUtf8StringWriter() : StringWriter(CultureInfo.InvariantCulture)
    {
        public override Encoding Encoding => Encoding.UTF8;
    }

    #endregion

    #region CustomXmlWriter

    // Workaround for removing quotes from quoted FuncIRI(s).

    private sealed class CustomXmlWriter(XmlWriter writer) : XmlWriter
    {
        private readonly XmlWriter writer = writer;
        public override WriteState WriteState => writer.WriteState;
        public override void Flush() => writer.Flush();
        public override string? LookupPrefix(string ns) => writer.LookupPrefix(ns);
        public override void WriteBase64(byte[] buffer, int index, int count) => writer.WriteBase64(buffer, index, count);
        public override void WriteCData(string? text) => writer.WriteCData(text);
        public override void WriteCharEntity(char ch) => writer.WriteCharEntity(ch);
        public override void WriteChars(char[] buffer, int index, int count) => writer.WriteChars(buffer, index, count);
        public override void WriteComment(string? text) => writer.WriteComment(text);
        public override void WriteDocType(string name, string? pubid, string? sysid, string? subset) => writer.WriteDocType(name, pubid, sysid, subset);
        public override void WriteEndAttribute() => writer.WriteEndAttribute();
        public override void WriteEndDocument() => writer.WriteEndDocument();
        public override void WriteEndElement() => writer.WriteEndElement();
        public override void WriteEntityRef(string name) => writer.WriteEntityRef(name);
        public override void WriteFullEndElement() => writer.WriteFullEndElement();
        public override void WriteProcessingInstruction(string name, string? text) => writer.WriteProcessingInstruction(name, text);
        public override void WriteRaw(char[] buffer, int index, int count) => writer.WriteRaw(buffer, index, count);
        public override void WriteRaw(string data) => writer.WriteRaw(data);
        public override void WriteStartAttribute(string? prefix, string localName, string? ns) => writer.WriteStartAttribute(prefix, localName, ns);
        public override void WriteStartDocument() => writer.WriteStartDocument();
        public override void WriteStartDocument(bool standalone) => writer.WriteStartDocument(standalone);
        public override void WriteStartElement(string? prefix, string localName, string? ns) => writer.WriteStartElement(prefix, localName, ns);
        public override void WriteString(string? text)
        {
            writer.WriteString(text?.Replace("\"", string.Empty).Replace("\'", string.Empty));
        }
        public override void WriteSurrogateCharEntity(char lowChar, char highChar) => writer.WriteSurrogateCharEntity(lowChar, highChar);
        public override void WriteWhitespace(string? ws) => writer.WriteWhitespace(ws);
    }

    #endregion
}


================================================
FILE: SvgFileType/Extensions/SvgUnitExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using Svg;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgUnitExtensions
{
    public static int ToDeviceValue(this SvgUnit unit, SvgElement owner, UnitRenderingType unitRenderingType = UnitRenderingType.Other)
    {
        ArgumentNullException.ThrowIfNull(owner);

        using ISvgRenderer renderer = SvgRenderer.FromNull();
        float value = unit.ToDeviceValue(renderer, unitRenderingType, owner);
        return checked((int)Math.Round(value));
    }
}


================================================
FILE: SvgFileType/Extensions/SvgUseExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using Svg;
using Svg.Transforms;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgUseExtensions
{
    public static SvgElement? GetCopyOfReferencedElement(this SvgUse useElement)
    {
        ArgumentNullException.ThrowIfNull(useElement);
        SvgDocument document = useElement.OwnerDocument 
            ?? throw new ArgumentException("Use element does not have an owner document.", nameof(useElement));

        List<SvgTransform> transforms = [];
        SvgElement? referencedElement = useElement;
        while (referencedElement is SvgUse parentUse and { ReferencedElement: Uri uri })
        {
            string href = uri.ToString().TrimStart('#');
            if (href.Length < 1)
            {
                return null;
            }
            if (parentUse.Transforms is { Count: > 0 })
            {
                transforms.AddRange(parentUse.Transforms);
            }
            referencedElement = document.GetElementById(href);
        }
        if (referencedElement is null)
        {
            return null;
        }
        SvgElement copiedElement = referencedElement.DeepCopy();
        useElement.CopyOverridedAttributes(copiedElement);
        copiedElement.Transforms ??= [];
        copiedElement.Transforms.AddRange(transforms);
        return copiedElement;
    }

    private static void CopyOverridedAttributes(this SvgUse useElement, SvgElement targetElement)
    {
        SvgAttributeCollection targetAttributes = targetElement.GetAttributes();
        SvgAttributeCollection sourceAttributes = useElement.GetAttributes();

        foreach (KeyValuePair<string, object> attribute in sourceAttributes)
        {
            string key = attribute.Key.ToLowerInvariant();

            // Most attributes on use do not override those already on the element
            // referenced by use. (This differs from how CSS style attributes override
            // those set 'earlier' in the cascade). Only the attributes x, y, width,
            // height and href on the use element will override those set on the
            // referenced element.However, any other attributes not set on the referenced
            // element will be applied to the use element.
            if (key is "x" or "y" or "width" or "height" or "href" or "xlink:href")
            {
                targetAttributes[key] = attribute.Value;
            }
        }
    }
}


================================================
FILE: SvgFileType/Extensions/SvgViewBoxExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using Svg;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgViewBoxExtensions
{
    public static bool IsEmpty(this SvgViewBox vb)
    {
        return vb.Width < float.Epsilon || vb.Height < float.Epsilon;
    }
}


================================================
FILE: SvgFileType/Extensions/SvgVisualElementExtensions.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Svg;

namespace SvgFileTypePlugin.Extensions;

internal static class SvgVisualElementExtensions
{
    #region OriginalVisibilityAttribute

    private const string OriginalVisibilityAttribute = "original_visibility";

    public static bool IsOriginallyVisible(this SvgVisualElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        return element.CustomAttributes.TryGetValue(OriginalVisibilityAttribute, out string? arg) 
            && string.Equals(arg.Trim(), "visible", StringComparison.OrdinalIgnoreCase);
    }

    public static void StoreOriginalVisibility(this SvgVisualElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        SvgCustomAttributeCollection col = element.CustomAttributes;
        if (col.ContainsKey(OriginalVisibilityAttribute))
        {
            col[OriginalVisibilityAttribute] = element.Visibility;
        }
        else
        {
            col.Add(OriginalVisibilityAttribute, element.Visibility);
        }
    }

    #endregion

    #region GroupNameAttribute 

    private const string GroupNameAttribute = "group_name";

    public static string? GetGroupName(this SvgVisualElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        return element.CustomAttributes.TryGetValue(GroupNameAttribute, out string? groupName) ? groupName : null;
    }

    public static void SetGroupName(this SvgVisualElement element, string? groupName)
    {
        ArgumentNullException.ThrowIfNull(element);

        SvgCustomAttributeCollection col = element.CustomAttributes;
        if (col.ContainsKey(GroupNameAttribute))
        {
            if (string.IsNullOrEmpty(groupName))
            {
                col.Remove(GroupNameAttribute);
            }
            else
            {
                col[GroupNameAttribute] = groupName;
            }
        }
        else if (!string.IsNullOrEmpty(groupName))
        {
            col.Add(GroupNameAttribute, groupName);
        }
    }

    #endregion

    public static IEnumerable<SvgVisualElement> NotOfType<TElement>(this IEnumerable<SvgVisualElement> source)
        where TElement : SvgVisualElement
    {
        ArgumentNullException.ThrowIfNull(source);

        return source.Where(element => element is not TElement);
    }

    public static bool IsDisplayable(this SvgVisualElement element)
    {
        ArgumentNullException.ThrowIfNull(element);

        return !element.Display.Trim().Equals("none", StringComparison.OrdinalIgnoreCase);
    }

    public static bool PreRender(this SvgVisualElement element, IReadOnlyCollection<SvgVisualElement> elements, bool hiddenElements, CancellationToken ctoken = default)
    {
        ArgumentNullException.ThrowIfNull(element);
        ArgumentNullException.ThrowIfNull(elements);

        // Turn off visibility of all other elements
        foreach (SvgVisualElement sibling in elements.Where(e => e != element))
        {
            ctoken.ThrowIfCancellationRequested();
            sibling.Visibility = "hidden";
        }

        element.Visibility = "visible";

        // Turn on visibility from node to parent
        for (SvgElement parent = element.Parent; parent != null; parent = parent.Parent)
        {
            ctoken.ThrowIfCancellationRequested();

            if (parent is not SvgVisualElement visual)
            {
                continue;
            }

            // Check, maybe parent element was initially hidden
            // Skip hidden layers.
            if (!hiddenElements && !visual.IsOriginallyVisible())
            {
                return false;
            }

            visual.Visibility = "visible";
        }
        return true;
    }
}


================================================
FILE: SvgFileType/FodyWeavers.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
    <ILMerge IncludeAssemblies="Svg|ExCss|resvg.net|BitmapVectorizer|SimplePaletteQuantizer|PaintDotNet.IndirectUI.Fluent" NamespacePrefix="" IncludeResources="\.(resources|dtd|zip)$" CompactMode="0" FullImport="0" />
</Weavers>

================================================
FILE: SvgFileType/FodyWeavers.xsd
================================================
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
  <xs:element name="Weavers">
    <xs:complexType>
      <xs:all>
        <xs:element name="ILMerge" minOccurs="0" maxOccurs="1">
          <xs:complexType>
            <xs:all>
              <xs:element name="IncludeAssemblies" type="xs:string" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A regular expression matching the assembly names to include in merging.</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="ExcludeAssemblies" type="xs:string" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A regular expression matching the assembly names to exclude from merging.</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="IncludeResources" type="xs:string" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A regular expression matching the resource names to include in merging.</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="ExcludeResources" type="xs:string" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A regular expression matching the resource names to exclude from merging.</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="HideImportedTypes" type="xs:boolean" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A switch to control whether the imported types are hidden (made private) or keep their visibility unchanged. Default is 'true'</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="NamespacePrefix" type="xs:string" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A string that is used as prefix for the namespace of the imported types.</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="FullImport" type="xs:boolean" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A switch to control whether to import the full assemblies or only the referenced types. Default is 'false'</xs:documentation>
                </xs:annotation>
              </xs:element>
              <xs:element name="CompactMode" type="xs:boolean" minOccurs="0" maxOccurs="1">
                <xs:annotation>
                  <xs:documentation>A switch to enable compacting of the target assembly by skipping properties, events and unused methods. Default is 'false'</xs:documentation>
                </xs:annotation>
              </xs:element>
            </xs:all>
            <xs:attribute name="IncludeAssemblies" type="xs:string">
              <xs:annotation>
                <xs:documentation>A regular expression matching the assembly names to include in merging.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="ExcludeAssemblies" type="xs:string">
              <xs:annotation>
                <xs:documentation>A regular expression matching the assembly names to exclude from merging.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="IncludeResources" type="xs:string">
              <xs:annotation>
                <xs:documentation>A regular expression matching the resource names to include in merging.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="ExcludeResources" type="xs:string">
              <xs:annotation>
                <xs:documentation>A regular expression matching the resource names to exclude from merging.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="HideImportedTypes" type="xs:boolean">
              <xs:annotation>
                <xs:documentation>A switch to control whether the imported types are hidden (made private) or keep their visibility unchanged. Default is 'true'</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="NamespacePrefix" type="xs:string">
              <xs:annotation>
                <xs:documentation>A string that is used as prefix for the namespace of the imported types.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="FullImport" type="xs:boolean">
              <xs:annotation>
                <xs:documentation>A switch to control whether to import the full assemblies or only the referenced types. Default is 'false'</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="CompactMode" type="xs:boolean">
              <xs:annotation>
                <xs:documentation>A switch to enable compacting of the target assembly by skipping properties, events and unused methods. Default is 'false'</xs:documentation>
              </xs:annotation>
            </xs:attribute>
          </xs:complexType>
        </xs:element>
      </xs:all>
      <xs:attribute name="VerifyAssembly" type="xs:boolean">
        <xs:annotation>
          <xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="VerifyIgnoreCodes" type="xs:string">
        <xs:annotation>
          <xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="GenerateXsd" type="xs:boolean">
        <xs:annotation>
          <xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
</xs:schema>

================================================
FILE: SvgFileType/Import/Direct2DSvgRenderer.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime;
using System.Threading;
using PaintDotNet;
using PaintDotNet.Direct2D1;
using PaintDotNet.DirectWrite;
using PaintDotNet.Imaging;
using PaintDotNet.Rendering;
using Svg;
using SvgFileTypePlugin.Extensions;
using FontStyle = PaintDotNet.DirectWrite.FontStyle;
using IDeviceContext = PaintDotNet.Direct2D1.IDeviceContext;
using SR = SvgFileTypePlugin.Localization.StringResources;

namespace SvgFileTypePlugin.Import;

internal sealed class Direct2DSvgRenderer() : SvgRenderer2(name: "Direct2D")
{
    protected override Document GetFlatDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        ctoken.ThrowIfCancellationRequested();
        (int width, int height) = (config.RasterWidth, config.RasterHeight);
        using BenchmarkScope _ = new BenchmarkScope();
        using MemoryFailPoint mfp = GetMemoryFailPoint(width, height, 1);
        ResetProgress(1);
        Surface surface = new Surface(width, height, SurfaceCreationFlags.DoNotZeroFillHint);
        try
        {
            SvgDocument svgdoc = SvgDocument.FromSvg<SvgDocument>(svgdata);
            IDirect2DFactory d2d = Services.Get<IDirect2DFactory>(); // Don't dispose this! It's singleton.
            using IBitmap<ColorBgra32> sbitmap = surface.CreateSharedBitmap();
            using IBitmap<ColorPbgra32> pbitmap = sbitmap.CreatePremultipliedAdapter(PremultipliedAdapterOptions.UnPremultiplyOnDispose);
            using IDeviceContext dc = d2d.CreateBitmapDeviceContext(pbitmap);
            using MemoryStream stream = new MemoryStream();
            svgdoc.WriteXML_QuotedFuncIRIHack(stream);
            using ISvgDocument svg = dc.CreateSvgDocument(stream, viewportSize: new SizeFloat(width, height));
            using DrawingScope _1 = dc.UseBeginDraw();
            dc.Transform = CalculateTransform(svgsize: new SizeF(svgdoc.Width, svgdoc.Height), config);
            dc.Clear();
            dc.DrawSvgDocument(svg);
        }
        catch (Exception)
        {
            surface.Dispose();
            throw;
        }

        Document document = surface.CreateSingleLayerDocument(takeOwnership: true);
        document.SetDpu(config.Ppi);
        IncrementProgress();
        return document;
    }

    protected override Document GetLayeredDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        using BenchmarkScope _ = new BenchmarkScope();
        SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
        using IDisposable _1 = svg.UseSetRasterDimensions(config);

        List<SvgVisualElement> elements = GetSvgVisualElements(svg, config, ctoken);
        ctoken.ThrowIfCancellationRequested();

        using MemoryFailPoint _2 = GetMemoryFailPoint(config.RasterWidth, config.RasterHeight, elements.Count);

        ResetProgress(elements.Count);
        List<BitmapLayer> layers = [];

        IDirect2DFactory d2d = Services.Get<IDirect2DFactory>(); // Don't dispose this! It's singleton.
        using Surface surface = new Surface(config.RasterWidth, config.RasterHeight);
        using IBitmap<ColorBgra32> sharedBitmap = surface.CreateSharedBitmap();
        using IBitmap<ColorPbgra32> premultiplied = sharedBitmap.CreatePremultipliedAdapter(PremultipliedAdapterOptions.None);
        using IDeviceContext dc = d2d.CreateBitmapDeviceContext(premultiplied);
        // Render all visual elements that are passed here.
        foreach (SvgVisualElement element in elements)
        {
            ctoken.ThrowIfCancellationRequested();

            BitmapLayer? layer;
            if (element is GroupBoundary boundaryNode)
            {
                // Render empty group boundary and continue
                layer = boundaryNode.ToEmptyLayer(config.RasterWidth, config.RasterHeight);
                layers.Add(layer);
                IncrementProgress();
                continue;
            }

            if (!element.PreRender(elements, config.ImportHiddenElements, ctoken))
            {
                IncrementProgress();
                continue;
            }

            RenderSvgDocument(element, dc);
            if (surface.IsEmpty())
            {
                IncrementProgress();
                continue;
            }
            layer = new BitmapLayer(surface, takeOwnership: false);
            try
            {
                layer.Name = GetLayerTitle(element);
                if (config.RespectElementOpacity)
                {
                    layer.Opacity = ToByteOpacity(element.Opacity);
                }

                if (config.ImportHiddenElements && !element.IsOriginallyVisible())
                {
                    layer.Visible = false;
                }
            }
            catch (Exception)
            {
                layer?.Dispose();
                layers.ForEach(layer => layer.Dispose());
                throw;
            }

            IncrementProgress();
            layers.Add(layer);
        }
        return GetDocument(layers, config);
    }

    public override Document GetNoPathDocument()
    {
        IDirectWriteFactory dw = Services.Get<IDirectWriteFactory>();
        IDirect2DFactory d2d = Services.Get<IDirect2DFactory>();
        using ITextFormat textFormat = dw.CreateTextFormat("Arial", null, FontWeight.Bold, FontStyle.Normal, FontStretch.Normal, UIScaleFactor.ConvertFontPointsToDips(24));
        using ITextLayout textLayout = dw.CreateTextLayout(SR.NoPath, textFormat);
        textLayout.WordWrapping = WordWrapping.NoWrap;
        TextMeasurement textMeasurement = textLayout.Measure();
        int width = (int)textMeasurement.Width;
        int height = (int)textMeasurement.Height;
        //StrokeStyleProperties strokeStyleProperties = StrokeStyleProperties.Default;
        //strokeStyleProperties.LineJoin = LineJoin.Bevel;
        //strokeStyleProperties.MiterLimit = 0;
        Surface surface = new Surface(width, height, SurfaceCreationFlags.DoNotZeroFillHint);
        using (IBitmap<ColorBgra32> shared = surface.CreateSharedBitmap())
        using (IBitmap<ColorPbgra32> premltd = shared.CreatePremultipliedAdapter(PremultipliedAdapterOptions.UnPremultiplyOnDispose))
        using (IDeviceContext dc = d2d.CreateBitmapDeviceContext(premltd))
        using (ISolidColorBrush textBrush = dc.CreateSolidColorBrush(Color.Black))
        //using (ISolidColorBrush strokeBrush = dc.CreateSolidColorBrush(Color.Red))
        //using (IGeometry textGeometry = d2d.CreateGeometryFromTextLayout(textLayout))
        //using (IStrokeStyle strokeStyle = d2d.CreateStrokeStyle(strokeStyleProperties))
        //using (IGeometry widenedGeometry = textGeometry.Widen(1, strokeStyle))
        //using (IGeometry outerStrokeGeometry = widenedGeometry.CombineWithGeometry(textGeometry, GeometryCombineMode.Exclude))
        using (dc.UseTextRenderingMode(TextRenderingMode.Default))
        using (dc.UseTextAntialiasMode(TextAntialiasMode.Grayscale))
        using (dc.UseBeginDraw())
        {
            dc.Clear(Color.LightGray);
            dc.DrawTextLayout(0, 0, textLayout, textBrush, DrawTextOptions.EnableColorFont);
            //dc.FillGeometry(textGeometry, textBrush);
            //dc.FillGeometry(outerStrokeGeometry, strokeBrush);
        }
        return surface.CreateSingleLayerDocument(takeOwnership: true);
    }

    private void RenderSvgDocument(SvgElement element, IDeviceContext dc)
    {
        if (element is SvgUse use)
        {
            RenderSvgUseElement(use, e => RenderSvgDocument(e, dc));
        }
        else
        {
            SvgDocument clone = element.OwnerDocument.RemoveInvisibleAndNonTextElements();
            using MemoryStream stream = new MemoryStream();
            clone.WriteXML_QuotedFuncIRIHack(stream);
            using ISvgDocument partial = dc.CreateSvgDocument(stream, dc.Size);
            using DrawingScope _ = dc.UseBeginDraw();
            dc.Clear();
            dc.DrawSvgDocument(partial);
        }
    }

    private static Matrix3x2Float CalculateTransform(SizeF svgsize, SvgImportConfig config)
    {
        float ratioX = config.RasterWidth / svgsize.Width;
        float ratioY = config.PreserveAspectRatio ? ratioX : config.RasterHeight / svgsize.Height;
        return new Matrix3x2Float()
        {
            M11 = ratioX,
            M22 = ratioY
        };
    }
}


================================================
FILE: SvgFileType/Import/GdipSvgRenderer.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime;
using System.Threading;
using PaintDotNet;
using Svg;
using SvgFileTypePlugin.Extensions;

namespace SvgFileTypePlugin.Import;

internal sealed class GdipSvgRenderer() : SvgRenderer2(name: "GDI+")
{
    protected override Document GetFlatDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        ctoken.ThrowIfCancellationRequested();

        using BenchmarkScope _ = new BenchmarkScope();
        SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
        using IDisposable _1 = svg.UseSetRasterDimensions(config);

        List<SvgVisualElement> elements = GetSvgVisualElements(svg, config, ctoken);
        using MemoryFailPoint _2 = GetMemoryFailPoint(config.RasterWidth, config.RasterHeight, 2);

        ResetProgress(elements.Count);
        using Bitmap bmp = new Bitmap(config.RasterWidth, config.RasterHeight);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            // Render all visual elements that are passed here.
            foreach (SvgVisualElement element in elements)
            {
                ctoken.ThrowIfCancellationRequested();
                if (!element.PreRender(elements, hiddenElements: false, ctoken))
                {
                    IncrementProgress();
                    continue;
                }
                RenderSvgDocument(element, g, config);
                IncrementProgress();
            }
        }
        Document document = Document.FromImage(bmp);
        document.SetDpu(config.Ppi);
        return document;
    }

    protected override Document GetLayeredDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        using BenchmarkScope _ = new BenchmarkScope();
        SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
        using IDisposable _1 = svg.UseSetRasterDimensions(config);

        List<SvgVisualElement> elements = GetSvgVisualElements(svg, config, ctoken);
        ctoken.ThrowIfCancellationRequested();

        using MemoryFailPoint _2 = GetMemoryFailPoint(config.RasterWidth, config.RasterHeight, elements.Count);

        ResetProgress(elements.Count);
        List<BitmapLayer> layers = [];
        using Bitmap bmp = new Bitmap(config.RasterWidth, config.RasterHeight);
        using Graphics g = Graphics.FromImage(bmp);
        // Render all visual elements that are passed here.
        foreach (SvgVisualElement element in elements)
        {
            ctoken.ThrowIfCancellationRequested();

            BitmapLayer? layer;
            if (element is GroupBoundary boundaryNode)
            {
                // Render empty group boundary and continue
                layer = boundaryNode.ToEmptyLayer(config.RasterWidth, config.RasterHeight);
                layers.Add(layer);
                IncrementProgress();
                continue;
            }

            if (!element.PreRender(elements, config.ImportHiddenElements, ctoken))
            {
                IncrementProgress();
                continue;
            }

            g.Clear(default);
            RenderSvgDocument(element, g, config);
            Surface surface = Surface.CopyFromBitmap(bmp, detectDishonestAlpha: false);
            if (surface.IsEmpty())
            {
                surface.Dispose();
                IncrementProgress();
                continue;
            }

            layer = new BitmapLayer(surface, takeOwnership: true);
            try
            {
                layer.Name = GetLayerTitle(element);
                if (config.RespectElementOpacity)
                    layer.Opacity = ToByteOpacity(element.Opacity);

                if (config.ImportHiddenElements && !element.IsOriginallyVisible())
                    layer.Visible = false;
            }
            catch (Exception)
            {
                surface.Dispose();
                layer?.Dispose();
                layers.ForEach(layer => layer.Dispose());
                throw;
            }
            IncrementProgress();
            layers.Add(layer);
        }
        return GetDocument(layers, config);
    }

    private void RenderSvgDocument(SvgElement element, Graphics graphics, SvgImportConfig config)
    {
        if (element is SvgUse use)
        {
            RenderSvgUseElement(use, e => RenderSvgDocument(e, graphics, config));
        }
        else
        {
            SvgDocument clone = element.OwnerDocument.RemoveInvisibleAndNonTextElements();
            clone.Draw(graphics);
        }
    }
}


================================================
FILE: SvgFileType/Import/LayersMode.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

namespace SvgFileTypePlugin.Import;

internal enum LayersMode
{
    Flat,
    Groups,
    All
}


================================================
FILE: SvgFileType/Import/MyBaseForm.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Forms;
using PaintDotNet;
using SvgFileTypePlugin.Extensions;

namespace SvgFileTypePlugin.Import;

internal partial class MyBaseForm : Form
{
    #region Properties

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool UseAppThemeColors { get; private set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual bool EnableImmersiveDarkMode => false;

    #endregion

    #region Constructor

    protected MyBaseForm(Form? owner)
    {
        Owner = owner;
        FormBorderStyle = FormBorderStyle.FixedDialog;
        StartPosition = FormStartPosition.CenterParent;
        MaximizeBox = false;
        MinimizeBox = false;
        ShowIcon = false;
    }

    protected MyBaseForm() : this(null)
    {
    }

    #endregion

    #region Public Instance Methods

    public void SetUseAppThemeColors(bool enable = true)
    {
        if (enable == UseAppThemeColors) 
        { 
            return;
        }
        using (PdnBaseForm dummy = new PdnBaseForm())
        {
            dummy.UseAppThemeColors = enable;
            BackColor = dummy.BackColor;
            ForeColor = dummy.ForeColor;
        }
        UpdateControlColorsRecursive();
        UseAppThemeColors = enable;
    }

    #endregion

    #region Private Instance Methods

    private void UpdateControlColorsRecursive()
    {
        bool isDark = ForeColor.GetBrightness() > BackColor.GetBrightness();

        if (EnableImmersiveDarkMode)
        {
            // Native.SetPreferredAppMode(true);
            Native.UseImmersiveDarkModeColors(this, isDark);
            Native.UseImmersiveDarkMode(this, isDark);
        }

        foreach (Control control in this.Descendants())
        {
            control.ForeColor = ForeColor;
            control.BackColor = BackColor;
            switch (control)

            {
                case LinkLabel linkLabel when isDark:
                    linkLabel.LinkColor = Color.Orange;
                    linkLabel.VisitedLinkColor = Color.Orange;
                    break;
                case LinkLabel linkLabel when !isDark:
                    linkLabel.LinkColor = Color.Empty;
                    linkLabel.VisitedLinkColor = Color.Empty;
                    break;
                case Label label:
                    label.FlatStyle = FlatStyle.Standard;
                    SubscribeOnPaint(label, Label_Paint);
                    break;
                case CheckBox _:
                case RadioButton _:
                    ((ButtonBase)control).FlatStyle = FlatStyle.Standard;
                    SubscribeOnPaint(control, CheckRadio_Paint);
                    break;
                case Button button:
                    button.FlatStyle = FlatStyle.System;
                    break;
                case GroupBox groupBox:
                    groupBox.FlatStyle = FlatStyle.Standard;
                    SubscribeOnPaint(groupBox, GroupBox_Paint);
                    break;
                case ComboBox _ when !isDark:
                case TextBox _ when !isDark:
                    control.BackColor = SystemColors.Window;
                    break;
            }

            if (EnableImmersiveDarkMode)
            {
                if (control.IsHandleCreated)
                {
                    Native.ControlSetDarkMode(control, isDark);
                }
                control.HandleCreated -= Control_HandleCreated;
                control.HandleCreated -= Control_HandleCreated;
                control.HandleCreated += Control_HandleCreated;
            }
        }
    }

    #endregion

    #region Private Static Methods

    private static void DrawBackground(Graphics g, Color backColor, Rectangle rect)
    {
        using SolidBrush brush = new SolidBrush(backColor);
        g.FillRectangle(brush, rect);
    }

    #region Control Event Handlers

    private static void Control_HandleCreated(object? sender, EventArgs e)
    {
        if (sender is not Control ctrl)
        {
            return;
        }

        bool isDark = ctrl.ForeColor.GetBrightness() > ctrl.BackColor.GetBrightness();
        Native.ControlSetDarkMode(ctrl, isDark);
    }

    private static void SubscribeOnPaint(Control control, PaintEventHandler handler)
    {
        control.Paint -= handler;
        control.Paint -= handler;
        control.Paint += handler;
    }

    private static void GroupBox_Paint(object? sender, PaintEventArgs e)
    {
        if (sender is not GroupBox ctrl || ctrl.Enabled)
        {
            return;
        }

        Color foreColor = SystemColors.GrayText;
        bool rtl = ctrl.RightToLeft == RightToLeft.Yes;
        TextFormatFlags tff = ConvertAlignment(ContentAlignment.MiddleLeft, rtl) | TextFormatFlags.WordBreak;
        DrawBackground(e.Graphics, ctrl.BackColor, e.ClipRectangle);
        GroupBoxRenderer.DrawGroupBox(e.Graphics, e.ClipRectangle, ctrl.Text, ctrl.Font, foreColor, tff, System.Windows.Forms.VisualStyles.GroupBoxState.Disabled);
    }

    private static void Label_Paint(object? sender, PaintEventArgs e)
    {
        if (sender is not Label ctrl || ctrl.Enabled)
        {
            return;
        }

        Color foreColor = SystemColors.GrayText;
        bool rtl = ctrl.RightToLeft == RightToLeft.Yes;
        TextFormatFlags tff = ConvertAlignment(ctrl.TextAlign, rtl) | TextFormatFlags.WordBreak;
        DrawBackground(e.Graphics, ctrl.BackColor, e.ClipRectangle);
        TextRenderer.DrawText(e.Graphics, ctrl.Text, ctrl.Font, e.ClipRectangle, foreColor, tff);
    }

    private static void CheckRadio_Paint(object? sender, PaintEventArgs e)
    {
        if (sender is not ButtonBase ctrl || ctrl.Enabled)
        {
            return;
        }

        Color foreColor = SystemColors.GrayText;
        Size glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
        bool rtl = ctrl.RightToLeft == RightToLeft.Yes;
        TextFormatFlags tff = ConvertAlignment(ctrl.TextAlign, rtl) 
            | TextFormatFlags.LeftAndRightPadding 
            | TextFormatFlags.Internal;
        Rectangle rect = e.ClipRectangle;
        Size size = new Size(rect.Width - 1 - glyphSize.Width, rect.Height);
        Point point = rtl ? new Point(rect.X - 1, rect.Y) : new Point(rect.X + glyphSize.Width + 1, rect.Y + 1);
        rect = new Rectangle(point, size);
        DrawBackground(e.Graphics, ctrl.BackColor, rect);
        TextRenderer.DrawText(e.Graphics, ctrl.Text, ctrl.Font, rect, foreColor, tff);
    }

    #endregion

    #region ContentAlignment<->TextFormatting Conversions

    public static TextFormatFlags ConvertAlignment(ContentAlignment alignment, bool rtl)
    {
        TextFormatFlags tff = TextFormatFlags.Default;
        // Vertical alignment
        tff |= alignment switch
        {
            ContentAlignment.TopLeft or ContentAlignment.TopRight or ContentAlignment.TopCenter => TextFormatFlags.Top,
            ContentAlignment.BottomLeft or ContentAlignment.BottomRight or ContentAlignment.BottomCenter => TextFormatFlags.Bottom,
            ContentAlignment.MiddleLeft or ContentAlignment.MiddleRight or ContentAlignment.MiddleCenter => TextFormatFlags.VerticalCenter,
            _ => TextFormatFlags.Default
        };
        // Horizontal alignment
        tff |= alignment switch
        {
            ContentAlignment.TopLeft or ContentAlignment.BottomLeft or ContentAlignment.MiddleLeft when rtl => TextFormatFlags.Right,
            ContentAlignment.TopLeft or ContentAlignment.BottomLeft or ContentAlignment.MiddleLeft => TextFormatFlags.Left,
            ContentAlignment.TopRight or ContentAlignment.BottomRight or ContentAlignment.MiddleRight when rtl => TextFormatFlags.Left,
            ContentAlignment.TopRight or ContentAlignment.BottomRight or ContentAlignment.MiddleRight => TextFormatFlags.Right,
            _ => TextFormatFlags.HorizontalCenter
        };
        return tff;
    }

    #endregion

    #endregion

    #region Native

    [SuppressUnmanagedCodeSecurity]
    private static partial class Native
    {
        #region Scaling Factor

        [LibraryImport("gdi32.dll", SetLastError = true)]
        private static partial int GetDeviceCaps(nint hdc, int nIndex);
        
        public static float GetScalingFactor()
        {
            const int VERTRES = 10;
            const int DESKTOPVERTRES = 117;
            using Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
            int logicalScreenHeight = GetDeviceCaps(desktop, VERTRES);
            int physicalScreenHeight = GetDeviceCaps(desktop, DESKTOPVERTRES);
            return physicalScreenHeight / (float)logicalScreenHeight; // 1.25 = 125%
        }

        #endregion

        #region Experimental Dark Mode

        private const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19;
        private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
        private const int PREFFERED_APP_MODE__ALLOW_DARK = 1;
        private const int PREFFERED_APP_MODE__DEFAULT = 0;
        private const int S_OK = 0;

        public static bool IsDarkModeSupported { get; } = IsWindows10OrGreater(17763);

        public static bool ControlSetDarkMode(IWin32Window window, bool enable)
        {
            if (!IsDarkModeSupported) 
            { 
                return false; 
            }
            int error = SetWindowTheme(window.Handle, enable ? "darkmode_explorer" : "explorer", null);
            return Check(error);
        }

        public static bool UseImmersiveDarkModeColors(IWin32Window window, bool enable)
        {
            if (!IsDarkModeSupported) 
            { 
                return false;
            }
            WindowCompositionAttributeData data = new()
            {
                Attribute = WindowCompositionAttribute.WCA_USEDARKMODECOLORS,
                Data = enable ? 1 : 0,
                SizeOfData = Marshal.SizeOf<int>()
            };
            return SetWindowCompositionAttribute(window.Handle, data);
        }

        public static bool SetPreferredAppMode(bool dark)
        {
            if (!IsDarkModeSupported) 
            {
                return false;
            }
            int error = SetPreferredAppMode(dark ? 1 : 0);
            return Check(error);
        }

        public static bool UseImmersiveDarkMode(IWin32Window window, bool enabled)
        {
            if (!IsDarkModeSupported) 
            { 
                return false; 
            }
            int attr = IsWindows10OrGreater(18985)
                ? DWMWA_USE_IMMERSIVE_DARK_MODE
                : DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1;
            int attrValue = enabled ? 1 : 0;
            int error = DwmSetWindowAttribute(window.Handle, attr, ref attrValue, sizeof(int));
            return Check(error);
        }

        private static bool Check(int error)
        {
            return error == S_OK ? true : throw new Win32Exception(error);
        }

        private static bool IsWindows10OrGreater(int build = -1)
        {
            Version version = Environment.OSVersion.Version;
            return version.Major >= 10 && version.Build >= build;
        }

        [LibraryImport("uxtheme.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
        private static partial int SetWindowTheme(nint hWnd, string? pszSubAppName, string? pszSubIdList);

        [LibraryImport("uxtheme.dll", EntryPoint = "#133", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static partial bool AllowDarkModeForWindow(nint hWnd, [MarshalAs(UnmanagedType.Bool)] bool allow);

        [LibraryImport("uxtheme.dll", EntryPoint = "#135", SetLastError = true)]
        private static partial int SetPreferredAppMode(int i);

        [LibraryImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static partial bool SetWindowCompositionAttribute(nint hwnd, WindowCompositionAttributeData data);
        
        [LibraryImport("dwmapi.dll", SetLastError = true)]
        private static partial int DwmSetWindowAttribute(nint hwnd, int attr, ref int attrValue, int attrSize);

        private enum WindowCompositionAttribute
        {
            WCA_ACCENT_POLICY = 19,
            WCA_USEDARKMODECOLORS = 26
        }

        [StructLayout(LayoutKind.Sequential)]
        private ref struct WindowCompositionAttributeData
        {
            public WindowCompositionAttribute Attribute;
            public int Data;
            public int SizeOfData;
        }

        #endregion
    }

    #endregion
}


================================================
FILE: SvgFileType/Import/MyBaseForm.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!-- 
    Microsoft ResX Schema 
    
    Version 2.0
    
    The primary goals of this format is to allow a simple XML format 
    that is mostly human readable. The generation and parsing of the 
    various data types are done through the TypeConverter classes 
    associated with the data types.
    
    Example:
    
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
                
    There are any number of "resheader" rows that contain simple 
    name/value pairs.
    
    Each data row contains a name, and value. The row also contains a 
    type or mimetype. Type corresponds to a .NET class that support 
    text/value conversion through the TypeConverter architecture. 
    Classes that don't support this are serialized and stored with the 
    mimetype set.
    
    The mimetype is used for serialized objects, and tells the 
    ResXResourceReader how to depersist the object. This is currently not 
    extensible. For a given mimetype the value must be set accordingly:
    
    Note - application/x-microsoft.net.object.binary.base64 is the format 
    that the ResXResourceWriter will generate, however the reader can 
    read any of the formats listed below.
    
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with 
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with 
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.

    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array 
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
</root>

================================================
FILE: SvgFileType/Import/ResvgSvgRenderer.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime;
using System.Threading;
using PaintDotNet;
using resvg.net;
using Svg;
using SvgFileTypePlugin.Extensions;

namespace SvgFileTypePlugin.Import;

internal sealed class ResvgSvgRenderer() : SvgRenderer2("resvg")
{
    protected override Document GetFlatDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        ctoken.ThrowIfCancellationRequested();
        (int width, int height) = (config.RasterWidth, config.RasterHeight);
        using BenchmarkScope _ = new BenchmarkScope();
        using MemoryFailPoint mfp = GetMemoryFailPoint(width, height, 1);
        ResetProgress(1);
        Surface surface = new Surface(width, height);
        try
        {
            using Resvg resvg = Resvg.FromData(svgdata, loadSystemFonts: true);
            ResvgTransform transform = CalculateTransform(resvg.Size, config);
            resvg.Render(surface.Scan0.Pointer, transform, width, height, PixelOpFlags.RgbaToBgra | PixelOpFlags.UnPremultiplyAlpha);
        }
        catch (Exception)
        {
            surface.Dispose();
            throw;
        }

        Document document = surface.CreateSingleLayerDocument(takeOwnership: true);
        document.SetDpu(config.Ppi);
        IncrementProgress();
        return document;
    }

    protected override Document GetLayeredDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(svgdata);
        ArgumentNullException.ThrowIfNull(config);

        using BenchmarkScope _ = new BenchmarkScope();
        SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
        using IDisposable _1 = svg.UseSetRasterDimensions(config);

        List<SvgVisualElement> elements = GetSvgVisualElements(svg, config, ctoken);
        ctoken.ThrowIfCancellationRequested();

        using MemoryFailPoint _2 = GetMemoryFailPoint(config.RasterWidth, config.RasterHeight, elements.Count);

        ResetProgress(elements.Count);
        List<BitmapLayer> layers = [];
        using ResvgOptions options = new ResvgOptions();
        options.LoadSystemFonts();

        using Surface surface = new Surface(config.RasterWidth, config.RasterHeight, SurfaceCreationFlags.DoNotZeroFillHint);
        // Render all visual elements that are passed here.
        foreach (SvgVisualElement element in elements)
        {
            ctoken.ThrowIfCancellationRequested();

            BitmapLayer? layer;
            if (element is GroupBoundary boundaryNode)
            {
                // Render empty group boundary and continue
                layer = boundaryNode.ToEmptyLayer(config.RasterWidth, config.RasterHeight);
                layers.Add(layer);
                IncrementProgress();
                continue;
            }

            if (!element.PreRender(elements, config.ImportHiddenElements, ctoken))
            {
                IncrementProgress();
                continue;
            }

            surface.Clear();
            RenderSvgDocument(element, surface, options, config);
            if (surface.IsEmpty())
            {
                IncrementProgress();
                continue;
            }
            layer = new BitmapLayer(surface, takeOwnership: false);
            try
            {
                layer.Name = GetLayerTitle(element);
                if (config.RespectElementOpacity)
                {
                    layer.Opacity = ToByteOpacity(element.Opacity);
                }

                if (config.ImportHiddenElements && !element.IsOriginallyVisible())
                {
                    layer.Visible = false;
                }
            }
            catch (Exception)
            {
                layer?.Dispose();
                layers.ForEach(layer => layer.Dispose());
                throw;
            }

            IncrementProgress();
            layers.Add(layer);
        }
        return GetDocument(layers, config);
    }

    private void RenderSvgDocument(SvgElement element, Surface surface, ResvgOptions options, SvgImportConfig config)
    {
        if (element is SvgUse use)
        {
            RenderSvgUseElement(use, e => RenderSvgDocument(e, surface, options, config));
        }
        else
        {
            SvgDocument clone = element.OwnerDocument.RemoveInvisibleAndNonTextElements();
            (int width, int height) = (surface.Width, surface.Height);
            using Resvg resvg = Resvg.FromData(clone.GetXML_QuotedFuncIRIHack(), options);
            resvg.Render(surface.Scan0.Pointer, width, height, PixelOpFlags.RgbaToBgra | PixelOpFlags.UnPremultiplyAlpha);
        }
    }

    private static ResvgTransform CalculateTransform(SizeF svgsize, SvgImportConfig config)
    {
        float ratioX = config.RasterWidth / svgsize.Width;
        float ratioY = config.PreserveAspectRatio ? ratioX : config.RasterHeight / svgsize.Height;
        return new ResvgTransform()
        {
            M11 = ratioX,
            M22 = ratioY
        };
    }
}


================================================
FILE: SvgFileType/Import/StreamTrackerCancellationTokenSource.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.IO;
using System.Threading;

namespace SvgFileTypePlugin.Import;

/// <summary>
/// Paint.NET input stream can throw <see cref="OperationCanceledException"></see> internally.
/// This class helps us to track these cancellation events. Provides us ability to gracefully end 
/// the ongoing operation.
/// <br />
/// <b>! Note: Must be used after reading the whole stream.</b>
/// </summary>
internal sealed class StreamTrackerCancellationTokenSource : CancellationTokenSource
{
    private bool disposed;
    private readonly Timer? timer;
    private readonly Func<bool>? action;

    public StreamTrackerCancellationTokenSource(Stream stream, int period = 1000)
    {
        ArgumentNullException.ThrowIfNull(stream);
        ArgumentOutOfRangeException.ThrowIfNegative(period);

        if (!stream.CanSeek)
        {
            return;
        }

        action = () => IsStreamCanceled(stream);
        timer = new Timer(OnTimer, null, 0, period);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (!disposed)
        {
            disposed = true;
            timer?.Dispose();
        }
    }

    private void OnTimer(object? state)
    {
        try
        {
            if (action!.Invoke())
            {
                Cancel();
                timer!.Dispose();
            }
        }
        catch (ObjectDisposedException)
        {
            // ignore
        }
    }

    private static bool IsStreamCanceled(Stream stream)
    {
        ArgumentNullException.ThrowIfNull(stream);

        try
        {
            stream.Position = 0;
            return false;
        }
        catch (ObjectDisposedException)
        {
            Logger.WriteLine("Completed!");
            return true;
        }
        catch (OperationCanceledException)
        {
            Logger.WriteLine("Canceled!");
            return true;
        }
    }
}


================================================
FILE: SvgFileType/Import/SvgImport.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Windows.Forms;
using PaintDotNet;
using Svg;
using SvgFileTypePlugin.Extensions;

namespace SvgFileTypePlugin.Import;

internal static class SvgImport
{
    public static Document Load(Stream stream)
    {
        ArgumentNullException.ThrowIfNull(stream);
        if (!stream.CanRead)
        {
            throw new IOException("Input stream is not readable.");
        }

        if (stream.Length <= 0)
        {
            return new Direct2DSvgRenderer().GetNoPathDocument();
        }

        // We are using resvg which gives the best result in my tests.
        // For testing purposes, I also have implemented GDI+ and Direct2D based SVG renderers as well.
        // Renderers: resvg, gdip or gdiplus or gdi+, direct2d or d2d
        const string rendererName = "resvg";

        string svgdata = Open(stream);
        using StreamTrackerCancellationTokenSource cts = new(stream);
        CancellationToken ctoken = cts.Token;
        if (UIHelper.IsSaveConfigDialogVisible())
        {
            // This is workaround for Saving functionality.
            // We don't want the dialog appear if Paint.NET is generating previews.
            SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
            SvgRenderer2 svgRenderer = SvgRenderer2.Create(rendererName);
            SvgImportConfig config = new SvgImportConfig
            {
                LayersMode = LayersMode.Flat,
                RasterWidth = svg.Width.ToDeviceValue(svg),
                RasterHeight = svg.Height.ToDeviceValue(svg),
                Ppi = 96
            };
            return svgRenderer.Rasterize(svgdata, config, ctoken);
        }

        Document? document = UIHelper.RunOnUIThread(() =>
        {
            using SvgImportDialog dialog = new SvgImportDialog(svgdata, rendererName, ctoken);
            DialogResult dialogResult = dialog.ShowDialog();
            return dialogResult == DialogResult.OK ? dialog.Result : throw dialog.Error ?? new InvalidOperationException();
        });
        Debug.Assert(document is not null);
        return document;
    }

    private static string Open(Stream input)
    {
        using MemoryStream ms = new();
        Span<byte> buf = new byte[3];
        if (input.Read(buf) < 3)
        {
            throw new IOException("Input stream is not a valid SVG.");
        }
        ms.Write(buf);
        input.CopyTo(ms);

        // Do not close the source stream.
        // It also can be used to track cancellation.

        ms.Position = 0;

        ReadOnlySpan<byte> gzipMagicBytes = [0x1F, 0x8B, 0x8];
        input = buf.SequenceEqual(gzipMagicBytes)
            ? new GZipStream(ms, CompressionMode.Decompress, leaveOpen: false)
            : ms;
        using StreamReader reader = new StreamReader(input, leaveOpen: false);
        return reader.ReadToEnd();
    }
}


================================================
FILE: SvgFileType/Import/SvgImportConfig.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

namespace SvgFileTypePlugin.Import;

internal sealed class SvgImportConfig
{
    public required int RasterWidth { get; init; }

    public required int RasterHeight { get; init; }

    public bool PreserveAspectRatio { get; set; } = true;

    public int Ppi { get; set; } = 96;

    public LayersMode LayersMode { get; set; } = LayersMode.Flat;

    public bool GroupBoundariesAsLayers { get; set; }

    public bool RespectElementOpacity { get; set; }

    public bool ImportHiddenElements { get; set; }
}


================================================
FILE: SvgFileType/Import/SvgImportDialog.Designer.cs
================================================
namespace SvgFileTypePlugin.Import;

partial class SvgImportDialog
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
        ToolTip1 = new System.Windows.Forms.ToolTip(components);
        PbWarning = new System.Windows.Forms.PictureBox();
        CbGroupBoundaries = new System.Windows.Forms.CheckBox();
        RootPanel = new System.Windows.Forms.Panel();
        StatusStrip = new System.Windows.Forms.StatusStrip();
        ProgressBar = new System.Windows.Forms.ToolStripProgressBar();
        ProgressLabel = new System.Windows.Forms.ToolStripStatusLabel();
        PlaceHolderLabel = new System.Windows.Forms.ToolStripStatusLabel();
        UpdateAvailLabel = new System.Windows.Forms.ToolStripStatusLabel();
        tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
        LnkGitHub = new System.Windows.Forms.LinkLabel();
        LnkForum = new System.Windows.Forms.LinkLabel();
        BtnOk = new System.Windows.Forms.Button();
        BtnCancel = new System.Windows.Forms.Button();
        GbLayers = new System.Windows.Forms.GroupBox();
        tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
        RbFlatten = new System.Windows.Forms.RadioButton();
        RbGroups = new System.Windows.Forms.RadioButton();
        CbHiddenLayers = new System.Windows.Forms.CheckBox();
        RbAllElements = new System.Windows.Forms.RadioButton();
        CbOpacity = new System.Windows.Forms.CheckBox();
        GbSizeSelection = new System.Windows.Forms.GroupBox();
        CbKeepAR = new System.Windows.Forms.CheckBox();
        tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
        LblResolution = new System.Windows.Forms.Label();
        LblCanvasWH = new System.Windows.Forms.Label();
        NudCanvasW = new System.Windows.Forms.NumericUpDown();
        NudCanvasH = new System.Windows.Forms.NumericUpDown();
        label9 = new System.Windows.Forms.Label();
        NudDpi = new System.Windows.Forms.NumericUpDown();
        GbInfo = new System.Windows.Forms.GroupBox();
        tableLayoutPanel9 = new System.Windows.Forms.TableLayoutPanel();
        LnkUseSvgSettings = new System.Windows.Forms.Button();
        tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
        LblViewport = new System.Windows.Forms.Label();
        TbViewboxH = new System.Windows.Forms.TextBox();
        label6 = new System.Windows.Forms.Label();
        TbViewportW = new System.Windows.Forms.TextBox();
        label3 = new System.Windows.Forms.Label();
        TbViewboxW = new System.Windows.Forms.TextBox();
        TbViewportH = new System.Windows.Forms.TextBox();
        LblViewboxWH = new System.Windows.Forms.Label();
        LblViewboxXY = new System.Windows.Forms.Label();
        TbViewboxY = new System.Windows.Forms.TextBox();
        label4 = new System.Windows.Forms.Label();
        TbViewboxX = new System.Windows.Forms.TextBox();
        ((System.ComponentModel.ISupportInitialize)PbWarning).BeginInit();
        RootPanel.SuspendLayout();
        StatusStrip.SuspendLayout();
        tableLayoutPanel3.SuspendLayout();
        GbLayers.SuspendLayout();
        tableLayoutPanel1.SuspendLayout();
        GbSizeSelection.SuspendLayout();
        tableLayoutPanel4.SuspendLayout();
        ((System.ComponentModel.ISupportInitialize)NudCanvasW).BeginInit();
        ((System.ComponentModel.ISupportInitialize)NudCanvasH).BeginInit();
        ((System.ComponentModel.ISupportInitialize)NudDpi).BeginInit();
        GbInfo.SuspendLayout();
        tableLayoutPanel9.SuspendLayout();
        tableLayoutPanel2.SuspendLayout();
        SuspendLayout();
        // 
        // ToolTip1
        // 
        ToolTip1.AutomaticDelay = 0;
        ToolTip1.AutoPopDelay = 0;
        ToolTip1.InitialDelay = 0;
        ToolTip1.IsBalloon = true;
        ToolTip1.ReshowDelay = 0;
        ToolTip1.ShowAlways = true;
        ToolTip1.UseAnimation = false;
        // 
        // PbWarning
        // 
        PbWarning.Dock = System.Windows.Forms.DockStyle.Fill;
        PbWarning.Location = new System.Drawing.Point(52, 0);
        PbWarning.Margin = new System.Windows.Forms.Padding(0);
        PbWarning.MinimumSize = new System.Drawing.Size(23, 23);
        PbWarning.Name = "PbWarning";
        PbWarning.Size = new System.Drawing.Size(23, 29);
        PbWarning.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
        PbWarning.TabIndex = 2;
        PbWarning.TabStop = false;
        ToolTip1.SetToolTip(PbWarning, "Please make sure you've enough memory, especially if you're importing with layers.");
        PbWarning.Visible = false;
        // 
        // CbGroupBoundaries
        // 
        CbGroupBoundaries.AutoSize = true;
        CbGroupBoundaries.Dock = System.Windows.Forms.DockStyle.Fill;
        CbGroupBoundaries.Enabled = false;
        CbGroupBoundaries.Location = new System.Drawing.Point(99, 53);
        CbGroupBoundaries.Name = "CbGroupBoundaries";
        CbGroupBoundaries.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
        CbGroupBoundaries.Size = new System.Drawing.Size(256, 19);
        CbGroupBoundaries.TabIndex = 2;
        CbGroupBoundaries.Text = "Group boundaries";
        ToolTip1.SetToolTip(CbGroupBoundaries, "Imports group boundaries as empty layers.");
        CbGroupBoundaries.UseVisualStyleBackColor = true;
        // 
        // RootPanel
        // 
        RootPanel.AutoSize = true;
        RootPanel.Controls.Add(StatusStrip);
        RootPanel.Controls.Add(tableLayoutPanel3);
        RootPanel.Controls.Add(GbLayers);
        RootPanel.Controls.Add(GbSizeSelection);
        RootPanel.Controls.Add(GbInfo);
        RootPanel.Dock = System.Windows.Forms.DockStyle.Top;
        RootPanel.Location = new System.Drawing.Point(0, 0);
        RootPanel.Name = "RootPanel";
        RootPanel.Padding = new System.Windows.Forms.Padding(10, 10, 10, 0);
        RootPanel.Size = new System.Drawing.Size(384, 421);
        RootPanel.TabIndex = 0;
        // 
        // StatusStrip
        // 
        StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { ProgressBar, ProgressLabel, PlaceHolderLabel, UpdateAvailLabel });
        StatusStrip.Location = new System.Drawing.Point(10, 399);
        StatusStrip.Name = "StatusStrip";
        StatusStrip.Size = new System.Drawing.Size(364, 22);
        StatusStrip.SizingGrip = false;
        StatusStrip.TabIndex = 0;
        StatusStrip.Text = "statusStrip1";
        // 
        // ProgressBar
        // 
        ProgressBar.Name = "ProgressBar";
        ProgressBar.Size = new System.Drawing.Size(100, 16);
        ProgressBar.Visible = false;
        // 
        // ProgressLabel
        // 
        ProgressLabel.BackColor = System.Drawing.Color.Transparent;
        ProgressLabel.Name = "ProgressLabel";
        ProgressLabel.Size = new System.Drawing.Size(42, 17);
        ProgressLabel.Text = "Ready!";
        // 
        // PlaceHolderLabel
        // 
        PlaceHolderLabel.BackColor = System.Drawing.Color.Transparent;
        PlaceHolderLabel.Name = "PlaceHolderLabel";
        PlaceHolderLabel.Size = new System.Drawing.Size(307, 17);
        PlaceHolderLabel.Spring = true;
        // 
        // UpdateAvailLabel
        // 
        UpdateAvailLabel.BackColor = System.Drawing.Color.Transparent;
        UpdateAvailLabel.ForeColor = System.Drawing.Color.Red;
        UpdateAvailLabel.Name = "UpdateAvailLabel";
        UpdateAvailLabel.Size = new System.Drawing.Size(0, 17);
        // 
        // tableLayoutPanel3
        // 
        tableLayoutPanel3.AutoSize = true;
        tableLayoutPanel3.ColumnCount = 5;
        tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
        tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel3.Controls.Add(LnkGitHub, 0, 0);
        tableLayoutPanel3.Controls.Add(LnkForum, 1, 0);
        tableLayoutPanel3.Controls.Add(BtnOk, 3, 0);
        tableLayoutPanel3.Controls.Add(BtnCancel, 4, 0);
        tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Top;
        tableLayoutPanel3.Location = new System.Drawing.Point(10, 350);
        tableLayoutPanel3.Name = "tableLayoutPanel3";
        tableLayoutPanel3.Padding = new System.Windows.Forms.Padding(10);
        tableLayoutPanel3.RowCount = 1;
        tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel3.Size = new System.Drawing.Size(364, 49);
        tableLayoutPanel3.TabIndex = 1;
        // 
        // LnkGitHub
        // 
        LnkGitHub.Dock = System.Windows.Forms.DockStyle.Fill;
        LnkGitHub.Location = new System.Drawing.Point(13, 10);
        LnkGitHub.Name = "LnkGitHub";
        LnkGitHub.Size = new System.Drawing.Size(45, 29);
        LnkGitHub.TabIndex = 2;
        LnkGitHub.TabStop = true;
        LnkGitHub.Text = "GitHub";
        LnkGitHub.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // LnkForum
        // 
        LnkForum.AutoSize = true;
        LnkForum.Dock = System.Windows.Forms.DockStyle.Fill;
        LnkForum.Location = new System.Drawing.Point(64, 10);
        LnkForum.Name = "LnkForum";
        LnkForum.Size = new System.Drawing.Size(42, 29);
        LnkForum.TabIndex = 3;
        LnkForum.TabStop = true;
        LnkForum.Text = "Forum";
        LnkForum.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // BtnOk
        // 
        BtnOk.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
        BtnOk.Location = new System.Drawing.Point(195, 13);
        BtnOk.Name = "BtnOk";
        BtnOk.Size = new System.Drawing.Size(75, 23);
        BtnOk.TabIndex = 0;
        BtnOk.Text = "OK";
        BtnOk.UseVisualStyleBackColor = true;
        // 
        // BtnCancel
        // 
        BtnCancel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
        BtnCancel.Location = new System.Drawing.Point(276, 13);
        BtnCancel.Name = "BtnCancel";
        BtnCancel.Size = new System.Drawing.Size(75, 23);
        BtnCancel.TabIndex = 1;
        BtnCancel.Text = "Cancel";
        BtnCancel.UseVisualStyleBackColor = true;
        // 
        // GbLayers
        // 
        GbLayers.AutoSize = true;
        GbLayers.Controls.Add(tableLayoutPanel1);
        GbLayers.Dock = System.Windows.Forms.DockStyle.Top;
        GbLayers.Location = new System.Drawing.Point(10, 253);
        GbLayers.Name = "GbLayers";
        GbLayers.Size = new System.Drawing.Size(364, 97);
        GbLayers.TabIndex = 2;
        GbLayers.TabStop = false;
        GbLayers.Text = "Layers";
        // 
        // tableLayoutPanel1
        // 
        tableLayoutPanel1.AutoSize = true;
        tableLayoutPanel1.ColumnCount = 2;
        tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel1.Controls.Add(RbFlatten, 0, 0);
        tableLayoutPanel1.Controls.Add(CbGroupBoundaries, 1, 2);
        tableLayoutPanel1.Controls.Add(RbGroups, 0, 1);
        tableLayoutPanel1.Controls.Add(CbHiddenLayers, 1, 1);
        tableLayoutPanel1.Controls.Add(RbAllElements, 0, 2);
        tableLayoutPanel1.Controls.Add(CbOpacity, 1, 0);
        tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
        tableLayoutPanel1.Location = new System.Drawing.Point(3, 19);
        tableLayoutPanel1.Name = "tableLayoutPanel1";
        tableLayoutPanel1.RowCount = 3;
        tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel1.Size = new System.Drawing.Size(358, 75);
        tableLayoutPanel1.TabIndex = 0;
        // 
        // RbFlatten
        // 
        RbFlatten.AutoSize = true;
        RbFlatten.Checked = true;
        RbFlatten.Dock = System.Windows.Forms.DockStyle.Fill;
        RbFlatten.Location = new System.Drawing.Point(3, 3);
        RbFlatten.Name = "RbFlatten";
        RbFlatten.Size = new System.Drawing.Size(90, 19);
        RbFlatten.TabIndex = 3;
        RbFlatten.TabStop = true;
        RbFlatten.Text = "Flatten";
        RbFlatten.UseVisualStyleBackColor = true;
        // 
        // RbGroups
        // 
        RbGroups.AutoSize = true;
        RbGroups.Dock = System.Windows.Forms.DockStyle.Fill;
        RbGroups.Location = new System.Drawing.Point(3, 28);
        RbGroups.Name = "RbGroups";
        RbGroups.Size = new System.Drawing.Size(90, 19);
        RbGroups.TabIndex = 4;
        RbGroups.Text = "Groups";
        RbGroups.UseVisualStyleBackColor = true;
        // 
        // CbHiddenLayers
        // 
        CbHiddenLayers.AutoSize = true;
        CbHiddenLayers.Checked = true;
        CbHiddenLayers.CheckState = System.Windows.Forms.CheckState.Checked;
        CbHiddenLayers.Dock = System.Windows.Forms.DockStyle.Fill;
        CbHiddenLayers.Enabled = false;
        CbHiddenLayers.Location = new System.Drawing.Point(99, 28);
        CbHiddenLayers.Name = "CbHiddenLayers";
        CbHiddenLayers.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
        CbHiddenLayers.Size = new System.Drawing.Size(256, 19);
        CbHiddenLayers.TabIndex = 1;
        CbHiddenLayers.Text = "Hidden layers";
        CbHiddenLayers.UseVisualStyleBackColor = true;
        // 
        // RbAllElements
        // 
        RbAllElements.AutoSize = true;
        RbAllElements.Dock = System.Windows.Forms.DockStyle.Fill;
        RbAllElements.Location = new System.Drawing.Point(3, 53);
        RbAllElements.Name = "RbAllElements";
        RbAllElements.Size = new System.Drawing.Size(90, 19);
        RbAllElements.TabIndex = 5;
        RbAllElements.Text = "All Elements";
        RbAllElements.UseVisualStyleBackColor = true;
        // 
        // CbOpacity
        // 
        CbOpacity.AutoSize = true;
        CbOpacity.Checked = true;
        CbOpacity.CheckState = System.Windows.Forms.CheckState.Checked;
        CbOpacity.Dock = System.Windows.Forms.DockStyle.Fill;
        CbOpacity.Enabled = false;
        CbOpacity.Location = new System.Drawing.Point(99, 3);
        CbOpacity.Name = "CbOpacity";
        CbOpacity.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
        CbOpacity.Size = new System.Drawing.Size(256, 19);
        CbOpacity.TabIndex = 0;
        CbOpacity.Text = "Opacity as layer property";
        CbOpacity.UseVisualStyleBackColor = true;
        // 
        // GbSizeSelection
        // 
        GbSizeSelection.AutoSize = true;
        GbSizeSelection.Controls.Add(CbKeepAR);
        GbSizeSelection.Controls.Add(tableLayoutPanel4);
        GbSizeSelection.Dock = System.Windows.Forms.DockStyle.Top;
        GbSizeSelection.Location = new System.Drawing.Point(10, 154);
        GbSizeSelection.Name = "GbSizeSelection";
        GbSizeSelection.Size = new System.Drawing.Size(364, 99);
        GbSizeSelection.TabIndex = 3;
        GbSizeSelection.TabStop = false;
        GbSizeSelection.Text = "Size selection by user";
        // 
        // CbKeepAR
        // 
        CbKeepAR.AutoSize = true;
        CbKeepAR.Checked = true;
        CbKeepAR.CheckState = System.Windows.Forms.CheckState.Checked;
        CbKeepAR.Dock = System.Windows.Forms.DockStyle.Top;
        CbKeepAR.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
        CbKeepAR.Location = new System.Drawing.Point(3, 77);
        CbKeepAR.Name = "CbKeepAR";
        CbKeepAR.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
        CbKeepAR.Size = new System.Drawing.Size(358, 19);
        CbKeepAR.TabIndex = 0;
        CbKeepAR.Text = "Keep aspect ratio";
        CbKeepAR.UseVisualStyleBackColor = true;
        // 
        // tableLayoutPanel4
        // 
        tableLayoutPanel4.AutoSize = true;
        tableLayoutPanel4.ColumnCount = 7;
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 23F));
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel4.Controls.Add(LblResolution, 2, 1);
        tableLayoutPanel4.Controls.Add(LblCanvasWH, 2, 0);
        tableLayoutPanel4.Controls.Add(PbWarning, 1, 0);
        tableLayoutPanel4.Controls.Add(NudCanvasW, 3, 0);
        tableLayoutPanel4.Controls.Add(NudCanvasH, 5, 0);
        tableLayoutPanel4.Controls.Add(label9, 4, 0);
        tableLayoutPanel4.Controls.Add(NudDpi, 3, 1);
        tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Top;
        tableLayoutPanel4.Location = new System.Drawing.Point(3, 19);
        tableLayoutPanel4.Name = "tableLayoutPanel4";
        tableLayoutPanel4.RowCount = 2;
        tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel4.Size = new System.Drawing.Size(358, 58);
        tableLayoutPanel4.TabIndex = 1;
        // 
        // LblResolution
        // 
        LblResolution.AutoSize = true;
        LblResolution.Dock = System.Windows.Forms.DockStyle.Fill;
        LblResolution.Location = new System.Drawing.Point(78, 29);
        LblResolution.Name = "LblResolution";
        LblResolution.Size = new System.Drawing.Size(92, 29);
        LblResolution.TabIndex = 0;
        LblResolution.Text = "Resolution (DPI)";
        LblResolution.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        // 
        // LblCanvasWH
        // 
        LblCanvasWH.AutoSize = true;
        LblCanvasWH.Dock = System.Windows.Forms.DockStyle.Fill;
        LblCanvasWH.Location = new System.Drawing.Point(78, 0);
        LblCanvasWH.Name = "LblCanvasWH";
        LblCanvasWH.Size = new System.Drawing.Size(92, 29);
        LblCanvasWH.TabIndex = 1;
        LblCanvasWH.Text = "Canvas (W×H)";
        LblCanvasWH.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        // 
        // NudCanvasW
        // 
        NudCanvasW.Dock = System.Windows.Forms.DockStyle.Fill;
        NudCanvasW.Location = new System.Drawing.Point(176, 3);
        NudCanvasW.Maximum = new decimal(new int[] { 100000, 0, 0, 0 });
        NudCanvasW.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
        NudCanvasW.MinimumSize = new System.Drawing.Size(50, 0);
        NudCanvasW.Name = "NudCanvasW";
        NudCanvasW.Size = new System.Drawing.Size(50, 23);
        NudCanvasW.TabIndex = 0;
        NudCanvasW.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
        NudCanvasW.Value = new decimal(new int[] { 512, 0, 0, 0 });
        // 
        // NudCanvasH
        // 
        NudCanvasH.Dock = System.Windows.Forms.DockStyle.Fill;
        NudCanvasH.Location = new System.Drawing.Point(253, 3);
        NudCanvasH.Maximum = new decimal(new int[] { 100000, 0, 0, 0 });
        NudCanvasH.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
        NudCanvasH.MinimumSize = new System.Drawing.Size(50, 0);
        NudCanvasH.Name = "NudCanvasH";
        NudCanvasH.Size = new System.Drawing.Size(50, 23);
        NudCanvasH.TabIndex = 1;
        NudCanvasH.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
        NudCanvasH.Value = new decimal(new int[] { 512, 0, 0, 0 });
        // 
        // label9
        // 
        label9.AutoSize = true;
        label9.Dock = System.Windows.Forms.DockStyle.Fill;
        label9.Location = new System.Drawing.Point(232, 0);
        label9.Name = "label9";
        label9.Size = new System.Drawing.Size(15, 29);
        label9.TabIndex = 5;
        label9.Text = "×";
        label9.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // NudDpi
        // 
        NudDpi.Dock = System.Windows.Forms.DockStyle.Fill;
        NudDpi.Location = new System.Drawing.Point(176, 32);
        NudDpi.Maximum = new decimal(new int[] { 32767, 0, 0, 0 });
        NudDpi.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
        NudDpi.MinimumSize = new System.Drawing.Size(50, 0);
        NudDpi.Name = "NudDpi";
        NudDpi.Size = new System.Drawing.Size(50, 23);
        NudDpi.TabIndex = 2;
        NudDpi.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
        NudDpi.Value = new decimal(new int[] { 96, 0, 0, 0 });
        // 
        // GbInfo
        // 
        GbInfo.AutoSize = true;
        GbInfo.Controls.Add(tableLayoutPanel9);
        GbInfo.Controls.Add(tableLayoutPanel2);
        GbInfo.Dock = System.Windows.Forms.DockStyle.Top;
        GbInfo.Location = new System.Drawing.Point(10, 10);
        GbInfo.Name = "GbInfo";
        GbInfo.Size = new System.Drawing.Size(364, 144);
        GbInfo.TabIndex = 4;
        GbInfo.TabStop = false;
        GbInfo.Text = "Size settings given in SVG file";
        // 
        // tableLayoutPanel9
        // 
        tableLayoutPanel9.AutoSize = true;
        tableLayoutPanel9.ColumnCount = 3;
        tableLayoutPanel9.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel9.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel9.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel9.Controls.Add(LnkUseSvgSettings, 1, 0);
        tableLayoutPanel9.Dock = System.Windows.Forms.DockStyle.Top;
        tableLayoutPanel9.Location = new System.Drawing.Point(3, 106);
        tableLayoutPanel9.Name = "tableLayoutPanel9";
        tableLayoutPanel9.RowCount = 1;
        tableLayoutPanel9.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel9.Size = new System.Drawing.Size(358, 35);
        tableLayoutPanel9.TabIndex = 0;
        // 
        // LnkUseSvgSettings
        // 
        LnkUseSvgSettings.AutoSize = true;
        LnkUseSvgSettings.Dock = System.Windows.Forms.DockStyle.Top;
        LnkUseSvgSettings.Location = new System.Drawing.Point(80, 5);
        LnkUseSvgSettings.Margin = new System.Windows.Forms.Padding(5);
        LnkUseSvgSettings.Name = "LnkUseSvgSettings";
        LnkUseSvgSettings.Size = new System.Drawing.Size(197, 25);
        LnkUseSvgSettings.TabIndex = 0;
        LnkUseSvgSettings.Text = "▼ Use size settings given in SVG ▼";
        // 
        // tableLayoutPanel2
        // 
        tableLayoutPanel2.AutoSize = true;
        tableLayoutPanel2.ColumnCount = 6;
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
        tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
        tableLayoutPanel2.Controls.Add(LblViewport, 1, 0);
        tableLayoutPanel2.Controls.Add(TbViewboxH, 4, 2);
        tableLayoutPanel2.Controls.Add(label6, 3, 2);
        tableLayoutPanel2.Controls.Add(TbViewportW, 2, 0);
        tableLayoutPanel2.Controls.Add(label3, 3, 0);
        tableLayoutPanel2.Controls.Add(TbViewboxW, 2, 2);
        tableLayoutPanel2.Controls.Add(TbViewportH, 4, 0);
        tableLayoutPanel2.Controls.Add(LblViewboxWH, 1, 2);
        tableLayoutPanel2.Controls.Add(LblViewboxXY, 1, 1);
        tableLayoutPanel2.Controls.Add(TbViewboxY, 4, 1);
        tableLayoutPanel2.Controls.Add(label4, 3, 1);
        tableLayoutPanel2.Controls.Add(TbViewboxX, 2, 1);
        tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Top;
        tableLayoutPanel2.Location = new System.Drawing.Point(3, 19);
        tableLayoutPanel2.Name = "tableLayoutPanel2";
        tableLayoutPanel2.RowCount = 3;
        tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
        tableLayoutPanel2.Size = new System.Drawing.Size(358, 87);
        tableLayoutPanel2.TabIndex = 1;
        // 
        // LblViewport
        // 
        LblViewport.AutoSize = true;
        LblViewport.Dock = System.Windows.Forms.DockStyle.Fill;
        LblViewport.Location = new System.Drawing.Point(60, 0);
        LblViewport.Name = "LblViewport";
        LblViewport.Size = new System.Drawing.Size(93, 29);
        LblViewport.TabIndex = 0;
        LblViewport.Text = "Viewport (W×H)";
        LblViewport.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        // 
        // TbViewboxH
        // 
        TbViewboxH.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewboxH.Enabled = false;
        TbViewboxH.Location = new System.Drawing.Point(242, 61);
        TbViewboxH.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewboxH.Name = "TbViewboxH";
        TbViewboxH.Size = new System.Drawing.Size(56, 23);
        TbViewboxH.TabIndex = 5;
        TbViewboxH.TabStop = false;
        TbViewboxH.Text = "-";
        TbViewboxH.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // label6
        // 
        label6.AutoSize = true;
        label6.Dock = System.Windows.Forms.DockStyle.Fill;
        label6.Location = new System.Drawing.Point(221, 58);
        label6.Name = "label6";
        label6.Size = new System.Drawing.Size(15, 29);
        label6.TabIndex = 2;
        label6.Text = "×";
        label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // TbViewportW
        // 
        TbViewportW.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewportW.Enabled = false;
        TbViewportW.Location = new System.Drawing.Point(159, 3);
        TbViewportW.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewportW.Name = "TbViewportW";
        TbViewportW.Size = new System.Drawing.Size(56, 23);
        TbViewportW.TabIndex = 0;
        TbViewportW.TabStop = false;
        TbViewportW.Text = "-";
        TbViewportW.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // label3
        // 
        label3.AutoSize = true;
        label3.Dock = System.Windows.Forms.DockStyle.Fill;
        label3.Location = new System.Drawing.Point(221, 0);
        label3.Name = "label3";
        label3.Size = new System.Drawing.Size(15, 29);
        label3.TabIndex = 4;
        label3.Text = "×";
        label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // TbViewboxW
        // 
        TbViewboxW.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewboxW.Enabled = false;
        TbViewboxW.Location = new System.Drawing.Point(159, 61);
        TbViewboxW.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewboxW.Name = "TbViewboxW";
        TbViewboxW.Size = new System.Drawing.Size(56, 23);
        TbViewboxW.TabIndex = 4;
        TbViewboxW.TabStop = false;
        TbViewboxW.Text = "-";
        TbViewboxW.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // TbViewportH
        // 
        TbViewportH.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewportH.Enabled = false;
        TbViewportH.Location = new System.Drawing.Point(242, 3);
        TbViewportH.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewportH.Name = "TbViewportH";
        TbViewportH.Size = new System.Drawing.Size(56, 23);
        TbViewportH.TabIndex = 1;
        TbViewportH.TabStop = false;
        TbViewportH.Text = "-";
        TbViewportH.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // LblViewboxWH
        // 
        LblViewboxWH.AutoSize = true;
        LblViewboxWH.Dock = System.Windows.Forms.DockStyle.Fill;
        LblViewboxWH.Location = new System.Drawing.Point(60, 58);
        LblViewboxWH.Name = "LblViewboxWH";
        LblViewboxWH.Size = new System.Drawing.Size(93, 29);
        LblViewboxWH.TabIndex = 7;
        LblViewboxWH.Text = "ViewBox (W×H)";
        LblViewboxWH.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        // 
        // LblViewboxXY
        // 
        LblViewboxXY.AutoSize = true;
        LblViewboxXY.Dock = System.Windows.Forms.DockStyle.Fill;
        LblViewboxXY.Location = new System.Drawing.Point(60, 29);
        LblViewboxXY.Name = "LblViewboxXY";
        LblViewboxXY.Size = new System.Drawing.Size(93, 29);
        LblViewboxXY.TabIndex = 8;
        LblViewboxXY.Text = "ViewBox (X,Y)";
        LblViewboxXY.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        // 
        // TbViewboxY
        // 
        TbViewboxY.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewboxY.Enabled = false;
        TbViewboxY.Location = new System.Drawing.Point(242, 32);
        TbViewboxY.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewboxY.Name = "TbViewboxY";
        TbViewboxY.Size = new System.Drawing.Size(56, 23);
        TbViewboxY.TabIndex = 3;
        TbViewboxY.TabStop = false;
        TbViewboxY.Text = "-";
        TbViewboxY.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // label4
        // 
        label4.AutoSize = true;
        label4.Dock = System.Windows.Forms.DockStyle.Fill;
        label4.Location = new System.Drawing.Point(221, 29);
        label4.Name = "label4";
        label4.Size = new System.Drawing.Size(15, 29);
        label4.TabIndex = 10;
        label4.Text = ",";
        label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // TbViewboxX
        // 
        TbViewboxX.Dock = System.Windows.Forms.DockStyle.Fill;
        TbViewboxX.Enabled = false;
        TbViewboxX.Location = new System.Drawing.Point(159, 32);
        TbViewboxX.MinimumSize = new System.Drawing.Size(50, 4);
        TbViewboxX.Name = "TbViewboxX";
        TbViewboxX.Size = new System.Drawing.Size(56, 23);
        TbViewboxX.TabIndex = 2;
        TbViewboxX.TabStop = false;
        TbViewboxX.Text = "-";
        TbViewboxX.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
        // 
        // SvgImportDialog
        // 
        AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
        AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
        AutoSize = true;
        ClientSize = new System.Drawing.Size(384, 341);
        Controls.Add(RootPanel);
        Name = "SvgImportDialog";
        ((System.ComponentModel.ISupportInitialize)PbWarning).EndInit();
        RootPanel.ResumeLayout(false);
        RootPanel.PerformLayout();
        StatusStrip.ResumeLayout(false);
        StatusStrip.PerformLayout();
        tableLayoutPanel3.ResumeLayout(false);
        tableLayoutPanel3.PerformLayout();
        GbLayers.ResumeLayout(false);
        GbLayers.PerformLayout();
        tableLayoutPanel1.ResumeLayout(false);
        tableLayoutPanel1.PerformLayout();
        GbSizeSelection.ResumeLayout(false);
        GbSizeSelection.PerformLayout();
        tableLayoutPanel4.ResumeLayout(false);
        tableLayoutPanel4.PerformLayout();
        ((System.ComponentModel.ISupportInitialize)NudCanvasW).EndInit();
        ((System.ComponentModel.ISupportInitialize)NudCanvasH).EndInit();
        ((System.ComponentModel.ISupportInitialize)NudDpi).EndInit();
        GbInfo.ResumeLayout(false);
        GbInfo.PerformLayout();
        tableLayoutPanel9.ResumeLayout(false);
        tableLayoutPanel9.PerformLayout();
        tableLayoutPanel2.ResumeLayout(false);
        tableLayoutPanel2.PerformLayout();
        ResumeLayout(false);
        PerformLayout();
    }

    #endregion
    private System.Windows.Forms.ToolTip ToolTip1;
    private System.Windows.Forms.Panel RootPanel;
    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
    private System.Windows.Forms.LinkLabel LnkGitHub;
    private System.Windows.Forms.LinkLabel LnkForum;
    private System.Windows.Forms.Button BtnOk;
    private System.Windows.Forms.Button BtnCancel;
    private System.Windows.Forms.GroupBox GbLayers;
    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
    private System.Windows.Forms.RadioButton RbFlatten;
    private System.Windows.Forms.CheckBox CbGroupBoundaries;
    private System.Windows.Forms.RadioButton RbGroups;
    private System.Windows.Forms.CheckBox CbHiddenLayers;
    private System.Windows.Forms.RadioButton RbAllElements;
    private System.Windows.Forms.CheckBox CbOpacity;
    private System.Windows.Forms.GroupBox GbSizeSelection;
    private System.Windows.Forms.CheckBox CbKeepAR;
    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
    private System.Windows.Forms.Label LblResolution;
    private System.Windows.Forms.Label LblCanvasWH;
    private System.Windows.Forms.PictureBox PbWarning;
    private System.Windows.Forms.NumericUpDown NudCanvasW;
    private System.Windows.Forms.NumericUpDown NudCanvasH;
    private System.Windows.Forms.Label label9;
    private System.Windows.Forms.NumericUpDown NudDpi;
    private System.Windows.Forms.GroupBox GbInfo;
    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
    private System.Windows.Forms.Label LblViewport;
    private System.Windows.Forms.TextBox TbViewboxH;
    private System.Windows.Forms.Label label6;
    private System.Windows.Forms.TextBox TbViewportW;
    private System.Windows.Forms.Label label3;
    private System.Windows.Forms.TextBox TbViewboxW;
    private System.Windows.Forms.TextBox TbViewportH;
    private System.Windows.Forms.Label LblViewboxWH;
    private System.Windows.Forms.Label LblViewboxXY;
    private System.Windows.Forms.TextBox TbViewboxY;
    private System.Windows.Forms.Label label4;
    private System.Windows.Forms.TextBox TbViewboxX;
    private System.Windows.Forms.StatusStrip StatusStrip;
    private System.Windows.Forms.ToolStripStatusLabel ProgressLabel;
    private System.Windows.Forms.ToolStripProgressBar ProgressBar;
    private System.Windows.Forms.ToolStripStatusLabel PlaceHolderLabel;
    private System.Windows.Forms.ToolStripStatusLabel UpdateAvailLabel;
    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel9;
    private System.Windows.Forms.Button LnkUseSvgSettings;
}


================================================
FILE: SvgFileType/Import/SvgImportDialog.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using PaintDotNet;
using Svg;
using SvgFileTypePlugin.Extensions;
using SR = SvgFileTypePlugin.Localization.StringResources;

namespace SvgFileTypePlugin.Import;

internal partial class SvgImportDialog : MyBaseForm
{
    private const string NotAvailable = "-";
    private const int CanvasSizeWarningThreshold = 1280;
    private const int DefaultFallbackSize = 512;
    private object? lastModifiedNud;
    private bool dontUpdate;
    private bool isRunning;
    private readonly CancellationTokenSource cts;
    private readonly Size docSize;
    private readonly int docPpi;
    private readonly string svgdata;
    private Size rasterSize;
    private readonly Rectangle docViewbox;
    private readonly string renderer;

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Document? Result { get; private set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Exception? Error { get; private set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override bool EnableImmersiveDarkMode => true;

    public SvgImportDialog(string svgdata, string renderer = "resvg", CancellationToken ctoken = default) : base(UIHelper.GetMainForm())
    {
        ArgumentNullException.ThrowIfNull(svgdata);
        ArgumentException.ThrowIfNullOrWhiteSpace(renderer);

        InitializeComponent();
        SetUseAppThemeColors();

        this.renderer = renderer;
        this.svgdata = svgdata;
        cts = CancellationTokenSource.CreateLinkedTokenSource(ctoken);

        SvgDocument svg = SvgDocument.FromSvg<SvgDocument>(svgdata);
        docSize = svg.GetDimensions().ToSize();
        docViewbox = Rectangle.Truncate(svg.ViewBox);
        docPpi = svg.Ppi;

        PopulateContols();
        HookEvents();
    }

    protected override void OnLoad(EventArgs e)
    {
        ClientSize = RootPanel.Size;
        base.OnLoad(e);
    }

    protected override void OnClosing(CancelEventArgs e)
    {
        base.OnClosing(e);

        if (!isRunning) 
        {
            Error = new WarningException(SR.CanceledUponYourRequest);
        }
        if (!cts.IsCancellationRequested)
        {
            cts.Cancel();
        }
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        cts.Dispose();
    }

    #region Private Methods

    private void PopulateContols()
    {
        Text = $"{SvgFileTypePluginSupportInfo.Instance.DisplayName} v{SvgFileTypePluginSupportInfo.Instance.Version}";
        PbWarning.Image = SystemIcons.Warning.ToBitmap();
        GbInfo.Text = SR.SizeSettingsGivenInSvgFile;
        LnkUseSvgSettings.Text = SR.UseSizeSettingsGivenInSvg.SplitIntoLines(maximumLineLength: 60);
        GbSizeSelection.Text = SR.SizeSelectionByUser;
        LblResolution.Text = SR.Resolution;
        LblCanvasWH.Text = SR.Canvas;
        LblViewport.Text = SR.Viewport;
        LblViewboxWH.Text = SR.ViewBoxWH;
        LblViewboxXY.Text = SR.ViewBoxXY;
        CbKeepAR.Text = SR.KeepAspectRatio;
        GbLayers.Text = SR.Layers;
        RbFlatten.Text = SR.Flatten;
        RbGroups.Text = SR.Groups;
        RbAllElements.Text = SR.AllElements;
        CbOpacity.Text = SR.OpacityAsLayerProperty.SplitIntoLines(maximumLineLength: 36);
        CbHiddenLayers.Text = SR.ImportHiddenElements.SplitIntoLines(maximumLineLength: 36);
        CbGroupBoundaries.Text = SR.GroupBoundaries.SplitIntoLines(maximumLineLength: 36);
        BtnOk.Text = SR.OK;
        BtnCancel.Text = SR.Cancel;
        ProgressLabel.Text = SR.Ready;
        ToolTip1.SetToolTip(PbWarning, SR.MemoryWarningText);

        TbViewportW.Text = docSize.Width > 0 ? docSize.Width.ToString() : NotAvailable;
        TbViewportH.Text = docSize.Height > 0 ? docSize.Height.ToString() : NotAvailable;

        if (!docViewbox.IsEmpty)
        {
            TbViewboxX.Text = docViewbox.X.ToString();
            TbViewboxY.Text = docViewbox.Y.ToString();
            TbViewboxW.Text = docViewbox.Width.ToString();
            TbViewboxH.Text = docViewbox.Height.ToString();
        }
        else
        {
            TbViewboxX.Text = NotAvailable;
            TbViewboxY.Text = NotAvailable;
            TbViewboxW.Text = NotAvailable;
            TbViewboxH.Text = NotAvailable;
        }

        rasterSize = docSize.Width == 0 || docSize.Height == 0
            ? new Size(DefaultFallbackSize, DefaultFallbackSize)
            : docSize;

        if (rasterSize.Width * rasterSize.Height > CanvasSizeWarningThreshold * CanvasSizeWarningThreshold)
        {
            double ratio = rasterSize.Width / (double)rasterSize.Height;
            if (rasterSize.Width > rasterSize.Height)
            {
                NudCanvasW.Value = CanvasSizeWarningThreshold;
                NudCanvasH.Value = (int)Math.Round(CanvasSizeWarningThreshold / ratio);
            }
            else
            {
                NudCanvasH.Value = CanvasSizeWarningThreshold;
                NudCanvasW.Value = (int)Math.Round(CanvasSizeWarningThreshold * ratio);
            }
        }
        else
        {
            NudCanvasW.Value = rasterSize.Width;
            NudCanvasH.Value = rasterSize.Height;
        }

        UpdateLayersPanel();
    }

    private void HookEvents()
    {
        RbAllElements.CheckedChanged += Rb_CheckedChanged;
        RbFlatten.CheckedChanged += Rb_CheckedChanged;
        RbGroups.CheckedChanged += Rb_CheckedChanged;
        NudCanvasW.Accelerations.Add(new NumericUpDownAcceleration(3, 10));
        NudCanvasW.KeyUp += NudCanvas_KeyUp;
        NudCanvasH.Accelerations.Add(new NumericUpDownAcceleration(3, 10));
        NudCanvasH.KeyUp += NudCanvas_KeyUp;
        NudCanvasW.LostFocus += NudCanvas_LostFocus;
        NudCanvasH.LostFocus += NudCanvas_LostFocus;
        NudCanvasW.ValueChanged += NudCanvas_ValueChanged;
        NudCanvasH.ValueChanged += NudCanvas_ValueChanged;
        CbKeepAR.CheckedChanged += CbKeepAR_CheckedChanged;
        LnkUseSvgSettings.Click += LnkUseSvgSettings_Click;
        LnkGitHub.LinkClicked += LnkGitHub_LinkClicked;
        LnkForum.LinkClicked += LnkForum_LinkClicked;
        BtnOk.Click += BtnOk_Click;
        BtnCancel.Click += BtnCancel_Click;
        CancelButton = BtnCancel;
    }

    private void UpdateLayersPanel()
    {
        CbOpacity.Enabled = CbHiddenLayers.Enabled = CbGroupBoundaries.Enabled = !RbFlatten.Checked;
        CbGroupBoundaries.Enabled = RbAllElements.Checked;
        ShowCanvasSizeWarningIfNeeded();
    }

    private void ShowCanvasSizeWarningIfNeeded()
    {
        PbWarning.Visible = !RbFlatten.Checked && NudCanvasH.Value * NudCanvasW.Value > CanvasSizeWarningThreshold * CanvasSizeWarningThreshold;
    }

    private void UpdateTheOtherNud()
    {
        lastModifiedNud ??= NudCanvasW.Value > NudCanvasH.Value ? NudCanvasW : NudCanvasH;

        if (ReferenceEquals(lastModifiedNud, NudCanvasW))
        {
            decimal newHeight = CbKeepAR.Checked ? NudCanvasW.Value * rasterSize.Height / rasterSize.Width : NudCanvasH.Value;
            newHeight = Math.Clamp(newHeight, 1, Math.Min(NudCanvasH.Maximum, int.MaxValue / (NudCanvasW.Value * 4)));
            NudCanvasH.Value = newHeight;
        }
        else
        {
            decimal newWidth = CbKeepAR.Checked ? NudCanvasH.Value * rasterSize.Width / rasterSize.Height : NudCanvasW.Value;
            newWidth = Math.Clamp(newWidth, 1, Math.Min(NudCanvasW.Maximum, int.MaxValue / (NudCanvasH.Value * 4)));
            NudCanvasW.Value = newWidth;
        }
        ShowCanvasSizeWarningIfNeeded();
    }

    private SvgImportConfig GetSvgImportConfig()
    {
        SvgImportConfig config = new SvgImportConfig
        {
            RasterWidth = (int)NudCanvasW.Value,
            RasterHeight = (int)NudCanvasH.Value,
            PreserveAspectRatio = CbKeepAR.Checked,
            Ppi = (int)NudDpi.Value,
            GroupBoundariesAsLayers = CbGroupBoundaries.Checked,
            ImportHiddenElements = CbHiddenLayers.Checked,
            RespectElementOpacity = CbOpacity.Checked,
            LayersMode = RbAllElements.Checked
                ? LayersMode.All
                : RbFlatten.Checked
                ? LayersMode.Flat
                : LayersMode.Groups
        };
        return config;
    }

    private void DisableControlsExceptCancelButton()
    {
        this.Descendants().OfType<GroupBox>().ToList().ForEach(groupbox => groupbox.Enabled = false);
        BtnOk.Enabled = false;
        ProgressBar.Visible = true;
    }

    #endregion

    #region Events

    private void NudCanvas_ValueChanged(object? sender, EventArgs e)
    {
        if (dontUpdate)
        {
            return;
        }

        lastModifiedNud = sender;
        UpdateTheOtherNud();
    }

    private void CbKeepAR_CheckedChanged(object? sender, EventArgs e)
    {
        if (dontUpdate)
        {
            return;
        }

        lastModifiedNud = null;
        UpdateTheOtherNud();
    }

    private void NudCanvas_KeyUp(object? sender, KeyEventArgs e)
    {
        if (dontUpdate)
        {
            return;
        }

        lastModifiedNud = sender;
        if (e.KeyValue >= '0' || e.KeyValue <= '9' || e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back)
        {
            // Handle key events like digits, delete and backspace
            UpdateTheOtherNud();
        }
        else
        {
            // We ignore any other key event on these controls
            e.SuppressKeyPress = true;
            e.Handled = true;
        }
    }

    private void NudCanvas_LostFocus(object? sender, EventArgs e)
    {
        if (sender is not NumericUpDown nud)
        {
            return;
        }

        TextBox? textbox = nud.Controls.OfType<TextBox>().FirstOrDefault();
        if (textbox is not null)
        {
            textbox.Text = Math.Round(nud.Value, nud.DecimalPlaces).ToString();
        }
    }

    private void Rb_CheckedChanged(object? sender, EventArgs e)
    {
        UpdateLayersPanel();
    }

    private void LnkUseSvgSettings_Click(object? sender, EventArgs e)
    {
        // Restore the original sizes and show the size warning if needed
        dontUpdate = true;
        NudCanvasW.Value = rasterSize.Width;
        NudCanvasH.Value = rasterSize.Height;
        dontUpdate = false;
        NudDpi.Value = docPpi;
        ShowCanvasSizeWarningIfNeeded();
    }

    private void LnkGitHub_LinkClicked(object? sender, LinkLabelLinkClickedEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            LaunchUrl(SvgFileTypePluginSupportInfo.Instance.WebsiteUri);
        }
    }

    private void LnkForum_LinkClicked(object? sender, LinkLabelLinkClickedEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            LaunchUrl(SvgFileTypePluginSupportInfo.Instance.ForumUri);
        }
    }

    private async void BtnOk_Click(object? sender, EventArgs e)
    {
        isRunning = true;
        try
        {
            DisableControlsExceptCancelButton();
            CancellationToken ctoken = cts.Token;
            SvgImportConfig config = GetSvgImportConfig();
            SvgRenderer2 svgRenderer = SvgRenderer2.Create(renderer);
            svgRenderer.ProgressChanged += OnProgressChanged;
            Result = await Task.Run(() => svgRenderer.Rasterize(svgdata, config, ctoken), ctoken).ConfigureAwait(false);
        }
        catch (Exception ex) when (ex is OperationCanceledException)
        {
            Error = new WarningException(SR.CanceledUponYourRequest, ex);
        }
        catch (Exception ex)
        {
            Error = ex;
        }
        finally
        {
            DialogResult = Result is null ? DialogResult.Cancel : DialogResult.OK;
        }
    }

    private void OnProgressChanged(object? sender, ProgressChangedEventArgs e)
    {
        if (IsDisposed)
        {
            return;
        }

        try
        {
            if (InvokeRequired)
            {
                Invoke(OnProgressChanged, sender, e);
                return;
            }

            int total = (int)e.UserState!;
            if (e.ProgressPercentage == 0)
            {
                if (total == 1)
                {
                    ProgressBar.Style = ProgressBarStyle.Marquee;
                    ProgressLabel.Text = SR.Working;
                }
                else
                {
                    ProgressBar.Style = ProgressBarStyle.Blocks;
                    ProgressBar.Maximum = total;
                    ProgressLabel.Text = SR.Ready;
                }
            }
            if (total > 1)
            {
                ProgressBar.Value = e.ProgressPercentage;
                float percentage = e.ProgressPercentage / (float)total;
                ProgressLabel.Text = percentage.ToString("P2");
            }
        }
        catch (ObjectDisposedException)
        {
            // ignore
        }
    }

    private void BtnCancel_Click(object? sender, EventArgs e)
    {
        BtnCancel.Enabled = false;
        try
        {
            cts.Cancel();
        }
        catch (ObjectDisposedException)
        {
            // This should never happen
        }
        finally
        {
            Error = new WarningException(SR.CanceledUponYourRequest);
        }
    }

    #endregion

    #region Static

    private static void LaunchUrl(Uri uri)
    {
        Process.Start("explorer", $@"""{uri}""");
    }

    #endregion
}


================================================
FILE: SvgFileType/Import/SvgImportDialog.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--
    Microsoft ResX Schema

    Version 2.0

    The primary goals of this format is to allow a simple XML format
    that is mostly human readable. The generation and parsing of the
    various data types are done through the TypeConverter classes
    associated with the data types.

    Example:

    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>

    There are any number of "resheader" rows that contain simple
    name/value pairs.

    Each data row contains a name, and value. The row also contains a
    type or mimetype. Type corresponds to a .NET class that support
    text/value conversion through the TypeConverter architecture.
    Classes that don't support this are serialized and stored with the
    mimetype set.

    The mimetype is used for serialized objects, and tells the
    ResXResourceReader how to depersist the object. This is currently not
    extensible. For a given mimetype the value must be set accordingly:

    Note - application/x-microsoft.net.object.binary.base64 is the format
    that the ResXResourceWriter will generate, however the reader can
    read any of the formats listed below.

    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.

    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.

    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <metadata name="ToolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>17, 17</value>
  </metadata>
  <metadata name="PbWarning.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="CbGroupBoundaries.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="RootPanel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="StatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>115, 17</value>
  </metadata>
  <metadata name="StatusStrip.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="tableLayoutPanel3.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LnkGitHub.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LnkForum.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="BtnOk.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="BtnCancel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="GbLayers.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="tableLayoutPanel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="RbFlatten.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="RbGroups.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="CbHiddenLayers.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="RbAllElements.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="CbOpacity.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="GbSizeSelection.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="CbKeepAR.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="tableLayoutPanel4.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LblResolution.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LblCanvasWH.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="NudCanvasW.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="NudCanvasH.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="label9.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="NudDpi.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="GbInfo.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="tableLayoutPanel9.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LnkUseSvgSettings.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="tableLayoutPanel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LblViewport.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewboxH.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="label6.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewportW.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="label3.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewboxW.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewportH.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LblViewboxWH.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="LblViewboxXY.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewboxY.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="label4.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
  <metadata name="TbViewboxX.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <value>True</value>
  </metadata>
</root>

================================================
FILE: SvgFileType/Import/SvgRenderer2.cs
================================================
// Copyright 2025 Osman Tunçelli. All rights reserved.
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.

using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime;
using System.Threading;
using PaintDotNet;
using Svg;
using SvgFileTypePlugin.Extensions;
using SR = SvgFileTypePlugin.Localization.StringResources;

namespace SvgFileTypePlugin.Import;

internal abstract class SvgRenderer2(string name)
{
    private static readonly FrozenSet<string> TitleAttributes = ["label", "title", "inkscape:label"];
    private int step, total;

    public string Name { get; } = name;

    public event ProgressChangedEventHandler? ProgressChanged;

    #region Public

    public Document Rasterize(string svgdata, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentNullException.ThrowIfNull(config);

        Logger.WriteLine($"Using '{Name}' renderer with '{config.LayersMode}' layers mode.");
        return config.LayersMode == LayersMode.Flat
            ? GetFlatDocument(svgdata, config, ctoken)
            : GetLayeredDocument(svgdata, config, ctoken);
    }

    #endregion

    #region Public Static

    public static SvgRenderer2 Create(string name)
    {
        ArgumentNullException.ThrowIfNull(name);

        return name.ToLowerInvariant() switch
        {
            "resvg" => new ResvgSvgRenderer(),
            "gdip" or "gdiplus" or "gdi+" => new GdipSvgRenderer(),
            "direct2d" or "d2d" => new Direct2DSvgRenderer(),
            _ => throw new ArgumentOutOfRangeException(nameof(name), $"Unknown SVG renderer: {name}")
        };
    }

    #endregion

    #region Protected

    protected abstract Document GetFlatDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default);

    protected abstract Document GetLayeredDocument(string svgdata, SvgImportConfig config, CancellationToken ctoken = default);

    public virtual Document GetNoPathDocument()
    {
        Graphics g;
        Size size;
        using Font font = new Font("Arial", 24, FontStyle.Bold);
        using (g = Graphics.FromHwnd(nint.Zero))
        {
            size = g.MeasureString(SR.NoPath, font).ToSize();
        }
        using Bitmap bmp = new Bitmap(size.Width, size.Height, PixelFormat.Format24bppRgb);
        g = Graphics.FromImage(bmp);
        using var _ = g;
        g.Clear(Color.LightGray);
        Rectangle layoutRectangle = new Rectangle(Point.Empty, bmp.Size);
        using StringFormat format = new StringFormat()
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Center
        };
        g.DrawString(SR.NoPath, font, Brushes.Black, layoutRectangle, format);
        return Document.FromImage(bmp);
    }

    protected void IncrementProgress()
    {
        if (ProgressChanged is null)
        {
            return;
        }

        int value = Interlocked.Increment(ref step);
        value = Math.Clamp(value, 0, total);
        ProgressChangedEventArgs args = new ProgressChangedEventArgs(value, total);
        ProgressChanged.Invoke(this, args);
    }

    /// <exception cref="ArgumentOutOfRangeException"></exception>
    protected void ResetProgress(int total)
    {
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(total);

        if (ProgressChanged is null)
        {
            return;
        }

        this.total = total;
        int value = Interlocked.Exchange(ref step, 0);
        ProgressChangedEventArgs args = new ProgressChangedEventArgs(value, total);
        ProgressChanged.Invoke(this, args);
    }

    #endregion

    #region Protected Static

    /// <exception cref="ArgumentNullException"></exception>
    protected static List<SvgVisualElement> GetSvgVisualElements(SvgDocument svg, SvgImportConfig config, CancellationToken ctoken = default)
    {
        ArgumentNullException.ThrowIfNull(svg);
        ArgumentNullException.ThrowIfNull(config);

        IEnumerable<SvgVisualElement> elements = GetPreparedElements(svg.Children, ctoken);

        if (config.LayersMode == LayersMode.Groups)
        {
            elements = FilterByGroups(elements, ctoken);
        }
        else
        {
            elements = FilterByNonGroups(elements);
        }

        if (config.LayersMode == LayersMode.Flat || !config.GroupBoundariesAsLayers)
        {
            elements = elements.NotOfType<GroupBoundary>();
        }

        if (config.LayersMode != LayersMode.Flat)
        {
            // Skip group boundaries for hidden layers.
            elements = elements.Where(e => config.ImportHiddenElements || (e is GroupBoundary groupBoundary
                ? groupBoundary.IsOriginallyVisible
                : e.IsOriginallyVisible()));
        }

        return elements.ToList();
    }

    /// <exception cref="ArgumentNullException"></exception>
    protected static string GetLayerTitle(SvgElement element, bool prependElementName = true)
    {
        ArgumentNullException.ThrowIfNull(element);

        string elementName = element.GetName();
        string? layerName = null;

        if (element.ID is not null)
        {
            layerName = element.ID;
        }

        if (string.IsNullOrEmpty(layerName) && element.CustomAttributes != null)
        {
            // get custom title attributes.
            foreach (string attr in TitleAttributes)
            {
                if (element.CustomAttributes.TryGetValue(attr, out string? title) && !string.IsNullOrEmpty(title))
                {
                    // found a title candidate
                    layerName = title;
                    break;
                }
            }
        }

        if (string.IsNullOrEmpty(layerName) && element.Children != null)
        {
            // Get child title tag
            SvgTitle? title = element.Children.OfType<SvgTitle>().FirstOrDefault();
            if (!string.IsNullOrEmpty(title?.Content))
            {
                layerName = title.Content;
            }
        }

        if (string.IsNullOrEmpty(layerName))
        {
            // Generate more meanfull name for a svg use node. Add reference element name in a case if it's local document.
            if (element is SvgUse useElement and { ReferencedElement.OriginalString.Length: > 1 })
            {
                string str = useElement.ReferencedElement.OriginalString.Trim();
                if (str.StartsWith('#'))
                {
                    layerName = str[1..];
                }
                prependElementName = true;
            }
            // Generate more meanfull name for a svg text.
            else if (element is SvgTextBase text and { Text.Length: > 0})
            {
                layerName = text.Text.Truncate(maxLength: 32);
            }
            // Generate more meanfull name for a svg path.
            else if (element is SvgPath path and { PathData.Count: > 0 })
            {
                layerName = path.PathData.ToString().Truncate(maxLength: 32);
            }
        }

        return layerName is null
            ? elementName
            : prependElementName
            ? $"{elementName}: {layerName}"
            : layerName;
    }

    /// <summary>
    /// Generates a Paint.NET document with given layers and configuration.
    /// </summary>
    /// <param name="layers"></param>
    /// <param name="config"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentException"></exception>
    protected static Document GetDocument(List<BitmapLayer> layers, SvgImportConfig config)
    {
        ArgumentNullException.ThrowIfNull(layers);
        ArgumentNullException.ThrowIfNull(config);
        if (layers.Count == 0)
        {
            throw new ArgumentException("There aren't any layers in the collection.", nameof(layers));
        }

        Debug.Assert(layers[0].Width == config.RasterWidth);
        Debug.Assert(layers[0].Height == config.RasterHeight);

        Document document = new Document(config.RasterWidth, config.RasterHeight);
        try
        {
            layers.ForEach(document.Layers.Add);
            document.SetDpu(config.Ppi);
            return document;
        }
        catch (Exception)
        {
            document.Dispose();
            layers.ForEach(layer => layer.Dispose());
            throw;
        }
    }

    /// <exception cref="ArgumentOutOfRangeException"></exception>
    protected static void RenderSvgUseElement(SvgUse useElement, Action<SvgElement> renderAction)
    {
        ArgumentNullException.ThrowIfNull(useElement);
        ArgumentNullException.ThrowIfNull(renderAction);

        if (useElement.GetCopyOfReferencedElement() is not SvgElement referencedElement)
        {
            return;
        }
        referencedElement.Visibility = "visible";
        useElement.Visibility = "hidden";
        SvgElementCollection children = useElement.Parent.Children;
        children.AddAndForceUniqueID(referencedElement);
        try
        {
            renderAction(referencedElement);
        }
        finally
        {
            children.Remove(referencedElement);
        }
    }

    /// <exception cref="ArgumentOutOfRangeException"></exception>
    protected static byte ToByteOpacity(float opacity)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(opacity);
        ArgumentOutOfRangeException.ThrowIfGreaterThan(opacity, 1f);

        int value = (int)MathF.Round(opacity * 255f);
        value = Math.Clamp(value, byte.MinValue, byte.MaxValue);
        return (byte)value;
    }

    /// <exception cref="ArgumentOutOfRangeException"></exception>
    /// <exception cref="InsufficientMemoryException"></exception>
    /// <exception cref="OverflowException"></exception>
    protected static MemoryFailPoint GetMemoryFailPoint(int width, int height, int count = 1)
    {
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(width);
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(height);
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count);

        int sizeInMegabytes = checked((int)(height * 4L * width * count / (1024 * 1024)));
        sizeInMegabytes = Math.Max(sizeInMegabytes, 1);
        return new MemoryFailPoint(sizeInMegabytes);
    }

    #endregion

    #region Private Static

    private static IEnumerable<SvgVisualElement> GetPreparedElements(IEnumerable<SvgElement> elements, CancellationToken ctoken = default)
    {
        return GetPreparedElements(elements, groupName: null, ctoken);
    }

    private static IEnumerable<SvgVisualElement> GetPreparedElements(IEnumerable<SvgElement> elements, string? groupName, CancellationToken ctoken = default)
    {
        // Prepare a collection of elements that about to be rendered. 
        // Don't prepare for a separate parsing def lists.
        foreach (SvgVisualElement visual in elements.OfType<SvgVisualElement>())
        {
            ctoken.ThrowIfCancellationRequested();

            // Fix problem that SVG visual element lib style "display:none" is not recognized as visible state.
            if (visual.Visible && !visual.IsDisplayable())
            {
                visual.Visibility = "hidden";
                visual.Display = string.Empty; // null throws exception
            }

            // Store visibility
            visual.StoreOriginalVisibility();

            // Save current group to indicate that elements inside a group.
            if (!string.IsNullOrEmpty(groupName))
            {
                visual.SetGroupName(groupName); // Store group info
            }

            SvgGroup? group = visual as SvgGroup;
            if (group is not null)
            {
                groupName = GetLayerTitle(group, prependElementName: false);

                // Return fake node to indicate group end. (order is reversed)
                yield return new GroupBoundary(group, groupName, isStart: false);
            }

            if (GetPreparedElements(visual.Children, groupName, ctoken) is IEnumerable<SvgVisualElement> preparedElements)
            {
                foreach (SvgVisualElement element in preparedElements)
                {
                    yield return element;
                }
            }

            if (group is not null)
            {
                Debug.Assert(groupName is not null);

                // Return fake node to indicate group start.
                yield return new GroupBoundary(group, groupName, isStart: true);
            }

            // Skip text with empty content. But keep all children nodes.
            if (visual is SvgTextBase textNode and { Text.Length: > 0 })
            {
                continue;
            }

            yield return visual;
        }
    }

    private static IEnumerable<SvgVisualElement> FilterByNonGroups(IEnumerable<SvgVisualElement> elements)
    {
        return elements.NotOfType<SvgGroup>();
    }

    private static IEnumerable<SvgVisualElement> FilterByGroups(IEnumerable<SvgVisualElement> elements, CancellationToken ctoken = default)
    {
        HashSet<SvgVisualElement> groups = [];
        foreach (SvgVisualElement element in elements.NotOfType<GroupBoundary>())
        {
            ctoken.ThrowIfCancellationRequested();

            SvgVisualElement? visual = null;
            if (element.GetGroupName() is not null)
            {
                // Get only root level
                for (SvgElement parent = element; parent is not null; parent = parent.Parent)
                {
                    // TODO: render more groups. In most cases svg has only few root groups.
                    if (parent is SvgGroup group)
                    {
                        visual = group;
                    }
                }
            }

            visual ??= element;
            if (groups.Add(visual))
            {
                yield return visual;
            }
        }
    }

    #endregion

    #region GroupBoundary

    /* a private type to determine boundaries of a group. */
    protected sealed class GroupBoundary(SvgGroup group, string name, bool isStart) : SvgVisualElement
    {
        private readonly SvgGroup group = group;

        public override bool Visible => group.Visible;

        public override float Opacity => group.Opacity;

        public bool IsOriginallyVisible => group.IsOriginallyVisible();

        public string Name { get; } = string.Format(isStart ? SR.LayerGroup : SR.EndLayerGroup, name);

        public override RectangleF Bounds => throw new NotImplementedException();

        public override SvgElement DeepCopy()
        {
            throw new NotImplementedException();
        }

        public override GraphicsPath Path(ISvgRenderer renderer)
        {
            throw new NotImplementedException();
        }

        public BitmapLayer ToEmptyLayer(int width, int height)
        {
            // Render empty group boundary and continue
            BitmapLayer layer = new BitmapLayer(width, height)
            {
               
Download .txt
gitextract_t5vkdpxu/

├── .gitattributes
├── .gitignore
├── .gitmodules
├── COPYING
├── README.md
├── SvgFileType/
│   ├── BenchmarkScope.cs
│   ├── Export/
│   │   ├── PreviewMode.cs
│   │   ├── PropertyNames.cs
│   │   ├── ScanMode.cs
│   │   └── SvgExport.cs
│   ├── Extensions/
│   │   ├── ControlExtensions.cs
│   │   ├── DocumentExtensions.cs
│   │   ├── StringExtensions.cs
│   │   ├── SurfaceExtensions.cs
│   │   ├── SvgDocumentExtensions.cs
│   │   ├── SvgElementExtensions.cs
│   │   ├── SvgUnitExtensions.cs
│   │   ├── SvgUseExtensions.cs
│   │   ├── SvgViewBoxExtensions.cs
│   │   └── SvgVisualElementExtensions.cs
│   ├── FodyWeavers.xml
│   ├── FodyWeavers.xsd
│   ├── Import/
│   │   ├── Direct2DSvgRenderer.cs
│   │   ├── GdipSvgRenderer.cs
│   │   ├── LayersMode.cs
│   │   ├── MyBaseForm.cs
│   │   ├── MyBaseForm.resx
│   │   ├── ResvgSvgRenderer.cs
│   │   ├── StreamTrackerCancellationTokenSource.cs
│   │   ├── SvgImport.cs
│   │   ├── SvgImportConfig.cs
│   │   ├── SvgImportDialog.Designer.cs
│   │   ├── SvgImportDialog.cs
│   │   ├── SvgImportDialog.resx
│   │   └── SvgRenderer2.cs
│   ├── Localization/
│   │   ├── InjectResourceManager.ps1
│   │   ├── Localize.cs
│   │   ├── SingleAssemblyResourceManager.cs
│   │   ├── StringResources.Designer.cs
│   │   ├── StringResources.resx
│   │   ├── StringResources_de.resx
│   │   ├── StringResources_fr.resx
│   │   ├── StringResources_ru.resx
│   │   └── StringResources_tr.resx
│   ├── Logger.cs
│   ├── Services.cs
│   ├── SvgFileType.cs
│   ├── SvgFileTypeFactory.cs
│   ├── SvgFileTypePlugin.csproj
│   ├── SvgFileTypePluginSupportInfo.cs
│   └── UIHelper.cs
├── SvgFileType.ThirdPartyNotices.txt
└── SvgFileType.sln
Download .txt
SYMBOL INDEX (223 symbols across 35 files)

FILE: SvgFileType/BenchmarkScope.cs
  type BenchmarkScope (line 11) | internal struct BenchmarkScope : IDisposable
    method BenchmarkScope (line 17) | public BenchmarkScope(string? name) : this()
    method BenchmarkScope (line 22) | public BenchmarkScope()
    method Dispose (line 27) | public void Dispose()

FILE: SvgFileType/Export/PreviewMode.cs
  type PreviewMode (line 6) | internal enum PreviewMode

FILE: SvgFileType/Export/PropertyNames.cs
  type PropertyNames (line 6) | internal enum PropertyNames

FILE: SvgFileType/Export/ScanMode.cs
  type ScanMode (line 6) | internal enum ScanMode

FILE: SvgFileType/Export/SvgExport.cs
  class SvgExport (line 21) | internal static partial class SvgExport
    method ShowSaveShapeDialog (line 41) | public static string? ShowSaveShapeDialog()
    method ThrowIfOverflow (line 58) | private static T ThrowIfOverflow<T>(Func<T> action, string message)
    method Export (line 70) | public static void Export(Surface input, Stream output, PropertyCollec...
    method Export (line 256) | public static void Export(Document input, Stream output, PropertyBased...
    method ConvertProgressValue (line 269) | private static float ConvertProgressValue(ProgressArgs args)

FILE: SvgFileType/Extensions/ControlExtensions.cs
  class ControlExtensions (line 10) | internal static class ControlExtensions
    method Descendants (line 12) | public static IEnumerable<Control> Descendants(this Control root)
    method RunOnUIThread (line 29) | public static object? RunOnUIThread<T>(this Control control, T action,...
    method RunOnUIThread (line 36) | public static object? RunOnUIThread<T>(this Control control, T action)...

FILE: SvgFileType/Extensions/DocumentExtensions.cs
  class DocumentExtensions (line 9) | internal static class DocumentExtensions
    method SetDpu (line 11) | public static void SetDpu(this Document doc, double dpuX, double dpuY,...
    method SetDpu (line 20) | public static void SetDpu(this Document doc, double dpu, MeasurementUn...

FILE: SvgFileType/Extensions/StringExtensions.cs
  class StringExtensions (line 9) | internal static class StringExtensions
    method Truncate (line 11) | public static string Truncate(this string s, int maxLength, string suf...
    method SplitIntoLines (line 19) | public static string SplitIntoLines(this string s, int maximumLineLength)

FILE: SvgFileType/Extensions/SurfaceExtensions.cs
  class SurfaceExtensions (line 11) | internal static class SurfaceExtensions
    method CreateSingleLayerDocument (line 13) | public static Document CreateSingleLayerDocument(this Surface surface,...
    method IsEmpty (line 31) | public static unsafe bool IsEmpty(this Surface surface)
    method BlendOnto (line 150) | public static void BlendOnto<T>(this Surface surface, ColorBgra backgr...

FILE: SvgFileType/Extensions/SvgDocumentExtensions.cs
  class SvgDocumentExtensions (line 11) | internal static class SvgDocumentExtensions
    method RemoveInvisibleAndNonTextElements (line 13) | public static SvgDocument RemoveInvisibleAndNonTextElements(this SvgDo...
    method UseSetRasterDimensions (line 24) | public static IDisposable UseSetRasterDimensions(this SvgDocument svg,...
    class DisposableAction (line 53) | private sealed class DisposableAction : IDisposable
      method DisposableAction (line 57) | public DisposableAction(Action dispose)
      method Dispose (line 64) | public void Dispose()

FILE: SvgFileType/Extensions/SvgElementExtensions.cs
  class SvgElementExtensions (line 14) | internal static class SvgElementExtensions
    method GetName (line 23) | public static string GetName(this SvgElement element)
    method GetAttributes (line 32) | public static SvgAttributeCollection GetAttributes(this SvgElement ele...
    method RemoveInvisibleAndNonTextElements (line 39) | public static void RemoveInvisibleAndNonTextElements(this SvgElement e...
    method GetXML_QuotedFuncIRIHack (line 57) | public static string GetXML_QuotedFuncIRIHack(this SvgElement svg)
    method WriteXML_QuotedFuncIRIHack (line 71) | public static void WriteXML_QuotedFuncIRIHack(this SvgElement svg, Str...
    method CreateGetterDelegate (line 84) | private static T CreateGetterDelegate<T>(string propertyName) where T ...
    class InvariantUtf8StreamWriter (line 95) | private sealed class InvariantUtf8StreamWriter(Stream stream) : Stream...
      method Dispose (line 102) | protected override void Dispose(bool disposing)
    class InvariantUtf8StringWriter (line 116) | private sealed class InvariantUtf8StringWriter() : StringWriter(Cultur...
    class CustomXmlWriter (line 127) | private sealed class CustomXmlWriter(XmlWriter writer) : XmlWriter
      method Flush (line 131) | public override void Flush() => writer.Flush();
      method LookupPrefix (line 132) | public override string? LookupPrefix(string ns) => writer.LookupPref...
      method WriteBase64 (line 133) | public override void WriteBase64(byte[] buffer, int index, int count...
      method WriteCData (line 134) | public override void WriteCData(string? text) => writer.WriteCData(t...
      method WriteCharEntity (line 135) | public override void WriteCharEntity(char ch) => writer.WriteCharEnt...
      method WriteChars (line 136) | public override void WriteChars(char[] buffer, int index, int count)...
      method WriteComment (line 137) | public override void WriteComment(string? text) => writer.WriteComme...
      method WriteDocType (line 138) | public override void WriteDocType(string name, string? pubid, string...
      method WriteEndAttribute (line 139) | public override void WriteEndAttribute() => writer.WriteEndAttribute();
      method WriteEndDocument (line 140) | public override void WriteEndDocument() => writer.WriteEndDocument();
      method WriteEndElement (line 141) | public override void WriteEndElement() => writer.WriteEndElement();
      method WriteEntityRef (line 142) | public override void WriteEntityRef(string name) => writer.WriteEnti...
      method WriteFullEndElement (line 143) | public override void WriteFullEndElement() => writer.WriteFullEndEle...
      method WriteProcessingInstruction (line 144) | public override void WriteProcessingInstruction(string name, string?...
      method WriteRaw (line 145) | public override void WriteRaw(char[] buffer, int index, int count) =...
      method WriteRaw (line 146) | public override void WriteRaw(string data) => writer.WriteRaw(data);
      method WriteStartAttribute (line 147) | public override void WriteStartAttribute(string? prefix, string loca...
      method WriteStartDocument (line 148) | public override void WriteStartDocument() => writer.WriteStartDocume...
      method WriteStartDocument (line 149) | public override void WriteStartDocument(bool standalone) => writer.W...
      method WriteStartElement (line 150) | public override void WriteStartElement(string? prefix, string localN...
      method WriteString (line 151) | public override void WriteString(string? text)
      method WriteSurrogateCharEntity (line 155) | public override void WriteSurrogateCharEntity(char lowChar, char hig...
      method WriteWhitespace (line 156) | public override void WriteWhitespace(string? ws) => writer.WriteWhit...

FILE: SvgFileType/Extensions/SvgUnitExtensions.cs
  class SvgUnitExtensions (line 9) | internal static class SvgUnitExtensions
    method ToDeviceValue (line 11) | public static int ToDeviceValue(this SvgUnit unit, SvgElement owner, U...

FILE: SvgFileType/Extensions/SvgUseExtensions.cs
  class SvgUseExtensions (line 11) | internal static class SvgUseExtensions
    method GetCopyOfReferencedElement (line 13) | public static SvgElement? GetCopyOfReferencedElement(this SvgUse useEl...
    method CopyOverridedAttributes (line 45) | private static void CopyOverridedAttributes(this SvgUse useElement, Sv...

FILE: SvgFileType/Extensions/SvgViewBoxExtensions.cs
  class SvgViewBoxExtensions (line 8) | internal static class SvgViewBoxExtensions
    method IsEmpty (line 10) | public static bool IsEmpty(this SvgViewBox vb)

FILE: SvgFileType/Extensions/SvgVisualElementExtensions.cs
  class SvgVisualElementExtensions (line 12) | internal static class SvgVisualElementExtensions
    method IsOriginallyVisible (line 18) | public static bool IsOriginallyVisible(this SvgVisualElement element)
    method StoreOriginalVisibility (line 26) | public static void StoreOriginalVisibility(this SvgVisualElement element)
    method GetGroupName (line 47) | public static string? GetGroupName(this SvgVisualElement element)
    method SetGroupName (line 54) | public static void SetGroupName(this SvgVisualElement element, string?...
    method NotOfType (line 78) | public static IEnumerable<SvgVisualElement> NotOfType<TElement>(this I...
    method IsDisplayable (line 86) | public static bool IsDisplayable(this SvgVisualElement element)
    method PreRender (line 93) | public static bool PreRender(this SvgVisualElement element, IReadOnlyC...

FILE: SvgFileType/Import/Direct2DSvgRenderer.cs
  class Direct2DSvgRenderer (line 23) | internal sealed class Direct2DSvgRenderer() : SvgRenderer2(name: "Direct...
    method GetFlatDocument (line 25) | protected override Document GetFlatDocument(string svgdata, SvgImportC...
    method GetLayeredDocument (line 63) | protected override Document GetLayeredDocument(string svgdata, SvgImpo...
    method GetNoPathDocument (line 139) | public override Document GetNoPathDocument()
    method RenderSvgDocument (line 174) | private void RenderSvgDocument(SvgElement element, IDeviceContext dc)
    method CalculateTransform (line 192) | private static Matrix3x2Float CalculateTransform(SizeF svgsize, SvgImp...

FILE: SvgFileType/Import/GdipSvgRenderer.cs
  class GdipSvgRenderer (line 15) | internal sealed class GdipSvgRenderer() : SvgRenderer2(name: "GDI+")
    method GetFlatDocument (line 17) | protected override Document GetFlatDocument(string svgdata, SvgImportC...
    method GetLayeredDocument (line 53) | protected override Document GetLayeredDocument(string svgdata, SvgImpo...
    method RenderSvgDocument (line 125) | private void RenderSvgDocument(SvgElement element, Graphics graphics, ...

FILE: SvgFileType/Import/LayersMode.cs
  type LayersMode (line 6) | internal enum LayersMode

FILE: SvgFileType/Import/MyBaseForm.cs
  class MyBaseForm (line 15) | internal partial class MyBaseForm : Form
    method MyBaseForm (line 29) | protected MyBaseForm(Form? owner)
    method MyBaseForm (line 39) | protected MyBaseForm() : this(null)
    method SetUseAppThemeColors (line 47) | public void SetUseAppThemeColors(bool enable = true)
    method UpdateControlColorsRecursive (line 67) | private void UpdateControlColorsRecursive()
    method DrawBackground (line 132) | private static void DrawBackground(Graphics g, Color backColor, Rectan...
    method Control_HandleCreated (line 140) | private static void Control_HandleCreated(object? sender, EventArgs e)
    method SubscribeOnPaint (line 151) | private static void SubscribeOnPaint(Control control, PaintEventHandle...
    method GroupBox_Paint (line 158) | private static void GroupBox_Paint(object? sender, PaintEventArgs e)
    method Label_Paint (line 172) | private static void Label_Paint(object? sender, PaintEventArgs e)
    method CheckRadio_Paint (line 186) | private static void CheckRadio_Paint(object? sender, PaintEventArgs e)
    method ConvertAlignment (line 211) | public static TextFormatFlags ConvertAlignment(ContentAlignment alignm...
    class Native (line 240) | [SuppressUnmanagedCodeSecurity]
      method GetDeviceCaps (line 245) | [LibraryImport("gdi32.dll", SetLastError = true)]
      method GetScalingFactor (line 248) | public static float GetScalingFactor()
      method ControlSetDarkMode (line 271) | public static bool ControlSetDarkMode(IWin32Window window, bool enable)
      method UseImmersiveDarkModeColors (line 281) | public static bool UseImmersiveDarkModeColors(IWin32Window window, b...
      method SetPreferredAppMode (line 296) | public static bool SetPreferredAppMode(bool dark)
      method UseImmersiveDarkMode (line 306) | public static bool UseImmersiveDarkMode(IWin32Window window, bool en...
      method Check (line 320) | private static bool Check(int error)
      method IsWindows10OrGreater (line 325) | private static bool IsWindows10OrGreater(int build = -1)
      method SetWindowTheme (line 331) | [LibraryImport("uxtheme.dll", SetLastError = true, StringMarshalling...
      method AllowDarkModeForWindow (line 334) | [LibraryImport("uxtheme.dll", EntryPoint = "#133", SetLastError = tr...
      method SetPreferredAppMode (line 338) | [LibraryImport("uxtheme.dll", EntryPoint = "#135", SetLastError = tr...
      method SetWindowCompositionAttribute (line 341) | [LibraryImport("user32.dll", SetLastError = true)]
      method DwmSetWindowAttribute (line 345) | [LibraryImport("dwmapi.dll", SetLastError = true)]
      type WindowCompositionAttribute (line 348) | private enum WindowCompositionAttribute
      type WindowCompositionAttributeData (line 354) | [StructLayout(LayoutKind.Sequential)]

FILE: SvgFileType/Import/ResvgSvgRenderer.cs
  class ResvgSvgRenderer (line 16) | internal sealed class ResvgSvgRenderer() : SvgRenderer2("resvg")
    method GetFlatDocument (line 18) | protected override Document GetFlatDocument(string svgdata, SvgImportC...
    method GetLayeredDocument (line 47) | protected override Document GetLayeredDocument(string svgdata, SvgImpo...
    method RenderSvgDocument (line 122) | private void RenderSvgDocument(SvgElement element, Surface surface, Re...
    method CalculateTransform (line 137) | private static ResvgTransform CalculateTransform(SizeF svgsize, SvgImp...

FILE: SvgFileType/Import/StreamTrackerCancellationTokenSource.cs
  class StreamTrackerCancellationTokenSource (line 17) | internal sealed class StreamTrackerCancellationTokenSource : Cancellatio...
    method StreamTrackerCancellationTokenSource (line 23) | public StreamTrackerCancellationTokenSource(Stream stream, int period ...
    method Dispose (line 37) | protected override void Dispose(bool disposing)
    method OnTimer (line 47) | private void OnTimer(object? state)
    method IsStreamCanceled (line 63) | private static bool IsStreamCanceled(Stream stream)

FILE: SvgFileType/Import/SvgImport.cs
  class SvgImport (line 16) | internal static class SvgImport
    method Load (line 18) | public static Document Load(Stream stream)
    method Open (line 65) | private static string Open(Stream input)

FILE: SvgFileType/Import/SvgImportConfig.cs
  class SvgImportConfig (line 6) | internal sealed class SvgImportConfig

FILE: SvgFileType/Import/SvgImportDialog.Designer.cs
  class SvgImportDialog (line 3) | partial class SvgImportDialog
    method Dispose (line 14) | protected override void Dispose(bool disposing)
    method InitializeComponent (line 29) | private void InitializeComponent()

FILE: SvgFileType/Import/SvgImportDialog.cs
  method SvgImportDialog (line 44) | public SvgImportDialog(string svgdata, string renderer = "resvg", Cancel...
  method OnLoad (line 65) | protected override void OnLoad(EventArgs e)
  method OnClosing (line 71) | protected override void OnClosing(CancelEventArgs e)
  method OnClosed (line 85) | protected override void OnClosed(EventArgs e)
  method PopulateContols (line 93) | private void PopulateContols()
  method HookEvents (line 163) | private void HookEvents()
  method UpdateLayersPanel (line 185) | private void UpdateLayersPanel()
  method ShowCanvasSizeWarningIfNeeded (line 192) | private void ShowCanvasSizeWarningIfNeeded()
  method UpdateTheOtherNud (line 197) | private void UpdateTheOtherNud()
  method GetSvgImportConfig (line 216) | private SvgImportConfig GetSvgImportConfig()
  method DisableControlsExceptCancelButton (line 236) | private void DisableControlsExceptCancelButton()
  method NudCanvas_ValueChanged (line 247) | private void NudCanvas_ValueChanged(object? sender, EventArgs e)
  method CbKeepAR_CheckedChanged (line 258) | private void CbKeepAR_CheckedChanged(object? sender, EventArgs e)
  method NudCanvas_KeyUp (line 269) | private void NudCanvas_KeyUp(object? sender, KeyEventArgs e)
  method NudCanvas_LostFocus (line 290) | private void NudCanvas_LostFocus(object? sender, EventArgs e)
  method Rb_CheckedChanged (line 304) | private void Rb_CheckedChanged(object? sender, EventArgs e)
  method LnkUseSvgSettings_Click (line 309) | private void LnkUseSvgSettings_Click(object? sender, EventArgs e)
  method LnkGitHub_LinkClicked (line 320) | private void LnkGitHub_LinkClicked(object? sender, LinkLabelLinkClickedE...
  method LnkForum_LinkClicked (line 328) | private void LnkForum_LinkClicked(object? sender, LinkLabelLinkClickedEv...
  method BtnOk_Click (line 336) | private async void BtnOk_Click(object? sender, EventArgs e)
  method OnProgressChanged (line 362) | private void OnProgressChanged(object? sender, ProgressChangedEventArgs e)
  method BtnCancel_Click (line 405) | private void BtnCancel_Click(object? sender, EventArgs e)

FILE: SvgFileType/Import/SvgRenderer2.cs
  class SvgRenderer2 (line 22) | internal abstract class SvgRenderer2(string name)
    method Rasterize (line 33) | public Document Rasterize(string svgdata, SvgImportConfig config, Canc...
    method Create (line 47) | public static SvgRenderer2 Create(string name)
    method GetFlatDocument (line 64) | protected abstract Document GetFlatDocument(string svgdata, SvgImportC...
    method GetLayeredDocument (line 66) | protected abstract Document GetLayeredDocument(string svgdata, SvgImpo...
    method GetNoPathDocument (line 68) | public virtual Document GetNoPathDocument()
    method IncrementProgress (line 91) | protected void IncrementProgress()
    method ResetProgress (line 105) | protected void ResetProgress(int total)
    method GetSvgVisualElements (line 125) | protected static List<SvgVisualElement> GetSvgVisualElements(SvgDocume...
    method GetLayerTitle (line 158) | protected static string GetLayerTitle(SvgElement element, bool prepend...
    method GetDocument (line 233) | protected static Document GetDocument(List<BitmapLayer> layers, SvgImp...
    method RenderSvgUseElement (line 261) | protected static void RenderSvgUseElement(SvgUse useElement, Action<Sv...
    method ToByteOpacity (line 285) | protected static byte ToByteOpacity(float opacity)
    method GetMemoryFailPoint (line 298) | protected static MemoryFailPoint GetMemoryFailPoint(int width, int hei...
    method GetPreparedElements (line 313) | private static IEnumerable<SvgVisualElement> GetPreparedElements(IEnum...
    method GetPreparedElements (line 318) | private static IEnumerable<SvgVisualElement> GetPreparedElements(IEnum...
    method FilterByNonGroups (line 377) | private static IEnumerable<SvgVisualElement> FilterByNonGroups(IEnumer...
    method FilterByGroups (line 382) | private static IEnumerable<SvgVisualElement> FilterByGroups(IEnumerabl...
    class GroupBoundary (line 416) | protected sealed class GroupBoundary(SvgGroup group, string name, bool...
      method DeepCopy (line 430) | public override SvgElement DeepCopy()
      method Path (line 435) | public override GraphicsPath Path(ISvgRenderer renderer)
      method ToEmptyLayer (line 440) | public BitmapLayer ToEmptyLayer(int width, int height)

FILE: SvgFileType/Localization/Localize.cs
  class Localize (line 10) | internal static partial class Localize
    method GetDisplayName (line 12) | public static string GetDisplayName<TEnum>(TEnum @enum) where TEnum : ...
    method SplitCamelCase (line 19) | private static string SplitCamelCase(string str)
    method CamelCaseRegex (line 24) | [GeneratedRegex("(\\B[A-Z])")]

FILE: SvgFileType/Localization/SingleAssemblyResourceManager.cs
  class SingleAssemblyResourceManager (line 14) | internal sealed class SingleAssemblyResourceManager : ResourceManager
    method SingleAssemblyResourceManager (line 20) | public SingleAssemblyResourceManager() : base()
    method SingleAssemblyResourceManager (line 24) | public SingleAssemblyResourceManager(Type resourceSource) : base(resou...
    method SingleAssemblyResourceManager (line 28) | public SingleAssemblyResourceManager(string baseName, Assembly assembl...
    method SingleAssemblyResourceManager (line 32) | public SingleAssemblyResourceManager(string baseName, Assembly assembl...
    method InternalGetResourceSet (line 36) | protected override ResourceSet? InternalGetResourceSet(CultureInfo cul...
    method CustomGetResourceSet (line 43) | private ResourceSet? CustomGetResourceSet(CultureInfo culture, bool cr...
    method ReleaseAllResources (line 54) | public override void ReleaseAllResources()
    method GetResourceFileName (line 68) | protected override string GetResourceFileName(CultureInfo culture)
    method VerifyCultureName (line 82) | private static bool VerifyCultureName(string cultureName, bool throwEx...

FILE: SvgFileType/Localization/StringResources.Designer.cs
  class StringResources (line 22) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resource...
    method StringResources (line 31) | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Mic...

FILE: SvgFileType/Logger.cs
  class Logger (line 8) | internal static class Logger
    method WriteLine (line 12) | public static void WriteLine(string message)
    method WriteLineIf (line 17) | public static void WriteLineIf(bool condition, string message)

FILE: SvgFileType/Services.cs
  class Services (line 9) | internal static class Services
    method Init (line 13) | public static void Init(IServiceProvider provider)
    method Get (line 20) | public static TService Get<TService>() where TService : class

FILE: SvgFileType/SvgFileType.cs
  class SvgFileType (line 19) | [PluginSupportInfo(typeof(SvgFileTypePluginSupportInfo))]
    method OnLoad (line 26) | protected override Document OnLoad(Stream input)
    method OnSaveT (line 35) | protected override void OnSaveT(Document input, Stream output, Propert...
    method PdnShape_Click (line 40) | private void PdnShape_Click(object? sender, ValueEventArgs<object> args)
    method OnCreateSaveConfigUI (line 48) | public override ControlInfo OnCreateSaveConfigUI(PropertyCollection pr...
    method OnCreateSavePropertyCollection (line 97) | public override PropertyCollection OnCreateSavePropertyCollection()
    method ShouldSerializeTokenProperty (line 139) | protected override bool ShouldSerializeTokenProperty(Property property)
    method IsSerializable (line 156) | private static bool IsSerializable(Property property)

FILE: SvgFileType/SvgFileTypeFactory.cs
  class SvgFileTypeFactory (line 9) | public sealed class SvgFileTypeFactory : IFileTypeFactory2
    method GetFileTypeInstances (line 11) | public FileType[] GetFileTypeInstances(IFileTypeHost host)

FILE: SvgFileType/SvgFileTypePluginSupportInfo.cs
  class SvgFileTypePluginSupportInfo (line 10) | public sealed class SvgFileTypePluginSupportInfo : IPluginSupportInfo, I...
    method GetPluginSupportInfo (line 36) | public IPluginSupportInfo GetPluginSupportInfo()
    method GetCustomAttribute (line 45) | private static T? GetCustomAttribute<T>() where T : Attribute
    method GetAssembly (line 50) | private static Assembly GetAssembly()

FILE: SvgFileType/UIHelper.cs
  class UIHelper (line 15) | internal static partial class UIHelper
    method GetMainForm (line 17) | public static Form? GetMainForm()
    method IsSaveConfigDialogVisible (line 23) | public static bool IsSaveConfigDialogVisible()
    method RunOnUIThread (line 36) | public static TResult? RunOnUIThread<TResult>(Func<TResult> action)
    method RunOnUIThread (line 63) | public static void RunOnUIThread(Action action)
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (386K chars).
[
  {
    "path": ".gitattributes",
    "chars": 2518,
    "preview": "###############################################################################\n# Set default behavior to automatically "
  },
  {
    "path": ".gitignore",
    "chars": 3894,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
  },
  {
    "path": ".gitmodules",
    "chars": 357,
    "preview": "[submodule \"resvg.net\"]\n\tpath = resvg.net\n\turl = https://github.com/otuncelli/resvg.net.git\n[submodule \"PaintDotNet.Indi"
  },
  {
    "path": "COPYING",
    "chars": 18092,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 F"
  },
  {
    "path": "README.md",
    "chars": 2519,
    "preview": "# ![W3C SVG Logo](https://www.w3.org/Icons/SVG/svg-logo-v.png) Scalable Vector Graphics (SVG) Plugin for Paint.NET \n\n[!"
  },
  {
    "path": "SvgFileType/BenchmarkScope.cs",
    "chars": 1042,
    "preview": "// Copyright 2025 Osman Tunçelli. Allrights reserved.\n// Use of this source code is governed by GNU General Public Lice"
  },
  {
    "path": "SvgFileType/Export/PreviewMode.cs",
    "chars": 261,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Export/PropertyNames.cs",
    "chars": 576,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Export/ScanMode.cs",
    "chars": 267,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Export/SvgExport.cs",
    "chars": 10221,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/ControlExtensions.cs",
    "chars": 1309,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/DocumentExtensions.cs",
    "chars": 722,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/StringExtensions.cs",
    "chars": 896,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SurfaceExtensions.cs",
    "chars": 5792,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgDocumentExtensions.cs",
    "chars": 2337,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgElementExtensions.cs",
    "chars": 6781,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgUnitExtensions.cs",
    "chars": 673,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgUseExtensions.cs",
    "chars": 2633,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgViewBoxExtensions.cs",
    "chars": 408,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Extensions/SvgVisualElementExtensions.cs",
    "chars": 3987,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/FodyWeavers.xml",
    "chars": 381,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Weavers xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSc"
  },
  {
    "path": "SvgFileType/FodyWeavers.xsd",
    "chars": 6391,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n  <!-- This file was gen"
  },
  {
    "path": "SvgFileType/Import/Direct2DSvgRenderer.cs",
    "chars": 8871,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/GdipSvgRenderer.cs",
    "chars": 5025,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/LayersMode.cs",
    "chars": 271,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/MyBaseForm.cs",
    "chars": 13051,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/MyBaseForm.resx",
    "chars": 5696,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prim"
  },
  {
    "path": "SvgFileType/Import/ResvgSvgRenderer.cs",
    "chars": 5416,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/StreamTrackerCancellationTokenSource.cs",
    "chars": 2126,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/SvgImport.cs",
    "chars": 3140,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/SvgImportConfig.cs",
    "chars": 684,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/SvgImportDialog.Designer.cs",
    "chars": 36222,
    "preview": "namespace SvgFileTypePlugin.Import;\n\npartial class SvgImportDialog\n{\n    /// <summary>\n    /// Required designer variab"
  },
  {
    "path": "SvgFileType/Import/SvgImportDialog.cs",
    "chars": 13916,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Import/SvgImportDialog.resx",
    "chars": 13222,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!--\n    Microsoft ResX Schema\n\n    Version 2.0\n\n    The primary goals "
  },
  {
    "path": "SvgFileType/Import/SvgRenderer2.cs",
    "chars": 15589,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Localization/InjectResourceManager.ps1",
    "chars": 221,
    "preview": "(Get-Content 'Localization\\StringResources.Designer.cs').replace('new global::System.Resources.ResourceManager', 'new Si"
  },
  {
    "path": "SvgFileType/Localization/Localize.cs",
    "chars": 929,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Localization/SingleAssemblyResourceManager.cs",
    "chars": 4011,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Localization/StringResources.Designer.cs",
    "chars": 25223,
    "preview": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code w"
  },
  {
    "path": "SvgFileType/Localization/StringResources.resx",
    "chars": 15380,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prim"
  },
  {
    "path": "SvgFileType/Localization/StringResources_de.resx",
    "chars": 15681,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prim"
  },
  {
    "path": "SvgFileType/Localization/StringResources_fr.resx",
    "chars": 15753,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prima"
  },
  {
    "path": "SvgFileType/Localization/StringResources_ru.resx",
    "chars": 15564,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prim"
  },
  {
    "path": "SvgFileType/Localization/StringResources_tr.resx",
    "chars": 15396,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The prim"
  },
  {
    "path": "SvgFileType/Logger.cs",
    "chars": 578,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/Services.cs",
    "chars": 904,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/SvgFileType.cs",
    "chars": 7834,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/SvgFileTypeFactory.cs",
    "chars": 501,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/SvgFileTypePlugin.csproj",
    "chars": 6186,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net9.0-windows</TargetFramewo"
  },
  {
    "path": "SvgFileType/SvgFileTypePluginSupportInfo.cs",
    "chars": 1636,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType/UIHelper.cs",
    "chars": 2310,
    "preview": "// Copyright 2025 Osman Tunçelli. All rights reserved.\n// Use of this source code is governed by GNU General Public Lic"
  },
  {
    "path": "SvgFileType.ThirdPartyNotices.txt",
    "chars": 40879,
    "preview": "Scalable-Vector-Graphics-Plugin-for-Paint.NET also uses third-party \nprojects that may be distributed under different li"
  },
  {
    "path": "SvgFileType.sln",
    "chars": 3229,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3201"
  }
]

About this extraction

This page contains the full source code of the otuncelli/Scalable-Vector-Graphics-Plugin-for-Paint.NET GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (358.9 KB), approximately 87.5k tokens, and a symbol index with 223 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!