Xojo Blog: Centering a Picture on any Graphic Context

Until now, I used a Method to do that. Why using a Method Class Extension ?

Also, the used size variables are declared as Integer. I noticed years ago that using Integer (as said the LR) produce wrong results, sometimes: I resize images to 210 dots tall, and sometimes I get 209 pixels tall. *

So, I decided to use double and i go no more get “wrong” result.

  • The base images I use to shrink to 210 pixels tall are magazine covers (Portrait orientation), and of course, I keep the Width/Height ratio (computed).

there is this other options
https://thezaz.com/blog/quicker_tip_centering_a_pictur

[quote=492685:@Emile Schwarz]Until now, I used a Method to do that. Why using a Method Class Extension ?
[/quote]
There’s very little difference except for the syntax of how you call it.

CenterPicture(Picture1.Graphics, Picture2)
vs.
Picture1.Graphics.CenterPicture(Picture2)

You can use integers, just remember to round all the results.

dim n as integer
n = 419/2    // 209
n = round(419/2)  // 210

I know you are talking about Graphics, but if you need to resize the Picture image and, optionally, keep it both proportional to the original and/or centre it in the frame:

[code]Protected Function getResizePictureWAD(myPicture As Picture, areaWidth As Integer, areaHeight As Integer, isProportional As Boolean = True, isCentrePicture As Boolean = True) as Picture
Dim tempPicture As Picture
Dim Ratio As Double

If myPicture = Nil Then
Return Nil
End If

If areaWidth < 1 Or areaHeight < 1 Then
Return Nil
End If

Ratio = myPicture.width / myPicture.height

If isProportional And Ratio <> 1 Then
If myPicture.Width > myPicture.Height Then
tempPicture = New Picture(areaWidth, areaHeight)
If isCentrePicture Then
Var NewHeight As Double = areaHeight * (myPicture.height / myPicture.width)
Var NewTop As Double = (areaHeight - (NewHeight)) / 2

    tempPicture.Graphics.DrawPicture(myPicture, 0, NewTop, areaWidth, NewHeight, 0, 0, myPicture.Width, myPicture.Height)
  Else
    tempPicture.Graphics.DrawPicture(myPicture, 0, 0, areaWidth, areaWidth / Ratio, 0, 0, myPicture.Width, myPicture.Height)
  End If
Else
  tempPicture = New Picture(areaWidth, areaHeight)
  If isCentrePicture Then
    Var NewWidth As Double = areaWidth * (myPicture.Width / myPicture.Height)
    Var NewLeft As Double = (areaWidth - (NewWidth)) / 2
    
    tempPicture.Graphics.DrawPicture(myPicture, NewLeft, 0, NewWidth, areaHeight, 0, 0, myPicture.Width, myPicture.Height)
    
  Else
    tempPicture.Graphics.DrawPicture(myPicture, 0, 0, areaHeight * Ratio, areaHeight, 0, 0, myPicture.Width, myPicture.Height)
  End If
End If

Else
tempPicture = New Picture(areaWidth, areaHeight)
tempPicture.Graphics.DrawPicture(myPicture, 0, 0, areaWidth, areaHeight, 0, 0, myPicture.Width, myPicture.Height)
End If

Return tempPicture
End Function[/code]

i take Javier code and adjust it include whether to center the image or not and remove code as follows which simply assign the picture to the canvas without doing any scaling (which is wrong)

 If image.Width <= g.Width And image.Height <= g.Height Then
    Width = image.Width
    Height = image.Height
  Else
  end if

this is my function with the extra parameter

Public Sub CenterPicture(Extends g as Graphics, Image as Picture, bCenter as Boolean)
  If Not (image Is Nil) Then
    
    Dim Height, Width As Integer
    Dim SourceY, SourceX As Integer = 0
    
    If g.Width >= g.Height And image.Width >= image.Height Then
      //***************************
      // pic: landscape + cvs: landscape
      //***************************
      Width = g.Width
      Height = (Image.Height * Width) / image.Width
      If Height > g.Height Then
        Height = g.Height
        Width = (image.Width * Height) / image.Height
      End If
      SYSTEM.DEBUGLOG "pic: landscape + cvs: landscape"
      
    ElseIf g.Width >= g.Height And image.Width <= image.Height Then
      //***************************
      // pic: landscape + cvs: portrait
      //***************************
      Height = g.Height
      Width = (image.Width * Height) / image.Height
      If Width > g.Width Then
        Width = g.Width
        Height = (image.Height * Width) / image.Width
      End If
      SYSTEM.DEBUGLOG "pic: portrait + cvs: landscape"
      
    ElseIf g.Width <= g.Height And image.Width >= image.Height Then
      //***************************
      // pic: portrait + cvs: landscape
      //***************************
      Width = g.Width
      Height = (image.Height * Width) / image.Width
      If Height > g.Height Then
        Height = g.Height
        Width = (image.Width * Height) / image.Height
      End If
      SYSTEM.DEBUGLOG "pic: portrait + cvs: landscape"
      
    ElseIf g.Width <= g.Height And image.Width <= image.Height Then
      //***************************
      // pic: portrait + cvs: portrait
      //***************************
      Height = g.Height
      Width = (image.Width * Height) / image.Height
      If Width > g.Width Then
        Width = g.Width
        Height = (image.Height * Width) / image.Width
      End If
      SYSTEM.DEBUGLOG "pic: portrait + cvs: portrait"
      
    End If
    
    If bCenter Then
      sourcex = (g.Width / 2) - (Width / 2)
      sourcey = (g.Height / 2) - (Height / 2)
    Else
      sourcex = 0
      sourcey = 0
    End If
    g.DrawPicture(image, sourcex, sourcey, Width, Height, 0, 0, image.Width, Image.Height)
    
  End If
End Sub

JFC all this code is so obtuse. It doesn’t need to be so complex. To comply with rules, here’s the code from my blog post.

[code] Public Sub CenterPicture(Extends Target As Graphics, Pic As Picture)
If Pic Is Nil Then
Return
End If

// We need the smallest ratio. Limit to a max of 1.0 to prevent scaling up.
Var Ratio As Double = Min(Target.Width / Pic.Width, Target.Height / Pic.Height, 1.0)

// Despite Graphics accepting Doubles now, use Integer for improved sharpness.
// More advanced code would round to a factor evenly divisible by the scale factor of Target.
// Don’t use Round, because one dimension might round differently than the other. Use Floor or Ceil.
Var Width As Integer = Floor(Pic.Width * Ratio)
Var Height As Integer = Floor(Pic.Height * Ratio)

// Now it’s simple math to center it
Var Left As Integer = Floor((Target.Width - Width) / 2)
Var Top As Integer = Floor((Target.Height - Height) / 2)

// And draw it
Target.DrawPicture(Pic, Left, Top, Width, Height, 0, 0, Pic.Width, Pic.Height)
End Sub[/code]

https://thezaz.com/blog/quicker_tip_centering_a_pictur

[quote=492848:@Thom McGrath]JFC all this code is so obtuse. It doesn’t need to be so complex. To comply with rules, here’s the code from my blog post.

https://thezaz.com/blog/quicker_tip_centering_a_pictur[/quote]

i try your code, and for some reason, under certain condition does not scale at all just like the code below from JM that i have removed . it does work the same as JM code for most of time

 If image.Width <= g.Width And image.Height <= g.Height Then
    Width = image.Width
    Height = image.Heigh
end if

[quote=492856:@Richard Duke]i try your code, and for some reason, under certain condition does not scale at all just like the code below from JM that i have removed . it does work the same as JM code for most of time

If image.Width <= g.Width And image.Height <= g.Height Then Width = image.Width Height = image.Heigh end if [/quote]
Well you should never scale up. But if you really want it to, remove the 1.0 from the Min function when finding the ratio. That’s why the comments say [quote]Limit to a max of 1.0 to prevent scaling up.[/quote]

brilliant… thom… i am using your code now but with another parameter whether to ScaleUp or not and use the following if ScaleUp =yes

Ratio = Min(Target.Width / Pic.Width, Target.Height / Pic.Height)