加载 Jpg/Gif/Bitmap 并转换为 Bitmap
Posted
技术标签:
【中文标题】加载 Jpg/Gif/Bitmap 并转换为 Bitmap【英文标题】:Load Jpg/Gif/Bitmap and convert to Bitmap 【发布时间】:2010-10-31 20:15:24 【问题描述】:我必须从 XML 文件加载图像。 XML 文件中没有关于图像是否为 JPG/GIF/BMP 的信息。加载图像后,我需要将其转换为位图。
有没有人知道如何在不知道实际文件格式的情况下将图像转换为位图?我正在使用 Delphi 2007/2009
谢谢。
【问题讨论】:
另见:***.com/questions/53382075/… 【参考方案1】:Delphi 2009 内置了对 JPEG、BMP、GIF 和 PNG 的支持。
对于早期版本的 Delphi,您可能需要为 PNG 和 GIF 寻找第三方实现,但在 Delphi 2009 中,您只需将 Jpeg
、pngimage
和 GIFImg
单位添加到您的 uses 子句中。
如果文件有扩展名,您可以使用以下代码,正如其他人所说,TPicture.LoadFromFile 会查看继承类注册的扩展名以确定要加载的图像。
uses
Graphics, Jpeg, pngimage, GIFImg;
procedure TForm1.Button1Click(Sender: TObject);
var
Picture: TPicture;
Bitmap: TBitmap;
begin
Picture := TPicture.Create;
try
Picture.LoadFromFile('C:\imagedata.dat');
Bitmap := TBitmap.Create;
try
Bitmap.Width := Picture.Width;
Bitmap.Height := Picture.Height;
Bitmap.Canvas.Draw(0, 0, Picture.Graphic);
Bitmap.SaveToFile('C:\test.bmp');
finally
Bitmap.Free;
end;
finally
Picture.Free;
end;
end;
如果文件扩展名未知,一种方法是查看前几个字节以确定图像类型。
procedure DetectImage(const InputFileName: string; BM: TBitmap);
var
FS: TFileStream;
FirstBytes: AnsiString;
Graphic: TGraphic;
begin
Graphic := nil;
FS := TFileStream.Create(InputFileName, fmOpenRead);
try
SetLength(FirstBytes, 8);
FS.Read(FirstBytes[1], 8);
if Copy(FirstBytes, 1, 2) = 'BM' then
begin
Graphic := TBitmap.Create;
end else
if FirstBytes = #137'PNG'#13#10#26#10 then
begin
Graphic := TPngImage.Create;
end else
if Copy(FirstBytes, 1, 3) = 'GIF' then
begin
Graphic := TGIFImage.Create;
end else
if Copy(FirstBytes, 1, 2) = #$FF#$D8 then
begin
Graphic := TJPEGImage.Create;
end;
if Assigned(Graphic) then
begin
try
FS.Seek(0, soFromBeginning);
Graphic.LoadFromStream(FS);
BM.Assign(Graphic);
except
end;
Graphic.Free;
end;
finally
FS.Free;
end;
end;
【讨论】:
就这么简单吗?太感谢了!是的,图像数据位于 xml 文件的 CDATA 部分。顺便说一句,Delphi 2007 不支持 Gif 吗?我不需要 png 支持。 Jpeg 已经有一段时间了。不确定GIF。过去我一直使用 Jedi 来支持 GIF。 使用:fmOpenRead OR fmShareDenyNone 这可以防止文件被锁定时失败【参考方案2】:如果您不知道图形具有什么格式,则不能使用TPicture.LoadFromFile
,因为此方法使用文件扩展名来确定需要加载哪些已注册的图形格式。没有匹配的TPicture.LoadFromStream
方法是有原因的。
可以在运行时检查数据并确定图形格式的外部库将是最佳解决方案。您可以使用efg page 作为您研究的起点。
一种快速而肮脏的解决方案是尝试几种您需要处理的格式,直到成功:
function TryLoadPicture(const AFileName: string; APicture: TPicture): boolean;
const
GraphicClasses: array[0..3] of TGraphicClass = (
TBitmap, TJPEGImage, TGIFImage, TPngImage);
var
FileStr, MemStr: TStream;
ClassIndex: integer;
Graphic: TGraphic;
begin
Assert(APicture <> nil);
FileStr := TFileStream.Create('D:\Temp\img.dat', fmOpenRead);
try
MemStr := TMemoryStream.Create;
try
MemStr.CopyFrom(FileStr, FileStr.Size);
// try various
for ClassIndex := Low(GraphicClasses) to High(GraphicClasses) do begin
Graphic := GraphicClasses[ClassIndex].Create;
try
try
MemStr.Seek(0, soFromBeginning);
Graphic.LoadFromStream(MemStr);
APicture.Assign(Graphic);
Result := TRUE;
exit;
except
end;
finally
Graphic.Free;
end;
end;
finally
MemStr.Free;
end;
finally
FileStr.Free;
end;
Result := FALSE;
end;
编辑:
GraphicEx library 有一个示例 convert 使用
GraphicClass := FileFormatList.GraphicFromContent(...);
确定图形格式。这似乎与您提到的 VB6 执行此操作的方式非常相似。也许你可以使用这个库来达到你的目的。
【讨论】:
感谢您的解决方案和澄清上述回复。您的代码看起来很有趣,但正如您所提到的,它实际上是一种快速而肮脏的方法。我正在寻找类似 VB 6 LoadPicture 函数的东西,它适用于支持的图像,而与文件扩展名无关。 引自 GraphicEx 网站:“上次更改:2007 年 2 月 3 日”【参考方案3】:我找到了一个更简单的方法!它自动加载 JPG/GIF/BMP 等文件,甚至不知道/检查文件格式,并相应地进行转换。它非常适合我。
在这里分享:)
Uses
Classes, ExtCtrls, Graphics, axCtrls;
Procedure TForm1.Button1Click(Sender: TObject);
Var
OleGraphic : TOleGraphic;
fs : TFileStream;
Source : TImage;
BMP : TBitmap;
Begin
Try
OleGraphic := TOleGraphic.Create; The magic class!
fs := TFileStream.Create('c:\testjpg.dat', fmOpenRead Or fmSharedenyNone);
OleGraphic.LoadFromStream(fs);
Source := Timage.Create(Nil);
Source.Picture.Assign(OleGraphic);
BMP := TBitmap.Create; Converting to Bitmap
bmp.Width := Source.Picture.Width;
bmp.Height := source.Picture.Height;
bmp.Canvas.Draw(0, 0, source.Picture.Graphic);
image1.Picture.Bitmap := bmp; Show the bitmap on form
Finally
fs.Free;
OleGraphic.Free;
Source.Free;
bmp.Free;
End;
End;
【讨论】:
是的。伤心。没有 PNG = 没有乐趣! 请注意,这个答案有严重的内存管理错误。如果TOleGraphic
构造函数失败,您将在随机指针上尝试fs.Free
、OleGraphic.Free
、Source.Free
和bmp.Free
,这非常糟糕!同样,如果TFileStream
构造函数失败,您将尝试fs.Free
、Source.Free
和bmp.Free
随机指针。以此类推,直到bmp.Width := ...
。这条线是第一条正确的线。始终使用成语X := TX.Create; try use X finally X.Free; end
,或者至少在try
之前初始化指向nil
的指针。在此问题解决之前,我会执行 -1。【参考方案4】:
我没有 Delphi 2007 或 2009 来查看这是否适用于这两个版本。但是,在 XE2 中,Vcl.Graphics
中还有一个名为 TWICImage
的类处理 Microsoft Imaging Component 支持的图像,包括 BMP、GIF、ICO、JPEG、PNG、TIF 和Windows 媒体照片。它能够从流中检测图像类型。假设您在名为 Image1 的表单上有一个 TImage
:
procedure LoadImageFromStream(Stream: TStream; Image: TImage);
var
wic: TWICImage;
begin
Stream.Position := 0;
wic := TWICImage.Create;
try
wic.LoadFromStream(Stream);
Image.Picture.Assign(wic);
finally
wic.Free;
end;
end;
procedure RenderImage(const Filename: string);
var
fs: TFileStream;
begin
fs := TFileStream.Create(Filename, fmOpenRead);
try
LoadImageFromStream(fs, Image1);
finally
fs.Free;
end;
end;
无需在您的 uses
语句中添加 PNGImage
、GIFImg
或 JPEG
即可工作。
其他答案显示了如何将TImage
转换为 BMP,所以我在这里不包括在内。我只是展示了另一种将各种图形类型加载到TImage
的方法,而无需事先知道图像类型或文件扩展名...
【讨论】:
在 C++Builder XE5 中完美运行TPicture::Assign
是否将图像数据复制到图片中? (我很警惕wic.Free
后面的悬空指针)
@MattMcNabb - 是的,它复制了它 (docwiki.embarcadero.com/Libraries/XE5/en/…),这是通过跟踪 VCL 代码来验证的。
通过 WIC 加载比通过 TImage 从文件加载快得多。以上是关于加载 Jpg/Gif/Bitmap 并转换为 Bitmap的主要内容,如果未能解决你的问题,请参考以下文章