Я новичок в разработке для Android, но не так уж нов в разработке Delphi. В любом случае, я изо всех сил пытаюсь получить данные EXIT из изображения (загруженного из библиотеки) и показать это изображение в форме.
Вот мой код:
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.
Теперь ошибка исходит от строка:
img1.Bitmap.LoadFromStream(ms);
и ошибка:
Project ObtainPhotoInfoDemo.apk поднял класс исключения Ошибка сегментации (11).
Спасибо
ОБНОВЛЕНИЕ
НАЙТИ РЕШЕНИЕ !!!!
blackapps прокомментировал и дал мне идею поток должен быть закрыт и снова открыт для использования в другом вызове, подобном этому:
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;