FIX: DARWIN: load the icon file content by native method (#513)

* FIX: DARWIN: load the icon file content by native method, support all MacOS ICNS formats (bitmap/png/jpeg), and avoid limited image formats support of Lazarus

* FIX: DARWIN: OpenWithSubMenu ImageList not free
This commit is contained in:
rich2014 2022-08-03 23:43:34 +08:00 committed by GitHub
commit d688c5e5fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 1 deletions

View file

@ -42,6 +42,7 @@ type
FFiles: TFiles;
FDrive: TDrive;
FUserWishForContextMenu: TUserWishForContextMenu;
FMenuImageList: TImageList;
procedure PackHereSelect(Sender: TObject);
procedure ExtractHereSelect(Sender: TObject);
procedure ContextMenuSelect(Sender: TObject);
@ -364,6 +365,8 @@ begin
Result:= True;
miOpenWith := TMenuItem.Create(Self);
miOpenWith.Caption := rsMnuOpenWith;
FMenuImageList := TImageList.Create(nil);
miOpenWith.SubMenuImages := FMenuImageList;
Self.Items.Add(miOpenWith);
for I:= 0 to CFArrayGetCount(ApplicationArrayRef) - 1 do
@ -392,7 +395,8 @@ begin
bmpTemp:= PixMapManager.GetBitmap(ImageIndex);
if Assigned(bmpTemp) then
begin
mi.Bitmap.Assign(bmpTemp);
mi.ImageIndex:=FMenuImageList.Count;
FMenuImageList.Add( bmpTemp , nil );
FreeAndNil(bmpTemp);
end;
end;
@ -906,6 +910,7 @@ end;
destructor TShellContextMenu.Destroy;
begin
FreeThenNil(FFiles);
FreeThenNil(FMenuImageList);
inherited Destroy;
end;

View file

@ -226,6 +226,7 @@ type
{$IF DEFINED(DARWIN)}
function GetSystemFolderIcon: PtrInt;
function GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt;
function LoadImageFileBitmap( const filename:String; const size:Integer ): TBitmap;
{$ENDIF}
function GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
@ -658,15 +659,22 @@ begin
else
DCDebug(Format('Error: pixmap [%s] not loaded!', [AIconName]));
{$ELSE}
{$IFDEF DARWIN}
bmpBitmap := LoadImageFileBitmap(AIconName, AIconSize);
{$ELSE}
bmpBitmap := LoadBitmapEnhanced(AIconName, AIconSize, False, clNone, nil);
{$ENDIF}
if Assigned(bmpBitmap) then
begin
// MacOS' high resolution screen parameters are different from other operating systems
{$IF NOT DEFINED(DARWIN)}
// Shrink big bitmaps before putting them into PixmapManager,
// to speed up later drawing.
if (bmpBitmap.Width > 48) or (bmpBitmap.Height > 48) then
begin
bmpBitmap := StretchBitmap(bmpBitmap, AIconSize, clBlack, True);
end;
{$ENDIF}
Result := FPixmapList.Add(bmpBitmap);
FPixmapsFileNames.Add(AIconName, Pointer(Result));
end;
@ -957,6 +965,79 @@ begin
Result := NSStringToString( appBundle.pathForImageResource( iconTag ) );
end;
function getBestNSImageWithSize( const srcImage:NSImage; const size:Integer ): NSImage;
var
bestRect: NSRect;
bestImageRep: NSImageRep;
bestImage: NSImage;
begin
Result := nil;
if srcImage=nil then exit;
bestRect.origin.x := 0;
bestRect.origin.y := 0;
bestRect.size.width := size;
bestRect.size.height := size;
bestImageRep:= srcImage.bestRepresentationForRect_context_hints( bestRect, nil, nil );
bestImage:= NSImage.Alloc.InitWithSize( bestImageRep.size );
bestImage.AddRepresentation( bestImageRep );
Result := bestImage;
end;
function getImageFileBestNSImage( const filename:NSString; const size:Integer ): NSImage;
var
srcImage: NSImage;
begin
Result:= nil;
try
srcImage:= NSImage.Alloc.initByReferencingFile( filename );
Result:= getBestNSImageWithSize( srcImage, size );
finally
if Assigned(srcImage) then srcImage.release;
end;
end;
function NSImageToTBitmap( const image:NSImage ): TBitmap;
var
tempData: NSData;
tempStream: TBlobStream;
tempBitmap: TTiffImage;
bitmap: TBitmap;
begin
Result:= nil;
if image=nil then exit;
tempStream:= nil;
tempBitmap:= nil;
try
tempData:= image.TIFFRepresentation;
tempStream:= TBlobStream.Create( tempData.Bytes, tempData.Length );
tempBitmap:= TTiffImage.Create;
tempBitmap.LoadFromStream( tempStream );
bitmap:= TBitmap.Create;
bitmap.Assign( tempBitmap );
Result:= bitmap;
finally
FreeAndNil(tempBitmap);
FreeAndNil(tempStream);
end;
end;
function TPixMapManager.LoadImageFileBitmap( const filename:String; const size:Integer ): TBitmap;
var
image: NSImage;
begin
Result:= nil;
image:= nil;
try
image:= getImageFileBestNSImage( StringToNSString(filename), size );
if Assigned(image) then Result:= NSImageToTBitmap( image );
finally
if Assigned(image) then image.release;
end;
end;
function TPixMapManager.GetApplicationBundleIcon(sFileName: String;
iDefaultIcon: PtrInt): PtrInt;