CGImage.ScreenImage(id,rect); is returning a 1x1 image

TroyChardTroyChard CAMember ✭✭
edited December 2017 in Xamarin.Mac

Hi there,

I'm trying to capture the screen into a CGImage object.
The code I'm converting originally called

cgImage = CGDisplayCreateImage(_displayId);

I don't see a direct replacement for that in Xamarin, so instead I'm trying:

CGRect rect = CGDisplay.GetBounds(_displayId);
cgImage = CGImage.ScreenImage(_displayId, rect);

I assume the _displayId is correct because I get a rect back 1680x1050
It's retrieved using

CGRect rect = CGDisplay.GetBounds(_displayId);

Is there some initializer call I'm missing? Or some alternative call I can make to get a CGImage back of the screen?

Alternatively, can anyone show me what the signature would look like to DllImport this one?

CG_EXTERN CGImageRef __nullable CGDisplayCreateImage(CGDirectDisplayID displayID)?

Best Answers

  • TroyChardTroyChard CAMember ✭✭
    Accepted Answer

    Hi Troy,

    Yes, to answer your question above "Is there any memory associated with calling CGDisplayCreateImage() that I should cleanup when I'm done?"

    Absolutely there is. The code in the Accepted answer here is a great way to torpedo your app with some mighty memory leaks :(

    Even if you are savvy enough to call Dispose() on the CGImage created above (which, inside Xamarin.Mac will call CGReleaseImage() for you), you'll still have a pretty nasty memory leak because CGReleaseImage() also has to be called on the ptr that's returned from CGDisplayCreateImage()

    So, a better way to invoke that native call might be this way...

        [DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
        static extern IntPtr CGDisplayCreateImage(uint displayId);
    
        [DllImport ("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
        extern static void CGImageRelease (/* CGImageRef */ IntPtr image);
    
        var ptr = CGDisplayCreateImage((uint)displayID);
    
        var myImage = new CGImage(ptr);
    
        CGImageRelease(ptr);
    
        // don't forget to call dispose() when done with myImage  above (which in turn calls CGReleaseImage )
    

    Regards,
    Troy

Answers

  • TroyChardTroyChard CAMember ✭✭

    ( I forgot to mention ) the result of calling cgImage = CGImage.ScreenImage(_displayId, rect);
    is giving me some kind of object, but the height and width are 1 (and downstream calls are failing, so I'm assuming there's a problem with that call.

  • TroyChardTroyChard CAMember ✭✭
    edited December 2017

    Thanks Timothy! This works great.

    I'm able to capture the display on my laptop no problem.

    I do seem to be hitting some problems calling it on a second monitor I've got here, but I'm assuming there could be a problem upstream (eg: maybe getting the displayID)(And I'll trouble-shoot tomorrow). But this is working great :)

    Thanks again!

    edit: Almost forgot, Is there any memory associated with calling CGDisplayCreateImage() that I should cleanup when I'm done?

  • TroyChardTroyChard CAMember ✭✭
    Accepted Answer

    Hi Troy,

    Yes, to answer your question above "Is there any memory associated with calling CGDisplayCreateImage() that I should cleanup when I'm done?"

    Absolutely there is. The code in the Accepted answer here is a great way to torpedo your app with some mighty memory leaks :(

    Even if you are savvy enough to call Dispose() on the CGImage created above (which, inside Xamarin.Mac will call CGReleaseImage() for you), you'll still have a pretty nasty memory leak because CGReleaseImage() also has to be called on the ptr that's returned from CGDisplayCreateImage()

    So, a better way to invoke that native call might be this way...

        [DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
        static extern IntPtr CGDisplayCreateImage(uint displayId);
    
        [DllImport ("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
        extern static void CGImageRelease (/* CGImageRef */ IntPtr image);
    
        var ptr = CGDisplayCreateImage((uint)displayID);
    
        var myImage = new CGImage(ptr);
    
        CGImageRelease(ptr);
    
        // don't forget to call dispose() when done with myImage  above (which in turn calls CGReleaseImage )
    

    Regards,
    Troy

Sign In or Register to comment.