Page 1 of 1
Insert SVG via macro into a writer document
Posted: Thu Aug 17, 2017 1:23 pm
by bassklampfe
I want to generate SVG's by Macros and then insert them into a writer document.
Example of SVG (this one is simple, will be much more complex later on)
Code: Select all
dim svg as string
svg="<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg=svg+"<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg=svg+"</svg>
Now: How can I insert this as a draw:frame ?
Thanks for any help?
Re: Insert SVG via macro into a writer document
Posted: Thu Aug 17, 2017 8:38 pm
by musikai
If anyone has a direct solution for that I would be interested in it as well.
My solution was a workaround by first writing the files to disk and then importing them:
For OO:
https://extensions.openoffice.org/de/node/18448
For LibO:
https://extensions.libreoffice.org/exte ... infoframes
Here someone directly creates draw shapes (not svg):
viewtopic.php?f=20&t=89330
Re: Insert SVG via macro into a writer document
Posted: Thu Aug 17, 2017 8:47 pm
by RoryOF
Andrew Pitonyak gives a macro for pasting HTML then embedding linked graphics in section 14.4 of
OpenOffice.org Macros Explained.odt
It should be simple enough to split out the graphic embedding code.
Re: Insert SVG via macro into a writer document
Posted: Fri Aug 18, 2017 2:51 pm
by bassklampfe
Thanks for all the suggestions. This is, how far I have done it for now
Code: Select all
REM ***** BASIC *****
Option Explicit
Sub Main
Dim document As Object
document = ThisComponent.CurrentController.Frame
Dim svg As String
svg="<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg=svg & "<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg=svg & "</svg>"
dim imgUrl as string
imgUrl=SaveAsTemp(svg)
InsertImage(document,imgUrl)
End Sub
Function InsertImage(document As Object,imgUrl As String)
Dim dispatcher As Object
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "FileName"
args1(0).Value = imgUrl
args1(1).Name = "AsLink"
args1(1).Value = false
dispatcher.executeDispatch(document, ".uno:InsertGraphic", "", 0, args1)
End Function
Function SaveAsTemp(text As String) As String
Dim ps As Object
ps = CreateUnoService("com.sun.star.util.PathSettings")
Dim tempDir As String
tempDir = ps.Temp
Dim Path as String
Path=tempDir & "/" & "svg.svg"
Dim FileNo As Integer
FileNo = FreeFile()
Open convertfromUrl(Path) For Output As #FileNo
Print #FileNo, text
Close #FileNo
SaveAsTemp=Path
End Function
But I still miss some properties. In a document created by the script I find the following in content.xml
Code: Select all
<draw:frame draw:style-name="fr2" draw:name="Bild2" text:anchor-type="paragraph" svg:width="2.646cm" svg:height="2.646cm" draw:z-index="2">
<draw:image xlink:href="Pictures/1000009900000A5600000A56E219DBE3638A9F01.svg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
<draw:image xlink:href="Pictures/100002010000006400000064E49D1618500EBFEF.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
</draw:frame>
I'd like to change "text:anchor-type" to "as-char" and update "svg:width" and "svg:height".
How to do this before the insert? Or get the draw object and change the properties?
Thanks for any help. Regards
Re: Insert SVG via macro into a writer document
Posted: Fri Aug 18, 2017 2:58 pm
by RoryOF
I think this might help
Code: Select all
AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
Re: Insert SVG via macro into a writer document
Posted: Fri Aug 18, 2017 3:22 pm
by bassklampfe
Ok, thanks! But where to add this in my macro?
Re: Insert SVG via macro into a writer document
Posted: Sat Aug 19, 2017 1:03 pm
by musikai
bassklampfe wrote:I'd like to change "text:anchor-type" to "as-char" and update "svg:width" and "svg:height".
How to do this before the insert? Or get the draw object and change the properties?
The easiest way to change the size would be your second idea. As the graphic is still selected after inserting it by the dispatcher you can just add this at the end to your "main":
Code: Select all
Dim selection as Object
selection = ThisComponent.CurrentSelection
If selection.ImplementationName <> "SwXTextGraphicObject" Then
Exit Sub
End If
Dim newHeight as long
Dim newWidth as long
newHeight = 1000
newWidth = 1000
selection.Height = newHeight
selection.Width = newWidth
To change the anchor to "as Character" add
Code: Select all
selection.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
BUT this conversion of the anchor will move your image to the start of the line.
So to have more control of where to insert the image it is better to not use the dispatcher but insert it as described in Pitonyak book, chapter 14.3.
Note: Despite your argument "AsLink" the image you inserted with the dispatcher is embedded. (which is a good thing I think).
Re: Insert SVG via macro into a writer document
Posted: Sun Aug 20, 2017 8:29 am
by bassklampfe
Thanks for the suggestions, I will come back to you when I made progress...
Re: Insert SVG via macro into a writer document
Posted: Sun Aug 20, 2017 10:00 am
by bassklampfe
Ok, now this is my current code:
Code: Select all
Option Explicit
Sub Main
Dim svg As String
svg = "<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg = svg & "<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg = svg & "</svg>"
dim imgUrl as string
imgUrl = SaveAsTemp(svg)
InsertGraphicObject(ThisComponent,imgUrl)
End Sub
Function SaveAsTemp(text As String) As String
Dim ps As Object
ps = CreateUnoService("com.sun.star.util.PathSettings")
Dim tempDir As String
tempDir = ps.Temp
Dim Path as String
Path=tempDir & "/" & "svg.svg"
Dim FileNo As Integer
FileNo = FreeFile()
Open convertfromUrl(Path) For Output As #FileNo
Print #FileNo, text
Close #FileNo
SaveAsTemp=Path
End Function
Sub InsertGraphicObject(oDoc, imgUrl)
Dim oText
oText = oDoc.getText()
Dim oCursor
oCursor = oText.createTextCursor()
oCursor.goToStart(FALSE)
Dim oGraph
oGraph = oDoc.createInstance("com.sun.star.text.GraphicObject")
With oGraph
.GraphicURL = imgUrl
.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
End With
oText.insertTextContent( oCursor, oGraph, False )
End Sub
Works, but now the graphic is inserted as external linked item. How can I "unlink" this in the macro?
I also tried to insert the graphic as data url
Code: Select all
Option Explicit
Sub Main
Dim svg As String
svg="<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg=svg & "<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg=svg & "</svg>"
dim imgUrl as string
imgUrl="data:image/svg+xml;base64,"&EncodeBase64(svg)
InsertGraphicObject(ThisComponent,imgUrl)
End Sub
Function EncodeBase64(binData As String)
Dim siz As Integer : siz=Len(binData)
Dim b1,b2,b3,b123,r1,r2,r3,r4,i As Integer
Dim B64 As String : B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
Dim s As String
For i = 1 To siz Step 3
b1=ASC(Mid(binData,i+0,1))
If i+1 <= siz then
b2=ASC(Mid(binData,i+1,1))
Else
b2=0
End If
If i+2 <= siz then
b3=ASC(Mid(binData,i+2,1))
Else
b3=0
End If
b123=(b1*256+b2)*256+b3
r4 = b123 MOD 64 : b123 = (b123-r4)/64
r3 = b123 MOD 64 : b123 = (b123-r3)/64
r2 = b123 MOD 64
r1 = (b123-r2)/64
s = s & Mid(B64,R1+1,1)
s = s & Mid(B64,R2+1,1)
If i+1 <= siz then
s = s & Mid(B64,R3+1,1)
Else
s=s & "="
End If
If i+2 <= siz then
s = s & Mid(B64,R4+1,1)
Else
s=s & "="
End If
Next
EncodeBase64=s
End Function
Sub InsertGraphicObject(oDoc, imgUrl)
Dim oText
oText = oDoc.getText()
Dim oCursor
oCursor = oText.createTextCursor()
oCursor.goToStart(FALSE)
Dim oGraph
oGraph = oDoc.createInstance("com.sun.star.text.GraphicObject")
With oGraph
.GraphicURL = imgUrl
.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
End With
oText.insertTextContent( oCursor, oGraph, False )
End Sub
But then the image is only displayed as an "inline image" placeholder. The Circle is only displayed in the property page. And it's lost, when I manually unink the graphic.
Any suggestions? Thanks for your help.
Re: Insert SVG via macro into a writer document
Posted: Sun Aug 20, 2017 9:58 pm
by musikai
I think the base64-way is for embedding pictures into an html-page. In Pitonyak's book chapter 14.3 he describes how to embed images into the writer document.
I left his helper apps out (for guessing image size, you can give it ) and make use of the viewcursor instead of the textcursor, so that the graphic will be inserted at the cursor and not at the start of document. (but you will get an error if you run the macro while you have an image selected because then there is no viewcursor.)
Code: Select all
REM ***** BASIC *****
Option Explicit
Sub Main
Dim svg As String
svg = "<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg = svg & "<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg = svg & "</svg>"
dim imgUrl as string
imgUrl = SaveAsTemp(svg)
Dim oHeight as long
Dim oWidth as long
oHeight = 1000
oWidth = 1000
InsertEmbeddedGraphicObject(ThisComponent,imgUrl, oHeight,oWidth)
End Sub
Function SaveAsTemp(text As String) As String
Dim ps As Object
ps = CreateUnoService("com.sun.star.util.PathSettings")
Dim tempDir As String
tempDir = ps.Temp
Dim Path as String
Path=tempDir & "/" & "svg.svg"
Dim FileNo As Integer
FileNo = FreeFile()
Open convertfromUrl(Path) For Output As #FileNo
Print #FileNo, text
Close #FileNo
SaveAsTemp=Path
End Function
Sub InsertEmbeddedGraphicObject(oDoc, imgUrl,oHeight,oWidth)
Dim oShape
Dim oGraph 'Das Grafikobjekt ist Textcontent.
Dim oProvider 'Der Service GraphicProvider.
rem Dim oText
oShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
oGraph = oDoc.createInstance("com.sun.star.text.GraphicObject")
oDoc.getDrawPage().add(oShape)
oProvider = createUnoService("com.sun.star.graphic.GraphicProvider")
Dim oProps(0) as new com.sun.star.beans.PropertyValue
oProps(0).Name = "URL"
oProps(0).Value = imgUrl
oShape.Graphic = oProvider.queryGraphic(oProps())
oGraph.graphicurl = oShape.graphicurl
oGraph.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
oGraph.Height = oHeight
oGraph.Width = oWidth
Dim oText
oText = oDoc.getText()
Dim oVCurs
oVCurs = oDoc.CurrentController.getViewCursor()
rem Dim oCursor
rem oCursor = oText.createTextCursor()
rem oCursor.goToStart(FALSE)
oText.insertTextContent( oVCurs, oGraph, False )
oDoc.getDrawPage().remove(oShape)
End Sub
Re: Insert SVG via macro into a writer document
Posted: Tue Aug 22, 2017 11:04 am
by bassklampfe
Just to give you a status: I'm making progress and I'm now working on the real graphics to insert (converting an existing Lua-Script to Basic). Meanwhile I have a second problem. I need to add a Caption ¹) to the graphic. It shall be above the graphic and needs formatting with Subscript and Superscript. Any suggestions?
Regards and Thanks for all your support.
¹) I believe this is the right term. My Libreoffice is german.
Re: Insert SVG via macro into a writer document
Posted: Tue Aug 22, 2017 11:38 am
by musikai
Yesterday i asked myself for what one can make use of this macro. Are you going to program a chord diagram inserter?
Normal captions in lo are constructed by a textframe into which the caption text is inserted and the graphic is anchored in. Of course you could just add the ctext to the normal paragraph but then you can't move the whole thing as an unity. Another solution could be to add the ctext directly into the generated svg.
Re: Insert SVG via macro into a writer document
Posted: Tue Aug 22, 2017 12:02 pm
by bassklampfe
musikai wrote:Yesterday i asked myself for what one can make use of this macro. Are you going to program a chord diagram inserter?
You're a clever guy
Yes, Indeed! Until now I had a Lua-Script, which generated A HTML-Page with embedded SVG-Graphics. This I copy'n'paste into my documents. Now I want to realize it in OO. Basic Idea: Enter a string like Gm:355333B3L3 , hit the Hotkey for the macro and get something like the attached SVG inserted into the Document.
In Lua I add the Chord name to SVG as text, but this seams impossible in OO-Basic, as I cannot get the TextExtends from the TrueTypeFont. Therefore I want to use the Caption
Re: Insert SVG via macro into a writer document
Posted: Wed Aug 23, 2017 12:26 pm
by bassklampfe
Just a short update: Managed the TextFrame task, now finalising the SVG stuff and the iterate over text selections task.
Thanks for your support...
Re: Insert SVG via macro into a writer document
Posted: Wed Aug 23, 2017 2:48 pm
by musikai
Perhaps a good thing you have separated the chord text from the grid, so you can change its size independently.
About the superscript and subscript.
Normal text:
Code: Select all
sub editselectedcharsNormal
oViewcursor = thiscomponent.CurrentController.getViewcursor()
oText=oViewcursor.text
oViewcursor.CharEscapement = 0
oViewcursor.CharEscapementHeight = 100
end sub
Superscript:
Code: Select all
sub editselectedcharsSuperscript
oViewcursor = thiscomponent.CurrentController.getViewcursor()
oText=oViewcursor.text
oViewcursor.CharEscapement = 101
oViewcursor.CharEscapementHeight = 58
end sub
Subscript:
Code: Select all
sub editselectedcharsSubscript
oViewcursor = thiscomponent.CurrentController.getViewcursor()
oText=oViewcursor.text
oViewcursor.CharEscapement = -101
oViewcursor.CharEscapementHeight = 58
end sub
Somehow your project inspired me to dive into Writer's own capabilities to create Draw-shapes by macro.
https://wiki.openoffice.org/wiki/Docume ... f_Drawings
Thanks for that and good wishes for your project

Re: Insert SVG via macro into a writer document
Posted: Wed Aug 23, 2017 4:15 pm
by hubert lambert
Hello,
If it helps, here is a function that creates a graphic object directly from the text definition of a svg:
Code: Select all
function getXGraphicFromSVGString(svg_string)
pipe = createUnoService("com.sun.star.io.Pipe")
outstream = createUnoService("com.sun.star.io.TextOutputStream")
outstream.setOutputStream(pipe)
outstream.writeString(svg_string)
dim bytes()
pipe.readBytes(bytes, pipe.available)
instream = com.sun.star.io.SequenceInputStream.createStreamFromSequence(bytes)
GP = createUnoService("com.sun.star.graphic.GraphicProvider")
dim props(0) as new com.sun.star.beans.PropertyValue
props(0).Name = "InputStream"
props(0).value = instream
graphic = GP.queryGraphic(props())
outstream.closeOutput()
instream.closeInput()
getXGraphicFromSVGString = graphic
end function
The function can be used this way:
Code: Select all
svg="<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg"">"
svg=svg+"<circle cx=""50"" cy=""50"" r=""50"" style=""fill:red;stroke:green;stroke-width=5px;""/>"
svg=svg+"</svg>"
shape = doc.createInstance("com.sun.star.drawing.GraphicObjectShape")
graphic = getXGraphicFromSVGString(svg)
shape.Graphic = graphic
Re: Insert SVG via macro into a writer document
Posted: Wed Aug 23, 2017 6:05 pm
by bassklampfe
@hubert lambert : Thanks for the snippet. For now I'm happy with the temp files, they allow me to review the generated svg's in a texteditor. But finally I will verify if getXGraphicFromSVGString does work for me.
Re: Insert SVG via macro into a writer document
Posted: Wed Aug 23, 2017 6:07 pm
by bassklampfe
@musikai : Thanks. Formatting the Chord name is a seperate task, I will have to do. Your snippets will help
Re: Insert SVG via macro into a writer document
Posted: Sun Oct 22, 2017 1:35 pm
by musikai
Hi bassklampfe,
as your thread inspired me to look how draw elements could be used to create chord grids here is what evolved from that:
viewtopic.php?f=47&t=90857