如何将 http 下载图像从扩展名转换为另一个?

how to convert idhttp downloaded image from extention to another?

我有这个线程从网络获取图像 url 然后将其保存到内存流然后从内存流保存到文件

我需要将任何下载的图像转换为 gif 图片,所以我做了这样的事情

unit downloadimgThread;

interface
uses Windows, SysUtils, Classes, dialogs, IdSSLOpenSSL, IdHttp, IdUri, System.AnsiStrings, Graphics, Jpeg, Vcl.Imaging.GIFImg, PNGImage;


type
  TDownloadUpdateVisualEvent = procedure(Sender: TObject; Anameofimg: String;
    var Aimagelocate: String) of object;

type
  TURLDownload = class(TThread)
  private
    FOnUpdateVisual: TDownloadUpdateVisualEvent;
    FURL: String;
    Fnameofimg: string;
    FPathImage: string;
    FFileNameImage: string;
    ImageName: string;
    PathURL: string;
    procedure DoUpdateVisual;
  protected
    procedure Execute; override;
  public
    constructor Create(Thrdid: Pointer; const AUrl: String;
      Const AOutPathImages: string; AOnUpdateVisual: TDownloadUpdateVisualEvent;
      Anameofimg: String); reintroduce;
    property URL: string read FURL write FURL;
    property PathImage: string read FPathImage;
    property FileNameImage: string read FFileNameImage;

  end;



var
URLDOWNLOAD: TURLDownload;

implementation

{ TURLDownload }



function JpgToGif(ms: TMemoryStream): Boolean;
var
  gif: TGIFImage;
  jpg: TJPEGImage;
begin
  Result := False;

  gif := TGIFImage.Create;
  try
    jpg := TJPEGImage.Create;
    try
      //jpg
      ms.Position := 0;
      jpg.LoadFromStream(ms);
      jpg.DIBNeeded;
      gif.Assign(jpg);

      //save...
      ms.Clear;
      gif.SaveToStream(ms);
      Result := True;
    finally
      jpg.Free;
      jpg := nil;
    end;
  finally
    gif.Free;
    gif := nil;
  end;
end;

constructor TURLDownload.Create(Thrdid: Pointer; const AUrl, AOutPathImages: string; AOnUpdateVisual: TDownloadUpdateVisualEvent; Anameofimg: String);
var
URI: TIdURI;
begin
inherited Create(false);
FreeOnTerminate := True;
FURL := AUrl;
FOnUpdateVisual := AOnUpdateVisual;
Fnameofimg := Anameofimg;
FPathImage := AOutPathImages;

URI := TIdURI.Create(AUrl);
try
ImageName := URI.Document;
PathURL := URI.path;
finally
URI.Free;
end;

end;

procedure TURLDownload.DoUpdateVisual;
begin
if Assigned(FOnUpdateVisual) then
FOnUpdateVisual(self, Fnameofimg, FFileNameImage);
end;

procedure TURLDownload.Execute;
var
aMs: TMemoryStream;
aIdHttp: TIdHttp;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
path: string;
dir: string;
SPEXT : String;
itsimage: string;
responsechk: Integer;
begin
dir := AnsiReplaceText(PathURL, '/', '');

if (ImageName = '') then
begin
exit;
end;

SPEXT := ExtractFileExt(ImageName);
ImageName := Copy(ImageName, 1, Length(ImageName) - Length(SPEXT));

path := PathImage + '\' + ImageName + '.gif';

if fileexists(path) then
begin
FFileNameImage := path;
if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;
exit;
end
else

if not fileexists(path) then
begin
aMs := TMemoryStream.Create;
aIdHttp := TIdHttp.Create(nil);
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try

IdSSL.SSLOptions.Method := sslvTLSv1;
IdSSL.SSLOptions.Mode := sslmUnassigned;
aIdHttp.HTTPOptions := [hoForceEncodeParams] + [hoNoProtocolErrorException];
aIdHttp.IOHandler := IdSSL;
aIdHttp.AllowCookies := True;
aIdHttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
aIdHttp.HandleRedirects := True;
aIdHttp.RedirectMaximum := 3;
try
aIdHttp.Head(trim(FURL));
except
end;
itsimage := aIdHttp.Response.ContentType;
responsechk := aIdHttp.ResponseCode;

if responsechk <> 200 then
begin
FFileNameImage := 'error';

if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;
exit;
end;


if (itsimage = 'image/gif') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
aMs.SaveToFile(path);
end else if (itsimage = 'image/jpeg') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
if JpgToGif(aMs) then
begin
aMs.SaveToFile(path);
end;
end;


try
if aIdHttp.Connected then
aIdHttp.Disconnect;

except

end;


finally
aMs.Free;
IdSSL.Free;
aIdHttp.Free;
end;
end;

FFileNameImage := path;

if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;

end;

end.

在本单元中,我尝试检查图像类型是否为 jpg 然后将其转换为 gif 并专门保存在这行代码中

if (itsimage = 'image/jpeg') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
if JpgToGif(aMs) then
begin
aMs.SaveToFile(path);
end;
// function to convert 
function JpgToGif(ms: TMemoryStream): Boolean;
var
  gif: TGIFImage;
  jpg: TJPEGImage;
begin
  Result := False;

  gif := TGIFImage.Create;
  try
    jpg := TJPEGImage.Create;
    try
      //jpg
      ms.Position := 0;
      jpg.LoadFromStream(ms);
      jpg.DIBNeeded;
      gif.Assign(jpg);

      //save...
      ms.Clear;
      gif.SaveToStream(ms);
      Result := True;
    finally
      jpg.Free;
      jpg := nil;
    end;
  finally
    gif.Free;
    gif := nil;
  end;
end;

当我尝试转换图像并保存时,保存的图像已损坏可能是什么问题?

对此有一个非常简单的解决方案。那就是使用 FMX Bitmap 而不是默认的 VCL Bitmap 因为它允许在加载时自动识别格式并在保存时根据您提供给 SaveToFile 方法的文件名的文件扩展名自动选择格式。

这是一个简单的代码,先将OpenDialog中选择的图像加载到Memory stream,然后再加载到Bitmap,然后将图像保存为GIF格式。

procedure TForm1.Button1Click(Sender: TObject);
var Bitmap: FMX.Graphics.TBitmap;
    MS: TMemoryStream;
begin
  if OpenDialog1.Execute then
  begin
    MS := TMemoryStream.Create;
    MS.LoadFromFile(OpenDialog1.FileName);
    Bitmap := FMX.Graphics.TBitmap.Create;
    Bitmap.LoadFromStream(MS);
    Bitmap.SaveToFile('D:\Proba.gif');
  end;
end;

如您所见,您只需要几行代码就可以在所有支持的格式之间转换图像。

您可以在此处查看支持哪些: http://docwiki.embarcadero.com/Libraries/XE8/en/FMX.Graphics.TBitmapCodecManager#Supported_Image_Formats

只需为文件所在的文件指定完整的命名空间,确保您确实在使用 FMX.Graphics.TBitmap。

注意:使用 VCL 应用程序并不意味着您不能使用 Fire Monkey 中存在的某些功能。