Insert SVG via macro into a writer document

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Insert SVG via macro into a writer document

Post 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?
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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
Last edited by musikai on Thu Aug 17, 2017 9:27 pm, edited 2 times in total.
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
User avatar
RoryOF
Moderator
Posts: 34612
Joined: Sat Jan 31, 2009 9:30 pm
Location: Ireland

Re: Insert SVG via macro into a writer document

Post 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.
Apache OpenOffice 4.1.15 on Xubuntu 22.04.4 LTS
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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
LibreOffice 6.0 on xubuntu 18.04 LTS
User avatar
RoryOF
Moderator
Posts: 34612
Joined: Sat Jan 31, 2009 9:30 pm
Location: Ireland

Re: Insert SVG via macro into a writer document

Post by RoryOF »

I think this might help

Code: Select all

AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
Apache OpenOffice 4.1.15 on Xubuntu 22.04.4 LTS
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post by bassklampfe »

Ok, thanks! But where to add this in my macro?
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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).
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post by bassklampfe »

Thanks for the suggestions, I will come back to you when I made progress...
LibreOffice 6.0 on xubuntu 18.04 LTS
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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.
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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 
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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.
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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.
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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 :super: :super:
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
Attachments
Example SVG Chord (as PNG, because SVG not allowed as attachment)
Example SVG Chord (as PNG, because SVG not allowed as attachment)
Gm=355333B3L3.png (1.56 KiB) Viewed 7760 times
LibreOffice 6.0 on xubuntu 18.04 LTS
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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...
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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 :super:
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
hubert lambert
Posts: 145
Joined: Mon Jun 13, 2016 10:50 am

Re: Insert SVG via macro into a writer document

Post 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
Attachments
svg_from_text.odt
(11.11 KiB) Downloaded 255 times
AOOo 4.1.2 on Win7 | LibreOffice on various Linux systems
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post 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.
LibreOffice 6.0 on xubuntu 18.04 LTS
User avatar
bassklampfe
Posts: 19
Joined: Thu Aug 17, 2017 1:18 pm

Re: Insert SVG via macro into a writer document

Post by bassklampfe »

@musikai : Thanks. Formatting the Chord name is a seperate task, I will have to do. Your snippets will help
LibreOffice 6.0 on xubuntu 18.04 LTS
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Insert SVG via macro into a writer document

Post 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
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
Post Reply