4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クリップボードのSVGデータをBlenderのパスに変換するスクリプト

Posted at

blenderではSVGのベクターデータをカーブとして読み込む機能があります
また、現行のPhotoshopではベクトルマスクのあるレイヤのコンテクストメニューから
テキストデータとしてクリップボードにコピーする機能があります
image.png
コピーしたものを メモ帳にペーストするとこんな感じです。
image.png
このままSVGの拡張子で保存すれば PhotoshopからBlenderへ 塗りを含めたベクトルデータとして渡せます

ただ、個人的に業務で使う頻度が増え いちいち一時ファイルを作るのも面倒になったために
クリップボードから直接カーブを作成するスクリプトを作ってみました

現在業務で使っているのがBlender3.3なのでBlender3.3の内容になります
試しに3.6で使ってみたところ 引用したコードに僅かな違いがあり動かない様子だったのでご注意を

既存アドオンのライブラリを利用する

とはいっても 既存のアドオンの機能で完全に動いているので書き直しは無駄です
アドオンフォルダにある io_curve_svg のコードを読んでみます。
このアドオンは__init__.pyにGUIまわりの操作が書かれていて
import_svg.py のload_svg関数の実行をしているようです
image.png
また読み込み処理の大まかな部分はSVGGeometryContainerを継承したSVGLoaderクラスで行っていて
xml.dom.minidom.parse(filepath) でファイルで指定したデータのXMLデータをパースすることで
SVGのデータを取得しているようです。

まずはこの部分をコピペして 既存アドオンのライブラリを利用するスクリプトをテストしてみます

testimport.py
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy

import xml.dom.minidom
from mathutils import Vector, Matrix
from io_curve_svg.import_svg import SVGGeometryContainer

class SVGLoader(SVGGeometryContainer):
    """
    SVG file loader
    """
    def getTransformMatrix(self):
        """
        Get matrix created from "transform" attribute
        """
        # SVG document doesn't support transform specification
        # it can't even hold attributes

        return None

    def __init__(self, context, filepath, do_colormanage):
        """
        Initialize SVG loader
        """
        import os
        svg_name = os.path.basename(filepath)
        scene = context.scene
        collection = bpy.data.collections.new(name=svg_name)
        scene.collection.children.link(collection)

        node = xml.dom.minidom.parse(filepath)

        m = Matrix()
        m = m @ Matrix.Scale(1.0 / 90.0 * 0.3048 / 12.0, 4, Vector((1.0, 0.0, 0.0)))
        m = m @ Matrix.Scale(-1.0 / 90.0 * 0.3048 / 12.0, 4, Vector((0.0, 1.0, 0.0)))

        rect = (0, 0)

        self._context = {'defines': {},
                         'transform': [],
                         'rects': [rect],
                         'rect': rect,
                         'matrix': m,
                         'materials': {},
                         'styles': [None],
                         'style': None,
                         'do_colormanage': do_colormanage,
                         'collection': collection}

        super().__init__(node, self._context)

def load_svg(context, filepath, do_colormanage):
    """
    Load specified SVG file
    """
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')

    loader = SVGLoader(context, filepath, do_colormanage)
    loader.parse()
    loader.createGeom(False)

context = bpy.context
do_colormanage = context.scene.display_settings.display_device != 'NONE'
# デスクトップにあるtest.svgを読み込む
import os
desktop_dir = os.path.expanduser('~/Desktop')
filepath = os.path.join(desktop_dir,'test.svg')
load_svg(context, filepath, do_colormanage)

コード内にファイルパス直書きで とりあえずの動作が確認できました

クリップボードからの読み込み

これを今回の目的のクリップボードからの読み込みに書き直してみます
とはいっても クリップボードのテキストを取得する bpy.context.window_manager.clipboard を使って
XMLのパースをxml.dom.minidom.parseString() でテキストデータから行うようにして整理するだけです

SVGcurve_from_clipboard.py
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
import xml.dom.minidom

from mathutils import Vector, Matrix
from io_curve_svg.import_svg import SVGGeometryContainer

class SVGLoaderClipboard(SVGGeometryContainer):
    """
    SVG file loader
    """
    def getTransformMatrix(self):
        """
        Get matrix created from "transform" attribute
        """
        # SVG document doesn't support transform specification
        # it can't even hold attributes
        return None

    def __init__(self, context, SVGstring, do_colormanage):
        """
        Initialize SVG loader
        """
        collection = context.scene.collection

        node = xml.dom.minidom.parseString(SVGstring, parser=None)

        m = Matrix()
        m = m @ Matrix.Scale(1.0 / 90.0 * 0.3048 / 12.0, 4, Vector((1.0, 0.0, 0.0)))
        m = m @ Matrix.Scale(-1.0 / 90.0 * 0.3048 / 12.0, 4, Vector((0.0, 1.0, 0.0)))

        rect = (0, 0)

        self._context = {'defines': {},
                         'transform': [],
                         'rects': [rect],
                         'rect': rect,
                         'matrix': m,
                         'materials': {},
                         'styles': [None],
                         'style': None,
                         'do_colormanage': do_colormanage,
                         'collection': collection}

        super().__init__(node, self._context)

context = bpy.context
do_colormanage = context.scene.display_settings.display_device != 'NONE'
# クリップボードのテキストを取得
SVGstring = bpy.context.window_manager.clipboard
if bpy.ops.object.mode_set.poll():
    bpy.ops.object.mode_set(mode='OBJECT')
if SVGstring:
    loader = SVGLoaderClipboard(context, SVGstring, do_colormanage)
    loader.parse()
    loader.createGeom(False)

少しだけシンプルな動作にしました 何かの参考になれば幸いです
image.png

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?