Programatically insert a SVG file into Writer document from a macro (with a correct size)

Hello, I would like to programatically embed a SVG file into a Writer document (from a macro). I’m aware of the example on page 380 in Andrew Pitonyak’s book, however the issue is that the RecommendGraphSize function (listed on page 379) doesn’t seem to work with SVGs, and therefore the image is embedded, but only as a tiny square.

image

One other thing that I’m aware is that when drag & dropping the SVG file into writer, the image is inserted with the aspect ratio and size that I would expect, so the functionality is definitely implemented in Writer, and the question is mainly about whether there is any way to use it from a macro.

image

What exactly is the reason for inserting an SVG file?

Broadly speaking, I’d like to generate diagrams from markup. Specifically I’m trying to fix this extension, because it currently doesn’t use SVG, so the images don’t look very good when zoomed.

1 Like

can you post an svg file?

This works like a charm for me …

Sub Main
	oDoc = ThisComponent
	sUrl = ConvertToUrl("nicubunu_People_faces_seraphim.svg") 'from https://freesvg.org/angel-girl-with-earring

	oText = oDoc.getText()
	oCursor = oText.createTextCursor()
	oCursor.goToStart(FALSE)
	
	oProvider = createUnoService("com.sun.star.graphic.GraphicProvider")
	oGraph = oDoc.createInstance("com.sun.star.text.GraphicObject")
	
	Dim oProps(0) as new com.sun.star.beans.PropertyValue
	oProps(0).Name = "URL"
	oProps(0).Value = sURL
	
	oGraph.Graphic = oProvider.queryGraphic(oProps) 'com.sun.star.graphic.XGraphic
	oGraph.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
	
	oGraph.Size = oGraph.Graphic.Size100thMM
	
	oText.insertTextContent( oCursor, oGraph, False )
End Sub
2 Likes

Try this macro, it uses the coefficient coef to recalculate the size of inserted SVG.

Sub PasteSVG
	dim sUrlSVG$
	sUrlSVG=ConvertToUrl("d:\a.svg") 'path to your file
	insertSVG(sUrlSVG)
End Sub


Sub insertSVG(sSVG$) 'sSVG is url to your file; or direct "body" of SVG
	dim oDoc as object, oShape as object, oSize as new com.sun.star.awt.Size, oSVG as object, oDlg as object
	oDoc=ThisComponent
	oSVG=urlSVG(sSVG) 'object with SVG
	rem object SVG
	const coef=0.4896 'coefficient to reduce the size of SVG (simulation of change the DPI)
	with oSize
		.Width=oSVG.Size100thMM.Width * coef
		.Height=oSVG.Size100thMM.Height * coef
	end with
	oShape=oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
	with oShape
		.Graphic=oSVG
		.AnchorType=com.sun.star.text.TextContentAnchorType.AS_CHARACTER
		.VertOrient=com.sun.star.text.VertOrientation.CHAR_CENTER
		.setSize(oSize)
	end with
	oDoc.DrawPage.add(oShape) 'paste to document
End Sub


Function urlSVG(sUrl$) as object 'graphic object from SVG file
	dim oSfa as object, oTextStream as object, oStream as object, oProvider as object, oSVG as object, props(0) as new com.sun.star.beans.PropertyValue
	sUrl=ConvertToURL(sUrl)
	oSfa=CreateUNOService("com.sun.star.ucb.SimpleFileAccess")
	oStream=oSfa.openFileRead(sUrl)
	oTextStream=CreateUNOService("com.sun.star.io.TextInputStream")
	with oTextStream
		.InputStream=oStream
		.Encoding="UTF-8"
	end with
	oProvider=createUnoService("com.sun.star.graphic.GraphicProvider")
		props(0).Name="InputStream" : props(0).Value=oStream
	oSVG=oProvider.queryGraphic(props) 'graphic object
	oTextStream.closeInput
	oStream.closeInput
	urlSVG=oSVG
End Function

How I got the coef? If some image is inserted via menu Insert > Image then it is sized according to DPI. And my experience is the image with DPI 165 is for size 1:1 (on Windows10). But mostly I have images with DPI 110, so I simulate the change of DPI by the change of image-size in the ratio 110/165=2/3 → example.

So I inserted SVG via menu Insert > Image and decreased its size by 2/3 and read its property Size.Height. Then I inserted SVG via macro and also read its property Size.Height. And the coef is ratio of these two Heights.


For reading the Sizes of elements in document I use macro for Xray

Sub xrayEl 'xray the selected element
	GlobalScope.BasicLibraries.LoadLibrary("XrayTool")
	dim oDoc as object, oSel as object, o as object
	oDoc=ThisComponent
	oSel=oDoc.CurrentController.getSelection
	if isEmpty(oSel) then exit sub
	o=oSel.getByIndex(0)
	xray o
End Sub