Just for fun with graphics

Hi everyone, wherever you are!

I’ve been working on Windows platform with a simple project that grabs image data from the clipboard and passes it to a dialog box image control.

Private oDlg As Object
Private oImg As Object
Private ImgPath As String
Private AltDown As Boolean

Sub ShowDialog
	
    DialogLibraries.LoadLibrary("Standard")
    oDlg = CreateUnoDialog(DialogLibraries.Standard.ClipDlg)
	
    Dim oSize As New com.sun.star.awt.Size, factor As Double
    Dim oCC, oComponentWindow, oTopWindowPosSize
    oCC = ThisComponent.getCurrentController()
    oComponentWindow = oCC.ComponentWindow
    
    With oComponentWindow
        oWindowPosSize	= .getPosSize()
        oToolKitWorkArea = .Toolkit.WorkArea
        oTopWindowPosSize = .Toolkit.ActiveTopWindow.getPosSize()
    End With
    
    With oSize
        .Width	=	oDlg.Model.Width
        .Height	 =	oDlg.Model.Height
    End With 

    factor = oSize.Width/oDlg.convertSizeToPixel(oSize, com.sun.star.util.MeasureUnit.APPFONT).Width
	
    With oDlg.Model
        .PositionX=(factor*oTopWindowPosSize.Width - .Width) / 2
        .PositionY=(factor*oTopWindowPosSize.Height - .Height) / 2
    End With

    factor = oSize.Width /    oDlg.convertSizeToPixel(oSize, com.sun.star.util.MeasureUnit.APPFONT).Width
	
    With oDlg.Model
        .PositionX=(factor*oTopWindowPosSize.Width - .Width) / 2
        .PositionY=(factor*oTopWindowPosSize.Height - .Height) / 2
    End With
    
    oImg=oDlg.getControl("ImageControl1")
	
    oDlg.Execute()
    oDlg.dispose()

End Sub
	
Sub TopListen_WindowClosing
    ThisComponent.setModified(False)
End Sub
Sub  TopListen_windowOpened
End Sub
Sub  TopListen_windowClosed
End Sub
Sub TopListen_windowMinimized
End Sub
Sub  TopListen_windowNormalized
End Sub
Sub  TopListen_windowActivated
End Sub
Sub  TopListen_windowDeactivated
End Sub
Sub  TopListen_disposing
End Sub


Sub GetImageFromClipBoard()

    Dim oClip As Object, oClipContents As Object, oTypes As Object, i%
    Dim oStream As Object
    Dim sText As String
	
    oClip = createUnoService("com.sun.star.datatransfer.clipboard.SystemClipboard")
    oClipContents = oClip.getContents
    On Error Resume Next
    oTypes = oClipContents.getTransferDataFlavors
	
    If Err <> 0 Then
        Reset : Exit Sub
    End If

For i = LBound(oTypes) To UBound(oTypes)
    
        'MsgBox "MIME-TYPE: " & oTypes(i).MimeType
        If oTypes(i).MimeType = "application/x-openoffice-file;windows_formatname=""FileNameW""" Then
        
        	
            ImgPath = oClipContents.getTransferData(oTypes(i))
            'Of course you could do like this but it's not the idea now	
            'oImg.Model.ImageUrl = ConvertToUrl(ImgPath) 
			
            If EndsWith(LCase(ImgPath), ".jpg") Or EndsWith(LCase(ImgPath), ".jpeg") _
            Or EndsWith(LCase(ImgPath), ".png") Or EndsWith(LCase(ImgPath), ".gif") _
            Or EndsWith(LCase(ImgPath), ".svg") Or EndsWith(LCase(ImgPath), ".tif") _
            Or EndsWith(LCase(ImgPath), ".tiff") Or EndsWith(LCase(ImgPath), ".webp") Then
                isPic = True
            End If
           
		End If
				
		If isPic And oTypes(i).MimeType = "application/x-openoffice-filecontent;windows_formatname=""FileContents""" Then
			oStream = oClipContents.getTransferData(oTypes(i))
			Dim  oInstream As Object
			oInstream=com.sun.star.io.SequenceInputStream.createStreamFromSequence(oStream)
			oStream.CloseInput() : oStream = Nothing
			Dim oProvider As Object
			Dim oObj As Object
			Dim props(0) As New com.sun.star.beans.PropertyValue
			oProvider=createUnoService("com.sun.star.graphic.GraphicProvider")                           
			props(0).Name="InputStream" : props(0).Value = oInstream
			oObj=oProvider.queryGraphic(props)
			oInstream.CloseInput()
			oInstream = Nothing
			oImg=oDlg.getControl("ImageControl1")
			oImg.Model.Graphic=oObj
			oProvider = Nothing
			oObj = Nothing

		End If

        End If

    Next i
    
End Sub


Sub ImgCtlMousUp

    oImg.Model.Graphic = Nothing
    ImgPath = ""
    If Not AltDown Then
        GetImageFromClipBoard
    Else
	'TO DO ... 
	'A routine that grabs the image data from oImg.Model.Graphic object
	'and transfers the data as a Stream to the ClipBoard object
    End If

End Sub

Sub ImgCtlKeyDown(oEvent)

    If oEvent.Modifiers AND com.sun.star.awt.KeyModifier.MOD2 _
    And oEvent.KeyCode = com.sun.star.awt.Key.X Then
        AltDown = True
    End If
	
End Sub

Sub ImgCtlKeyUp(oEvent)
	AltDown = False
End Sub

This no-one-never-needs project works like a charm, but I would like to retrieve the data from a Graphic object and transfer the data back in Stream format to an XTransferable object and further to the clipboard.

Any suggestions?

If the image control is connected to a database field (type BLOB) it is maybe a possible way to copy images into a database. (I usually store only external references like path or url, so I never tried…)

This is not the case, I copy an image file to the clipboard by right-clicking on the image file icon in Windows Explorer and selecting Copy. I have three different systems, to transfer image data to db table OLEObject / LONGVARBINARY fields by using three different systems Dao/ADODB/HSQL, so that’s not what I’m looking for

Here’s the related project
ClipBoardTest.odt (22.3 KB)

It certainly won’t be superfluous for our forum. :slight_smile:
The clipboard isn’t a simple object.
The LO developers have put in the effort and written commands for working with the clipboard. I think these commands should be used.
I once wrote a macro like this (but I haven’t tested it thoroughly):

 Function ClipBoardToGraphic() As Object
  Dim oDoc As Object, oDisp As Object
  Dim props(0) as new com.sun.star.beans.PropertyValue
  ClipBoardToGraphic = Nothing
  
  props(0).Name = "Hidden"
  props(0).Value = True
  oDoc=StarDesktop.LoadComponentFromUrl("private:factory/sdraw", "_default", 0, props())
  
  oDisp = createUnoService("com.sun.star.frame.DispatchHelper")
  oDoc.CurrentController.Select oDoc.DrawPages(0)
  oDisp.executeDispatch oDoc.CurrentController.Frame, ".uno:Paste", "", 0, Array()
  On Error GoTo ErrLabel
  ClipBoardToGraphic = oDoc.DrawPages.getByIndex(0).getByIndex(0).Graphic   
ErrLabel:  
  oDoc.Close True 
End Function

I think you can do the opposite in a similar way:

  • create a new (invisible) Draw document
  • create an image with the specified Graphic property and add it to the document
  • select this image
  • copy to the clipboard (.uno:Copy)
  • close the document
1 Like

Let’s try:

Sub GraphicToClipBoard(ByVal oGraphic As Object)
  Dim oDoc As Object, oDisp As Object, oDrawPage as Object, oGShape As Object
  Dim props(0) as new com.sun.star.beans.PropertyValue
    
  props(0).Name = "Hidden"
  props(0).Value = True
  oDoc = StarDesktop.LoadComponentFromUrl("private:factory/sdraw", "_default", 0, props())
  oDrawPage = oDoc.DrawPages(0)
  oGShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")  
  oGShape.Graphic = oGraphic
  oDrawPage.add(oGShape)
  
  oDisp = createUnoService("com.sun.star.frame.DispatchHelper")
  oDoc.CurrentController.Select oDoc.DrawPages.getByIndex(0).getByIndex(0)  ' select shape
  oDisp.executeDispatch oDoc.CurrentController.Frame, ".uno:OriginalSize", "", 0, Array()
  oDisp.executeDispatch oDoc.CurrentController.Frame, ".uno:Copy", "", 0, Array()
  oDoc.Close True 
End Sub

image
Sokol92

Thanks for your code example.

I did try to extract something usefull to my project from your code but didn’t get anything to working. By the way, is it even possible to select anything hidden in LibreOffice projects?

Let’s check it together.
Run the ShowDialog Macro macro in the attached document.
Press button Copy Image To ClipBoard
The image from the picControl will be copied to the clipboard. After this, I successfully added the clipboard contents to Calc, Writer, MS Excel, MS Word documents, and a Thunderbird letter.

Version: 25.2.6.2 (X86_64) / LibreOffice Community
Build ID: 729c5bfe710f5eb71ed3bbde9e06a6065e9c6c5d
CPU threads: 6; OS: Windows 10 X86_64 (10.0 build 19045); UI render: Skia/Raster; VCL: win
Locale: ru-RU (ru_RU); UI: en-US
Calc: CL threaded

ClipBoardTest3.odt (50.7 KB)

sokol92:
Yeah, it works, but it also doesn’t attach DataFlavour elements to the package, so you can’t paste image data for example to the desktop, by right-clicking and selecting Paste…

Yes. The mechanism for copying to the clipboard is the same as when copying an image from any LibreOffice module.
As for copying Graphic to/from a file, GraphicProvider handles that.

Maybe I expressed it a little unclear:
When you copy image data to the clipboard using your test project (ClipBoardTest3.odt), the DataFlavors are added to the package. But the package does not contain a filename because it doesn’t even exisist. But even if was existing you cant add it to DataFlavors because LibreOffice Basic is not able to to write that value in UTF-16 format ( application/x-openoffice-file;windows_formatname=“FileNameW”)

If you want, you can test it by running your own test project and then my test project:
getTransferDataFlavors.odt (14.8 KB)

I once wrote a macro that (for later study) saves the clipboard contents in all formats to C:\Temp\ClipBoard directory.

Option Explicit

' Writes the contents of the clipboard (all formats) to files C:\temp\Clipboard\Clip_ ...
Sub ClipboardToFiles()
  Dim oClip As Object, oContents As Object, oTransferDataFlavors As Object, aDataFlavor As Object
  Dim oFA As Object, oFile As Object, oTextStream As Object
  Dim aData() As Byte, i As Long, DFName As String, fileName as String, folder as String, v
  
  folder = "C:\Temp\Clipboard"  ' ???
  
  oFA=CreateUnoService("com.sun.star.ucb.SimpleFileAccess") 
  oContents = CreateUnoService("com.sun.star.datatransfer.clipboard.SystemClipboard").getContents()
  If oContents Is Nothing Then 
    Exit Sub
  End If
  
  oTransferDataFlavors = oContents.getTransferDataFlavors()
  oFA=CreateUnoService("com.sun.star.ucb.SimpleFileAccess") 
  On Error Resume Next
  fileName=folder & "\Clip_" & Format(Now(), "YYYYMMDD\_HHMMSS")
  For i=0 To Ubound(oTransferDataFlavors)
    aDataFlavor = oTransferDataFlavors(i)
    DFName=aDataFlavor.HumanPresentableName
    oFile=oFA.openFileWrite(ConvertToUrl(fileName & "_" & Replace(DFName, " ", "_")))
    aData=Array()      
    v=Empty
    v=oContents.getTransferData(aDataFlavor)
    ' mri oContents 
    If IsArray(v) Then
      aData=oContents.getTransferData(aDataFlavor) 
      oFile.writeBytes aData
    ElseIf Not IsEmpty(v) Then
      oTextStream = CreateUnoService("com.sun.star.io.TextOutputStream")
      oTextStream.setOutputStream oFile
      oTextStream.writeString oContents.getTransferData(aDataFlavor) 
      oFile.writeBytes aData
    End If  
  Next i  
End Sub

I used my macro to see what happens when we copy file(s) to the clipboard using Explorer (this is all well-known).
Three DataFlavors are created:

  1. FileList: a list of full file paths (UTF-16 Little Endian encoding)
  2. FileContent: the contents of the (first) file (binary file)
  3. FileName: the name of the (first) file

When I tested your test project
ClipBoardTest3.odt (57.7 KB) (mouse right click → Paste option stays grayed)
And then examined content of the clipboard to see what DataFlavors looks like, using my own test project…
getTransferDataFlavors.odt (14.8 KB)
the result looked like this:
Näyttökuva 2025-10-29 205848
Näyttökuva 2025-10-29 205904
Näyttökuva 2025-10-29 205917
Näyttökuva 2025-10-29 205927
Näyttökuva 2025-10-29 205944
Näyttökuva 2025-10-29 205957
Näyttökuva 2025-10-29 210009
Näyttökuva 2025-10-29 210020
Näyttökuva 2025-10-29 210030
Näyttökuva 2025-10-29 210040
When I copy one image file to the clipboard by right-clicking and selecting Paste and then examine content of the clipboard to see what DataFlavors looks like, using my own test project… the result looks like this:
Näyttökuva 2025-10-29 215147
Näyttökuva 2025-10-29 215204
Näyttökuva 2025-10-29 215219

' The filename can be extracted (UTF-8 format) like this: 
If oTypes(i).MimeType Like "*FileNameW*"  Then
        ImgPath = oClipContents.getTransferData(oTypes(i))	
       'oImg.Model.ImageUrl = ConvertToUrl(ImgPath) ' of course you could use this but that's not the idea at this time
       ext = "." & Split(oClipContents.getTransferData(oTypes(i)), ".")(UBound(Split(oClipContents.getTransferData(oTypes(i)), ".")))
End If
1 Like

Please have you some documentation or description for operator Like? I see it in code for 1st time and it seems functional, but I don’t know in what all cases

Sub fceLike
	dim s$
	s="abc"
	msgbox s like "ab*" 'show True
	msgbox s like "*bc" 'show True
End Sub

152689 – BASIC: Like operator (available in compatibility mode) needs documentation :wink:

1 Like

Bug for operator Like
https://bugs.documentfoundation.org/show_bug.cgi?id=169147

2 Likes

yep.
not an easy spot …

We can convert FileList into an array of strings, but to do this we’ll have to write a 2-line function in Python (which can be called from Basic).

@ sokol92:

I wrote a .NET ComVisble .dll to handle the whole thing, which can be used in Basic with the CreateObject method.

Unfortunately the code contains more than two lines, because of a few Imports lines. Public Sub …End Sub takes already those two lines…

But as an additional feature, drag and drop functionality has been introduced.

To avoid leaving any mystery to future readers of this topic, I’ll quote these two lines:

def arr_decode(arg, encoding = "utf-8"):
    return bytearray(arg).decode(encoding)

By the way, I remembered a trick for LO Basic (and VBA too).
To assign a UTF16-encoded byte array to a String variable…

you can...

you can use the assignment operator.

This way, we can see a list of files selected by Windows Explorer:

' ...
    Dim aByte() as Byte, arr, j as Long
    
    If aDataFlavor.HumanPresentableName = "FileList" Then
      arr = oContents.getTransferData(aDataFlavor)
      Redim aByte(Ubound(arr))
      For j = 0 To UBound(arr) Step 2
        aByte(j+1) = arr(j+1)
        aByte(j) = IIf(arr(j) = 0 And arr(j+1) = 0, 10, arr(j))  ' Replace Chr(0) -> Chr(10)
      Next j  
      Msgbox CStr(aByte)
    End If
1 Like