├── src ├── soname.txt ├── .clang-tidy ├── makefile └── svgren │ ├── config.hxx │ ├── surface.cpp │ ├── surface.hxx │ ├── filter_applier.hxx │ ├── render.hpp │ ├── util.hxx │ ├── render.cpp │ ├── renderer.hxx │ └── util.cpp ├── .gitignore ├── .clang-tidy ├── .clang-format ├── config ├── default.mk ├── dev.mk ├── asan.mk ├── lint.mk ├── dbg.mk ├── gcov.mk ├── emsc.mk ├── base │ └── base.mk └── rel.mk ├── makefile ├── .gitattributes ├── wiki ├── camera.png ├── building.adoc ├── features.adoc ├── usages.adoc ├── main.adoc └── usage.adoc ├── tests ├── makefile ├── unit │ ├── samples_data │ │ ├── expected │ │ │ ├── 1.png │ │ │ ├── 3.png │ │ │ ├── arc.png │ │ │ ├── car.png │ │ │ ├── use.png │ │ │ ├── 0.451.png │ │ │ ├── 3.072.png │ │ │ ├── back.png │ │ │ ├── lines.png │ │ │ ├── mouse.png │ │ │ ├── test2.png │ │ │ ├── tiger.png │ │ │ ├── 3color.png │ │ │ ├── FW5-24V.png │ │ │ ├── caltrain.png │ │ │ ├── camera.png │ │ │ ├── circle.png │ │ │ ├── circle1.png │ │ │ ├── ellipse.png │ │ │ ├── gradtest.png │ │ │ ├── granddad.png │ │ │ ├── masking.png │ │ │ ├── opacity.png │ │ │ ├── sample1.png │ │ │ ├── sample2.png │ │ │ ├── sample3.png │ │ │ ├── sample4.png │ │ │ ├── six_ball.png │ │ │ ├── SPHERE_GSP.png │ │ │ ├── VOLUME_GSP.png │ │ │ ├── composite.png │ │ │ ├── cover_test.png │ │ │ ├── defs_style.png │ │ │ ├── instagram.png │ │ │ ├── menue-cut.png │ │ │ ├── quadratic.png │ │ │ ├── rectangle.png │ │ │ ├── visibility.png │ │ │ ├── SPHERE_S_GSP.png │ │ │ ├── css_simple0.png │ │ │ ├── cubic_smooth.png │ │ │ ├── dashoffset1.png │ │ │ ├── default_black.png │ │ │ ├── defs_style_2.png │ │ │ ├── group_opacity.png │ │ │ ├── menue-search.png │ │ │ ├── rgb_percent.png │ │ │ ├── invisible_rect.png │ │ │ ├── linear_gradient.png │ │ │ ├── radial_gradient.png │ │ │ ├── dropshadowfilter.png │ │ │ ├── gauge_arrow_shadow.png │ │ │ ├── interface-ethernet.png │ │ │ ├── radial_gradient_2.png │ │ │ ├── Customs-Ground_Level.png │ │ │ ├── Turntable-Active-NEW5.png │ │ │ ├── machupicchu_collection_01.png │ │ │ ├── machupicchu_collection_02.png │ │ │ ├── machupicchu_collection_04.png │ │ │ ├── machupicchu_collection_06.png │ │ │ ├── tiger_with_smooth_cubic_curves.png │ │ │ ├── gradient-transform-rotate-compare.png │ │ │ ├── percentage_dimensions_and_viewbox.png │ │ │ └── Pioneer_all_vector_720_wo_bg_inkscape.png │ │ ├── circle.svg │ │ ├── ellipse.svg │ │ ├── circle1.svg │ │ ├── group_opacity.svg │ │ ├── opacity.svg │ │ ├── rectangle.svg │ │ ├── 3color.svg │ │ ├── css_simple0.svg │ │ ├── masking.svg │ │ ├── 3.svg │ │ ├── six_ball.svg │ │ ├── use.svg │ │ ├── sample2.svg │ │ ├── default_black.svg │ │ ├── invisible_rect.svg │ │ ├── percentage_dimensions_and_viewbox.svg │ │ ├── lines.svg │ │ ├── defs_style.svg │ │ ├── dashoffset1.svg │ │ ├── arc.svg │ │ ├── cubic_smooth.svg │ │ ├── rgb_percent.svg │ │ ├── defs_style_2.svg │ │ ├── gradtest.svg │ │ ├── radial_gradient_2.svg │ │ ├── gradient-transform-rotate-compare.svg │ │ ├── caltrain.svg │ │ ├── menue-cut.svg │ │ ├── visibility.svg │ │ ├── menue-search.svg │ │ ├── linear_gradient.svg │ │ ├── quadratic.svg │ │ ├── sample3.svg │ │ ├── radial_gradient.svg │ │ ├── interface-ethernet.svg │ │ ├── gauge_arrow_shadow.svg │ │ ├── mouse.svg │ │ ├── instagram.svg │ │ ├── dropshadowfilter.svg │ │ ├── composite.svg │ │ ├── sample1.svg │ │ ├── sample4.svg │ │ ├── cover_test.svg │ │ └── SPHERE_S_GSP.svg │ ├── render_dims.cpp │ ├── makefile │ └── samples.cpp ├── async │ ├── makefile │ └── main.cpp └── render │ ├── makefile │ └── main.cpp ├── .github └── FUNDING.yml ├── .gitmodules ├── pkg-config ├── makefile └── svgren.pc.in ├── doc └── makefile ├── README.adoc ├── LICENSE └── .vscode ├── launch.json └── tasks.json /src/soname.txt: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/out/* 2 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | tool-configs/clang-tidy/.clang-tidy -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | tool-configs/clang-format/.clang-format -------------------------------------------------------------------------------- /config/default.mk: -------------------------------------------------------------------------------- 1 | $(eval $(call prorab-config-default, rel)) 2 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | 3 | $(eval $(prorab-include-subdirs)) 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # disable line endings conversion for all files 2 | * -text 3 | -------------------------------------------------------------------------------- /wiki/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/wiki/camera.png -------------------------------------------------------------------------------- /tests/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | 3 | $(eval $(prorab-include-subdirs)) 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [igagis] 2 | patreon: igagis 3 | custom: ["https://paypal.me/igagis"] 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tool-configs"] 2 | path = tool-configs 3 | url = ../tool-configs 4 | branch = main 5 | -------------------------------------------------------------------------------- /config/dev.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -DDEBUG 4 | this_cxxflags += -O0 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/1.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/3.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/arc.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/car.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/use.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/use.png -------------------------------------------------------------------------------- /config/asan.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)rel.mk 2 | 3 | this_cxxflags += -fsanitize=address 4 | this_ldflags += -fsanitize=address 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/0.451.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/0.451.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/3.072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/3.072.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/back.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/lines.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/mouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/mouse.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/test2.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/tiger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/tiger.png -------------------------------------------------------------------------------- /config/lint.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)dev.mk 2 | 3 | this_lint_cmd = $(prorab_lint_cmd_clang_tidy) 4 | this_no_format_test := false 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/3color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/3color.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/FW5-24V.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/FW5-24V.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/caltrain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/caltrain.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/camera.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/circle.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/circle1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/circle1.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/ellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/ellipse.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/gradtest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/gradtest.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/granddad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/granddad.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/masking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/masking.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/opacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/opacity.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/sample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/sample1.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/sample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/sample2.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/sample3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/sample3.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/sample4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/sample4.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/six_ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/six_ball.png -------------------------------------------------------------------------------- /src/.clang-tidy: -------------------------------------------------------------------------------- 1 | # TODO: remove when moved to C++20 2 | Checks: | 3 | -modernize-use-designated-initializers 4 | InheritParentConfig: true 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/SPHERE_GSP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/SPHERE_GSP.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/VOLUME_GSP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/VOLUME_GSP.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/composite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/composite.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/cover_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/cover_test.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/defs_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/defs_style.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/instagram.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/menue-cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/menue-cut.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/quadratic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/quadratic.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/rectangle.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/visibility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/visibility.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/SPHERE_S_GSP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/SPHERE_S_GSP.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/css_simple0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/css_simple0.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/cubic_smooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/cubic_smooth.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/dashoffset1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/dashoffset1.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/default_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/default_black.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/defs_style_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/defs_style_2.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/group_opacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/group_opacity.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/menue-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/menue-search.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/rgb_percent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/rgb_percent.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/invisible_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/invisible_rect.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/linear_gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/linear_gradient.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/radial_gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/radial_gradient.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/dropshadowfilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/dropshadowfilter.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/gauge_arrow_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/gauge_arrow_shadow.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/interface-ethernet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/interface-ethernet.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/radial_gradient_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/radial_gradient_2.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/Customs-Ground_Level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/Customs-Ground_Level.png -------------------------------------------------------------------------------- /pkg-config/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-pkg-config.mk 3 | 4 | this_version := $(shell myci-deb-version.sh) 5 | 6 | $(eval $(prorab-pkg-config)) 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/Turntable-Active-NEW5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/Turntable-Active-NEW5.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/machupicchu_collection_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/machupicchu_collection_01.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/machupicchu_collection_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/machupicchu_collection_02.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/machupicchu_collection_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/machupicchu_collection_04.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/machupicchu_collection_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/machupicchu_collection_06.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/tiger_with_smooth_cubic_curves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/tiger_with_smooth_cubic_curves.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/gradient-transform-rotate-compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/gradient-transform-rotate-compare.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/percentage_dimensions_and_viewbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/percentage_dimensions_and_viewbox.png -------------------------------------------------------------------------------- /tests/unit/samples_data/expected/Pioneer_all_vector_720_wo_bg_inkscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgren/HEAD/tests/unit/samples_data/expected/Pioneer_all_vector_720_wo_bg_inkscape.png -------------------------------------------------------------------------------- /doc/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-doxygen.mk 3 | 4 | this_out_dir := out 5 | this_name := svgren 6 | this_version := $(shell myci-deb-version.sh) 7 | 8 | $(eval $(prorab-build-doxygen)) 9 | -------------------------------------------------------------------------------- /config/dbg.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -DDEBUG 4 | this_cxxflags += -O0 5 | 6 | this_dbg := -dbg 7 | 8 | # do not install headers 9 | this_install_hdrs := $(prorab_space) 10 | -------------------------------------------------------------------------------- /tests/unit/samples_data/circle.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/ellipse.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /pkg-config/svgren.pc.in: -------------------------------------------------------------------------------- 1 | Name: svgren # human-readable name 2 | Description: SVG rendering C++ library # human-readable description 3 | Version: $(version) 4 | URL: https://github.com/cppfw/svgren 5 | Requires: 6 | Conflicts: 7 | Libs: -lsvgren 8 | Libs.private: 9 | Cflags: 10 | -------------------------------------------------------------------------------- /config/gcov.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | # no optimization to avoid mismamtch of actual code to source lines, 4 | # otherwise coverage report will not be accurate 5 | this_cxxflags += -O0 6 | 7 | this_cxxflags += -ftest-coverage 8 | this_cxxflags += -fprofile-arcs 9 | 10 | this_ldflags += --coverage 11 | -------------------------------------------------------------------------------- /tests/unit/samples_data/circle1.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wiki/building.adoc: -------------------------------------------------------------------------------- 1 | = Building in Linux 2 | 3 | == Installing build dependencies 4 | 5 | First of all one needs to install all the software packages needed for building. 6 | The list of needed packages can be seen in `build/debian/control.in` files's `Build-Depends:` section. 7 | 8 | == Building 9 | 10 | Building is easy, just use `make`. 11 | -------------------------------------------------------------------------------- /tests/unit/samples_data/group_opacity.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/unit/samples_data/opacity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /wiki/features.adoc: -------------------------------------------------------------------------------- 1 | = SVG features 2 | 3 | **svgren** is supposed to conform to https://www.w3.org/TR/SVG11/[SVG 1.1] specification except some features. 4 | 5 | == Features not planned to support 6 | 7 | - Animation 8 | - Interactivity 9 | 10 | == List of some supported features 11 | 12 | - all gradient kinds (linear, radial) 13 | - group opacity 14 | - all shape kinds 15 | - all path elements 16 | - gaussian blur effect 17 | - masking 18 | - built-in CSS 19 | -------------------------------------------------------------------------------- /wiki/usages.adoc: -------------------------------------------------------------------------------- 1 | = Projects using svgren 2 | 3 | . link:https://www.sae-it.com/en/products/software/setit-configuration-tool.html[setIT configuration tool] by link:https://www.sae-it.com[SAE it-systems] 4 | . link:https://play.google.com/store/apps/details?id=com.symbolicone.ouille[Speech therapy app] for Android. 5 | . link:https://transitapp.com[Commuting trip planning app] for iOS. 6 | . link:https://www.image-line.com/fl-studio/[Fruity Loops Studio] for Windows and MacOS. 7 | . Add your project 8 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rectangle.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /config/emsc.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -O3 4 | 5 | this_cxx := em++ 6 | this_cc := emcc 7 | this_ar := emar 8 | 9 | this_static_lib_only := true 10 | 11 | # TODO: remove the warning suppression when the PR is merged 12 | # Suppress version-check warning due to https://github.com/conan-io/conan-center-index/pull/26247 13 | this_cxxflags += -Wno-version-check 14 | 15 | this_cxxflags += -fwasm-exceptions 16 | this_ldflags += -fwasm-exceptions 17 | 18 | this_cxxflags += -pthread 19 | this_ldflags += -pthread -------------------------------------------------------------------------------- /tests/unit/samples_data/3color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/css_simple0.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/unit/samples_data/masking.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /config/base/base.mk: -------------------------------------------------------------------------------- 1 | this_cxxflags += -Wall # enable all warnings 2 | this_cxxflags += -Wnon-virtual-dtor # warn if base class has non-virtual destructor 3 | this_cxxflags += -Werror # warnings as errors 4 | this_cxxflags += -Wfatal-errors # stop on first error encountered 5 | this_cxxflags += -fstrict-aliasing # in order to comply with the c++ standard more strictly 6 | this_cxxflags += -std=c++17 7 | this_cxxflags += -g 8 | this_cxxflags += -fPIC 9 | 10 | this_ldlibs += -lstdc++ 11 | 12 | this_no_format_test := true 13 | 14 | ifeq ($(gprof), true) 15 | this_cxxflags += -pg 16 | this_ldflags += -pg 17 | endif 18 | -------------------------------------------------------------------------------- /tests/unit/samples_data/3.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/six_ball.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/unit/samples_data/use.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/unit/samples_data/sample2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/unit/samples_data/default_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/unit/samples_data/invisible_rect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/unit/samples_data/percentage_dimensions_and_viewbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/async/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-test.mk 3 | 4 | $(eval $(call prorab-config, ../../config)) 5 | 6 | this_name := tests 7 | 8 | this_srcs += main.cpp 9 | 10 | this_ldlibs += -l svgdom$(this_dbg) 11 | this_ldlibs += -l fsif$(this_dbg) 12 | this_ldlibs += -l utki$(this_dbg) 13 | this_ldlibs += -l png 14 | this_ldlibs += -l pthread 15 | 16 | this_ldlibs += ../../src/out/$(c)/libsvgren$(this_dbg)$(dot_so) 17 | 18 | this_no_install := true 19 | 20 | $(eval $(prorab-build-app)) 21 | 22 | this_test_cmd := $(prorab_this_name) $(shell ls $(d)../unit/samples_data/*.svg) 23 | this_test_deps := $(prorab_this_name) 24 | this_test_ld_path := ../../src/out/$(c) 25 | $(eval $(prorab-test)) 26 | 27 | $(eval $(call prorab-include, ../../src/makefile)) 28 | -------------------------------------------------------------------------------- /tests/unit/render_dims.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "../../src/svgren/render.hpp" 7 | 8 | #ifdef assert 9 | # undef assert 10 | #endif 11 | 12 | namespace{ 13 | const tst::set set("render_dims", [](tst::suite& suite){ 14 | suite.add( 15 | "requested_dimensions", 16 | [](){ 17 | auto dom = svgdom::load(fsif::native_file("samples_data/camera.svg")); 18 | 19 | utki::assert(dom, SL); 20 | 21 | svgren::parameters p; 22 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) 23 | p.dims_request = decltype(p.dims_request){10, 10}; 24 | auto res = svgren::rasterize(*dom, p); 25 | 26 | utki::assert(res.dims() == p.dims_request, SL); 27 | } 28 | ); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /wiki/main.adoc: -------------------------------------------------------------------------------- 1 | = WiKi main page 2 | 3 | == Supported/unsupported SVG features 4 | See link:features.adoc[Features] page. 5 | 6 | == Installation 7 | :package_name: svgren 8 | 9 | . Setup your OS-preferred package system repo following link:https://github.com/cppfw/wiki/blob/main/enable_repo/enable_repo.adoc[this manual] 10 | . Install package 11 | + 12 | - **vcpkg** (multi-OS): `{package_name}` 13 | - **conan** (multi-OS): `{package_name}` 14 | - **deb** (Linux): `lib{package_name}-dev` 15 | - **homebrew** (MacOS X): `lib{package_name}` 16 | - **android**: `io.github.cppfw:{package_name}` 17 | - **msys2** (Windows): `mingw-w64-i686-{package_name}`, `mingw-w64-x86_64-{package_name}` 18 | 19 | == Tutorials 20 | - link:usage.adoc[Basic usage tutorial] 21 | 22 | == Building 23 | - link:building.adoc[Linux] 24 | -------------------------------------------------------------------------------- /config/rel.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | # TODO: use -O3 when https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105651 is fixed in debian bookworm 4 | this_cxxflags += -O2 5 | 6 | # WORKAROUND: on ubuntu jammy dpkg-buildpackage passes -ffat-lto-objects compilation flag 7 | # which is not supported by clang and clang-tidy complains about it: 8 | # error: optimization flag '-ffat-lto-objects' is not supported [clang-diagnostic-ignored-optimization-argument] 9 | # Thus, suppress this warning. 10 | this_cxxflags += -Wno-ignored-optimization-argument 11 | 12 | ifeq ($(os),macosx) 13 | # WORKAROUND: 14 | # clang-tidy on macos doesn't use /usr/local/include as default place to 15 | # search for header files, so we add it explicitly 16 | this_cxxflags += -isystem /usr/local/include 17 | endif 18 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-license.mk 3 | include prorab-clang-format.mk 4 | include prorab-install-dbgsrc.mk 5 | 6 | $(eval $(call prorab-config, ../config)) 7 | 8 | this_src_dir := svgren 9 | 10 | this_name := $(this_src_dir)$(this_dbg) 11 | 12 | this_soname := $(shell cat $(d)soname.txt) 13 | 14 | this_srcs := $(call prorab-src-dir, $(this_src_dir)) 15 | 16 | # this_cxxflags += -D SVGREN_BACKGROUND=0xffffffff 17 | # this_cxxflags += -D SVGREN_BACKGROUND=0xff00ffff 18 | 19 | this_ldlibs += -l veg$(this_dbg) 20 | this_ldlibs += -l svgdom$(this_dbg) 21 | this_ldlibs += -l utki$(this_dbg) 22 | 23 | this_ldlibs += -l m 24 | 25 | $(eval $(prorab-build-lib)) 26 | 27 | this_license_file := ../LICENSE 28 | $(eval $(prorab-license)) 29 | 30 | $(eval $(prorab-clang-format)) 31 | 32 | $(eval $(prorab-install-dbgsrc)) 33 | -------------------------------------------------------------------------------- /tests/unit/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-test.mk 3 | 4 | $(eval $(call prorab-config, ../../config)) 5 | 6 | this_name := tests 7 | 8 | this_srcs += $(call prorab-src-dir, .) 9 | 10 | this_ldlibs += -l svgdom$(this_dbg) 11 | this_ldlibs += -l fsif$(this_dbg) 12 | this_ldlibs += -l utki$(this_dbg) 13 | this_ldlibs += -l tst$(this_dbg) 14 | this_ldlibs += -l rasterimage$(this_dbg) 15 | 16 | this_ldlibs += ../../src/out/$(c)/libsvgren$(this_dbg)$(dot_so) 17 | 18 | this_ldlibs += -l png 19 | this_ldlibs += -l m 20 | 21 | this_no_install := true 22 | 23 | $(eval $(prorab-build-app)) 24 | 25 | this_test_cmd := $(prorab_this_name) --junit-out=out/$(c)/junit.xml 26 | this_test_deps := $(prorab_this_name) 27 | this_test_ld_path := ../../src/out/$(c) 28 | $(eval $(prorab-test)) 29 | 30 | $(eval $(call prorab-include, ../../src/makefile)) 31 | -------------------------------------------------------------------------------- /tests/unit/samples_data/lines.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 13 | 14 | 17 | 18 | 21 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :name: svgren 2 | 3 | = {name} 4 | 5 | |==== 6 | | link:https://github.com/cppfw/{name}/releases[image:https://img.shields.io/github/tag/cppfw/{name}.svg[releases]] | link:https://github.com/cppfw/{name}/actions[image:https://github.com/cppfw/{name}/workflows/ci/badge.svg[ci status]] | link:https://codecov.io/gh/cppfw/{name}/tree/main[image:https://codecov.io/gh/cppfw/{name}/branch/main/graph/badge.svg?token=vwqhr1CujV[codecov.io]] 7 | |==== 8 | 9 | SVG renderer library in C++. 10 | 11 | image:wiki/camera.png[image sample] 12 | 13 | **{name}** uses **link:https://github.com/cppfw/svgdom[svgdom]** to read the SVG file and **link:http://github.com/cppfw/agg[AGG]** to render graphics. 14 | 15 | = Installation and Tutorials 16 | Read link:wiki/main.adoc[WiKi] for installation instructions and tutorials. 17 | 18 | = Projects using {name} 19 | link:wiki/usages.adoc[See list here]. 20 | -------------------------------------------------------------------------------- /tests/unit/samples_data/defs_style.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dashoffset1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 17 | 18 | 21 | 22 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/unit/samples_data/arc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | 17 | 18 | 20 | 21 | 23 | 24 | -------------------------------------------------------------------------------- /tests/async/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../src/svgren/render.hpp" 5 | 6 | #include 7 | 8 | // NOLINTNEXTLINE(bugprone-exception-escape, "we need exceptions from main() to indicate test failure") 9 | int main(int argc, const char** argv) { 10 | if(argc < 2){ 11 | std::cerr << "at least 1 argument expected (SVG filename)" << std::endl; 12 | return 1; 13 | } 14 | 15 | std::vector> svgs; 16 | 17 | for(const char* arg : utki::make_span(std::next(argv), argc - 1)){ 18 | svgs.push_back(svgdom::load(fsif::native_file(arg))); 19 | } 20 | 21 | std::vector threads; 22 | 23 | for(auto& svg : svgs){ 24 | decltype(svg.get()) s = svg.get(); 25 | threads.emplace_back( 26 | [s](){ 27 | auto res = svgren::rasterize(*s); 28 | utki::log([&](auto&o){o << "rendered, width = " << res.dims().x() << std::endl;}); 29 | } 30 | ); 31 | } 32 | 33 | for(auto& t : threads){ 34 | t.join(); 35 | } 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2024 Ivan Gagis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /tests/unit/samples_data/cubic_smooth.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | 14 | 15 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rgb_percent.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /tests/unit/samples_data/defs_style_2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/render/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-test.mk 3 | 4 | $(eval $(call prorab-config, ../../config)) 5 | 6 | this_name := tests 7 | 8 | this_srcs += main.cpp 9 | 10 | this_ldlibs += -l svgdom$(this_dbg) 11 | this_ldlibs += -l rasterimage$(this_dbg) 12 | this_ldlibs += -l fsif$(this_dbg) 13 | this_ldlibs += -l utki$(this_dbg) 14 | 15 | this_ldlibs += -l png 16 | this_ldlibs += -l m 17 | 18 | this_ldlibs += ../../src/out/$(c)/libsvgren$(this_dbg)$(dot_so) 19 | 20 | ifeq ($(os), macosx) 21 | else ifeq ($(os),windows) 22 | else 23 | this_ldlibs += -l X11 24 | endif 25 | 26 | this_no_install := true 27 | 28 | $(eval $(prorab-build-app)) 29 | 30 | # TODO: use prorab-run 31 | ifeq ($(os),windows) 32 | this_run_cmd := $(a)cp $(d)../../src/out/$(c)/libsvgren$(dot_so) $(d) && $$^) 33 | else 34 | this_run_cmd := $(a)(cd $(d); LD_LIBRARY_PATH=../../src/out/$(c) $$^) 35 | endif 36 | 37 | define this_rules 38 | run:: $(prorab_this_name) 39 | $(.RECIPEPREFIX)@echo running $$^... 40 | $(.RECIPEPREFIX)$(a)cp $(d)../../src/out/$(c)/libsvgren$(dot_so) . || true 41 | $(.RECIPEPREFIX)$(a)LD_LIBRARY_PATH=$(d)../../src/out/$(c) $(d)out/$(c)/tests $(d)../samples/testdata/tiger.svg $(d)out.png 42 | endef 43 | $(eval $(this_rules)) 44 | 45 | $(eval $(call prorab-include, ../../src/makefile)) 46 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gradtest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /wiki/usage.adoc: -------------------------------------------------------------------------------- 1 | = Basic usage tutorial 2 | 3 | Please note, that **svgren** uses C++'17 features. 4 | 5 | First of all we need to include the **svgren** header file 6 | 7 | [source,c++] 8 | .... 9 | #include 10 | #include // we will need this to load the SVG file 11 | .... 12 | 13 | Then we need to load the SVG file and create the document object model (DOM), let's load the file called **camera.svg** 14 | 15 | [source,c++] 16 | .... 17 | auto dom = svgdom::load(fsif::native_file("camera.svg")); 18 | .... 19 | 20 | Then we just render the SVG into a memory buffer 21 | 22 | [source,c++] 23 | .... 24 | auto result = svgren::render(*dom); 25 | // returned 'result.pixels' is a std::vector holding array of RGBA values. 26 | .... 27 | 28 | If SVG document specifies any coordiantes or lengthes in physical units, like milimeters or centimeters or inches, 29 | we have to supply the dots per inch (DPI) value of our physical display to the svgren::render() function. This is done using the `svgren::parameters` structure 30 | 31 | [source,c++] 32 | .... 33 | svgren::parameters p; 34 | p.dpi = 240; // pixel density of target physical display is 240 dpi 35 | p.dims_request.x() = 0; // 0 means use width from SVG document 36 | p.dims_request.y() = 0; // 0 means use height from SVG document 37 | auto result = svgren::render(*dom, p); 38 | .... 39 | 40 | After that one can use the rendered image data to display it on any physical display or whatever. 41 | -------------------------------------------------------------------------------- /tests/unit/samples_data/radial_gradient_2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Pad 30 | Repeat 31 | Reflect 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/svgren/config.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | namespace svgren { 34 | 35 | using real = svgdom::real; 36 | 37 | // TODO: take these types from veg 38 | using image_type = rasterimage::image; 39 | using image_span_type = decltype(std::declval().span()); 40 | 41 | } // namespace svgren 42 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gradient-transform-rotate-compare.svg: -------------------------------------------------------------------------------- 1 | 4 | Rotating Gradients in User Space vs Bounding Box 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 22 | 23 | 24 | 26 | 28 | 30 | 31 | 33 | 35 | 36 | -------------------------------------------------------------------------------- /tests/unit/samples_data/caltrain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page 1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/unit/samples_data/menue-cut.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/unit/samples_data/visibility.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/unit/samples_data/menue-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/svgren/surface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "surface.hxx" 29 | 30 | #include 31 | 32 | using namespace svgren; 33 | 34 | surface surface::intersection(const r4::rectangle& r) 35 | { 36 | auto ret_rect = r4::rectangle(this->rect()).intersect(r); 37 | 38 | ASSERT(ret_rect.d.y() <= r.d.y(), [&](auto& o) { 39 | o << "ret_rect = " << ret_rect << " this->rect() = " << this->rect() << " r = " << r; 40 | }) 41 | 42 | if (ret_rect.d.is_any_zero()) { 43 | // resulting surface is of zero size 44 | return {}; 45 | } 46 | 47 | ASSERT(this->rect().contains(ret_rect)) 48 | 49 | return { 50 | ret_rect.p, // 51 | this->image_span.subspan({ret_rect.p - this->position, ret_rect.d}) 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /src/svgren/surface.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "config.hxx" 37 | 38 | namespace svgren { 39 | 40 | struct surface { 41 | r4::vector2 position = 0; 42 | image_span_type image_span; 43 | 44 | surface() = default; 45 | 46 | surface(image_span_type image_span) : 47 | position(0), 48 | image_span(image_span) 49 | {} 50 | 51 | surface(r4::vector2 position, image_span_type image_span) : 52 | position(position), 53 | image_span(image_span) 54 | {} 55 | 56 | r4::rectangle rect() const noexcept 57 | { 58 | return {this->position, this->image_span.dims()}; 59 | } 60 | 61 | surface intersection(const r4::rectangle& r); 62 | }; 63 | 64 | } // namespace svgren 65 | -------------------------------------------------------------------------------- /tests/unit/samples_data/linear_gradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | Example lingrad01 - fill a rectangle using a 7 | linear gradient paint server 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 34 | 36 | 38 | 40 | 41 | -------------------------------------------------------------------------------- /tests/unit/samples_data/quadratic.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | Example quad01 - quadratic Bézier commands in path data 7 | Picture showing a "Q" a "T" command, 8 | along with annotations showing the control points 9 | and end points 10 | 12 | 13 | 15 | 16 | 18 | 19 | 21 | 22 | 24 | 25 | 27 | 28 | 30 | 31 | 33 | 34 | 36 | 37 | 39 | 40 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | -------------------------------------------------------------------------------- /src/svgren/filter_applier.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include "renderer.hxx" 33 | 34 | namespace svgren { 35 | 36 | struct filter_result { 37 | image_type image; 38 | svgren::surface surface; 39 | 40 | filter_result(r4::rectangle surface_rect) : 41 | image(surface_rect.d), 42 | surface( 43 | surface_rect.p, // 44 | this->image.span() 45 | ) 46 | {} 47 | }; 48 | 49 | class filter_applier : public svgdom::const_visitor 50 | { 51 | renderer& r; 52 | 53 | // TODO: naming convention 54 | decltype(svgdom::filter_element::primitive_units) primitiveUnits = svgdom::coordinate_units::user_space_on_use; 55 | 56 | r4::rectangle filterRegion = {0, std::numeric_limits::max()}; 57 | 58 | std::map results; 59 | 60 | filter_result* lastResult = nullptr; 61 | 62 | surface get_source(const std::string& in); 63 | void set_result(const std::string& name, filter_result&& result); 64 | 65 | surface get_source_graphic(); 66 | 67 | public: 68 | surface get_last_result(); 69 | 70 | filter_applier(renderer& r) : 71 | r(r) 72 | {} 73 | 74 | void visit(const svgdom::filter_element& e) override; 75 | 76 | void visit(const svgdom::fe_gaussian_blur_element& e) override; 77 | void visit(const svgdom::fe_color_matrix_element& e) override; 78 | void visit(const svgdom::fe_blend_element& e) override; 79 | void visit(const svgdom::fe_composite_element& e) override; 80 | }; 81 | 82 | } // namespace svgren 83 | -------------------------------------------------------------------------------- /tests/unit/samples_data/sample3.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/svgren/render.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | namespace svgren { 35 | 36 | using image_type = rasterimage::image; 37 | 38 | /** 39 | * @brief SVG render parameters. 40 | */ 41 | struct parameters { 42 | /** 43 | * @brief Width and height request for the resulting raster image. 44 | * If width request is set to 0 then the width will be adjusted to preserve 45 | * aspect ratio of the SVG image or determined from the SVG root element if 46 | * height request is also set to zero. Same works for height request. 47 | */ 48 | r4::vector2 dims_request = 0; 49 | 50 | constexpr static auto default_dpi = 96; 51 | 52 | /** 53 | * @brief Dots per inch to use for unit conversion to pixels. 54 | */ 55 | unsigned dpi = default_dpi; 56 | }; 57 | 58 | /** 59 | * @brief SVG image rendering result. 60 | */ 61 | struct result { 62 | /** 63 | * @brief Array of pixels. 64 | */ 65 | std::vector pixels; 66 | 67 | /** 68 | * @brief Resulting width and height of the raster image. 69 | */ 70 | r4::vector2 dims = 0; 71 | }; 72 | 73 | /** 74 | * @brief Render SVG image to raster image. 75 | * @param svg - the SVG document object model to render. 76 | * @param p - render parameters. 77 | * @return Rendering result. 78 | */ 79 | [[deprecated("use rasterize()")]] result render(const svgdom::svg_element& svg, const parameters& p = parameters()); 80 | 81 | /** 82 | * @brief Create raster image from given SVG DOM. 83 | * @param svg - SVG DOM to rasterize. 84 | * @param params - rasterization parameters. 85 | * @return Raster image of the SVG. 86 | */ 87 | image_type rasterize(const svgdom::svg_element& svg, const parameters& params = parameters()); 88 | 89 | } // namespace svgren 90 | -------------------------------------------------------------------------------- /tests/unit/samples_data/radial_gradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /tests/unit/samples_data/interface-ethernet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gauge_arrow_shadow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 29 | 33 | 34 | 35 | 58 | 60 | 61 | 63 | image/svg+xml 64 | 66 | 67 | 68 | 69 | 70 | 75 | 82 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tests/unit/samples_data/mouse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/svgren/util.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "veg/util.hpp" 41 | 42 | #include "config.hxx" 43 | #include "surface.hxx" 44 | 45 | namespace svgren { 46 | 47 | real percent_to_fraction(const svgdom::length& l); 48 | 49 | class renderer_viewport_push 50 | { 51 | class renderer& r; 52 | r4::vector2 old_viewport; 53 | 54 | public: 55 | renderer_viewport_push(renderer& r, const decltype(old_viewport)& viewport); 56 | 57 | renderer_viewport_push(const renderer_viewport_push&) = delete; 58 | renderer_viewport_push& operator=(const renderer_viewport_push&) = delete; 59 | 60 | renderer_viewport_push(renderer_viewport_push&&) = delete; 61 | renderer_viewport_push& operator=(renderer_viewport_push&&) = delete; 62 | 63 | ~renderer_viewport_push() noexcept; 64 | }; 65 | 66 | class common_element_push 67 | { 68 | bool group_pushed; 69 | surface old_background; 70 | class svgren::renderer& renderer; 71 | 72 | real opacity = real(1); 73 | 74 | const svgdom::element* mask_element = nullptr; 75 | 76 | veg::canvas_matrix_push matrix_push; 77 | 78 | r4::segment2 old_device_space_bounding_box; 79 | 80 | public: 81 | common_element_push(svgren::renderer& renderer, bool is_container); 82 | 83 | common_element_push(const common_element_push&) = delete; 84 | common_element_push& operator=(const common_element_push&) = delete; 85 | 86 | common_element_push(common_element_push&&) = delete; 87 | common_element_push& operator=(common_element_push&&) = delete; 88 | 89 | ~common_element_push() noexcept; 90 | 91 | bool is_group_pushed() const noexcept 92 | { 93 | return this->group_pushed; 94 | } 95 | }; 96 | 97 | struct gradient_caster : public svgdom::const_visitor { 98 | const svgdom::linear_gradient_element* linear = nullptr; 99 | const svgdom::radial_gradient_element* radial = nullptr; 100 | const svgdom::gradient* gradient = nullptr; 101 | 102 | void visit(const svgdom::linear_gradient_element& e) override 103 | { 104 | this->gradient = &e; 105 | this->linear = &e; 106 | } 107 | 108 | void visit(const svgdom::radial_gradient_element& e) override 109 | { 110 | this->gradient = &e; 111 | this->radial = &e; 112 | } 113 | }; 114 | 115 | } // namespace svgren 116 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "debug render_dims", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/tests/render_dims/out/dbg_agg/tests", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/tests/render_dims", 15 | "environment": [{"name": "LD_LIBRARY_PATH", "value": "../../src/out/dbg_agg"}], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | "preLaunchTask": "build_debug_agg" 26 | }, 27 | { 28 | "name": "debug render", 29 | "type": "cppdbg", 30 | "request": "launch", 31 | "program": "${workspaceFolder}/tests/render/out/dbg_agg/tests", 32 | "args": ["${workspaceFolder}/tests/unit/samples_data/Customs-Ground_Level.svg", "${workspaceFolder}/out.png"], 33 | "stopAtEntry": false, 34 | "cwd": "${workspaceFolder}/tests/render", 35 | "environment": [{"name": "LD_LIBRARY_PATH", "value": "../../src/out/dbg_agg"}], 36 | "externalConsole": false, 37 | "MIMode": "gdb", 38 | "setupCommands": [ 39 | { 40 | "description": "Enable pretty-printing for gdb", 41 | "text": "-enable-pretty-printing", 42 | "ignoreFailures": true 43 | } 44 | ], 45 | "preLaunchTask": "build_dbg_agg" 46 | }, 47 | { 48 | "name": "debug unit tests", 49 | "type": "cppdbg", 50 | "request": "launch", 51 | "program": "${workspaceFolder}/tests/unit/out/dbg_agg/tests", 52 | "args": [], 53 | "stopAtEntry": false, 54 | "cwd": "${workspaceFolder}/tests/unit", 55 | "environment": [{"name": "LD_LIBRARY_PATH", "value": "../../src/out/dbg_agg"}], 56 | "externalConsole": false, 57 | "MIMode": "gdb", 58 | "setupCommands": [ 59 | { 60 | "description": "Enable pretty-printing for gdb", 61 | "text": "-enable-pretty-printing", 62 | "ignoreFailures": true 63 | } 64 | ], 65 | "preLaunchTask": "build_dbg_agg" 66 | }, 67 | { 68 | "name": "debug checksvg", 69 | "type": "cppdbg", 70 | "request": "launch", 71 | "program": "${workspaceFolder}/tests/samples/checksvg", 72 | "args": ["${workspaceFolder}/tests/samples/testdata/mouse.svg", "${workspaceFolder}/tests/samples/testdata/mouse.png"], 73 | "stopAtEntry": false, 74 | "cwd": "${workspaceFolder}/tests/render", 75 | "environment": [{"name": "LD_LIBRARY_PATH", "value": "../../src/build"}], 76 | "externalConsole": false, 77 | "MIMode": "gdb", 78 | "setupCommands": [ 79 | { 80 | "description": "Enable pretty-printing for gdb", 81 | "text": "-enable-pretty-printing", 82 | "ignoreFailures": true 83 | } 84 | ], 85 | "preLaunchTask": "build_debug" 86 | } 87 | ] 88 | } -------------------------------------------------------------------------------- /src/svgren/render.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "render.hpp" 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "config.hxx" 37 | #include "renderer.hxx" 38 | 39 | using namespace svgren; 40 | 41 | result svgren::render(const svgdom::svg_element& svg, const parameters& p) 42 | { 43 | result ret; 44 | 45 | auto im = rasterize(svg, p); 46 | 47 | ret.dims = im.dims(); 48 | 49 | ret.pixels.resize(im.pixels().size()); 50 | 51 | // This deprecated render() function uses the rasterize() and then just reinterprets the result, 52 | // so it is OK to use reinterpret_cast here. 53 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 54 | auto span = utki::make_span(reinterpret_cast(im.pixels().data()), im.pixels().size()); 55 | 56 | std::copy(span.begin(), span.end(), ret.pixels.begin()); 57 | 58 | return ret; 59 | } 60 | 61 | image_type svgren::rasterize(const svgdom::svg_element& svg, const parameters& params) 62 | { 63 | auto svg_dims = svg.get_dimensions(svgdom::real(params.dpi)); 64 | 65 | if (!svg_dims.is_positive()) { 66 | return {}; 67 | } 68 | 69 | image_type::dimensions_type raster_dims; 70 | 71 | if (params.dims_request.is_zero()) { 72 | using std::ceil; 73 | raster_dims = ceil(svg_dims).to(); 74 | } else { 75 | real aspect_ratio = svg.aspect_ratio(svgdom::real(params.dpi)); 76 | if (aspect_ratio == 0) { 77 | return {}; 78 | } 79 | ASSERT(aspect_ratio > 0) 80 | using std::round; 81 | using std::max; 82 | if (params.dims_request.x() == 0 && params.dims_request.y() != 0) { 83 | raster_dims.x() = unsigned(round(aspect_ratio * real(params.dims_request.y()))); 84 | raster_dims.x() = max(raster_dims.x(), unsigned(1)); // we don't want zero width 85 | raster_dims.y() = params.dims_request.y(); 86 | } else if (params.dims_request.x() != 0 && params.dims_request.y() == 0) { 87 | raster_dims.y() = unsigned(round(real(params.dims_request.x()) / aspect_ratio)); 88 | raster_dims.y() = max(raster_dims.y(), unsigned(1)); // we don't want zero height 89 | raster_dims.x() = params.dims_request.x(); 90 | } else { 91 | ASSERT(params.dims_request.is_positive()) 92 | raster_dims = params.dims_request; 93 | } 94 | } 95 | 96 | ASSERT(raster_dims.is_positive()) 97 | ASSERT(svg_dims.is_positive()) 98 | 99 | veg::canvas canvas(raster_dims); 100 | 101 | canvas.scale(raster_dims.to().comp_div(svg_dims.to())); 102 | 103 | renderer r(canvas, params.dpi, svg_dims, svg); 104 | 105 | svg.accept(r); 106 | 107 | return canvas.release(); 108 | } 109 | -------------------------------------------------------------------------------- /tests/unit/samples_data/instagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dropshadowfilter.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 46 | 48 | 50 | 54 | 55 | 57 | 61 | 62 | 69 | 72 | 73 | 75 | 80 | 81 | 83 | 87 | 88 | 89 | 91 | 93 | 98 | 103 | 104 | 108 | 110 | 115 | 116 | 118 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /tests/unit/samples_data/composite.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | Example feComposite - Examples of feComposite operations 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Render the examples using the filters that draw on top of 49 | an opaque white surface, thus obliterating the background. 50 | 51 | Render the examples using the filters that do not obliterate 52 | the background, thus sometimes causing the background to continue 53 | to appear in some cases, and in other cases the background 54 | image blends into itself ("double-counting"). 55 | opacity 1.0 56 | (without feFlood) 57 | opacity 0.5 58 | (without feFlood) 59 | 60 | 61 | 62 | 63 | over 64 | 65 | 66 | 67 | 68 | in 69 | 70 | 71 | 72 | 73 | out 74 | 75 | 76 | 77 | 78 | atop 79 | 80 | 81 | 82 | 83 | xor 84 | 85 | 86 | 87 | 88 | arithmetic 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /tests/unit/samples_data/sample1.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 33 | 37 | 40 | 46 | 52 | 58 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /tests/render/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../../src/svgren/render.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #if CFG_OS == CFG_OS_LINUX 21 | # include 22 | # include 23 | #endif 24 | 25 | #ifdef assert 26 | # undef assert 27 | #endif 28 | 29 | // NOLINTNEXTLINE(bugprone-exception-escape): fatal exceptions are not caught 30 | int main(int argc, char **argv){ 31 | std::string filename; 32 | std::string out_filename; 33 | switch(argc){ 34 | case 0: 35 | case 1: 36 | std::cout << "Warning: 2 arguments expected: " << std::endl; 37 | std::cout << "\t Got 0 arguments, assume =tiger.svg =tiger.png" << std::endl; 38 | filename = "tiger.svg"; 39 | out_filename = "tiger.png"; 40 | break; 41 | case 2: 42 | std::cout << "Warning: 2 arguments expected: " << std::endl; 43 | // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 44 | filename = argv[1]; 45 | { 46 | auto dot_index = filename.find_last_of(".", filename.size()); 47 | if(dot_index == std::string::npos){ 48 | dot_index = filename.size(); 49 | } 50 | out_filename = filename.substr(0, dot_index) + ".png"; 51 | } 52 | std::cout << "\t Got 1 argument, assume =" << filename << " =" << out_filename << std::endl; 53 | break; 54 | default: 55 | // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 56 | filename = argv[1]; 57 | // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 58 | out_filename = argv[2]; 59 | break; 60 | } 61 | 62 | #ifdef DEBUG 63 | auto load_start = utki::get_ticks_ms(); 64 | #endif 65 | 66 | auto dom = svgdom::load(fsif::native_file(filename)); 67 | utki::assert(dom, SL); 68 | 69 | LOG([&](auto&o){o << "SVG loaded in " << float(utki::get_ticks_ms() - load_start) / float(std::milli::den) << " sec." << std::endl;}) 70 | 71 | auto render_start_ms = utki::get_ticks_ms(); 72 | 73 | auto image = rasterimage::image_variant(svgren::rasterize(*dom)); 74 | 75 | const auto& img = image.get(); 76 | 77 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) 78 | utki::log([&](auto&o){o << "SVG rendered in " << float(utki::get_ticks_ms() - render_start_ms) / 1000.0f << " sec." << std::endl;}); 79 | 80 | utki::log([&](auto&o){o << "img.dims = " << img.dims() << " img.pixels.size() = " << img.pixels().size() << std::endl;}); 81 | 82 | image.write_png(fsif::native_file(out_filename)); 83 | 84 | #if CFG_OS == CFG_OS_LINUX 85 | auto width = int(img.dims().x() + 2); 86 | auto height = int(img.dims().y() + 2); 87 | 88 | Display *display = XOpenDisplay(nullptr); 89 | 90 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic) 91 | Visual *visual = DefaultVisual(display, 0); 92 | 93 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic) 94 | Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, width, height, 1, 0, 0); 95 | 96 | if(visual->c_class != TrueColor){ 97 | utki::log([](auto&o){o << "Cannot handle non true color visual ...\n" << std::endl;}); 98 | return 1; 99 | } 100 | 101 | XSelectInput(display, window, ButtonPressMask|ExposureMask|KeyPressMask); 102 | 103 | XMapWindow(display, window); 104 | 105 | while(true){ 106 | XEvent ev; 107 | XNextEvent(display, &ev); 108 | switch(ev.type){ 109 | default: 110 | break; 111 | case Expose: 112 | { 113 | int dummy_int = 0; 114 | unsigned dummy_unsigned = 0; 115 | Window dummy_window = 0; 116 | unsigned win_width = 0; 117 | unsigned win_height = 0; 118 | 119 | XGetGeometry(display, window, &dummy_window, &dummy_int, &dummy_int, &win_width, &win_height, &dummy_unsigned, &dummy_unsigned); 120 | 121 | using std::max; 122 | 123 | svgren::parameters p; 124 | p.dpi = svgren::parameters::default_dpi; 125 | p.dims_request.x() = max(int(win_width) - 2, 0); 126 | p.dims_request.y() = max(int(win_height) - 2, 0); 127 | auto img = svgren::rasterize(*dom, p); 128 | 129 | img.span().swap_red_blue(); 130 | 131 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 132 | auto ximage = XCreateImage(display, visual, utki::byte_bits * 3, ZPixmap, 0, reinterpret_cast(img.pixels().data()), img.dims().x(), img.dims().y(), utki::byte_bits, 0); 133 | utki::scope_exit scope_exit([ximage](){ 134 | ximage->data = nullptr; // Xlib will try to deallocate data which is owned by 'img' variable. 135 | XDestroyImage(ximage); 136 | }); 137 | 138 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic) 139 | XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 1, 1, img.dims().x(), img.dims().y()); 140 | } 141 | break; 142 | case KeyPress: 143 | case ButtonPress: 144 | exit(0); 145 | break; 146 | } 147 | } 148 | #endif 149 | 150 | utki::log([](auto&o){o << "[PASSED]" << std::endl;}); 151 | } 152 | -------------------------------------------------------------------------------- /src/svgren/renderer.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "config.hxx" 41 | #include "surface.hxx" 42 | #include "util.hxx" 43 | 44 | namespace svgren { 45 | 46 | class renderer : public svgdom::const_visitor 47 | { 48 | public: 49 | veg::canvas& canvas; 50 | 51 | svgdom::finder_by_id finder_by_id; 52 | svgdom::style_stack_cache style_stack_cache; 53 | 54 | const real dpi; 55 | 56 | bool is_outermost_element = true; 57 | 58 | r4::vector2 viewport; 59 | 60 | // this bounding box is used for gradients 61 | r4::rectangle user_space_bounding_box{}; 62 | 63 | // this bounding box is used for filter region calculation. 64 | r4::segment2 device_space_bounding_box{}; 65 | 66 | svgdom::style_stack style_stack; 67 | 68 | surface background; // for accessing background image from filter effects 69 | 70 | void blit(const surface& s); 71 | 72 | real length_to_px(const svgdom::length& l) const noexcept; 73 | r4::vector2 length_to_px(const svgdom::length& x, const svgdom::length& y) const noexcept; 74 | 75 | void apply_transformation(const svgdom::transformable::transformation& t); 76 | 77 | void apply_transformations(const decltype(svgdom::transformable::transformations)& transformations); 78 | 79 | void set_gradient_properties( 80 | veg::gradient& gradient, // 81 | const svgdom::gradient& g, 82 | const svgdom::style_stack& ss 83 | ); 84 | 85 | void set_gradient(const std::string& id); 86 | 87 | void apply_filter(const std::string& id); 88 | void apply_filter(); 89 | 90 | void update_bounding_box(); 91 | 92 | void render_shape(bool is_group_pushed); 93 | 94 | void apply_viewbox(const svgdom::view_boxed& e, const svgdom::aspect_ratioed& ar); 95 | 96 | void render_svg_element( 97 | const svgdom::container& c, 98 | const svgdom::styleable& s, 99 | const svgdom::view_boxed& v, 100 | const svgdom::aspect_ratioed& a, 101 | const svgdom::length& x, 102 | const svgdom::length& y, 103 | const svgdom::length& width, 104 | const svgdom::length& height 105 | ); 106 | 107 | const decltype(svgdom::transformable::transformations)& gradient_get_transformations(const svgdom::gradient& g); 108 | svgdom::coordinate_units gradient_get_units(const svgdom::gradient& g); 109 | 110 | svgdom::length gradient_get_x1(const svgdom::linear_gradient_element& g); 111 | svgdom::length gradient_get_y1(const svgdom::linear_gradient_element& g); 112 | svgdom::length gradient_get_x2(const svgdom::linear_gradient_element& g); 113 | svgdom::length gradient_get_y2(const svgdom::linear_gradient_element& g); 114 | 115 | svgdom::length gradient_get_cx(const svgdom::radial_gradient_element& g); 116 | svgdom::length gradient_get_cy(const svgdom::radial_gradient_element& g); 117 | svgdom::length gradient_get_r(const svgdom::radial_gradient_element& g); 118 | svgdom::length gradient_get_fx(const svgdom::radial_gradient_element& g); 119 | svgdom::length gradient_get_fy(const svgdom::radial_gradient_element& g); 120 | 121 | const decltype(svgdom::container::children)& gradient_get_stops(const svgdom::gradient& g); 122 | const decltype(svgdom::styleable::styles)& gradient_get_styles(const svgdom::gradient& g); 123 | const decltype(svgdom::styleable::classes)& gradient_get_classes(const svgdom::gradient& g); 124 | svgdom::gradient::spread_method gradient_get_spread_method(const svgdom::gradient& g); 125 | 126 | decltype(svgdom::styleable::presentation_attributes) // 127 | gradient_get_presentation_attributes(const svgdom::gradient& g); 128 | 129 | bool is_invisible(); 130 | bool is_group_invisible(); 131 | 132 | public: 133 | renderer( 134 | veg::canvas& canvas, // 135 | unsigned dpi, 136 | r4::vector2 viewport, 137 | const svgdom::svg_element& root 138 | ); 139 | 140 | // declare public method which calls protected one. 141 | void relay_accept(const svgdom::container& e) 142 | { 143 | this->const_visitor::relay_accept(e); 144 | } 145 | 146 | void visit(const svgdom::g_element& e) override; 147 | void visit(const svgdom::use_element& e) override; 148 | void visit(const svgdom::svg_element& e) override; 149 | void visit(const svgdom::path_element& e) override; 150 | void visit(const svgdom::circle_element& e) override; 151 | void visit(const svgdom::polyline_element& e) override; 152 | void visit(const svgdom::polygon_element& e) override; 153 | void visit(const svgdom::line_element& e) override; 154 | void visit(const svgdom::ellipse_element& e) override; 155 | void visit(const svgdom::rect_element& e) override; 156 | void visit(const svgdom::style_element& e) override; 157 | void visit(const svgdom::defs_element& e) override; 158 | 159 | void default_visit(const svgdom::element& e, const svgdom::container& c) override 160 | { 161 | // do nothing by default 162 | } 163 | }; 164 | 165 | } // namespace svgren 166 | -------------------------------------------------------------------------------- /tests/unit/samples.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "../../src/svgren/render.hpp" 16 | 17 | namespace{ 18 | const unsigned tolerance = 10; 19 | 20 | const std::string data_dir = "samples_data/"; 21 | 22 | const std::string expected_dir = "expected"; 23 | } 24 | 25 | namespace{ 26 | const tst::set set("samples", [](tst::suite& suite){ 27 | std::vector files; 28 | 29 | { 30 | const std::regex suffix_regex("^.*\\.svg$"); 31 | auto all_files = fsif::native_file(data_dir).list_dir(); 32 | 33 | std::copy_if( 34 | all_files.begin(), 35 | all_files.end(), 36 | std::back_inserter(files), 37 | [&suffix_regex](auto& f){ 38 | return std::regex_match(f, suffix_regex); 39 | } 40 | ); 41 | } 42 | 43 | suite.add( 44 | "sample__deprecated_render", 45 | { 46 | #if CFG_CPU_BITS != 64 47 | tst::flag::disabled 48 | #endif 49 | }, 50 | files, 51 | [](const auto& p){ 52 | fsif::native_file in_file(data_dir + p); 53 | 54 | auto dom = svgdom::load(in_file); 55 | 56 | #if CFG_COMPILER == CFG_COMPILER_GCC || CFG_COMPILER == CFG_COMPILER_CLANG 57 | # pragma GCC diagnostic push 58 | # pragma GCC diagnostic ignored "-Wdeprecated-declarations" 59 | #endif 60 | #if CFG_COMPILER == CFG_COMPILER_MSVC 61 | # pragma warning(disable : 4996) 62 | #endif 63 | // NOLINTNEXTLINE(clang-diagnostic-deprecated-declarations, "false positive") 64 | auto res = svgren::render(*dom); 65 | #if CFG_COMPILER == CFG_COMPILER_MSVC 66 | # pragma warning(enable: 4996) 67 | #endif 68 | #if CFG_COMPILER == CFG_COMPILER_GCC 69 | # pragma GCC diagnostic pop 70 | #endif 71 | 72 | auto& img = res.pixels; 73 | 74 | fsif::native_file png_file(data_dir + expected_dir + "/" + fsif::not_suffix(in_file.not_dir()) + ".png"); 75 | 76 | auto png_var = rasterimage::read_png(png_file); 77 | 78 | tst::check(!png_var.empty(), SL); 79 | 80 | tst::check(png_var.get_format() == rasterimage::format::rgba, SL) << "Error: PNG color format is not rgba: " << unsigned(png_var.get_format()); 81 | tst::check(png_var.get_depth() == rasterimage::depth::uint_8_bit, SL) << "Error: PNG color depth is not 8 bit: " << unsigned(png_var.get_depth());; 82 | 83 | tst::check(res.dims == png_var.dims(), SL) << "Error: svg dims " << res.dims << " did not match PNG dims " << png_var.dims(); 84 | 85 | tst::check(img.size() == png_var.buffer_size(), SL) << "Error: svg pixel buffer size (" << img.size() << ") did not match PNG pixel buffer size(" << png_var.buffer_size() << ")"; 86 | 87 | const auto& png = png_var.get(); 88 | 89 | for(size_t i = 0; i != img.size(); ++i){ 90 | std::array rgba = rasterimage::from_32bit_pixel(img[i]); 91 | 92 | for(unsigned j = 0; j != rgba.size(); ++j){ 93 | // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) 94 | auto c1 = rgba[j]; 95 | auto c2 = png.pixels()[i][j]; 96 | if(c1 > c2){ 97 | std::swap(c1, c2); 98 | } 99 | 100 | if(unsigned(c2 - c1) > tolerance){ 101 | auto png_px = png.pixels()[i]; 102 | 103 | uint32_t pixel = rasterimage::to_32bit_pixel(png_px); 104 | 105 | tst::check(false, SL) << "Error: PNG pixel #" << std::dec << i << " [" << (i % res.dims.x()) << ", " << (i / res.dims.y()) << "]" << " (0x" << std::hex << pixel << ") did not match SVG pixel (0x" << img[i] << ")" << ", png_file = " << png_file.path(); 106 | } 107 | } 108 | } 109 | } 110 | ); 111 | 112 | suite.add( 113 | "sample", 114 | { 115 | #if CFG_CPU_BITS != 64 116 | tst::flag::disabled 117 | #endif 118 | }, 119 | files, 120 | [](const auto& p){ 121 | fsif::native_file in_file(data_dir + p); 122 | 123 | auto dom = svgdom::load(in_file); 124 | 125 | auto im = svgren::rasterize(*dom); 126 | 127 | fsif::native_file png_file(data_dir + expected_dir + "/" + fsif::not_suffix(in_file.not_dir()) + ".png"); 128 | 129 | auto png_var = rasterimage::read_png(png_file); 130 | 131 | tst::check(!png_var.empty(), SL); 132 | 133 | tst::check(png_var.get_format() == rasterimage::format::rgba, SL) << "Error: PNG color format is not rgba: " << unsigned(png_var.get_format()); 134 | tst::check(png_var.get_depth() == rasterimage::depth::uint_8_bit, SL) << "Error: PNG color depth is not 8 bit: " << unsigned(png_var.get_depth());; 135 | 136 | tst::check(im.dims() == png_var.dims(), SL) << "Error: svg dims " << im.dims() << " did not match PNG dims " << png_var.dims(); 137 | 138 | tst::check(im.pixels().size() == png_var.buffer_size(), SL) << "Error: svg pixel buffer size (" << im.pixels().size() << ") did not match PNG pixel buffer size(" << png_var.buffer_size() << ")"; 139 | 140 | const auto& png = png_var.get(); 141 | 142 | for(size_t i = 0; i != im.pixels().size(); ++i){ 143 | auto rgba = im.pixels()[i]; 144 | auto png_px = png.pixels()[i]; 145 | 146 | for(unsigned j = 0; j != rgba.size(); ++j){ 147 | auto c1 = rgba[j]; 148 | auto c2 = png_px[j]; 149 | if(c1 > c2){ 150 | std::swap(c1, c2); 151 | } 152 | 153 | if(unsigned(c2 - c1) > tolerance){ 154 | uint32_t png_pixel = rasterimage::to_32bit_pixel(png_px); 155 | uint32_t svg_pixel = rasterimage::to_32bit_pixel(rgba); 156 | 157 | tst::check(false, SL) << "Error: PNG pixel #" << std::dec << i << " [" << (i % im.dims().x()) << ", " << (i / im.dims().y()) << "]" << " (0x" << std::hex << png_pixel << ") did not match SVG pixel (0x" << svg_pixel << ")" << ", png_file = " << png_file.path(); 158 | } 159 | } 160 | } 161 | } 162 | ); 163 | }); 164 | } 165 | -------------------------------------------------------------------------------- /src/svgren/util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2024 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "util.hxx" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "renderer.hxx" 40 | 41 | using namespace svgren; 42 | 43 | real svgren::percent_to_fraction(const svgdom::length& l) 44 | { 45 | if (l.is_percent()) { 46 | return l.value / real(std::centi::den); 47 | } 48 | if (l.unit == svgdom::length_unit::number) { 49 | return l.value; 50 | } 51 | return 0; 52 | } 53 | 54 | renderer_viewport_push::renderer_viewport_push(renderer& r, const decltype(old_viewport)& viewport) : 55 | r(r), 56 | old_viewport(r.viewport) 57 | { 58 | this->r.viewport = viewport; 59 | } 60 | 61 | renderer_viewport_push::~renderer_viewport_push() noexcept 62 | { 63 | this->r.viewport = this->old_viewport; 64 | } 65 | 66 | common_element_push::common_element_push(svgren::renderer& renderer, bool is_container) : 67 | renderer(renderer), 68 | matrix_push(this->renderer.canvas), 69 | old_device_space_bounding_box(renderer.device_space_bounding_box) 70 | { 71 | // old device space bounding box is saved, set current one to empty 72 | this->renderer.device_space_bounding_box.set_empty_bounding_box(); 73 | 74 | auto background_prop = this->renderer.style_stack.get_style_property(svgdom::style_property::enable_background); 75 | 76 | if (background_prop && std::holds_alternative(*background_prop) && 77 | std::get_if(background_prop)->value == 78 | svgdom::enable_background::new_background) 79 | { 80 | this->old_background = this->renderer.background; 81 | } 82 | 83 | auto filter_prop = this->renderer.style_stack.get_style_property(svgdom::style_property::filter); 84 | 85 | if (auto mask_prop = this->renderer.style_stack.get_style_property(svgdom::style_property::mask)) { 86 | if (std::holds_alternative(*mask_prop)) { 87 | if (auto ei = this->renderer.finder_by_id.find(svgdom::get_local_id_from_iri(*mask_prop))) { 88 | this->mask_element = ei; 89 | } 90 | } 91 | } 92 | 93 | this->group_pushed = filter_prop || this->mask_element || !this->old_background.image_span.empty(); 94 | 95 | auto opacity = svgdom::real(1); 96 | { 97 | auto stroke_prop = this->renderer.style_stack.get_style_property(svgdom::style_property::stroke); 98 | auto fill_prop = this->renderer.style_stack.get_style_property(svgdom::style_property::fill); 99 | 100 | // OPTIMIZATION: if opacity is set on an element then push group only in case it is a container element, like 101 | // 'g' or 'svg', or in case the fill or stroke is a non-solid color, like gradient or pattern, or both fill and 102 | // stroke are non-none. If element is non-container and one of stroke or fill is solid color and other one is 103 | // none, then opacity will be applied later without pushing group. 104 | if (this->group_pushed || is_container || (stroke_prop && std::holds_alternative(*stroke_prop)) || 105 | (fill_prop && std::holds_alternative(*fill_prop)) || 106 | (fill_prop && stroke_prop && !svgdom::is_none(*fill_prop) && !svgdom::is_none(*stroke_prop))) 107 | { 108 | auto p = this->renderer.style_stack.get_style_property(svgdom::style_property::opacity); 109 | if (p && std::holds_alternative(*p)) { 110 | opacity = *std::get_if(p); 111 | this->group_pushed = this->group_pushed || opacity < 1; 112 | } 113 | } 114 | } 115 | 116 | if (this->group_pushed) { 117 | // TRACE(<< "setting temp context" << std::endl) 118 | this->renderer.canvas.push_group(); 119 | 120 | this->opacity = opacity; 121 | } 122 | 123 | if (!this->old_background.image_span.empty()) { 124 | this->renderer.background = surface(this->renderer.canvas.get_image_span()); 125 | } 126 | } 127 | 128 | common_element_push::~common_element_push() noexcept 129 | { 130 | // restore device space bounding box 131 | this->old_device_space_bounding_box.unite(this->renderer.device_space_bounding_box); 132 | this->renderer.device_space_bounding_box = this->old_device_space_bounding_box; 133 | 134 | if (!this->group_pushed) { 135 | return; 136 | } 137 | 138 | if (this->mask_element) { 139 | // render mask 140 | try { 141 | this->renderer.canvas.push_group(); 142 | 143 | utki::scope_exit scope_exit([this]() { 144 | this->renderer.canvas.pop_group(1); 145 | }); 146 | 147 | // TODO: setup the correct coordinate system based on maskContentUnits value 148 | // (userSpaceOnUse/objectBoundingBox) 149 | // Currently nothing on that is done which is equivalent to userSpaceOnUse 150 | 151 | class mask_renderer : public svgdom::const_visitor 152 | { 153 | svgren::renderer& r; 154 | 155 | public: 156 | mask_renderer(svgren::renderer& r) : 157 | r(r) 158 | {} 159 | 160 | void visit(const svgdom::mask_element& e) override 161 | { 162 | svgdom::style_stack::push push_styles(this->r.style_stack, e); 163 | 164 | this->r.relay_accept(e); 165 | } 166 | } mr(this->renderer); 167 | 168 | this->mask_element->accept(mr); 169 | 170 | scope_exit.release(); 171 | 172 | this->renderer.canvas.pop_mask_and_group(); 173 | // NOLINTNEXTLINE(bugprone-empty-catch) 174 | } catch (...) { 175 | // rendering mask failed, just ignore it 176 | } 177 | } else { 178 | this->renderer.canvas.pop_group(this->opacity); 179 | } 180 | 181 | // restore background if it was pushed 182 | if (!this->old_background.image_span.empty()) { 183 | this->renderer.background = this->old_background; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /tests/unit/samples_data/sample4.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 32 | 36 | 41 | 42 | 46 | 50 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/unit/samples_data/cover_test.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 16 | 18 | 19 | 20 | 21 | 22 | 24 | 26 | 28 | 30 | 31 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 54 | 55 | 56 | 57 | 58 | 60 | 62 | 64 | 66 | 67 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 88 | 90 | 92 | 93 | 94 | 95 | 96 | 98 | 100 | 102 | 104 | 106 | 108 | 109 | 110 | 112 | 114 | 116 | 118 | 120 | 122 | 123 | 124 | 126 | 128 | 130 | 132 | 134 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 144 | 146 | 148 | 149 | 150 | 151 | 152 | 154 | 156 | 158 | 160 | 162 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 172 | 174 | 175 | 176 | 177 | 178 | 180 | 182 | 184 | 186 | 188 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "make config=rel", 10 | "problemMatcher": [ 11 | "$gcc" 12 | ], 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | } 17 | }, 18 | { 19 | "label": "build-dev", 20 | "type": "shell", 21 | "command": "make config=dev", 22 | "problemMatcher": [ 23 | "$gcc" 24 | ], 25 | "group": { 26 | "kind": "build", 27 | "isDefault": true 28 | } 29 | }, 30 | { 31 | "label": "build-dev_bg", 32 | "type": "shell", 33 | "command": "make config=dev CXXFLAGS=-DSVGREN_BACKGROUND=0xffffffff", 34 | "problemMatcher": [ 35 | "$gcc" 36 | ], 37 | "group": { 38 | "kind": "build", 39 | "isDefault": true 40 | } 41 | }, 42 | { 43 | "label": "run", 44 | "type": "shell", 45 | "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/rel out/rel/tests ../unit/samples_data/defs_style_2.svg ../unit/samples_data/agg/defs_style_2.png)", 46 | "problemMatcher": [], 47 | "dependsOn": "build", 48 | "group": { 49 | "kind": "build", 50 | "isDefault": true 51 | } 52 | }, 53 | { 54 | "label": "run-dev", 55 | "type": "shell", 56 | "dependsOn": "build-dev", 57 | // "dependsOn": "build-dev_bg", 58 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/Customs-Ground_Level.svg out.png)", 59 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/rgb_percent.svg out.png)", 60 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/defs_style_2.svg out.png)", 61 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/defs_style.svg out.png)", 62 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/opacity.svg out.png)", 63 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/ready_test.svg out.png)", 64 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/shadow_test.svg out.png)", 65 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/car.svg out.png)", 66 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/Turntable-Active-NEW5.svg out.png)", 67 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/machupicchu_collection_06.svg out.png)", 68 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/machupicchu_collection_04.svg out.png)", 69 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/machupicchu_collection_02.svg out.png)", 70 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/machupicchu_collection_01.svg out.png)", 71 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/test2.svg out.png)", 72 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/rectangle.svg out.png)", 73 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/dropshadowfilter.svg out.png)", 74 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/six_ball.svg out.png)", 75 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/granddad.svg out.png)", 76 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/3.072.svg out.png)", 77 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/0.451.svg out.png)", 78 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/gradtest.svg out.png)", 79 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/radial_gradient.svg out.png)", 80 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/car.svg out.png)", 81 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/VOLUME_GSP.svg out.png)", 82 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/visibility.svg out.png)", 83 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/use.svg out.png)", 84 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/tiger_with_smooth_cubic_curves.svg out.png)", 85 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/SPHERE_S_GSP.svg out.png)", 86 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/SPHERE_GSP.svg out.png)", 87 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/sample4.svg out.png)", 88 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/sample3.svg out.png)", 89 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/sample2.svg out.png)", 90 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/sample1.svg out.png)", 91 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/quadratic.svg out.png)", 92 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/percentage_dimensions_and_viewbox.svg out.png)", 93 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/mouse.svg out.png)", 94 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/menue-cut.svg out.png)", 95 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/lines.svg out.png)", 96 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/linear_gradient.svg out.png)", 97 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/invisible_rect.svg out.png)", 98 | "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/interface-ethernet.svg out.png)", 99 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/gauge_arrow_shadow.svg out.png)", 100 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/FW5-24V.svg out.png)", 101 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/ellipse.svg out.png)", 102 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/default_black.svg out.png)", 103 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/cubic_smooth.svg out.png)", 104 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/css_simple0.svg out.png)", 105 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/composite.svg out.png)", 106 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/circle.svg out.png)", 107 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/circle1.svg out.png)", 108 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/caltrain.svg out.png)", 109 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/arc.svg out.png)", 110 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/1.svg out.png)", 111 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/group_opacity.svg out.png)", 112 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/masking.svg out.png)", 113 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/camera.svg out.png)", 114 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/back.svg out.png)", 115 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/tiger.svg out.png)", 116 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/radial_gradient_2.svg out.png)", 117 | // "command": "(cd ${workspaceFolder}/tests/render && LD_LIBRARY_PATH=../../src/out/dev out/dev/tests ../unit/samples_data/gradient-transform-rotate-compare.svg out.png)", 118 | "problemMatcher": [], 119 | "group": { 120 | "kind": "build", 121 | "isDefault": true 122 | } 123 | }, 124 | { 125 | "label": "clean-all", 126 | "type": "shell", 127 | "command": "make clean-all", 128 | "problemMatcher": [], 129 | "group": { 130 | "kind": "build", 131 | "isDefault": true 132 | } 133 | }, 134 | { 135 | "label": "clean", 136 | "type": "shell", 137 | "command": "make clean config=rel", 138 | "problemMatcher": [], 139 | "group": { 140 | "kind": "build", 141 | "isDefault": true 142 | } 143 | }, 144 | { 145 | "label": "rebuild", 146 | "type": "shell", 147 | "command": "make re", 148 | "dependsOn": [ 149 | "clean", 150 | "build" 151 | ], 152 | "problemMatcher": [], 153 | "group": { 154 | "kind": "build", 155 | "isDefault": true 156 | } 157 | }, 158 | { 159 | "label": "test_", 160 | "type": "shell", 161 | "command": "make test config=rel", 162 | "problemMatcher": [], 163 | "group": { 164 | "kind": "build", 165 | "isDefault": true 166 | } 167 | }, 168 | { 169 | "label": "test-dev", 170 | "type": "shell", 171 | "command": "make test config=dev", 172 | "problemMatcher": [], 173 | "group": { 174 | "kind": "build", 175 | "isDefault": true 176 | } 177 | }, 178 | { 179 | "label": "format", 180 | "type": "shell", 181 | "command": "make format", 182 | "problemMatcher": [], 183 | "group": { 184 | "kind": "build", 185 | "isDefault": true 186 | } 187 | } 188 | ] 189 | } 190 | -------------------------------------------------------------------------------- /tests/unit/samples_data/SPHERE_S_GSP.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 25 | 42 | 45 | 47 | 50 | 53 | 56 | 58 | 60 | 63 | 66 | 73 | 76 | 83 | 89 | 95 | 101 | 108 | 119 | 126 | 134 | 138 | 142 | 150 | 158 | 165 | 172 | 178 | 184 | 190 | 191 | 192 | 193 | 194 | 201 | 207 | 208 | 209 | --------------------------------------------------------------------------------