问题
I am new at developing for Android, but not so new on Delphi development though. Anyway I am struggling to get EXIT data from an image (loaded from library) and show that image on the form.
Here is my code:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
System.Messaging,
{$IF CompilerVersion > 32}
System.Permissions,
{$ENDIF}
Androidapi.JNI.JavaTypes, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics,
FMX.Dialogs, FMX.StdActns, FMX.Controls.Presentation, FMX.Objects, FMX.Layouts,
FMX.ScrollBox, FMX.Memo, FMX.Surfaces, FMX.ExtCtrls, FMX.StdCtrls,
FMX.Helpers.Android, System.Actions, FMX.ActnList, FMX.MediaLibrary.Actions;
type
TForm1 = class(TForm)
Button1: TButton;
Layout1: TLayout;
Memo1: TMemo;
img1: TImageControl;
procedure Button1Click(Sender: TObject);
private
FFileName: JString;
procedure GetEXIF(const AFileName: JInputStream);
procedure ResultNotificationMessageHandler(const Sender: TObject; const M: TMessage);
procedure TakePhoto;
{$IF CompilerVersion > 32}
procedure TakePhotoPermissionsResultHandler(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
{$ENDIF}
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses
System.IOUtils, Androidapi.Helpers, Androidapi.JNI.Media, Androidapi.JNIBridge,
Androidapi.JNI.Provider, Androidapi.JNI.App, Androidapi.JNI.Os,
Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Net,
FMX.Platform.Android, DW.Androidapi.JNI.Os;
const
cPermissionReadExternalStorage = 'android.permission.READ_EXTERNAL_STORAGE';
cPermissionWriteExternalStorage = 'android.permission.WRITE_EXTERNAL_STORAGE';
cPermissionCamera = 'android.permission.CAMERA';
{$IF CompilerVersion > 32}
type
TGrantResults = TArray<TPermissionStatus>;
TGrantResultsHelper = record helper for TGrantResults
public
function AreAllGranted: Boolean;
end;
{ TGrantResultsHelper }
function TGrantResultsHelper.AreAllGranted: Boolean;
var
LStatus: TPermissionStatus;
begin
for LStatus in Self do
begin
if LStatus <> TPermissionStatus.Granted then
Exit(False); // <======
end;
Result := True;
end;
{$ENDIF}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
{$IF CompilerVersion > 32}
TPermissionsService.DefaultService.RequestPermissions([cPermissionReadExternalStorage, cPermissionWriteExternalStorage, cPermissionCamera], TakePhotoPermissionsResultHandler);
{$ELSE}
TakePhoto;
{$ENDIF}
end;
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, ResultNotificationMessageHandler);
end;
destructor TForm1.Destroy;
begin
TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, ResultNotificationMessageHandler);
inherited;
end;
procedure TForm1.GetEXIF(const AFileName: JInputStream);
var
LEXIF: JExifInterface;
LLatLong: TJavaArray<Single>;
LStream: JFileInputStream;
begin
try
LEXIF := TJExifInterface.JavaClass.init(AFileName);
Memo1.Lines.Clear;
Memo1.Lines.Add('Date Taken: ' + JStringToString(LEXIF.getAttribute(TJExifInterface.JavaClass.TAG_DATETIME)));
Memo1.Lines.Add('Camera Make: ' + JStringToString(LEXIF.getAttribute(TJExifInterface.JavaClass.TAG_MAKE)));
Memo1.Lines.Add('Camera Model: ' + JStringToString(LEXIF.getAttribute(TJExifInterface.JavaClass.TAG_MODEL)));
LLatLong := TJavaArray<Single>.Create(2);
try
if LEXIF.getLatLong(LLatLong) then
begin
Memo1.Lines.Add('Latitude: ' + LLatLong.Items[0].ToString);
Memo1.Lines.Add('Longitude: ' + LLatLong.Items[1].ToString);
end;
finally
LLatLong.Free;
end;
except
on E: Exception do
ShowMessage(e.Message);
end;
end;
procedure TForm1.ResultNotificationMessageHandler(const Sender: TObject; const M: TMessage);
var
LMessage: TMessageResultNotification;
Str: string;
FullPhotoUri: Jnet_Uri;
ms: TMemoryStream;
jis: JInputStream;
b: TJavaArray<Byte>;
NativeBitmap: JBitmap;
Bitmap: TBitmapSurface;
begin
if M is TMessageResultNotification then
begin
LMessage := TMessageResultNotification(M);
if LMessage.RequestCode = 10011 then
if (LMessage.ResultCode = TJActivity.JavaClass.RESULT_OK) then
if Assigned(LMessage.Value) then
try
try
FullPhotoUri := LMessage.Value.getData();
jis := TAndroidHelper.Context.getContentResolver.openInputStream(FullPhotoUri);
GetEXIF(jis);
ms := TMemoryStream.Create;
b := TJavaArray<Byte>.Create(jis.available);
jis.read(b);
ms.Write(b.Data^, b.Length);
img1.Bitmap.LoadFromStream(ms);
jis.close;
except
on E: Exception do
Application.ShowException(e);
end;
finally
ms.Free;
end;
end;
end;
procedure TForm1.TakePhotoPermissionsResultHandler(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
if TGrantResults(AGrantResults).AreAllGranted then
TakePhoto
else
ShowMessage('Not all photo permissions granted!');
end;
// Based on: https://developer.android.com/training/camera/photobasics#java
procedure TForm1.TakePhoto;
var
LIntent: JIntent;
LFile, LDir: JFile;
LUri: Jnet_Uri;
LFileName: string;
begin
LIntent := TJIntent.Create;
LIntent.setAction(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT).addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE).setType(StringToJString('image/*'));
if LIntent.resolveActivity(TAndroidHelper.Context.getPackageManager) <> nil then
begin
MainActivity.startActivityForResult(LIntent, 10011);
end
else
ShowMessage('Cannot take a photo!');
end;
end.
Now, the error comes from the line:
img1.Bitmap.LoadFromStream(ms);
and the error is:
Project ObtainPhotoInfoDemo.apk raised exception class Segmentation fault (11).
Thanks
UPDATE
FOUND THE SOLUTION!!!!
blackapps commented and gave me an idea, the stream should be closed and reopened again to be used in an another call like this:
FullPhotoUri := LMessage.Value.getData();
//get input stream
jis := TAndroidHelper.Context.getContentResolver.openInputStream(FullPhotoUri);
GetEXIF(jis);
//have to close it because GetEXIF already consumed it
jis.close;
//open it again
jis := TAndroidHelper.Context.getContentResolver.openInputStream(FullPhotoUri);
NativeBitmap := TJBitmapFactory.JavaClass.decodeStream(jis);
Surf := TBitmapSurface.Create;
if JBitmapToSurface(NativeBitmap, Surf) then
img1.Bitmap.Assign(Surf);
jis.close;
来源:https://stackoverflow.com/questions/60155948/deplhi-trying-to-get-exif-data-on-library-images-in-android