Search code examples
delphifiremonkeynsimagetbitmap

How to convert NSImage to FireMonkey TBitmap?


How to convert an NSImage to Delphis FireMonkey TBitmap? The NSImage is being passed to me from an Objective C API. I am using Delphi XE8.


Solution

  • Try using NSImage.TIFFRepresentation data. Save it to memory stream and then load TBitmap from the stream. Another way is using NSImage.CGImageForProposedRect, you may find a sample here: https://delphi-foundations.googlecode.com/svn/trunk/FMX%20Utilities/CCR.FMXClipboard.Mac.pas https://delphi-foundations.googlecode.com/svn/trunk/XE2%20book/13.%20Native%20APIs/Taking%20a%20screenshot/ScreenshotForm.pas

    Update: OK, here comes my solution:

    function PutBytesCallback(info: Pointer; buffer: Pointer; count: Longword): Longword; cdecl;
    begin
      Result := TStream(info).Write(buffer^, count)
    end;
    
    procedure ReleaseConsumerCallback(info: Pointer); cdecl;
    begin
    end;
    
    function NSImageToBitmap(Image: NSImage; Bitmap: TBitmap): Boolean;
    var
      LStream: TMemoryStream;
      LCGImageRef: CGImageRef;
      LCallbacks: CGDataConsumerCallbacks;
      LConsumer: CGDataConsumerRef;
      LImageDest: CGImageDestinationRef;
    begin
      Result := False;
      LStream := TMemoryStream.Create;
      LImageDest := nil;
      LConsumer := nil;
      try
        LCallbacks.putBytes := PutBytesCallback;
        LCallbacks.releaseConsumer := ReleaseConsumerCallback;
        LCGImageRef := Image.CGImageForProposedRect(nil, nil, nil);
        LConsumer := CGDataConsumerCreate(LStream, @LCallbacks);
        if LConsumer <> nil then
          LImageDest := CGImageDestinationCreateWithDataConsumer(LConsumer, CFSTR('public.png'), 1, nil);
        if LImageDest <> nil then
        begin
          CGImageDestinationAddImage(LImageDest, LCGImageRef, nil);
          CGImageDestinationFinalize(LImageDest);
          LStream.Position := 0;
          Bitmap.LoadFromStream(LStream);
          Result := True
        end
      finally
        if LImageDest <> nil then CFRelease(LImageDest);
        if LConsumer <> nil then CGDataConsumerRelease(LConsumer);
        LStream.Free
      end;
    end;