ImgUtil.pas
上传用户:xjwsee
上传日期:2008-08-02
资源大小:796k
文件大小:12k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {$R-}  // Turn off Range Checking because of ARRAY[0..0] construct below
  2. unit ImgUtil;
  3. // The new algorithms are 5 to 8 imes faster (dirty but fast) and they
  4. // not need so many memory (if the bitmap very large you have a problem ->
  5. // windows must use the swapfile).
  6. //{$WARNINGS OFF}
  7. //{$HINTS OFF}
  8. interface
  9. uses   Windows, Graphics,math;
  10.   procedure SpiegelnHorizontal  (Bitmap:TBitmap);
  11.   procedure SpiegelnVertikal    (Bitmap:TBitmap);
  12.   procedure Drehen90Grad        (Bitmap:TBitmap);
  13.   procedure Drehen270Grad       (Bitmap:TBitmap);
  14.   procedure Drehen180Grad       (Bitmap:TBitmap);
  15.   FUNCTION Rotate90(Bitmap:TBitmap):  TBitmap;
  16.   procedure ConvertBitmapToGrayscale (const Bmp: TBitmap);
  17.   procedure ChangeTrans(abmp:Tbitmap;colorf:Tcolor);
  18.   function Blend(C1, C2: TColor; W1: Integer): TColor;
  19.   procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: integer = 1);
  20.   function GetHSV(c:Tcolor):integer;
  21. implementation
  22. USES dialogs,
  23.      Classes,    // Rect
  24.      SysUtils;
  25. TYPE
  26.   EBitmapError = CLASS(Exception);
  27.   TRGBArray    = ARRAY[0..0] OF TRGBTriple;
  28.   pRGBArray    = ^TRGBArray;
  29. procedure ConvertBitmapToGrayscale (const Bmp: TBitmap);
  30. var
  31.   x, y, Gray: Integer;
  32.   Row: PRGBArray;
  33. begin
  34.   Bmp.PixelFormat := pf24Bit;
  35.   for y := 0 to Bmp.Height - 1 do
  36.   begin
  37.     Row := Bmp.ScanLine[y];
  38.     for x := 0 to Bmp.Width - 1 do
  39.     begin
  40.       Gray           := (Row[x].rgbtRed + Row[x].rgbtGreen + Row[x].rgbtBlue) div 3;
  41.       Row[x].rgbtRed := Gray;
  42.       Row[x].rgbtGreen := Gray;
  43.       Row[x].rgbtBlue := Gray;
  44.     end;
  45.   end;
  46. end;
  47. procedure ChangeTrans(abmp:Tbitmap;colorf:Tcolor);
  48. var x, y, Gray: Integer;
  49.     Row: PRGBArray;
  50.     r,g,b:integer;
  51. begin
  52.    r:=GetRValue(colorf);
  53.    g:=GetGValue(colorf);
  54.    b:=GetBValue(colorf);
  55.    if (abmp.PixelFormat<>pf24bit) then
  56.      abmp.PixelFormat:=pf24bit;
  57.    for y := 0 to aBmp.Height - 1 do  begin
  58.     Row := aBmp.ScanLine[y];
  59.     for x := 0 to aBmp.Width - 1 do begin
  60.       if (Row[x].rgbtRed=255) and
  61.          (Row[x].rgbtGreen=0) and
  62.          (Row[x].rgbtBlue =255) then begin
  63.            Row[x].rgbtRed:=r;
  64.            Row[x].rgbtGreen:=g;
  65.            Row[x].rgbtBlue :=b;
  66.       end;
  67.     end;
  68.   end;
  69. end;
  70. procedure SpiegelnHorizontal(Bitmap:TBitmap);
  71. var i,j,w,n :  INTEGER;
  72.     RowIn :  pRGBArray;
  73.     RowOut:  pRGBArray;
  74.     temp:Tbitmap;
  75. begin
  76.     temp:=Tbitmap.create;
  77.     temp.Width  := Bitmap.Width;
  78.     temp.Height := Bitmap.Height;
  79.     temp.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
  80.     n:=bitmap.width;
  81.     for j := 0 to Bitmap.Height-1 do begin
  82.       rowout := temp.Scanline[j];
  83.       rowin := Bitmap.Scanline[j];
  84.       for i := 0 to n-1 do rowout[i] := rowin[n-1-i];
  85.     end;
  86.     bitmap.Assign(temp);
  87.     temp.free;
  88. end;
  89. procedure SpiegelnVertikal(Bitmap : TBitmap);
  90. var j,w :  INTEGER;
  91.     help  :  TBitmap;
  92. begin
  93.     help := TBitmap.Create;
  94.     help.Width       := Bitmap.Width;
  95.     help.Height      := Bitmap.Height;
  96.     help.PixelFormat := Bitmap.PixelFormat;
  97.     w := Bitmap.Width*sizeof(TRGBTriple);
  98.     for j := 0 to Bitmap.Height-1 do move(Bitmap.Scanline[j]^,Help.Scanline[Bitmap.Height - 1 - j]^,w);
  99.     Bitmap.Assign(help);
  100.     help.free;
  101. end;
  102. type THelpRGB = packed record
  103.                    rgb    : TRGBTriple;
  104.                    dummy  : byte;
  105.                 end;
  106. procedure Drehen270Grad(Bitmap:TBitmap);
  107. var aStream : TMemorystream;
  108.     header  : TBITMAPINFO;
  109.     dc      : hDC;
  110.     P       : ^THelpRGB;
  111.     x,y,b,h : Integer;
  112.     RowOut:  pRGBArray;
  113. BEGIN
  114.    aStream := TMemoryStream.Create;
  115.    aStream.SetSize(Bitmap.Height*Bitmap.Width * 4);
  116.    with header.bmiHeader do begin
  117.      biSize := SizeOf(TBITMAPINFOHEADER);
  118.      biWidth := Bitmap.Width;
  119.      biHeight := Bitmap.Height;
  120.      biPlanes := 1;
  121.      biBitCount := 32;
  122.      biCompression := 0;
  123.      biSizeimage := aStream.Size;
  124.      biXPelsPerMeter :=1;
  125.      biYPelsPerMeter :=1;
  126.      biClrUsed :=0;
  127.      biClrImportant :=0;
  128.    end;
  129.    dc := GetDC(0);
  130.    P  := aStream.Memory;
  131.    GetDIBits(dc,Bitmap.Handle,0,Bitmap.Height,P,header,dib_RGB_Colors);
  132.    ReleaseDC(0,dc);
  133.    b := bitmap.Height;  // rotate
  134.    h := bitmap.Width;   // rotate
  135.    bitmap.Width := b;
  136.    bitmap.height := h;
  137.    for y := 0 to (h-1) do begin
  138.      rowOut := Bitmap.ScanLine[(h-1)-y];
  139.      P  := aStream.Memory;        // reset pointer
  140.      inc(p,y);
  141.      for x := (b-1) downto 0 do begin
  142.         rowout[x] := p^.rgb;
  143.         inc(p,h);
  144.      end;
  145.    end;
  146.    aStream.Free;
  147. end;
  148. procedure Drehen90Grad(Bitmap:TBitmap);
  149. var aStream : TMemorystream;
  150.     header  : TBITMAPINFO;
  151.     dc      : hDC;
  152.     P       : ^THelpRGB;
  153.     x,y,b,h : Integer;
  154.     RowOut:  pRGBArray;
  155. BEGIN
  156.    aStream := TMemoryStream.Create;
  157.    aStream.SetSize(Bitmap.Height*Bitmap.Width * 4);
  158.    with header.bmiHeader do begin
  159.      biSize := SizeOf(TBITMAPINFOHEADER);
  160.      biWidth := Bitmap.Width;
  161.      biHeight := Bitmap.Height;
  162.      biPlanes := 1;
  163.      biBitCount := 32;
  164.      biCompression := 0;
  165.      biSizeimage := aStream.Size;
  166.      biXPelsPerMeter :=1;
  167.      biYPelsPerMeter :=1;
  168.      biClrUsed :=0;
  169.      biClrImportant :=0;
  170.    end;
  171.    dc := GetDC(0);
  172.    P  := aStream.Memory;
  173.    GetDIBits(dc,Bitmap.Handle,0,Bitmap.Height,P,header,dib_RGB_Colors);
  174.    ReleaseDC(0,dc);
  175.    b := bitmap.Height;  // rotate
  176.    h := bitmap.Width;   // rotate
  177.    bitmap.Width := b;
  178.    bitmap.height := h;
  179.    for y := 0 to (h-1) do begin
  180.      rowOut := Bitmap.ScanLine[y];
  181.      P  := aStream.Memory;        // reset pointer
  182.      inc(p,y);
  183.      for x := 0 to (b-1) do begin
  184.         rowout[x] := p^.rgb;
  185.         inc(p,h);
  186.      end;
  187.    end;
  188.    aStream.Free;
  189. end;
  190. procedure Drehen180Grad(Bitmap:TBitmap);
  191. var i,j     :  INTEGER;
  192.     rowIn :  pRGBArray;
  193.     rowOut:  pRGBArray;
  194.     help  : TBitmap;
  195. begin
  196.    help := TBitmap.Create;
  197.    help.Width  := Bitmap.Width;
  198.    help.Height := Bitmap.Height;
  199.    help.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
  200.    FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
  201.      rowIn  := Bitmap.ScanLine[j];
  202.      rowOut := help.ScanLine[Bitmap.Height - j - 1];
  203.      FOR i := 0 TO Bitmap.Width - 1 DO rowOut[Bitmap.Width - i - 1] := rowIn[i]
  204.    END;
  205.    bitmap.assign(help);
  206.    help.free;
  207. end;
  208. FUNCTION Rotate90(Bitmap:TBitmap):  TBitmap;
  209. VAR i,j     :  INTEGER;
  210.         rowIn :  pRGBArray;
  211. BEGIN
  212.    IF   Bitmap.PixelFormat <> pf24bit then
  213.      exit;
  214.    RESULT := TBitmap.Create;
  215.    RESULT.Width  := Bitmap.Height;
  216.    RESULT.Height := Bitmap.Width;
  217.    RESULT.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
  218.    // Out[j, Right - i - 1] = In[i, j]
  219.    FOR  j := 0 TO Bitmap.Height - 1 DO  BEGIN
  220.       rowIn  := Bitmap.ScanLine[j];
  221.       FOR i := 0 TO Bitmap.Width - 1 DO
  222.           pRGBArray(RESULT.ScanLine[Bitmap.Width - i - 1])[j] := rowIn[i]
  223.    END;
  224. END;
  225. function Blend(C1, C2: TColor; W1: Integer): TColor;
  226. var
  227.   W2, A1, A2, D, F, G: Integer;
  228. begin
  229.   if C1 < 0 then C1 := GetSysColor(C1 and $FF);
  230.   if C2 < 0 then C2 := GetSysColor(C2 and $FF);
  231.   if W1 >= 100 then D := 1000
  232.   else D := 100;
  233.   W2 := D - W1;
  234.   F := D div 2;
  235.   A2 := C2 shr 16 * W2;
  236.   A1 := C1 shr 16 * W1;
  237.   G := (A1 + A2 + F) div D and $FF;
  238.   Result := G shl 16;
  239.   A2 := (C2 shr 8 and $FF) * W2;
  240.   A1 := (C1 shr 8 and $FF) * W1;
  241.   G := (A1 + A2 + F) div D and $FF;
  242.   Result := Result or G shl 8;
  243.   A2 := (C2 and $FF) * W2;
  244.   A1 := (C1 and $FF) * W1;
  245.   G := (A1 + A2 + F) div D and $FF;
  246.   Result := Result or G;
  247. end;
  248. const
  249.   GRADIENT_CACHE_SIZE = 16;
  250. type
  251.   PRGBQuad = ^TRGBQuad;
  252.   TRGBQuad = Integer;
  253.   PRGBQuadArray = ^TRGBQuadArray;
  254.   TRGBQuadArray = array [0..0] of TRGBQuad;
  255. var
  256.   GradientCache: array [0..GRADIENT_CACHE_SIZE] of array of TRGBQuad;
  257.   NextCacheIndex: Integer = 0;
  258. function FindGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  259. begin
  260.   Assert(Size > 0);
  261.   Result := GRADIENT_CACHE_SIZE - 1;
  262.   while Result >= 0 do
  263.   begin
  264.     if (Length(GradientCache[Result]) = Size) and
  265.       (GradientCache[Result][0] = CL) and
  266.       (GradientCache[Result][Length(GradientCache[Result]) - 1] = CR) then Exit;
  267.     Dec(Result);
  268.   end;
  269. end;
  270. function MakeGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  271. var
  272.   R1, G1, B1: Integer;
  273.   R2, G2, B2: Integer;
  274.   R, G, B: Integer;
  275.   I: Integer;
  276.   Bias: Integer;
  277. begin
  278.   Assert(Size > 0);
  279.   Result := NextCacheIndex;
  280.   Inc(NextCacheIndex);
  281.   if NextCacheIndex >= GRADIENT_CACHE_SIZE then NextCacheIndex := 0;
  282.   R1 := CL and $FF;
  283.   G1 := CL shr 8 and $FF;
  284.   B1 := CL shr 16 and $FF;
  285.   R2 := CR and $FF - R1;
  286.   G2 := CR shr 8 and $FF - G1;
  287.   B2 := CR shr 16 and $FF - B1;
  288.   SetLength(GradientCache[Result], Size);
  289.   Dec(Size);
  290.   Bias := Size div 2;
  291.   if Size > 0 then
  292.     for I := 0 to Size do
  293.     begin
  294.       R := R1 + (R2 * I + Bias) div Size;
  295.       G := G1 + (G2 * I + Bias) div Size;
  296.       B := B1 + (B2 * I + Bias) div Size;
  297.       GradientCache[Result][I] := R + G shl 8 + B shl 16;
  298.     end
  299.   else
  300.   begin
  301.     R := R1 + R2 div 2;
  302.     G := G1 + G2 div 2;
  303.     B := B1 + B2 div 2;
  304.     GradientCache[Result][0] := R + G shl 8 + B shl 16;
  305.   end;
  306. end;
  307. function GetGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  308. begin
  309.   Result := FindGradient(Size, CL, CR);
  310.   if Result < 0 then Result := MakeGradient(Size, CL, CR);
  311. end;
  312. procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: integer = 1);
  313. const
  314. //  GRAD_MODE: array [0..1] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
  315.   W: array [0..1] of Integer = (2, 1);
  316.   H: array [0..1] of Integer = (1, 2);
  317. type
  318.   TriVertex = packed record
  319.     X, Y: Longint;
  320.     R, G, B, A: Word;
  321.   end;
  322. var
  323.   V: array [0..1] of TriVertex;
  324.   GR: GRADIENT_RECT;
  325.   Size, I, Start, Finish: Integer;
  326.   GradIndex: Integer;
  327.   R, CR: TRect;
  328.   Brush: HBRUSH;
  329. begin
  330.   if not RectVisible(DC, ARect) then Exit;
  331.   ClrTopLeft := ColorToRGB(ClrTopLeft);
  332.   ClrBottomRight := ColorToRGB(ClrBottomRight);
  333.     { Have to do it manually if msimg32.dll is not available }
  334.     GetClipBox(DC, CR);
  335.     if Kind = 0 then begin
  336.       Size := ARect.Right - ARect.Left;
  337.       if Size <= 0 then Exit;
  338.       Start := 0; Finish := Size - 1;
  339.       if CR.Left > ARect.Left then Inc(Start, CR.Left - ARect.Left);
  340.       if CR.Right < ARect.Right then Dec(Finish, ARect.Right - CR.Right);
  341.       R := ARect; Inc(R.Left, Start); R.Right := R.Left + 1;
  342.     end else begin
  343.       Size := ARect.Bottom - ARect.Top;
  344.       if Size <= 0 then Exit;
  345.       Start := 0; Finish := Size - 1;
  346.       if CR.Top > ARect.Top then Inc(Start, CR.Top - ARect.Top);
  347.       if CR.Bottom < ARect.Bottom then Dec(Finish, ARect.Bottom - CR.Bottom);
  348.       R := ARect; Inc(R.Top, Start); R.Bottom := R.Top + 1;
  349.     end;
  350.     GradIndex := GetGradient(Size, ClrTopLeft, ClrBottomRight);
  351.     for I := Start to Finish do begin
  352.       Brush := CreateSolidBrush(GradientCache[GradIndex][I]);
  353.       Windows.FillRect(DC, R, Brush);
  354.       OffsetRect(R, Integer(Kind = 0), Integer(Kind = 1));
  355.       DeleteObject(Brush);
  356.     end;
  357. end;
  358. function GetHSV(c:Tcolor):integer;
  359. var
  360.   Delta:  double;
  361.   Min  :  double;
  362.   R,G,B:  integer;
  363.   ss,vv,hh:double;
  364.   H,S,V:Integer;
  365. begin
  366.     R := C and $FF;
  367.     G := C shr 8 and $FF;
  368.     B := C shr 16 and $FF;
  369.     
  370.     Min := MinIntValue( [R, G, B] );
  371.     V   := MaxIntValue( [R, G, B] );
  372.     Delta := V - Min;
  373.     if   V =  0  then ss := 0
  374.     else ss := Delta/V;
  375.     if ss = 0 then hh := 0
  376.     else begin
  377.       if      R = V then hh := 60 * (G - B) / Delta
  378.       else if G = V then hh := 120 + 60 * (B - R) / Delta
  379.       else if B = V then hh := 240 + 60 * (R - G) / Delta;
  380.       if hh < 0 then hh := hh + 360;
  381.     end;
  382.     S := round(ss*255);
  383.     H := round(hh*255/360);
  384.     if (r<160) and (g<160) and (b<160) then s:=200;
  385.     result:=s;
  386. end;
  387. end.