【问题标题】:Lazarus TImage to Base64Lazarus TImage 转 Base64
【发布时间】:2019-08-13 15:54:57
【问题描述】:

我正在尝试将 TImage 图片编码为 base64 以进行其余传输,我尝试了几种方法,但似乎无法将其编码为字符串。这就是我现在拥有的:

      imgstream := TStringStream.Create('');
      OutputStream := TStringStream.Create('');
      Encoder := TBase64EncodingStream.Create(OutputStream);
      try
        image1.Picture.SaveToStream(imgstream);
        Encoder.CopyFrom(imgstream, imgstream.Size);

        showmessage(OutputStream.DataString);
      finally
        imgstream.Free;
        Encoder.Free;
        OutputStream.Free;
      end;

现在它给了我一个例外。当我showmessage(imgstream.DataString) 时,我得到一个奇怪的BM6~ 字符串。

CopyFrom 之前添加imgstream.Position := 0; 之后,现在我将数据恢复为空白,无一例外:

【问题讨论】:

  • it's give me an exception 仅当您包含有关您所看到的特定异常的信息时才有意义。我们无法从这里看到您的屏幕。第一步,我的心理调试技巧告诉我,你应该在CopyFrom 之前有一个imgstream.Position := 0;
  • 感谢您的洞察!现在添加它不再有异常,但现在它返回空白。请检查上面的截图。
  • 我看不到截图(企业代理不允许图片分享网站,这是避免使用图片的原因之一)。不过,我猜您需要在访问 OutputStream 之前通过设置它的位置来倒带它。
  • 例外是EReadError, Stream Read Error,我在showmessage 之前重置了位置,但仍然是空的。 OutputStream.Position := 0;
  • showmessage 出现空白,尝试将输出添加到 TMemo 组件会冻结程序而没有错误:memo1.Lines.LoadFromStream(OutputStream);

标签: pascal lazarus freepascal


【解决方案1】:

TBase64EncodingStream不适合大二进制转换,我的意思是,它会很慢,还有Image1.Picture.SaveToStream,默认情况下会将图片保存为Bitmap格式,所以会很大。尝试使用 JPG 格式。

procedure TForm1.Button1Click(Sender: TObject);
var
  imgstream, Outputstream: TStream;
  Encoder: TBase64EncodingStream;
  jpg: TJPEGImage;
  I: Int64;
begin
  I := GetTickCount64;
  imgstream := TMemoryStream.Create();
  Outputstream := TStringStream.Create('');
  jpg := TJPEGImage.Create;
  Encoder := TBase64EncodingStream.Create(Outputstream);
  try
    jpg.Assign(Image1.Picture.Bitmap);
    jpg.CompressionQuality:=75;
    jpg.SaveToStream(imgstream);
    imgstream.Position:= 0;
    Encoder.CopyFrom(TStringStream(imgstream), imgstream.Size);
    Encoder.Flush;
    Memo1.Text:='data:image/jpg;base64,'+ TStringStream(Outputstream).DataString;
    ShowMessage('Created in '+IntToStr(GetTickCount64-I)+'ms');
  finally
    imgstream.Free;
    Encoder.Free;
    Outputstream.Free;
    jpg.Free;
  end;
end;         

为了改进编码,也许您可​​以尝试使用线程将二进制文件分成 3 的倍数的块来处理每个块并在最后加入处理后的编码块。

例如使用 4 个线程,硬编码。

{ TEncodeThread }

  TEncodeThread = class (TThread)
  private
    fForm: TForm1;
    fStream: TStream;
    fStatusText: String;
    procedure ShowStatus;
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended:Boolean; const AForm: TForm1);
    procedure SetStream(const AStream: TStream);
  end;   

...
procedure TForm1.Button3Click(Sender: TObject);
var
  jpg: TJPEGImage;
  mul3: Int64;
  mod3: Int64;
  dif3: Int64;
  imgstream: TStringStream;
begin
  Steps:=0;
  Start:=GetTickCount64;
  imgstream := TStringStream.Create('');
  jpg := TJPEGImage.Create;
  try
    jpg.Assign(Image1.Picture.Bitmap);
    jpg.CompressionQuality:=75;
    jpg.SaveToStream(imgstream);

    mul3 := imgstream.Size div 4;
    mod3 := mul3 mod 3;
    if mod3 <> 0 then
       mul3 := mul3 + 3 - mod3;
    dif3 := imgstream.Size - mul3*4;
    memo1.text := 'Total Size: '+ IntToStr(imgstream.size)
    + #13'Part1: '+IntToStr(mul3)
    + #13'Part2: '+IntToStr(mul3)
    + #13'Part3: '+IntToStr(mul3)
    + #13'Part4: '+IntToStr(mul3+dif3)
    + #13'Rest: '+IntToStr(dif3);

    Part1.Position:=0;
    Part2.Position:=0;
    Part3.Position:=0;
    Part4.Position:=0;
    imgstream.Position:=0;
    Part1.CopyFrom(imgstream,mul3);
    Part2.CopyFrom(imgstream,mul3);
    Part3.CopyFrom(imgstream,mul3);
    Part4.CopyFrom(imgstream,mul3+dif3);

    Thr1 := TEncodeThread.Create(True, Self);
    Thr2 := TEncodeThread.Create(True, Self);
    Thr3 := TEncodeThread.Create(True, Self);
    Thr4 := TEncodeThread.Create(True, Self);

    Thr1.SetStream(Part1);
    Thr1.Start;
    Thr2.SetStream(Part2);
    Thr2.Start;
    Thr3.SetStream(Part3);
    Thr3.Start;
    Thr4.SetStream(Part4);
    Thr4.Start;

  finally
    imgstream.Free;
    jpg.Free;
  end;
end;

procedure TEncodeThread.Execute;
var
  Encoder: TBase64EncodingStream;
  buf: TStream;
begin

    buf := TStringStream.Create('');
    Encoder := TBase64EncodingStream.Create(buf);
    try
      fStream.Position:= 0;
      Encoder.CopyFrom(TStringStream(fStream), fStream.Size);
      Encoder.Flush;
      buf.Position:= 0;
      fForm.Out1.CopyFrom(TStringStream(buf), buf.Size);
      Inc(fForm.Steps);
      if fForm.Steps = 3 then
      begin
        fForm.Out1.Position:=0;
        fForm.Out2.Position:=0;
        fForm.Out3.Position:=0;
        fForm.Out4.Position:=0;
        fForm.Memo1.Text:='data:image/jpg;base64,'
        + TStringStream(fForm.Out1).DataString
        + TStringStream(fForm.Out2).DataString
        + TStringStream(fForm.Out3).DataString
        + TStringStream(fForm.Out4).DataString;
      end;


    finally
      Encoder.Free;
      buf.Free;
    end;


end;     

这个演示并没有真正优化,也没有正确同步(输出可能格式错误),不过,作为一个起点,它可能会有所帮助。 zipped project

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多