TLogFont中使字体为斜体只能有固定的倾斜程度,如何实现任意角度的倾斜?

解决方案 »

  1.   

    这是别人写的程序,用LOGFONT字体:
          FillChar(FLogFont,Sizeof(TLogFont),0);
          With FlogFont do
          begin
           lfHeight:=Font.Height;
           lfWidth:=0;
           lfEscapement:=2700;     //想旋转多少度,修改这里的参数就可以了啊
           lforientation:=lfEscapement;
           lfWeight:=Fw_Normal;
           lfItalic:=0;
           lfUnderline:=0;
           lfStrikeOut:=0;
           lfCharSet:=Ansi_CHARSET;
           StrPCopy(lfFaceName,Font.Name);
           lfQuality:=PROOF_QUALITY;
           lfOutPrecision:=OUT_TT_ONLY_PRECIS;
           lfClipPrecision:=CLIP_DEFAULT_PRECIS;
           lfPitchAndFamily:=Variable_Pitch;
          end;
          Font.Handle:=CreateFontIndirect(FLogFont);      Textout(x,y,'旋转文字');
      

  2.   

    谁说的,我就是用TLogFont做的任意角度倾斜。
      

  3.   

    我特意强调的是斜体字的倾斜程度,就是在Flash中把文字进行skew变换时的那种效果
      

  4.   

    找到一种方法:用PlgBlt。但效果不好,锯齿很多。有好点的方法么?
      

  5.   

    还是要自己来解决:用GetGlyphOutLine获得文字的轮廓,然后想怎么变形就处理一下,再输出。
      

  6.   

    http://www.china-askpro.com/msg2/qa27.shtml 里面说:这个函数的难点在于返回的字体数据的格式。我们的时间有限,无法给出VB实例。这里只能给出三篇有关的文章供你参考。如果你能完成VB实例,我们也非常希望能在我们的站点上与大家分享。这三篇文章都来自微软的Knowledge Base(http://support.microsoft.com)。一篇文章是“Q87115 GetGlyphOutline() Native Buffer Format”介绍了Native格式。一篇文章“Q113262 SAMPLE: Plotting TrueType Characters”,这是一个用C语言写的例子,也是关于Native格式,程序比较短,容易看懂。最后一篇是“Q97340 SAMPLE: GetGlyphOutline() Function Demonstration”,这是三篇中最详细的了,其中有一个帮助文件,全面的介绍所有参数的用法,例子也是用C语言写的,比较长。 下面的C++Builder的代码是从网上找到的 。提取Windows的 
    TTF字体轮廓矢量数据 
    西安飞机工业公司设计部 朱朝阳 ------------------------------------------------------------------------------------ Windows系统的TTF字体具有字体优美、可无级缩放等优点,最适合应用在CAD类图形处理等软件中。直接分析TTF字体的文件格式并读出每个字的轮廓矢量是相当困难的,我们可以借助API函数来方便地获得这些数据。 ---- 调用函数GetGlyphOutline可以得到一个字的轮廓矢量或者位图。 ---- 函数原型如下:     DWORD GetGlyphOutline(
          HDC hdc,            // 设备句柄
          UINT uChar,    // 将要读取的字符
          UINT uFormat,    // 返回数据的格式
        LPGLYPHMETRICS lpgm,  // GLYPHMETRICS结构地址
          DWORD cbBuffer,  // 数据缓冲区的大小
          LPVOID lpvBuffer,  // 数据缓冲区的地址
          CONST MAT2 *lpmat2 // 转置矩阵的地址
        );
     
    ---- 其中,参数uFormat取值如下:     GGO_NATIVE  - 要求函数返回字符的轮廓矢量数据;
        GGO_METRICS - 函数仅返回GLYPHMETRICS结构至lpgm;
        参数lpgm指向GLYPHMETRICS结构,该结构描述字符的位置。
        参数lpmat2指向字符的转置矩阵。
     
    ---- 本文以下C++ Builder程序示范如何在画布上以指定的大小绘制字符串。 ---- 首先,建立一个新项目,在主窗口上放置一个Image控件,一个Edit控件,一个Button控件;然后,在Button的点击事件中加入如下代码: #include < stdlib.h >void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      TRect ClipRect = Rect(0,0,Image1->Width,Image1->Height);
      Image1->Picture = 0;
      StretchTextRect(Image1->Canvas, ClipRect, Edit1->Text);
    }---- 添加如下子程序: //---------------------
    void TForm1::StretchTextRect(TCanvas 
    *pCanvas, TRect ClipRect, AnsiString Text)
    {
      pCanvas->Font->Size = 100;
      pCanvas->Font->Name = “宋体";
      pCanvas->Pen->Color = clBlack;
      pCanvas->Pen->Mode = pmCopy;
      pCanvas->Pen->Style = psSolid;
      pCanvas->Pen->Width = 1;
      int XSize = ClipRect.Width() / Text.Length();
      int YSize = ClipRect.Height();  MAT2 mat2;  // 转置矩阵,不用变换
      mat2.eM11.value = 1;mat2.eM11.fract = 0;
      mat2.eM12.value = 0;mat2.eM12.fract = 0;
      mat2.eM21.value = 0;mat2.eM21.fract = 0;
      mat2.eM22.value = 1;mat2.eM22.fract = 0;  GLYPHMETRICS gm,gmm;  // 首先获得字符的位置矩阵,存入gm
      GetGlyphOutlineA(pCanvas->Handle,0x0b0a1,
       GGO_METRICS,&gm,0,NULL,&mat2);  char *ptr = Text.c_str();
      TRect TheRect;
      for(int i = 0;i < Text.Length();) {
        int c1 = (unsigned char)*ptr;
        int c2 = (unsigned char)*(ptr + 1);
        UINT nChar;
        TheRect.Left = i * XSize + ClipRect.Left;
        TheRect.Top = ClipRect.Top;
       TheRect.Right = (i + 2) * XSize + ClipRect.Left;
        TheRect.Bottom = ClipRect.Top + YSize;
         
        // 获得当前字符数据的数组的大小
     DWORD cbBuffer = GetGlyphOutlineA(pCanvas->
    Handle,nChar,GGO_NATIVE,&gmm,0,NULL,&mat2);
        if(cbBuffer == GDI_ERROR) break;
        void *lpBuffer = malloc(cbBuffer);
        if(lpBuffer != NULL) {
          // 读入数据置缓冲区
          if(GetGlyphOutlineA(pCanvas->
          Handle,nChar,GGO_NATIVE,
         &gmm,cbBuffer,lpBuffer,&mat2) != GDI_ERROR) {
    // 分析数据并绘制字符
        TMemoryStream *MBuffer = new TMemoryStream();
        MBuffer->Write(lpBuffer,cbBuffer);
        MBuffer->Position = 0;
        for(;MBuffer->Position < MBuffer->Size;) {
        int CurPos = MBuffer->Position;      
        TTPOLYGONHEADER polyheader;    int ptn = 0;
      MBuffer->Read(&polyheader,sizeof(polyheader));  //读入头指针在头后面
        ptn++;
        
        for(int j = 0;j < (int)(polyheader.cb      //头后的位置开始到头中记录的大小(头加记录)
                                    - sizeof(polyheader));) 
       {
        WORD wtype,cpfx;
        MBuffer->Read(&wtype,sizeof(WORD));    //这里度的的是tpolycurve
        MBuffer->Read(&cpfx,sizeof(WORD));
        MBuffer->Position += cpfx * sizeof(POINTFX);      //指针在一个记录的后面tpolyheader+tpolycurve+若干pointfx
        j += sizeof(WORD) * 2 + cpfx * sizeof(POINTFX);//j是tpolycurve和后面跟的pointfx的总长度
       
        if(wtype == TT_PRIM_LINE) ptn += cpfx;            //若干如果是qspline那么点的数目要三倍?
        else ptn += (cpfx - 1) * 3 + 1;
       }    TPoint *pts = new TPoint[ptn+1];  // 存储多边形顶点
        MBuffer->Position = CurPos;        //当前大记录的开始位置
        ptn = 0;
        MBuffer->Read(&polyheader,sizeof(polyheader));  //读头,指针在头后面
        TPoint pt0 = POINTFX2TPoint(polyheader.pfxStart,TheRect,&gm);
         pts[ptn++] = pt0;                 //头位置 点 ptn=1
        for(int j = 0;j < (int)(polyheader.cb - sizeof(polyheader));) {
        TPoint pt1;
        WORD wtype,cpfx;
        MBuffer->Read(&wtype,sizeof(WORD));
        MBuffer->Read(&cpfx,sizeof(WORD));   //指针在tpolycurve的pointfx位置
        POINTFX *pPfx = new POINTFX[cpfx];
        MBuffer->Read((void *)pPfx,cpfx * sizeof(POINTFX));
        j += sizeof(WORD) * 2 + cpfx * sizeof(POINTFX);  //j到了大记录的尾位置
        //处理读来的点数组记录
        if(wtype == TT_PRIM_LINE) { // 直线段
        for(int i = 0;i < cpfx;i++) {
        pt1 = POINTFX2TPoint(pPfx[i],TheRect,&gm);
        pts[ptn++] = pt1;
        }
      }
        else {  // Bezier曲线
        TPoint p0,p1,p2,p3,p11,p22,pp0,pp1,pp2,pt11,pt22;
        int i;
        for(i = 0;i < cpfx-1;i++) {
        pt11 = POINTFX2TPoint(pPfx[i],TheRect,&gm);
        pt22 = POINTFX2TPoint(pPfx[i+1],TheRect,&gm);
        pp0 = pts[ptn-1];
        pp1 = pt11;
        pp2.x = (pt11.x + pt22.x)/2;
        pp2.y = (pt11.y + pt22.y)/2;    p0 = pp0;
        p1.x = pp0.x/3 + 2 * pp1.x/3;
        p1.y = pp0.y/3 + 2 * pp1.y/3;
        p2.x = 2 * pp1.x/3 + pp2.x/3;
        p2.y = 2 * pp1.y/3 + pp2.y/3;
        p3 = pp2;    for(float t = 0.0f;t <= 1.0f;t += 0.5f) {
    float x = (1-t)*(1-t)*(1-t)*p0.x+ 
    3*t*(1-t)*(1-t)*p1.x+ 3*t*t
    *(1-t)*p2.x + t*t*t*p3.x;
    float y = (1-t)*(1-t)*(1-t)*p0.y
    + 3*t*(1-t)*(1-t)*p1.y+3
    *t*t*(1-t)*p2.y + t*t*t*p3.y;
        pts[ptn].x = x;
        pts[ptn].y = y;
        ptn++;
        }
      }
        pt1 = POINTFX2TPoint(pPfx[i],TheRect,&gm);
        pts[ptn++] = pt1;
        }
        delete pPfx;
        }
        pts[ptn] = pts[0]; // 封闭多边形
        pCanvas->Brush->Color = clWhite;
        pCanvas->Pen->Mode = pmXor;
        pCanvas->Pen->Style = psClear;
        pCanvas->Brush->Style = bsSolid;
        pCanvas->Polygon(pts,ptn);    delete pts;
        }
        delete MBuffer;
        }
        free(lpBuffer);
        }
      }
    }
    //---------------------
    TPoint TForm1::POINTFX2TPoint(POINTFX pf,
    TRect TheRect,GLYPHMETRICS *gm)
    {
      TPoint point;
      float fx,fy;
      fx = pf.x.value + pf.x.fract / 65536.0f + 0.5f;
      fx = fx
         / (float)(gm->gmBlackBoxX + gm->gmptGlyphOrigin.x)
         * (float)TheRect.Width() + (float)TheRect.Left;
      fy = pf.y.value + pf.y.fract / 65536.0f + 0.5f;
      fy = ((float)gm->gmBlackBoxY - fy)
         / (float)(gm->gmBlackBoxX + gm->gmptGlyphOrigin.x)
         * (float)TheRect.Height() + (float)TheRect.Top;
      point.x = int(fx);
      point.y = int(fy);
      return point;
    }