How to copy a picture (graphic object) to the Clipboard in VBA? - excel

In Excel 2003, I need to copy a Graphics object (sheet.PageSetup.LeftFooterPicture) to the Clipboard.
How can I do that?

In Excel versions prior to 2007, you cannot extract the graphic from the footer. You would need to have the original image file.
See this previous question for more details

According to MSDN a Graphic loads the Image through a file (filename). The Filename should contain the whole path to the file like 'C:\myimage.jpg' but once the worksheet is saved it changed the filename to 'myiamge' without the path and the extension. I wasn't able to find any other Reference to the file within Excel.
The following code might help you.
Sub yourMethod()
copyGraphic Me.PageSetup.LeftFooterPicture
End Sub
Sub copyGraphic(srcGraphic As Graphic)
Dim imagefolder As String
Dim imageExtension As String
Dim imagePath As String
imagefolder = "D:\" '"
imageExtension = ".gif"
If InStr(1, srcGraphic.filename, ".") Then
imagePath = srcGraphic.filename
Else
imagePath = imagefolder & srcGraphic.filename & imageExtension
End If
Me.Shapes.AddPicture imagePath, False, True, 10, 10, Round(srcGraphic.Width, 0), Round(srcGraphic.Height, 0)
End Sub
You might want to change Me. to the Name of your Sheet and the Destination Sheet.

as it mentioned before the problem is that I cannot extract picture from graphic object(LeftFooterPicture)
Looking on the answers I did muddle through this issue.
The Filename should contain the whole path to the file like 'C:\myimage.jpg' but once the worksheet is saved it changed the filename to 'myiamge' without the path and the extension.
so here is my workaround:
Before 'Save' event I scan all worksheets and get their Graphic to that time "Filename" has right content (absolute path like C:\mypic.jpg)
I create a hiden worksheet and add all pictures as Shape objects (Shapes.AddPicture with picture's path)
I bind a current workshhet name and picture position with shape name
By the time I need to copy a picture to cliapboard I look up the picture in the hiden page (shape.CopyPicture xlScreen, xlPicture)

When I try to copy something that doesn't seem to want to copy, I do a Print Screen from my keyboard and then paste it to the PAINT accessory. From there, you can crop out anything you don't want and then cut and paste the new image into a new PAINT file so it is clean. You can save it in a .jpg for easier use.
Hope that helps.

Private Sub Command1_Click()
Clipboard.Clear
Clipboard.SetData Picture1.Picture, vbCFBitmap
Command1.Enabled = False
End Sub
Like this you can copy pictures to the clipboard.

Related

Excel 2010 Macro - Creating txt files with names from ColA and content ColB. Stacko. solutions not work

I have found some answers/examples here on stackoverflow for an issue where in Microsoft Excell 2010, I want to create a txt files for each cell from for e.g. ColumnA which would contain file names, and ColumnB which would contain what is inside certain text file, however one example doesn't work at all, and second bugs after few files created.
You can use the CreateTextFile method which will create your file and provide a TextStream object which you can use to write to the text files. Microsoft Docs
Here's a code example that will do what you asked.
Sub CreateTxt()
Dim my_range As Range
Dim pth As String
Set my_range = Selection
For Each x In my_range.Rows:
pth = "C:\excel_test\" + x.Cells(1) + ".txt" 'file name in column A
Set file_sys = CreateObject("Scripting.FileSystemObject")
Set txt_file = file_sys.CreateTextFile(pth, True)
txt_file.WriteLine (x.Cells(2)) 'content in Column B
txt_file.Close
Next x
End Sub
Just remember, in order to create a file you need adequate permissions on the path you're writing to - I had to run excel as administrator to get the functionality.
Also, the True value in the CreateTextFile method is necessary to overwrite any files with the existing file name, if set to false it will throw an error when trying to write to the file.

Excel-vba: Pasting Image only from Clipboard + allowing for re-use later

I would like to do allow the user to do following in excel. This would probably be achieved using macros.
User takes a screenshot, like with Snipping Tool
Code checks if the clipboard contains an image or not (code only to run only when clipboard holds an image)
Code will then paste the image from clipboard onto a specified area (e.g. Cell J55).
At the same time, I want to give this pasted image an ID (say, imgSource1), so that the user can later re-use this image on another sheet (say, on sheet 2, call for imgSource1 and paste it in there)
I've gotten thus far: learnt how to paste something into excel at the said location. I haven't been able to find a working code for checking if the clipboard is holding an image or not. Now I need to figure out how to paste only image (how to check clipboard is holding only image before pasting). The following code doesn't seem to work for me.
Sub btn_addImg1()
If (Clipboard.GetImage() != null)
Sheet1.Paste Destination:=Range("J55"), Link:=False
Else
'do nothing
End If
The "If (Clipboard.GetImage()" line is red, and it's telling me it needs a ")" at "!=".
Note that saving an image on a local drive is not a feasible solution for my situation. It has to be pasted from the clipboard.
Thank you!
I figured out some workaround, but it need testing.
Btw, you need to go Tools -> References -> Microsoft Forms 2.0 Oject Librarty to make MSForms working.
Sub btn_addImg1()
Dim DataObj As New MSForms.DataObject
DataObj.GetFromClipboard
On Error GoTo Img
GetClipboardText = DataObj.GetText
On Error GoTo 0
Img:
If Err = -2147221404 Then
Err = 0
Sheet1.Paste Destination:=Sheet1.Range("J55"), Link:=False
Else
'do nothing
End If
End Sub

Determine Image in Excel Comment

I have found plenty of vba for inserting images into a comment
Selection.ShapeRange.Fill.UserPicture "C:\Temp\Pictures\ewe.jpg"
How can you determine the image already used for an comment?
I would like to extract the embedded image names if possible.
Is there not a property to access that will give me this?
In the comment Fill Effects dialog box the image name somehow seems to be accessible.
Sorry, I didn't have the reputation to just comment on your question for clarification.
I made a test file, inserted a comment and image in that comment, and then extracted the base files. I then checked them all for the original file name. I also found the embedded JPEG and decoded it to get the metadata. As you've noted, the original file names are stored in xl\drawings\vmlDrawing1.vml (once you've extracted the xml files from the excel file by appending .zip to the filename and then running an unzip utility on it). I did find the file name, but not the path or file type, so I'm fairly certain that the path and file type aren't preserved.
If just the file name is sufficient for you, then that file contains information for each drawing that you have, and those will include the cell location, although they're 0 based, so you'd have to add one to get the actual row and column. My question is two part:
1) Is the file name alone sufficient, or did you need the entire path? If you needed the entire path, I think you're out of luck, since the paths are on a different computer and you can't even search for them if you do extract the file name.
2) If that is all you need, does the solution have to be VBA? In the past, I have programmatically unzipped and manipulated the xml base files, but it's a little tricky. It's simplified by the fact that you only have to read out the data, so that's a plus. I did it in .net before, but I'm sure that if it had to be VBA it could be done, but it would be simpler if you were open to the type of solution.
Let me know, I'd be happy to help you out.
====================================================================================
Try this: make a copy of the spreadsheet, append .zip (test.xlsm.zip), and then extract the files manually. Change vmlPath to the location of your xl\drawings\vmlDrawing1.vml file. Then run this. I did make some assumptions, for instance, I assumed that the order of the nodes and attributes would always be the same and so I used hardcoded indexes (shp.attributes(0), etc) instead of using logic to make sure I had the correct node or attribute, but you seem like you know your way around VBA, so I'm just going to code a barebones. This will need a reference to Microsoft XML 6.0.
Sub vmlParse()
Dim vmlPath As String: vmlPath = "C:\Users\Lenovo\Desktop\test - Copy.xlsm\xl\drawings\vmlDrawing1.vml"
Dim this As Worksheet: Set this = ActiveSheet
Dim doc As New DOMDocument, shps As IXMLDOMNodeList
Dim shp As IXMLDOMNode, n As IXMLDOMNode, a As IXMLDOMAttribute
Dim fileName As String, productID As String
Dim rng As Range, r As Long, c As Long
doc.Load vmlPath
Set shps = doc.getElementsByTagName("x:ClientData")
For Each shp In shps
If shp.Attributes(0).nodeValue = "Note" Then
r = 0: c = 0
For Each a In shp.ParentNode.FirstChild.Attributes
If a.nodeName = "o:title" Then
fileName = a.nodeValue
Exit For
End If
Next
For Each n In shp.childNodes
If n.nodeName = "x:Row" Then r = n.text
If n.nodeName = "x:Column" Then c = n.text
Next
Set rng = this.Cells(r + 1, c + 1)
productID = rng.Value
'now you have the productID, the fileName, and the cell location
End If
Next
End Sub
Let me know how that worked out for you.
If c4 contains your comment:
Set shp = Range("C4").Comment.Shape
if shp.Fill.TextureType = msoTextureUserDefined then
end if

Excel VBA global variables "lifetime"?

Sorry about the non descriptive Title, I just didn't know how to describe my goal.
I'm new at VBA and didn't yet understand how things really work.
I've written a function which gets a directory from the user, and displays data from the first file in the directory. Now, I want to add a "next" button.
When the "next" button is pressed, my code should display data from the next file in the directory.
I tried to use global variables but they seem to get initialized each time the button is pressed.
What is the best way to achieve my goal? Do I have to use the spreadsheet as memory and write and read everything from there? Or does Excel VBA have some other "live memory" mechanism?
Thanks,
Li
Globals will not normally be reinitialized when you click a button. They will be reinitialized if you recompile your VBA project. Therefore, while debugging, you may see a global being reinitialized.
You can use the spreadsheet as memory. One way to do this is to have a worksheet whose Visibility property you set to xlSheetVeryHidden (you can do this from the VBA project). This worksheet won't be visible to users, so your VBA application can use it to store data.
This could be approached many ways, as with any problem I guess!
You could break the problem up into two subroutines:
1) Retrieve all the file names in the selected directory and display the first file's data
2) If it's not the last file, get the next file's data and display it
You could use a global variable to store the filenames and an index to remember where you are up to in the collection of filenames.
Global filenames As Collection
Global fileIndex As Integer
Public Sub GetFilenames()
Dim selectedDirectory As String
Dim currentFile As String
selectedDirectory = "selected\directory\"
currentFile = Dir$(selectedDirectory)
Set filenames = New Collection
While currentFile <> ""
filenames.Add selectedDirectory & currentFile
currentFile = Dir$()
Wend
' Make sure there were files
If filenames.Count >= 1 Then
fileIndex = 1
' Call a method to display data
DisplayData(filenames(fileIndex))
Else
' No files
End If
End Sub
Public Sub GetNextFile()
' Make sure we have a filenames object
If Not filenames Is Nothing Then
If fileIndex < filenames.Count Then
fileIndex = fileIndex + 1
' Call the display method again
DisplayData(filenames(fileIndex))
Else
' Decide what to do after reaching the final file
End If
Else
' No filenames
End If
End Sub
I didn't include the DisplayData procedure as I'm not sure what type of files you're grabbing or what you are doing with them but if it were say excel files it could be something like:
Public Function DisplayData(filename As String)
Dim displayWb As Workbook
Set displayWb = Workbooks.Open(filename)
' Do things with displayWb
End Function
You could then set the macro of the button to "GetNextFile" and it will cycle through the files after each click. As for the lifetime of global variables, they only reinitialize when the VBA project is reset or when they are specifically initialized through a procedure or the immediate window.
Perhaps these two functions can also help you:
SaveSetting
GetSetting
as showed here: http://www.j-walk.com/ss/excel/tips/tip60.htm

Is is possible to insert an image into an excel cell via COM?

I have used automation to insert values into a cell, however I have never seen any documentation, for example, that demonstrate inserting anything other than text and/or formula's.
Has anybody been able to insert an image from an external application?
Dim FileName as string
FileName="c:\text.jpg"
Set NewPic = ActiveSheet.Pictures.Insert(FileName)
NewPic.top=100
NewPic.left=100
If you want to position the picture to a specific cell then select that cell as a range and use that ranges top/left/with to position the picture.
Samples: http://exceltip.com/st/Insert_pictures_using_VBA_in_Microsoft_Excel/486.html
Note: In Excel cells cannot contain pictures. The pictures live on an invisible drawing layer that floats about the cells. They can be positioned based on the cell coordinates, which makes it feel like they are living "in" the cells.
I see it's already been answered, but see my post here.
Basically rather than use the Worksheet.Pictures.Insert method (which the MSDN recommends you don't use directly, and which returns a raw COM object), try the Worksheet.Shapes.AddPicture method instead.
Dim range As Microsoft.Office.Interop.Excel.Range
Dim pic as Microsoft.Office.Interop.Excel.Shape
Dim filePath as String
range = ...
filePath = ...
pic = range.Worksheet.Shapes.AddPicture(filePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, range.Left, range.Top, 300, 300)
It's not quite as straightforward because you have to specify the exact position and dimensions, but otherwise, pretty cool!
Sure, the following code gives a good example using the Microsoft Interop libraries:
string excelfilename = #"C:\excelfile.xlsx";
string picturename = #"C:\image.jpg";
object missing = Type.Missing;
Microsoft.Office.Interop.Excel.Application app = new ApplicationClass();
Workbook book = app.Workbooks.Add(missing);
Worksheet sheet = (Worksheet)book.ActiveSheet;
Pictures pics = (Pictures)sheet.Pictures(missing);
pics.Insert(picturename, missing);
book.SaveAs(excelfilename, missing, missing, missing, missing, missing, XlSaveAsAccessMode.xlNoChange,
missing, missing, missing, missing, missing);
app.Quit();
app = null;

Resources