Heads up with BitmapForCaching

This works fine on macOS
But on Windows if you use bitmapforcahcing to hold onto a picture properly configured like the graphics you get in a paint event (so you can do measurements etc outside the pain event) and use code like

Dim p As picture = Self.BitmapForCaching(1,1)

System.debuglog "g.StringWidth = " + Str(g.StringWidth("abcdefghijklmn"))
System.debuglog "p.Graphics.StringWidth = " + Str(p.Graphics.StringWidth("abcdefghijklmn"))

you will find that you do NOT get the same measurements

The recommendation is to create a picture with alpha and then it measures the same way the graphics surface does. Which means you need to write your own version of bitmapforcaching :frowning:

And here you go
So you can, for windows, pass in a depth which is needed if you want to get string measurements the same as you would get from the graphics in a paint event

This at least gives you the option to get one that measures strings the same

And, like so many things, it doesnt matter which you use on macOS as it just measures the same either way

Public Function BetterBitmapForCaching(extends g as graphics, width as integer, height as integer, depth as integer = 0) as Picture
  Dim p As picture
  
  If depth <> 0 Then
    p = New picture(width * g.ScaleX, height * g.ScaleY, depth )
  Else
    p = New picture(width * g.ScaleX, height * g.ScaleY )
  End If
  
  p.Graphics.ScaleX = g.ScaleX
  p.Graphics.ScaleY = g.ScaleY
  p.Graphics.AntiAlias = g.AntiAlias
  p.Graphics.AntiAliasMode = g.AntiAliasMode
  p.Graphics.Bold = g.Bold
  p.Graphics.ForeColor = g.ForeColor
  p.Graphics.Italic = g.Italic
  p.Graphics.PenHeight = g.PenHeight
  p.Graphics.PenWidth = g.PenWidth
  p.Graphics.TextFont = g.TextFont
  p.Graphics.TextSize = g.TextSize
  p.Graphics.TextUnit = g.TextUnit
  p.Graphics.Transparency = g.Transparency
  p.Graphics.Underline = g.Underline
  
  return p
  
  
End Function
Public Function BetterBitmapForCaching(extends w as Window, width as integer, height as integer, depth as integer = 0) as Picture
  Dim base As picture = w.BitmapForCaching(1,1)
  
  If base <> Nil Then
    
    Dim g As graphics = base.Graphics
    
    Dim p As picture
    
    If depth <> 0 Then
      p = New picture(width * g.ScaleX, height * g.ScaleY, depth )
    Else
      p = New picture(width * g.ScaleX, height * g.ScaleY )
    End If
    
    p.Graphics.ScaleX = g.ScaleX
    p.Graphics.ScaleY = g.ScaleY
    p.Graphics.AntiAlias = g.AntiAlias
    p.Graphics.AntiAliasMode = g.AntiAliasMode
    p.Graphics.Bold = g.Bold
    p.Graphics.ForeColor = g.ForeColor
    p.Graphics.Italic = g.Italic
    p.Graphics.PenHeight = g.PenHeight
    p.Graphics.PenWidth = g.PenWidth
    p.Graphics.TextFont = g.TextFont
    p.Graphics.TextSize = g.TextSize
    p.Graphics.TextUnit = g.TextUnit
    p.Graphics.Transparency = g.Transparency
    p.Graphics.Underline = g.Underline
    
    Return p
    
  End If
  
End Function

I’m not sure I understand your problem. Probably not. Why don’t you continue using Xojo’s own BitmapForCaching and create a MeasurePicture with the dimension 1, 1? Then you can use it to get the string width.

Does this mean that we can’t use BitmapForCaching on Windows at all, as it has existed for years?

If you have code in the paint event that uses the passed in graphics to measure strings you will get a different measurement than one created from BitMapForCaching :frowning:

Try this on macOS and Windows

new desktop app
add paint event to window1
in the paint event put

Dim p As picture = Self.BitmapForCaching(1,1)

System.debuglog "g.StringWidth = " + Str(g.StringWidth("abcdefghijklmn"))
System.debuglog "p.Graphics.StringWidth = " + Str(p.Graphics.StringWidth("abcdefghijklmn"))

you get different measurements for the same string - one from the passed in graphics and one from bitmapforcaching
So IF you create a bitmapforcaching to retain & use outside the paint event you will get the wrong sizes :frowning:

feedback://showreport?report_id=60512