click shape or button (preview/close) that displays an image - vba

I am new to VBA and seeking help on a work project. I have done some research and got started but am now over my head.
My objectives are:
Create a click shape or button (preview/close) that displays an image from another location on computer.
The image displayed will be dependent on the data input (col A: patient name; same name of jpeg image) for each name that is entered in the same row.
Also I would like a new button/shape to be automatically created in the corresponding cell when a new name is added
Thanks Rick
Sub Macro1()
Dim Path As String
Set myDocument = Worksheets(1)
Path = "F:\CAD_CAM division\Unsorted Models\"
myDocument.Pictures.Insert (Path & ActiveCell.Value & ".jpg")
With ActiveSheet.Shapes("Rounded Rectangle 1").TextFrame2.TextRange.Characters
If .Text = "Close" Then
.Text = "Preview"
ActiveSheet.Pictures.Delete
Else
.Text = "Close"
With ActiveSheet.Shapes("Rounded Rectangle 1")
End With
End If
End With
End Sub

While your original code was actually working, I made a few slight adjustments to ensure that all (multiple) pictures are included / shown on the sheet and to align these picture below each other. Have a look at the comments in the code and let me know what you think:
Option Explicit
Sub Macro1()
Dim lngRow As Long
Dim strPath As String
Dim picItem As Picture
Dim shtPatient As Worksheet
'If there are multiple pictures then they should be shown
' underneath each other. dblLeft and dblTop will be used
' to place the next picture underneath the last one.
Dim dblTop As Double
Dim dblLeft As Double
Set shtPatient = ThisWorkbook.Worksheets(1)
strPath = "F:\CAD_CAM division\Unsorted Models\"
With shtPatient.Shapes("Rounded Rectangle 1").TextFrame2.TextRange.Characters
If .Text = "Close" Then
.Text = "Preview"
ActiveSheet.Pictures.Delete
Else
.Text = "Close"
For lngRow = 2 To shtPatient.Cells(shtPatient.Rows.Count, "A").End(xlUp).Row
'First check if the file actually exists / can be found and inserted
If Dir(strPath & shtPatient.Cells(lngRow, 1).Value2 & ".jpg") <> "" Then
Set picItem = shtPatient.Pictures.Insert(strPath & shtPatient.Cells(lngRow, 1).Value2 & ".jpg")
'Name the picture so it can be found afterwards again using VBA
picItem.Name = shtPatient.Cells(lngRow, 1).Value2 & ".jpg"
If lngRow = 2 Then
picItem.Top = shtPatient.Range("F2").Top
picItem.Left = shtPatient.Range("F2").Left
dblTop = picItem.Top + picItem.Height + 10
dblLeft = picItem.Left
Else
picItem.Top = dblTop
picItem.Left = dblLeft
dblTop = picItem.Top + picItem.Height + 10
End If
End If
Next lngRow
End If
End With
End Sub

Related

Excel VBA to replace image, create PDF, move to next image in folder and repeat

I have an Excel worksheet that i use as a printable single page PDF report that contains an image with some text. In a column to the side I have a list of all the images in a specific folder and i would like to use VBA to cycle through the list replacing the image in the worksheet and creating a PDF to be stored in the same folder. I currently do this manually which is a pain and would like to automate it with VBA.
Any help would be greatly appreciated.
Thanks in advance.
The code i use manualy by changing the full path of the image to be replaced is as follows>
Sub AddPicturesFULL()
Dim myPic As Picture
Dim wkSheet As Worksheet
Dim myRng As Range
Dim myCell As Range
Dim rowCount As Long
Dim rowCount2 As Long
Dim Pic As Object
Set wkSheet = Sheets("REPORT(FULL)") ' -- Change to your sheet
For Each Pic In wkSheet.Pictures
Pic.Delete
Next Pic
'-- The usual way of finding used row count for specific column
rowCount2 = wkSheet.Cells(wkSheet.Rows.Count, "N").End(xlUp).Row
If rowCount2 <> 0 Then
Set myRng = wkSheet.Range("N2", wkSheet.Cells(wkSheet.Rows.Count, "N").End(xlUp))
For Each myCell In myRng.Cells
If Trim(myCell.Value) = "" Then
'MsgBox "No file path"
ElseIf Dir(CStr(myCell.Value)) = "" Then
MsgBox myCell.Value & " Doesn't exist!"
Else
'myCell.Offset(0, 1).Parent.Pictures.Insert (myCell.Value)
Set myPic = myCell.Parent.Pictures.Insert(myCell.Value)
With myCell.Offset(0, -13) '1 columns to the right of C ( is D)
'-- resize image here to fit into the size of your cell
myPic.Top = .Top
myPic.Width = .Width
myPic.Height = 640
myPic.Left = .Left
myPic.Placement = xlMoveAndSize
myPic.SendToBack
End With
End If
Next myCell
Else
MsgBox "There is no file paths in your column"
End If
End Sub
Create an ActiveX Image on the Sheet instead of using drawing Pictures
Then you can use
Dim i As Integer
For i = 1 To 20 Step 1
imgTest.Picture = LoadPicture(Sheets("Sheet1").Cells(i, COLUMN).Value)
Sheets("Sheets1").ExportAsFixedFormat Type:=xlTypePDF, Filename:="C:\test" & i & ".pdf", Quality:=xlQualityStandard
Next i
To loop through the column with imagepaths and set the image for each of them. Then just export it as a PDF.
Of course you have to adjust the i values and COLUMN to your needs.

Delete chart series but keep their formatting

This is the code I use to dynamically create charts in Virtual Basic:
Dim Chart As Object
Set Chart = Charts.Add
With Chart
If bIssetSourceChart Then
CopySourceChart
.Paste Type:=xlFormats
End If
For Each s In .SeriesCollection
s.Delete
Next s
.ChartType = xlColumnClustered
.Location Where:=xlLocationAsNewSheet, Name:=chartTitle
Sheets(chartTitle).Move After:=Sheets(Sheets.count)
With .SeriesCollection.NewSeries
If Val(Application.Version) >= 12 Then
.values = values
.XValues = columns
.Name = chartTitle
Else
.Select
Names.Add "_", columns
ExecuteExcel4Macro "series.columns(!_)"
Names.Add "_", values
ExecuteExcel4Macro "series.values(,!_)"
Names("_").Delete
End If
End With
End With
#The CopySourceChart Sub:
Sub CopySourceChart()
If Not CheckSheet("Source chart") Then
Exit Sub
ElseIf TypeName(Sheets("Grafiek")) = "Chart" Then
Sheets("Grafiek").ChartArea.Copy
Else
Dim Chart As ChartObject
For Each Chart In Sheets("Grafiek").ChartObjects
Chart.Chart.ChartArea.Copy
Exit Sub
Next Chart
End If
End Sub
How can I keep the formatting of series that is applied in the If bIssetSourceChart part while deleting those series' data?
I have solved this issue before. I have charts that were created by macro but it only applied to the date I made them. So a made a refresh macro that runs after every Workbook open. I used source before and found that it deletes everything. then moved on to series only. I will paste my work here and try to explain. For quick navigation the second part of the code down there called sub aktualizacegrafu() might help you if you get lost find a reference in upper part of the code starting with sub generacegrafu()
Sub generacegrafu()
ThisWorkbook.Sheets("List1").CommandButton6.BackColor = &H0&
ThisWorkbook.Sheets("List1").CommandButton6.ForeColor = &HFFFFFF
Dim najdiposlradek As Object
Dim graf As Object
Dim vkladacistring As String
Dim vykreslenysloupec As Integer
Dim hledejsloupec As Object
Dim hledejsloupec2 As Object
Dim kvantifikator As Integer
Dim grafx As ChartObject
Dim shoda As Boolean
Dim jmenografu As String
Dim rngOrigSelection As Range
Cells(1, 1).Select
If refreshcharts = True Then
Set hledejsloupec = Range("11:11").Find(What:=prvnislovo, LookIn:=xlValues)
'dynamicaly generated, prvnislovo is for first word in graph and the macro looks for match in row 11 if it doesnt find any then
Else
'then it looks for match in option box
Set hledejsloupec = Range("11:11").Find(What:=ThisWorkbook.Sheets("List1").ComboBox1.Value, LookIn:=xlValues)
End If
If hledejsloupec Is Nothing Then
MsgBox "Zadaný sloupec v první nabídce nebyl nalezen."
Else
If refreshcharts = True Then
Set hledejsloupec2 = Range("11:11").Find(What:=druheslovo, LookIn:=xlValues)
Else
Set hledejsloupec2 = Range("11:11").Find(What:=ThisWorkbook.Sheets("List1").ComboBox2.Value, LookIn:=xlValues)
End If
If hledejsloupec2 Is Nothing Then
MsgBox "Zadaný sloupec v druhé nabídce nebyl nalezen."
Else
jmenografu = Cells(11, hledejsloupec.Column).Value & "_" & Cells(11, hledejsloupec2.Column).Value
Set najdiposlradek = Range("A:A").Find(What:=Date, LookIn:=xlValues)
Application.ScreenUpdating = False
Set rngOrigSelection = Selection
'This one selects series for new graph to be created
Cells(1048576, 16384).Select
Set graf = ThisWorkbook.Sheets("List1").Shapes.AddChart
rngOrigSelection.Parent.Parent.Activate
rngOrigSelection.Parent.Select
rngOrigSelection.Select 'trouble with annoing excel feature to unselect graphs
Application.ScreenUpdating = True
graf.Select
kvantifikator = 1
Do
shoda = False
For Each grafx In ThisWorkbook.Sheets("List1").ChartObjects
If grafx.Name = jmenografu Then
shoda = True
jmenografu = jmenografu & "(" & kvantifikator & ")"
kvantifikator = kvantifikator + 1
End If
Next grafx
'this checks if graph has younger brother in sheet
'but no we get to the part that matter do not bother playing with source of the graph because I have found it is quite hard to make it work properly
Loop Until shoda = False
'here it starts
ActiveChart.Parent.Name = jmenografu
ActiveChart.SeriesCollection.NewSeries 'add only series!
vkladacistring = "=List1!R12C" & hledejsloupec.Column & ":R" & najdiposlradek.Row & "C" & hledejsloupec.Column 'insert this into series
ActiveChart.SeriesCollection(1).Values = vkladacistring
vkladacistring = "=List1!R11C" & hledejsloupec.Column
ActiveChart.SeriesCollection(1).Name = vkladacistring
vkladacistring = "=List1!R12C" & hledejsloupec2.Column & ":R" & najdiposlradek.Row & "C" & hledejsloupec2.Column
ActiveChart.SeriesCollection(1).XValues = vkladacistring
'here it ends and onward comes formating
ActiveChart.Legend.Delete
ActiveChart.ChartType = xlConeColClustered
ActiveChart.ClearToMatchStyle
ActiveChart.ChartStyle = 41
ActiveChart.ClearToMatchStyle
ActiveSheet.Shapes(jmenografu).Chart.ChartArea.Format.ThreeD.RotationY = 90
ActiveSheet.Shapes(jmenografu).Chart.ChartArea.Format.ThreeD.RotationX = 0
ActiveChart.Axes(xlValue).MajorUnit = 8.33333333333333E-02
ActiveChart.Axes(xlValue).MinimumScale = 0.25
ActiveChart.Walls.Format.Fill.Visible = msoFalse
ActiveChart.Axes(xlCategory).MajorUnitScale = xlMonths
ActiveChart.Axes(xlCategory).MajorUnit = 1
ActiveChart.Axes(xlCategory).BaseUnit = xlDays
End If
End If
Call aktualizacelistboxu
ThisWorkbook.Sheets("List1").CommandButton6.BackColor = &H8000000D
ThisWorkbook.Sheets("List1").CommandButton6.ForeColor = &H0&
End Sub
the result i found is that you cannot keep formating completely when you close chart because source of chart doesnt work very well and when you delete it some format will be lost
I will post my actualization of chart as well
Sub aktualizacegrafu()
Dim grafx As ChartObject
Dim hledejsloupec As Object
Dim hledejsloupec2 As Object
Dim vkladacistring As String
Dim najdiposlradek As Object
For Each grafx In ThisWorkbook.Sheets("List1").ChartObjects
prvnislovo = Left(grafx.Name, InStr(1, grafx.Name, "_") - 1)
druheslovo = Right(grafx.Name, Len(grafx.Name) - InStr(1, grafx.Name, "_"))
'now it checks the names of charts .. the data loads from respective columns that are named the same way so I ussualy choose what statistic I want by choosing the columns needed
'for example I want to reflect my arrivals to work according to the hours I worked or to the date so I set 1st option to arrival and 2nd to date
grafx.Activate
Set najdiposlradek = Range("A:A").Find(What:=Date, LookIn:=xlValues)
Set hledejsloupec = Range("11:11").Find(What:=prvnislovo, LookIn:=xlValues)
If hledejsloupec Is Nothing Then
MsgBox "Hodnota v grafu již není mezi sloupci v tabulce. Aktualizace grafu " & grafx.Name & " bude ukončena."
Else
Set hledejsloupec2 = Range("11:11").Find(What:=druheslovo, LookIn:=xlValues)
If hledejsloupec2 Is Nothing Then
MsgBox "Hodnota v grafu již není mezi sloupci v tabulce. Aktualizace grafu " & grafx.Name & " bude ukončena."
Else
here it enters string that contains adress of desired cell I always enter it as string cause its easier to see with debug.print what is being entered
result looks like this List means Sheet in czech
activechart.seriescollection(1).values=List1!R12C1:R13C16
activechart.seriescollection(1).name=List1!R1C1:R1C15
vkladacistring = "=List1!R12C" & hledejsloupec.Column & ":R" & najdiposlradek.Row & "C" & hledejsloupec.Column
ActiveChart.SeriesCollection(1).Values = vkladacistring
vkladacistring = "=List1!R11C" & hledejsloupec.Column
ActiveChart.SeriesCollection(1).Name = vkladacistring
vkladacistring = "=List1!R12C" & hledejsloupec2.Column & ":R" & najdiposlradek.Row & "C" & hledejsloupec2.Column
ActiveChart.SeriesCollection(1).XValues = vkladacistring
End If
End If
Next grafx
Call aktualizacelistboxu
End Sub
so result of this is when you actually have a chart already but want to make slight changes to the area it applies to then it keeps the formating
hope this helped a bit if not I am sorry if it did keep the revard. It just got me curious because I was solving the same problem recently
if you need any further explanation comment this and I will try to explain

Implement For Loop with Counter

I have a Word Userform where I add text boxes dynamically. The code then puts information from the textboxes to bookmarks which are picture filenames. It is all dynamic in that you enter how many textboxes you need and it then adds them to the userform and the text in the document. I left this last part of code out because its very long and not needed at this point.
I am attempting to put this first part of my code into a "For Loop" but I have been having a lot of difficulty doing so. The second part of my code I am providing has a textbox counter I trying to tie into it.
Right now my code works if I enter 10 into a textbox called "Amount" which you see throughout the code. I need to be able to enter any number.
If you think the entire code will help let me know and I will add it instead. I have been able to get everything else to work but for some reason this has had me stumped for days.
Need "For loop" implemented
Sub CommandButton1_Click()
Dim Textbox As Object
Dim Textbox1 As Object
Dim Textbox2 As Object
Dim Textbox3 As Object
Dim Textbox4 As Object
Dim Textbox5 As Object
Dim Textbox6 As Object
Dim Textbox7 As Object
Dim Textbox8 As Object
Dim Textbox9 As Object
Dim Textbox10 As Object
Dim TBs(9) As Object
Set TBs(0) = UserForm1.Controls("TextBox_1"): Set TBs(1) = UserForm1.Controls("TextBox_2"): Set TBs(2) = UserForm1.Controls("TextBox_3")
Set TBs(3) = UserForm1.Controls("TextBox_4"): Set TBs(4) = UserForm1.Controls("TextBox_5"): Set TBs(5) = UserForm1.Controls("TextBox_6")
Set TBs(6) = UserForm1.Controls("TextBox_7"): Set TBs(7) = UserForm1.Controls("TextBox_8"): Set TBs(8) = UserForm1.Controls("TextBox_9")
Set TBs(9) = UserForm1.Controls("TextBox_10"):
Dim i
For i = 0 To Amount - 1
With ActiveDocument
If .Bookmarks("href" & i + 1).Range = ".jpg" Then
.Bookmarks("href" & i + 1).Range _
.InsertBefore TBs(i)
.Bookmarks("src" & i + 1).Range _
.InsertBefore TBs(i)
.Bookmarks("alt" & i + 1).Range _
.InsertBefore TBs(i)
End If
End With
Next
End Sub
TextBox Counter
Private Sub AddLine_Click()
Dim theTextbox As Object
Dim textboxCounter As Long
For textboxCounter = 1 To Amount
Set theTextbox = UserForm1.Controls.Add("Forms.TextBox.1", "Test" & textboxCounter, True)
With theTextbox
.Name = "TextBox_" & textboxCounter
.Width = 200
.Left = 70
.Top = 30 * textboxCounter
End With
Next
End Sub

Displaying only a determined range of data

I want to display to the user certain information that exists on a separated worksheet, whenever he clicks a button.
I can set Excel to "go" to this worksheet at the starting line of the range , but I could not find a way to hide everything else.
Is there some method for this, or do I have to hide all rows and columns?
Insert a UserForm in the Workbook's VB Project.
Add a ListBox control to the userform.
Then do something like this code in the UserForm_Activate event code:
Private Sub UserForm_Activate()
Dim tbl As Range
Set tbl = Range("B2:E7") '## Change this to capture the rang you need '
Me.Caption = "Displaying data from " & _
ActiveSheet.Name & "!" & tbl.Address
With ListBox1
.ColumnHeads = False
.ColumnCount = tbl.Columns.Count
.RowSource = tbl.Address
End With
End Sub
Which gives unformatted data from the range:
To export the range as an image, you could create an Image in the UserForm instead of a Listbox. Then this should be enough to get you started.
As you can see from this screenshot, the image might not always come out very clearly. Also, if you are working with a large range of cells, the image might not fit on your userform, etc. I will leave figuring that part out up to you :)
Private Sub UserForm_Activate()
Dim tbl As Range
Dim imgPath As String
Set tbl = Range("B2:E7") '## Change this to capture the rang you need '
imgPath = Export_Range_Images(tbl)
Caption = "Displaying data from " & _
ActiveSheet.Name & "!" & tbl.Address
With Image1
If Not imgPath = vbNullString Then
.Picture = LoadPicture(imgPath)
.PictureSizeMode = fmPictureSizeModeClip
.PictureAlignment = 2 'Center
.PictureTiling = False
.SpecialEffect = 2 'Sunken
End If
End With
End Sub
Function Export_Range_Images(rng As Range) As String
'## Modified by David Zemens with
' credit to: _
' http://vbadud.blogspot.com/2010/06/how-to-save-excel-range-as-image-using.html ##'
Dim ocht As Object
Dim srs As Series
rng.CopyPicture xlScreen, xlPicture
ActiveSheet.Paste
Set ocht = ActiveSheet.Shapes.AddChart
For Each srs In ocht.Chart.SeriesCollection
srs.Delete
Next
'## Modify this line as needed ##'
fname = "C:\users\david_zemens\desktop\picture.jpg"
On Error Resume Next
Kill fname
On Error GoTo 0
ocht.Width = rng.Width
ocht.Height = rng.Height
ocht.Chart.Paste
ocht.Chart.Export Filename:=fname, FilterName:="JPG"
Application.DisplayAlerts = False
ocht.Delete
Application.DisplayAlerts = True
Set ocht = Nothing
Export_Range_Images = fname
End Function
If you record a macro and hide some columns and rows manually, the code will be produced for you, and you will see how it's done.

Using VBA code, how to export Excel worksheets as image in Excel 2003?

Please suggest the better way of exporting range of data from excel worksheets as image either in .jpeg or .png or in .gif.
do you want to try the below code I found on the internet somewhere many moons ago and used.
It uses the Export function of the Chart object along with the CopyPicture method of the Range object.
References:
MSDN - Export method as it applies to the Chart object. to save the clipboard as an Image
MSDN - CopyPicture method as it applies to the Range object to copy the range as a picture
dim sSheetName as string
dim oRangeToCopy as range
Dim oCht As Chart
sSheetName ="Sheet1" ' worksheet to work on
set oRangeToCopy =Range("B2:H8") ' range to be copied
Worksheets(sSheetName).Range(oRangeToCopy).CopyPicture xlScreen, xlBitmap
set oCht =charts.add
with oCht
.paste
.Export FileName:="C:\SavedRange.jpg", Filtername:="JPG"
end with
I've tried to improve this solution in several ways. Now resulting image has right proportions.
Set sheet = ActiveSheet
output = "D:\SavedRange4.png"
zoom_coef = 100 / sheet.Parent.Windows(1).Zoom
Set area = sheet.Range(sheet.PageSetup.PrintArea)
area.CopyPicture xlPrinter
Set chartobj = sheet.ChartObjects.Add(0, 0, area.Width * zoom_coef, area.Height * zoom_coef)
chartobj.Chart.Paste
chartobj.Chart.Export output, "png"
chartobj.Delete
Thanks everyone! I modified Winand's code slightly to export it to the user's desktop, no matter who is using the worksheet. I gave credit in the code to where I got the idea (thanks Kyle).
Sub ExportImage()
Dim sFilePath As String
Dim sView As String
'Captures current window view
sView = ActiveWindow.View
'Sets the current view to normal so there are no "Page X" overlays on the image
ActiveWindow.View = xlNormalView
'Temporarily disable screen updating
Application.ScreenUpdating = False
Set Sheet = ActiveSheet
'Set the file path to export the image to the user's desktop
'I have to give credit to Kyle for this solution, found it here:
'http://stackoverflow.com/questions/17551238/vba-how-to-save-excel-workbook-to-desktop-regardless-of-user
sFilePath = CreateObject("WScript.Shell").specialfolders("Desktop") & "\" & ActiveSheet.Name & ".png"
'Export print area as correctly scaled PNG image, courtasy of Winand
zoom_coef = 100 / Sheet.Parent.Windows(1).Zoom
Set area = Sheet.Range(Sheet.PageSetup.PrintArea)
area.CopyPicture xlPrinter
Set chartobj = Sheet.ChartObjects.Add(0, 0, area.Width * zoom_coef, area.Height * zoom_coef)
chartobj.Chart.Paste
chartobj.Chart.Export sFilePath, "png"
chartobj.Delete
'Returns to the previous view
ActiveWindow.View = sView
'Re-enables screen updating
Application.ScreenUpdating = True
'Tells the user where the image was saved
MsgBox ("Export completed! The file can be found here:" & Chr(10) & Chr(10) & sFilePath)
End Sub
Winand, Quality was also an issue for me so I did this:
For Each ws In ActiveWorkbook.Worksheets
If ws.PageSetup.PrintArea <> "" Then
'Reverse the effects of page zoom on the exported image
zoom_coef = 100 / ws.Parent.Windows(1).Zoom
areas = Split(ws.PageSetup.PrintArea, ",")
areaNo = 0
For Each a In areas
Set area = ws.Range(a)
' Change xlPrinter to xlScreen to see zooming white space
area.CopyPicture Appearance:=xlPrinter, Format:=xlPicture
Set chartobj = ws.ChartObjects.Add(0, 0, area.Width * zoom_coef, area.Height * zoom_coef)
chartobj.Chart.Paste
'scale the image before export
ws.Shapes(chartobj.Index).ScaleHeight 3, msoFalse, msoScaleFromTopLeft
ws.Shapes(chartobj.Index).ScaleWidth 3, msoFalse, msoScaleFromTopLeft
chartobj.Chart.Export ws.Name & "-" & areaNo & ".png", "png"
chartobj.delete
areaNo = areaNo + 1
Next
End If
Next
See here:https://robp30.wordpress.com/2012/01/11/improving-the-quality-of-excel-image-export/
Solution without charts
Function SelectionToPicture(nome)
'save location ( change if you want )
FName = CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\" & nome & ".jpg"
'copy selection and get size
Selection.CopyPicture xlScreen, xlBitmap
w = Selection.Width
h = Selection.Height
With ThisWorkbook.ActiveSheet
.Activate
Dim chtObj As ChartObject
Set chtObj = .ChartObjects.Add(100, 30, 400, 250)
chtObj.Name = "TemporaryPictureChart"
'resize obj to picture size
chtObj.Width = w
chtObj.Height = h
ActiveSheet.ChartObjects("TemporaryPictureChart").Activate
ActiveChart.Paste
ActiveChart.Export FileName:=FName, FilterName:="jpg"
chtObj.Delete
End With
End Function
If you add a Selection and saving to workbook path to Ryan Bradley code that will be more elastic:
Sub ExportImage()
Dim sheet, zoom_coef, area, chartobj
Dim sFilePath As String
Dim sView As String
'Captures current window view
sView = ActiveWindow.View
'Sets the current view to normal so there are no "Page X" overlays on the image
ActiveWindow.View = xlNormalView
'Temporarily disable screen updating
Application.ScreenUpdating = False
Set sheet = ActiveSheet
'Set the file path to export the image to the user's desktop
'I have to give credit to Kyle for this solution, found it here:
'http://stackoverflow.com/questions/17551238/vba-how-to-save-excel-workbook-to-desktop-regardless-of-user
'sFilePath = CreateObject("WScript.Shell").specialfolders("Desktop") & "\" & ActiveSheet.Name & ".png"
'##################
'Łukasz : Save to workbook directory
'Asking for filename insted of ActiveSheet.Name is also good idea, without file extension
dim FileID as string
FileID=inputbox("Type a file name","Filename...?",ActiveSheet.Name)
sFilePath = ThisWorkbook.Path & "\" & FileID & ".png"
'Łukasz:Change code to use Selection
'Simply select what you want to export and run the macro
'ActiveCell should be: Top Left
'it means select from top left corner to right bottom corner
Dim r As Long, c As Integer, ar As Long, ac As Integer
r = Selection.rows.Count
c = Selection.Columns.Count
ar = ActiveCell.Row
ac = ActiveCell.Column
ActiveSheet.PageSetup.PrintArea = Range(Cells(ar, ac), Cells(ar, ac)).Resize(r, c).Address
'Export print area as correctly scaled PNG image, courtasy of Winand
'Łukasz: zoom_coef can be constant = 0 to 5 can work too, but save is 0 to 4
zoom_coef = 5 '100 / sheet.Parent.Windows(1).Zoom
'#############
Set area = sheet.Range(sheet.PageSetup.PrintArea)
area.CopyPicture xlPrinter 'xlBitmap '
Set chartobj = sheet.ChartObjects.Add(0, 0, area.Width * zoom_coef, area.Height * zoom_coef)
chartobj.Chart.Paste
chartobj.Chart.Export sFilePath, "png"
chartobj.Delete
'Returns to the previous view
ActiveWindow.View = sView
'Re-enables screen updating
Application.ScreenUpdating = True
'Tells the user where the image was saved
MsgBox ("Export completed! The file can be found here: :" & Chr(10) & Chr(10) & sFilePath)
'Close
End Sub
This gives me the most reliable results:
Sub RangeToPicture()
Dim FileName As String: FileName = "C:\file.bmp"
Dim rPrt As Range: Set rPrt = ThisWorkbook.Sheets("Sheet1").Range("A1:C6")
'Add a Zoom to increase the resolution of the image.
ActiveWindow.Zoom = 300
Dim chtObj As ChartObject
rPrt.CopyPicture xlScreen, xlBitmap
Set chtObj = ActiveSheet.ChartObjects.Add(1, 1, rPrt.Width, rPrt.Height)
chtObj.Activate
ActiveChart.Paste
ActiveChart.Export FileName
chtObj.Delete
'Reset Zoom to innitial zoom of the image.
ActiveWindow.Zoom = 100
End Sub
Based on the link provided by Philip I got this to working
Worksheets("Final Analysis Sheet").Range("A4:G112").CopyPicture xlScreen, xlBitmap
Application.DisplayAlerts = False
Set oCht = Charts.Add
With oCht
.Paste
.Export Filename:="C:\FTPDailycheck\TodaysImages\SavedRange.jpg", Filtername:="JPG"
.Delete
End With
There's a more direct way to export a range image to a file, without the need to create a temporary chart. It makes use of PowerShell to save the clipboard as a .png file.
Copying the range to the clipboard as an image is straightforward, using the vba CopyPicture command, as shown in some of the other answers.
A PowerShell script to save the clipboard requires only two lines, as noted by thom schumacher in Save Image from clipboard using PowerShell.
VBA can launch a PowerShell script and wait for it to complete, as noted by Asam in Wait for shell command to complete.
Putting these ideas together, we get the following routine. I've tested this only under Windows 10 using the Office 2010 version of Excel. Note that there's an internal constant AidDebugging which can be set to True to provide additional feedback about the execution of the routine.
Option Explicit
' This routine copies the bitmap image of a range of cells to a .png file.
' Input arguments:
' RangeRef -- the range to be copied. This must be passed as a range object, not as the name
' or address of the range.
' Destination -- the name (including path if necessary) of the file to be created, ending in
' the extension ".png". It will be overwritten without warning if it exists.
' TempFile -- the name (including path if necessary) of a temporary script file which will be
' created and destroyed. If this is not supplied, file "RangeToPNG.ps1" will be
' created in the default folder. If AidDebugging is set to True, then this file
' will not be deleted, so it can be inspected for debugging.
' If the PowerShell script file cannot be launched, then this routine will display an error message.
' However, if the script can be launched but cannot create the resulting file, this script cannot
' detect that. To diagnose the problem, change AidDebugging from False to True and inspect the
' PowerShell output, which will remain in view until you close its window.
Public Sub RangeToPNG(RangeRef As Range, Destination As String, _
Optional TempFile As String = "RangeToPNG.ps1")
Dim WSH As Object
Dim PSCommand As String
Dim WindowStyle As Integer
Dim ErrorCode As Integer
Const WaitOnReturn = True
Const AidDebugging = False ' provide extra feedback about this routine's execution
' Create a little PowerShell script to save the clipboard as a .png file
' The script is based on a version found on September 13, 2020 at
' https://stackoverflow.com/questions/55215482/save-image-from-clipboard-using-powershell
Open TempFile For Output As #1
If (AidDebugging) Then ' output some extra feedback
Print #1, "Set-PSDebug -Trace 1" ' optional -- aids debugging
End If
Print #1, "$img = get-clipboard -format image"
Print #1, "$img.save(""" & Destination & """)"
If (AidDebugging) Then ' leave the PowerShell execution record on the screen for review
Print #1, "Read-Host -Prompt ""Press <Enter> to continue"" "
WindowStyle = 1 ' display window to aid debugging
Else
WindowStyle = 0 ' hide window
End If
Close #1
' Copy the desired range of cells to the clipboard as a bitmap image
RangeRef.CopyPicture xlScreen, xlBitmap
' Execute the PowerShell script
PSCommand = "POWERSHELL.exe -ExecutionPolicy Bypass -file """ & TempFile & """ "
Set WSH = VBA.CreateObject("WScript.Shell")
ErrorCode = WSH.Run(PSCommand, WindowStyle, WaitOnReturn)
If (ErrorCode <> 0) Then
MsgBox "The attempt to run a PowerShell script to save a range " & _
"as a .png file failed -- error code " & ErrorCode
End If
If (Not AidDebugging) Then
' Delete the script file, unless it might be useful for debugging
Kill TempFile
End If
End Sub
' Here's an example which tests the routine above.
Sub Test()
RangeToPNG Worksheets("Sheet1").Range("A1:F13"), "E:\Temp\ExportTest.png"
End Sub