• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評論-2670  文章-0  trackbacks-0
                為了讓這篇文章說的東西能夠落實,無法躲避的基本東西還是要先準備一下的。今天花了6個小時查了無數資料終于把文字的邊框弄出來了。

                在此貼出代碼和效果圖,不作過多解釋。熟悉Win32API中的GDI部分的朋友們可以很容易看懂。

                效果圖:
                提取的輪廓:紅色和黑色為直線,藍色為四次貝塞爾曲線。其中上面是先TextOut后自己畫,下面是先自己畫后TextOut。四次貝塞爾曲線轉換成三次貝塞爾曲線之后使用PolyBezier繪制。


                代碼:
                代碼使用的框架是我自己寒假無聊的時候封裝API的結果,暫時有窗口、菜單、組合鍵以及菜單,附帶GDI。事件自己弄了一個跟C#差不多的可以同時Bind很多不同種類函數的東西。不過這個不是重點。需要重點閱讀的是如何使用GetGlyphOutline

                dtof將double轉換成FIXED,ftod相反。
                GetPoint進行點的變換,主要是因為畫字符的時候需要偏移。
                DrawCurve繪制邊框。
                DrawString繪制文字。
              1 #include "..\..\..\..\Library\Windows\VL_WinMain.h"
              2 #include "..\..\..\..\Library\Windows\VL_WinGDI.h"
              3 
              4 using namespace vl;
              5 using namespace vl::windows;
              6 
              7 class MyForm : public VL_WinForm
              8 {
              9 protected:
             10     VL_WinDIB* FBuffer;
             11     VL_WinDC* FFormDC;
             12     VL_WinDC* FBufferDC;
             13 
             14     FIXED dtof(VDouble D)
             15     {
             16         VInt l;
             17         l=(VInt)(D * 65536L);
             18         return *(FIXED *)&l;
             19     }
             20 
             21     VDouble ftod(FIXED F)
             22     {
             23         return F.value+(VDouble)F.fract/65536;
             24     }
             25 
             26     POINT GetPoint(POINTFX fx , GLYPHMETRICS& gm , TEXTMETRIC& TextMetric , POINT Origin)
             27     {
             28         /*Y值比最高點搞出了Ascent,即Top與Baseline的距離*/
             29         POINT Result;
             30         Result.x=(VInt)ftod(fx.x)+Origin.x;
             31         Result.y=(VInt)ftod(fx.y)+Origin.y+TextMetric.tmAscent;
             32         return Result;
             33     }
             34 
             35     void DrawCurve(VBuffer Buffer , VInt Count , GLYPHMETRICS gm , POINT Origin)
             36     {
             37         VL_WinPen::Ptr Pen_Line=new VL_WinPen(PS_SOLID,1,RGB(255,0,0));
             38         VL_WinPen::Ptr Pen_Bezier=new VL_WinPen(PS_SOLID,1,RGB(0,0,255));
             39         VL_WinPen::Ptr Pen_Close=new VL_WinPen(PS_SOLID,1,RGB(0,0,0));
             40 
             41         TEXTMETRIC TextMetric;
             42         GetTextMetrics(FBufferDC->GetHandle(),&TextMetric);
             43 
             44         while(Count>0)
             45         {
             46             TTPOLYGONHEADER* Header=(TTPOLYGONHEADER*)Buffer;
             47             VInt Remain=Header->cb-sizeof(TTPOLYGONHEADER);
             48             VBuffer Start=Buffer+sizeof(TTPOLYGONHEADER);
             49             POINTFX StartPoint=Header->pfxStart;
             50             POINTFX InitPoint=StartPoint;
             51             while(Remain>0)
             52             {
             53                 TTPOLYCURVE* Curve=(TTPOLYCURVE*)Start;
             54                 switch(Curve->wType)
             55                 {
             56                 case TT_PRIM_LINE:
             57                     {
             58                         POINT* Points=new POINT[Curve->cpfx+1];
             59                         Points[0]=GetPoint(StartPoint,gm,TextMetric,Origin);
             60                         for(VInt i=0;i<Curve->cpfx;i++)
             61                         {
             62                             Points[i+1]=GetPoint(Curve->apfx[i],gm,TextMetric,Origin);
             63                         }
             64                         /**/
             65                         FBufferDC->SetPen(Pen_Line);
             66                         FBufferDC->PolyLine(Points,Curve->cpfx+1);
             67                         delete[] Points;
             68                     }
             69                     break;
             70                 case TT_PRIM_QSPLINE:
             71                     {
             72                         /*
             73                         Quadratic Bezier轉Cubic Bezier
             74                         假設一共有n個點,從1開始,那么在2-3,3-4,,(n-2)-(n-1)中間插入中點
             75                         遍歷每三個點(1,2,3) (3,4,5)  ((n-2),(n-1),n),
             76                             將A,B,C變成A,2(A+B)/3,(B+C)/3,C
             77                         這個時候得到一個完整的點數組,直接PolyBezier
             78                         */
             79                         VInt PointCount=1+(Curve->cpfx-1)*3;
             80                         POINT* Points=new POINT[PointCount];
             81                         POINT P0=GetPoint(StartPoint,gm,TextMetric,Origin);
             82                         POINT P1,P2;
             83                         Points[0]=P0;
             84                         VInt Current=1;
             85 
             86                         for(VInt i=0;i<Curve->cpfx;)
             87                         {
             88                             P1=GetPoint(Curve->apfx[i++],gm,TextMetric,Origin);
             89                             if(i==Curve->cpfx-1)
             90                             {
             91                                 P2=GetPoint(Curve->apfx[i++],gm,TextMetric,Origin);
             92                             }
             93                             else
             94                             {
             95                                 P2=GetPoint(Curve->apfx[i],gm,TextMetric,Origin);
             96                                 P2.x=(P1.x+P2.x)/2;
             97                                 P2.y=(P1.y+P2.y)/2;
             98                             }
             99 
            100                             Points[Current+0].x=P0.x + 2*(P1.x - P0.x)/3;
            101                             Points[Current+0].y=P0.y + 2*(P1.y - P0.y)/3;
            102                             Points[Current+1].x = P1.x + 1*(P2.x - P1.x)/3;
            103                             Points[Current+1].y = P1.y + 1*(P2.y - P1.y)/3;
            104                             Points[Current+2]=P2;
            105                             Current+=3;
            106                             P0=P2;
            107                         }
            108                         /**/
            109                         FBufferDC->SetPen(Pen_Bezier);
            110                         FBufferDC->PolyBezier(Points,PointCount);
            111                         delete[] Points;
            112                     }
            113                     break;
            114                 case TT_PRIM_CSPLINE:
            115                     {
            116                         POINT* Points=new POINT[Curve->cpfx+1];
            117                         Points[0]=GetPoint(StartPoint,gm,TextMetric,Origin);
            118                         for(VInt i=0;i<Curve->cpfx;i++)
            119                         {
            120                             Points[i+1]=GetPoint(Curve->apfx[i],gm,TextMetric,Origin);
            121                         }
            122                         /**/
            123                         FBufferDC->SetPen(Pen_Bezier);
            124                         FBufferDC->PolyLine(Points,Curve->cpfx+1);
            125                         delete[] Points;
            126                     }
            127                     break;
            128                 }
            129                 StartPoint=Curve->apfx[Curve->cpfx-1];
            130                 Start+=sizeof(TTPOLYCURVE)+(Curve->cpfx-1)*sizeof(POINTFX);
            131                 Remain-=sizeof(TTPOLYCURVE)+(Curve->cpfx-1)*sizeof(POINTFX);
            132             }
            133             if(
            134                 (StartPoint.x.value!=InitPoint.x.value)||
            135                 (StartPoint.x.fract!=InitPoint.x.fract)||
            136                 (StartPoint.y.value!=InitPoint.y.value)||
            137                 (StartPoint.y.fract!=InitPoint.y.fract)
            138                 )
            139             {
            140                 POINT P1=GetPoint(StartPoint,gm,TextMetric,Origin);
            141                 POINT P2=GetPoint(InitPoint,gm,TextMetric,Origin);
            142                 FBufferDC->SetPen(Pen_Close);
            143                 FBufferDC->MoveTo(P1.x,P1.y);
            144                 FBufferDC->LineTo(P2.x,P2.y);
            145             }
            146             InitPoint=StartPoint;
            147             Buffer+=Header->cb;
            148             Count-=Header->cb;
            149         }
            150     }
            151 
            152     void DrawString(VInt X , VInt Y , PWChar String , VBool GDIFirst)
            153     {
            154         if(GDIFirst)
            155         {
            156             FBufferDC->SetTextColor(RGB(255,255,0));
            157             FBufferDC->DrawString(X,Y,String);
            158         }
            159         {
            160             GLYPHMETRICS gm;
            161             /*初始化變換矩陣:上下倒轉*/
            162             MAT2 mat;
            163             mat.eM11=dtof(1);
            164             mat.eM12=dtof(0);
            165             mat.eM21=dtof(0);
            166             mat.eM22=dtof(-1);
            167             POINT Origin={X,Y};
            168             for(VInt i=0;String[i];i++)
            169             {
            170                 DWORD BufferLength=GetGlyphOutline(FBufferDC->GetHandle(),String[i],GGO_NATIVE,&gm,0,0,&mat);
            171                 if(BufferLength!=GDI_ERROR)
            172                 {
            173                     VBuffer Buffer=new VByte[BufferLength];
            174                     DWORD Result=GetGlyphOutline(FBufferDC->GetHandle(),String[i],GGO_NATIVE,&gm,BufferLength,Buffer,&mat);
            175                     DrawCurve(Buffer,BufferLength,gm,Origin);
            176                     Origin.x+=gm.gmCellIncX;
            177                     Origin.y+=gm.gmCellIncY;
            178                     delete[] Buffer;
            179                 }
            180             }
            181         }
            182         if(!GDIFirst)
            183         {
            184             FBufferDC->SetTextColor(RGB(255,255,0));
            185             FBufferDC->DrawString(X,Y,String);
            186         }
            187     }
            188 public:
            189 
            190     MyForm():VL_WinForm(true)
            191     {
            192         FBuffer=new VL_WinDIB(800,600);
            193         FBufferDC=&FBuffer->DC;
            194         FBufferDC->FillRect(0,0,800,600);
            195         FBufferDC->SetFont(new VL_WinFont(L"宋體",200,0,0,0,400,false,false,false,false));
            196         FBufferDC->SetBackTransparent(true);
            197         FFormDC=new VL_WinControlDC(GetHandle());
            198 
            199         PWChar String=L"漢字ABC";
            200         DrawString(50,50,String,true);
            201         DrawString(50,350,String,false);
            202 
            203         SetMaximizeBox(false);
            204         SetMinimizeBox(false);
            205         SetBorder(vwfbSingle);
            206         SetClientWidth(800);
            207         SetClientHeight(600);
            208         SetText(L"Text Outline");
            209         MoveCenter();
            210 
            211         OnPaint.Bind(this,&MyForm::Form_OnPaint);
            212 
            213         Show();
            214     }
            215 
            216     ~MyForm()
            217     {
            218         delete FFormDC;
            219         delete FBuffer;
            220     }
            221 
            222     void Form_OnPaint(VL_Base* Sender)
            223     {
            224         FFormDC->Draw(0,0,FBuffer);
            225     }
            226 };
            227 
            228 void main()
            229 {
            230     new MyForm();
            231     GetApplication()->Run();
            232 }
            posted on 2008-06-11 07:48 陳梓瀚(vczh) 閱讀(12228) 評論(12)  編輯 收藏 引用 所屬分類: 2D

            評論:
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-11 17:54 | Xw.Y
            嗷嗷贊~有空試一下~  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-12 06:35 | ??
            有點問題,你用的是truetype字體嗎?

            看代碼是,但是啥時候truetype font開始使用4次bezier曲線了??

            看代碼,好像是做了bezier的升次,嘿嘿,這個差距有點大。
              回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-12 07:28 | 陳梓瀚(vczh)
            是truetype吧,不然不能返回曲線。truetype用的是4次,是我降次了……四次貝塞爾曲線降到三次還真是麻煩。  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-12 19:32 | ??
            呵呵,實際上是做的升次,從二次到三次,代碼里寫的也是這個樣子,

            100 Points[Current+0].x=P0.x + 2*(P1.x - P0.x)/3;
            101 Points[Current+0].y=P0.y + 2*(P1.y - P0.y)/3;
            102 Points[Current+1].x = P1.x + 1*(P2.x - P1.x)/3;
            103 Points[Current+1].y = P1.y + 1*(P2.y - P1.y)/3;
            104 Points[Current+2]=P2;

            turetype font制作軟件多用二次B樣條函數來表示曲線,也有三次的Bezier。

            具體文章可見
            http://support.microsoft.com/kb/243285
            對應中文版
            http://support.microsoft.com/kb/243285/zh-cn
            以及
            http://msdn.microsoft.com/en-us/library/ms534021(VS.85).aspx

            四次的好像沒有,從你代碼里也看不到

            呵呵。。。  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-12 22:06 | 陳梓瀚(vczh)
            是不是真的四次那我就不知道啦,只不過所有的資料都顯示那個東西的名字叫“Quadratic Bezier”。等什么時候有空我把公式還原了,然后再推導出那條方程才知道。不過我想應該是升次吧,怎么說那個“Quadratic Bezier”的定義都像是“Cubic Bezier”的子集。  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-06-13 01:28 | 夢在天涯
            bucuo!
            good!  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-07-07 20:13 | Jetricy
            再弄一個筆順庫就可以寫字了.:-)  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2008-11-13 21:21 | SpringSnow
            不錯耶  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了[未登錄] 2010-01-21 01:24 | 無名
            復制代碼的時候能不能不復制行號啊  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2010-01-23 22:12 | 陳梓瀚(vczh)
            @無名
            寫代碼自己消  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2010-05-05 04:53 | messi
            #include "..\..\..\..\Library\Windows\VL_WinMain.h"
            2 #include "..\..\..\..\Library\Windows\VL_WinGDI.h"
            這是什嗎啊??用vc報錯啊  回復  更多評論
              
            # re: 終于提取到了TrueType字體的輪廓了 2013-02-20 17:21 | lalala
            頂一個...
            頭文件這個還要弄一下...Include文件夾里貌似沒有VL_WinMain.h和VL_WinGDI.h啊...我自己改別的試試...
            2次B樣條曲線...夠了,這個夠煩了...3次4次以后再說吧...  回復  更多評論
              
            国产精品久久免费| 久久综合88熟人妻| 久久久久无码中| 欧美精品福利视频一区二区三区久久久精品 | 久久青草国产精品一区| 麻豆精品久久久一区二区| 精品无码久久久久久久动漫| 亚洲国产成人精品91久久久 | 国产精品岛国久久久久| 亚洲精品乱码久久久久久不卡| 亚洲午夜久久影院| 精品国产一区二区三区久久| 99久久免费国产特黄| 国产精品99精品久久免费| 人妻少妇久久中文字幕 | 久久综合一区二区无码| 久久精品成人欧美大片| 色狠狠久久综合网| 亚洲中文字幕无码久久综合网| 99久久国产精品免费一区二区| 99精品国产综合久久久久五月天| 久久久久se色偷偷亚洲精品av| 97久久婷婷五月综合色d啪蜜芽 | 国产成人综合久久精品红| 国产精品99久久久精品无码| 久久久久久久亚洲Av无码| 99久久无码一区人妻a黑| 精品国产青草久久久久福利 | 久久九九亚洲精品| 久久www免费人成看国产片| 欧美一区二区久久精品| 国产亚洲综合久久系列| 久久人妻少妇嫩草AV蜜桃| 无码人妻久久久一区二区三区| 久久久综合九色合综国产| 思思久久精品在热线热| 99久久成人国产精品免费| 免费一级做a爰片久久毛片潮| 蜜臀av性久久久久蜜臀aⅴ| 久久夜色精品国产| 久久精品视频免费|