如何在Delphi 11.3中程序化反转TImageCollection图像(保留透明度)
程序化修改TImageCollection图标颜色(适配深色主题/多颜色需求)
针对Delphi 11.3中TImageCollection+TVirtualImageList的图标颜色适配问题,无需维护多套图像资源,可通过直接操作图像像素或动态绘制的方式实现颜色转换,同时保留透明度。
一、批量转换图像颜色(预生成变体)
适合需要长期保留多色版本的场景,直接修改或新增TImageCollection中的图像条目。
核心函数实现
1. 反转颜色(黑→白,适配深色背景)
procedure ReverseImageColor(const SrcBitmap, DestBitmap: TBitmap); var X, Y: Integer; SrcPixel, DestPixel: PRGBQuad; SrcScanline, DestScanline: PByte; begin DestBitmap.SetSize(SrcBitmap.Width, SrcBitmap.Height); DestBitmap.PixelFormat := pf32bit; // 强制32位带Alpha通道 for Y := 0 to SrcBitmap.Height - 1 do begin SrcScanline := SrcBitmap.ScanLine[Y]; DestScanline := DestBitmap.ScanLine[Y]; for X := 0 to SrcBitmap.Width - 1 do begin SrcPixel := PRGBQuad(SrcScanline + X * SizeOf(TRGBQuad)); DestPixel := PRGBQuad(DestScanline + X * SizeOf(TRGBQuad)); // 保留Alpha通道,反转RGB分量 DestPixel^.rgbBlue := 255 - SrcPixel^.rgbBlue; DestPixel^.rgbGreen := 255 - SrcPixel^.rgbGreen; DestPixel^.rgbRed := 255 - SrcPixel^.rgbRed; DestPixel^.rgbReserved := SrcPixel^.rgbReserved; // 继承原透明度 end; end; end;
2. 替换指定颜色(如黑→红)
procedure ReplaceImageColor(const SrcBitmap, DestBitmap: TBitmap; OldColor, NewColor: TColor); var X, Y: Integer; SrcPixel, DestPixel: PRGBQuad; SrcScanline, DestScanline: PByte; OldRGB, NewRGB: TRGBQuad; begin DestBitmap.SetSize(SrcBitmap.Width, SrcBitmap.Height); DestBitmap.PixelFormat := pf32bit; // 将TColor转换为RGBQuad格式 ColorToRGBQuad(OldColor, OldRGB); ColorToRGBQuad(NewColor, NewRGB); for Y := 0 to SrcBitmap.Height - 1 do begin SrcScanline := SrcBitmap.ScanLine[Y]; DestScanline := DestBitmap.ScanLine[Y]; for X := 0 to SrcBitmap.Width - 1 do begin SrcPixel := PRGBQuad(SrcScanline + X * SizeOf(TRGBQuad)); DestPixel := PRGBQuad(DestScanline + X * SizeOf(TRGBQuad)); // 匹配目标颜色则替换,否则保留原像素 if (SrcPixel^.rgbRed = OldRGB.rgbRed) and (SrcPixel^.rgbGreen = OldRGB.rgbGreen) and (SrcPixel^.rgbBlue = OldRGB.rgbBlue) then begin DestPixel^.rgbRed := NewRGB.rgbRed; DestPixel^.rgbGreen := NewRGB.rgbGreen; DestPixel^.rgbBlue := NewRGB.rgbBlue; end else DestPixel^ := SrcPixel^; DestPixel^.rgbReserved := SrcPixel^.rgbReserved; // 保留透明度 end; end; end; // 辅助函数:TColor转TRGBQuad procedure ColorToRGBQuad(Color: TColor; out RGBQuad: TRGBQuad); var RGB: TColorRGB; begin RGB := ColorToRGB(Color); RGBQuad.rgbRed := GetRValue(RGB); RGBQuad.rgbGreen := GetGValue(RGB); RGBQuad.rgbBlue := GetBValue(RGB); RGBQuad.rgbReserved := 255; end;
批量处理TImageCollection
遍历所有图像,生成对应颜色变体并添加到集合中:
type TImageColorMode = (icmReverse, icmRed); procedure ProcessImageCollection(ImageCollection: TImageCollection; Mode: TImageColorMode); var I: Integer; SrcBmp, DestBmp: TBitmap; Item: TImageCollectionItem; Suffix: string; begin SrcBmp := TBitmap.Create; DestBmp := TBitmap.Create; try case Mode of icmReverse: Suffix := '_white'; icmRed: Suffix := '_red'; end; for I := 0 to ImageCollection.Images.Count - 1 do begin Item := ImageCollection.Images[I]; Item.Bitmap.AssignTo(SrcBmp); case Mode of icmReverse: ReverseImageColor(SrcBmp, DestBmp); icmRed: ReplaceImageColor(SrcBmp, DestBmp, clBlack, clRed); end; // 新增颜色变体条目 with ImageCollection.Images.Add do begin Name := Item.Name + Suffix; Bitmap.Assign(DestBmp); Width := Item.Width; Height := Item.Height; end; end; finally SrcBmp.Free; DestBmp.Free; end; end;
调用示例:
// 生成白色变体(适配深色主题) ProcessImageCollection(ImageCollection1, icmReverse); // 生成红色变体 ProcessImageCollection(ImageCollection1, icmRed);
二、动态绘制时修改颜色(按需转换)
适合需要频繁切换主题/颜色的场景,无需修改原ImageCollection,在TVirtualImageList绘制时实时转换:
procedure TMainForm.VirtualImageList1DrawImage(Sender: TCustomVirtualImageList; const AImage: TVirtualImage; ACanvas: TCanvas; const ARect: TRect; AOpacity: Byte; AState: TVirtualImageState); var Bmp: TBitmap; TempBmp: TBitmap; begin Bmp := TBitmap.Create; TempBmp := TBitmap.Create; try // 从ImageCollection获取原图像 ImageCollection1.GetBitmap(AImage.Name, Bmp); TempBmp.SetSize(Bmp.Width, Bmp.Height); TempBmp.PixelFormat := pf32bit; // 根据当前主题判断是否反转颜色 if TOSThemeManager.Current.IsDarkMode then ReverseImageColor(Bmp, TempBmp) else TempBmp.Assign(Bmp); // 绘制到目标画布 ACanvas.Draw(ARect.Left, ARect.Top, TempBmp); finally Bmp.Free; TempBmp.Free; end; end;
注意事项
- 确保所有图像为32位带Alpha通道格式,否则透明度会丢失;若原图像格式不符,可在处理前先转换为pf32bit。
- 批量处理时,建议通过命名后缀区分不同颜色变体,方便在VirtualImageList中指定调用。
- 动态绘制方式更节省内存,但会增加少量绘制开销,适合主题切换频繁的场景。
内容的提问来源于stack exchange,提问作者Alister
相关产品推荐
相关产品推荐

