Taking Pictures Using FireMonkey Interfaces

From RAD Studio
Jump to: navigation, search

Go Up to Mobile Tutorial: Taking and Sharing a Picture, and Sharing Text (iOS and Android)


This tutorial explains how to take and handle pictures on your mobile devices using the IFMXPhotoLibrary and IFMXCameraService interfaces.

Building the User Interface for Your Application

Drop the following components onto the Form Designer:

  • TToolBar component
    • On the toolbar, put two TSpeedButton components. You will use these buttons to take pictures with the device camera and select them from the device Photo Library.
    • In the Object Inspector, specify the following properties of these buttons:
      • Set the StyleLookup property to cameratoolbuttonbordered, and searchtoolbuttonbordered, respectively.
      • Set the Align property to Left, and Right, respectively.
  • TImage component
    • Set the Align property to Client.

The form this sample application should now look like the following screen, before you set the Style or View in the Form Designer:

AppMasterUserInterface.png

Note: For more information about the selection of the Style and Views, see Style Selector and Using FireMonkey Views.

Taking a Picture with a Device Camera

To take pictures with a mobile device camera, you can use the IFMXCameraService interface. Perform the following steps:

  1. Open the Code Editor and add the following lines to your code if they are not present:

    Delphi:

    uses
      System.Messaging, System.Permissions, FMX.MediaLibrary, FMX.Platform;
    

    C++:

    #include <System.Messaging.hpp>
    #include <System.Permissions.hpp>
    #include <FMX.MediaLibrary.hpp>
    #include <FMX.Platform.hpp>
    
  2. Add the following procedure header to the private section of the form definition:

    Delphi:

     procedure DoDidFinish(Image: TBitmap);
     procedure DoMessageListener(const Sender: TObject; const M: TMessage);
    

    C++:

    void __fastcall DoDidFinish(TBitmap *Image);
    void __fastcall DoMessageListener(const TObject *Sender, TMessage const *M);
    
  3. In the implementation section, define DoDidFinish and DoMessageListener as follows:

    Delphi:

     procedure TForm1.DoDidFinish(Image: TBitmap);
    begin
      Image1.Bitmap.Assign(Image);
    end;
    
    procedure TForm1.DoMessageListener(const Sender: TObject; const M: TMessage);
    begin
      if M is TMessageDidFinishTakingImageFromLibrary then
        Image1.Bitmap.Assign(TMessageDidFinishTakingImageFromLibrary(M).Value);
    end;
    

    C++:

    void __fastcall TForm1::DoDidFinish(TBitmap *Image) {
    	Image1->Bitmap->Assign(Image);
    }
    
    void __fastcall TForm1::DoMessageListener(const TObject *Sender, TMessage const *M) {
    	TMessageDidFinishTakingImageFromLibrary const *v = dynamic_cast<TMessageDidFinishTakingImageFromLibrary const *>(M);
    	if (v) {
    		Image1->Bitmap->Assign(v->Value);
    	}
    }
    
  4. On the Form Designer, double-click the SpeedButton1 button, and then in the Code Editor, implement the following onClick event handler:

    Delphi:

    procedure TForm1.SpeedButton1Click(Sender: TObject);
    var
      Service: IFMXCameraService;
      Params: TParamsPhotoQuery;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFMXCameraService, Service) then
      begin
        Params.Editable := True;
        // Specifies whether to save a picture to device Photo Library
        Params.NeedSaveToAlbum := True;
        Params.RequiredResolution := TSize.Create(640, 640);
        Params.OnDidFinishTaking := DoDidFinish;
    {$IF Defined(ANDROID)}
        if TOSVersion.Check(11) then
          Service.TakePhoto(SpeedButton1, Params)
        else
          PermissionsService.RequestPermissions(['android.permission.WRITE_EXTERNAL_STORAGE'],
            procedure(const Permissions: TClassicStringDynArray; const GrantResults: TClassicPermissionStatusDynArray)
            begin
              if (Length(GrantResults) = 1) and (GrantResults[0] = TPermissionStatus.Granted) then
                Service.TakePhoto(SpeedButton1, Params)
              else
                ShowMessage('Cannot take a photo because the required permission has not been granted')
            end);
    {$ELSE}
        Service.TakePhoto(SpeedButton1, Params);
    {$ENDIF}
      end
      else
        ShowMessage('This device does not support the camera service');
    end;
    

    C++:

    void __fastcall TForm1::SpeedButton1Click(TObject *Sender) {
        _di_IFMXCameraService service;
        TParamsPhotoQuery params;
        if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXCameraService), &service)) {
            params.Editable = true;
            // Specifies whether to save a picture to device Photo Library
            params.NeedSaveToAlbum = true;
            params.RequiredResolution = TSize(640, 640);
            params.OnDidFinishTaking = DoDidFinish;
    #if defined(_PLAT_ANDROID)
            if (TOSVersion::Check(11)) {
                service->TakePhoto(SpeedButton1, params);
            } else {
                PermissionsService()->RequestPermissions({ "android.permission.WRITE_EXTERNAL_STORAGE" },
                    [this, service, params](const TClassicStringDynArray Permissions, const TClassicPermissionStatusDynArray GrantResults) {
                        if (GrantResults.Length == 1 && GrantResults[0] == TPermissionStatus::Granted) {
                            service->TakePhoto(SpeedButton1, params);
                        } else {
                            ShowMessage("Cannot take a photo because the required permission has not been granted");
                        }
                    });
            }
    #else
            service->TakePhoto(SpeedButton1, params);
    #endif
        } else {
            ShowMessage("This device does not support the camera service");
        }
    }
    
Note: When creating a FireMonkey application project, the ’Camera project’ option, found at Project > Options > Application > Uses Permissions and enabled by default, has an unexpected implication on the application behavior. Even if the application does not directly access the camera (e.g., through the use of the TCameraComponent component) and instead asks another application (e.g., the built-in camera application) to do it on its behalf, as soon as the CAMERA Uses Permission is declared in the manifest file, it becomes an unexpected required Uses Permission for the IFMXCameraService platform service. Consider disabling the 'Camera project’ option to prevent their applications from requesting an unnecessary Uses Permission.
Note: The updated implementations behind the IFMXCameraService and IFMXTakenImageService platform services no longer support editing the obtained image, as the 'Android' platform has no built-in support for that operation. This implies that the TParamsPhotoQuery.Editable field is now ignored.

Running the Application

Run the application on your mobile device, either by pressing F9 or by choosing Run > Run. To turn on the device camera, tap the camera icon on the toolbar of your application:

iOS Android

TakePicture IOS.png

TakePicture Android.png

To use this picture:

  • On Android devices, click OK.
  • On iOS devices, click Use.

Saving a Picture to the Device Photo Library

If you want your application to automatically save the pictures taken by a device camera to the device Photo Library, set the NeedSaveToAlbum field of the second parameter of the TakePhoto method to True (see code snippets in Step 4 of the above procedure).

Your application saves the pictures to an album in the device Photo Library. The album name depends on the device operation system in the following way:

OS version   Album Name  
iOS Camera Roll
Android Camera

Selecting a Picture from the Device Photo Library

FireMonkey defines the IFMXTakenImageService interface that allows you to select a picture from the device Photo Library.

To let your application select a picture from the device Photo Library, perform the following steps:

  1. On the Form Designer, double-click the SpeedButton2 button (for picking up a picture), and then in the Code Editor, implement the following onClick event handler:

    Delphi:

    procedure TForm1.SpeedButton2Click(Sender: TObject);
    var
      Service: IFMXTakenService;
      Params: TParamsPhotoQuery;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFMXTakenService, Service) then
      begin
        Params.RequiredResolution := TSize.Create(640, 640);
        Params.OnDidFinishTaking := DoDidFinish;
        Service.TakeImageFromLibrary(SpeedButton2, Params);
      end;
    end;
    

    C++:

    void __fastcall TForm1::SpeedButton2Click(TObject *Sender) {
        _di_IFMXTakenImageService service;
        TParamsPhotoQuery params;
        if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXTakenImageService), &service) {
            params.RequiredResolution = TSize(640, 640);
            params.OnDidFinishTaking = DoDidFinish;
            service->TakeImageFromLibrary(SpeedButton2, params);
        } else {
            ShowMessage("This device does not support the photo library service");
        }
    }
    
  2. In the Structure View, select Form1, in the Object Inspector, open the Events tab, double-click an empty field next to OnCreate, and then implement the following onFormCreate event handler:

    Delphi:

     procedure TForm1.FormCreate(Sender: TObject);
    begin
    TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromLibrary, DoMessageListener);
    end;
    

    C++:

    void __fastcall TForm1::FormCreate(TObject *Sender) {
    	TMessageManager::DefaultManager->SubscribeToMessage(__classid(TMessageDidFinishTakingImageFromLibrary),
    		TMessageListenerMethod(&DoMessageListener));
    }
    


  3. Compile and run your application. To select a picture, tap the search button, and then select the picture of interest from the device Photo Library.
    iOS Android

    TakePhotoFromLibraryAction.PNG

    Android SelectfromLibrary.png

    Note: On iPad devices, the application displays thumbnail pictures in a popup window next to the control element specified in the first parameter of the TakeImageFromLibrary method. In our sample project, SpeedButton2 refers to the search button.
Note: The updated implementations behind the IFMXCameraService and IFMXTakenImageService platform services no longer support editing the obtained image, as the 'Android' platform has no built-in support for that operation. This implies that the TParamsPhotoQuery.Editable field is now ignored.

See Also