GDI+ ColorMatrix的完全揭秘与代码实现(下)
2008-09-09 19:25:20 来源:WEB开发网因代码已经有了注释,而实现原理、公式已经在《GDI+ ColorMatrix的完全揭秘与代码实现(上)》中进行了详尽的介绍,所以本文不再累述。
该过程代码的特点是简单易读,缺点是效率较低,在我的P4 2.8G计算机上,处理一张千万像素的照片,耗时为1000ms左右(不包括GDI+图像格式转换耗时。千万像素的24位格式图像转换为32位格式,耗时就达650ms)。
下面是一个以汇编为核心代码的整数ColorMatrix实现代码:
procedure SetColorMatrix(Data: TImageData; Matrix: TColorMatrix);
var
I, J: Integer;
MatrixI: array[0..4, 0..4] of Word;
v: Integer;
MainValue: Boolean;
procedure SetMainLineData;
asm
push edi
lea edi, Data
mov ecx, [edi + 4] // ecx = Data.Width * Data.Height
imul ecx, [edi]
mov edi, [edi + 16] // edi = Data.Scan0
cld
pxor mm7, mm7
movq mm1, qword ptr MatrixI // 颜色矩阵中argb主对角线值
@Loop1: // 以下按像素个数循环操作:
movd mm0, dword ptr [edi] // 装入像素argb
punpcklbw mm0, mm7 // argb由字节扩展到字
pmullw mm0, mm1 // argb分别乘主角线上对应的值
psrlw mm0, 8 // argb分别除以256
packuswb mm0, mm0 // argb由字压缩为字节
movd eax, mm0
stosd // *(int*)edi ++ = argb
loop @Loop1
pop edi
emms
end;
procedure SetImageData;
asm
push esi
push edi
push ebx
lea esi, MatrixI // 分别计算argb平移量并压入栈
add esi, 8
mov ecx, 4
@Loop0:
movzx eax, word ptr [esi]
imul eax, 255
push eax
add esi, 10
loop @Loop0
lea edi, Data
mov ebx, [edi + 4] // 像素总数 = Data.Width * Data.Height
imul ebx, [edi]
mov edi, [edi + 16] // 图像扫描线首地址 = Data.Scan0
pxor mm7, mm7
cld
@Loop1: // 以下按像素个数循环操作:
movd mm3, dword ptr [edi] // 装入像素argb
punpcklbw mm3, mm7 // argb由字节扩展到字
lea esi, MatrixI // 载入矩阵
mov ecx, 4 // 以下按矩阵行分别计算argb
@Loop2: // 计算顺序为b,g,r,a:
movq mm0, qword ptr [esi] // 装入argb对应矩阵行
pmaddwd mm0, mm3 // 计算4组可能的线性变换
movd eax, mm0 // 将2个32位计算结果分别取出
punpckhdq mm0, mm0
movd edx, mm0
add eax, edx // 2个32位结果相加
add eax, [esp + ecx * 4 - 4]// 再加上平移量
sar eax, 8 // 还原因矩阵整数化时扩大的256倍
jns @@1
xor eax, eax
jmp @@2
@@1:
cmp eax, 255
jle @@2
mov eax, 255
@@2:
stosb // 设置argb为计算结果
add esi, 10
loop @Loop2
dec ebx
jnz @Loop1
add esp, 16
pop ebx
pop edi
pop esi
emms
end;
begin
MainValue := True;
// 处理矩阵中大与255的值(取模),并判断主对角线外是否存在数据
for I := 0 to 4 do
for J := 0 to 4 do
begin
v := Round(Matrix[I, J]) div 256;
if v > 0 then
Matrix[I, J] := Matrix[I, J] - 256.0 * v;
if (I <> J) and (Matrix[I, J] <> 0) then
MainValue := False;
end;
// 如果只存在主对角线数据,转换主对角线浮点数为整数,只处理颜色缩放
if MainValue then
begin
// 扩大256倍,并交换0行和2行,与argb顺序对应
MatrixI[0, 0] := Round(Matrix[2, 2] * 256);
MatrixI[0, 1] := Round(Matrix[1, 1] * 256);
MatrixI[0, 2] := Round(Matrix[0, 0] * 256);
MatrixI[0, 3] := Round(Matrix[3, 3] * 256);
SetMainLineData;
end
// 否则,转换整个浮点矩阵为整数矩阵,处理所有颜色变换
else
begin // 扩大256倍,并将矩阵列转换为矩阵行
for I := 0 to 4 do
for J := 0 to 4 do
MatrixI[I, J] := Round(Matrix[J, I] * 256);
for I := 0 to 4 do // 交换0行和2行,与argb顺序对应
begin
v := MatrixI[I, 0];
MatrixI[I, 0] := MatrixI[I, 2];
MatrixI[I, 2] := v;
end;
for I := 0 to 4 do // 交换0列和2列,与argb顺序对应
begin
v := MatrixI[0, I];
MatrixI[0, I] := MatrixI[2, I];
MatrixI[2, I] := v;
end;
SetImageData;
end;
end;
Tags:GDI ColorMatrix 完全
编辑录入:爽爽 [复制链接] [打 印]更多精彩
赞助商链接