Scaling pictures using Excel VBA - excel

I’m trying to scale pictures to fit on a cell of height 172.75.
If sPhoto > -1 Then
x.RowHeight = AltRow + x.Font.Size + 2
On Error GoTo IsError
factor = CSng(AltRow / Selection.ShapeRange.Height)
If factor > CSng(x.Width / Selection.ShapeRange.Width) Then
factor = CSng(x.Width / Selection.ShapeRange.Width)
End If
If factor < 0.5 Then
factor = factor / 3.8
End If
With Selection
.ShapeRange.LockAspectRatio = msoTrue
.ShapeRange.ScaleWidth factor, msoTrue, msoScaleFromTopLeft
.ShapeRange.ScaleHeight factor, msoTrue, msoScaleFromTopLeft
.ShapeRange.Top = x.Top
.ShapeRange.Left = x.Left
End With
End If
Some pictures have a really big size in terms of height and width in their original format. I need the scale factor to more flexible.

Found a way to scale the pictures to snap to the bounds of the cell.
Dim AspectRatio As Double
Dim W, H As DoubleI
if SketchPhoto > -1 Then
x.RowHeight = AltRow + x.Font.Size + 2 'Adjusting height to fit the picture for each cell
With Selection.ShapeRange
.LockAspectRatio = msoTrue
AspectRatio = .Width / .Height
.Left = x.Left
.Top = x.Top
W = x.Width ' width of cell range
H = x.Height ' height of cell range
If (W / H < AspectRatio) Then
.Width = W - x.Font.Size + 0.5 ' scale picture to available width
Else
.Height = H - x.Font.Size + 0.5 ' scale picture to available height
End If
Range("A1").Activate
End With
End If

Related

VBA excel .Left .Top when picture is rotated

I tried countlessly but I still have this problem. I try to fit a picture in to a given range with a macro in excel. As long as the picture is not rotate (orientation = 0) there's not a problem. But from the moment the picture gets rotated everything bleeds out. I have already discovered that the picture height and width are rotated as wel. But what happens to the .top and .left? Here's my code:
Function fotoInsert(ByVal PictureFileName As String, ByVal rng As Range)
Set pic = ActiveSheet.Pictures.Insert(PictureFileName)
If pic.ShapeRange.Rotation = 90 Then
With pic
'keep original aspect ratio
.ShapeRange.LockAspectRatio = msoTrue
'Picture's aspect is less than rng aspect then adjust the picture's width to fit rng
If (pic.Width \ pic.Height) <= (rng.Height \ rng.Width) Then
.Width = rng.Height - 1 'pictures' width is the larger height, by this line it fits exactly into range width
.Left = rng.Left + ((rng.Width - pic.Height) / 2)
.Top = rng.Top + 1
Else 'Picture's aspect is greater than rng aspect then adjust the picture's height to fit rng
.Width = rng.Height - 1 'picture's heigth is larger than its width, this line makes it exactly fit int range height
.Top = rng.Top
.Left = rng.Left
End If
.Placement = xlMoveAndSize
.PrintObject = True
End With
Else
With pic
'keep original aspect ratio
.ShapeRange.LockAspectRatio = msoTrue
'Picture's aspect is less than rng aspect then adjust the picture's width to fit rng
If (.Height \ .Width) <= (rng.Height \ rng.Width) Then
.Width = rng.Width - 1 'pictures' width is the larger height, by this line it fits exactly into range width
.Left = rng.Left + 1 'position at left range border
.Top = rng.Top + ((rng.Height - pic.Height) / 2) 'position in center of range height
Else 'Picture's aspect is greater than rng aspect then adjust the picture's height to fit rng
.Top = rng.Top + 1 'position at upper border of the range[/color]
.Height = rng.Height - 1 'picture's heigth is larger than its width, this line makes it exactly fit int range height
.Left = rng.Left + ((rng.Width - pic.Width) / 2) 'position in center of range width
End If
.Placement = xlMoveAndSize
.PrintObject = True 'make sure picture gets printed
End With
End If
End Function
So the problem occurs in the very first If condition (rotation = 90)
In the other cases I don't seem to have a problem.
A typical range I use to test is:
"A7:N46"
Thanks for your fast response!
What I try to do is to fit any given picture in a pre determined range. So yes, I also will receive rotated pictures.
The idea is that the user selects pictures (up to 4) and automatically they are arranged and resized to fit in one pre-determined excel sheet. So I made 4 scenario's (with different ranges) how to arrange those pictures on one sheet. This is done in an other routine via a switch case.
So far this code works with non rotated pictures. From the moment there's a rotation in there it is getting messy and pictures 'bleed out'. If there's an other way to tackle my problem, I'm glad to here it.
I had exactly the same problem as described here. It is unclear what happens with top and left properties of the shaperange when rotation 90 or 270 occurs.
In case of rotation, my workaround was:
create a new hidden sheet;
insert the rotated picture;
hard code the position of the picture;
copy the rows to the range where you want it;
delete the temporary sheet.

Coloring Circle in Vba

I am new to Vba, I have to draw circles which are color filled in the following way
1/4 color filled circle,
Half color filled circle,
3/4 color filled circle
I know I can draw a color-filled circle with the following code
Set shpOval = ActiveSheet.Shapes.AddShape(msoShapeOval, curCellLeft, curCellTop, 20, 20)
shpOval.Fill.ForeColor.RGB = RGB(128, 0, 0)
Above code gives me a full color filled circle, which property I have to change to get circle shapes that I have mentioned above.
Just for fun: Playing around with PIE-Shapes.
Sub DrawCircle(pieces As Integer, size As Double, position As Range, color)
If pieces < 1 Then pieces = 1
If pieces > 4 Then pieces = 4
Dim varShape() As String
ReDim shapeNames(0 To pieces - 1)
Dim i As Long
For i = 0 To pieces - 1
Dim sh As Shape
Dim x As Double, y As Double
x = position.Left + IIf(i = 1 Or i = 2, size, 0)
y = position.Top + IIf(i >= 2, size, 0)
Set sh = position.Parent.Shapes.AddShape(msoShapePieWedge, x, y, size, size)
shapeNames(i) = sh.Name
sh.Rotation = i * 90
If IsArray(color) Then
sh.Fill.ForeColor.RGB = color(i + LBound(color))
Else
sh.Fill.ForeColor.RGB = color
End If
sh.Line.Visible = False
Next i
If pieces > 1 Then
position.Parent.Shapes.Range(shapeNames).Group
End If
End Sub
Playing with it:
Sub test()
Call DrawCircle(3, 20, ActiveCell, vbRed)
Call DrawCircle(4, 10, ThisWorkbook.Sheets(1).Range("F3"), Array(vbYellow, vbYellow, vbBlue, vbYellow))
Call DrawCircle(1, 40, ActiveCell.Offset(2, 2), vbGreen)
End Sub
Create a range of values in excel from A1 to A4 as 25,50,75,100. Go to Insert and select "Doughnut" chart.

Inserting a picture in the correct position

I'm using a code that inserts a picture (column A) of the corresponding item number located in Column B.
Current positioning of the picture:
However, the pictures that are inserted are located in the top left corner of each cell and I'd like to have them in the center of the cell a little below the cell line (cell size is 54 and picture is 50).
Here's the code that I use:
Sub InsertImageFullName()
On Error Resume Next
Application.ScreenUpdating = False
Dim path$, cl As Range, myPicture As Object
Set Rng = Range("A2:A300")
cell_h = Range("A2").Top - Range("A1").Top
For Each cl In Rng
path = cl.Offset(0, 8).Value
If path Like "*?*" Then
Set myPicture = ActiveSheet.Pictures.Insert(path)
With myPicture
.ShapeRange.LockAspectRatio = msoTrue
.Height = 50
.Top = Rows(cl.Row).Top
.Left = Columns(cl.Column).Left
End With
End If
Set myPicture = Nothing
Next
End Sub
What needs to be modified to make this work ?
Any help is greatly appreciated
To set the position of the picture you youst need to adjust the top and left position of it.
.Top = Rows(cl.Row).Top
.Left = Columns(cl.Column).Left
So you just need to add something. So if your cell height is 54 and your picture height is 50 and your picture should be centered the amount you need to add calculates like add = (CellHeight - PictureHeight) / 2 which is (54 - 50) / 2 which is 2 so you need to add 2 to the .Top position:
.Top = Rows(cl.Row).Top + 2 'add 2 to the top position of your picture.
You know image width and height by myPicture.Width and myPicture.Height. And cell width and height by cl.Width and cl.Height
Image top position is Cell top + (Cell top - Image Height) / 2
And image left position is Cell left + (Cell left - Image Width) / 2
So you need to Change your code from
.Top = Rows(cl.Row).Top
.Left = Columns(cl.Column).Left
End With
To
.Top = cl.Top + (cl.Height - myPicture.Height) / 2
.Left = cl.Left + (cl.Width - myPicture.Width) / 2
End With
Try to use Vertical Alignment and Horizontal Alignment on Range object to align content of a cell properly.

Positioning labels on a donut-chart

I have the following code which attempts to add a datalabel to a point in a combined donut/pie-chart:
For Each co In .ChartObjects
With co.Chart.FullSeriesCollection("Grøn pil").Points(2)
.HasDataLabel = True
With .DataLabel
.Position = xlLabelPositionOutsideEnd
.Format.AutoShapeType = msoShapeRectangle
.Format.Line.Visible = msoTrue
End With
End With
Next co
However, the code aborts on the line .Position = xlLabelPositionOutsideEnd with the error message "Run-time error 2147467259 (80004005)". Method 'Position' of object 'DataLabel' failed".
Looking at the chart, the label has been added, but it is still positioned inside the chart.
As you can see I've already positioned a label outside the chart for a different series, which is represented as a pie chart. While the series I am trying to add the label to is represented as a donut-chart.
Can't I have both the labels for the donut- and pie-chart on the outside? Isn't xlLabelPositionOutsideEnd a valid position for labels of a donut-chart? Or is the problem something else which eludes me?
Any help would be greatly appreciated!
I don't think it's possible to do exactly you want to do the way you want to do it! The option to place the labels outside the chart is not available on the doughnut chart options:
like they do on a pie chart:
However, you could perform a trick using a pie chart and a white circle to make it look like a doughnut by doing the following:
Sub AddCircle()
'Get chart size and position:
Dim CH01 As Chart: Set CH01 = ThisWorkbook.Sheets("Sheet1").ChartObjects("Chart1").Chart
Dim OB01 As ChartObject: Set OB01 = CH01.Parent
Dim x As Double: x = 0 'horizontal coordinate
Dim y As Double: y = 0 'vertical coordinate
Dim w As Double: w = 0 'width
Dim h As Double: h = 0 'height
x = OB01.Left
y = OB01.Top
w = OB01.Width
h = OB01.Height
'Adding the circle:
ThisWorkbook.Sheets("Sheet1").Shapes.AddShape(msoShapeOval, x + w / 2 - 20, y + h / 2 - 20, 40, 40).Name = "Circle01"
'Formatting the circle:
With ThisWorkbook.Sheets("Sheet1").Shapes("Circle01")
.LINE.Visible = msoFalse
.Fill.ForeColor.RGB = RGB(255, 255, 255)
End With
End Sub
And it works very nicely:
Had some fun "solving" this one...
Working with sinus and cosinus we can also calculate the outside position of the label. Following a VB snippet, how this can be done:
Sub Macro1()
Dim cx
Dim cy
Dim x
Dim y
Dim radius
Dim angle
Dim new_radius
Dim new_x
Dim new_y
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveSheet.ChartObjects("Chart 1").Select
cx = Selection.width / 2
cy = Selection.height / 2
For i = 1 To ActiveChart.FullSeriesCollection(1).Points.Count Step 1
ActiveChart.FullSeriesCollection(1).Points(i).DataLabel.Select
x = Selection.left + (Selection.width / 2)
y = Selection.top + (Selection.height / 2)
radius = Sqr(((x - cx) ^ 2) + ((y - cy) ^ 2))
angle = WorksheetFunction.Atan2(y - cy, x - cx)
new_radius = radius + 40
new_x = cx + (Sin(angle) * new_radius)
new_y = cy + (Cos(angle) * new_radius)
Selection.left = new_x - (Selection.width / 2)
Selection.top = new_y - (Selection.height / 2)
Next i
End Sub

Changing Color of Chart Shape Textbox (Excel VBA)

Having trouble figuring out how to take the input of a .Font.ColorIndex and using it to change the font color of a chart's textbox shape.
.Font.ColorIndex returns 48
When I change the color of the text in a macro, it returns this:
With Selection.ShapeRange.TextFrame2.TextRange.Font.Fill
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1 ' How to set this value from a font color? Can you?
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.5
.Transparency = 0
.Solid
End With
Is this possible?
You're mixing different color types. ObjectThemeColor represents a different type of color than what you have as 48.
Looking at Microsoft website The available options are:
You probably want to convert your ColorIndex to RGB and then insert. You'll need a custom function, but not hard. Just paste this function somewhere into your Code module.
Function getRGB(C As Long, LetterTYPE As String) As Integer
Dim R As Long
Dim G As Long
Dim B As Long
R = C Mod 256
G = C \ 256 Mod 256
B = C \ 65536 Mod 256
If UCase(LetterTYPE) = "R" Then
getRGB = R
ElseIf UCase(LetterTYPE) = "G" Then
getRGB = G
ElseIf UCase(LetterTYPE) = "B" Then
getRGB = B
End If
End Function
Then rewrite your original code to include newly created formula:
YourColor = 48
With Selection.ShapeRange.TextFrame2.TextRange.Font.Fill
.Visible = msoTrue
.ForeColor.RGB = RGB(getRGB(YourColor , "R"), getRGB(YourColor , "G"), getRGB(YourColor , "B"))
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.5
.Transparency = 0
.Solid
End With

Resources