找回密码
 注册
搜索
查看: 4607|回复: 16

truetype技术和矢量字库的技术原理及实现

[复制链接]
发表于 2009-4-17 09:34:34 | 显示全部楼层 |阅读模式
广泛汉字矢量字库(HZKSLxxJ)格式   
          在矢量字库中,每个汉字都是以128   X   128点阵制成矢量数据。每个汉字   
  的矢量数据都由一指针指向,   指针区在每个汉字字库文件的开头0xBB3E字节。   
  每个汉字矢量数据指针占6个字节,   其格式为:前4个字节为汉字的矢量数据在   
  文件中的偏移,   后2个字节为汉字的矢量数据的长度。   
   
          汉字指针在指针区的偏移由公式计算:pos=((qu-16)*94+wei-1)*6。   
                          注:qu--区号。wei--位号。   
   
          汉字的矢量数据格式为:控制码+坐标值。共有十种控制码,以下是控制码的   含义:   
          (1)若控制码第7,6位为11,清除码,结束当前笔划,将第一个坐标与当前坐   
  标连线;建立新笔划,(X,Y)各占7位,由控制码的第5位开始,即:11XXXXXX   XYYYYYYY。   
                  注:一个字节的位:   
                        7   6   5   4   3   2   1   0   
                        X   X   X   X   X   X   X   X   
          (2)若控制码小于等于0x40,之后控制码大小个字节为坐标值,每个坐标占   一个字节,   
  共有控制码大小个坐标,(X,Y)坐标各占4位,其自的最高位为符号位,   即:FXXXFYYY。   
          (3)若控制码的高4位等于4,之后控制码的低4位大小个字节为坐标值,每个   
  坐标占一个字节,共有控制码大小个坐标,(X,Y)坐标各占4位,X为正,Y为正,   
  即:+XXXX+YYYY。   
          (4)若控制码的高4位等于5,之后控制码的低4位大小个字节为坐标值,每个   
  坐标占一个字节,共有控制码大小个坐标,(X,Y)坐标各占4位,X为负,Y为正,   
  即:-XXXX+YYYY。   
          (5)若控制码的高4位等于6,之后控制码的低4位大小个字节为坐标值,每个   
  坐标占一个字节,共有控制码大小个坐标,(X,Y)坐标各占4位,X为负,Y为负,   
  即:-XXXX-YYYY。   
          (6)若控制码的高4位等于7,之后控制码的低4位大小个字节为坐标值,每个   
  坐标占一个字节,共有控制码大小个坐标,(X,Y)坐标各占4位,X为正,Y为负,   
  即:+XXXX-YYYY。   
          (7)若控制码等于0x80,   其后1字节为Y坐标值,   最高位为符号位,   X坐标不   变,   即:   
  10000000   FYYYYYYY。   
          (8)   若控制码等于0x90,   其后1字节为X坐标值,   最高位为符号位,   Y坐标不   变,即:   
  10000001   FXXXXXXX。   
          (9)   若控制码的高4位等于8,其后1字节为Y坐标值,控制码的低4位值为X坐   
  标值,X坐标各占4位,最高位为符号位,Y坐标各占8位,最高位为符号位,   即:1000FXXX   
  FYYYYYYY。   
          (10)若控制码的高4位等于9,其后1字节为X坐标值,控制码的低4位值为Y坐   
  标值,Y坐标各占4位,最高位为符号位,X坐标各占8位,最高位为符号位,   即:1000FYYY   
  FXXXXXXX。   
  -------------------------------------------------------------------------   
  用Turbo   C   2.0编译以下程序:   
  #include   <stdio.h>   
  #include   <graphics.h>   
  main()   
  {   
    unsigned   long   int   pos;   
    unsigned   int   i,j,k,len,q,w;   
    unsigned   char   c,a,x=0,y=0,x1,y1,xs=0,ys=0,buffer[100];   
    FILE   *fp;   
    int   d=DETECT,m=VGAHI;   
    if((fp=fopen("hzkslt","rb"))==NULL)   return;   
  /*                           ^^^^^^汉字字库的文件名                           */   
    printf("Input   Qu   :");scanf("%u",&q);   
    printf("Input   Wei:");scanf("%u",&w);   
    printf("\n");   
    pos=((q-1l)*94l+w-1l)*6l;   
    fseek(fp,pos,0);   
    fread(&pos,4,1,fp);   
  /*   printf("%lX   :   ",pos);*/   
    fread(&len,2,1,fp);   
    fseek(fp,pos,0);   
    initgraph(&d,&m,"   ");   
    while   (len!=0)   
    {   
      c=getc(fp);   
      len--;   
      if   ((c&0xf0)>=0xc0)   
      {   
        if   (q==0)   
          line(xs,ys,x,y);   
        x=c;   
        fread(&y,1,1,fp);   
        len--;   
        a=y;   
        y>>=7;   
        x=x&0x3f;   
        x<<=1;   
        x=x+y;   
        y=a&0x7f;   
        x1=x;y1=y;   
        xs=x;ys=y;   
        q=0;   
        continue;   
      }   
      /*if   ((c&0xf0)==0x00   &&   (c&0x0f)!=0)*/   
      if   (c<0x40   &&   c!=0)   
      {   
        fread(buffer,1,c,fp);   
        len-=c;   
        for(i=0;i<c;i++)   
        {   
          if   ((buffer&0x80)==0)   
            x1=x+(buffer>>4);   
          else   
            x1=x-((buffer&0x70)>>4);   
          if   ((buffer&0x08)==0)   
            y1=y+(buffer&0x07);   
          else   
            y1=y-(buffer&0x07);   
          line(x,y,x1,y1);   
          x=x1;   
          y=y1;   
        }   
        continue;   
      }   
      if   ((c&0xf0)==0x40   &&   (c&0x0f)!=0)   
      {   
        fread(buffer,1,(c&0x0f),fp);   
        len-=(c&0x0f);   
        for(i=0;i<(c&0x0f);i++)   
        {   
          x1=x+(buffer>>4);   
          y1=y+(buffer&0x0f);   
          line(x,y,x1,y1);   
          x=x1;   
          y=y1;   
        }   
        continue;   
      }   
      if   ((c&0xf0)==0x50   &&   (c&0x0f)!=0)   
      {   
        fread(buffer,1,(c&0x0f),fp);   
        len-=(c&0x0f);   
        for(i=0;i<(c&0x0f);i++)   
        {   
          x1=x-(buffer>>4);   
          y1=y+(buffer&0x0f);   
          line(x,y,x1,y1);   
          x=x1;   
          y=y1;   
        }   
        continue;   
      }   
      if   ((c&0xf0)==0x60   &&   (c&0x0f)!=0)   
      {   
        fread(buffer,1,(c&0x0f),fp);   
        len-=(c&0x0f);   
        for(i=0;i<(c&0x0f);i++)   
        {   
          x1=x-(buffer>>4);   
          y1=y-(buffer&0x0f);   
          line(x,y,x1,y1);   
          x=x1;   
          y=y1;   
        }   
        continue;   
      }   
      if   ((c&0xf0)==0x70   &&   (c&0x0f)!=0)   
      {   
        fread(buffer,1,(c&0x0f),fp);   
        len-=(c&0x0f);   
        for(i=0;i<(c&0x0f);i++)   
        {   
          x1=x+(buffer>>4);   
          y1=y-(buffer&0x0f);   
          line(x,y,x1,y1);   
          x=x1;   
          y=y1;   
        }   
        continue;   
      }   
      if   ((c&0xf0)==0x80   &&   (c&0x0f)==0x00)   
      {   
        buffer[0]=getc(fp);   
        len--;   
        if   ((buffer[0]&0x80)==0x80)   
          y1=y-(buffer[0]&0x7f);   
        else   
          y1=y+buffer[0];   
        line(x,y,x,y1);   
        y=y1;   
        continue;   
      }   
      if   ((c&0xf0)==0x80   &&   (c&0x0f)!=0x00)   
      {   
        buffer[0]=getc(fp);   
        len--;   
        if   ((c&0x08)==0x08)   
          x1=x-(c&0x07);   
        else   
          x1=x+(c&0x07);   
        if   ((buffer[0]&0x80)==0x80)   
          y1=y-(buffer[0]&0x7f);   
        else   
          y1=y+buffer[0];   
        line(x,y,x1,y1);   
        x=x1;   
        y=y1;   
        continue;   
      }   
      if   ((c&0xf0)==0x90   &&   (c&0x0f)==0x00)   
      {   
        buffer[0]=getc(fp);   
        len--;   
        if   ((buffer[0]&0x80)==0x80)   
          x1=x-(buffer[0]&0x7f);   
        else   
          x1=x+buffer[0];   
        line(x,y,x1,y);   
        x=x1;   
        continue;   
      }   
      if   ((c&0xf0)==0x90   &&   (c&0x0f)!=0x00)   
      {   
        buffer[0]=getc(fp);   
        len--;   
        if   ((buffer[0]&0x80)==0x80)   
          x1=x-(buffer[0]&0x7f);   
        else   
          x1=x+buffer[0];   
        if   ((c&0x08)==0x08)   
          y1=y-(c&0x07);   
        else   
          y1=y+(c&0x07);   
        line(x,y,x1,y1);   
        x=x1;   
        y=y1;   
        continue;   
      }   
      if   (c==0xb0)   
      {   
        buffer[0]=getc(fp);   
        buffer[1]=getc(fp);   
        len-=2;   
        if   ((buffer[0]&0x80)==0)   
          x1=x+(buffer[0]&0x7f);   
        else   
          x1=x-(buffer[0]&0x7f);   
        if   ((buffer[1]&0x80)==0)   
          y1=y+(buffer[1]&0x7f);   
        else   
          y1=y-(buffer[1]&0x7f);   
        line(x,y,x1,y1);   
        x=x1;   
        y=y1;   
        continue;   
      }   
      getch();   
      closegraph();   
      printf("<Hex:%X,Dec:%u,X=%u,Y=%u,V=%X,Vn=%X>\n",len,len,x,y,c,getc(fp));   
      break;   
    }   
    line(xs,ys,x,y);   
    getch();   
    closegraph();   
    /*printf("--<Hex:%X,Dec:%u,X=%u,Y=%u>\n",len,len,x,y);*/   
    fclose(fp);   
  }
 楼主| 发表于 2009-4-17 09:43:39 | 显示全部楼层
点阵字库是把每一个汉字都分成16×16或24×24个点,然后用每个点的虚实来表示汉字的轮廓,常用来作为显示字库使用,这类点阵字库汉字最大的缺点是不能放大,一旦放大后就会发现文字边缘的锯齿。 矢量字库保存的是对每一个汉字的描述信息,比如一个笔划的起始、终止坐标,半径、弧度等等。在显示、打印这一类字库时,要经过一系列的数学运算才能输出结果,但是这一类字库保存的汉字理论上可以被无限地放大,笔划轮廓仍然能保持圆滑,打印时使用的字库均为此类字库。Windows使用的字库也为以上两类,在FONTS目录下,如果字体扩展名为FON,表示该文件为点阵字库,扩展名为TTF则表示矢量字库!
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 09:48:49 | 显示全部楼层
矢量字体是与点阵字体相对应的一种字体。矢量字体的每个字形都是通过数学方程来描述的,一个字形上分割出若干个关键点,相邻关键点之间由一条光滑曲线连接,这条曲线可以由有限个参数来唯一确定。矢量字的好处是字体可以无级缩放而不会产生变形。目前主流的矢量字体格式有3种:Type1,TrueType和OpenType,这三种格式都是平台无关的。
  Type1全称PostScript? Type1,是1985年由Adobe公司提出的一套矢量字体标准,由于这个标准是基于PostScript Description Language(PDL),而PDL又是高端打印机首选的打印描述语言,所以Type1迅速流行起来。但是Type1是非开放字体,Adobe对使用Type1的公司征收高额的使用费。
  TrueType是1991年由Apple公司与Microsoft公司联合提出另一套矢量字标准。
  Typ1使用三次贝塞尔曲线来描述字形,TrueType则使用二次贝塞尔曲线来描述字形。所以Type1的字体比TrueType字体更加精确美观。一个误解是,Type1字体比TrueType字体占用空间多。这是因为同样描述一个圆形,二次贝塞尔曲线只需要8个关键点和7段二次曲线;而三次贝塞尔曲线则需要12个关键点和11段三次曲线。然而实际情况是一般来说 Type1比TrueType要小10%左右。这是因为对于稍微复杂的字形,为了保持平滑,TrueType必须使用更多的关键点。由于现代大部分打印机都是使用PDL作为打印描述语言,所以True1字体打印的时候不会产生形变,速度快;而TrueType则需要翻译成PDL,由于曲线方程的变化,还会产生一定的形变,不如Type1美观。
  这么说来,Type1应该比TrueType更具有优势,为什么如今的计算机上TrueType反而比Type1使用更广泛呢?这是因为第一:Type1由于字体方程的复杂,所以在屏幕上渲染的时候,花费的时间多,解决方案是大部分Type1字体嵌入了点阵字体,这样渲染快,但是边缘不光滑,比较难看。很多ps文档和ps转换的pdf文档都是这样,在计算机上浏览的时候字体很难看,但是打印出来很美观。TrueType则渲染比较快,可以平滑的显示在屏幕上,看上去很美观。
  第二个原因是Type1的高额使用费,使得Type1没有被所有的操作系统所支持。Windows家族只有OS/2和windows 2000及之后的版本从操作系统级别开始支持Type1。由于这个问题,Adobe只好在其所有的产品中嵌入Adobe Type Manager(ATM)作为渲染引擎。
  OpenType则是Type1与TrueType之争的最终产物。1995年,Adobe公司和Microsoft公司开始联手开发一种兼容Type1和TrueType,并且真正支持Unicode的字体,后来在发布的时候,正式命名为OpenType。OpenType可以嵌入Type1和TrueType,这样就兼有了二者的特点,无论是在屏幕上察看还是打印,质量都非常优秀。可以说OpenType是一个三赢的结局,无论是Adobe,Microsoft还是最终用户,都从OpenType中得到了好处。Windows家族从Windows 2000开始,正式支持OpenType。打开系统的字体目录(一般是C:\Windows\Fonts\或C:\Winnt\Fonts),可以看到:一个红色A的图标的是点阵字体,两个重叠的T的图标是TrueType字体,一个O的图标就是OpenType字体。
  btw, Agfa貌似是Type1的忠实拥趸,我看到的Agfa字体都是Type1的,不过真的是非常漂亮。
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 09:54:19 | 显示全部楼层
作者:evolrof

说起矢量字体,不得不说一下多边形填充原理。本来是想将多边形填充作为单独的一节内容,可惜说得太细我累大家也累。

  多边形填充最需要关注的就是斜率,计算每条边的斜率,从而得到每条边在每一行上的切点。然后从左到右,将各切点连接起来,逐行进行。

   多边形有两种填充方式,Alternate和Winding。矢量字体主要用的前一种方式,而winding会将所有的切点都连接起来,没有了中间的分隔区域。

  比如,在Alternate模式下,从最左边的切点1,会连接切点2,然后从切点3连接到切点4,而2到3是不连接的。这样就形成了一个空洞,也是矢量字的奥秘所在。Winding模式会将所有的切点都连接起来,即从最左边的一直画到最右边。

FillMode



多边形组——PolyPolygon



将多个多边形组合成一个组,从而形成复杂的多边形组。同样,这个组也依赖于FillMode的填充模式。下面我们来看一下中文的“口”是如何写出来的。

“口”由两条多边形组合而成,根据FillMode为Alternate,相重叠的部分不显示。用笔在字的中央画一条横线,就可以找到4个交点,而交点2到3是不连接的,这样就形成了“口”中间的洞。



微软Arial字体中“S”的曲线

微软的Arial字体中存储的“S”,就是多个Bezier3点组成的。点41是锚点,而40和42是控制点,来控制通过41的曲线的张力。在点的定义上,有on curve和not on curve两种,通常将在曲线上的点定为锚点,而不在曲线上的点为控制点。



这是我年初的时候,为了研究矢量字体,将字母P用微软的方式输出后,再读取字库点阵数据,使用红叉画出字库中所有的点。P是由两条Bezier曲线包围而成的,第二条起着切割的目的,已形成P中间的圆洞。



看看字母“B”的填充。



  字体是如何保证对齐的呢?原来在字库内部,有一个基准线,就好像信纸的虚线,用来水平方向对齐的,同样,也有个垂直方向的基准线。每个字都有上浮和下沉的高度,这也是该字的最上和最下的点所处的位置。



    矢量字在不同字号下,根据点阵尺寸,显示的精细程度也不一样。我们这里将“8”放大了看,在小字号和大字号下的效果。



    在不同的字号下,根据最简单的缩放原理,将所有的点缩放到合适的位置,再确定曲线。这时候,一条边就占据不了整列像素,或者一条边压在了两列像素的中间,这样就造成了灰色的线条。而这并不是我们想要的效果,Photoshop通过USM锐化滤镜,将虚边得以逐步清晰,以达到所要的矢量字。



    苹果系统通过调整整体点阵的位置,将所有的点适当便宜半个像素以内的位置,可以实现较为清晰的字体。如果在关闭了消除锯齿方式,则有些边线由于占据不了半个像素,而不能够显示,这就形成了所谓的缺边或者缺笔划。



有些软件,比如Adobe Acrobat,通过一种较为复杂的方式,以实现矢量字的清晰。将某些关联的点作为一个segment,并且局部偏移到邻近的整数位,而其他部分不动。这种方法目前较为流行,可以实现比苹果和ps还要清晰的矢量效果。



为什么我们通常看到的齿条文字这么清晰呢

  微软的TTF为了保证小字号下的清晰,可谓是用尽了方法。首先,在庞大的字库,内置了数个字号的点阵字,接着才是矢量字。比如宋体,内置了12、14、16、18等几个点阵字库,在这些之外才使用矢量字库来渲染。这也是为什么一个TTF文件要几兆甚至几十兆的容量,不过内嵌的点阵字越多,在不同字号下实现的效果自然越好。别小看了这些点阵字,每一个都是平面设计师在工具上画的,并非由软件生成。唉,可怜的设计师啊~~~~~~

  不过,有个特例。比如Arial字体,内部全是矢量字,但各种尺寸下都是这么清晰。为什么呢?

  原来,微软在字库中加入了解释程序,interpreter,一种专门用于字库渲染的脚本命令。在不同的字号下,都有相应的语句,将矢量字得以最清晰化。这是一种复杂的技术,微软也觉得不能广泛使用,所以只有在部分的英文字库中才有,而且该脚本对应每个字都有一段代码,容量非常大,用在汉字上几乎是不可能,除非是整个文字不多于100个才能使用。

  interpreter就是这么神奇,他也是目前最好的技术,能够将矢量字渲染的和点阵字一样的清晰。他将某些边线的距离拉开,而将另一部分收缩,总之是按照人的想法来做的,这也是编好的程序。



  我用一种新的方式,保证了任何字号下的清晰。目前还在做实验,希望将来能够做成PS的插件,或者做成个工具,输出成PNG格式。这样,设计师就能够显示最清晰的矢量字体了,免得用PS输出的看不清。





矢量字体的终极技术


在1998年的时候,微软声称发明了一种新的技术,能在LCD上将矢量字体的清晰度提高到300%。而后,出现了名为Microsoft Reader的软件,我还用过几个版本。Adobe也不甘示弱,随即在Acrobat 4中对CoolType进行了支持,而Linux的FreeType库也开始支持次像素平滑。据我多年的研究观察,Acrobat做的最好,最灵活,而微软的缺少适当的调节工具,Linux的次像素平滑简直就是垃圾,照虎画猫。

ClearType使用彩色来描边,显示对比度越是强的文字,比如白底黑字或者黑底白字,都是最清晰的。其实,理论上ClearType能够将显示精度提到到300%,但实际上只能达到200%左右。



一般来说,液晶显示器的点阵分布都非常均匀,每个点都是由红绿蓝3色排列而成。我们通常要显示一个白色,需要将红绿蓝都点亮,而黑色是都不显示。ClearType将点的概念再次扩展,把邻近的两个点3色混淆,借前一个点的颜色而忽略后一点的某种颜色。这样,就可以把传统的一个点的最小单位扩展到1/3个点的单位。



在使用ClearType技术后,原来的字体渲染将更加清晰,当然,只限于LCD显示器,CRT会更加模糊。ClearType还有一个关键的技术,就是Linux的次像素平滑没有学去的地方,一定要考虑到红绿蓝的颜色亮度平衡。一般来说,绿色的亮度最高,而蓝色的最低,所以我们要在显示绿色的时候加点红色和蓝色来调低亮度,而显示蓝色的时候要加入绿色和红色来增加亮度。这种做法也可以使边界的彩边不是那么明显,看起来更像是黑色的字。不过,这种做法使得原本可以提高显示精细程度到300%的技术,降低了许多,不过还是要高于200%。

下面我最满意的矢量字效果,这是试验程序截图,以后做成PS的插件,供大家免费下载使用。

注:仅限LCD显示器观看,否则效果只会更差。
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 10:00:51 | 显示全部楼层
矢量字体中每一个字形是通过数学曲线来描述的,它包含了字形边界上的关键点,连线的导数信息等,字体的渲染引擎通过读取这些数学矢量,然后进行一定的数学运算来进行渲染。这类字体的好处是字体可以无限放大而不产生变形。矢量字体主要包括 Type1 和 TrueType 等几类。

  又叫Outline font,通常使用贝塞尔曲线,绘图指令和数学公式进行绘制。这样可以在对字体进行放大的时候保持字体边缘的光滑,更美观。
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 10:06:03 | 显示全部楼层
一般图片根据信息表示方式分为的矢量图和位图。


   矢量图就是用一系列计算指令来表示的图,因此矢量图是用数学方法描述的图,本质上是很多个数学表达式的编程语言表达。画矢量图的时候如果速度比较慢,你可以看到绘图的过程。



   可以把矢量图理解为一个“形状”,比如一个圆,一个抛物线等等,因此缩放不会影响其质量。



   位图是象素集合。不用我解释了。



   矢量图用途是:



   矢量图一般用来表达比较小的图像,移动,缩放,旋转,拷贝,改变属性都很容易,一般用来做成一个图库,比如很多软件里都有矢量图库,把它拖出来随便你画多大都行。



   而数码照片一般都是位图。



   矢量图可以转换成位图,不过反过来把位图转换为矢量图技术上比较难实现,很多图形设计软件都支持将像素图转换成矢量图性,一般可用矢量软件的描摹功能实现,这样就可以在矢量图形的基础上再做编辑,但这样的转换有时候会很耗时,有时候并不能达到预想的效果,一般用于比较简单的位图,或者想要表现一些特殊的效果。



   矢量图由矢量轮廓线和矢量色块组成,文件的大小由图像的复杂程度决定,与图形的大小无关,并且矢量图可以无限放大而不会模糊。



   平时看到的很多图像(如数码照片)被称为像素图(也叫点阵图、光栅图、位图),它们是由许多像小方块一样的像素点(Pixels)组成的,位图中的像素由其位置值和颜色值表示。
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 10:06:34 | 显示全部楼层
位图:
又称光栅图,一般用于照片品质的图像处理,是由许多像小方块一样的"像素"组成的图形。由其位置与颜色值表示,能表现出颜色阴影的变化。在PHOTOSHOP主要用于处理位图。

关于矢量图形几个概念的说明
2000-07-10· sunone·CPCW

何谓矢量图像?
矢量图像,也称为面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。既然每个对象都是一个自成一体的实体,就可以在维持它原有清晰度和弯曲度的同时,多次移动和改变它的属性,而不会影响图例中的其它对象。这些特征使基于矢量的程序特别适用于图例和三维建模,因为它们通常要求能创建和操作单个对象。基于矢量的绘图同分辨率无关。这意味着它们可以按最高分辨率显示到输出设备上。
何谓位图图像?
  与上述基于矢量的绘图程序相比,像 Photoshop 这样的编辑照片程序则用于处理位图图像。当您处理位图图像时,可以优化微小细节,进行显著改动,以及增强效果。位图图像,亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增多单个像素,从而使线条和形状显得参差不齐。然而,如果从稍远的位置观看它,位图图像的颜色和形状又显得是连续的。由于每一个像素都是单独染色的,您可以通过以每次一个像素的频率操作选择区域而产生近似相片的逼真效果,诸如加深阴影和加重颜色。缩小位图尺寸也会使原图变形,因为此举是通过减少像素来使整个图像变小的。同样,由于位图图像是以排列的像素集合体形式创建的,所以不能单独操作(如移动)局部位图。
为什么处理位图时要着重考虑分辨率?
  处理位图时,输出图像的质量决定于处理过程开始时设置的分辨率高低。分辨率是一个笼统的术语,它指一个图像文件中包含的细节和信息的大小,以及输入、输出、或显示设备能够产生的细节程度。操作位图时,分辨率既会影响最后输出的质量也会影响文件的大小。处理位图需要三思而后行,因为给图像选择的分辨率通常在整个过程中都伴随着文件。无论是在一个300 dpi的打印机还是在一个2570dpi的照排设备上印刷位图文件,文件总是以创建图像时所设的分辨率大小印刷,除非打印机的分辨率低于图像的分辨率。如果希望最终输出看起来和屏幕上显示的一样,那么在开始工作前,就需要了解图像的分辨率和不同设备分辨率之间的关系。显然矢量图就不必考虑这么多。
了解 CorelDRAW 中的对象
  CorelDRAW 中的对象可以是任何基本的绘图元素或者是一行文字,例如线条、椭圆、多边形、矩形、标注线或一行美术字等。创建完一个简单对象后,就可以定义出它的特征,如填充颜色、轮廓颜色、曲线平滑度等,并对其应用特殊效果。在这些信息中,包括对象在屏幕中的位置、创建它的顺序、以及定义的属性值,都将作为对象描述的一部分。这意味着当操作对象(如移动对象)时,CorelDRAW 会重建其形状和全部属性。
  对象可以有一条封闭路径或者一条开放路径。一个群组对象是由一个或多个对象构成的。当用挑选工具选择一个对象时,可以通过它四周的选择框来识别它。当选中一个对象时,选择框的边角和中点会出现 8个填充方块。每个单独的对象都有自己的选择框。当用“组群”命令把两个或更多的对象进行组合时,将会产生一个组群,可以把它当作一个对象来选择和操作。对象由路径构成,这些路径构成了它的轮廓和边界。一个路径可由单个或几个线段构成。每个线段的端点有一个中空的方块,称为节点。可以用形状工具选择一个对象的节点,从而改变它的总体形状和弯曲角度。
开放路径对象和封闭路径对象有什么区别?
  开放路径对象的两个端点是不相交的。封闭路径对象就是那种两个端点相连构成连续路径的对象。开放路径对象既可能是直线,也可能是曲线,例如用手绘工具创建的线条、用贝塞尔曲线工具创建的线条或用螺纹工具创建的螺纹线等。但是,在用“手绘工具”或“贝塞尔曲线工具”时,把起点和终点连在一起也可以创建封闭路径。封闭路径对象包括圆、正方形、网格、自然笔线、多边形和星形等。封闭路径对象是可以填充的,而开放路径对象则不能填充。
点评回复

使用道具 举报

 楼主| 发表于 2009-4-17 10:21:50 | 显示全部楼层
MTK多国语言相关经验总结
一、        移植多国语言
移植多国语言主要牵涉到对mmi_features.h(整个工程的宏控定义文件)、fontres.c(字体资源文件)的修改,并添加相应的字库文件。
1、        语言宏控的修改
在mmi_features.h文件中,用于控制各种语言的开关是类似于__MMI_LANG_ENGLISH__的宏,打开该宏,那么工程就支持该种语言。有时侯,需要同时打开与该语言相关的一些宏,比如阿拉伯语的编码模式、汉语的编码模式。(当然这个编码模式一般都是设置好了的,但也有些许例外,自己看着办)
2、        字库文件的添加
在mtk中,字库主要是两个文件,一个是*.h文件,还有一个是对应的fontres.c文件。
①字库的获取
有两个方式:1)直接去网上找对应语言的字库文件。2)自己利用mtk公司所提供的MCT 6.0工具来制作字库。不过mct6.0制作字库需要.bdf的点阵字库源文件,而网上能找的基本上都是.ttf的矢量字库文件,这就存在一个需要将ttf文件转换成bdf文件的第三方软件,并且转换的好坏将直接影响到最终用mct6.0生成的字库文件(目前我们用的是otf2bdf3,免费的,因此效果不是很好)。
        ②字库的使用。首先我们查看下mtk版本中自带的英文字库L_1_Pluto_Large.h是存放在什么位置的,然后将我们的*.h也放入相同的文件夹下;接下来我们需要将我们的fontres.c文件与mtk中原有的fontres.c文件合并为一个fontres.c文件:合并的方法就参考原有的fontres.c文件中英文字库的代码分布方式,将我们的fontres.c文件里面的代码利用语言宏控拷入mtk原有的fontres.c文件中。
        3、修改默认显示语言
        这个只需要修改C:\NEOTEL26_06B_W07.20.MP.V21_MMI\custom\app\NEOTEL26_
06B_BB这个目录下面的nvram_cust_pack.c文件(不同的版本,该文件所处位置不一样,这里是6225的版本)。在该文件里面有如下一处:
    0x00,         /* NVRAM_SETTING_LANG,//17 */
这个0x00值指的就是设置语言界面某种语言所处的位置。如果我们想修改默认显示语言为简体中文,而设置语言界面中文在第6的位置,那么我们将0x00这个值改为0x05即可。

二、        移植zi输入法
1、打开zi开关
        1)文件:..\make\ZTENC26_07B_GPRS.mak
修改输入法为MMI_ZI;
          INPUT_METHOD = MMI_ZI                # Input methods: NONE, MMI_T9, or MMI_ZI

        2)在mmi_features.h里面打开相应的zi语言输入法宏开关,形如__MMI_ZI_PRC_ENG
LISH__。

2、添加zi代码
  ..\zi   
  Zi目录添加到工程根目录.
3、添加zi的编译选项
  工程文件要最终通过makefile编译成目标文件,每个模块的编译路径都写入该模块的编译目录中。
  ..\make\zi  包含文件:
zi.def
zi.inc
zi.lis
zi.pth

另外几个模块用到了zi的文件,因此必须把zi的头文件目录:zi\include 包含到下面几个文件中,否则编译时候报错“不能打开xxx.h文件”。(这个是07b版本中修改遇到编译错误后再加上去的,其他版本也可以类似地修改)
make\gdi_arm\gdi_arm.inc
make\mmiresource\mmiresource.inc
make\vendorapp\vendorapp.inc
make\plutommi\conn_app.inc
make\plutommi\inet_app.inc
make\plutommi\media_app.inc
make\plutommi\mmi_framework.inc
4、添加zi输入法库文件
  在make\option.mak文件里面,查找MMI_ZI,找到类似如下代码:
  ifeq ($(strip $(INPUT_METHOD)),MMI_ZI)
    CUSTOM_COMMINC  +=        
vendor\InputMethod\ZI\project\$(strip $(INPUT_METHOD_BASE))\v6_official\inc
    COMPOBJS          +=
vendor\InputMethod\ZI\project\$(strip $(INPUT_METHOD_BASE))\v6_official\lib\zi8clib.a
CUS_REL_OBJ_LIST          +=
vendor\InputMethod\ZI\project\$(strip $(INPUT_METHOD_BASE))\v6_official\lib\zi8clib.a
    CUS_INPUTMETHOD_BASE         =
vendor\InputMethod\ZI\project\$(strip $(INPUT_METHOD_BASE))\v6_official
  endif

  从上面的脚本中可以看到,zi输入法的库文件的存放位置:
  C:\ZTENC26_07B_V4\vendor\InputMethod\ZI\project\plutommi\v6_official\lib
  头文件存放位置:
  C:\ZTENC26_07B_V4\vendor\InputMethod\ZI\project\plutommi\v6_official\inc
  
  因此我们开始添加zi输入法的库文件和头文件到上面的目录,如果目录不存在,则自己创建。其中,头文件放在inc文件夹下,.lib和.a文件放在lib文件夹下。

(当然,版本不同,库文件和头文件存放的路径也许不同,到时参照上面的步骤就是了,上面的展示是依据07b来说的。)

三、        移植手写hanwang输入法
1、打开hanwang开关
  文件:..\make\ZTENC26_07B_GPRS.mak
修改手写输入法为MMI_HANWANG;
  HAND_WRITING    = MMI_HANWANG # MMI_HANWANG,  MMI_PENPOWER
2、添加hanwang代码
  ..\hanwang   
  hanwang目录添加到工程根目录.
3、添加hanwang的编译选项
  工程文件要最终通过makefile编译成目标文件,每个模块的编译路径都写入该模块的编译目录中。
  ..\make\hanwang  包含文件:
hanwang.def
hanwang.inc
hanwang.lis
hanwang.pth

4、添加hanwang输入法库文件
  在make\option.mak文件里面,查找MMI_HANWANG,找到类似如下代码:
  ifeq ($(strip $(HAND_WRITING)),MMI_HANWANG)
    COM_DEFS    += __MMI_HANWANG__
    COMPLIST    += hanwang
    CUS_REL_SRC_COMP += hanwang
    COMPOBJS    += vendor\handwriting\hanwang\v1_official\lib\hw.a
    CUS_REL_OBJ_LIST    += vendor\handwriting\hanwang\v1_official\lib\hw.a
    CUS_REL_OBJ_LIST    += vendor\handwriting\hanwang\v1_official\lib\hw.lib
    CUS_REL_OBJ_LIST    += vendor\handwriting\hanwang\v1_official\lib\hw.dll
    CUS_REL_OBJ_LIST    += vendor\handwriting\hanwang\v1_official\lib\hws.lib
    CUSTOM_COMMINC  +=        vendor\handwriting\hanwang\v1_official\inc
  endif
  从上面的脚本中可以看到,hanwang输入法的库文件的存放位置:
  C:\ZTENC26_07B_V4\vendor\ handwriting\hanwang\v1_official\lib
  头文件存放位置:
  C:\ZTENC26_07B_V4\vendor\ handwriting\hanwang\v1_official\inc
  
  因此我们开始添加hanwang输入法的库文件和头文件到上面的目录,如果目录不存在,则自己创建。其中,头文件放在inc文件夹下,.lib和.a文件放在lib文件夹下。

(当然,版本不同,库文件和头文件存放的路径也许不同,到时参照上面的步骤就是了,上面的展示是依据07b来说的。)

四、打开MTK自带输入法支持
在mmi_features.h里面打开形如__MMI_MULTITAP_THAI__的宏开关,每种语言都对应着一个宏开关,根据需要打开。

五、添加不同语言输入法的虚拟键盘
1、添加虚拟键盘字库
        这种字库文件比较特殊,目前我们没有去研究自己怎么制作这种字库文件,我们用的字库文件来源主要是07b上面的虚拟键盘字库(因为07b上面虚拟键盘字库很全)。同时,我也试过直接用我们自己生成的普通字库,结果虚拟键盘上显示出方框,说明字库不支持。
        按照07b上的代码模式,直接把对应的关于虚拟键盘字库的所有代码拷贝过来就是。
2、添加虚拟键盘布局
        这个主要是要去修改Wgui_virtual_keyboard.c文件,这里面有写好的标准键盘布局模式,可以参考其代码自己写其他语言的虚拟键盘布局模式。另外我们也可以比较07b的代码,将对应的虚拟键盘布局代码拷贝过来即可。注意,别加漏了,这个文件里面有好几处都需要添加代码的,自己搜语言宏控来加代码就是了。
3、虚拟键盘的显示与隐藏
        虚拟键盘的显示与隐藏主要体现在输入法的切换方面,因此需要修改代码的地方在这个叫EditorPen.c里面。主要修改的函数是mmi_pen_editor_vk_show和mmi_pen_editor_set_virtual_keyboard_by_input_mode。大家按照函数里面已经写好的代码模式很容易就加上其他语言虚拟键盘的支持代码的。

六、输入界面底部条中间输入法提示符的显示
        这个主要调用的是EditorPen.c文件中的mmi_pen_editor_set_CSK_content函数来进行文字、图标的设置以及绘制的。如果输入界面底部条中间的输入法提示符的显示出现问题,大家调试该函数就是了。

七、输入界面左上角输入法提示符的显示
        这个主要调用的是wgui_categories_inputs.c文件中的wgui_get_inputbox_information_ic
on函数和wgui_redraw_input_information_bar函数,具体的绘制步骤哪个地方出问题了,就请大家用模拟器打断点调吧。
点评回复

使用道具 举报

发表于 2009-4-18 16:22:52 | 显示全部楼层
很不错,只是没时间细细研究一番
点评回复

使用道具 举报

发表于 2009-4-20 08:53:47 | 显示全部楼层
写这么多干嘛,直接用freetype,稳定又好用!
点评回复

使用道具 举报

发表于 2009-4-20 11:40:52 | 显示全部楼层
以下是引用evolrof在2009-4-20 8:53:47的发言:
写这么多干嘛,直接用freetype,稳定又好用!


这位仁兄,有没有移植freetype到MTK上?两年前我试过,速度慢的令人愤慨----当然是没有优化的那种。如何优化?可否讨论一二?[em08][em08][em08]
点评回复

使用道具 举报

发表于 2009-4-20 11:58:21 | 显示全部楼层
不错,挺详细!
点评回复

使用道具 举报

发表于 2009-4-21 12:54:48 | 显示全部楼层
NEOTEL26_06B_W07.20.MP.V21_MMI

NEOTEL这是哪个公司的源代码包?????
点评回复

使用道具 举报

发表于 2010-3-17 20:55:19 | 显示全部楼层
NEOTEL 力合通信,清华力合!
点评回复

使用道具 举报

发表于 2010-3-18 09:55:08 | 显示全部楼层
不错,学习一下。
点评回复

使用道具 举报

发表于 2010-3-18 20:06:30 | 显示全部楼层
可以用点cache,做加速来优化性能。
点评回复

使用道具 举报

发表于 2010-3-19 09:02:51 | 显示全部楼层
居然里面包含我写的文章,呵呵。

很多公司就拿着开源的freetype,来忽悠MTK客户。很难移植吗?非常easy。
还有的干脆关掉freetype很重要的autohint,号称自己的算法优于MTK自己的矢量字引擎,速度快。你去掉代码当然速度快了,但损失的是字体成像质量。
点评回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

Archiver|手机版|小黑屋|52RD我爱研发网 ( 沪ICP备2022007804号-2 )

GMT+8, 2024-11-30 11:40 , Processed in 0.052429 second(s), 17 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表