Code Works When Using F8 but Not When Run Fully - excel

First of all I'm not very good at Excel macro.
After going through multiple forums, I managed to come up with a code to Crop images in a folder using Excel VBA.
the code opens up each image in Excel, paste in a chart, crop the image, resize to match the height & width and then replace the original image with the edited image.
Macro is working fine with F8 but when I run the macro fully, Images are not getting replaced with the edited one, instead it's replacing with blank image.
After digging through multiple options, the only conclusion I came up with is the macro is running fine in Excel 2013 but it's not running properly with office 365.
Can anybody help me, how to resolve this or have any better code to run?
Option Explicit
Sub ImportData()
Dim XL As Object
Dim thisPath As String
Dim BooksPAth As String
BooksPAth = "C:\Images\"
thisPath = ActivePresentation.path
Set XL = CreateObject("Excel.Application")
Run "Crop_vis", BooksPAth
End Sub
Sub DeleteAllShapes()
Dim Shp As Shape
For Each Shp In ActiveSheet.Shapes
If Not (Shp.Type = msoOLEControlObject Or Shp.Type = msoFormControl) Then Shp.Delete
Next Shp
End Sub
Sub Crop_Vis(ByVal folderPath As String)
Dim Shp As Object, path As String, sht As Worksheet, s As Shape, TempChart As String
'Dim folderPath As String
Application.ScreenUpdating = True
If folderPath = "" Then Exit Sub
Set sht = Sheet1
sht.Activate
sht.Range("A10").Activate
path = Dir(folderPath & "\*.jpg")
Do While path <> ""
DeleteAllShapes
Set Shp = sht.Pictures.Insert(folderPath & "\" & path)
' Use picture's height and width.
Set s = sht.Shapes(sht.Shapes.Count)
s.PictureFormat.CropTop = 50
s.Width = 768
s.Height = 720
'Add a temporary chart in sheet1
Charts.Add
ActiveChart.Location Where:=xlLocationAsObject, Name:=sht.Name
Selection.Border.LineStyle = 0
TempChart = Selection.Name & " " & Split(ActiveChart.Name, " ")(2)
With sht
'Change the dimensions of the chart to suit your need
With .Shapes(TempChart)
.Width = s.Width
.Height = s.Height
End With
'Copy the picture
s.Copy
'Paste the picture in the chart
With ActiveChart
.ChartArea.Select
.Paste
End With
'Finally export the chart
.ChartObjects(1).Chart.Export fileName:=folderPath & "\" & path, FilterName:="jpg"
'Destroy the chart. You may want to delete it...
.Shapes(TempChart).Cut
End With
path = Dir
Loop
DeleteAllShapes
Application.DisplayAlerts = False
End Sub

Before
'Finally export the chart
insert something like this, to make sure that pasting of the image into the chart has finished:
Do
If ActiveChart.Shapes.Count > 0 Then
Exit Do
End If
Loop

The problem is with the pasting. When you tell it to paste the clipboard (image) into the chart, sometimes it ignores you. When you go to export the chart, you end up with an empty image.
It's not that you have to wait for it to paste, because it's not going to - it ignored you. I have no idea why it ignores you, or why it doesn't error out when it ignores you - it just ignores you with no warning. Maybe Windows is just too busy under the hood to paste.
Basically, what you have to do is check to see if it pasted, and if not, paste again....and again....until it finally sees fit to process your instruction.
I debugged, Googled, trialed and errored and banged my head on the wall for week on this and finally ended up with this:
Sub SavePictureFromExcel(shp As Shape, SavePath As String)
Dim Imagews As Worksheet
Dim tempChartObj As ChartObject
Dim ImageFullPath As String
Set Imagews = Sheets("Image Files")
Set tempChartObj = Imagews.ChartObjects.Add(0, 0, shp.Width, shp.Height)
shp.Copy
tempChartObj.Chart.ChartArea.Format.Line.Visible = msoFalse 'No Outline
tempChartObj.Chart.ChartArea.Format.Fill.Visible = msoFalse 'No Background
Do
DoEvents
tempChartObj.Chart.Paste
Loop While tempChartObj.Chart.Shapes.Count < 1
ImageFullPath = SavePath & "\" & shp.Name & ".png"
tempChartObj.Chart.Export ImageFullPath, Filtername:="png"
tempChartObj.Delete
End Sub

Related

Rotate picture in user form

I'm trying to rotate an image inside an user form, here is the cose I'm using:
Private Declare Function GetTempPath Lib "kernel32" Alias"GetTempPathA_(ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Const MAX_PATH As Long = 260
Dim NewPath As String
Function TempPath() As String
TempPath = String$(MAX_PATH, Chr$(0))
GetTempPath MAX_PATH, TempPath
TempPath = Replace(TempPath, Chr$(0), "")
End Function
Sub RotatePic(deg As Long)
Dim ws As Worksheet
Dim p As Object
Dim chrt As Chart
'~~> Adding a temp sheet
Set ws = ThisWorkbook.Sheets.Add
'~~> Insert the picture in the newly created worksheet
Set p = ws.Pictures.Insert(**PROBLEM**)
'~~> Rotate the pic
p.ShapeRange.IncrementRotation deg
'~~> Add a chart. This is required so that we can paste the picture in it
'~~> and export it as jpg
Set chrt = Charts.Add()
With ws
'~~> Move the chart to the newly created sheet
chrt.Location Where:=xlLocationAsObject, Name:=ws.Name
'~~> Resize the chart to match shapes picture. Notice that we are
'~~> setting chart's width as the pictures `height` becuse even when
'~~> the image is rotated, the Height and Width do not swap.
With .Shapes(2)
.Width = p.Height
.Height = p.Width
End With
.Shapes(p.Name).Copy
With ActiveChart
.ChartArea.Select
.Paste
End With
'~~> Temp path where we will save the pic
NewPath = TempPath & "NewFile.Jpg"
'~~> Export the image
.ChartObjects(1).Chart.Export filename:=NewPath, FilterName:="jpg"
End With
'~~> Delete the temp sheet
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End Sub
the problem (you can see PROBLEM in the code) is that I don't know how to get the path of the picture that is in image box (I upload the picture through a image dialog)
How can I solve?
May simply try like this
Code:
Private Sub CommandButton1_Click()
Me.Image1.Picture = LoadPicture("C:\users\user\desktop\Range.jpg")
End Sub
Sub test()
Dim Ws As Worksheet, fname As String
Dim Shp As ShapeRange, p As Object
Dim Chrt As Chart
fname = "C:\users\user\desktop\TempXXX.jpg"
Set Ws = ThisWorkbook.Sheets("Sheet1")
SavePicture Me.Image1.Picture, fname
DoEvents
Set p = Ws.Pictures.Insert(fname)
p.ShapeRange.Rotation = 90
Ws.Shapes(p.Name).Copy
Set Chrt = Ws.ChartObjects.Add(10, 10, Ws.Shapes(p.Name).Height, Ws.Shapes(p.Name).Width).Chart
Chrt.Paste
Chrt.Export Filename:=fname, FilterName:="jpg"
DoEvents
Me.Image1.Picture = LoadPicture(fname)
'clean temp objects
Kill fname
p.Delete
Chrt.Parent.Delete
End Sub
Private Sub CommandButton2_Click()
test
End Sub
The ".chart" method described above is a hack. It cost me 12 hours of debugging due to the code running faster than the system as it rotates large images (which is pretty much the standard for most phones and cameras these days). Issues such as the resulting image being a blank image, to the unchanged image being loaded back into the UserForm (because the code has run on to insert the image from the specified directory before the system has replaced it with the rotated image. No amount of Wait, Sleep, DoEvents, solved this. It works when stepping through fine but not in real-time for me, I'm afraid.
The solution is to implement the Windows Image Acquisition API. Daniel Pineault has developed a tidy VBA function here. This should be the go-to solution.

Run a Power point macro code for other PPTs

I have a macro code named "KillSpecificSlide" for power point. This codes is run behind ppt.If I want to copy the same code to some another ppt or if I want to run the code from One PPT to some other different PPTs then How to do this?
My code is given below:
Sub KillSpecificSlide()
Dim oSld As Slide
Dim oShp As Shape
Dim L As Long
For L = ActivePresentation.Slides.Count To 1 Step -1
Set oSld = ActivePresentation.Slides(L)
For Each oShp In oSld.Shapes
If oShp.HasTextFrame Then
Select Case UCase(oShp.TextFrame.TextRange)
Case Is = "Q4", "CJ"
oSld.Delete
Case Else
'not found
End Select
End If
Next oShp
Next L
End Sub
This is saved in Module 1 of a PPT named BOX.pptm..I want to run the same code for other ppt files by browsing it.
Sub PPTTest()
Dim PPT As Object
Set PPT = CreateObject("PowerPoint.Application")
PPT.Presentations.Open "D:\Us\70\Desktop\Shaon\BOD.pptx", , , False
' Note that the file name and the module
' name are required to path the macro correctly.
PPT.Run "BOD.pptx!Module1.KillSpecificSlide"
End Sub
Option Explicit
Sub listOpenPresentations()
Dim myPpt As Presentation
Debug.Print "Open ppt's : "; Application.Presentations.Count & vbCrLf
For Each myPpt In Application.Presentations
Debug.Print myPpt.Name
Call Add_and_Delete_Slide(myPpt)
Next myPpt
End Sub
Sub Add_and_Delete_Slide(locPPT As Presentation)
Dim pptSlide As Slide
Dim pptLayout As CustomLayout
Dim actWindow As Variant
For Each actWindow In Windows
If actWindow.Caption = locPPT.Name Then actWindow.Activate
Next actWindow
Set pptLayout = ActivePresentation.Slides(1).CustomLayout
Set pptSlide = ActivePresentation.Slides.AddSlide(2, pptLayout)
MsgBox "Slide 2 added in """ & ActivePresentation.Name & """"
ActivePresentation.Slides(2).Delete
MsgBox "Slide 2 deleted in """ & ActivePresentation.Name & """"
End Sub

Excel image comments --> picture objects

I get an excel report each week with images in the comments.
I am trying to loop through all comments in the file, and paste all the comments to the worksheet as pictures
I have tried the method found on the "Ku Tools" website...
https://www.extendoffice.com/documents/excel/4328-excel-extract-image-from-comment.html
Here is the code from the website (that i use exactly)...
Sub CommentPictures()
'Updateby Extendoffcie 20161207
Dim cmt As Comment
Dim xRg As Range
Dim visBool As Boolean
Dim cmtTxt As String
Dim jpgPath As String
Dim shpHeight As Integer, shpWidth As Integer
Application.ScreenUpdating = False
For Each cmt In ActiveSheet.Comments
With cmt
cmtTxt = .Text
shpHeight = .Shape.Height
shpWidth = .Shape.Width
.Text Text:="" & Chr(10) & ""
visBool = .Visible
.Visible = True
On Error Resume Next
Set xRg = .Parent.Offset(0, 1)
.Shape.CopyPicture _
Appearance:=xlScreen, Format:=xlPicture
xRg.PasteSpecial
Selection.ShapeRange.LockAspectRatio = msoFalse
Selection.Width = xRg.Width
Selection.Height = xRg.Height
.Visible = visBool
.Text Text:=cmtTxt
End With
Next cmt
Application.ScreenUpdating = True
End Sub
When I use this code, it works sporadically
When it "doesn't work", the macro creates an invisible rectangle object
When it does work, it creates a visible rectangle image/object (rectangle shape that can be seen).
In the below screenshot, row 715 contains a visible image (when the macro works right) and row 755 contains an invisible image (when it doesn't work right)
Visible vs Non-Visible
I want to make all 700+ image comments actual images as easily as possible, if anyone has any ideas, they would be greatly appreciated.
My hypothesis is that there might be a size limit, because the macro worked perfectly when I ran it in a small batch of a couple dozen images
Thanks

Bug Fixing: Copied images in Excel 2016 VBA appear as blank images

I am trying to export into my local file a defined Excel range as image (PNG) (it’s named: “ Print_Area” on tab “Summary” Range: P1:AI92 ) . The program runs well, however when I open the file all the imagines are blank
Here is the coding that I am using:
Sub _Daily_Mail()
Dim Rango7 As Range
Dim Archivo As String
Dim Imagen As Chart
Dim Result As Boolean
Set Rango7 = Sheets("Summary").Range("P2:AI92") ' Summary
Sheets("Summary").Select
With Rango7
.CopyPicture Appearance:=xlScreen, Format:=xlPicture
Set Imagen = Rango7.Parent.ChartObjects.Add(33, 39, .Width, .Height).Chart
End With
Imagen.Paste
Imagen.ChartArea.Border.LineStyle = 0
Imagen.ChartArea.Width = Imagen.ChartArea.Width * 3
Imagen.ChartArea.Height = Imagen.ChartArea.Height * 3
Imagen.export "C:\Users\mely\Documents\Imagenes_POS\Informe1.png", filtername:="PNG"
Imagen.Parent.Delete
Set Imagen = Nothing
When I open the file
In Excel 2016 you need to use .Activate command before Paste operation.
Example:
Set rng = Range("A1:C1")
With rng
.CopyPicture xlPrinter, xlPicture
Set oChart = ActiveSheet.ChartObjects.Add(.Left, .Top, 1920, 1080)
oChart.Activate
With oChart.Chart
.ChartArea.Border.LineStyle = 0
.Paste
.Export Filename:="C:\File.jpg", Filtername:="jpg"
.Parent.Delete
End With
End With
I am running into the same issue with office 2016. It appears to be a timing issue. When creating the Chart Object and being able to paste to it. If I step through the code it works as expected and generates my image.
I came up with a fix which appears to work:
For some reason selecting The chart's parent shape before calling the Paste corrects The issue.
Function CopyRangeToPNG(ByRef rngImage As Range) As String
Dim vFilePath As Variant
rngImage.CopyPicture Appearance:=xlScreen, Format:=xlPicture
With rngImage.Parent.ChartObjects.Add( _
Left:=rngImage.Left, Top:=rngImage.Top, _
Width:=rngImage.Width + 2, Height:=rngImage.Height + 2)
With .Chart
.Parent.Select
.ChartArea.Format.Line.Visible = msoFalse
.Paste
With .Pictures(1)
.Left = .Left + 2
.Top = .Top + 2
End With
' export
.Export CStr(ThisWorkbook.Path & "\ImageName.PNG")
End With
.Delete
End With
CopyRangeToPNG = ThisWorkbook.Path & "\ImageName.PNG"
End Function

How do I rotate a saved image with VBA?

I currently have a userform in excel with images displayed on it (saved in a temporary folder "C:\Temp\Photos")
What I want to do is have buttons (90, 180, 270) for rotating the images located in "C:\Temp\Photos". Thinking it may be an FileSystemObject but dont know enough about them yet to know how to do this.
EDIT: Added some code by request. Pictures are inserted depending on value selected in combobox. Any changes would reference pic1-pic5 (only ever 5 pics at any time).
Private Sub ComboBox1_Change()
pic1 = "C:\Temp\Photos\" & Me.ComboBox1.Text & "\1.jpg"
pic2 = "C:\Temp\Photos\" & Me.ComboBox1.Text & "\2.jpg"
pic3 = "C:\Temp\Photos\" & Me.ComboBox1.Text & "\3.jpg"
pic4 = "C:\Temp\Photos\" & Me.ComboBox1.Text & "\4.jpg"
pic5 = "C:\Temp\Photos\" & Me.ComboBox1.Text & "\5.jpg"
If Dir(pic1) <> vbNullString Then
Me.Image1.Picture = LoadPicture(pic1)
Else
Me.Image1.Picture = LoadPicture("")
End If
If Dir(pic2) <> vbNullString Then
Me.Image2.Picture = LoadPicture(pic2)
Else
Me.Image2.Picture = LoadPicture("")
End If
If Dir(pic3) <> vbNullString Then
Me.Image3.Picture = LoadPicture(pic3)
Else
Me.Image3.Picture = LoadPicture("")
End If
If Dir(pic4) <> vbNullString Then
Me.Image4.Picture = LoadPicture(pic4)
Else
Me.Image4.Picture = LoadPicture("")
End If
If Dir(pic5) <> vbNullString Then
Me.Image5.Picture = LoadPicture(pic5)
Else
Me.Image5.Picture = LoadPicture("")
End If
End Sub
Like I mentioned, there is no inbuilt way to rotate a picture in userform. Having said that, there is an alternative to achieve what you want. Below I have demonstrated on how to rotate the image 90 degrees.
Logic:
Insert a temp sheet
Insert the image into that sheet
Use IncrementRotation rotation property
Export the image to user's temp directory
Delete the temp sheet
Load the image back
Preparing your form
Create a userform and insert an image control and a command button. Your form might look like this. Set the Image Control's PictureSizeMode to fmPictureSizeModeStretch in the properties window.
Code:
I have written a sub RotatePic to which you can pass the degree. Like I mentioned that This example will rotate it 90 degrees as I am just demonstrating for 90. You can create extra buttons for rest of the degrees. I have also commented the code so you shouldn't have any problem understanding it. If you do then simply ask :)
Option Explicit
'~~> API to get the user's temp folder path
'~~> We will use this to store the rotated image
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
(ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Const MAX_PATH As Long = 260
Dim NewPath As String
'~~> Load the image on userform startup
Private Sub UserForm_Initialize()
Image1.Picture = LoadPicture("C:\Users\Public\Pictures\Sample Pictures\Koala.jpg")
End Sub
'~~> Rotating the image 90 degs
Private Sub CommandButton1_Click()
RotatePic 90
DoEvents
Image1.Picture = LoadPicture(NewPath)
End Sub
'~~> Rotating the image
Sub RotatePic(deg As Long)
Dim ws As Worksheet
Dim p As Object
Dim chrt As Chart
'~~> Adding a temp sheet
Set ws = ThisWorkbook.Sheets.Add
'~~> Insert the picture in the newly created worksheet
Set p = ws.Pictures.Insert("C:\Users\Public\Pictures\Sample Pictures\Koala.jpg")
'~~> Rotate the pic
p.ShapeRange.IncrementRotation deg
'~~> Add a chart. This is required so that we can paste the picture in it
'~~> and export it as jpg
Set chrt = Charts.Add()
With ws
'~~> Move the chart to the newly created sheet
chrt.Location Where:=xlLocationAsObject, Name:=ws.Name
'~~> Resize the chart to match shapes picture. Notice that we are
'~~> setting chart's width as the pictures `height` becuse even when
'~~> the image is rotated, the Height and Width do not swap.
With .Shapes(2)
.Width = p.Height
.Height = p.Width
End With
.Shapes(p.Name).Copy
With ActiveChart
.ChartArea.Select
.Paste
End With
'~~> Temp path where we will save the pic
NewPath = TempPath & "NewFile.Jpg"
'~~> Export the image
.ChartObjects(1).Chart.Export Filename:=NewPath, FilterName:="jpg"
End With
'~~> Delete the temp sheet
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End Sub
'~~> Get the user's temp path
Function TempPath() As String
TempPath = String$(MAX_PATH, Chr$(0))
GetTempPath MAX_PATH, TempPath
TempPath = Replace(TempPath, Chr$(0), "")
End Function
In Action
When you run the userform, the image is uploaded and when you click on the button, the image is rotated!
The only way I see of doing this would be to copy the picture into a chart, rotate it, export it, and re-open it inside the form the same way you are displaying pictures right now.
Try this.
Change
If Dir(pic1) <> vbNullString Then
Me.Image1.Picture = LoadPicture(pic1)
Else ...
To
If Dir(pic1) <> vbNullString Then
pic1 = myFunction(pic1, rotationDegree)
Me.Image1.Picture = LoadPicture(pic1)
Else ...
(And everywhere else this structure is used)
Insert, inside a module, the following function :
Public Function myFunction(myPicture As String, myRotation As Integer) As String
ActiveSheet.Pictures.Insert(myPicture).Select
Selection.ShapeRange.IncrementRotation myRotation
Selection.CopyPicture
tempPictureName = "C:\testPic.jpg"
'Change for the directory/filename you want to use
Set myChart = Charts.Add
myChart.Paste
myChart.Export Filename:=tempPictureName, Filtername:="JPG"
Application.DisplayAlerts = False
myChart.Delete
Selection.Delete
Application.DisplayAlerts = True
myFunction = myDestination
End Function
EDIT : Took so long to get the time to finish writing the post (from work) that I missed the other user's answer, which seems to use the same logic. However, my approach might be easier to use for you!
EDIT2 : rotationDegree needs to be set to the degree of the rotation (which needs to be determined before retrieving the picture).

Resources