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

将彩色位图转为pf8bit灰度图:设置像素格式后图像失真问题

解决pf8bit灰度图失真问题

你遇到的问题本质是:直接修改PixelFormat为pf8bit时,TBitmap会自动做通用颜色量化——它不知道你已经把图像转成灰度了,会把所有灰度色当成独立彩色压缩,自然出现类似GIF的失真。

要生成正确的pf8bit灰度图,不能靠自动格式转换,得手动把灰度值映射到预设的灰度调色板索引上,具体实现如下:

function CreateGrayPalette(NumColors: Integer = 256): HPALETTE;
VAR
  i  : Integer;
  lp : TMaxLogPalette;
  Grey: Byte;
begin
  lp.palVersion := $300;
  lp.palNumEntries := NumColors;
  for i := 0 to NumColors - 1 do
  begin
    Grey := i * 255 DIV NumColors;
    lp.palPalEntry[i].peRed   := Grey;
    lp.palPalEntry[i].peGreen := Grey;
    lp.palPalEntry[i].peBlue  := Grey;
    lp.palPalEntry[i].peFlags := PC_RESERVED;
  end;
  Result := CreatePalette(pLogPalette(@lp)^);
end;

// 直接创建带灰度调色板的pf8bit Bitmap
function CreateGray8BitBitmap(Width, Height: Integer): TBitmap;
begin
  Result := TBitmap.Create;
  Result.PixelFormat := pf8bit;
  Result.Width := Width;
  Result.Height := Height;
  // 绑定灰度调色板
  var GrayPalette := CreateGrayPalette;
  if GrayPalette <> 0 then
  begin
    Result.Palette := GrayPalette;
    DeleteObject(GrayPalette); // 绑定后释放调色板对象
  end;
end;

{$R-}
function GetGrayValue(Color: TColor): Byte;
CONST
  LuminanceR = 54;   // 亮度权重系数
  LuminanceG = 184;
  LuminanceB = 18;
begin
  Result :=
    (((Color AND $00FF0000) SHR 16 * LuminanceR) +
     ((Color AND $0000FF00) SHR 8  * LuminanceG) +
     ((Color AND $000000FF)        * LuminanceB)) SHR 8;
end;
{$R+}

procedure ConvertToGrayscale(BMP: TBitmap);
var
  GrayBMP: TBitmap;
  Row, Col: Integer;
  SrcLine: PDWord;
  DstLine: PByte;
  GrayVal: Byte;
begin
  // 先把原图像转成32位方便读取像素
  BMP.PixelFormat := pf32bit;

  // 创建目标8位灰度图
  GrayBMP := CreateGray8BitBitmap(BMP.Width, BMP.Height);
  try
    // 逐行复制并转换灰度索引
    for Row := 0 to BMP.Height - 1 do
    begin
      SrcLine := PDWord(BMP.ScanLine[Row]);
      DstLine := PByte(GrayBMP.ScanLine[Row]);
      for Col := 0 to BMP.Width - 1 do
      begin
        GrayVal := GetGrayValue(SrcLine^);
        DstLine^ := GrayVal; // 直接用灰度值作为调色板索引
        Inc(SrcLine);
        Inc(DstLine);
      end;
    end;

    // 把结果替换回原BMP
    BMP.Assign(GrayBMP);
  finally
    GrayBMP.Free;
  end;
end;

关键说明:

  • 不再依赖TBitmap自动转换格式,手动创建pf8bit位图并绑定灰度调色板
  • 每个像素的灰度值直接对应调色板索引(调色板索引i对应灰度值i),无需量化,直接映射避免失真
  • 绑定调色板后调用DeleteObject释放资源,防止内存泄漏

内容的提问来源于stack exchange,提问作者Error - CPU Not Foud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:12:49