Delphi图像处理 -- 色相/饱和度调整

本文是基于《GDI+在Delphi程序的应用 – Photoshop色相/饱和度/明度功能》一文的BASM实用性过程,有关实现原理可参见《GDI+ 在Delphi程序的应用 -- 图像饱和度调整》和《GDI+ 在Delphi程序的应用 -- 仿Photoshop的明度调整》,纯PAS实现代码和测试例子代码见《GDI+在Delphi程序的应用 – Photoshop色相/饱和度/明度功能》。

过程定义: // 图像色相/饱和度/明度调整。参数: // Dest输出图,Source原图,Data自身操作图像 // hValue色相值,sValue饱和度,bValur明度 // Callback回调函数,返回True终止操作,CallbackData回调函数参数地址 procedure ImageHSBAdjustment(var Data: TImageData; hValue, sValue, bValue: Integer); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} procedure ImageHSBAdjustment(var Dest: TImageData; const Source: TImageData; hValue, sValue, bValue: Integer); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} // 无效参数或者被回调函数终止操作返回False。 function ImageHSBAdjustment(var Dest: TImageData; const Source: TImageData; hValue, sValue, bValue: Integer; Callback: TImageAbort; CallbackData: Pointer): Boolean; overload; 代码实现: const _Bright_Frist = 1; _Bright_Last = 2; _Saturat = 4; _Hue = 8; procedure HSBAdjustment(Hv, Sv, Bv, flag: Integer); pascal; var argbW: TARGBQuadW; delta, maxRgb: Integer; S, Stmp: Integer; height, dstOffset, srcOffset: Integer; asm mov height, edx mov dstOffset, ebx mov srcOffset, eax pxor mm7, mm7 // mm7 = 00 00 00 00 00 00 00 00 movd mm5, Bv punpcklwd mm5, mm5 punpcklwd mm5, mm5 // mm5 = 00 Bv 00 Bv 00 Bv 00 Bv pcmpeqb mm6, mm6 psrlw mm6, 8 // mm6 = 00 FF 00 FF 00 FF 00 FF mov eax, Sv sar eax, 1 mov Stmp, eax jle @@0 mov ebx, 128 // if (Sv > 0) sub ebx, eax // mm4 = 16384 / (128 - Sv) - 128 shl ebx, 3 add ebx, PSTable movq mm4, qword ptr [ebx] jmp @@yLoop @@0: movd mm4, eax punpcklwd mm4, mm4 // else mm4 = sValue punpcklwd mm4, mm4 // @@yLoop: push ecx @@xLoop: push ecx movd mm0, [esi] // mm0 = rgb punpcklbw mm0, mm7 test flag, _Bright_Frist jz @@2 movq mm1, mm0 // if (Bv != 0 && Sv > 0) cmp Bv, 0 // { jl @@1 // if (Bv >= 0) pxor mm0, mm6 // rgb = rgb + (255 - eax) * Bv / 128 @@1: pmullw mm0, mm5 // else psraw mm0, 7 // rgb = rgb + eax * Bv / 128 paddsw mm0, mm1 // } packuswb mm0, mm7 punpcklbw mm0, mm7 @@2: test flag, _Saturat or _Hue jz @@30 // if (Hv == 0 && Sv == 0) goto @@30 movq qword ptr argbW, mm0 movzx ecx, argbW.wBlue movzx edx, argbW.wGreen movzx eax, argbW.wRed cmp ecx, edx // ecx = rgbMax jge @@3 // edx = rgbMin xchg ecx, edx @@3: cmp ecx, eax jge @@4 xchg ecx, eax @@4: cmp eax, edx jge @@5 xchg eax, edx @@5: mov eax, ecx // delta = rgbMax - rgbmin sub eax, edx jz @@30 // if (delta == 0) continue mov delta, eax mov maxRgb, ecx add ecx, edx // ecx = rgbMax + rgbMin mov ebx, ecx // ebx = rgbMax + rgbMin shr ecx, 1 // ecx = L = (rgbMax + rgbMin) / 2 cmp ecx, 128 jl @@7 neg ebx add ebx, 510 // if (L >= 128) ebx = 510 - ebx @@7: imul eax, 255 cdq idiv ebx mov S, eax // S = delta * 255 / ebx test flag, _Hue jz @@20 // if (Hv == 0) goto @@20 push ecx // save L mov ebx, Hv // add = Hv mov edx, maxRgb cmp dx, argbW.wRed jne @@8 mov ax, argbW.wGreen sub ax, argbW.wBlue // if (R == rgbMax) eax = G - B jmp @@10 @@8: cmp dx, argbW.wGreen jne @@9 mov ax, argbW.wBlue sub ax, argbW.wRed add ebx, 120 // if (G == rgbMax) eax = B - R; add += 120 jmp @@10 @@9: mov ax, argbW.wRed sub ax, argbW.wGreen add ebx, 240 // if (B == rgbMax) eax = R - G; add += 240 @@10: movsx eax, ax imul eax, 60 // H = eax * 60 / delta + add cdq idiv delta add eax, ebx jns @@11 add eax, 360 // if (H < 0) H += 360 jmp @@12 @@11: cmp eax, 360 jb @@12 sub eax, 360 @@12: mov ebx, 60 cdq // eax = newH / 60 (hue index) div ebx // edx = newH % 60 (hue extra) test eax, 1 jz @@13 neg edx // if (eax & 1) edx = 60 - edx add edx, ebx @@13: push eax // Save hue index mov eax, edx imul eax, 255 add eax, 30 cdq idiv ebx mov ebx, eax // extra = edx * 255 / 60 mov edx, S xor edx, 255 sub eax, 128 imul eax, edx sar eax, 8 sub ebx, eax // rgbCenter = extra - mov eax, ebx // (rxtra - 128) * (255 - S) / 255 sub ecx, 128 // L -= 128 js @@14 // eax = L < 0? rgbCenter : 255 - rgbCenter xor eax, 255 @@14: imul eax, ecx js @@15 add eax, 64 @@15: sar eax, 7 add ebx, eax // ebx = rgbCenter + eax * L / 128 mov eax, maxRgb // eax = maxRgb mov ecx, eax // ecx = minRgb = maxRgb - delta sub ecx, delta pop edx jmp @@setHue[edx*4].Pointer // SetHue(index, eax, ebx, ecx) @@setHue: dd offset @@H60 dd offset @@H120 dd offset @@H180 dd offset @@H240 dd offset @@H300 dd offset @@H360 @@H60: // 0 - 59 mov argbW.wRed, ax mov argbW.wGreen, bx mov argbW.wBlue, cx jmp @@16 @@H120: // 60 - 119 mov argbW.wRed, bx mov argbW.wGreen, ax mov argbW.wBlue, cx jmp @@16 @@H180: // 120 - 179 mov argbW.wRed, cx mov argbW.wGreen, ax mov argbW.wBlue, bx jmp @@16 @@H240: // 180 - 239 mov argbW.wRed, cx mov argbW.wGreen, bx mov argbW.wBlue, ax jmp @@16 @@H300: // 240 - 299 mov argbW.wRed, bx mov argbW.wGreen, cx mov argbW.wBlue, ax jmp @@16 @@H360: // 300 - 359 mov argbW.wRed, ax mov argbW.wGreen, cx mov argbW.wBlue, bx @@16: pop ecx // reset L movq mm0, qword ptr argbW // mm0 = argbW @@20: cmp Stmp, 0 // if (Sv == 0) goto @@30 je @@30 jl @@21 mov eax, Sv add al, byte ptr S jnc @@21 // if (Sv > 0 && Sv + S >= 255) mov ebx, S // { inc ebx // ebx = ((S + 1) / 2) * 8 + PSTable shr ebx, 1 // rgb = rgb + (rgb - L) * *ebx / 128 shl ebx, 3 // } add ebx, PSTable psubsw mm0, qword ptr ArgbTable[ecx*8] pmullw mm0, qword ptr [ebx] jmp @@22 @@21: psubsw mm0, qword ptr ArgbTable[ecx*8] pmullw mm0, mm4 // else rgb = rgb + (rgb - L) * mm4 / 128 @@22: psraw mm0, 7 paddsw mm0, qword ptr argbW @@30: test flag, _Bright_Last jz @@next movq mm1, mm0 // if (Bv != 0 && Sv <= 0) cmp Bv, 0 // { jl @@32 // if (Bv >= 0) pxor mm0, mm6 // rgb = rgb + (255 - eax) * Bv / 128 @@32: pmullw mm0, mm5 // else psraw mm0, 7 // rgb = rgb + eax * Bv / 128 paddsw mm0, mm1 // } @@next: packuswb mm0, mm7 mov al, [esi+3] movd [edi], mm0 mov [edi+3], al add edi, 4 add esi, 4 pop ecx dec ecx jnz @@xLoop add edi, dstOffset add esi, srcOffset pop ecx dec height jnz @@yLoop emms end; function ImageHSBAdjustment(var Dest: TImageData; const Source: TImageData; hValue, sValue, bValue: Integer; Callback: TImageAbort; CallbackData: Pointer): Boolean; var flag: Integer; begin Result := False; if ImageEmpty(Dest) or ImageEmpty(Source) then Exit; if hValue > 180 then hValue := 180 else if hValue < -180 then hValue := -180; if sValue > 255 then sValue := 255 else if sValue < -255 then sValue := -255; if bValue > 255 then bValue := 255 else if bValue < -255 then bValue := -255; flag := 0; if hValue <> 0 then flag := flag or _Hue; if sValue <> 0 then flag := flag or _Saturat; bValue := bValue div 2; if bValue <> 0 then begin if sValue > 0 then flag := flag or _Bright_Frist else flag := flag or _Bright_Last; end; if Assigned(Callback) then Result := ExecuteAbort(Dest, Source, @HSBAdjustment, [hValue, sValue, bValue, flag], Callback, CallbackData) else Result := ExecuteProc(Dest, Source, @HSBAdjustment, [hValue, sValue, bValue, flag]); end; procedure ImageHSBAdjustment(var Dest: TImageData; const Source: TImageData; hValue, sValue, bValue: Integer); begin ImageHSBAdjustment(Dest, Source, hValue, sValue, bValue, nil, nil); end; procedure ImageHSBAdjustment(var Data: TImageData; hValue, sValue, bValue: Integer); begin ImageHSBAdjustment(Data, Data, hValue, sValue, bValue, nil, nil); end;

文章中所用数据类型及一些过程见《Delphi图像处理 -- 数据类型及内部过程》和《Delphi图像处理 -- 图像像素结构与图像数据转换》。

尽管我十分努力,但水平有限,错误在所难免,欢迎指正和指导。邮箱地址:

maozefa@hotmail.com

本文代码于2010.5.20重新修订过。增加了拷贝形式的调整过程和响应回调函数的调整过程。代码中的ExecuteAbort过程和ExecuteProc过程见《Delphi图像处理 -- 图像像素结构与图像数据转换》。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值