flex动态生成矢量swf字体--java动态生成swf文件

前言

相信很多在线设计的前端WEB应用会用到字体作为素材的案例,丰富多样的字体一般是部署在服务器端让用户去选择,而且能动态部署,使用客户端字体显然是不可取的;

 

现状

然而中文字体动不动就几个M,做过flash的同学应该知道嵌入字体是怎么回事,假如嵌入字体会使得swf整个体积变大,而flex目前容易做到的是整个字体文件编译成swf格式来动态加载。假如需要根据用户输入的文字动态的加载该如何做呢?

 

最简单的方案是后台根据字体生产位图,这不能满足我的要求,1,位图拉伸后有锯齿2,大一点的位图文件很占空间,前台设计需要至少1000×1000以上才能保证清晰度,这么一张图动不动就大于100K。

 

目的

最完美的一个方案,是能让我的用户输入文字后,生成一个对应字体仅仅包含这几个文字的swf资源文件,这个swf占的空间很小并且在flex中用<mx:image source=这个资源>就可以加载。

 

阿里妈妈bannermaker是有这个方案的,但是商业机密没有公开出来,可以肯定的是一定在后台端生成swf,至于怎么产生,目前也没找到过现成方案。只能自己研究了,经过一段时间实践,结合java动态生成swf的一个框架,终于成功了,20个文字的矢量图,10K不到,而且矢量图和字体大小无关,随便前端怎么拉伸无锯齿。

 

首先,重述下动态矢量swf字体是什么含义呢?

 

      用户-》选择1字体并输入‘abc’-》后台生成一个swf,这个swf仅仅包含1字体中abc三个字符并且是矢量的。

 

类似于flash IDE里的这个功能:

嵌入字体并导出资源swf图像。

 

遗憾的是IDE不容易和应用整合,如何用代码来实现呢?

 

实现的核心:java登场了,感谢anotherbigidea大师的开放和分享

http://www.anotherbigidea.com/javaswf/

 

这已经是anotherbigidea大师03年时候的杰作了,用java io操作 根据flash 6字节位组织方式可以从swf 1中提取任何的元素再去动态生成swf 2的内容。

 

因此,一个想法诞生了,后台放置一个字体a的全量swf1文件,java端获取到用户输入的文字后动态的从swf1拷贝那几个图形文字生成一个 swf2 不就ok了么。 果然,如我所料:

 

1,全量的swf字库怎么做?

 

可依照上图,在本地安装字体后,嵌入所有字符导出一个swf,最好是swf 6.0格式。(flex和flash共享资源文件目前都用6 )

 

2,怎么用java动态生成swf?

 

/**
 * 简单测试
 */
package test;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;

import com.anotherbigidea.flash.movie.Font;
import com.anotherbigidea.flash.movie.FontDefinition;
import com.anotherbigidea.flash.movie.FontLoader;
import com.anotherbigidea.flash.movie.Frame;
import com.anotherbigidea.flash.movie.Movie;
import com.anotherbigidea.flash.movie.Text;
import com.anotherbigidea.flash.movie.Font.NoGlyphException;
import com.anotherbigidea.flash.structs.Color;

/**
 * @author jianwen

 * @email  wen2375160@163.com 
 *
 */
public class Testtxt {

 /**
  * @param args
  * @throws IOException
  * @throws NoGlyphException
  */
 public static void main(String[] args) throws IOException, NoGlyphException {
  
   //--Load a font from another movie.  That movie should contain only an
        // edit field that is specified to include all the glyphs in the
        // appropriate font.
        // Font definitions can be referenced by multiple fonts (for example if
        // there is a font used for a text block and another font used with an
        // edit field which restricts the allowable characters).

 

  //初始化 加载全量字库
         java.awt.Font nf = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, new FileInputStream("c://mnjmb.ttf"));
       
  
  //第一步,输入文字
  String instr = "文字这个的房贷首付第三方第三方/n/n/n地方地方haha牛x第三方我祖国好地方/n地方/ndfdfdsf";
  
  //第二步:选择/导入字库
  /避免重复加载
  String fontpath = "ccxkt";
  HashMap<String, FontDefinition> fonts = new HashMap<String, FontDefinition>();
  FontDefinition fontdef = fonts.get(fontpath);
  System.out.println("当前使用内存:"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024);
  if(fontdef==null){
   //导入swf格式的文字类库,注意路径
    fontdef = FontLoader.loadFont( "c://"+fontpath+".swf" ); //导入全量的字库,我这里有很多个,为了测试性能,发现一个中文字体要占30M左右的内存
    fonts.put(fontpath, fontdef);
  }
//  File f = new File("c://ch");
//  System.out.println("一共"+f.list().length+"个中文字体");
//  for (String s :f.list()){
//   System.out.print(s);
//   fonts.put(s,FontLoader.loadFont("c://ch//"+s));
//   System.out.println(":"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024);
//  }
//  System.out.println("加载中文字体后内存2:"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024);
//  f = new File("c://en");
//  System.out.println("一共"+f.list().length+"个英文字体");
//  for (String s :f.list()){
//   System.out.print(s);
//   fonts.put(s,FontLoader.loadFont("c://en//"+s));
//   System.out.println(":"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024);
//  }
//  System.out.println("加载所有字体后内存3:"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024);

 

/下面是动态生成文字对应的swf部分,性能很不错,io操作由于是内存拷贝,奇快无比,比后台动态用flex sdk编译方式还要快
        //初始化参数
        int fontsize = 100;//默认字体大小,由于矢量格式,大小没关系(swf文件大小不受此参数影响)
        Color c = new Color(0,0,0);//文字颜色
        //--Create a text object with a default transform
        Text text = new Text(null);
        //--The font references the Font Definition and pulls over only the
        // glyph definitions that are required for any text referencing the font
        System.out.println("len1:"+fontdef.getGlyphList().size());
        Font font = new Font( fontdef );
       
        //第四步:
        /处理输入字符串,支持回车多行解析
        StringReader re = new StringReader(instr);
        BufferedReader bf = new BufferedReader(re);
        String s =  bf.readLine();
        int i=0;
        while(s!=null){
         //多行间必须使用空格
         if(s.length()==0){s = " ";}
         //--Add a row of characters - specify the starting (x,y) within the text symbol
         
         try {
    text.addRow(font.chars(s, fontsize), c, 0, fontsize * i + 5,true, true);
   } catch (NoGlyphException e) {
    // 某文字没有该对应字体,忽略
   }
   s = bf.readLine();
         i++;
        }
       /解析完毕
      
      
        //--Add another row - different color, no (x,y) specified so the chars will
        // flow immediately after the preceding chars.
        // text.row( font.chars( "2我来无敌", 25), new Color(255,0,255),0,0,false,false);
     
        //计算文本框大小,重要,必须在movie初始化前 这是我改造的代码,先计算大小
        text.measureRect(null, null, font, false);
       
        //默认文字x=0, 推算出中文宽度需要多加一个单位的fontsize,偶也不知道为什么,加了没坏处
        Movie movie = new Movie( (int)text.maxX+fontsize,(int)(text.maxY-text.minY),12,5,null);
        Frame frame = movie.appendFrame();
        //--instantiate the text
        frame.placeSymbol( text, 0, -((int) text.minY ));//让文本框显示在0,0坐标
        //--save the movie
        movie.write( "c://output.swf",true );
        
         //输出到流
        //movie.write( OutputStream out, boolean compressed )


 }

}

 

最后,大师提供了一个基础,优化需继续

 

这种方式生成的swf比通过flexsdk动态编译生成swf要快而且文件要小,精简,很多无用信息都不会生成。

 

不过也有几个局限:

1,字体swf必须导出flash 6格式, 只能提供了简单的动画接口。

2,后台导入的是一个全量swf库,占用静态内存极大,要部署50套字体的话 2G内存都不够;动态加载全量字体的话也是不可行的,因为加载一个全量字体花费极大,可考虑拆分部署,或者按字体文字的字节流引入数据库,再或者可按字体分布多个服务器部署。

 

这个库已经很久没人更新了,里面的代码逻辑看得一头雾水,虽然功能和性能都通过了,但是基于继续大师的优化工作还有待继续前行。

 

参考文献:

 

http://www.anotherbigidea.com/javaswf/

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值