CnPack Forum » CnVCL 组件包 » AAFont字体描边及32位图像处理


2005-10-10 09:38 croslq
AAFont字体描边及32位图像处理

使用BeginPath, EndPath, FillPath函数
下载地址: [url]http://lqcros.go1.wy8.net/NewAAFont2.63.rar[/url]

我觉得要制作更多的字体效果的话,最好是用,32位图像来制作
TBitmap就支持这个功能,不过,图像合成时需要一个函数CombineAlphaPixel(函数附后,这个函数是FLib里的)
使用Bitmap时请把他设成32位的,如: PixelFormat := pf32Bit;

//===================================================================
// 计算两个32bit象素的等效象素,这个函数非常重要(speed),安全检查就不做了
// cr1:背景    cr2:前景


// 这两个函数引用自FLIB //
// 只处理目标ALPHA通道时,两个函数可以替换到用 //

// :o 注意这里一下, 替换时请在DrawTo,DrawFrom 里面替换就可以了

//这个函数是以目标像素及源像素的Alpha通道合成
procedure  TBitmap32.CombineAlphaPixel(var pDest: TRGBQuad; cr1: TRGBQuad; nAlpha1: integer; cr2: TRGBQuad; nAlpha2: integer);
var
    nTmp1, nTmp12, nTemp, nTmp2: integer;
begin
        if ((nAlpha1 <> 0) or (nAlpha2 <> 0)) then
        begin
                if (nAlpha2 = 0) then
                begin
                        pDest.rgbBlue  := cr1.rgbBlue ;
                        pDest.rgbGreen := cr1.rgbGreen ;
                        pDest.rgbRed  := cr1.rgbRed ;
                        pDest.rgbReserved := nAlpha1 ;
                        exit;
                end;
                if ((nAlpha1 = 0) or (nAlpha2 = $FF)) then
                begin
                        pDest.rgbBlue  := cr2.rgbBlue ;
                        pDest.rgbGreen := cr2.rgbGreen ;
                        pDest.rgbRed   := cr2.rgbRed ;
                        pDest.rgbReserved := nAlpha2 ;
                        exit;
        end;


                // 以下用不着判断[0,0xFF],我验算过了
                nTmp1 := $FF * nAlpha1;
        nTmp2 := $FF * nAlpha2 ;
                nTmp12 := nAlpha1 * nAlpha2;
                nTemp  := nTmp1 + nTmp2 - nTmp12 ;
                pDest.rgbBlue  := (nTmp2 * cr2.rgbBlue  + (nTmp1 - nTmp12) * cr1.rgbBlue)  div nTemp ;
                pDest.rgbGreen := (nTmp2 * cr2.rgbGreen + (nTmp1 - nTmp12) * cr1.rgbGreen) div nTemp ;
                pDest.rgbRed   := (nTmp2 * cr2.rgbRed   + (nTmp1 - nTmp12) * cr1.rgbRed)   div nTemp ;
                pDest.rgbReserved := nTemp div $FF ;


//                下面的代码是未优化过的,可读性更好些
{
                nTemp :=  $FF * (nAlpha1 + nAlpha2) - nAlpha1*nAlpha2 ;
                pDest.rgbBlue  := min($FF, ($FF * cr2.rgbBlue  * nAlpha2 + ($FF - nAlpha2) * cr1.rgbBlue  * nAlpha1) div nTemp) ;
                pDest.rgbGreen := min($FF, ($FF * cr2.rgbGreen * nAlpha2 + ($FF - nAlpha2) * cr1.rgbGreen * nAlpha1) div nTemp) ;
                pDest.rgbRed   := min($FF, ($FF * cr2.rgbRed   * nAlpha2 + ($FF - nAlpha2) * cr1.rgbRed   * nAlpha1) div nTemp) ;
                pDest.rgbReserved := nTemp div $FF ;
}
        end
        else
        begin
                pDest.rgbBlue  := $FF;
        pDest.rgbGreen := $FF;
        pDest.rgbRed   := $FF;
                pDest.rgbReserved := 0 ;
        end;
end;

如:
            CombineAlphaPixel(Target^[x], Target^[x], Target^[x].rgbReserved, Source^[x - DstX], Source^[x- DstX].rgbReserved);

// 这个函数就更重要了,安全检查当然不做了:-),根据pSrc中的alpha计算,nAlphaSrc一定要保证在0,0xFF之间

//这个函数只是以源像素的Alpha通道合成
procedure TBitmap32.AlphaBlendPixel(var pDest: TRGBQuad; pSrc: TRGBQuad);
begin
    if (pSrc.rgbReserved = $FF) then
    begin
        PRGBArray(pDest) := PRGBArray(pSrc);
        exit;
    end;

    if (pSrc.rgbReserved = 0) then
    exit;
    // 以下用不着判断[0,0xFF],我验算过了

    if (PRGBArray(pSrc) <> PRGBArray(pDest)) then
    begin
        pDest.rgbBlue := (PSrc.rgbBlue - pDest.rgbBlue) * pSrc.rgbReserved div $FF + pDest.rgbBlue;
        pDest.rgbGreen := (PSrc.rgbGreen - pDest.rgbGreen) * pSrc.rgbReserved div $FF + pDest.rgbGreen;
        pDest.rgbRed := (PSrc.rgbRed - pDest.rgbRed) * pSrc.rgbReserved div $FF + pDest.rgbRed;
    end;
end;

如:
    AlphaBlendPixel(Target^[x], Source^[x]);


    //:o:o:o:o:o:o:o//
{    把这个函数写到DrawTo函数以替换CombineAlphaPiexl
     
图层的概念
[
最下层是画布(就是一个TBitmap32对像,也可以是Image1.Picture.Bitmap)
跟着上面的就是图层啦,文字层什么的
]


从最下层的32位图像画起
就可以把许多个32位图层到画布上,显示出来


procedure TBitmap32.DrawTo(DstX, DstY: Integer; Tge: TBitmap);
var
    x, y: integer;
    TR, SR: TRect;
    Source, Target: pRGBQuadArray;
begin
    Tge.PixelFormat := pf32bit;
    SetAlphaChannels(Tge, $FF);

    Tr := Rect(0, 0, Tge.Width, Tge.Height);
    SR := Rect(DstX, DstY, DstX + Width, DstY + Height);

    if IntersectRect(Tr, Tr, SR) = false then
    exit;

    for y := Tr.Top to Tr.Bottom - 1 do
    begin
        Target := Tge.ScanLine[y];
        Source := ScanLine[y - Dsty];


        for x := Tr.Left to Tr.Right - 1 do
        begin
//这里替换了
//            CombineAlphaPixel(Target^[x], Target^[x], Target^[x].rgbReserved, Source^[x - DstX], Source^[x- DstX].rgbReserved);
            AlphaBlendPixel(Target^[x], Source^[x]);
        end;


    end;

end;

for i := 0 to LayerList.Count -1 do
begin
    TBitmap32(LayerList.Items[i ]).DrawTo(0,0, Image1.Picture.Bitmap);
end;

}


    //:o:o:o:o:o:o//

[[i] Last edited by croslq on 2005-10-15 at 14:39 [/i]]

2005-10-10 10:21 croslq
请高手把上面哪个函数MMX优化一下

请高手把上面哪个函数MMX优化一下,不然哪个性能就有点差了哈

2005-10-10 10:23 croslq
TBitmap32的可以这样实现

type
   TBitmap32 := class(TBitmap)


   end;

2005-10-10 10:25 croslq
哈哈这样就可以处理32位图像了三

type
  TBitmap32 = class(TBitmap)
  private

  protected
  public
    constructor Create; override;
    destructor Destroy; override;

    procedure Assign(Source: TPersistent); override;                //重载,设置为32位
    procedure LoadFromFile(const Filename: string); override;       //重载,设置为32位
  end;



constructor TBitmap32.Create;
begin
    inherited Create;
    PixelFormat := pf32bit;
end;

destructor TBitmap32.Destroy;
begin
    inherited Destroy;
end;

procedure TBitmap32.LoadFromFile(const Filename: string);
begin
    inherited LoadFromFile(FileName);
    PixelFormat := pf32bit;
end;

procedure TBitmap32.Assign(Source: TPersistent);
begin
    inherited Assign(Source);
    PixelFormat := pf32bit;
end;

2005-10-10 10:29 croslq
TBitmap32的可以这样实现

TBitmap32的FillRect不要使用,因为处理的颜色不是32位

procedure FillLongword(var X; Count: Integer; Value: Longword);
asm
// EAX = X
// EDX = Count
// ECX = Value
        PUSH    EDI

        MOV     EDI,EAX  // Point EDI to destination              
        MOV     EAX,ECX
        MOV     ECX,EDX
        TEST    ECX,ECX
        JS      @exit

        REP     STOSD    // Fill count dwords
@exit:
        POP     EDI
end;

procedure  TBitmap32.Clear(color: TColor32);
var
    x, y: integer;
    t1: int64;
begin

    t1 := timegettime;
    {
    for y := 0 to Height-1 do
    for x := 0 to Width-1 do
    SetPixel(x, y, Color);
    }
//    ZeroMemory(GetBits, Height* width *4);


    FillLongword(GetBits^[0], Width * Height, Color);

    TraceString(IntToStr(timegettime-t1));

end;

2005-10-10 10:56 zjy
有个开放源码的 Graphi32 项目就是专门做 32 位位图处理的,里面有 MMX 优化的。
[url]http://www.graphics32.org/[/url]

2005-10-10 14:10 zjy
没地方上传,也可以用附件放到论坛上来。

2005-10-10 14:16 croslq
这样的说。好的

OK,知道了

2005-10-10 14:19 croslq
这个是你们网站的AAFont,我加了描边的

这个是你们网站的AAFont,我加了描边的,因为上次给你发了一个,不过性能不佳,
终于找到哪个原因,是因为StrokePath这个微软的函数本身就性能差

2005-10-10 14:29 zjy
好,那我把那些链接不能下载的帖子删除吧?

2005-10-12 20:34 croslq
我用G32库里的BlendLine函数(MMX优化)测试了一下,性能没有明显的提高
可能是DELPHI的编译本身就带有pentium优化

2005-10-12 21:07 croslq
上面这个32位图像处理的方法,可以开发字体特效(抗锯齿,字体的纹理填充,阴影,描边及描边的纹理填充),也可以开发其他的如图像处理软件(图层什么的),只要再在里面加入一部分功能(如:画线、矩形,非规则区域选择<ALPHA通道(把ALPHA作为一个MASK处理就行)>......)。。。。。。

刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-13 at 14:06 [/i]]

2005-10-13 08:53 croslq
font32image.rar包里面一个GraphicEx库,通过他可以打开TGA,PSD,BMP,TIFF等图像文件。
我一般是用他来打开32位TGA图像或32位BMP图像,然后通过32位图像处理函数里的DrawTo函数输出到屏幕,DrawTo有2个重载函数,一个是把self写到32位图像,一个是把self写到一般的Tbitmap。
例:
    Bitmap.DrawTo(0,0,Image1.Picture.Bitmap);


刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-13 at 14:07 [/i]]

2005-10-13 09:19 croslq
刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-13 at 14:07 [/i]]

2005-10-13 13:50 croslq
其实 CreateFontIndirect 这个函数就能输出抗锯齿的字体啦

Delphi这样使用:

procedure TForm1.Button1Click(Sender: TObject);
var
  lf : TLogFont;
  Bitmap: TBitmap;
begin
    Bitmap := TBitmap.create;
    Bitmap.Width := 400;
    Bitmap.Height := 200;

    Bitmap.Canvas.Font.Name := '华文行楷';
    Bitmap.Canvas.Font.Size := 72;
    Bitmap.Canvas.Font.Style := [fsBold, fsItalic, fsUnderline, fsStrikeOut];
    GetObject(Bitmap.Canvas.Font.Handle, SizeOf(TLogFont), @lf);
    lf.lfQuality := ANTIALIASED_QUALITY;   //设置输出质量(抗锯齿)
    Bitmap.Canvas.Font.Handle := CreateFontIndirect(lf);
    Bitmap.Canvas.TextOut(0,0,'平滑字体');
    Image1.Picture.Bitmap.Assign(Bitmap);
    Bitmap.Free;
end;


刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-13 at 14:13 [/i]]

2005-10-13 14:03 croslq
通过函数 GetGlyphOutline 可以取得 TrueType 字体的轮廓,就可以描边啦
可以参考网址:[url]http://www.legalsoft.com.cn/articles/show.asp?id=269[/url]

也可以使用beginPath, EndPath, GetPath 提取


        FPathPoints: array of TPoint;
        FPathTypes: array of Byte;
        FNumber: Integer;
        PointIdx: integer;

  BeginPath(GrayBmp.Canvas.Handle);
    SetBkMode(GrayBmp.Canvas.Handle, TRANSPARENT);
    GrayBmp.Canvas.TextOut(0, 0, Text);
  EndPath(GrayBmp.Canvas.Handle);

  FNumber := GetPath(GrayBmp.Canvas.Handle, Pointer(nil^), Pointer(nil^), 0);
  SetLength(FPathPoints, FNumber);
  SetLength(FPathTypes, FNumber);
  FNumber := GetPath(GrayBmp.Canvas.Handle, FPathPoints[0], FPathTypes[0], FNumber);

  PointIdx := 0;  

//+++  描边//
    while PointIdx < FNumber do begin

    case FPathTypes[PointIdx] of PT_MOVETO:
        begin
            GrayBmp.Canvas.MoveTo(FPathPoints[PointIdx].X, FPathPoints[PointIdx].Y);
            LastMove := FPathPoints[PointIdx];
            inc(PointIdx, 1);
        end;
        PT_LINETO:
        begin
            GrayBmp.Canvas.LineTo(FPathPoints[PointIdx].X, FPathPoints[PointIdx].Y);
            inc(PointIdx, 1);
        end;
        PT_BEZIERTO:
        begin
            PolyBezierTo(GrayBmp.Canvas.Handle, FPathPoints[PointIdx], 3);
            inc(PointIdx, 3);
        end;
        PT_LINETO or PT_CLOSEFIGURE:
        begin
            GrayBmp.Canvas.LineTo(FPathPoints[PointIdx].X, FPathPoints[PointIdx].y);
            GrayBmp.Canvas.LineTo(LastMove.x, LastMove.y);
            inc(PointIdx, 1);
        end;
        PT_BEZIERTO or PT_CLOSEFIGURE:
        begin
            PolyBezierTo(GrayBmp.Canvas.Handle, FPathPoints[PointIdx], 3);
            GrayBmp.Canvas.LineTo(LastMove.x, LastMove.y);
            inc(PointIdx, 3);
        end;
    end;
    end;


  SetLength(FPathPoints, 0);
  SetLength(FPathTypes, 0);

刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-13 at 14:07 [/i]]

2005-10-15 14:44 croslq
32位图层(随手写的,没测试,你们看一下原理就行了哈:P)

type
   TLayerList = class(TList)
   private

   end;

Bitmap32 : TBitmap32;
LayerList := TLayerList.Create;

Bitmap32 := TBitmap32.Create;
Bitmap32.LoadFromFile('1.tga');
LayerList.Items.add(Bitmap32);


for i := 0 to LayerList.Count -1 do
begin
    TBitmap32(LayerList.Items[i ]).DrawTo(0,0, Image1.Picture.Bitmap);
end;


for i := 0 to LayerList.Count -1 do
begin
TBitmap32(LayerList.Items[i ]).Free;
end;
LayerList.Free;

刘 强 2005.10.13
邮箱地址:[email]lqcros@163.com[/email]
主页地址:[url]http://lqcros.go1.wy8.net[/url]

[[i] Last edited by croslq on 2005-10-15 at 14:45 [/i]]

2005-10-15 18:02 croslq
MMX优化AlphaBlendPixel

//                             TColor32(AARRGGBB)     TColor32        0 .. 255
//                                 |            |                |
//               AlphaBlendPixel(Source^[x], Target^[x], AlphaComponent(Source^[x]));
procedure AlphaBlendPixel(Source: TColor32; var Target: TColor32; Alpha: DWORD);
asm
    MOVD            MM1, EAX        // MM1 = 00 00 00 00 ** Fr Fg Fb
    MOVD            MM2,[EDX]      // MM2 = 00 00 00 00 ** Br Bg Bb
    PUNPCKLBW MM1, MM0       // MM1 = 00 ** 00 Fr 00 Fg 00 Fb
    MOVD            MM3, ECX       // MM3 = 00 00 00 00 00 00 00 AA  
    PUNPCKLBW MM2, MM0       // MM2 = 00 ** 00 Br 00 Bg 00 Bb
    PSHUFW       MM3, MM3, 0   // MM3 = 00 AA 00 AA 00 AA 00 AA
    PSUBW         MM1, MM2
    PSLLW          MM2, 8
    PMULLW       MM1, MM3
    PADDW         MM1, MM2
    PSRLW          MM1, 8
    PACKUSWB   MM1, MM0
    MOVD           [EDX],MM1
    emms
end;

[[i] Last edited by croslq on 2005-10-15 at 20:30 [/i]]

2005-10-17 15:40 croslq
抗锯齿直线的实现

附件里的自定义的画笔(掩码图),它本身边缘就是羽化了的,所以就能抗锯齿
下面画线函数,首先确定直线的每一点的坐标,然后把自定义画笔画到这个坐标上,直到画完线
:P:P:P(这个抗锯齿直线就画起了三)

这个方法还可以反走样字体的边缘啦
在哪个EndPath后面
加一个FlattenPath函数(平整为直线的)
16楼哪个画直线函数用这个函数替换


procedure DrawMaskPen(TargetBitmap: TBitmap; DstX, DstY: Integer; Mask8: TBitmap);
var
    Source, Target: PByteArray;
    TR, SR: TRect;
    x, y: integer;   
begin

    TR := Rect(0, 0, TargetBitmap.Width, TargetBitmap.Height);
    SR := Rect(DstX, DstY, DstX + Mask8.Width, DstY + Mask8.Height);

    if IntersectRect(TR, TR, SR) = false then
    exit;

    for y := Tr.Top to Tr.Bottom - 1 do
    begin
        Target := TargetBitmap.ScanLine[y];
        Source := Mask8.ScanLine[y - Dsty];
        for x := TR.Left to Tr.Right - 1 do
        begin
            if (Target^[x] + Source^[x - Dstx]) > 255 then
            Target^[x] := 255
            else
            Target^[x] := Target^[x] + Source^[x - Dstx];
        end;
    end;   
end;


//采用Bresenham算法绘制一条颜色相同的直线
//将Bresenham算法写成统一的形式
//x1, y1, x2, y2直线的起点和端点
//通过附件里自定义的画笔,实现了8位蒙板图画抗锯齿直线

procedure LineMaskPen(Target8: TBitmap; x1, y1, x2, y2: integer; MaskPen8: TBitmap);
var
    nDx, nDy: integer;
    nIx, nIy: integer;
    nInc: integer;
    nJudgeX, nJudgeY: integer;
    x, y: integer;
    nTwoIx, nTwoIy: integer;
    i: integer;
    bPlot: boolean;

begin
        //两端点间的水平偏移量和垂直偏移量
        nDx := x2 - x1;
        nDy := y2 - y1;

        //两端点间的水平距离和垂直距离
        nIx := ABS(nDx);
        nIy := ABS(nDy);

        //描点步数(增量总值)
        nInc := MAX(nIx, nIy);

        //绘制第一个点, 即, 直线的起点
//        SetPixel(hdc, x1, y1, clr);
    DrawMaskPen(Target, x1- MaskPen8.Width div 2, y1 - MaskPen8.Height div 2, MaskPen8);

        //不包含终点
        if(nInc < 2) then
    exit;

        //用于判断是否在nJudgeX, nJudgeY方向上向前进
        nJudgeX := -nIy;
    nJudgeY := -nIx;

        //通过增量计算得到的当前点
        x := x1;
    y := y1;
       
        //开始进行增量计算
        //采用Bresenham算法.在这里, 我们将算法进行改进,
        //使其对于任意斜率的直线都能绘制, 而且绘制方向始终为从起点绘制到终点

        //注意, 整数乘2在计算机中采用移位实现
        //Bresenham算法
        nTwoIx := 2 * nIx;
    nTwoIy := 2 * nIy;

        //与Windows相对应, 该算法也不包含最后一个点(x2, y2)
        dec(nInc);

        //开始增量计算
        for i := 0  to nInc -1 do
    begin
                nJudgeX := nJudgeX + nTwoIx;
                nJudgeY := nJudgeY + nTwoIy;

                //通过增量法计算的当前点是否属于直线上的点
                bPlot := FALSE;

                //检测 X 方向
                if(nJudgeX >= 0) then
                begin
                        bPlot := TRUE;
                        nJudgeX := nJudgeX - nTwoIy;

                        //将任意走向的直线统一起来
                        if(nDx > 0) then
            inc(x)
                        else if(nDx < 0) then
            dec(x)
                end;

                //检测 Y 方向
                if(nJudgeY >= 0) then
                begin
                        bPlot := TRUE;
                        nJudgeY := nJudgeY - nTwoIx;

                        //将任意走向的直线统一起来
                        if(nDy > 0) then
            inc(y)
                        else if(nDy < 0) then
            dec(y);
                end;
                //如果当前点在直线上, 则绘制当前点
                if(bPlot) then
//        SetPixel(hdc, x, y, clr);
        DrawMaskPen(Target, x- MaskPen8.Width div 2, y- MaskPen8.Height div 2, MaskPen8);
        end;//end for  
end;

//画32位色直线这样画啦
var
   Bitmap: TBitmap32;
   Mask: TBitmap;
begin
   Bitmap := TBitmap32.Create;
   Bitmap.Width := 500;
   Bitmap.Height := 500;
   Mask := TBitmap.Create;
   Mask.Width := 500;
   Mask.Height := 500;
   
   Image1.Picture.Bitmap.PixelFormat := pf8bit;
   LineMaskPen(Mask, 0, 0, 200, 200, Image1.Picture.Bitmap);  //Image1.Picture.Bitmap 这里保存的是附件里的8位自定义画笔

   Bitmap.Clear($FFFF0000);         //设为红色
   Bitmap.SetAlphaChannels(Mask);   //只有线条显示

   Bitmap.Free;
end;

[[i] Last edited by croslq on 2005-10-17 at 15:53 [/i]]

2005-10-20 08:29 croslq
定义一个画笔类

定义画笔公用类,就像Windows里的CreatePen,
通过这个函数直接生成自定义大小的反走样8位Bitmap。

//生成掩码灰度画笔

TPenMaskBitmap = class(TBitmap)
public
    constructor Create; override;
    destructor Destroy; override;
    procedure CreateMaskBitmap(w, h: integer);
end;

constructor TPenMaskBitmap.Create;
begin
    inherited Create;
    PixelFormat := pf8bit;
end;

destructor TPenMaskBitmap.Destroy;
begin
    inherited Destroy;
end;

procedure TPenMaskBitmap.CreateMaskBitmap(w, h: integer);
begin
    //这里省了哈

end;

// 这个类在程序启动时就运行,在程序完了时就释放;
// 这个类直接生成32位色画笔,可以设定颜色,纹理,大小,透明度什么的。

TPenBitmap = class(TBitmap)  // class(TBitmap32)

public
    constructor Create; override;
    destructor Destroy; override;
    procedure CreateBitmap(w, h: integer);
end;

constructor TPenBitmap.Create;
begin
    inherited Create;
    PixelFormat := pf32bit;
end;

destructor TPenBitmap.Destroy;
begin
    inherited Destroy;
end;

procedure TPenMaskBitmap.CreateMaskBitmap(w, h: integer);
begin
    //这里省了哈

end;

2005-10-21 13:23 croslq
反走样直线

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

procedure AALine(x1,y1,x2,y2 : single; color: TColor32; Bitmap: TBitmap32);



implementation

{$R *.dfm}

procedure AALine(x1, y1, x2, y2: single; color: TColor32; Bitmap: TBitmap32);

    function CrossFadeColor(FromColor, ToColor: TColor32; Rate: Single) : TColor32;
    var
        R,G,B,A: BYTE;
    begin
//      r := Round(RedComponent(FromColor) * Rate + RedComponent(ToColor) * (1 - Rate));
//      g := Round(GreenComponent(FromColor) * Rate + GreenComponent(ToColor) * (1 - Rate));
//      b := Round(BlueComponent(FromColor) * Rate + BlueComponent(ToColor) * (1 - Rate));
//      a := Round(AlphaComponent(FromColor) * Rate + AlphaComponent(ToColor) * (1 - Rate));
        r := RedComponent(FromColor);
        g := GreenComponent(FromColor);
        b := BlueComponent(FromColor);
        a := Round(AlphaComponent(FromColor) * Rate);

      Result := RGBA(r,g,b,a); //RGB(b,g,r);
    end;

//    type
//      intarray = array[0..1] of integer;
//      pintarray = ^intarray;

procedure hpixel(x : single; y : integer);
var
  FadeRate : single;
begin
  FadeRate := x - trunc(x);
  with bitmap do
  begin
    if (x>=0) and (y>=0) and (height>y) and (width>x) then
          pColor32array(bitmap.ScanLine[y])[trunc(x)] := CrossFadeColor(Color,pColor32array(bitmap.ScanLine[y])[trunc(x)],1-FadeRate);

    if (trunc(x)+1>=0) and (y>=0) and (height>y) and (width>trunc(x)+1) then
          pColor32array(bitmap.ScanLine[y])[trunc(x)+1]:=CrossFadeColor(Color,pColor32array(bitmap.ScanLine[y])[trunc(x)+1],FadeRate);
  end;
end;

procedure vpixel(x : integer; y : single);
var
  FadeRate : single;
begin
  FadeRate:=y-trunc(y);
  with bitmap do
  begin
    if (x>=0) and (trunc(y)>=0) and (height>trunc(y)) and (width>x) then
                        pColor32array(bitmap.ScanLine[trunc(y)])[x]:=CrossFadeColor(Color,pColor32array(bitmap.ScanLine[trunc(y)])[x],1-FadeRate);

         if (x>=0) and (trunc(y)+1>=0) and (height>trunc(y)+1) and (width>x) then
         pColor32array(bitmap.ScanLine[trunc(y)+1])[x]:=CrossFadeColor(Color,pColor32array(bitmap.ScanLine[trunc(y)+1])[x],FadeRate);
         end;
end;

var i: integer;
    ly, lx, currentx, currenty, deltax, deltay, l, skipl: single;
begin
  if (x1 <> x2) or (y1 <> y2) then
  begin
//    bitmap.PixelFormat := pf32Bit;
//    Bitmap.Clear($00000000);

    currentx := x1;
    currenty := y1;
    lx := abs(x2 - x1);
    ly := abs(y2 - y1);

    if lx > ly then
    begin
      l := trunc(lx);
      deltay := (y2-y1)/l;
      if x1 > x2 then
      begin
        deltax := -1;
        skipl  := (currentx - trunc(currentx));
      end
      else
      begin
        deltax := 1;
        skipl  := 1- (currentx - trunc(currentx));
      end;
    end
    else
    begin
      l      :=  trunc(ly);
      deltax := (x2-x1)/l;
      if y1 > y2 then
      begin
        deltay := -1;
        skipl := (currenty-trunc(currenty));
      end
      else
      begin
        deltay := 1;
        skipl  := 1-(currenty-trunc(currenty));
      end;
    end;

    currentx := currentx+deltax*skipl;
    currenty := currenty+deltay*skipl;{}

    for i := 1 to trunc(l) do
    begin
      if lx > ly then
        vpixel(trunc(currentx), currenty)
      else
        hpixel(currentx, trunc(currenty));
        
      currentx := currentx + deltax;
      currenty := currenty + deltay;
    end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    bitmap: TBitmap32;
begin
    Bitmap := TBitmap32.Create;
    Bitmap.Width := 400;
    Bitmap.Height := 400;

    Image1.picture.Bitmap.Width := 400;
    Image1.picture.Bitmap.Height := 400;

    AALine(0,0, 300,100, $FFFF0000, Bitmap);
    Bitmap.DrawTo(0,0,Image1.Picture.Bitmap);


    Bitmap.Free;
end;

end.

2005-12-4 11:13 croslq
影音风暴开源项目:guliverkli
里面Subtitles有实现字幕描边,阴影代码(我觉得性能还是很好的啦)



附件里有摘录的部分代码,是关于实现字幕的(C++)

字幕编辑器(Subresync):字体输出效果

页: [1]


Powered by Discuz! Archiver 5.0.0  © 2001-2006 Comsenz Inc.