Преобразование Jnet_uri в Tbitmap в delphi

В приложении я выбираю фотографии через галерею Android. Поскольку я хочу выбрать сразу несколько фотографий, я использую функцию JIntent. Теперь все работает, и я хочу загрузить выбранные фотографии в TMSFMXtableview. Для этого мне нужно преобразовать фотографии из JNet_Uri в TBitmap. Как лучше всего это сделать?

Это фрагмент кода, который я хочу использовать для загрузки фотографий в TMSFMXtableview:

function TfmMain.OnActivityResult(RequestCode: Integer; ResultCode: Integer; Data: Jintent): Boolean;
var
  I,count: Integer;
  ImageUri : Jnet_Uri;
  Fid : Integer;
  bitmap : Tbitmap;
begin
Result := False;
TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FmessageSubscriptionID);
FmessageSubscriptionID := 0;

if requestcode=LibraryRequestCode then
  begin
    if ResultCode=TJActivity.JavaClass.RESULT_OK then
    begin
      if assigned(data) then
      begin

      Count := data.getClipData.getItemCount;
      for I := 0 to count-1 do
        begin
        ImageUri := data.getClipData.getItemAt(i).getUri;
        bitmap := //convert the imageuri to a Tbitmap
        tv2.Items.Add;
        FID := tv2.Items.Count-1;
        tv2.Items.Items[FID].Bitmap.Assign(bitmap);
        tv2.Items.Items[FID].Caption := 'NEW';
        end;
      end;
    end
    else
    if ResultCode= TJActivity.JavaClass.RESULT_CANCELED then
    begin
    
    end;
   result := true;
  end;
end;

Откройте InputStream для полученного uri. Затем используйте Bitmap.decodeStream().

blackapps 10.05.2022 13:04

@blackapps у меня нет bitmap.decodestream в delphi.

aaron versfeld 10.05.2022 13:39

@aaronversfeld decodeStream() — это метод класса BitmapFactory Android, а не класса TBitmap Delphi.

Remy Lebeau 10.05.2022 15:53
2
3
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Боюсь, это не так просто. Этот код (из примеров, предоставленных Дэйвом Ноттеджем) может вам помочь. AddAFile принимает Jnet_URI в качестве входного параметра и сохраняет этот файл в GetPublicPath. Конечно, вы можете сохранить array of bytes в поток, а затем загрузить растровое изображение из этого потока, если хотите.

function TfrmChat.AddAFile(const AURI: Jnet_Uri): TBitMap;
var
  LSelectedFile: TSelectedFile;
  LProjection: TJavaObjectArray<JString>;
  LCursor: JCursor;
  LURI: Jnet_Uri;
  LInput: JInputStream;
  LJavaBytes: TJavaArray<Byte>;
  LBytes: TBytes;
  FileName: String;
  APath, AFileName: String;
  lStream: TMemoryStream;
begin

  if AURI = nil then
    EXIT;

  LSelectedFile.RawPath := JStringToString(AURI.toString); 
  LSelectedFile.DecodedPath := JStringToString(TJnet_Uri.JavaClass.decode(AURI.toString));
  LProjection := TJavaObjectArray<JString>.Create(1);
  try
    LProjection[0] := TJMediaStore_MediaColumns.JavaClass.DISPLAY_NAME;
    LCursor := TAndroidHelper.Context.getContentResolver.query(AURI, LProjection, nil, nil, nil);
  finally
    LProjection.Free;
  end;

  if LCursor = nil then
    EXIT;

  try

    if LCursor.moveToFirst then
      LSelectedFile.DisplayName := JStringToString(LCursor.getString(0));

    FileName := lSelectedFile.DisplayName;

    LURI := TJnet_Uri.JavaClass.parse(AURI.toString); // raw path again
    LInput := TAndroidHelper.Context.getContentResolver.openInputStream(LURI);

    // copy java input stream to array of bytes
    LJavaBytes := TJavaArray<Byte>.Create(LInput.available);
    try
      LInput.read(LJavaBytes, 0, LJavaBytes.Length);
      SetLength(LBytes, LJavaBytes.Length);
      Move(LJavaBytes.Data^, LBytes[0], LJavaBytes.Length);
    finally
      LJavaBytes.Free;
    end;

    // write the bytes to a local file
    // APath := System.IOUtils.TPath.GetPublicPath;
    // AFileName := TPath.Combine(aPath, FileName);
    // TFile.WriteAllBytes(AFileName, LBytes);

    // create a bitmap to return
    lStream := TMemoryStream.Create;
    try
      lStream.WriteBuffer(LBytes[0], length(lBytes));
      Result := TBitmap.CreateFromStream(lStream);
    finally
      lStream.Free;
    end;

  finally
    LCursor.Close;
  end;

end;

[Изменить] Я изменил процедуру на функцию, которая возвращает TBitmap. Вы можете использовать его следующим образом:

var
  lBitMap: TBitMap;
begin
  
  lBitMap := AddFile(ImageUri);
  try
    // do stuff with the bitmap
  finally
    lBitMap.Free;
  end;

Мне не удается загрузить байты в поток, а затем использовать поток для растрового изображения. Можете ли вы помочь мне с этим?

aaron versfeld 10.05.2022 13:29

Я добавил строки, которые вы можете использовать для создания memorystream из byte array, а затем создает bitmap, загружая из memorystream.

Freddie Bell 10.05.2022 14:06

К вашему сведению, в RTL есть класс TBytesStream, поэтому вам не нужно делать копию данных TBytes в TMemoryStream. Я бы, вероятно, пошел еще дальше, создав пользовательский TStream для чтения из TJavaArray<Byte> или JInputStream, чтобы избежать копирования TBytes. В любом случае, вы можете удалить локальный файл, поскольку вместо этого вы загружаете его из памяти.

Remy Lebeau 10.05.2022 15:57

@RemyLebeau Я не понимаю, как использование TByteStream приведет к уменьшению количества строк кода.

Freddie Bell 10.05.2022 17:09

@FreddieBell Я не говорил, что это приведет к меньшему количеству кода (хотя и будет, поскольку lStream := TMemoryStream.Create; lStream.WriteBuffer(LBytes[0], length(lBytes)); станет lStream := TBytesStream.Create(LBytes);). Я сказал, что использование TBytesStream позволит избежать необходимости делать отдельную копию данных TBytes в памяти, вместо этого загрузив их из оригинала TBytes.

Remy Lebeau 10.05.2022 17:47

Другие вопросы по теме