ReactOS 图形系统分析(19):颜色转换对象 — XLATEOBJ(xlateobj.c/h)

ReactOS 图形系统分析(19):颜色转换对象 — XLATEOBJ(xlateobj.c/h)

ReactOS 图形系统分析(19):颜色转换对象 — XLATEOBJ(xlateobj.c/h)

1. 概述

xlateobj.c / xlateobj.h位于win32ss/gdi/eng/,实现XLATEOBJ(颜色转换对象)——Windows GDI/DDI 中描述"源表面颜色 → 目标表面颜色"转换的核心对象。它解决一个本质问题:不同位深/格式/调色板的表面之间复制像素时,每个像素值如何映射

与《分析_16/17/18》不同,xlateobj不是预留服务层,而是引擎最核心、被高频调用的模块:DIB 引擎每个位深(1/4/8/16/24/32bpp)的 BitBlt、拉伸、Alpha 混合、文本字形上屏、画刷填充,全部经过XLATEOBJ_iXlate做像素级颜色转换。

┌─────────────────────────────────────────────────────────────┐ │ 消费方 │ │ DIB 引擎 (dib*.c / BitBlt 内联 XLATEOBJ_iXlate) │ │ eng/bitblt.c (画刷/前景背景色) dib/alphablend.c │ │ dib/stretchblt.c ntgdi(bitblt/fillshap/freetype/palette) │ ├─────────────────────────────────────────────────────────────┤ │ gdi/eng/xlateobj.c(本分析对象) │ │ 核心: EXLATEOBJ 结构 + pfnXlate 函数指针分发 │ │ ├── ~25 个专用转换函数 (FN_XLATE) │ │ ├── EXLATEOBJ_vInitialize: 按源/目标调色板类型选择函数 │ │ └── DDI 公开: XLATEOBJ_iXlate / cGetPalette / │ │ hGetColorTransform / piVector │ ├─────────────────────────────────────────────────────────────┤ │ ntgdi/palette.c (调色板对象/位掩码) │ │ 提供 gpalRGB/gpalRGB555/gpalRGB565/gppalMono 等全局调色板 │ └─────────────────────────────────────────────────────────────┘

2. 核心数据结构

2.1 XLATEOBJ — DDI 公开部分([winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L1254-L1261))

typedefstruct_XLATEOBJ{ULONG iUniq;// 唯一编号(每次初始化递增,用于缓存命中判断)FLONG flXlate;// XO_* 标志USHORT iSrcType;// 源调色板类型USHORT iDstType;// 目标调色板类型ULONG cEntries;// 转换表项数ULONG*pulXlate;// 转换表指针(可指向内嵌数组或堆分配)}XLATEOBJ;

2.2 EXLATEOBJ — 引擎扩展([xlateobj.h](file:///d:/reactos/win32ss/gdi/eng/xlateobj.h#L19-L51))

typedefstruct_EXLATEOBJ{XLATEOBJ xlo;// 公开头PFN_XLATE pfnXlate;// ← 函数指针分发核心(FASTCALL ULONG(pexlo, iColor))PPALETTE ppalSrc;// 源调色板PPALETTE ppalDst;// 目标调色板PPALETTE ppalDstDc;// 目标 DC 调色板(DC_PALETTE 用)HANDLE hColorTransform;// 颜色变换句柄(ICM)union// 6 个 ULONG 的复用池:{ULONG aulXlate[6];// ① 内嵌小转换表(≤6 项,省去堆分配)struct{// ② 位域转换参数(掩码 + 旋转偏移)ULONG ulRedMask;ULONG ulGreenMask;ULONG ulBlueMask;ULONG ulRedShift;ULONG ulGreenShift;ULONG ulBlueShift;};struct{// ③ 彩色→单色转换参数(点积判别常数)LONG lDeltaR;LONG lDeltaG;LONG lDeltaB;LONG lHalfDist;}ToMono;};}EXLATEOBJ,*PEXLATEOBJ;

设计亮点:pfnXlate函数指针 + 6 个 ULONG 的联合池——同一块内嵌存储按转换类型复用作"小表 / 位域掩码偏移 / 单色点积常数",避免为小转换表堆分配,且转换本身是一条快路径调用。

2.3 标志位

XO_转换类型标志([winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L1247-L1249)):*

标志含义
XO_TRIVIAL恒等转换(源值即目标值)
XO_TABLE查表转换
XO_TO_MONO转换到单色

XO_调色板编号(XLATEOBJ_cGetPalette用,[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L3151-L3155)):*XO_SRCPALETTE=1XO_DESTPALETTE=2XO_DESTDCPALETTE=3XO_SRCBITFIELDS=4XO_DESTBITFIELDS=5

PAL_调色板类型([palette.h](file:///d:/reactos/win32ss/gdi/ntgdi/palette.h#L10-L28),节选):*

标志含义
PAL_INDEXED索引色(查表,含颜色表)
PAL_BITFIELDS位域(RGB 掩码 + 偏移)
PAL_RGB/PAL_BGR24/32bpp 直接 RGB / BGR 顺序
PAL_RGB16_555/PAL_RGB16_56516bpp 高/低 5 位格式
PAL_MONOCHROME单色(仅 2 色)
PAL_DIBSECTIONDIB Section 专用(转换方向特殊处理)

2.4 全局单例 gexloTrivial

EXLATEOBJ gexloTrivial={{0,XO_TRIVIAL,0,0,0,0},EXLATEOBJ_iXlateTrivial};

恒等转换的全局实例(flXlate=XO_TRIVIAL+pfnXlate=iXlateTrivial),当无颜色转换需求时直接引用([bitblt_new.c](file:///d:/reactos/win32ss/gdi/eng/bitblt_new.c#L141)、[mouse.c](file:///d:/reactos/win32ss/gdi/eng/mouse.c#L357)),避免每次分配对象。


3. 转换函数族(~25 个 FN_XLATE)

全部签名为FASTCALL ULONG(PEXLATEOBJ, ULONG iColor),按用途分五类:

3.1 单色快速通道

函数行为
iXlateTrivial恒等(返回 iColor)
iXlateMonoInvertiColor ^ 1(黑白互换)
iXlateMonoTo0/iXlateMonoTo1全部映射为 0 / 1
iXlateToMono查 1 项表:(iColor == pulXlate[0])
iXlateRGBToBW/iXlateRGBToWB亮度阈值(r+g+b >= 383判黑/白),仅用于纯黑/纯白目标

3.2 彩色→单色(点积判别)

EXLATEOBJ_iXlateRGBToMono(pexlo,rgbColor){LONG lDist=r*pexlo->ToMono.lDeltaR+g*pexlo->ToMono.lDeltaG+b*pexlo->ToMono.lDeltaB;return(lDist>pexlo->ToMono.lHalfDist);}

把前景/背景色看成 RGB 空间两点,预计算前景减背景的方向向量lDelta*)与判别阈值lHalfDist = (|F|²−|B|²)/2),每像素用点积符号判归属——几何意义即"像素点落在前背景连线哪一侧"。iXlateBGRToMono仅是字节序反转版本(GetRValue取蓝)。

3.3 位格式转换(16bpp 家族)

转换要点
RGBtoBGR/ 反向仅交换 R/B 字节(`(v&0x00ff00ff)<<16
RGBto555/BGRto55524bpp → 5-5-5(右移+掩码,含 BGR 序)
RGBto565/BGRto56524bpp → 5-6-5
555toRGB/555toBGR5-5-5 → 24bpp,gajXlate5to8扩位表(5bit→8bit 按 8 间隔扩展)
565toRGB/565toBGR5-6-5 → 24bpp,绿用gajXlate6to8(6bit→8bit,4 间隔)
555to565/565to55516bpp 互转(复制最高绿位等位操作)

扩位查表:gajXlate5to8[32]/gajXlate6to8[64]把 5/6 位分量均匀映射到 8 位(如 5bit 值 v →v*255/31取整),比移位+或操作精度更高。

3.4 位域转换

EXLATEOBJ_iXlateShiftAndMask(pexlo,iColor){iNewColor=_rotl(iColor,ulRedShift)&ulRedMask;iNewColor|=_rotl(iColor,ulGreenShift)&ulGreenMask;iNewColor|=_rotl(iColor,ulBlueShift)&ulBlueMask;returniNewColor;}

通用位域重排:用循环左移对齐各通道后按掩码提取,源/目标的 555/565/掩码位域一律走此函数。

3.5 调色板索引转换

函数行为
RGBtoPal/555toPal/565toPal转 RGB 后PALETTE_ulGetNearestPaletteIndex求最近色索引
BitfieldsToPal先 ShiftAndMask 转 RGB 再查最近索引
Table通用查表:iColor >= cEntries ? 0 : pulXlate[iColor](越界保护)

4. EXLATEOBJ_vInitialize — 转换器选择器

这是模块的总调度器,根据源/目标调色板类型(flFlags)组合,从 ~25 个函数中挑出最优实现:

MONO → MONO

MONO → 彩色

彩色 → MONO

INDEXED → INDEXED

RGB/BGR/555/565/BITFIELDS
→ 各目标

ShiftAndMask 且偏移全 0

pfnXlate == Trivial

EXLATEOBJ_vInitialize(ppalSrc, ppalDst,
crSrcBack, crDstBack, crDstFore)

默认 RGB; iUniq++ 递增; 清空状态

ppalDst == ppalSrc?

pfnXlate = Trivial, XO_TRIVIAL

非索引调色板 → 预计算
PALETTE_vGetBitMasks + CalculateShift

源/目标类型组合

4 情形: trivial / invert / to0 / to1

2 项查表 (DIB/直接 或 前背景色)

iXlateToMono + 点积常数
(CLR_INVALID 时 vInitRGBToMono)

建全量表; cDiff==0 → 退化 Trivial
(>6 项才堆分配)

按 5×5 组合表选专用函数

尾优化

退化 Trivial

XO_TRIVIAL

关键分支细节:

  1. MONO→MONO 四情形([xlateobj.c](file:///d:/reactos/win32ss/gdi/eng/xlateobj.c#L541-L589)):先按"DIB/DDB 方向 + 前背景色"算出iColors[0]/[1],再匹配 4 种简化:(0,1)→Trivial(1,0)→Invert(0,0)→To0(1,1)→To1
  2. 彩色→MONO 的 CLR_INVALID 特例:调用方(如NtGdiSetPixel)传CLR_INVALID表示"直接用 DIB 颜色表做点积判别",此时EXLATEOBJ_vInitRGBToMono用目标单色调色板的 0/1 号色初始化点积参数。
  3. INDEXED→INDEXED 退化优化:构建全量表后若所有项pulXlate[i]==i(恒等映射)则释放堆内存、退回 Trivial;表 ≤6 项时直接复用联合池内嵌aulXlate[6]>6EngAllocMemGDITAG_PXLATE)。
  4. 位域偏移预计算CalculateShift:由源/目标掩码算旋转偏移,使运行时仅_rotl + and

三个初始化包装:

函数用途
EXLATEOBJ_vInitXlateFromDCs由源/目标 DC 表面调色板初始化(BitBlt 用)
EXLATEOBJ_vInitXlateFromDCsEx同前,但可指定源背景色(透明色/掩码 blt 用)
EXLATEOBJ_vInitSrcMonoXlate强制源为单色调色板(gppalMono,单色源 blt 用)

EXLATEOBJ_vCleanuppulXlate指向堆内存(≠内嵌aulXlate)则EngFreeMem并复位。


5. DDI 公开函数与导出

函数行为win32k 导出UMPD(gdi32→win32u→umpdstubs)
XLATEOBJ_iXlate转换入口:空指针→原值;否则pfnXlate(pexlo, iColor)分发—(内部+UMPD)NtGdiXLATEOBJ_iXlate([umpdstubs](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c#L718),桩)
XLATEOBJ_cGetPaletteiPal(XO_* 编号)返回源/目标/DC 调色板颜色(pPalOut==NULL时返回项数);校验PAL_INDEXED/PAL_BITFIELDS匹配✓([win32k.spec](file:///d:/reactos/win32ss/win32k.spec#L228))NtGdiXLATEOBJ_cGetPalette(桩)
XLATEOBJ_hGetColorTransform返回 ICM 颜色变换句柄✓(L229)NtGdiXLATEOBJ_hGetColorTransform(桩)
XLATEOBJ_piVector源为索引色时返回转换表指针,否则 NULL✓(L231)

注意:XLATEOBJ_iXlate在 xlateobj.c 中定义前先#undef XLATEOBJ_iXlate(防御早期 winddi.h 曾把它定义成宏);内核态驱动直接调用,用户态 UMPD 经NtGdiXLATEOBJ_iXlate


6. 消费方与调用链(核心活跃证据)

ntgdi/bitblt.c IntGdiBitBlt → EXLATEOBJ_vInitXlateFromDCs → XLATEOBJ_iXlate(每像素) ↓ BLTINFO.XlateSourceToDest DIB 引擎 (dib1bpp~dib32bpp, stretchblt, alphablend) 内联宏: XLATEOBJ_iXlate(ColorTranslation, Source) ← 每像素调用 eng/bitblt.c 画刷颜色 → XLATEOBJ_iXlate(pxloBrush, iSolidColor) 前/背景色 → pxloRGB2Dest ntgdi/freetype.c 文本 → exloRGB2Dst / exloDst2RGB (字形掩码与画刷) ntgdi/fillshap.c 椭圆/洪水填充 → 目标色转换 ntgdi/dcutil.c GetPixel/SetPixel → gpalRGB → 表面调色板 ntgdi/palette.c GetNearestColor → EXLATEOBJ_vInitialize + iXlate ntgdi/dibobj.c DIB 位图/调色板互转 dib/alphablend.c Alpha 混合 → 3 个 exlo 来回转换
/* DIB 引擎内联转换宏(dib.h),所有位深 BitBlt 的像素必经之路 */#defineXLATEOBJ_iXlate(ColorTranslation,Source)\((ColorTranslation)?\XLATEOBJ_pfnXlate(ColorTranslation)((ColorTranslation),(Source)):(Source))

性能设计:转换以函数指针单跳实现(无分支判断);Trivial 情形(最普遍,如 32bpp→32bpp 同格式)退化为直接返回原值,DIB 引擎甚至可走无转换快路径。


7. 与《分析_4》标注对照

标注核对
《_4》第 39 行:xlateobj.c/h =「颜色转换对象」准确。补充:核心活跃模块(非预留层);由 EXLATEOBJ.pfnXlate 函数指针分发 ~25 个专用转换函数,EXLATEOBJ_vInitialize 按调色板类型选择实现

8. 源码索引

文件关键内容
[xlateobj.c](file:///d:/reactos/win32ss/gdi/eng/xlateobj.c)转换函数族、EXLATEOBJ_vInitialize/vInitXlateFromDCs(Ex)/vInitSrcMonoXlate/vCleanup、XLATEOBJ_iXlate/cGetPalette/hGetColorTransform/piVector
[xlateobj.h](file:///d:/reactos/win32ss/gdi/eng/xlateobj.h)EXLATEOBJ 结构(联合池)、PFN_XLATE、初始化声明
[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h)XLATEOBJ 结构、XO_* 标志、ENGAPI 声明
[palette.h](file:///d:/reactos/win32ss/gdi/ntgdi/palette.h)PAL_* 标志、CalculateShift、gpalRGB 等全局
[palette.c](file:///d:/reactos/win32ss/gdi/ntgdi/palette.c)调色板对象、全局调色板初始化
[dib.h](file:///d:/reactos/win32ss/gdi/dib/dib.h)XLATEOBJ_iXlate 内联宏(BLTINFO 中调用)
[bitblt.c](file:///d:/reactos/win32ss/gdi/eng/bitblt.c)画刷/前景背景色转换消费
[ntgdi/bitblt.c](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c)IntGdiBitBlt 初始化 exlo
[umpdstubs.c](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c#L705-L740)NtGdiXLATEOBJ_*(UMPD 桩)

关联模块:

  • 上层调用者:[ntgdi/](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c)(BitBlt/GetPixel/填充/文本)
  • 后端消费:[gdi/dib/](file:///d:/reactos/win32ss/gdi/dib/)(各位深 BitBlt 内联转换)
  • 调色板来源:[ntgdi/palette.c](file:///d:/reactos/win32ss/gdi/ntgdi/palette.c)
  • 兄弟对象:BRUSHOBJ/CLIPOBJ/SURFOBJ(同属 DDI 对象族)

本文档基于 ReactOS 源代码win32ss/gdi/eng/xlateobj.c/h及关联模块分析(2026 年 8 月)