본문 바로가기

파이어몽키

Image URL로 TImage에 이미지 로드

웹에 있는 이미지를 표시해야 할 것 같아 간단하게 라이브러리 형태로 만들었어요.

TBitmap을 class helper로 확장했습니다.

소스가 몇 줄 되지 않으니 설명은 생략합니다.


iOS(아이폰5), Android(Nexus 7), 윈도우(Windows 7)에서 모두 정상 동작 확인했습니다.


참고하세요^^







사용법


procedure TForm3.Button1Click(Sender: TObject);
var
  Size: Int64;
begin
  Image1.Bitmap.LoadFromUrl('https://t1.daumcdn.net/cfile/tistory/2353573E529FDAAC03', Size);

  Memo1.Lines.Add('1 : ' + Format('W: %d, H: %d, S: %d', [Image1.Bitmap.Width, Image1.Bitmap.Height, Size]))
end;

procedure TForm3.Button2Click(Sender: TObject);
begin
  Image1.Bitmap.LoadFromUrl('https://t1.daumcdn.net/cfile/tistory/2353573E529FDAAC03');

  Memo1.Lines.Add('2 : ' + Format('W: %d, H: %d', [Image1.Bitmap.Width, Image1.Bitmap.Height]))
end;

procedure TForm3.Button3Click(Sender: TObject);
begin
  Image1.Bitmap.LoadThumbnailFromURL('https://t1.daumcdn.net/cfile/tistory/2353573E529FDAAC03', 100, 100);

  Memo1.Lines.Add('3 : ' + Format('W: %d, H: %d', [Image1.Bitmap.Width, Image1.Bitmap.Height]))
end;


쓰레드로 처리하도록 변경해 사용법의 첫번째 사이즈 정보를 얻어오는 부분은 제외됩니다.

(깃허브의 소스코드를 참고하세요. https://github.com/hjfactory/FMX.Devgear)

구현부

unit FMX.Devgear.HelperClass;

interface

uses
  System.Classes, FMX.Graphics;

type
  TBitmapHelper = class helper for TBitmap
  public
    procedure LoadFromUrl(AUrl: string);

    procedure LoadThumbnailFromUrl(AUrl: string; const AFitWidth, AFitHeight: Integer);
  end;

implementation

uses
  System.SysUtils, System.Types, IdHttp, IdTCPClient, AnonThread;

procedure TBitmapHelper.LoadFromUrl(AUrl: string);
var
  _Thread: TAnonymousThread;
begin
  _Thread := TAnonymousThread.Create(
    function: TMemoryStream
    var
      Http: TIdHttp;
    begin
      Result := TMemoryStream.Create;
      Http := TIdHttp.Create(nil);
      try
        try
          Http.Get(AUrl, Result);
        except
          Result.Free;
        end;
      finally
        Http.Free;
      end;
    end,
    procedure(AResult: TMemoryStream)
    begin
      if AResult.Size > 0 then
        LoadFromStream(AResult);
      AResult.Free;
    end,
    procedure(AException: Exception)
    begin
    end
  );
end;

procedure TBitmapHelper.LoadThumbnailFromUrl(AUrl: string; const AFitWidth,
  AFitHeight: Integer);
var
  Bitmap: TBitmap;
  scale: Single;
begin
  LoadFromUrl(AUrl);
  scale := RectF(0, 0, Width, Height).Fit(RectF(0, 0, AFitWidth, AFitHeight));
  Bitmap := CreateThumbnail(Round(Width / scale), Round(Height / scale));
  try
    Assign(Bitmap);
  finally
    Bitmap.Free;
  end;
end;

end.


안드로이드 환경에서 8bit GIF 이미지가 표시되지 않는경우

아래와 같이 FMX.Graphics.Android.pas 파일을 수정하세요. 결과적으로 IsGIFStream 메소드에서 GIF 여부를 파악하는 부분이 잘못되어 있어 8bit GIF 표시에 문제가 있습니다.

class function TBitmapCodecAndroid.IsGIFStream(const Stream: TStream): Boolean;
const
  IDCharCount = 3;
type
  GIFByteArray = array[0..IDCharCount-1] of Byte;
const
  GifBytes: GIFByteArray = ($47, $49, $46); // G I F
var
  I: Integer;
  PrevPosition: Int64;
  ReadBytes: GIFByteArray;
begin
  if (Stream = nil) or (Stream.Size < IDCharCount) then
    Exit(False);

  Result := True;
  PrevPosition := Stream.Position;
  try
    Stream.ReadBuffer(ReadBytes, IDCharCount);
    for I := Low(ReadBytes) to High(ReadBytes) do
      if ReadBytes[I] <> GifBytes[I] then
        Exit(False);
  finally
    Stream.Position := PrevPosition;
  end;
end;