Delphi FMX环境下如何检测TImage指定区域的色调明暗
实现思路与可运行方案
1. 核心检测逻辑:获取指定区域平均亮度
FMX的TBitmap原生支持像素级访问,你可以通过锁定像素块计算指定区域的平均亮度,采用人眼感知友好的加权公式计算亮度值,范围为0(纯黑)~255(纯白)。
亮度检测函数代码
uses System.Types, FMX.Graphics; function CalcRegionLuminance(const ABitmap: TBitmap; const TargetRegion: TRectF): Byte; var LockedBits: TBitmapData; X, Y: Integer; Pixel: TAlphaColor; TotalLum: Int64; PixelCount: Integer; // 适配FMX缩放,将控件区域转换为Bitmap实际像素区域 BitmapRegion: TRect; begin Result := 0; if (not Assigned(ABitmap)) or ABitmap.IsEmpty then Exit; // 转换目标区域为Bitmap实际像素坐标,兼容MacOS Retina屏缩放 BitmapRegion.Left := Trunc(TargetRegion.Left * ABitmap.Scale); BitmapRegion.Top := Trunc(TargetRegion.Top * ABitmap.Scale); BitmapRegion.Right := Trunc(TargetRegion.Right * ABitmap.Scale); BitmapRegion.Bottom := Trunc(TargetRegion.Bottom * ABitmap.Scale); // 边界修正 BitmapRegion.Intersect(Rect(0, 0, ABitmap.Width, ABitmap.Height)); if BitmapRegion.IsEmpty then Exit; TotalLum := 0; PixelCount := 0; if ABitmap.Map(TMapAccess.Read, LockedBits) then try for Y := BitmapRegion.Top to BitmapRegion.Bottom - 1 do begin for X := BitmapRegion.Left to BitmapRegion.Right - 1 do begin Pixel := LockedBits.GetPixel(X, Y); // 人眼加权亮度公式:0.299R + 0.587G + 0.114B TotalLum := TotalLum + Trunc(0.299 * TAlphaColorRec(Pixel).R + 0.587 * TAlphaColorRec(Pixel).G + 0.114 * TAlphaColorRec(Pixel).B); Inc(PixelCount); end; end; if PixelCount > 0 then Result := Trunc(TotalLum / PixelCount); finally ABitmap.Unmap(LockedBits); end; end;
2. 明暗判断与叠加层切换逻辑
- 亮度阈值默认取128:平均亮度>128判定为亮色调区域,使用黑色叠加层;反之使用白色叠加层,你可以根据业务场景调整阈值。
- 叠加层如果放在
TListboxItem的Style中,你可以通过FindStyleResource方法获取到内置TImage和叠加层控件:
uses FMX.ListBox, FMX.Controls, FMX.Objects; procedure UpdateOverlayStyle(AListBoxItem: TListBoxItem); var Img: TImage; OverlayText: TText; OverlayImg: TImage; Lum: Byte; UseBlackOverlay: Boolean; // 叠加层在图片上的区域,示例为图片顶部20dp高度的全宽区域,按需调整 OverlayCoverRegion: TRectF; begin // 从Style中取出对应控件,名称和你在StyleBook里定义的一致 Img := AListBoxItem.FindStyleResource('inner_img') as TImage; OverlayText := AListBoxItem.FindStyleResource('overlay_text') as TText; OverlayImg := AListBoxItem.FindStyleResource('overlay_icon') as TImage; if (not Assigned(Img)) or Img.Bitmap.IsEmpty then Exit; // 定义你要检测的叠加层覆盖区域 OverlayCoverRegion := RectF(0, 0, Img.Width, 20); // 计算区域亮度 Lum := CalcRegionLuminance(Img.Bitmap, OverlayCoverRegion); UseBlackOverlay := Lum > 128; // 切换叠加层样式 if UseBlackOverlay then begin OverlayText.TextColor := TAlphaColors.Black; OverlayImg.Bitmap := YourBlackIconBitmap; // 提前准备好的黑色版本小图标 end else begin OverlayText.TextColor := TAlphaColors.White; OverlayImg.Bitmap := YourWhiteIconBitmap; // 提前准备好的白色版本小图标 end; end;
3. 注意事项
- 性能优化:仅在TImage加载完成后计算一次亮度并缓存结果,不要在列表滚动时反复调用,避免列表卡顿。
- 坐标适配:如果TImage的
WrapMode设置为Fit/Stretch等非原尺寸显示模式,需要先将叠加层的控件坐标转换为图片实际显示的像素坐标,再传入检测函数,避免取到图片外的无效区域。 - 透明像素处理:如果图片带透明通道,你可以在计算亮度时跳过透明度低于阈值的像素,避免透明区域影响判断。
内容的提问来源于stack exchange,提问作者Jimbob
相关产品推荐
相关产品推荐

