PHOTOSHOP流动型选取边框

 

学习编程真是一件艰苦的事情。不过,对于我们编程的人来说,肯定感觉它也是最有趣的。当我们苦苦思索都无法实现一个功能时,我们并不会感觉苦恼,强烈的求知欲足以使我们忘掉一切。而当我们终于实现了,那种柳暗花明、豁然开朗、拨云见日出的玄妙感觉真是只可意会不可言传。我相信,大多数的共享软件、免费软件不是因为作者不想赚钱,而是因为程序员更愿意把自己的旷世绝招惊天一式炫耀给大家看。

有很多学习编程的人问我,怎样提高自己的水平。哦,我的回答可能和别人有点不同呵。我认为不要抱着书本,等全部都弄明白了再来编程。懂得一点就可以动手了。那我们编什么呢?很简单,我们试着实现别的优秀的软件里实现的功能,看看我们能不能实现它。这样,大家的水平一定提高得很快哦。

比如说,POTOSHOP里的喷枪是怎样实现的呢?

我们可以这样思考:喷枪的形状我们可以通过改变鼠标的形状得到,这样我们就前进一步了。我们把剩下的问题简化,可以先不考虑喷枪的强弱,而将问题简化成如何在鼠标的周围的一定范围内画点。具体的方法不需要我再罗嗦了吧?然后我们再慢慢添加线形、色彩、强弱等其它功能,喷枪我们就算完成了。

今天我要实现的是POTOSHOP里流动的选取边框功能。

POTOSHOP里,当我们选取部分图形时,它的选取边框是流动式的。在其他的画图看图软件里可不是这样的哦,比如说ACDSEE。如果在我们的程序中使用这项功能,感觉一定很酷。不过,它是怎样实现的呢?

一开始我也认为很简单。矩形的流动选取边框很容易实现吗。不过,在POTOSHOP里,套索等其他不规则的选取边框都是流动型的。

我是这样解决问题的。

首先,在不知怎么入手时,要选择合适的关键词来查找资料。你会选择什么词?这就要凭借个人的经验了。我注意到“划线”(Line)和“路径”(Path)两个词。你也首先会选Line这个词吧?为什么我会选Path呢?哎,这就是感觉了,我也说不清楚,不过,随着你编程越来越多(实际呢,我曾经编过空心字的程序,所以有过这方面的经验了)。废话少说,先试试帮助文件吧,还不必动用MSDN。依次打开DELPHI的帮助Help——>Windows SDK,输入关键字Line或者Path,真的不错,出来一堆函数。不管有没有用,都先看看吧,就当作是一次学习。不过,我的运气真好:两个关键字都命中了目标!如果没有命中怎么办?多选几个啦。不过,不要选对了都不知道噢。

在这里,我们关键要阅读一下LineDDA函数的说明。

我们下一步就是来编程试验一下了。我选择建立一个流动的字体边框,就像是霓虹灯的那种效果。

程序如下,程序我加了详细的注释。没想到程序会这么短吧。

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, ExtCtrls, StdCtrls;

 

type

  TForm1 = class(TForm)

    Button1: TButton;

    Timer1: TTimer;

    procedure Button1Click(Sender: TObject);

    procedure Timer1Timer(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  pathpoints :array [0..1000] of TPoint;

  PathTypes:array [0..1000] of byte;

  PPts :PPoint;

  PTypes :PByteArray;

  Number :Integer;

  Counter :Byte;

 

 

implementation

 

{$R *.dfm}

 

 // MovingDots的格式可是预定好的。你可阅读LineDDA的帮助。

 //这里我用它来定义流动线的色彩。

 //注意了:MovingDots是一个CALLBACK函数,需加上stdcall关键字。

procedure MovingDots(X,Y: Integer; TheCanvas: TCanvas); stdcall;

begin

  if counter=15 then counter:=0;

  if counter<5 then

    TheCanvas.Pixels[X,Y] :=clWhite

  else if counter<12 then

    TheCanvas.Pixels[X,Y] :=clred

  else

    TheCanvas.Pixels[X,Y] :=clBlue;

    inc(counter);

end;

 

//Timer1Interval我设置为100

//如果你在编程时感觉到字体闪烁,你可以调整Interval、流动线色彩长度、字体

//比如在本程序中,去掉字体[fsItalic]属性,你就会感到闪烁。

//甚至字数也闪烁的程度影响。你只能综合这些因素慢慢调试。

procedure TForm1.Timer1Timer(Sender: TObject);

var

  J ,k:Integer;

begin

  //你用过Pred函数吗?这儿你也可以用Number-1代替。

  //你知道它们的区别吗?哈哈。

  for J := 0 to Pred(Number) do

  begin 

     //当前点与下一个关键点使用MovingDots的方法相连     LineDDA(PathPoints[J].X,PathPoints[J].Y,PathPoints[J+1].X,PathPoints[J+1].Y,

              @MovingDots,LongInt(Form1.Canvas))

  end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  Canvas.Font.Name := '幼圆'; //这里的字体一定要是TrueType Font

  Canvas.Font.size := 72;

  Canvas.Font.style := [fsItalic,fsBold];//最好设置为粗体字,这样轮廓大一些

  beginpath(canvas.handle); //开始捕获 Canvas上绘制的轮廓

    //使用SetBkMode去除文字外框,你可以不使用它,比较一下效果

    SetBkMode( Canvas.Handle, TRANSPARENT );

    canvas.TextOut(120,20,'电脑');

  endpath(canvas.handle); //结束捕获

 

  //使用FlattenPath使轮廓平滑,你可以不使用它,比较一下效果

  if FlattenPath(Canvas.Handle)then

  begin

   //得到轮廓的控制点

    PPts := nil;

    PTypes := nil;

    Number := GetPath(Canvas.Handle,PPts,PTypes,0);

    Number := GetPath(Canvas.Handle,PathPoints,PathTypes,Number);

  end; 

end;

 

end.

效果如图:

上边怎么有那么多杂线?

为了去掉这些杂线,我熬了整个通宵。怪就怪我没有好好的看帮助啊。你也跟踪一下PathTypes这个数组的内容吧,然后再读一遍关于它的帮助。

PT_MOVETO:相当于线段的起点啦。

PT_CLOSEFIGURE:相当于封闭曲线的结束点,与相对的PT_MOVETO连接构成一个封闭的曲线。

现在你知道毛病出在那儿了吧?我们举的例子“电脑” 两个字是由多个封闭的曲线组成的。在我们的程序中,一条曲线的PT_CLOSEFIGURE并没有与相对的PT_MOVETO连接构成一个封闭的曲线,而是与下一条曲线的起点连接了。那条从(00)点斜拉的线段是由于PathPoints最终点后的数据都是0

知道了这些,程序就好改动了。把下面的几个句子输到LineDDA函数前:

if PathTypes[j]=3 then  //如果是曲线的终点。为什么是3呢?

//注意,我没有用PT_MOVETO来判断。

     begin

         for k:=J downto 0 do

         begin

           if  PathTypes[k]=6 then //找到对应的曲线起点。为什么是6呢?

                          //注意,我没有用PT_CLOSEFIGURE来判断。

           begin 

//把终点和起点连接起来构成一条封闭的曲线。           LineDDA(PathPoints[J].X,PathPoints[J].Y,PathPoints[k].X,PathPoints[k].Y,

              @MovingDots,LongInt(Form1.Canvas));

             break;

           end;

         end;

         continue;

     end;

这次可以了,效果不错吧?如图:

不知道你从本次编程中学到点什么没有。你有什么心得也可以和我交流啊。我的QQ号为44065089,呢称吗,就是寒夜看雪。

本程序在DELPHI7.0+WIN ME下通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值