----->> 图片处理问题:拖动鼠标选择裁切区域时,让区域外的图像变暗,怎么实现? <<--(100分)

  • 主题发起人 主题发起人 starsite
  • 开始时间 开始时间
S

starsite

Unregistered / Unconfirmed
GUEST, unregistred user!
要的是以下这种效果:
http://ftp.mobtime.com/tmp/zhezhao.jpg
 
给你个例子,放个image,加载一幅图片
注意!!image一定要Stretch:=false;
如果一定要缩放图片,请先把图片外面缩放完毕后再加载到image

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, jpeg, StdCtrls;

type
TForm1 = class(TForm)
Image1: TImage;
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
sdimg:Timage;
mdpt:TPoint;
public
{ Public declarations }
end;

const
CL_BG=clgray; {蒙版颜色,自己改}

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure ATGBitMap(var bmp:TBitMap;TR,TG,TB:byte;
alpha:smallint;WPixel:integer);
var
mb,mg,mr,
tmpg,i,j:integer;
p:PByteArray;
begin
j:=255-Alpha;
mb:=TB*j;
mg:=TG*j;
mr:=TR*j;
for i:=bmp.height-1 downto 0 do
begin
p:=bmp.ScanLine;
j:=0;
while j<WPixel do
begin
tmpg := (p[j]*28+p[j+1]*151+p[j+2]*77) shr 8*Alpha;
p[j]:=(tmpg+mb) shr 8;
p[j+1]:=(tmpg+mg) shr 8;
p[j+2]:=(tmpg+mr) shr 8;
inc(j,3);
end;
end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
bmp:TBitMap;
begin
with TImage(Sender) do
begin
sdimg:=TImage.Create(Parent);
sdimg.SetBounds(left,top,width,height);
sdimg.Parent:=parent;
bmp:=TBitMap.Create;
try
bmp.Assign(picture.Graphic);
ATGBitMap(bmp,
GetRValue(CL_BG),GetGValue(CL_BG),GetBValue(CL_BG),
100,bmp.Width*3);
sdimg.Picture.Assign(bmp);
finally
bmp.Free;
end;
mdpt.X:=x;
mdpt.Y:=y;
end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if assigned(sdimg) then
sdimg.Free;
sdimg:=nil;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
bmp,tmpbmp:tbitmap;
begin
if assigned(sdimg) then
with TImage(Sender) do
begin
bmp:=tbitmap.Create;
tmpbmp:=tbitmap.Create;
try
bmp.Assign(picture.Graphic);
tmpbmp.Assign(picture.Graphic);
ATGBitMap(bmp,
GetRValue(CL_BG),GetGValue(CL_BG),GetBValue(CL_BG),
100,bmp.Width*3);
bmp.Canvas.CopyRect(rect(mdpt.X,mdpt.Y,x,y),tmpbmp.Canvas,rect(mdpt.X,mdpt.Y,x,y));
sdimg.Picture.Assign(bmp);
finally
bmp.Free;
tmpbmp.Free;
end;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
image1.Parent.DoubleBuffered:=true;
end;

end.
 
这个方式我考虑过,是否可能通过更简单的运算达到想要的效果呢?
比如“遮罩层”控件通过与底层进行Canvas的运算来达到这中效果?
 
更简单的运算? 我给的方法运算很复杂吗?只不过是一个图像的半透明叠加算法而已

或者说,你想用现有的东西,写几行代码就要达到这种效果,而不想看到那么多计算的代码?

还有一种方法,我就不给出代码了,说说思路吧...还是先创建一个image,然后建立一个png图像,设置图像颜色为灰色,整体透明度50%,然后设置选择区域的透明度100%,把这个png图像加载到新建的image

你要是觉得在image上再加个image显的不专业的话,就先找个bitmap变量保存原始图像,然后每次计算后的图像直接显示到原来image上
 
谢谢hs-kill的耐心讲解,
我指的复杂,不是算法本身,实际上是担心在图片较大效率会比较低下。。。
因为鼠标拖动选框时需要刷新,这样的计算量还是不小的。
所以我在考虑是否能先设定一个掏空的hRgn,用相对快速的CANVAS作图,比如XOR,来完整这样的效果。

我抽空把几种方案都测试一下,看看那种更为快速有效,而且能让代码维护方便。
或许还有其他方法 :)

再次感谢!
 
哦~~呵呵,我改进了下,下面的代码我经过测试2304*1728的图像一点也不卡
主要是用蒙版一次生成后保存,以后每次重画更新的区域


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, jpeg, ExtCtrls;

type
TForm1 = class(TForm)
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
sdimg:Timage;
sdbmp:TBitMap; {增加个变量保存蒙版}
mdpt,mlpt:TPoint; {增加个变量保存上次的选区}
public
{ Public declarations }
end;

const
CL_BG=clgray; {蒙版颜色,自己改}

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure ATGBitMap(var bmp:TBitMap;TR,TG,TB:byte;
alpha:smallint;WPixel:integer);
var
mb,mg,mr,
tmpg,i,j:integer;
p:PByteArray;
begin
j:=255-Alpha;
mb:=TB*j;
mg:=TG*j;
mr:=TR*j;
for i:=bmp.height-1 downto 0 do
begin
p:=bmp.ScanLine;
j:=0;
while j<WPixel do
begin
tmpg := (p[j]*28+p[j+1]*151+p[j+2]*77) shr 8*Alpha;
p[j]:=(tmpg+mb) shr 8;
p[j+1]:=(tmpg+mg) shr 8;
p[j+2]:=(tmpg+mr) shr 8;
inc(j,3);
end;
end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
with TImage(Sender) do
begin
sdimg:=TImage.Create(Parent);
sdimg.SetBounds(left,top,width,height);
sdimg.Parent:=parent;
sdbmp:=TBitMap.Create;
sdbmp.Assign(picture.Graphic);
ATGBitMap(sdbmp,
GetRValue(CL_BG),GetGValue(CL_BG),GetBValue(CL_BG),
100,sdbmp.Width*3);
sdimg.Picture.Assign(sdbmp);
mdpt.X:=x;
mdpt.Y:=y;
mlpt.X:=x;
mlpt.Y:=y;
end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if assigned(sdimg) then
sdimg.Free;
sdimg:=nil;
if assigned(sdbmp) then
sdbmp.Free;
sdbmp:=nil;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
rc:TRect;
begin
if assigned(sdimg) then
begin
with TImage(Sender) do
begin
rc:=rect(mdpt.X,mdpt.Y,mlpt.X,mlpt.Y);
sdimg.Canvas.CopyRect(rc,sdbmp.Canvas,rc);
rc:=rect(mdpt.X,mdpt.Y,x,y);
sdimg.Canvas.CopyRect(rc,Canvas,rc);
end;
mlpt.X:=x;
mlpt.Y:=y;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
bmp:TBitMap;
begin
image1.Parent.DoubleBuffered:=true;
bmp:=TBitMap.Create;
try {这里最好先把image里的图像改为bmp格式,免的每次获取图像时都要转换}
bmp.Assign(image1.Picture.Graphic);
image1.Picture.Assign(bmp);
finally
bmp.Free;
end;
end;

end.
 
后退
顶部