Why no simple way to copy a graphics object into another ?

Perhaps relevant : there may be a big memory leak using DockItem? See <https://xojo.com/issue/17605>

BTW this is the standard way if you want to work with xojo picture object under MacOSX. You should keep this in mind if you
want to use filters and other fancy OSX stuff which opens doors…

[quote=202085:@Michael Diehr]Sam, thanks - it turns out in this case, it does work.

So here’s the latest version, which runs in 6 msec (which is about 230x as fast as the original code which took 1400+ msec):

Usual caveats apply : this is untested and may blow up your system, etc.

[code]
Protected Function GetDockImageFast4() As Picture
// Fastest way yet to convert App.DockItem.Graphics into a Xojo Picture
// as discussed https://forum.xojo.com/24237-why-no-simple-way-to-copy-a-graphics-object-into-another
// This version of code inspired by https://forum.xojo.com/9403-scale-quality-of-canvas-control/p5#p195272
//

// Note: needs a NSRect (or CGRect) structure (they are identical) which is defined as
// struct NSRect { x as single, y as single, width as single, height as single }

// Get the graphics of the picture as CGContext
dim g as graphics = app.dockItem.Graphics
dim w,h as integer
w = g.width
h = g.height

// make a new empty picture
dim pic as new Picture(w,h)

// get the CGContext from the dockItem
dim cntx as Ptr = ptr(g.Handle(Graphics.HandleTypeCGContextRef))

// sometimes you can get an image from a CGContext
Declare Function CGBitmapContextCreateImage Lib “CoreGraphics” (context as Ptr) As Ptr
Declare sub CGContextDrawImage lib “Cocoa” (cntxt As Ptr, r As NSRect, img As Ptr)

dim pSrc as ptr = CGBitmapContextCreateImage(cntx)
dim pDst as ptr = Ptr( pic.graphics.handle(Graphics.HandleTypeCGContextRef) )

// draw source into dest
dim r as NSRect
r.width = w
r.height = h

CGContextDrawImage(pDst,r,pSrc)

Return pic

End Function
[/code][/quote]

So from what I understand reading this, it should work for any graphic, right ? Not only DockIcon ?

No. It’ll only work for certain kinds of Graphics objects and the only place where the Xojo framework makes a guarantee of returning a bitmap graphics context is from a Picture’s Graphics’ handle.

[quote=202085:@Michael Diehr]Sam, thanks - it turns out in this case, it does work.

So here’s the latest version, which runs in 6 msec (which is about 230x as fast as the original code which took 1400+ msec):

Usual caveats apply : this is untested and may blow up your system, etc.

[code]
Protected Function GetDockImageFast4() As Picture
// Fastest way yet to convert App.DockItem.Graphics into a Xojo Picture
// as discussed https://forum.xojo.com/24237-why-no-simple-way-to-copy-a-graphics-object-into-another
// This version of code inspired by https://forum.xojo.com/9403-scale-quality-of-canvas-control/p5#p195272
//

// Note: needs a NSRect (or CGRect) structure (they are identical) which is defined as
// struct NSRect { x as single, y as single, width as single, height as single }

// Get the graphics of the picture as CGContext
dim g as graphics = app.dockItem.Graphics
dim w,h as integer
w = g.width
h = g.height

// make a new empty picture
dim pic as new Picture(w,h)

// get the CGContext from the dockItem
dim cntx as Ptr = ptr(g.Handle(Graphics.HandleTypeCGContextRef))

// sometimes you can get an image from a CGContext
Declare Function CGBitmapContextCreateImage Lib “CoreGraphics” (context as Ptr) As Ptr
Declare sub CGContextDrawImage lib “Cocoa” (cntxt As Ptr, r As NSRect, img As Ptr)

dim pSrc as ptr = CGBitmapContextCreateImage(cntx)
dim pDst as ptr = Ptr( pic.graphics.handle(Graphics.HandleTypeCGContextRef) )

// draw source into dest
dim r as NSRect
r.width = w
r.height = h

CGContextDrawImage(pDst,r,pSrc)

Return pic

End Function
[/code][/quote]

This code at the very least needs to check for getting Nil back from CGBitmapContextCreateImage. It also leaks memory because it’s missing a CFRelease at the end of the CGImage.

Indeed and that’s my bad! I forgot to mention that CGBitmapContextCreateImage requires a release of the image once you’ve finished with it, otherwise it leaks.

[code] CGContextDrawImage(pDst,r,pSrc)
declare sub CGImageRelease lib “CoreGraphics” ( CGImageRef as Ptr )
CGImageRelease( pSrc )

Return pic

End Function[/code]

Thanks Sam & Joe : here’s a slightly less dangerous version with those changes and some additional error-checking:

Protected Function GetDockImageFast5() As Picture
  // Fastest way yet to convert App.DockItem.Graphics into a Xojo Picture
  // as discussed https://forum.xojo.com/24237-why-no-simple-way-to-copy-a-graphics-object-into-another
  // This version of code inspired by https://forum.xojo.com/9403-scale-quality-of-canvas-control/p5#p195272

 // Note: needs a NSRect (or CGRect) structure (they are identical) which is defined as
 // struct NSRect { x as single, y as single, width as single, height as single }

  // Get the graphics of the picture as CGContext
  dim g as graphics = app.dockItem.Graphics

  if g = nil then
    return nil
  end if

  dim w,h as integer
  w = g.width
  h = g.height
  
  // make a new empty picture
  dim pic as new Picture(w,h)
  if pic = nil then
    return nil
  end if
  
  // get the CGContext from the dockItem
  dim cntx as Ptr = ptr(g.Handle(Graphics.HandleTypeCGContextRef))
  if cntx = nil then
     return nil
  end if
  
  // sometimes you can get an image from a CGContext 
  Declare Function CGBitmapContextCreateImage Lib "CoreGraphics" (context as Ptr) As Ptr
  Declare sub CGContextDrawImage lib "Cocoa" (cntxt As Ptr, r As NSRect, img As Ptr)
  
  dim pSrc as ptr = CGBitmapContextCreateImage(cntx)
  if pSrc = nil then
     return Nil
  end if

  dim pDst as ptr = Ptr( pic.graphics.handle(Graphics.HandleTypeCGContextRef) )
  if pDst = nil then
     return Nil
  end if

  // draw source into dest
  dim r as NSRect
  r.width = w
  r.height = h
  
  
  CGContextDrawImage(pDst,r,pSrc)

  // clean up after ourself
  Declare sub CGImageRelease lib "CoreGraphics" ( CGImageRef as Ptr )
  CGImageRelease( pSrc )

  Return pic

  End Function