GDI+ 在Delphi程序的应用 -- Photoshop色相/饱和度/明度功能

眉间皱痕 提交于 2020-03-03 18:27:19

 

GDI+在Delphi程序的应用 – Photoshop色相/饱和度/明度功能

本文用GDI+实现Photoshop色相/饱和度/明度功能,参照我的其它有关GDI+在 Delphi程序的应用的文章,代码也可供TBitmap使用。

    有些人不喜欢,或者不太懂Delphi的BASM代码,所以本文给出纯PAS代码。须说明的是,纯PAS代码效率较低,不适合实际应用。喜欢C/C++的,可以看本人文章《C++实现Photoshop色相/饱和度/明度功能》,除了语言不同,其它都一样。

    有关Photoshop饱和度调整原理可参见《GDI+ 在Delphi程序的应用 -- 图像饱和度调整》,明度调整原理可参见《GDI+ 在Delphi程序的应用 -- 仿Photoshop的明度调整》。

    下面是一个完整的Delphi程序,Photoshop色相/饱和度/明度功能纯PAS代码包含在其中:

 

  1. unit main;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs, ExtCtrls, StdCtrls, ComCtrls, Gdiplus;  
  8.   
  9. type  
  10.   TForm1 = class(TForm)  
  11.     Label1: TLabel;  
  12.     Label2: TLabel;  
  13.     Label3: TLabel;  
  14.     Hbar: TTrackBar;  
  15.     SBar: TTrackBar;  
  16.     BBar: TTrackBar;  
  17.     HEdit: TEdit;  
  18.     SEdit: TEdit;  
  19.     BEdit: TEdit;  
  20.     Button1: TButton;  
  21.     PaintBox1: TPaintBox;  
  22.     procedure FormCreate(Sender: TObject);  
  23.     procedure FormDestroy(Sender: TObject);  
  24.     procedure PaintBox1Paint(Sender: TObject);  
  25.     procedure HBarChange(Sender: TObject);  
  26.     procedure SBarChange(Sender: TObject);  
  27.     procedure BBarChange(Sender: TObject);  
  28.     procedure HEditChange(Sender: TObject);  
  29.     procedure Button1Click(Sender: TObject);  
  30.   private  
  31.     { Private declarations }  
  32.     Source: TGpBitmap;  
  33.     Bitmap: TGpBitmap;  
  34.     r: TGpRect;  
  35.     Lock: Boolean;  
  36.   public  
  37.     { Public declarations }  
  38.   end;  
  39.   
  40. var  
  41.   Form1: TForm1;  
  42.   
  43. implementation  
  44.   
  45. {$R *.dfm}  
  46.   
  47. procedure SwapRGB(var a, b: Integer);  
  48. begin  
  49.   Inc(a, b);  
  50.   b := a - b;  
  51.   Dec(a, b);  
  52. end;  
  53.   
  54. procedure CheckRGB(var Value: Integer);  
  55. begin  
  56.   if Value < 0 then Value := 0  
  57.   else if Value > 255 then Value := 255;  
  58. end;  
  59.   
  60. procedure AssignRGB(var R, G, B: Byte; intR, intG, intB: Integer);  
  61. begin  
  62.   R := intR;  
  63.   G := intG;  
  64.   B := intB;  
  65. end;  
  66.   
  67. procedure SetBright(var R, G, B: Byte; bValue: Integer);  
  68. var  
  69.   intR, intG, intB: Integer;  
  70. begin  
  71.   intR := R;  
  72.   intG := G;  
  73.   intB := B;  
  74.   if bValue > 0 then  
  75.   begin  
  76.     Inc(intR, (255 - intR) * bValue div 255);  
  77.     Inc(intG, (255 - intG) * bValue div 255);  
  78.     Inc(intB, (255 - intB) * bValue div 255);  
  79.   end  
  80.   else if bValue < 0 then  
  81.   begin  
  82.     Inc(intR, intR * bValue div 255);  
  83.     Inc(intG, intG * bValue div 255);  
  84.     Inc(intB, intB * bValue div 255);  
  85.   end;  
  86.   CheckRGB(intR);  
  87.   CheckRGB(intG);  
  88.   CheckRGB(intB);  
  89.   AssignRGB(R, G, B, intR, intG, intB);  
  90. end;  
  91.   
  92. procedure SetHueAndSaturation(var R, G, B: Byte; hValue, sValue: Integer);  
  93. var  
  94.   intR, intG, intB: Integer;  
  95.   H, S, L, Lum: Integer;  
  96.   delta, entire: Integer;  
  97.   index, extra: Integer;  
  98. begin  
  99.   intR := R;  
  100.   intG := G;  
  101.   intB := B;  
  102.   
  103.   if intR < intG then SwapRGB(intR, intG);  
  104.   if intR < intB then SwapRGB(intR, intB);  
  105.   if intB > intG then SwapRGB(intB, intG);  
  106.   
  107.   delta := intR - intB;  
  108.   if delta = 0 then Exit;  
  109.   
  110.   entire := intR + intB;  
  111.   L := entire shr 1;  
  112.   if L < 128 then  
  113.     S := delta * 255 div entire  
  114.   else  
  115.     S := delta * 255 div (510 - entire);  
  116.   if hValue <> 0 then  
  117.   begin  
  118.     if intR = R then  
  119.       H := (G - B) * 60 div delta  
  120.     else if intR = G then  
  121.       H := (B - R) * 60 div delta + 120  
  122.     else  
  123.       H := (R - G) * 60 div delta + 240;  
  124.     Inc(H, hValue);  
  125.     if H < 0 then  
  126.       Inc(H, 360)  
  127.     else if H > 360 then  
  128.       Dec(H, 360);  
  129.     index := H div 60;  
  130.     extra := H mod 60;  
  131.     if (index and 1) <> 0 then  
  132.       extra := 60 - extra;  
  133.     extra := (extra * 255 + 30div 60;  
  134.     intG := extra - (extra - 128) * (255 - S) div 255;  
  135.     Lum := L - 128;  
  136.     if Lum > 0 then  
  137.       Inc(intG, (((255 - intG) * Lum + 64div 128))  
  138.     else if Lum < 0 then  
  139.       Inc(intG, (intG * Lum div 128));  
  140.     CheckRGB(intG);  
  141.     case index of  
  142.       1: SwapRGB(intR, intG);  
  143.       2:  
  144.       begin  
  145.         SwapRGB(intR, intB);  
  146.         SwapRGB(intG, intB);  
  147.       end;  
  148.       3: SwapRGB(intR, intB);  
  149.       4:  
  150.       begin  
  151.         SwapRGB(intR, intG);  
  152.         SwapRGB(intG, intB);  
  153.       end;  
  154.       5: SwapRGB(intG, intB);  
  155.     end;  
  156.   end  
  157.   else  
  158.   begin  
  159.     intR := R;  
  160.     intG := G;  
  161.     intB := B;  
  162.   end;  
  163.   if sValue <> 0 then  
  164.   begin  
  165.     if sValue > 0 then  
  166.     begin  
  167.       if sValue + S >= 255 then sValue := S  
  168.       else sValue := 255 - sValue;  
  169.       sValue := 65025 div sValue - 255;  
  170.     end;  
  171.     Inc(intR, ((intR - L) * sValue div 255));  
  172.     Inc(intG, ((intG - L) * sValue div 255));  
  173.     Inc(intB, ((intB - L) * sValue div 255));  
  174.     CheckRGB(intR);  
  175.     CheckRGB(intG);  
  176.     CheckRGB(intB);  
  177.   end;  
  178.   AssignRGB(R, G, B, intR, intG, intB);  
  179. end;  
  180.   
  181. procedure GdipHSBAdjustment(Bmp: TGpBitmap; hValue, sValue, bValue: Integer);  
  182. var  
  183.   Data: TBitmapData;  
  184.   x, y: Integer;  
  185.   p: PRGBQuad;  
  186. begin  
  187.   sValue := sValue * 255 div 100;  
  188.   bValue := bValue * 255 div 100;  
  189.   Data := Bmp.LockBits(GpRect(00, Bmp.Width, Bmp.Height), [imRead, imWrite], pf32bppARGB);  
  190.   try  
  191.     p := Data.Scan0;  
  192.     for y := 1 to Data.Height do  
  193.     begin  
  194.       for x := 1 to Data.Width do  
  195.       begin  
  196.         if (sValue > 0and (bValue <> 0then  
  197.           SetBright(p^.rgbRed, p^.rgbGreen, p^.rgbBlue, bValue);  
  198.         SetHueAndSaturation(p^.rgbRed, p^.rgbGreen, p^.rgbBlue, hValue, sValue);  
  199.         if (sValue <= 0and (bValue <> 0then  
  200.           SetBright(p^.rgbRed, p^.rgbGreen, p^.rgbBlue, bValue);  
  201.         Inc(p);  
  202.       end;  
  203.     end;  
  204.   finally  
  205.     Bmp.UnlockBits(Data);  
  206.   end;  
  207. end;  
  208.   
  209. procedure TForm1.FormCreate(Sender: TObject);  
  210. begin  
  211.   Source := TGpBitmap.Create('http://www.cnblogs.com/GdiplusDemo/media/100_0349.jpg');  
  212.   r := GpRect(00, Source.Width, Source.Height);  
  213.   Bitmap := Source.Clone(r, pf32bppARGB);  
  214.   DoubleBuffered := True;  
  215. end;  
  216.   
  217. procedure TForm1.FormDestroy(Sender: TObject);  
  218. begin  
  219.   Bitmap.Free;  
  220.   Source.Free;  
  221. end;  
  222.   
  223. procedure TForm1.PaintBox1Paint(Sender: TObject);  
  224. var  
  225.   g: TGpGraphics;  
  226. begin  
  227.   g := TGpGraphics.Create(PaintBox1.Canvas.Handle);  
  228.   try  
  229.     g.DrawImage(Bitmap, r);  
  230.     g.TranslateTransform(0, r.Height);  
  231.     g.DrawImage(Source, r);  
  232.   finally  
  233.     g.Free;  
  234.   end;  
  235. end;  
  236.   
  237. procedure TForm1.HBarChange(Sender: TObject);  
  238. begin  
  239.   if not Lock then  
  240.     HEdit.Text := IntToStr(HBar.Position);  
  241. end;  
  242.   
  243. procedure TForm1.SBarChange(Sender: TObject);  
  244. begin  
  245.   if not Lock then  
  246.     SEdit.Text := IntToStr(SBar.Position);  
  247. end;  
  248.   
  249. procedure TForm1.BBarChange(Sender: TObject);  
  250. begin  
  251.   if not Lock then  
  252.     BEdit.Text := IntToStr(BBar.Position);  
  253. end;  
  254.   
  255. procedure TForm1.HEditChange(Sender: TObject);  
  256. begin  
  257.   Lock := True;  
  258.   if TEdit(Sender).Text = '' then  
  259.     TEdit(Sender).Text := '0';  
  260.   case TEdit(Sender).Tag of  
  261.     0: HEdit.Text := IntToStr(HBar.Position);  
  262.     1: HEdit.Text := IntToStr(HBar.Position);  
  263.     2: HEdit.Text := IntToStr(HBar.Position);  
  264.   end;  
  265.   Lock := False;  
  266.   Bitmap.Free;  
  267.   Bitmap := Source.Clone(r, pf32bppARGB);  
  268.   if (HBar.Position <> 0or (SBar.Position <> 0or (BBar.Position <> 0then  
  269.     GdipHSBAdjustment(Bitmap, HBar.Position, SBar.Position, BBar.Position);  
  270.   PaintBox1.Invalidate;  
  271. end;  
  272.   
  273. procedure TForm1.Button1Click(Sender: TObject);  
  274. begin  
  275.   HBar.Position := 0;  
  276.   SBar.Position := 0;  
  277.   BBar.Position := 0;  
  278. end;  
  279.   
  280. end.  

 

    程序运行界面截图:

代码中所用Gdiplus单元下载地址及BUG更正见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!