Jump to content
Sign in to follow this  
Rollo62

[Android] Some insights with this TBitmap SaveToFile snippet

Recommended Posts

Hi there,

recently I've got some insights, about the internal TBitmap magic in FMX, for the following code snippet, under Android:
 

procedure TTestForm.SaveImageToTemporaryStore( const AImage     : TBitmap;
                                               const AArrayList : JArrayList;
                                               const AIndex     : Integer );
var
    LImageFile : JFile;
    LImageUri  : Jnet_Uri;
    LOutputDir : JFile;
    LPath      : String;

begin
    // Retrieves the apps cache, temporary file storage folder
    LOutputDir := TAndroidHelper.Context.getExternalCacheDir();

    // Creates a temporary file in that cache folder
    LImageFile := TJFile.JavaClass.createTempFile(  StringToJString( 'attachment' + AIndex.ToString ),
                                                    StringToJString( '.png' ),  //<== This is the only palce where png comes into play
                                                    LOutputDir
                                                 );

    // Get that file as URI
    LImageUri  := TAndroidHelper.JFileToJURI( LImageFile      );
    
    // Retrieve that path, for testing purposes, it looks like this: 
    // '/storage/emulated/0/Android/data/com.embarcadero.APPNAMEHERE/cache/attachment05833119307942135994.png' 
    LPath      := JStringToString( LImageFile.getAbsolutePath );
    // Save the TBitmap to that IRI file Path, works pretty well
    AImage.SaveToFile( LPath );

That works well and all as expected.

When I send that file via sharesheet then after, also that works fine.

    // If we use ACTION_SEND_MULTIPLE action of Intent, we should put image throught Parcelable Array List.
    // Because in this case other application read EXTRA_STREAM like a ArrayList<Uri>
    // Created externally by LArrayList := TJArrayList.Create;

    AArrayList.add( LImageUri );
      
end;

Then finally this is added to an Intent, to share to other apps.

That works well, put it as below into the Intent as EXTRA_STREAM, it sends the .png file via different apps:

    LIntent.putParcelableArrayListExtra( TJIntent.JavaClass.EXTRA_STREAM,
                                         LArrayList );


So all works well and I should not complain.
But it struck my, when I asked myself:
Why does the source TBitmap converts to a *.png file in the first place ?

Why didn't I had to fumble around with TBitmapCodecManager or something else, to get this conversion coded ?

After some investigation, looking into the

TBitmap.SaveToFile( LPath );

I found that the trick, by hidden conversion, depending on the file extension:

procedure TBitmap.SaveToFile(const AFileName: string; const SaveParams: PBitmapCodecSaveParams = nil);
var
  Surf: TBitmapSurface;
begin
  TMonitor.Enter(Self);
  try
    Surf := TBitmapSurface.Create;
    try
      Surf.Assign(Self);
      if not TBitmapCodecManager.SaveToFile(AFileName, Surf, SaveParams) then
        raise EBitmapSavingFailed.CreateFMT(SBitmapSavingFailedNamed, [AFileName]);
    finally
      Surf.Free;
    end;
  finally
    TMonitor.Exit(Self);
  end;
end;

 

Sometimes, I'm still surprised by the hidden convenience that Firemonkey provides for us.
Under VCL I would have to convert this image the hard way by myself, for example with TPNGImage, like PeterBelow pointer out here.

I'm always happy when FMX made me forget such nasty details :classic_biggrin:


 

 

 

Edited by Rollo62

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×