You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 02:24:05