├── test-requirements.txt ├── .gitattributes ├── pytest.ini ├── images ├── enable-addon.png ├── install-button.png ├── open-item-panel.png ├── selector-usage.png ├── menu-search-usage.png └── simple-transform-panel.png ├── .editorconfig ├── .gitignore ├── package.json ├── tests ├── conftest.py ├── test_addon_registered.py └── test_add_icons.py ├── helpers.py ├── LICENSE.md ├── .github └── workflows │ ├── verify.yml │ └── publish.yml ├── README.md └── simple_icons_blender.template /test-requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | pytest-blender 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | simple_icons_blender.py -diff 3 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = -sx 3 | blender-addons-dirs = . 4 | -------------------------------------------------------------------------------- /images/enable-addon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/enable-addon.png -------------------------------------------------------------------------------- /images/install-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/install-button.png -------------------------------------------------------------------------------- /images/open-item-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/open-item-panel.png -------------------------------------------------------------------------------- /images/selector-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/selector-usage.png -------------------------------------------------------------------------------- /images/menu-search-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/menu-search-usage.png -------------------------------------------------------------------------------- /images/simple-transform-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mondeja/simple-icons-blender/HEAD/images/simple-transform-panel.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | 13 | [*.template] 14 | indent_size = 4 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | node_modules/ 3 | *.backup 4 | *.zip 5 | .pytest_cache/ 6 | htmlcov/ 7 | package-lock.json 8 | *.blend1 9 | *.mp4 10 | *.gif 11 | failed-slugs.txt 12 | scripts/showcase/frames/ 13 | scripts/showcase/inkscape-pngs/ 14 | build-failed-slugs-list.js 15 | __pycache__/ 16 | *.tar.xz 17 | blender-*/ 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-icons-blender", 3 | "version": "16.2.0", 4 | "description": "Blender Simple Icons addon", 5 | "scripts": { 6 | "build": "node build.js" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "simple-icons": "16.2.0" 13 | }, 14 | "type": "module" 15 | } 16 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import pytest 5 | 6 | ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 7 | if ROOT_DIR not in sys.path: 8 | sys.path.append(ROOT_DIR) 9 | 10 | from helpers import simple_icons_slugs as _simple_icons_slugs 11 | 12 | @pytest.fixture 13 | def simple_icons_slugs(): 14 | return _simple_icons_slugs() 15 | -------------------------------------------------------------------------------- /tests/test_addon_registered.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def test_addon_registered(simple_icons_slugs): 4 | import _bpy 5 | import addon_utils 6 | 7 | # check addon registered 8 | installed_addons = [addon.__name__ for addon in addon_utils.modules()] 9 | assert "simple_icons_blender" in installed_addons 10 | 11 | # check addon operators registered 12 | current_operators = [cls.__name__ for cls in _bpy.types.Operator.__subclasses__()] 13 | for expected_si_operator in [f"AddSi_{slug}" for slug in simple_icons_slugs]: 14 | assert expected_si_operator in current_operators 15 | -------------------------------------------------------------------------------- /helpers.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def simple_icons_slugs(): 5 | with open("simple_icons_blender.py") as f: 6 | slugs = re.findall( 7 | r'^class AddSi_(.+)\(A,O\):', 8 | f.read(), 9 | re.M, 10 | ) 11 | return slugs 12 | 13 | 14 | def simple_icons_titles(): 15 | with open("simple_icons_blender.py") as f: 16 | titles = re.findall(r'bl_label=(.+);bl_description=', f.read(), re.M) 17 | return [title.strip("'").replace("\\'", "'") for title in titles[:-1]] 18 | 19 | 20 | def simple_icons_svgs(): 21 | with open("simple_icons_blender.py") as f: 22 | svgs = re.findall(r';si_svg=(.+)$', f.read(), re.M) 23 | return [svg.strip("'").replace("\\'", "'") for svg in svgs] 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Álvaro Mondéjar Rubio 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | test: 12 | name: Test 13 | runs-on: ${{ matrix.platform }} 14 | timeout-minutes: 30 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | platform: 19 | - ubuntu-latest 20 | - macos-latest 21 | blender-version: 22 | - "2.93.9" 23 | - "3.1.2" 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Set up Python 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: 3.x 31 | - name: Cache Blender ${{ matrix.blender-version }} 32 | uses: actions/cache@v4 33 | id: cache-blender 34 | with: 35 | path: | 36 | blender-* 37 | _blender-executable-path.txt 38 | key: ${{ runner.os }}-${{ matrix.blender-version }} 39 | - name: Download Blender ${{ matrix.blender-version }} 40 | if: steps.cache-blender.outputs.cache-hit != 'true' 41 | id: download-blender 42 | run: | 43 | python -m pip install -U pip blender-downloader 44 | echo "$(blender-downloader \ 45 | ${{ matrix.blender-version }} --extract --remove-compressed \ 46 | --print-blender-executable --quiet)" > _blender-executable-path.txt 47 | - name: Install dependencies 48 | id: install-dependencies 49 | run: | 50 | python -m pip install -r test-requirements.txt 51 | blender_executable="$(< _blender-executable-path.txt tr -d '\n')" 52 | python_blender_executable="$(pytest-blender --blender-executable $blender_executable)" 53 | $python_blender_executable -m ensurepip 54 | $python_blender_executable -m pip install pytest 55 | echo "blender-executable=$blender_executable" >> $GITHUB_OUTPUT 56 | - name: Run tests 57 | run: pytest -s --blender-executable "${{ steps.install-dependencies.outputs.blender-executable }}" tests 58 | -------------------------------------------------------------------------------- /tests/test_add_icons.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | 4 | import pytest 5 | 6 | from helpers import simple_icons_slugs, simple_icons_titles 7 | 8 | 9 | @pytest.mark.parametrize( 10 | ('slug', 'title'), 11 | zip(simple_icons_slugs(), simple_icons_titles()) 12 | ) 13 | def test_add_icon_operators(slug, title): 14 | import bpy 15 | 16 | # add icon 17 | op_executor = getattr(bpy.ops.mesh, f"si_{slug}") 18 | assert op_executor() == {"FINISHED"} 19 | 20 | # get added icon (created inside a new collection) 21 | last_collection = bpy.context.scene.collection.children[-1] 22 | assert last_collection.name == title.replace(os.sep, "-") 23 | last_object = last_collection.all_objects[-1] 24 | 25 | # check that icon is properly added 26 | assert bpy.context.active_object == last_object 27 | assert last_object in bpy.context.selected_objects 28 | 29 | assert last_object.type == "CURVE" 30 | assert tuple(last_object.location) == (0.0, 0.0, 0.0) 31 | assert re.match(r'SVGMat\.\d+', last_object.active_material.name) 32 | 33 | if slug == "simpleicons": 34 | # test simpleicons icon geometry 35 | bezier_curves_expected_n_points = [13, 5, 5, 12, 4, 4] 36 | assert len(last_object.data.splines) == len(bezier_curves_expected_n_points) 37 | 38 | for i, spline in enumerate(last_object.data.splines): 39 | assert spline.type == "BEZIER" 40 | 41 | n_points = len(spline.bezier_points) 42 | n_expected_points = bezier_curves_expected_n_points[i] 43 | assert n_points == n_expected_points, ( 44 | f"Expected {n_expected_points} points at index {i}, got {n_points}" 45 | ) 46 | 47 | for obj in last_collection.objects: 48 | bpy.data.objects.remove(obj, do_unlink=True) 49 | bpy.data.collections.remove(last_collection) 50 | 51 | # check that was removed 52 | last_collection = bpy.context.scene.collection.children[-1] 53 | assert last_collection.name != title.replace(os.sep, "-") 54 | last_object = last_collection.all_objects[-1] 55 | 56 | # check that icon is properly added 57 | assert last_object.type != "CURVE" 58 | assert last_object.type == "CAMERA" 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simple-icons-blender 2 | 3 | [Simple Icons] Blender addon. Add 2D SVG brand icons to Blender easily. 4 | 5 | Requires Blender v2.93.0 or greater. 6 | 7 | [![Verify Workflow][tests-badge]][tests-link] 8 | 9 | ## Download 10 | 11 | Download the addon using [the next link](https://github.com/mondeja/simple-icons-blender/releases/download/16.2.0/simple_icons_blender.py): 12 | 13 | ```txt 14 | https://github.com/mondeja/simple-icons-blender/releases/download/16.2.0/simple_icons_blender.py 15 | ``` 16 | 17 | If you want to install [another version of Simple Icons][si-releases], change the version 18 | number in the link. 19 | 20 | ## Install 21 | 22 | Under `Edit` -> `Preferences` -> `Add-ons`, press on `Install` and select the 23 | downloaded file: 24 | 25 |
26 |
27 |
33 |
34 |
42 |
43 |
49 |
50 |
56 |
57 |
62 |
63 |