Crop an Image (Enhanced Metafile) in PPT 2007 - vba

Can anyone help me with an issue in PPT 2007.
I have an image (a chart from excel pasted as 'Picture (Enhanced Metafile)') in a slide. I just need to crop this image to fit in the slide. I tried following code, but to no avail:
'1:
With ActivePresentation.Slides(1).Shapes(1)
.PictureFormat.CropLeft = 10
.PictureFormat.CropTop = 10
.PictureFormat.CropRight = 10
.PictureFormat.CropBottom = 10
End With
'Runtime error "ActiveX Component can't create object
'2:
ActiveWindow.Selection.ShapeRange.PictureFormat.CropRight = 10
ActiveWindow.Selection.ShapeRange.PictureFormat.CropLeft = 10
ActiveWindow.Selection.ShapeRange.PictureFormat.CropBottom = 10
ActiveWindow.Selection.ShapeRange.PictureFormat.CropTop = 10
'Object doesnt support this property or method
Any suggestion is most welcome.

This works with EMFs pasted from Excel:
Dim oSh as Shape
Set oSh = ActiveWindow.Selection.ShapeRange(1)
' Note: ShapeRange(1), not just ShapeRange
' That's the problem with your second example
With oSh
.CropLeft = 10
' etc
End With
The fact that it's yelling about an activex object in the first example makes me wonder whether the first shape is really an EMF, which would not be an ActiveX object.

Related

Change the text color of the chart title in a PowerPoint Histogram chart

I am trying to change the text color of the chart title of a histogram chart in PowerPoint.
Here is what I do:
var colorFormat = chart.ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor;
colorFormat.RGB = ...;
// or
colorFormat.ObjectThemeColor = ...;
This works for the standard charts like line charts. But it doesn't work for other chart types like histogram, waterfall, tree map etc.
In these cases, setting ObjectThemeColor sets the text to black. Setting RGB does actually set the correct color. However, in both cases, as soon as the user changes the selection, the text color jumps back to the one it had previously.
How can I set the text color of the title of one of these charts?
I am using VSTO and C# but a VBA solution is just as welcome as long as it can be translated to C# and still work.
Based on what info you gave I built a histogram and waterfall chart in PowerPoint and was successful using:
Sub ChartTitleFontColor()
Dim oShp As Shape
Dim oCht As Chart
'Waterfall on slide 1
Set oShp = ActivePresentation.Slides(1).Shapes(1)
If oShp.HasChart Then
Set oCht = oShp.Chart
End If
' Do stuff with your chart
If oCht.HasTitle Then
Debug.Print oCht.ChartTitle.Text
oCht.ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(251, 5, 40)
End If
'Histogram on slide 2
Set oShp = ActivePresentation.Slides(2).Shapes(1)
If oShp.HasChart Then
Set oCht = oShp.Chart
End If
' Do stuff with your chart
If oCht.HasTitle Then Debug.Print oCht.ChartTitle.Text
oCht.ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(251, 5, 40)
End If
' Clean up
Set oShp = Nothing
Set oCht = Nothing
End Sub
Your code works in my test. I created two charts in PowerPoint 2016, the first one a waterfall, and the second another type. The following code changes the title color only (and text just a proof of it being changed) and nothing else. I can select the other chart and nothing changes. I could not find a bug about this in a search. Perhaps something in the remaining code is changing it back?
Sub test()
Dim myPresentation As Presentation
Set myPresentation = ActivePresentation
Dim myShape As Shape
Set myShape = myPresentation.Slides(1).Shapes(1)
Dim theChart As Chart
If myShape.HasChart Then
Set theChart = myShape.Chart
If theChart.ChartTitle.Text = "This is blue" Then
theChart.ChartTitle.Text = "This is yellow"
theChart.ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 0)
Else
theChart.ChartTitle.Text = "This is blue"
theChart.ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 255, 255)
End If
End If
End Sub
This is not exactly an answer but I think you should name your object.
Instead of using
ActivePresentation.Slides(1).Shapes(1)
You can name the object.

How to find the index of a Powerpoint Shape

I'm writing a VBA script to copy+paste charts from an Excel worksheet to an existing Powerpoint presentation as Picture.
So far I was successful to do the copy-paste as Picture, but failed to change the size of the pasted picture. I believe the pasted picture is a shape, so I'm trying to do something like:
For Each iChart In arrChart
xlWorkBook.Worksheets("PPT").ChartObjects(iChart).CopyPicture
ActivePresentation.Slides(iCurrSlide).Shapes.Paste
'Reshape
ActivePresentation.Slides(iCurrSlide).Select
With ActivePresentation.Slides(iCurrSlide).Shapes.Item(5)
.Select
.Height = ActiveWindow.Presentation.PageSetup.SlideHeight
.Width = ActiveWindow.Presentation.PageSetup.SlideWidth
.Left = 0
.Top = 0
End With
iCurrSlide = iCurrSlide + 1
Next iChart
However I seem to get the wrong index, so I'm wondering if there is a way to capture the index of the picture (as a shape)? I have my hands tied as I cannot name the picture (if I'm to name each picture pasted, I'd rather throw the script into garbage can and simply paste manually), and I cannot change anything about the pptx and xlsx.
Avoid selecting anything unless it's absolutely necessary, which it seldom is.
Assuming this is happening in VBA within PPT:
Dim oSh as Shape
For Each iChart In arrChart
xlWorkBook.Worksheets("PPT").ChartObjects(iChart).CopyPicture
' Set a reference to the just-pasted shape
Set oSh = ActivePresentation.Slides(iCurrSlide).Shapes.Paste(1)
'Reshape
' You don't need this:
' ActivePresentation.Slides(iCurrSlide).Select
' With ActivePresentation.Slides(iCurrSlide).Shapes.Item(5)
With oSh
' No need to select it as long as you've got a reference to it:
'.Select
' I'd use ActivePresentation.PageSetup here but it may not matter
.Height = ActiveWindow.Presentation.PageSetup.SlideHeight
.Width = ActiveWindow.Presentation.PageSetup.SlideWidth
.Left = 0
.Top = 0
End With ' oSh
iCurrSlide = iCurrSlide + 1
Next iChart

VBA Chart automation using ActivateChartDataWindow

I'm building a chart automation script in powerpoint and i have any issue when calling upon "ActivateChartDataWindow".
I would use "Activate" instead of "ActivateChartDataWindow", but "Activate" loads the full Excel program and makes the whole routine run slow and ulgy.
The problem I have is that "ActivateChartDataWindow" does work to populate the charts, but when I manually go to edit the data - right click, edit data - to access the excel application, it does not seem to want to load!
It has been driving my crazy for the last 5 hours and would appreciate any ideas on how to over come this.
OLE.dlll are working correctly and the code I am using is given below.
Code below:
There are 5 slides with one chart on each page and the code below is what i am using as a point of concept
I have a felling i am using "ActivateChartDataWindow" wrong, but there is not much on the web to know what i am doing wrong! Arrrhhhh!
For i = 1 To 5
Set instance = Nothing
Set instance = ActivePresentation.Slides(i).Shapes(1).Chart.ChartData
With instance
.ActivateChartDataWindow
instance.Workbook.Sheets(1).Range("A1:H26").Value = 27
instance.Workbook.Close
End With
Next i
End Sub
As always recommended, you don't need to Activate an object to modify it. If you're trying to handle a Workbook embedded in a slide, you can do it this way
' This function will get you a Workbook object embedded in a Slide (late binding)
Function getEmbeddedWorkbook(sld As Slide) As Object
Dim shp As Shape
On Error Resume Next
For Each shp In sld.Shapes
If shp.Type = 3 Then ' embedded chart workbook created in PP
Set getEmbeddedWorkbook = shp.Chart.ChartData.Workbook
Exit Function
End If
If shp.Type = 7 Then ' embedded workbook pasted from excel
Set getEmbeddedWorkbook = shp.OLEFormat.Object
Exit Function
End If
Next
End Function
' For Testing, I have 6 slides, Some have a workbook pasted from Excel
' OLE, shape type = 7, others have a chart created in PP (type = 3)
Sub Test()
Dim wb As Object, i As Long
For i = 6 To 6 'ActivePresentation.Slides.Count
Set wb = getEmbeddedWorkbook(ActivePresentation.Slides(i))
If Not wb Is Nothing Then
wb.Sheets(1).Range("A1:D5").Value = i * i
End If
Next
End Sub

Code stopped working in Powerpoint 2016

Code that perfectly works in earlier versions of PPT stopped working in 2016.
When I try to change the left property of a shape in a chart, I get a Method left of object shape failed error.
I can perfectly read the .Left property.
I am running out of ideas? What can I do?
Sub test11()
Dim sld As Slide
Dim objChart As Object
Dim shpBubble As Object
Set sld = ActivePresentation.Slides("ScatterPlot01_Purch6")
Set objChart = sld.Shapes("Chart01").Chart
sld.Select
objChart.Select
Set shpBubble = objChart.Shapes("P01")
'shpBubble.Select
Debug.Print shpBubble.Left, shpBubble.Visible
shpBubble.Left = 10
End Sub
UPDATE
Having tested in PowerPoint 2010 and 2013, where it works, this now looks like a bug in 2016!
* END *
I managed to recreate the error in PowerPoint 2016 (PC) by manually adding a shape to a test chart (select the chart then click Format / Insert Shapes) and trying to write to several of it's properties including position and formatting such as changing fill colour. All generate an error.
Maybe one workaround is to use the .Delete method to delete the desired shape and then add a new shape at the required size and position. Something like this:
Sub test11()
Dim sld As Slide
Dim objChart As Chart 'Object
Dim shpBubble As Shape 'Object
Set sld = ActivePresentation.Slides("ScatterPlot01_Purch6")
Set objChart = sld.Shapes("Chart01").Chart
sld.Select
objChart.Select ' this won't work as you can only select the parent shape sld.Shapes("Chart01")
With objChart
.Shapes("P01").Delete
.Shapes.AddShape msoShapeOval, 10, 10, 20, 20
End With
End Sub
The challenge is that because the new shape is added as read only, the formatting can't be set!

Replace existing image in MS PowerPoint with a new image using VBA

I'm updating my MS PowerPoint by pasting images on different slides using VBA.
Rest of the code is working fine. What I'm unable to do is delete the existing image on all the slides and paste the new image. Currently it paste the new image on top of old image, but old image remains. I'm using below code:
Dim pptApp As PowerPoint.Application
Set pptApp = CreateObject("PowerPoint.Application")
pptApp.Visible = msoTrue
xlApp.Worksheets(2).Range("M2:S12").Copy
Set shp1 = ActivePresentation.Slides(17).Shapes.PasteSpecial(ppPasteEnhancedMetafile)(1)
With shp1
.Left = 370
.Top = 100
.Height = 360
.Width = 340
End With
Being a newbie to VBA, I dont know where and how to add delete command in above code. Any kind of help would be appreciated.
This (thanks, L42) will work for single msoPicture shapes on a slide, but if there's more than one shape, it may miss some:
Dim s As Shape
For Each s In ActivePresentation.Slides(17).Shapes
If s.Type = 13 Then s.Delete '13 is msoPicture
Next
Why? Suppose you have three shapes on the slide. We iterate through the shapes collection, find that the first shape is a picture and delete it. Now there are two shapes in the shapes collection, but VBA's counter doesn't take account of changes in the collection count. It looks at the second shape in the collection, but that's now what WAS the third shape on the slide, so the code will miss shape #2 altogether.
It's more reliable to use something like this:
Dim x as Long
For x = ActivePresentation.Slides(17).Shapes.Count to 1 Step -1
If ActivePresentation.Slides(17).Shapes(x).Type = msoPicture Then
ActivePresentation.Slides(17).Shapes(x).Delete
End If
Next
Edit1: As what Steve pointed out, the first posted solution is unreliable; also as confirmed in this POST by Doug.
To delete all pictures using loop, take Steve's approach as explained in his post.
Now, if you just want to delete all the pictures, you can try this:
ActivePresentation.Slides(17).Shapes.Range.Delete
But this deletes all shapes, not only pictures but textboxes, lines, shapes etc.
To delete only pictures, below is another approach using loop.
Dim s As Shape, pictodel As Variant
For Each s In ActivePresentation.Slides(17).Shapes
If s.Type = 13 Then
If IsArray(pictodel) Then
ReDim Preserve pictodel(UBound(pictodel) + 1)
pictodel(UBound(pictodel)) = s.Name
Else
pictodel = Array(s.Name)
End If
End If
Next
ActivePresentation.Slides(17).Shapes.Range(pictodel).Delete
Hope this helps but a simpler solution would be Steve's. :)