Delphi TImage:如何显示大于它们正在加载或分配给的 TImage 组件的图像?
Delphi TImage: How do I display images that are larger than the TImage component they are being loaded in or assigned to?
某些具有以下格式的 JPEG 文件未显示在 Delphi 的 TImage
控件中。
- 问题已解决.. [TImage.Autosize] 默认情况下不选中图像控件中的复选框,因此图像未调整大小。我正在做这个项目.. https://community.embarcadero.com/blogs/entry/converting-to-grayscale-with-tbitmapscanline-property-39051
并将速度与我现有的灰度代码进行比较。他们使用的扫描线过程似乎比我目前使用的扫描线过程稍微快一些。对于处理图像的人来说,这是一个很好的起点。当我 运行 进入问题并注意到文件大小时,我添加了标准的 jpeg 转换代码和滚动框。我相信这个问题是有效的,但我改写了它。如果我找到问题更容易找到的另一个相关答案,我会拉这个post。没有的话我就走了
例如,来自尼康数码相机。
Dimensions : Width 5184 x Height 3888
Vertical Resolution : 300 dpi
Color Representation : sRGB
Compressed bits/pixel : 2
Bit depth : 24
EXIF version : 0230
Attributes : N
来自三星手机 phone 相机:
Dimensions : Width 4128 x Height 2322
Horizontal & Vertical Resolution : 72 dpi
Color Representation : sRGB
Resolution unit : 2
Compressed bits/pixel : [blank]
Bit depth : 24
EXIF version : 0220
Attributes : A
来自 Adobe Photoshop 的灰度文件:
Dimensions : Width 1800 x Height 3600
Horizontal and Vertical Resolution : 300 dpi
Color Representation : Uncalibrated
Compressed bits/pixel : [blank]
Bit depth : 8
EXIF version : [blank]
Attributes : A
与上一个格式完全相同但尺寸小得多的文件有效。
Dimensions of one working file : Width 570 x Height 248
具有 24 位深度、较小尺寸且没有分辨率或压缩设置的文件也能正常工作。
当我尝试使用下面的代码显示图片时,失败文件上的图片总是空白,并且没有返回任何错误。它与许多其他 jpg
和 bmp
文件完美配合。
sRGB 格式的文件是否需要转换?控件可以在屏幕上显示的内容是否有大小限制?如果是这样,有没有办法显示更大的文件?
procedure TForm1.btnBrowseClick(Sender: TObject);
var
bmp: TBitmap;
c2g: TColor2Grayscale;
ba: TBitmapAccess;
sw: TStopwatch;
jpg : TJPEGImage; // jpeg does not show 32-bit support in Delphi, only 24 and 8.
path, name, ext : string;
alreadyGray : boolean;
begin
bmp := TBitmap.Create;
jpg := TJPEGImage.Create;
OpenPicturedialog1.InitialDir := FindImageFolder(true);
if OpenPictureDialog1.Execute() then
try
name := OpenPictureDialog1.FileName;
path := ExtractFilePath(name);
ext := Lowercase ( ExtractFileExt(name) );
alreadyGray := false;
try
if ( ext = '.jpg' ) or ( ext = '.jpeg' ) then
begin
jpg.LoadFromFile(name);
bmp.Assign(jpg);
alreadyGray := jpg.Grayscale;
end
else
bmp.LoadFromFile( name );
except
on err: Exception do
begin
ShowMessage(err.Message);
Exit;
end;
end;
if bmp.PixelFormat = pfDevice then
bmp.PixelFormat := pf32bit;
Image1.Picture.Assign(bmp);
if alreadyGray then
begin
Image2.Picture.Assign(bmp);
Exit;
end;
finally
jpg.Free;
bmp.Free;
end;
end;
由于您在加载 JPEG 图像时没有遇到错误,我怀疑问题可能出在从 TJPEGImage
到 TBitmap
的转换中。除非你要操纵图像像素,否则根本不需要转换,你可以将原始 TJPEGImage
直接分配给 TImage
。 VCL 的 TPicture
class 使用派生的 TGraphic
classes 因此它可以以原始格式显示图像,您应该利用该功能,例如:
procedure TForm1.btnBrowseClick(Sender: TObject);
var
jpg: TJPEGImage;
bmp: TBitmap;
begin
OpenPicturedialog1.InitialDir := FindImageFolder(true);
if OpenPictureDialog1.Execute then
begin
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
if Image1.Picture.Graphic is TJPEGImage then
begin
if TJPEGImage(Image1.Picture.Graphic).Grayscale then
begin
Image2.Picture.Assign(Image1.Picture.Graphic);
end else
begin
jpg := TJPEGImage.Create;
try
jpg.Assign(Image1.Picture.Graphic);
jpg.Grayscale := True;
Image2.Picture.Assign(jpg);
finally
jpg.Free;
end;
end;
end else
begin
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32bit;
bmp.Assign(Image1.Picture.Graphic);
...
Image2.Picture.Assign(bmp);
finally
bmp.Free;
end;
end;
end;
end;
更新:我在 Windows 7 上用 XE2 做了一些测试,发现了和你一样的问题。
如果我使用 TImage.Picture.LoadFromFile()
加载 JPG as-is,它们显示正常 仅当 TImage.Stretch
或 TImage.Proportional
属性 是真的。如果它们都设置为 False(默认值),则图像显示为空白。
如果我先将 JPG 加载到 TJPEGImage
,然后将其分配给 TBitmap
,转换本身工作正常(通过将 TBitmap
保存到 .bmp
证明文件),并且位图显示正常 只有当 Stretch
或 Proportional
为 True 时,否则它们显示空白。
因此,作为另一个测试,我尝试使用 TPaintBox
,在其 OnPaint
事件中手动绘制图像。如果我使用 TCanvas.Draw()
以完整尺寸绘制图像 as-is,它们将显示为空。如果我使用 TCanvas.StretchDraw()
使图像适合 `PaintBox 的客户区,它们显示良好。
因此,我认为 TCanvas
可能会 运行 尝试以如此大的尺寸显示图像时出现内存问题。它与正在使用的特定类型的 JPG(正在正常加载)无关。
更新:别管我上面说的了。我看到所提供的 JPG 只是具有非常大的 DPI,并且 碰巧 在它们的 top-left 角落都是白色的。如果 TImage
/TPaintBox
尺寸较大以进行补偿,我现在可以看到完整尺寸的图像(更容易看出 TImage
是否放在 TScrollBox
TImage.AutoSize
设置为 True)。这可以解释为什么 stretch/proportional 绘图有效,通过在需要时拉伸图像以匹配 TImage
的尺寸。
某些具有以下格式的 JPEG 文件未显示在 Delphi 的 TImage
控件中。
- 问题已解决.. [TImage.Autosize] 默认情况下不选中图像控件中的复选框,因此图像未调整大小。我正在做这个项目.. https://community.embarcadero.com/blogs/entry/converting-to-grayscale-with-tbitmapscanline-property-39051
并将速度与我现有的灰度代码进行比较。他们使用的扫描线过程似乎比我目前使用的扫描线过程稍微快一些。对于处理图像的人来说,这是一个很好的起点。当我 运行 进入问题并注意到文件大小时,我添加了标准的 jpeg 转换代码和滚动框。我相信这个问题是有效的,但我改写了它。如果我找到问题更容易找到的另一个相关答案,我会拉这个post。没有的话我就走了
例如,来自尼康数码相机。
Dimensions : Width 5184 x Height 3888
Vertical Resolution : 300 dpi
Color Representation : sRGB
Compressed bits/pixel : 2
Bit depth : 24
EXIF version : 0230
Attributes : N
来自三星手机 phone 相机:
Dimensions : Width 4128 x Height 2322
Horizontal & Vertical Resolution : 72 dpi
Color Representation : sRGB
Resolution unit : 2
Compressed bits/pixel : [blank]
Bit depth : 24
EXIF version : 0220
Attributes : A
来自 Adobe Photoshop 的灰度文件:
Dimensions : Width 1800 x Height 3600
Horizontal and Vertical Resolution : 300 dpi
Color Representation : Uncalibrated
Compressed bits/pixel : [blank]
Bit depth : 8
EXIF version : [blank]
Attributes : A
与上一个格式完全相同但尺寸小得多的文件有效。
Dimensions of one working file : Width 570 x Height 248
具有 24 位深度、较小尺寸且没有分辨率或压缩设置的文件也能正常工作。
当我尝试使用下面的代码显示图片时,失败文件上的图片总是空白,并且没有返回任何错误。它与许多其他 jpg
和 bmp
文件完美配合。
sRGB 格式的文件是否需要转换?控件可以在屏幕上显示的内容是否有大小限制?如果是这样,有没有办法显示更大的文件?
procedure TForm1.btnBrowseClick(Sender: TObject);
var
bmp: TBitmap;
c2g: TColor2Grayscale;
ba: TBitmapAccess;
sw: TStopwatch;
jpg : TJPEGImage; // jpeg does not show 32-bit support in Delphi, only 24 and 8.
path, name, ext : string;
alreadyGray : boolean;
begin
bmp := TBitmap.Create;
jpg := TJPEGImage.Create;
OpenPicturedialog1.InitialDir := FindImageFolder(true);
if OpenPictureDialog1.Execute() then
try
name := OpenPictureDialog1.FileName;
path := ExtractFilePath(name);
ext := Lowercase ( ExtractFileExt(name) );
alreadyGray := false;
try
if ( ext = '.jpg' ) or ( ext = '.jpeg' ) then
begin
jpg.LoadFromFile(name);
bmp.Assign(jpg);
alreadyGray := jpg.Grayscale;
end
else
bmp.LoadFromFile( name );
except
on err: Exception do
begin
ShowMessage(err.Message);
Exit;
end;
end;
if bmp.PixelFormat = pfDevice then
bmp.PixelFormat := pf32bit;
Image1.Picture.Assign(bmp);
if alreadyGray then
begin
Image2.Picture.Assign(bmp);
Exit;
end;
finally
jpg.Free;
bmp.Free;
end;
end;
由于您在加载 JPEG 图像时没有遇到错误,我怀疑问题可能出在从 TJPEGImage
到 TBitmap
的转换中。除非你要操纵图像像素,否则根本不需要转换,你可以将原始 TJPEGImage
直接分配给 TImage
。 VCL 的 TPicture
class 使用派生的 TGraphic
classes 因此它可以以原始格式显示图像,您应该利用该功能,例如:
procedure TForm1.btnBrowseClick(Sender: TObject);
var
jpg: TJPEGImage;
bmp: TBitmap;
begin
OpenPicturedialog1.InitialDir := FindImageFolder(true);
if OpenPictureDialog1.Execute then
begin
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
if Image1.Picture.Graphic is TJPEGImage then
begin
if TJPEGImage(Image1.Picture.Graphic).Grayscale then
begin
Image2.Picture.Assign(Image1.Picture.Graphic);
end else
begin
jpg := TJPEGImage.Create;
try
jpg.Assign(Image1.Picture.Graphic);
jpg.Grayscale := True;
Image2.Picture.Assign(jpg);
finally
jpg.Free;
end;
end;
end else
begin
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32bit;
bmp.Assign(Image1.Picture.Graphic);
...
Image2.Picture.Assign(bmp);
finally
bmp.Free;
end;
end;
end;
end;
更新:我在 Windows 7 上用 XE2 做了一些测试,发现了和你一样的问题。
如果我使用 TImage.Picture.LoadFromFile()
加载 JPG as-is,它们显示正常 仅当 TImage.Stretch
或 TImage.Proportional
属性 是真的。如果它们都设置为 False(默认值),则图像显示为空白。
如果我先将 JPG 加载到 TJPEGImage
,然后将其分配给 TBitmap
,转换本身工作正常(通过将 TBitmap
保存到 .bmp
证明文件),并且位图显示正常 只有当 Stretch
或 Proportional
为 True 时,否则它们显示空白。
因此,作为另一个测试,我尝试使用 TPaintBox
,在其 OnPaint
事件中手动绘制图像。如果我使用 TCanvas.Draw()
以完整尺寸绘制图像 as-is,它们将显示为空。如果我使用 TCanvas.StretchDraw()
使图像适合 `PaintBox 的客户区,它们显示良好。
因此,我认为 TCanvas
可能会 运行 尝试以如此大的尺寸显示图像时出现内存问题。它与正在使用的特定类型的 JPG(正在正常加载)无关。
更新:别管我上面说的了。我看到所提供的 JPG 只是具有非常大的 DPI,并且 碰巧 在它们的 top-left 角落都是白色的。如果 TImage
/TPaintBox
尺寸较大以进行补偿,我现在可以看到完整尺寸的图像(更容易看出 TImage
是否放在 TScrollBox
TImage.AutoSize
设置为 True)。这可以解释为什么 stretch/proportional 绘图有效,通过在需要时拉伸图像以匹配 TImage
的尺寸。