Delphi TImage:如何显示大于加载或分配给它们的TImage组件的图像?

时间:2017-01-17 20:14:00

标签: image delphi bitmap jpeg srgb

某些具有以下格式的JPEG文件未显示在Delphi的TImage控件中。

并将速度与我现有的灰度代码进行比较。他们使用的扫描线过程似乎比我现有的扫描线过程略快。对于使用图像的人来说,这是一个很好的起点。当我遇到问题并注意到文件大小时,我添加了标准的jpeg转换代码和滚动框。我相信这个问题是有效的,但我重写了它。如果我找到另一个相关答案,问题更容易找到,我会拉这个帖子。如果没有,我会离开它。

例如,使用尼康数码相机。

  

尺寸:宽5184 x高3888
  垂直分辨率:300 dpi
  颜色表示:sRGB
  压缩位/像素:2
  钻头深度:24
  EXIF版本:0230
  属性:N

来自三星手机相机:

  

尺寸:宽度4128 x高度2322
  水平&垂直分辨率:72 dpi
  颜色表示:sRGB
  分辨率单位:2
  压缩位/像素:[空白]
  钻头深度:24
  EXIF版本:0220
  属性:A

Adob​​e Photoshop的灰度文件:

  

尺寸:宽1800 x高3600
  水平和垂直分辨率:300 dpi
  颜色表示:未校准的
  压缩位/像素:[空白]
  钻头深度:8
  EXIF版本:[空白]
  属性:A

具有确切格式的文件作为最后一个,但尺寸小得多的文件有效。

  

一个工作文件的尺寸:宽度570 x高度248

24位深度,更小尺寸,无分辨率或压缩设置的文件也能正常工作。

当我尝试使用下面的代码显示图片时,失败文件上的图片始终为空白,并且不会返回任何错误。它与许多其他jpgbmp文件完美配合。

是否存在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;

1 个答案:

答案 0 :(得分:2)

由于您在加载JPEG图像时没有收到错误,我怀疑问题可能出在从TJPEGImageTBitmap的转换中。除非您要操纵图像像素,否则根本不需要转换,您可以将原始TJPEGImage直接分配给TImage。 VCL的TPicture类使用派生的TGraphic类,因此它可以以原生格式显示图像,您应该使用该功能,例如:

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,只有 TImage.StretchTImage.Proportional属性为True时,它们才会显示正常的。如果它们都设置为False(默认值),则图像显示为空白。

如果我先将JPG加载到TJPEGImage然后再将其分配给TBitmap,转换本身就可以正常工作(通过将TBitmap保存到.bmp文件来证明) ,只有当 StretchProportional为True时,位图才会正常显示,否则它们会显示为空白。

因此,作为另一项测试,我尝试使用TPaintBox,在OnPaint事件中手动绘制图像。如果我使用TCanvas.Draw()按原样绘制图像,则显示为空。如果我使用TCanvas.StretchDraw()来适应`PaintBox的客户区域内的图像,它们显示正常。

所以,我认为TCanvas可能会遇到内存问题,试图以更大的尺寸显示图像。它与正在使用的特定类型的JPG(正在加载正常)无关。

更新:没关系我上面说的话。我看到提供的JPG只有非常大的DPI,并且发生在它们的左上角都是白色的。如果TImage / TPaintBox的大小足以弥补,我现在可以看到完整维度的图片(更容易看出TImage是否放在TScrollBox上将TImage.AutoSize设置为True)。这可以解释为什么拉伸/比例绘制有效,通过在需要时拉伸图像以匹配TImage的尺寸。