如何实现photoshop的透明效果(100分)

  • 主题发起人 主题发起人 周卿锦
  • 开始时间 开始时间
在执行后,原来的Bitmap : BKGround ,已经混合了FrGround 的图象
。注意,由于我的设计错误,left ,和top 植不能小于 0;

另外,我反而建议你使用Alphablend,适应范围要大一些。
 
GGCAT大侠,我输入的left和top都是正数,但也没有效果。还有,用Alphablend好象
也不用Image2.Refresh,你在改变它的图象时好象已经刷新了。而且,我要做的仅仅是
一个模块,接口可以自己设定,有没有更好的招啊!

 
要刷新光滑, 其实还有一些技巧很容易被大多数人忽略. 1. 不要用TImage作为动画图象
的载体. 理由见2.
2.重画时不要调用Invalidate, 因为这将使窗口中的图象先清除再重画(闪烁的根源).
对TWinControl类的控件可以在ControlStyle中加入csOpaque以防止Invalidate时清屏
但对TGraphicControl类则不行, 因为如果加了csOpaque, 则会出现该刷新的部分未
重画的故障.
3. 使用双缓冲, 在内存中画完图象帧后一次copy到屏幕上.
4. 需要刷新图象时直接用API InvalidateRect(Handle/Parent.Handle, @Rect, False).
这将不会清除屏幕上的图象. 其中False是必须的, 否则即使你用双缓冲, 在你在后台
内存中做画时, 前台屏幕上的图象已经清空了, 所以copy到屏幕时仍会产生很强的闪
烁感.

关于你的要求, 给你一个小程序: XCombineBmp.(我写的, 算是王婆卖瓜吧)

对Tag进行操作(注, 所有图象必须是24bit的):

如果Src不为nil:
Src将根据FillStyle画到Tag上:
填图时: 如果FromRate<>BandRate并且Gradient不为gsNone,
那么Src部分将用渐进透明方式画到Tag, 如果FromRate=BandRate并且Gradient
为gsNone, 则根据BandRate指定的透明度画到Tag上

如果Src=nil:
则实现渐进或透明或两者结合方式将Tag填色

以下程序摘自我做的一套工具函数库, 45个函数/过程中的2个, 不好意思, 还没调试过,
程序我已经尽量优化了, 如果你用了没问题, 请告诉我一声, 如果有Bug或者改进意见
也请务必告诉我 :)

interface

uses .....;

type
P24Color = ^T24Color;
T24Color = record
b, g, r: byte;
end;

TGradientStyle = (gsNone, gsVertical, gsHorizon, gsBox, gsEllipse);

TFillStyle = (fsCenter, fsTiled, fsStretched, fsVTiled, fsHTiled);

procedure CreateGradient(Bmp: TBitmap; FromC, ToC: TColor;
Style: TGradientStyle; Center: TPoint;
Step: Integer);

procedure XCombineBmp(Tag, Src: TBitmap; FillStyle: TFillStyle;
Gradient: TGradientStyle;
GradCenter: TPoint;
BandColor: TColor;
FromColor: TColor;
BandRate: Integer;
FromRate: Integer;
GradStep: Integer = 64);

.....
.....
implimentation
var
Colors : array [0..100, 0..255] of Byte;

function AdjustColor(Value: Integer): Byte;
begin
if Value > 255 then
Result := 255
else if Value < 0 then
Result := 0
else Result := Value;
end;

procedure CreateGradient(Bmp: TBitmap; FromC, ToC: TColor;
Style: TGradientStyle; Center: TPoint;
Step: Integer);
var
CList: array [0..127] of Cardinal;
IndsH: array [ShortInt] of Integer;
IndsV: array [ShortInt] of Integer;
rb, gb, bb:Byte;
r, g, b: Integer;
i, n, l, h: Integer;

begin
Step := Step and $7f;
CList[0] := ColorToRGB(FromC);
rb := GetRValue(CList[0]);
gb := GetGValue(CList[0]);
bb := GetBValue(CList[0]);
i := ColorToRGB(ToC);
l := CreateSolidBrush(i);
FillRect(Bmp.Canvas.Handle, Rect(0,0,Bmp.Width, Bmp.Height), l);
DeleteObject(l);
r := GetRValue(i) - rb + 1;
g := GetGValue(i) - gb + 1;
b := GetBValue(i) - bb + 1;
for i := 1 to Step - 1 do
CList := RGB(AdjustColor(Round(rb + r * i / Step)),
AdjustColor(Round(gb + g * i / Step)),
AdjustColor(Round(bb + b * i / Step)));
n := Step;
l := Bmp.Width - Center.x;
if l < Center.x then l := Center.x;
h := Bmp.Height - Center.y;
if h < Center.y then h := Center.y;
for i := 0 to n - 1 do
begin
IndsH := Round((i+1) * l / (n));
IndsH[-i] := -IndsH + 1;
IndsV := Round((i+1) * h / (n));
IndsV[-i] := -IndsV + 1;
end;
for i := n-1 downto 0 do
case Style of
gsVertical:
begin
l := CreateSolidBrush(CList);
FillRect(Bmp.Canvas.Handle, Rect(IndsH[-i] + Center.x,
0,
IndsH + Center.x,
Bmp.Height), l);
DeleteObject(l);
end;
gsHorizon:
begin
l := CreateSolidBrush(CList);
FillRect(Bmp.Canvas.Handle, Rect(0, IndsV[-i] + Center.y,
Bmp.Width,
IndsV + Center.y), L);
DeleteObject(l);
end;
gsBox:
begin
l := CreateSolidBrush(CList);
FillRect(Bmp.Canvas.Handle, Rect( IndsH[-i] + Center.x,
IndsV[-i] + Center.y,
IndsH + Center.x,
IndsV + Center.y), l);
DeleteObject(l);
end;
gsEllipse:
begin
DeleteObject(SelectObject(Bmp.Canvas.Handle, CreateSolidBrush(CList)));
DeleteObject(SelectObject(Bmp.Canvas.Handle, CreatePen(PS_SOLID,1,CList)));
Ellipse(Bmp.Canvas.Handle, IndsH[-i]+Center.x,
IndsV[-i]+Center.y,
IndsH + Center.x,
IndsV+Center.y);
end;
end;

end;

procedure XCombineBmp(Tag, Src: TBitmap; FillStyle: TFillStyle;
Gradient: TGradientStyle;
GradCenter: TPoint;
BandColor: TColor;
FromColor: TColor;
BandRate: Integer;
FromRate: Integer;
GradStep: Integer = 64);
var
Rates: TBitmap;
Tmp: TBitmap;
Br: HBRUSH;
c: array [0..255] of Byte;

procedure TiledDraw(Dst: TBitmap);
var
x, y: Integer;
begin
case FillStyle of
fsCenter:
BitBlt(Dst.Canvas.Handle, (Dst.Width - Src.Width) div 2,
(Dst.Height - Src.Height) div 2,
Src.Width, Src.Height,
Src.Canvas.Handle, 0, 0, SRCCOPY);
fsTiled:
begin
y := 0;
while y < Dst.Height do
begin
x := 0;
while x < Dst.Width do
begin
BitBlt(Dst.Canvas.Handle, x, y, Src.Width, Src.Height,
Src.Canvas.Handle, 0, 0,
SRCCOPY);
Inc(x, Src.Width);
end;
Inc(y, Src.Height);
end;
end;
fsStretched:
StretchBlt(Dst.Canvas.Handle, 0, 0, Dst.Width, Dst.Height,
Src.Canvas.Handle, 0, 0,
Src.Width, Src.Height, SRCCOPY);
fsVTiled:
begin
y := 0;
while y < Dst.Height do
begin
StretchBlt(Dst.Canvas.Handle, 0, y, Tmp.Width, Dst.Height,
Src.Canvas.Handle, 0, 0,
Src.Width, Src.Height, SRCCOPY);
Inc(y, Src.Height);
end;
end;
fsHTiled:
begin
x := 0;
while x < Dst.Width do
begin
StretchBlt(Dst.Canvas.Handle, x, 0, Src.Width, Dst.Height,
Src.Canvas.Handle, 0, 0,
Src.Width, Src.Height, SRCCOPY);
Inc(x, Src.Width);
end;
end;
end;
end;

procedure TransLucent;
var
p: P24Color;
Gap: Integer;
r, g, b: byte;
i, j: Integer;
begin
for i := 0 to 255 do
c := i * BandRate div 100;
r := GetRValue(ColorToRGB(BandColor)) * (100 - BandRate) div 100;
g := GetGValue(ColorToRGB(BandColor)) * (100 - BandRate) div 100;
b := GetBValue(ColorToRGB(BandColor)) * (100 - BandRate) div 100;
Gap := ((Tag.Width * 24 + 31) and -32) shr 3 - Tag.Width * 3;
p := Tag.ScanLine[Tag.Height - 1];
for i := 0 to Tag.Height - 1 do
begin
for j := 0 to Tag.Width - 1 do
begin
if c[p^.b] + b > 255 then
p^.b := 255
else
p^.b := c[p^.b] + b;
if c[p^.g] + g > 255 then
p^.g := 255
else
p^.g := c[p^.g] + g;
if c[p^.r] + r > 255 then
p^.r := 255
else
p^.r := c[p^.r] + r;
p := Pointer(Integer(p) + 3);
end;
p := Pointer(Integer(p) + Gap);
end;
end;

procedure TransBlend;
var
p1, p2: P24Color;
Gap: Integer;
i, j: Integer;
begin
for i := 0 to 255 do
c := i * BandRate div 100;
Gap := ((Tag.Width * 24 + 31) and -32) shr 3 - Tag.Width * 3;
p1 := Tag.ScanLine[Tag.Height - 1];
p2 := Tmp.ScanLine[Tmp.Height - 1];
for i := 0 to Tag.Height - 1 do
begin
for j := 0 to Tag.Width - 1 do
begin
p1^.r := AdjustColor(c[p1^.r] - c[p2^.r] + p2^.r);
p1^.g := AdjustColor(c[p1^.g]- c[p2^.g] + p2^.g);
p1^.b := AdjustColor(c[p1^.b] - c[p2^.b] + p2^.b);
p1 := Pointer(Integer(p1) + 3);
p2 := Pointer(Integer(p2) + 3);
end;
p1 := Pointer(Integer(p1) + Gap);
p2 := Pointer(Integer(p2) + Gap);
end;
end;

procedure GradDraw;
var
Gap: Integer;
p1, p2: P24Color;
r, g, b: Integer;
i, j: Integer;
begin
Gap := ((Tag.Width * 24 + 31) and -32) shr 3 - Tag.Width * 3;
r := GetRValue(ColorToRGB(BandColor));
g := GetGValue(ColorToRGB(BandColor));
b := GetBValue(ColorToRGB(BandColor));
p1 := Tag.ScanLine[Tag.Height - 1];
p2 := Rates.ScanLine[Rates.Height - 1];
for i := 0 to Tag.Height - 1 do
begin
for j := 0 to Tag.Width - 1 do
begin
p1^.r := AdjustColor(Colors[p2^.r, p1^.r] + Colors[100-p2^.r, r]);
p1^.g := AdjustColor(Colors[p2^.r, p1^.g] + Colors[100-p2^.r, g]);
p1^.b := AdjustColor(Colors[p2^.r, p1^.b] + Colors[100-p2^.r, b]);
p1 := Pointer(Integer(p1) + 3);
p2 := Pointer(Integer(p2) + 3);
end;
p1 := Pointer(Integer(p1) + Gap);
p2 := Pointer(Integer(p2) + Gap);
end;
end;

procedure GradBlend;
var
Gap: Integer;
p1, p2, p3: P24Color;
i, j: Integer;
begin
Gap := ((Tag.Width * 24 + 31) and -32) shr 3 - Tag.Width * 3;
p1 := Tag.ScanLine[Tag.Height - 1];
p2 := Rates.ScanLine[Rates.Height - 1];
p3 := Tmp.ScanLine[Tmp.Height - 1];
for i := 0 to Tag.Height - 1 do
begin
for j := 0 to Tag.Width - 1 do
begin
p1^.r := AdjustColor(Colors[p2^.r, p1^.r] + Colors[100-p2^.r, p3^.r]);
p1^.g := AdjustColor(Colors[p2^.r, p1^.g] + Colors[100-p2^.r, p3^.g]);
p1^.b := AdjustColor(Colors[p2^.r, p1^.b] + Colors[100-p2^.r, p3^.b]);
p1 := Pointer(Integer(p1) + 3);
p2 := Pointer(Integer(p2) + 3);
p3 := Pointer(Integer(p3) + 3);
end;
p1 := Pointer(Integer(p1) + Gap);
p2 := Pointer(Integer(p2) + Gap);
p3 := Pointer(Integer(p3) + Gap);
end;
end;

begin
if (Gradient = gsNone) and (BandRate >= 100) then Exit;
Rates := nil;
Tmp := nil;
if (Gradient <> gsNone) then
begin
Rates := TBitmap.Create;
Rates.PixelFormat := pf24Bit;
Rates.Width := Tag.Width;
Rates.Height := Tag.Height;
if (BandRate > 0) or (FromRate > 0) then
CreateGradient(Rates, FromRate, BandRate, Gradient, GradCenter, GradStep)
else
CreateGradient(Rates, FromColor, BandColor, Gradient, GradCenter, GradStep);
end;
if Assigned(Src) and not Src.Empty and (BandRate>0) and (BandRate < 100) then
begin
Tmp := TBitmap.Create;
Tmp.PixelFormat := pf24Bit;
Tmp.Width := Tag.Width;
Tmp.Height := Tag.Height;
TiledDraw(Tmp);
end;
case BandRate of
0: begin
if Assigned(Rates) then
if FromRate > 0 then
GradDraw
else
BitBlt(Tag.Canvas.Handle, 0, 0, Tag.Width, Tag.Height,
Rates.Canvas.Handle, 0, 0, SRCCOPY)
else if Assigned(Src) and not Src.Empty then
TiledDraw(Tag)
else begin
Br := CreateSolidBrush(BandColor);
FillRect(Tag.Canvas.Handle, Rect(0, 0, Tag.Width, Tag.Height), br);
DeleteObject(Br);
end;
end;
else begin
if not Assigned(Tmp) and not Assigned(Rates) then
TransLucent
else if not Assigned(Rates) then TransBlend
else if not Assigned(Tmp) then GradDraw
else GradBlend;
end;
end;
FreeAndNil(Rates);
FreeAndNil(Tmp);
end;

var
StepX, StepY: Integer;

Initialization

for StepY := 0 to 100 do
for StepX := 0 to 255 do
Colors[StepY, StepX] := StepY * StepX div 100;
end.
 
多人接受答案了。
 
后退
顶部