Search code examples
androiddelphifiremonkeydelphi-10.1-berlin

Preventing FireMonkey from shrinking photo


The problem:

I have a mobile app in FireMonkey (XE 10.1 Berlin) that needs to take pictures. The problem is that FireMonkey seems to re-size my pictures to be much smaller, at least on Android. I don't just see this occurring in my own app, but also in the PhotoEditor Demo app that comes with FireMonkey.

When I take a picture with my camera outside FireMonkey, the image is about 6-7 Mb large and 5184 x 2916 pixels in size.
When I take a picture using my app or using the PhotoEditor demo app, the image is between 140 and 180 kB and 365 x 648 pixels in size.

This happens on Android; I don't have a Mac handy, so I can't test this on an iPad or iPhone at the moment.

What I've found so far:

I've set breakpoints in the code to find out where this happens. When the OnDidFinishTaking event handler is called, the image it receives is already shrunk.

The event is called from procedure TImageManagerAndroid.DidReceiveBitmap(const Sender: TObject; const M: TMessage); in FMX.MediaLibrary.Android.pas. In this event, I see the line:

Photo := TBitmap.CreateFromFile(ImagePath);

ImagePath refers to a .jpg file on the device, that is already shrunk.

Looking further down the call stack, I see a call to

procedure TFMXNativeActivityListener.onReceiveImagePath(ARequestCode: Integer; AFileName: JString);

This procedure lives in FMX.Platform.Android.pas. When looking at the declaration for this procedure, I see that it is followed by the keyword cdecl, which might imply this method is called from native Android code.

I've also looked at this tutorial. Here, the IFMXCameraService.TakePhoto procedure is used. Remarkably this one is not used in the PhotoEditor demo!
It might be an option to use this, as it takes a record with parameters that include a RequiredResolution field. However, I would prefer to use an approach similar to the PhotoEditor demo.

The question:
How can I prevent FireMonkey from shrinking my photo?


Solution

  • I've found that FireMonkey has a default maximum width and height for photos taken with a TTakeCustomPhotoAction. If the image does not fit that maximum size, the picture is shrunk. The shrink factor is always a power of 2, so it seems that FireMonkey keeps halving the image until it fits.

    The TTakeCustomPhotoAction (which is the direct base class for TTakePhotoFromCameraAction) defines two properties, MaxWidth and MaxHeight. For some reason, they both default to 1024.

    By setting the default values to a much higher value, for example 8192, you can prevent shrinkage:

    actTakePhotoFromCameraAction1.MaxWidth := Max(8192, actTakePhotoFromCameraAction1.MaxWidth);
    actTakePhotoFromCameraAction1.MaxHeight := Max(8192, actTakePhotoFromCameraAction1.MaxHeight);
    

    These default properties are of type Cardinal, meaning they have a maximum value of 4.294.967.295 (0xFFFFFFFF) - they are unsigned values of 8 bytes.