GDI+ 在Delphi程序的应用 -- 调整图像亮度

GDI+ 在Delphi程序的应用 -- 调整图像亮度
调整图像的亮度可以有很多方法,最常用的方法就是对图像像素点的R、G、B三个分量同时进行增加(减少)某个值,达到调整亮度的目的。我在这里使用GDI+图像的扫描线来处理,核心处理采用了2个相同的过程,一个是Pascal过程,一个是嵌入汇编过程,通过比较,对小的图像几乎没有什么区别,对比较大的图像处理还是有一定的区别(具体测试效果见代码中的注释),这说明Delphi的代码优化还是很好的。
使用GDI+图像的扫描线处理必须调用TGpBitmap.LockBits和TGpBitmap.UnLockBits过程,而这2个过程的调用相当耗时,以2304 *1728大小的图片为例,耗时竟达188毫秒!而亮度调整过程最长只耗时63毫秒。由此可以看出使用GDI+图像扫描线处理图像并非十分理想。
需要说明的是,本例子及以后GDI+ for Delphi例子的Gdiplus单元是本人自己写的,与目前网上流通的版本有一定的区别,浏览着需要测试例子,可作适当修改,或者发邮件向本人索取Gdiplus单元。
说明:为了统一《GDI+ 在Delphi程序的应用》系列文章所用数据类型和图像处理格式,本文代码已重新修订,代码中所用Gdiplus单元下载地址及BUG更正见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。(2008.8.18记)
数据类型:
  1. type
  2. //与GDI+TBitmapData结构兼容的图像数据结构
  3. TImageData=packedrecord
  4. Width:LongWord;//图像宽度
  5. Height:LongWord;//图像高度
  6. Stride:LongWord;//图像扫描线字节长度
  7. PixelFormat:LongWord;//未使用
  8. Scan0:Pointer;//图像数据地址
  9. Reserved:LongWord;//保留
  10. end;
  11. PImageData=^TImageData;
  12. //获取TBitmap图像的TImageData数据结构,便于处理TBitmap图像
  13. functionGetImageData(Bmp:TBitmap):TImageData;
  14. begin
  15. Bmp.PixelFormat:=pf32bit;
  16. Result.Width:=Bmp.Width;
  17. Result.Height:=Bmp.Height;
  18. Result.Scan0:=Bmp.ScanLine[Bmp.Height-1];
  19. Result.Stride:=Result.Widthshl2;
  20. //Result.Stride:=(((32*Bmp.Width)+31)and$ffffffe0)shr3;
  21. end;

过程代码:
  1. //调整图像亮度
  2. procedureBrightness(Data:TImageData;Value:Integer);
  3. asm
  4. pushesi
  5. pushedi
  6. movedi,[eax+16]
  7. movesi,[eax+4]
  8. imulesi,[eax]
  9. cld
  10. @PixelLoop:
  11. movecx,3
  12. @RGBLoop:
  13. movzxeax,[edi]
  14. addeax,edx
  15. jns@@1
  16. xoreax,eax
  17. jmp@@2
  18. @@1:
  19. cmpeax,255
  20. jle@@2
  21. moveax,255
  22. @@2:
  23. stosb
  24. loop@RGBLoop
  25. incedi
  26. decesi
  27. jnz@PixelLoop
  28. popedi
  29. popesi
  30. end;
  31. //调整GDI+图像亮度
  32. procedureGdipBrightness(Bmp:TGpBitmap;Value:Integer);
  33. var
  34. Data:TBitmapData;
  35. begin
  36. ifValue=0thenExit;
  37. Data:=Bmp.LockBits(GpRect(0,0,Bmp.Width,Bmp.Height),[imRead,imWrite],pf32bppARGB);
  38. try
  39. Brightness(TImageData(Data),Value);
  40. finally
  41. Bmp.UnlockBits(Data);
  42. end;
  43. end;
  44. //调整TBitmap图像亮度
  45. procedureBitmapBrightness(Bmp:TBitmap;Value:Integer);
  46. begin
  47. ifValue<>0then
  48. Brightness(GetImageData(Bmp),Value);
  49. end;

测试代码:

  1. //为方便初学者理解前面的BASM代码,写了个处理GDI+图像亮度的纯Pas代码过程
  2. //稍稍改动一下,也可用来处理TBitmap图像亮度
  3. procedureGdipBrightness_Pas(Bmp:TGpBitmap;Value:Integer);
  4. functionSetRGBValue(Rgb:Byte):Integer;
  5. begin
  6. Result:=Value+Rgb;//像素颜色分量+亮度值
  7. ifResult<0then//像素颜色分量>=0and<=255
  8. Result:=0
  9. elseifResult>255then
  10. Result:=255;
  11. end;
  12. var
  13. Data:TBitmapData;
  14. P:PRGBQuad;
  15. I,Count:LongWord;
  16. begin
  17. ifValue=0thenExit;
  18. Data:=Bmp.LockBits(GpRect(0,0,Bmp.Width,Bmp.Height),[imRead,imWrite],pf32bppARGB);
  19. try
  20. Count:=Data.Width*Data.Height;
  21. P:=Data.Scan0;
  22. forI:=1toCountdo
  23. begin
  24. P^.rgbBlue:=SetRGBValue(P^.rgbBlue);
  25. P^.rgbGreen:=SetRGBValue(P^.rgbGreen);
  26. P^.rgbRed:=SetRGBValue(P^.rgbRed);
  27. Inc(P);
  28. end;
  29. finally
  30. Bmp.UnlockBits(Data);
  31. end;
  32. end;
  33. //测试GDI+图像
  34. procedureTForm1.Button1Click(Sender:TObject);
  35. var
  36. Image:TGpBitmap;
  37. g:TGpGraphics;
  38. begin
  39. Image:=TGpBitmap.Create('D:\VclLib\GdiplusDemo\Media\20041001.jpg');
  40. g:=TGpGraphics.Create(Handle,False);
  41. g.DrawImage(Image,10,10);
  42. //GdipBrightness_Pas(Image,30);
  43. GdipBrightness(Image,30);
  44. g.DrawImage(Image,10,220);
  45. Image.Free;
  46. g.Free;
  47. end;
  48. //测试TBitmap图像
  49. procedureTForm1.Button2Click(Sender:TObject);
  50. var
  51. Image:TBitmap;
  52. begin
  53. Image:=TBitmap.Create;
  54. Image.LoadFromFile('D:\VclLib\GdiplusDemo\Media\20041001.bmp');
  55. Canvas.Draw(10,10,Image);
  56. BitmapBrightness(Image,-30);
  57. Canvas.Draw(10,220,Image);
  58. Image.Free;
  59. end;

你可能感兴趣的:(GDI+ 在Delphi程序的应用 -- 调整图像亮度)