【问题标题】:How to draw a scaled version of images from the system ImageList?如何从系统 ImageList 中绘制图像的缩放版本?
【发布时间】:2015-01-23 23:19:02
【问题描述】:

我创建并初始化TImageList...

ImageList:=TImageList.Create(self);
ImageList.ShareImages:=true;

我获得了小图标 (16x16) 的系统 ImageList 句柄...

ImageList.Handle:=SHGetFileInfo('',0,FileInfo,SizeOf(FileInfo),SHGFI_SYSICONINDEX or SHGFI_SMALLICON);

现在我想在缩放到 50x50 像素的控制画布上绘制图标。我该怎么做?

【问题讨论】:

  • 不能再小2个像素吗? 48x48 像素?
  • 不,例如,我说的是 50,但我希望能够将其缩放到任何大小。
  • 最好获得 48x48 或更大的尺寸并将其缩小,而不是将 16x16 拉伸到 50x50。在任何情况下,您都可以使用ImageList.GetBitmap 并使用它做任何您想做的事情。或者甚至更好地从中获取一个图标句柄,并使用DrawIconEx
  • 是的,缩小总比扩大好。这样,您将获得更好的图像分辨率。
  • 您关心结果的质量吗?你介意这些图标看起来很可怕吗?

标签: delphi scale timagelist


【解决方案1】:

放大小图标绝不是个好主意。 16X16 图标太小,无法按原样以任何其他方式使用。

首先,您可以使用获得更大的外壳图像

ImageList.Handle:=SHGetFileInfo('',0,FileInfo,SizeOf(FileInfo),SHGFI_SYSICONINDEX or SHGFI_ICON);

这些图像通常为 32x32 像素,但为了安全起见(如果 Windows 以高 DPI 模式运行),您可以从系统中获取正确的尺寸

uses
  Winapi.Windows;

var
  IconWidth, IconHeight: integer;

  IconWidth := GetSystemMetrics(SM_CXICON);
  IconHeight := GetSystemMetrics(SM_CYICON);

您还可以使用SHGetImageList http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185%28v=vs.85%29.aspx 获得更大的外壳图像

要从您的 ImageList 中检索图标(如果 ImageList 包含图标,并且在您的情况下包含图标),您可以使用:

ImageList.GetIcon(Index: Integer; Image: TIcon);

要在保持透明度的同时将图标缩放到自定义尺寸,您可以使用以下代码:

procedure StretchDrawIcon(Canvas: TCanvas; Dest: TRect; Icon: TIcon);
begin
  DrawIconEx(Canvas.Handle, Dest.Left, Dest.Top, Icon.Handle, Dest.Right - Dest.Left, Dest.Bottom - Dest.Top, 0, 0, DI_NORMAL);
end;

【讨论】:

    【解决方案2】:

    由于无法使用 StretchDraw 拉伸提取的图标,并且提取的位图会失去透明度,一种方法可能是提取图标并使用 SetWorldTransform 操作目标画布:

    uses Shellapi, Math;
    
    Procedure SetCanvasZoomAndRotation(ACanvas:TCanvas;Zoom:Double;Angle:Double;CenterpointX,CenterpointY:Double);
    var
        form : tagXFORM;
        Winkel:Double;
    
    begin
          Winkel := DegToRad(Angle);
          SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
          SetMapMode(ACanvas.Handle,MM_ANISOTROPIC);
          form.eM11 := Zoom * cos( Winkel);
          form.eM12 := Zoom *Sin( Winkel)  ;
          form.eM21 := Zoom * (-sin( Winkel));
          form.eM22 := Zoom * cos( Winkel) ;
          form.eDx := CenterpointX;
          form.eDy := CenterpointY;
          SetWorldTransform(ACanvas.Handle,form);
    end;
    
     Procedure ResetCanvas(ACanvas:TCanvas);
    begin
       SetCanvasZoomAndRotation(ACanvas , 1, 0, 0,0);
    end;
    
    procedure TDemoForm.Button1Click(Sender: TObject);
    var
     FileInfo:_SHFileINfoW;
     ico:TIcon;
     ImageList:TImageList;
     i,x,y:Integer;
     zoom:double;
    begin
      ImageList:=TImageList.Create(self);
      ImageList.ShareImages:=true;
      ImageList.Handle:=SHGetFileInfo('',0,FileInfo,SizeOf(FileInfo),SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
      ico:=TIcon.Create;
      try
      x := 0;
      y := 0;
      zoom := 50 / Imagelist.Width;
      SetCanvasZoomAndRotation(Canvas,zoom,0,0 ,0);
      for I := 0 to ImageList.Count-1 do
       begin
        ImageList.GetIcon(i,ico);
        Canvas.Draw(x,y,ico);
        inc(x,Imagelist.Width);
        if (x + Imagelist.Width) * zoom > width then
            begin
            x := 0;
            inc(y,Imagelist.Height);
            end;
       end;
      finally
        ico.Free;
        ResetCanvas(Canvas);
        ImageList.Free;
      end;
    end;
    

    使用 250 作为所需大小的示例:

    【讨论】:

      【解决方案3】:

      TImageList 不支持绘制缩放图像,它按原样绘制图像。它提供的唯一选项是让您指定应在目标 Canvas 上绘制图像的 X/Y 坐标。

      要缩放图像,您必须先将所需图像提取到临时的TBitmap 并调用其Draw() 方法,该方法允许您在目标画布上指定所需的矩形。然后,位图将根据需要拉伸/缩放其绘图以填充该矩形。

      【讨论】:

        猜你喜欢
        • 2018-02-03
        • 1970-01-01
        • 2012-06-06
        • 2017-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-07
        相关资源
        最近更新 更多