Svg scale factor

It seems the importer does not correctly interpret inches… Maybe that should be reported as a bug…

Ah yes, very true, but then “correctly defined” is the issue, isn’t it?

Unfortunately the programs I use to create vector art – usually logos and type treatments – are Sketch and Adobe Illustrator, and as lqppro pointed out, they convert the output units to pixels.

So no matter if my document settings are metric or imperial, my 1000mm artboard gets converted to viewBox="0 0 2834.6 2834.6" in the export.

There may be a workaround to force Illustrator to write as metric, but I haven’t found it yet.

If I’m making something I know will go into Blender, my SOP is to work on an artboard with one or both sides sized to 1,000 pixels. Then, when all is finished and ready for export, I scale the entire mamma jamma up to 354.4 percent or to 3,544 pixels, and export to SVG.

It occurs to me that a possible workaround might be to export the document to SVG without scaling – meaning one or both sides would remain at 1,000 pixels – and then open the SVG file in a text editor and add width="1000mm" height="1000mm".

All in all tho, I think signguy wins the Simplest Solution trophy for “scale to 125%”. This seems like the kind of useful info that should be added to https://docs.blender.org/manual/en/latest/addons/import_export/curve_svg.html.


Followup: I tested it on my sample file, and adding width="1000mm" height="1000mm" to the svg tag brings the square in at 1 meter, even tho the viewbox is set to 0 0 3544 3544.

Setting it to 500mm brings it in at 0.5 meters, so it looks like the results are consistent and controllable.

I’ll have to play with SVGs of different artboard sizes and aspect ratios to see where things break, but it’s a useful bit of info, so thanks for the tip!

It seems I was wrong at first. The SVG importer in Blender does not work correctly at least when I test it. It fails to interpret the units correctly in a lot of cases. That’s a disappointment. I would not trust any particular workflow for all possible ways SVG file can be saved in. I think it makes sense to double-check the dimensions when importing SVG.

I have to import various vector drawings to my scenes often in many different formats and different units, so I have written myself a script for scaling based on known distance between 2 verts of a mesh. It only works for single mesh object because I usually merge the drawings and convert them to mesh for what I do, but maybe it could be useful in this context. Here it is: https://blender.stackexchange.com/a/288942/60759

I think Import as Grease Pencil works almost correctly importing ( grease pencil lines have a thickness so when converting they produce double lines…)
But you can set the scale to 1.0 on the import and get only minor rounding errors…
In Inches…


After you convert the Grease Pencil lines to Curves…
Then you can either keep it as a curve or convert it to a mesh…

This is my experience, as well. It’s not just a matter of not interpolating units, but not interpreting them at all. As a test a moment ago, I made an SVG in illustrator that’s 1000 pixels wide - blender imports this as 0.281 M wide. Ok, let’s change the Illustrator document to millimeters - blender still imports it at 0.281 M wide. Why is the import at 28%? I suppose because 72dpi file equals 100dpi - 72dpi = 28dpi? What a weird way to do math for importing.

At bare minimum, it would be nice if there was a “scale import” option when you import the vector, similar to the OBJ options.

It does something with the units:

units = {"": 1.0,
         "px": 1.0,
         "in": 90.0,
         "mm": 90.0 / 25.4,
         "cm": 90.0 / 2.54,
         "pt": 1.25,
         "pc": 15.0,
         "em": 1.0,
         "ex": 1.0,
         "INVALID": 1.0,  # some DocBook files contain this
         }

and

class SVGGeometrySVG(SVGGeometryContainer):
    """
    Main geometry holder
    """

    def _doCreateGeom(self, instancing):
        """
        Create real geometries
        """

        rect = SVGRectFromNode(self._node, self._context)

        matrix = self.getNodeMatrix()

        # Better SVG compatibility: match svg-document units
        # with blender units

        viewbox = []
        unit = ''

        if self._node.getAttribute('height'):
            raw_height = self._node.getAttribute('height')
            token, last_char = read_float(raw_height)
            document_height = float(token)
            unit = raw_height[last_char:].strip()

        if self._node.getAttribute('viewBox'):
            viewbox = parse_array_of_floats(self._node.getAttribute('viewBox'))

        if len(viewbox) == 4 and unit in ('cm', 'mm', 'in', 'pt', 'pc'):

            #convert units to BU:
            unitscale = units[unit] / 90 * 1000 / 39.3701

            #apply blender unit scale:
            unitscale = unitscale / bpy.context.scene.unit_settings.scale_length

            matrix = matrix @ Matrix.Scale(unitscale, 4, Vector((1.0, 0.0, 0.0)))
            matrix = matrix @ Matrix.Scale(unitscale, 4, Vector((0.0, 1.0, 0.0)))

        # match document origin with 3D space origin.
        if self._node.getAttribute('viewBox'):
            viewbox = parse_array_of_floats(self._node.getAttribute('viewBox'))
            matrix = matrix @ matrix.Translation([0.0, - viewbox[1] - viewbox[3], 0.0])

        self._pushMatrix(matrix)
        self._pushRect(rect)

        super()._doCreateGeom(False)

        self._popRect()
        self._popMatrix()


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': {},
                         'rects': [rect],
                         'rect': rect,
                         'matrix_stack': [],
                         'matrix': m,
                         'materials': {},
                         'styles': [None],
                         'style': None,
                         'do_colormanage': do_colormanage,
                         'collection': collection}

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

But that doesn’t seem to work.

As a non-coder, I don’t see the need to re-interpolate the size as it comes into blender. SVG is just vectors - there’s no “loss” in enlarging. Though I may design a piece of art that prints at 6" x 6", the likelihood that I need to covert that to meters in Blender (and use it at the 6" x 6" size) is - never. Blender has a scaling tool, so even if I did

  1. I can do the math myself, afterwards
  2. I’d probably not be working in both imperial and metric units to start with

Blender should just convert everything to it’s own unit, 1 to 1, have the user choose an overall import scale, and be done with it. Would be far better than what happens now which is - mystery size, and sometimes 1800% smaller than can even be seen in the viewport.

i switch a lot depending on the work i do, either from CAD to blender or from affinity designer to blender.
The former is in mm’s normally, i allready get there in the situation that i always forget (ooh you silly boy hahaha) that blender settings are standard in m (at least in my configuration, did not look to see how to change the startup files ) so they blew up a 1000 times standard. The last things i import, according to above indeed seemde to work with the 1.25x factor, and 72DPI setting. But i have to check cause if i forget that i didnt not convert (native files are 400 DPI) i allready have to scale. But thats fine, just two numbers, and as affinity is 1:1 scale i just copy the numbers as i work 1:1 real life scale in blender as well. so that works for now (for me)

Well, you can definitely work with any units in Blender with no math required. All length input fields support units and even modal operators have advanced numerical input that takes any units on the fly and converts them to whatever you have set for your scene. I think it would be nice if it managed to deal with units while importing drawings as well. There is no reason it shouldn’t. I believed it did… Apparently I was wrong. That’s a programing mistake in the importer. It’s a pity. I make interior design visualisations and have to model various real products, so I often have to use whatever technical drawings manufacturers provide… and those come in all sorts of formats, shapes and sizes :smiley: It would be nice if software made life easier by dealing with them correctly. I am a bit disappointed with Blender and SVG.

Hm. Now that you mention it, adding a Transform section to the Tool Properties side panel during import would be a great feature.

The OBJ importer, for example, includes fields for Scale, Clamp, and Axes.

Options for Scale and even fixed X and Y dimensions would be very useful.

Perhaps one of you hardy souls might be willing to post this suggestion to Right-Click Select?

To export propper svg scale from Illustrator set ruler or document setup to mm instead of inches.
Have all software ecosystem set to inches including Blender, but only this trick worked for me.