[delphi]​view plain​​​ ​​copy​​​ ​​print​​​​?​


  1. procedure SetColorMatrixF(Data: TImageData; Matrix: TColorMatrix);
  2. var
  3. I, J, Count: Integer;
  4. P: PRGBQuad;
  5. MainValue: Boolean;
  6. v: Integer;

  7. procedure SetPixel;
  8. var
  9. Pixel: array[0..3] of Byte;
  10. I, J: Integer;
  11. ps: PByteArray;
  12. begin
  13. ps := Pointer(P);
  14. // 注意:为使矩阵与ARGB排列顺序一致,以下运算中调整了行列的顺序
  15. for I := 0 to 3 do
  16. begin
  17. if I < 3 then
  18. J := 2 - I
  19. else
  20. J := I;
  21. // 如果只存在主对角线数据,只处理颜色缩放
  22. if MainValue then
  23. Pixel[J] := Round(Matrix[I, I] * ps[J])
  24. // 否则,处理所有颜色变换
  25. else
  26. Pixel[J] := Max(0, Min(255, Round(Matrix[0, I] * ps[2] +
  27. Matrix[1, I] * ps[1] +
  28. Matrix[2, I] * ps[0] +
  29. Matrix[3, I] * ps[3] +
  30. Matrix[4, I] * 255)));
  31. end;
  32. for I := 0 to 3 do
  33. ps[I] := Pixel[I];
  34. end;

  35. begin
  36. // 处理矩阵中大与255的值(取模),并判断主对角线外是否存在数据
  37. MainValue := True;
  38. for I := 0 to 4 do
  39. for J := 0 to 4 do
  40. begin
  41. v := Round(Matrix[I, J]) div 256;
  42. if v > 0 then
  43. Matrix[I, J] := Matrix[I, J] - 256.0 * v;
  44. if (I <> J) and (Matrix[I, J] <> 0) then
  45. MainValue := False;
  46. end;
  47. Count := Data.Width * Data.Height;
  48. P := Data.Scan0;
  49. for I := 1 to Count do
  50. begin
  51. SetPixel;
  52. Inc(P);
  53. end;
  54. end;


因代码已经有了注释,而实现原理、公式已经在《​​GDI+ ColorMatrix的完全揭秘​​》中进行了详尽的介绍,所以本文不再累述。

该过程代码的特点是简单易读,缺点是效率较低,在我的P4 2.8G计算机上,处理一张千万像素的照片,耗时为1000ms左右(不包括GDI+图像格式转换耗时。千万像素的24位格式图像转换为32位格式,耗时就达650ms)。

下面是一个MMX BASM代码的整数ColorMatrix实现过程:

[delphi]​view plain​​​ ​​copy​​​ ​​print​​​​?​


  1. 过程定义:

  2. // 设置图像颜色矩阵。参数:
  3. // Dest输出图,Source原图,Data自身操作图像
  4. // Matrix颜色矩阵
  5. procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix); overload;
  6. {$IF RTLVersion >= 17.00}inline;{$IFEND}
  7. procedure ImageSetColorMatrix(var Dest: TImageData;
  8. const Source: TImageData; Matrix: TColorMatrix); overload;

  9. 实现代码:

  10. type
  11. PARGBQuadW = ^TARGBQuadW;
  12. TARGBQuadW = packed record
  13. wBlue: Word;
  14. wGreen: Word;
  15. wRed: Word;
  16. wAlpha: Word;
  17. end;

  18. procedure ImageSetColorMatrix(var Dest: TImageData;
  19. const Source: TImageData; Matrix: TColorMatrix);
  20. asm
  21. push esi
  22. push edi
  23. push ebx
  24. mov ebx, eax
  25. mov edi, ecx // edi = matrix
  26. mov esi, 4 // for (i = 4; i >= 0; i --)
  27. fldz // {
  28. @@iLoop:
  29. mov ecx, 4 // for (j = 4; j >= 0; j --)
  30. @@jLoop: // {
  31. cmp ecx, esi
  32. je @@1
  33. mov eax, esi
  34. imul eax, 5
  35. add eax, ecx
  36. fcom dword ptr [edi+eax*4]
  37. fstsw ax
  38. sahf
  39. je @@1
  40. fstp st(0) // if (i != j && matrix[i, j] != 0)
  41. jmp @@TransformAll // goto TransformAll
  42. @@1:
  43. dec ecx
  44. jns @@jLoop // }
  45. dec esi
  46. jns @@iLoop // }
  47. fstp st(0)
  48. fwait

  49. // 处理颜色缩放(主对角线的数据)

  50. sub esp, 8+2
  51. mov dword ptr [esp], 256
  52. fild dword ptr [esp]
  53. fld st(0)
  54. fmul dword ptr [edi+(2*5+2)*4]
  55. fistp dword ptr [esp] // matrixI[0, 0] = matrix[2, 2] * 256
  56. fld st(0)
  57. fmul dword ptr [edi+(1*5+1)*4]
  58. fistp dword ptr [esp+2] // matrixI[0, 1] = matrix[1, 1] * 256
  59. fld st(0)
  60. fmul dword ptr [edi+(0*5+0)*4]
  61. fistp dword ptr [esp+4] // matrixI[0, 2] = matrix[0, 0] * 256
  62. fmul dword ptr [edi+(3*5+3)*4]
  63. fistp dword ptr [esp+6] // matrixI[0, 3] = matrix[3, 3] * 256
  64. mov eax, ebx
  65. call _SetCopyRegs
  66. pxor mm7, mm7
  67. movq mm1, [esp] // mm1 = m44 m11 m22 m33
  68. @@yLoop:
  69. push ecx
  70. @@xLoop:
  71. movd mm0, [esi]
  72. punpcklbw mm0, mm7 // mm0 = 00 A 00 R 00 G 00 B
  73. pmullw mm0, mm1 // mm0 = A*m44 R*m11 G*m22 B*m33
  74. psrlw mm0, 8 // mm0 = A*m44/256 R*m11/256 G*m22/256 B*m33/256
  75. packuswb mm0, mm0 // mm0 = 00 00 00 00 An Rn Gn Bn
  76. movd [edi], mm0
  77. add esi, 4
  78. add edi, 4
  79. loop @@xLoop
  80. add esi, eax
  81. add edi, ebx
  82. pop ecx
  83. dec edx
  84. jnz @@yLoop
  85. add esp, 8+2
  86. jmp @@end

  87. // 处理全部颜色变换

  88. @@TransformAll:
  89. sub esp, 5*8+2 // 浮点颜色矩阵行列交换转换为128倍整数
  90. mov dword ptr [esp], 128
  91. fild dword ptr [esp]
  92. mov esi, esp // esi = matrixI
  93. mov eax, edi
  94. mov ecx, 4 // for (i = 0; i < 4; i ++)
  95. @@cvtLoop: // {
  96. fld st(0)
  97. fmul dword ptr [edi]
  98. fistp dword ptr [esi] // matrixI[i, 0] = matrix[0, i] * 128
  99. fld st(0)
  100. fmul dword ptr [edi+1*5*4]
  101. fistp dword ptr [esi+2] // matrixI[i, 1] = matrix[1, i] * 128
  102. fld st(0)
  103. fmul dword ptr [edi+2*5*4]
  104. fistp dword ptr [esi+4] // matrixI[i, 2] = matrix[2, i] * 128
  105. fld st(0)
  106. fmul dword ptr [edi+3*5*4]
  107. fistp dword ptr [esi+6] // matrixI[i, 3] = matrix[3, i] * 128
  108. add esi, 8
  109. add edi, 4
  110. loop @@cvtLoop // }
  111. fstp st(0)
  112. add eax, 4*5*4 // 浮点数平移量转换为255倍整数
  113. mov dword ptr [esi], 255
  114. fild dword ptr [esi]
  115. mov ecx, 4 // for (j = 0; j < 4; j ++)
  116. @@tLoop:
  117. fld st(0)
  118. fmul dword ptr [eax]
  119. fistp dword ptr [esi] // matrixI[4, j] = matrix[4, j] * 255
  120. add esi, 2
  121. add eax, 4
  122. loop @@tLoop
  123. fstp st(0)
  124. mov esi, esp // 红蓝(0、2列)交换
  125. mov ecx, 5 // for (i = 0; i < 5; i ++)
  126. @@swapLoop: // matrixI[i, 0] <--> matrixI[i, 2]
  127. mov ax, [esi].TARGBQuadW.wBlue
  128. xchg ax, [esi].TARGBQuadW.wRed
  129. mov [esi].TARGBQuadW.wBlue, ax
  130. add esi, 8
  131. loop @@swapLoop
  132. mov eax, ebx
  133. call _SetCopyRegs
  134. pxor mm7, mm7
  135. pcmpeqb mm4, mm4 // mm4 = FF FF FF FF FF FF FF FF
  136. psrlw mm4, 15 // mm4 = 00 01 00 01 00 01 00 01
  137. @@yLoopA:
  138. push ecx
  139. @@xLoopA:
  140. movd mm0, [esi]
  141. punpcklbw mm0, mm7 // mm0 = 00 A 00 R 00 G 00 B
  142. movq mm1, mm0
  143. movq mm2, mm0
  144. movq mm3, mm0
  145. // esp+4: ecx push stack
  146. pmaddwd mm0, [esp+16+4] // mm0 = A*m43+R*m13 G*m23+B*m33 蓝色行
  147. pmaddwd mm1, [esp+8+4] // mm1 = A*m42+R*m12 G*m22+B*m32 绿色行
  148. pmaddwd mm2, [esp+4] // mm2 = A*m41+R*m11 G*m21+B*m31 红色行
  149. pmaddwd mm3, [esp+24+4] // mm3 = A*m44+R*m14 G*m24+B*m34 Alpha行
  150. psrad mm0, 7 // mm0 = A*m43+R*m13/128 G*m23+B*m33/128
  151. psrad mm1, 7 // mm1 = A*m42+R*m12/128 G*m22+B*m32/128
  152. psrad mm2, 7 // mm2 = A*m41+R*m11/128 G*m21+B*m31/128
  153. psrad mm3, 7 // mm3 = A*m44+R*m14/128 G*m24+B*m34/128
  154. packssdw mm0, mm1 // mm0 = Ag+Rg Gg+Bg Ab+Rb Gb+Bb
  155. packssdw mm2, mm3 // mm2 = Aa+Ra Ga+Ba Ar+Rr Gr+Br
  156. pmaddwd mm0, mm4 // mm0 = Ag+Rg+Gg+Bg=Gn Ab+Rb+Gb+Bb=Bn
  157. pmaddwd mm2, mm4 // mm2 = Aa+Ra+Ga+Ba=An Ar+Rr+Gr+Br=Rn
  158. packssdw mm0, mm2 // mm0 = 00 An 00 Rn 00 Gn 00 Bn
  159. paddw mm0, [esp+32+4] // mm0 = An+At Rn+Rt Gn+Gt Bn+Bt 平移行
  160. packuswb mm0, mm0 // mm0 = 00 00 00 00 An Rn Gn Bn
  161. movd [edi], mm0
  162. add esi, 4
  163. add edi, 4
  164. loop @@xLoopA
  165. add esi, eax
  166. add edi, ebx
  167. pop ecx
  168. dec edx
  169. jnz @@yLoopA
  170. add esp, 5*8+2
  171. @@end:
  172. emms
  173. @@Exit:
  174. pop ebx
  175. pop edi
  176. pop esi
  177. end;

  178. procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix);
  179. begin
  180. ImageSetColorMatrix(Data, Data, Matrix);
  181. end;


该过程中作了更详细的注释,其特点是处理速度较快。在我的机器上,不包括图像格式转换耗时,处理千万像素图片主对角线数据耗时不到50ms,而处理全部变换耗时350-400ms。

 

[delphi]​view plain​​​ ​​copy​​​ ​​print​​​​?​


  1. unit main2;

  2. interface

  3. uses
  4. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  5. Dialogs, StdCtrls, Buttons, Grids, ExtCtrls, Gdiplus, ImageData;

  6. type
  7. TForm1 = class(TForm)
  8. Label1: TLabel;
  9. PaintBox1: TPaintBox;
  10. SpeedButton1: TSpeedButton;
  11. SpeedButton2: TSpeedButton;
  12. SpeedButton3: TSpeedButton;
  13. SpeedButton4: TSpeedButton;
  14. StringGrid1: TStringGrid;
  15. BitBtn1: TBitBtn;
  16. BitBtn3: TBitBtn;
  17. BitBtn2: TBitBtn;
  18. procedure FormCreate(Sender: TObject);
  19. procedure FormDestroy(Sender: TObject);
  20. procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  21. Rect: TRect; State: TGridDrawState);
  22. procedure StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
  23. var Value: string);
  24. procedure PaintBox1Paint(Sender: TObject);
  25. procedure BitBtn1Click(Sender: TObject);
  26. procedure BitBtn2Click(Sender: TObject);
  27. procedure BitBtn3Click(Sender: TObject);
  28. procedure SpeedButton2Click(Sender: TObject);
  29. procedure SpeedButton3Click(Sender: TObject);
  30. procedure SpeedButton1Click(Sender: TObject);
  31. procedure SpeedButton4Click(Sender: TObject);
  32. procedure StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
  33. const Value: string);
  34. private
  35. { Private declarations }
  36. Source: TGpBitmap;
  37. Dest: TGpBitmap;
  38. SrcData: TImageData;
  39. DstData: TImageData;
  40. Matrix: TColorMatrix;

  41. function CheckFloatStr(Str: string): Double;
  42. procedure InitColorMatrix;
  43. public
  44. { Public declarations }
  45. end;

  46. var
  47. Form1: TForm1;

  48. implementation

  49. {$R *.dfm}

  50. procedure TForm1.BitBtn1Click(Sender: TObject);
  51. begin
  52. ImageSetColorMatrix(DstData, SrcData, Matrix);
  53. PaintBox1.Invalidate;
  54. with StringGrid1 do
  55. begin
  56. Cells[Col, Row] := FloatToStr(Matrix[Row, Col]);
  57. Invalidate;
  58. SetFocus;
  59. end;
  60. end;

  61. procedure TForm1.BitBtn2Click(Sender: TObject);
  62. begin
  63. InitColorMatrix;
  64. BitBtn1.Click;
  65. end;

  66. procedure TForm1.BitBtn3Click(Sender: TObject);
  67. begin
  68. Close;
  69. end;

  70. function TForm1.CheckFloatStr(Str: string): Double;
  71. var
  72. i, len: Integer;
  73. dec, neg: Boolean;
  74. s: string;
  75. begin
  76. Result := 0;
  77. len := Length(Str);
  78. if len = 0 then Exit;
  79. dec := False;
  80. neg := False;
  81. i := 1;
  82. s := '';
  83. if (Str[i] = '-') or (Str[i] = '+') then
  84. begin
  85. if Str[i] = '-' then neg := True;
  86. Inc(i);
  87. end;
  88. while (i <= len) do
  89. begin
  90. if Str[i] = '.' then
  91. begin
  92. if dec then Break;
  93. dec := True;
  94. end
  95. else if (Str[i] < '0') or (Str[i] > '9') then Break;
  96. s := s + Str[i];
  97. Inc(i);
  98. end;
  99. if Length(s) > 0 then
  100. begin
  101. if neg then s := '-' + s;
  102. Result := StrToFloat(s);
  103. end;
  104. end;

  105. procedure TForm1.FormCreate(Sender: TObject);
  106. var
  107. Bmp: TGpBitmap;
  108. Data: TBitmapData;
  109. R: TGpRect;
  110. begin
  111. // 从文件装入图像到Bmp
  112. Bmp := TGpBitmap.Create('..\..\media\100_0349.jpg');
  113. R := GpRect(0, 0, Bmp.Width, Bmp.Height);
  114. // 分别建立新的源和目标图像数据到SrcData和DstData
  115. SrcData := NewImageData(R.Width, R.Height);
  116. DstData := NewImageData(R.Width, R.Height);
  117. // 将Bmp图像数据分别锁定拷贝到SrcData和DstData
  118. Data := TBitmapData(SrcData);
  119. Data := Bmp.LockBits(R, [imRead, imWrite, imUserInputBuf], pf32bppARGB);
  120. Bmp.UnlockBits(Data);
  121. Data.Scan0 := DstData.Scan0;
  122. Data := Bmp.LockBits(R, [imRead, imWrite, imUserInputBuf], pf32bppARGB);
  123. Bmp.UnlockBits(Data);
  124. Bmp.Free;
  125. // 分别用图像数据SrcData和DstData建立位图Source和Dest
  126. // 注:图像数据结构用于数据处理,位图用于显示,这样即可绑定数据结构和位图,
  127. // 又能避免每次处理图像数据时的锁定和解锁操作
  128. Source := TGpBitmap.Create(SrcData.Width, SrcData.Height, SrcData.Stride,
  129. pf32bppARGB, SrcData.Scan0);
  130. Dest := TGpBitmap.Create(DstData.Width, DstData.Height, DstData.Stride,
  131. pf32bppARGB, DstData.Scan0);

  132. InitColorMatrix;
  133. end;

  134. procedure TForm1.FormDestroy(Sender: TObject);
  135. begin
  136. Dest.Free;
  137. Source.Free;
  138. FreeImageData(DstData);
  139. FreeImageData(SrcData);
  140. end;

  141. procedure TForm1.InitColorMatrix;
  142. var
  143. i, j: Integer;
  144. begin
  145. for i := 0 to 4 do
  146. begin
  147. for j := 0 to 4 do
  148. if i = j then Matrix[i, j] := 1 else Matrix[i, j] := 0;
  149. end;
  150. end;

  151. procedure TForm1.PaintBox1Paint(Sender: TObject);
  152. var
  153. g: TGpGraphics;
  154. begin
  155. g := TGpGraphics.Create(PaintBox1.Canvas.Handle);
  156. try
  157. g.DrawImage(Source, 10, 10);
  158. g.DrawImage(Dest, SrcData.Width + 20, 10);
  159. finally
  160. g.Free;
  161. end;
  162. end;

  163. procedure TForm1.SpeedButton1Click(Sender: TObject);
  164. var
  165. i: Integer;
  166. begin
  167. InitColorMatrix;
  168. for i := 0 to 2 do
  169. begin
  170. Matrix[0, i] := 0.30;
  171. Matrix[1, i] := 0.59;
  172. Matrix[2, i] := 0.11;
  173. end;
  174. BitBtn1.Click;
  175. end;

  176. procedure TForm1.SpeedButton2Click(Sender: TObject);
  177. var
  178. i: Integer;
  179. begin
  180. InitColorMatrix;
  181. for i := 0 to 2 do
  182. Matrix[4, i] := 0.10;
  183. BitBtn1.Click;
  184. end;

  185. procedure TForm1.SpeedButton3Click(Sender: TObject);
  186. begin
  187. InitColorMatrix;
  188. Matrix[0, 0] := -1;
  189. Matrix[1, 1] := -1;
  190. Matrix[2, 2] := -1;
  191. BitBtn1.Click;
  192. end;

  193. procedure TForm1.SpeedButton4Click(Sender: TObject);
  194. begin
  195. InitColorMatrix;
  196. Matrix[3, 3] := 0.5;
  197. BitBtn1.Click;
  198. end;

  199. procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  200. Rect: TRect; State: TGridDrawState);
  201. var
  202. Text: string;
  203. begin
  204. Text := Format('%.2f', [Matrix[ARow, ACol]]);
  205. StringGrid1.Canvas.FillRect(Rect);
  206. StringGrid1.Canvas.Pen.Color := clBtnShadow;
  207. StringGrid1.Canvas.Rectangle(Rect);
  208. InflateRect(Rect, -2, -2);
  209. DrawText(StringGrid1.Canvas.Handle, PChar(text), Length(text), &Rect, DT_RIGHT);
  210. end;

  211. procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
  212. var Value: string);
  213. begin
  214. Value := Format('%.2f', [Matrix[ARow, ACol]]);
  215. end;

  216. procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
  217. const Value: string);
  218. begin
  219. Matrix[ARow, ACol] := CheckFloatStr(Value);
  220. end;

  221. end.

 ​


  1. procedure ImageSetColorMatrix(var Dest: TImageData;
  2. const Source: TImageData; Matrix: TColorMatrix); overload;
  3. asm
  4. push ebp
  5. push esi
  6. push edi
  7. push ebx
  8. // ebp为16字节对齐的128位栈内存地址
  9. sub esp, 32
  10. mov ebp, esp
  11. add ebp, 16
  12. and ebp, -16

  13. // 检查颜色矩阵除主对角线和虚拟列外的数据项,如不等于零,执行全部颜色变换
  14. mov edi, ecx
  15. mov esi, 4 // for (i = 4; i >= 0; i --)
  16. @@iLoop: // {
  17. mov ecx, 3 // for (j = 3; j >= 0; j --)
  18. @@jLoop: // {
  19. cmp ecx, esi // if (i == j) continue
  20. je @@1
  21. lea ebx, [esi+esi*4]
  22. add ebx, ecx // index = i * 5 + j
  23. cmp dword ptr[edi+ebx*4], 0
  24. jne @@Transform // if (Matrix[Index]) goto @@Transform
  25. @@1:
  26. dec ecx
  27. jns @@jLoop // }
  28. dec esi
  29. jns @@iLoop // }

  30. // 处理颜色缩放
  31. mov ebx, [edi+(2*5+2)*4]
  32. mov ecx, [edi+(1*5+1)*4]
  33. mov [ebp], ebx
  34. mov [ebp+4], ecx
  35. mov ebx, [edi+(0*5+0)*4]
  36. mov ecx, [edi+(3*5+3)*4]
  37. mov [ebp+8], ebx
  38. mov [ebp+12], ecx
  39. movaps xmm1, [ebp] // xmm1 = m44 m11 m22 m33
  40. pxor xmm7, xmm7
  41. call _SetCopyRegs
  42. @@yLoop_Scale:
  43. push ecx
  44. @@xLoop_Scale:
  45. movd xmm0, [esi]
  46. punpcklbw xmm0, xmm7
  47. punpcklwd xmm0, xmm7
  48. cvtdq2ps xmm0, xmm0
  49. mulps xmm0, xmm1 // xmm0 = [A R G B] * [m44 m11 m22 m33]
  50. cvtps2dq xmm0, xmm0
  51. packssdw xmm0, xmm7
  52. packuswb xmm0, xmm7
  53. movd [edi], xmm0
  54. add esi, 4
  55. add edi, 4
  56. loop @@xLoop_Scale
  57. pop ecx
  58. add esi, eax
  59. add edi, ebx
  60. dec edx
  61. jnz @@yLoop_Scale
  62. jmp @@Exit

  63. // 处理全部的颜色变换
  64. @@Transform:
  65. // 颜色矩阵按行分别装入sse寄存器,不包括虚拟位列
  66. movups xmm1, [edi+0*5*4]
  67. movups xmm2, [edi+1*5*4]
  68. movups xmm3, [edi+2*5*4]
  69. movups xmm4, [edi+3*5*4]
  70. movups xmm5, [edi+4*5*4]
  71. // 平移行乘上255
  72. mov ebx, 255
  73. cvtsi2ss xmm6, ebx
  74. pshufd xmm6, xmm6, 0
  75. mulps xmm5, xmm6
  76. // 交换每行的红与蓝位置
  77. pshufd xmm1, xmm1, 11000110b
  78. pshufd xmm2, xmm2, 11000110b
  79. pshufd xmm3, xmm3, 11000110b
  80. pshufd xmm4, xmm4, 11000110b
  81. pshufd xmm5, xmm5, 11000110b
  82. // 平移行保存在栈中
  83. movaps [ebp], xmm5
  84. pxor xmm7, xmm7
  85. call _SetCopyRegs
  86. @@yLoop:
  87. push ecx
  88. @@xLoop:
  89. movd xmm0, [esi]
  90. punpcklbw xmm0, xmm7
  91. punpcklwd xmm0, xmm7
  92. cvtdq2ps xmm0, xmm0
  93. pshufd xmm5, xmm0, 0
  94. pshufd xmm6, xmm0, 01010101b
  95. mulps xmm5, xmm3 // vb = blue * m3
  96. mulps xmm6, xmm2 // vg = green * m2
  97. addps xmm5, [ebp] // vb += m5
  98. addps xmm5, xmm6 // vb += vg
  99. pshufd xmm6, xmm0, 10101010b
  100. pshufd xmm0, xmm0, 11111111b
  101. mulps xmm6, xmm1 // vr = red * m1
  102. mulps xmm0, xmm4 // va = alpha * m4
  103. addps xmm0, xmm6 // v = va + vr
  104. addps xmm0, xmm5 // v += vb
  105. cvtps2dq xmm0, xmm0
  106. packssdw xmm0, xmm7
  107. packuswb xmm0, xmm7
  108. movd [edi], xmm0
  109. add esi, 4
  110. add edi, 4
  111. loop @@xLoop
  112. pop ecx
  113. add esi, eax
  114. add edi, ebx
  115. dec edx
  116. jnz @@yLoop
  117. @@Exit:
  118. add esp, 32
  119. pop ebx
  120. pop edi
  121. pop esi
  122. pop ebp
  123. end;

  124. procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix); overload;
  125. begin
  126. ImageSetColorMatrix(Data, Data, Matrix);
  127. end;
  128. //---------------------------------------------------------------------------