如何在 TWebBrowser 或 TImage 中加载 base64 加密 url?

How load a base64 encrypted url in a TWebBrowser or TImage?

我已经 this url 以 base64 加密,这是一个动画 QRCode。

如何将它加载到 TWebBrowser(或 TImage)中?提前致谢。


编辑:

这是我的尝试,但没有成功:

uses
 IdHTTP, IdSSLOpenSSL, GIFImg, ClipBrd;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetStrFromClipbrd: string;
begin
  if Clipboard.HasFormat(CF_TEXT) then
    Result := Clipboard.AsText
  else
  begin
    ShowMessage('There is no text in the Clipboard!');
    Result := '';
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  MS: TMemoryStream;
  IdHTTP1: TIdHTTP;
  GIF: TGIFImage;
begin
  MS := TMemoryStream.Create;
  try
    IdHTTP1 := TIdHTTP.Create;
    try
      GIF := TGIFImage.Create;
      try
        IdHTTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
        IdHTTP1.HandleRedirects := True;
        IdHTTP1.Get(GetStrFromClipbrd, MS);
        MS.Seek(0, soFromBeginning);
        GIF.LoadFromStream(MS);
        Image1.Picture.Assign(GIF);
        (Image1.Picture.Graphic as TGIFImage).Animate := True;
        //(Image1.Picture.Graphic as TGIFImage).AnimationSpeed := 500;
      finally
        FreeAndNil(GIF);
      end;
    finally
      FreeAndNil(IdHTTP1);
    end;
  finally
    FreeAndNil(MS);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.DoubleBuffered := True;
end;

end.

data: 不是您可以使用 TIdHTTP(或任何其他 HTTP 库)请求的 URL 类型,您也不需要这样做,因为所有数据都直接编码在URL 本身。因此,只需提取 base64 部分并使用您选择的任何 base64 解码器对其进行解码。

由于您的代码已经在使用 Indy,因此您可以在 IdCoderMIME 单元中使用其 TIdDecoderMIME class 将 base64 数据解码为二进制流,例如使用TIdDecoderMIME.DecodeStream() class 程序。然后您可以将该流加载到适当的 TGraphic 后代(TGIFImageTBitmap 等),最后您可以将该图形加载到您的 TImage.

例如:

uses
  IdGlobal, IdGlobalProtocols, IdCoderMIME, IdHTTP, IdSSLOpenSSL,
  Graphics, GIFImg, JPEG, ClipBrd;

function GetStrFromClipbrd: string;
const
  CTextFormat = {$IFDEF UNICODE}CF_UNICODETEXT{$ELSE}CF_TEXT{$ENDIF};
begin
  if Clipboard.HasFormat(CTextFormat) then
    Result := Clipboard.AsText
  else
    Result := '';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Graphic: TGraphic;
  MS: TMemoryStream;
  IdHTTP1: TIdHTTP;
  URL, ContentType: string;
begin
  URL := GetStrFromClipbrd;
  if URL = '' then
  begin
    ShowMessage('There is no text in the Clipboard!');
    Exit;
  end;

  Graphic := nil;
  try
    MS := TMemoryStream.Create;
    try
      if TextStartsWith(URL, 'data:') then
      begin
        Fetch(URL, ':');
        ContentType := Fetch(URL, ',');
        if not TextEndsWith(ContentType, ';base64') then
        begin
          ShowMessage('Data is not encoded in base64!');
          Exit;
        end;
        SetLength(ContentType, Length(ContentType)-7);
        TIdDecoderMIME.DecodeStream(URL, MS);
        if ContentType = '' then
          ContentType := 'text/plain;charset=US-ASCII';
      end else
      begin
        IdHTTP1 := TIdHTTP.Create;
        try
          IdHTTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
          IdHTTP1.HandleRedirects := True;
          IdHTTP1.Get(URL, MS);
          ContentType := IdHTTP1.Response.ContentType;
        finally
          IdHTTP1.Free;
        end;
      end;

      MS.Position := 0;

      case PosInStrArray(ExtractHeaderItem(ContentType),
        ['image/gif', 'image/jpeg', 'image/bmp'{, ...}],
        False) of
          0: Graphic := TGIFImage.Create;
          1: Graphic := TJPEGImage.Create;
          2: Graphic := TBitmap.Create;
          // ...
      else
        ShowMessage('Unsupported image type!');
        Exit;
      end;

      { the 'data:' URL you provided is malformed, is says the image type
        is 'image/bmp' even though it is actually a GIF and thus should
        say 'image/gif'.  To avoid problems with the above code determining
        the wrong TGraphic class to use in that case, you can instead look
        at the first few bytes of the decoded data to determinate its actual
        image type, eg...

        const
          Signature_GIF87a: array[0..5] of Byte = (,,,,,);
          Signature_GIF89a: array[0..5] of Byte = (,,,,,);
          Signature_JPEG:   array[0..2] of Byte = ($FF,$D8,$FF);
          Signature_BMP:    array[0..1] of Byte = (,D);
          ...

        if (MS.Size >= 6) and
           (CompareMem(MS.Memory, @Signature_GIF87a, 6) or
            CompareMem(MS.Memory, @Signature_GIF89a, 6)) then
        begin
          Graphic := TGIFImage.Create;
        end
        else if (MS.Size >= 3) and
                 CompareMem(MS.Memory, @Signature_JPEG, 3) then
        begin
          Graphic := TJPEGImage.Create;
        end
        else if (MS.Size >= 2) and
                 CompareMem(MS.Memory, @Signature_BMP, 2) then
        begin
          Graphic := TBitmap.Create;
        end
        ...
        else
          ShowMessage('Unsupported image type!');
          Exit;
        end;
      }

      Graphic.LoadFromStream(MS);
    finally
      MS.Free;
    end;

    Image1.Picture.Assign(Graphic);
  finally
    Graphic.Free;
  end;

  if Image.Picture.Graphic is TGIFImage then
  begin
    TGIFImage(Image.Picture.Graphic).Animate := True;
    //TGIFImage(Image.Picture.Graphic).AnimationSpeed := 500;
  end;
end;