当前位置:  编程技术>移动开发
本页文章导读:
    ▪自定义ContentProvider 范例演示        自定义ContentProvider 实例演示参考:contentprovider的学习实例总结  http://www.cnblogs.com/chenglong/articles/1892029.html Android学习十九:ContentProvider初步  http://blog.sina.com.cn/s/blog_5688414b0100xagp.html android 自.........
    ▪ 【OpenGL】GLSL-两面渲染技术(Two-sided rendering)        【OpenGL】GLSL-双面渲染技术(Two-sided rendering)当我们渲染一个完全封闭的物体的时候,多边形的背面都是隐藏的,我们无法看见。但是如果这个物体有一些空洞,那么一些背面就可以被看见了。.........
    ▪ [Feature phone 系列]字符信息的展示和绘制原理       [Feature phone 系列]字符信息的显示和绘制原理 这里的内容,不属于完全原创,引用了比部分内容,由于之前整理的时间过早,所以没有记录出处,如有雷同请包涵. 1>首先必须有字库,这.........

[1]自定义ContentProvider 范例演示
    来源: 互联网  发布时间: 2014-02-18
自定义ContentProvider 实例演示

参考:contentprovider的学习实例总结  http://www.cnblogs.com/chenglong/articles/1892029.html
Android学习十九:ContentProvider初步  http://blog.sina.com.cn/s/blog_5688414b0100xagp.html
android 自定义 Content Provider示例  http://byandby.iteye.com/blog/837466


实例源码下载:http://download.csdn.net/detail/yang_hui1986527/4430639


Profile.java

package com.snowdream.contentprovider;

import android.net.Uri;

public class Profile {
	
	/**
	 * 表格名称
	 */
	public static final String TABLE_NAME = "profile";
	
	/**
	 * 列表一,_ID,自动增加
	 */
	public static final String COLUMN_ID = "_id";
	
	/**
	 * 列表二,名称
	 */
	public static final String COLUMN_NAME = "name";
     
     
    public static final String AUTOHORITY = "com.snowdream.provider";
    public static final int ITEM = 1;
    public static final int ITEM_ID = 2;
     
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.snowdream.profile";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.snowdream.profile";
     
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTOHORITY + "/profile");
}


DBHelper.java

package com.snowdream.contentprovider;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

	/**
	 * 数据库名称
	 */
	private static final String DATABASE_NAME = "test.db";  
	
	/**
	 * 数据库版本
	 */
	private static final int DATABASE_VERSION = 1;  

	public DBHelper(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db)  throws SQLException {
		//创建表格
		db.execSQL("CREATE TABLE IF NOT EXISTS "+ Profile.TABLE_NAME + "("+ Profile.COLUMN_ID +" INTEGER PRIMARY KEY AUTOINCREMENT," + Profile.COLUMN_NAME +" VARCHAR NOT NULL);");
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)  throws SQLException {
		//删除并创建表格
		db.execSQL("DROP TABLE IF EXISTS "+ Profile.TABLE_NAME+";");
		onCreate(db);
	}
}


MyProvider.java

package com.snowdream.contentprovider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class MyProvider extends ContentProvider {

	DBHelper mDbHelper = null;
	SQLiteDatabase db = null;

	private static final UriMatcher mMatcher;
	static{
		mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		mMatcher.addURI(Profile.AUTOHORITY,Profile.TABLE_NAME, Profile.ITEM);
		mMatcher.addURI(Profile.AUTOHORITY, Profile.TABLE_NAME+"/#", Profile.ITEM_ID);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getType(Uri uri) {
		switch (mMatcher.match(uri)) {
		case Profile.ITEM:
			return Profile.CONTENT_TYPE;
		case Profile.ITEM_ID:
			return Profile.CONTENT_ITEM_TYPE;
		default:
			throw new IllegalArgumentException("Unknown URI"+uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		long rowId;
		if(mMatcher.match(uri)!=Profile.ITEM){
			throw new IllegalArgumentException("Unknown URI"+uri);
		}
		rowId = db.insert(Profile.TABLE_NAME,null,values);
		if(rowId>0){
			Uri noteUri=ContentUris.withAppendedId(Profile.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(noteUri, null);
			return noteUri;
		}

		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		mDbHelper = new DBHelper(getContext());

		db = mDbHelper.getReadableDatabase();

		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// TODO Auto-generated method stub
		Cursor c = null;
		switch (mMatcher.match(uri)) {
		case Profile.ITEM:
			c =  db.query(Profile.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
			break;
		case Profile.ITEM_ID:
			c = db.query(Profile.TABLE_NAME, projection,Profile.COLUMN_ID + "="+uri.getLastPathSegment(), selectionArgs, null, null, sortOrder);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI"+uri);
		}

		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}

}

MainActivity.java

package com.snowdream.contentprovider;

import com.snowdream.contentprovider.R;

import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.widget.SimpleCursorAdapter;


public class MainActivity extends ListActivity {
	private SimpleCursorAdapter adapter= null;
	private Cursor mCursor = null;
	private ContentResolver mContentResolver = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		initData();
		initAdapter();
	}

	public void initData(){
		mContentResolver = getContentResolver();

		//填充数据
		for (int i = 0; i < 100; i++) {
			ContentValues values = new ContentValues();
			values.put(Profile.COLUMN_NAME, "张三"+i);
			mContentResolver.insert(Profile.CONTENT_URI, values);
		}
	}


	public void initAdapter(){
		//查询表格,并获得Cursor
		//查询全部数据
		mCursor = mContentResolver.query(Profile.CONTENT_URI, new String[]{Profile.COLUMN_ID,Profile.COLUMN_NAME}, null, null, null);

		//查询部分数据
		//String selection = Profile.COLUMN_ID + " LIKE '%1'";
		//mCursor = mContentResolver.query(Profile.CONTENT_URI, new String[]{Profile.COLUMN_ID,Profile.COLUMN_NAME}, selection, null, null);


		//查询一个数据
		//Uri uri = ContentUris.withAppendedId(Profile.CONTENT_URI, 50);
		//mCursor = mContentResolver.query(uri, new String[]{Profile.COLUMN_ID,Profile.COLUMN_NAME}, null, null, null);

		startManagingCursor(mCursor);

		//设置adapter
		adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, mCursor, new String[]{Profile.COLUMN_ID,Profile.COLUMN_NAME}, new int[]{android.R.id.text1,android.R.id.text2});
		setListAdapter(adapter);
	}


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}


}

预览效果:



    
[2] 【OpenGL】GLSL-两面渲染技术(Two-sided rendering)
    来源: 互联网  发布时间: 2014-02-18
【OpenGL】GLSL-双面渲染技术(Two-sided rendering)

当我们渲染一个完全封闭的物体的时候,多边形的背面都是隐藏的,我们无法看见。但是如果这个物体有一些空洞,那么一些背面就可以被看见了。然而因为这些多边形的法向量的方向在这个时候不是正确的,所以会渲染出错误的结果。为了合理的渲染这些背面,我们必须反转法向量,然后基于这些反转的法向量来计算光照。

下图显示了一个采用Phong光照模型绘制茶壶使用双面渲染与否的结果对比:


图一 使用双面渲染与不使用的效果对比

一、固定管线OpenGL实现双面渲染

在固定管线中,我们需要用一个函数来启用双面光照:

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);

这样,OpenGL将会反转表面的法线的方向,表示背面多边形的法线。

实例:

void GLWidget::initLight()
{
	GLfloat light_ambient[]={0.7,0.8,0.9,1.0};   
	GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};   
	GLfloat light_specular[]={1.0,1.0,1.0,1.0};   
	GLfloat light_position[]={2.0,2.0,2.0,0.0};
	GLfloat mat_diffuse[]={0.8,0.8,0.8,1.0}; 

	glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);   
	glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);   
	glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);   
	glLightfv(GL_LIGHT0,GL_POSITION,light_position); 

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_AUTO_NORMAL);
	glEnable(GL_NORMALIZE);
	//glEnable(GL_CULL_FACE);
	//启用双面光照
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse);  
}
效果:



二、可编程管线OpenGL实现双面渲染

假设我们的光照(采用Phong光照模型)计算是基于顶点的。在顶点着色器中,我们需要为每个顶点分别计算两次:front face和back face。两次计算采用的法向量不同。

#version 400

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;

out vec3 FrontColor;
out vec3 BackColor;

struct LightInfo{
	vec4 Position;
	vec3 La;
	vec3 Ld;
	vec3 Ls;
};
uniform LightInfo Light;

struct MaterialInfo{
	vec3 Ka;
	vec3 Kd;
	vec3 Ks;
	float Shininess;
};
uniform MaterialInfo Material;

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;

//转化到视空间
void getEyeSpace(out vec3 tnorm,out vec4 eyeCoords)
{
	//convert normal and position to eye coords
	tnorm = normalize(NormalMatrix * VertexNormal);
	eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
}

//计算Phong光照模型
vec3 phongModel(vec4 eyeCoords,vec3 tnorm)
{
	vec3 s = normalize(vec3(Light.Position - eyeCoords));
	vec3 v = normalize(-eyeCoords.xyz);
	vec3 r = reflect(-s,tnorm);

	vec3 ambient = Light.La * Material.Ka;

	float sDotN = max(dot(s,tnorm),0.0);
	vec3 diffuse = Light.Ld * Material.Kd * sDotN;

	vec3 specular = vec3(0.0);
	if(sDotN > 0)
		specular = Light.Ls * Material.Ks * 
					pow(max(dot(r,v),0.0),Material.Shininess);

	return (ambient + diffuse + specular);
}

void main()
{
	vec3 tnorm;
	vec4 eyeCoords;
	getEyeSpace(tnorm,eyeCoords);
	FrontColor = phongModel(eyeCoords,tnorm);
	BackColor = phongModel(eyeCoords,-tnorm);

	gl_Position = MVP * vec4(VertexPosition,1.0);
}
在片断着色器中,我们根据关键字gl_FrontFacing的值来为片断赋予颜色值。

gl_FrontFacing是GLSL内置的关键字,它代表图元是面向光源还是背向光源。

片断着色器 twosided.frag:

#version 400

in vec3 FrontColor;
in vec3 BackColor;

layout (location = 0) out vec4 FragColor;

void main()
{
	if(gl_FrontFacing)
	{
		FragColor = vec4(FrontColor,1.0);
	}
	else
	{
		FragColor = vec4(BackColor,1.0);
	}
}



    
[3] [Feature phone 系列]字符信息的展示和绘制原理
    来源: 互联网  发布时间: 2014-02-18
[Feature phone 系列]字符信息的显示和绘制原理
这里的内容,不属于完全原创,引用了比部分内容,由于之前整理的时间过早,所以没有记录出处,如有雷同请包涵.
1>首先必须有字库,这里只涉及点阵字库[不同国家,不同大小]
    因为点阵字库在嵌入式设备上使用最广。
    有点:方便开发,执行效率高;
    缺点:通用性差[不能对字体进行缩放等操作].
2>如何添加字库?
首先澄清一些概念:
字符:是各种文字和符号的总称,包括各个国家的文字,标点符号,图形符号,数字等.
字符集:是多个字符的集合,如:ASCII字符集,ISO8859字符集,GB2312-80字符集,BIG5字符集,GB18030字符
           集,Unicode字符集等.<字符的集合>
字符编码:规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”.
              当各个国家和地区在制订编码标准的时候,"字符的集合"和"编码"一般都是同时定制的.因此我们平常所说的"字  
              符集",比如:GB2312等,除了有"字符的集合"这层含义外,同时也包含了"编码"的含义.
内码:维基百科上解释,内码指的是"将资讯编码后,透过某种方式存储在特定的记忆装置时,装置内部的编码形式"。在不
        同的系统中,会有不同的内码。比如:GB2312字符集内定义的编码的含义[双字节,四字节],ASCII字符集单字节    
        编码.
Windows 操作系统上,记事本保存TXT格式的三个选项:
ANSI, American National Standards Institute(ANSI——美国国家标准学会),ASCII字符集[英文系统]/GB2312字符集[简体中文系统]
Unicode,
Unicode big endian,
UTF-8,
    首先我们需要根据自己的平台[硬件平台无关,软件平台],当前支持哪种字符编码规范[或者说当前使用的是哪种]
    当前可供使用的字符集编码规范:
    1>ASCII用来表示英文字符的一种编码规范,每个字符占用一个byte宽度,因此它能表示的最大英文字符数是256.
        英文字符并没有这么多因此,一般只用前128个(最高位为0),其中包括了控制字符、数字、大小写字母和其他一些符号.
          而最高位为1的另128个字符被成为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其他符号,这种字符编
          码规范显然用来处理英文没有什么问题。(实际上也可以用来处理法文、德文等一些其他的西欧字符,但是不能和英文通用),但
          是面对中文、阿拉伯文之类复杂的文字,255个字符显然不够用.
     2>GB2312-80
          GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,
          
        ......
        

         占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE.
         由于上面的原因,中文的文字编码规范叫做“GB2312-80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准
          化这一点,把一个中文字符用两个扩展ASCII字符来表示.
          问题:
          中文文字没有真正属于自己的编码,因为扩展ASCII码虽然没有真正的标准化,但是PC里的ASCII码还是有一个事实标准的
         (存放着英文制表符),所以很多软件利用这些符号来画表格。这样的软件用到中文系统中,这些表格符就会被误认作中文字,
         破坏版面。而且,统计中英文混合字符串中的字数,也是比较复杂的,我们必须判断一个ASCII码是否扩展,以及它的下一个
         ASCII是否扩展,然后才“猜”那可能是一个中文字。
          扩展问题:
          GB2312是内地国家标准;Big5是台湾标准,而且同时和GB2312存在一些相同的编码.
          所以手机、MP3一般只支持GB2312.
---------------------------------
      当中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存,于是想到把那些ASCII码中127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展。兼容ASCII。
       对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现.
分区表示
GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601。
字节结构
在使用GB2312的程序通常采用EUC[Extend Unix Code]储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。
“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存。(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。

       3>Big5 
           同样由于第一个原因,TW自己也弄了一个标准:Big5其中和GB3212里面存在一些相同的编码.
       4>Unicode
           Unicode的学名"Universal Multiple-Octet Coded Character Set",
           前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1
           兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。
           简称为UCS。UCS可以看作是"Unicode Character Set"的缩写.
           很过国家的语言都面临上面的问题,因此要解决这个问题,Unicode编码就诞生了。Unicode有两个标准:
            <UCS-2(Unicode-16),用2个字节为字符编码> Unicode Character Set
            以目前常用的UCS-2为例,它可以表示的字符数为2^16=65535,基本上可以容纳所有的欧美字符和绝大部分的亚洲字符。
            在Unicode里,所有的字符被一视同仁。汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,注意,现在的汉字是
            “一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了。
            问题:
            A.兼容ASCII编码
            由于Unicode诞生的时候不是所有的系统都使用Unicode来处理字符,因此必须考虑这个严峻的问题:和ASCII字符集之间的不兼容问题。
            ----ASCII字符是单个字节的,比如“A”的ASCII是65。而Unicode是双字节的,比如“A”的Unicode是0065,这就造成了一个
                 非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了
            B.C语言使用'\0'作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处
               理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉.
            <UCS-4(Unicode-32),用4个字节为字符编码>
             UCS-2、UCS-4、BMP[Basic Multilingual Plane]
             UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,
             最高位必须为0)编码。下面让我们做一些简单的数学游戏:
             UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位
             UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个
             字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同.
             group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。
             将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。
             而目前的UCS-4规范中还没有任何字符被分配在BMP之外.
      5>UTF= UCS Transformation Format
            要解决上面的问题,UTF诞生了,UCS转换格式,它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。
            现在流行的UTF有2种:UTF-8和utf-8.
            A.utf-8:
               其中utf-8和上面提到的Unicode本身的编码规范是一致的,因此不用再叙述.
            B.UTF-8:
               它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容.
               UTF-8有点类似于Haffman编码,它将Unicode编码为00000000-0000007F的字符,用单个字节来表示:
               00000080-000007FF的字符用两个字节表示
               00000800-0000FFFF的字符用3字节表示
               因为目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,
               UTF-8最多需要用6字节表示一个字符.
               在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,
              因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理.
            PS:
            在Unicode出来之前总共有三套中文编码标准:
            GB2312-80,是中国大陆使用的国家标准,其中一共编码了6763个常用简体汉字。Big5,是台湾使用的编码标准,编码了台湾使用
            的繁体汉字,大概有8千多个。HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同.
            这3套编码标准都采用了两个扩展ASCII的方法,因此,几套编码互不兼容,而且编码区间也各有不同。
            --------------------
            UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:
            UCS-2编码(16进制) UTF-8 字节流(二进制)
  0000 - 007F 0xxxxxxx
  0080 - 07FF 110xxxxx 10xxxxxx
  0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
           例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。
           将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,
           即E6 B1 89.
           utf-8以16位为单元对UCS进行编码。对于小于0x10000的UCS码,utf-8编码就等于UCS码对应的16位无符号整数。对于不小于
           0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为
           utf-8和UCS-2基本相同。但UCS-2只是一个编码方案,utf-8却要用于实际的传输,所以就不得不考虑字节序的问题.
           UTF的字节序和BOM[Byte Order Mark]
           UTF-8以字节为编码单元,没有字节序的问题。utf-8以两个字节为编码单元,在解释一个utf-8文本前,首先要弄清楚每个编码单元
           的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到utf-8字节流“594E”,那么这
           是“奎”还是“乙”?
           Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有
           点小聪明的想法:
           在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该
           出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
           这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符
           "ZERO WIDTH NO-BREAK SPACE"又被称作BOM.
           UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是
           EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了.
           Windows就是使用BOM来标记文本文件的编码方式的.
        6>GBK
           1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符.
            国际上又制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现.
           GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容.
       7>GB18030
            GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030.
            2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、
            维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求.
       8>HKSCS
           HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同.
     PS:
     big endian和little endian
     endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,
     还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian.
     字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,
     程序员设计了用于简体中文的GB2312和用于繁体中文的big5.
   
    其实任何平台上都是同样的过程:把font.c文件添加到对应的编译目录下就可以了。
   
3>系统编译好之后,运行时如何找到并正确显示出来对应的字符?
    the font use the unicode Character coding standard[字符编码规范].
    u4E00_4E5A_font.h  //Just include all font information from 0X4E00~0X4E5A.
 
    //The font information include:
     //Ex, 4E00 is the chinese character “一”
     bbw=16, bbh=16, bbx=0, bby=0, width=16
     //Comments: we can image the screen is big area, a font will take a rectangular
     //which have start coordination< x,y >, with and height.  the font are a series binary data which 1 is
     //showing   a point in current screen, 0 is showing nothing on the screen on the 16X16 screen erea.
0x0000, //16 bit size                                
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0xfffe,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,
    u4E00_4E5A_font_offset.h  //Just include the value of a series font offset from 0X4E00~0X4E5A.
    // Ex,
       11904,      /* (0x4e00) */
       .....
       0              /* (0x4e5a) */ “乙”
    u4E00_4E5A_font_width.h  //Just include the value of a series font with
       16,   /* (0x4e00) */
       ......
        8     /* (0x4e5a) */    “乙”

---------------------------------------
    
T_FontBmInfo MMI_lcd_get_font_Bm_data(UINT16 wUnicode)
{
    UINT8 i = 0;
    INT32 wOffset = -1;
    INT32 wLocalOffset = -1;
    T_FontBmInfo tFontBmInfo;
    //Please add the detail comments at here!!
    for (i = 0;  g_tFontTable[i].bCodeType != 0xFF ; i++)
    {   //Please add the detail comments at here!!
        if (wUnicode >= g_tFontTable[i].bCodeStart && wUnicode <= g_tFontTable[i].bCodeEnd)
        {
            //Please add the detail comments at here!!
            wOffset = wUnicode - g_tFontTable[i].bCodeStart;
            if(g_tFontTable[i].bdwOffset[wOffset]) //check all table until find it.
            {
                break;
            }
            else
            {  //Please add the detail comments at here!!
                wOffset = -1;
            }
        }
	else
	{      //Please add the detail comments at here!!
		wOffset = -1;
	}
	
    }

    if (-1 == wOffset)
    {
        wOffset = 32;
        i = 0;
    }
    wLocalOffset = g_tFontTable[i].bdwOffset[wOffset]-g_tFontTable[i].bdwOffset[0];
    tFontBmInfo.bWidth = g_tFontTable[i].baWidth[wOffset];
    tFontBmInfo.pwFontBm = (UINT16 *)(&g_tFontTable[i].baFontRowData[wLocalOffset]);
    tFontBmInfo.bHeight = LCD_DEFAULT_FONT_HEIGHT;
    return tFontBmInfo;
}

4>把找到的字符显示到LCD屏幕上
    
void MMI_lcd_show_font_Bm(UINT16 wShowPos, T_FontBmInfo *ptFontBmInfo, UINT16 wFwdColor, UINT16 wBackColor)
{
    UINT8 bLoopHeight = 0;
    UINT8 bLoopWidth = 0;
    UINT8 i = 0;
    UINT16 wFontword;
    UINT16 wOffset = 0;
    UINT16 wLcdPointIndex = wShowPos;
    T_ALLCDRect tRect;

    //write font bitmap to lcd
    //Please add the detail comments at here!!
    for (bLoopHeight = 0; bLoopHeight < ptFontBmInfo->bHeight; bLoopHeight++)
    {   //Please add the detail comments at here!!
        for (bLoopWidth = 0; bLoopWidth < ptFontBmInfo->bWidth; bLoopWidth+=16)
        {   //Please add the detail comments at here!!
            wFontword = ptFontBmInfo->pwFontBm[wOffset];
            //Please add the detail comments at here!!
            for (i = 0; i < min(16, ptFontBmInfo->bWidth-bLoopWidth); i++)
            {  //Please add the detail comments at here!!
                if (((wLcdPointIndex) > (AL_PLCD_MAX_WIDTH * AL_PLCD_MAX_HEIGHT - 1)) || (wLcdPointIndex < 0))
                {
                    return;
                }
                if (wFontword & 0x8000)//Please add the detail comments at here!!
                {
                    g_waLcdPanelBuf[wLcdPointIndex] = wFwdColor;
                }
                else
                {
                    if (wFwdColor != wBackColor)
                    {
                        g_waLcdPanelBuf[wLcdPointIndex] = wBackColor;
                    }
                }
                wFontword <<= 1;
                wLcdPointIndex++;
            }// for (i = 0; i < min(16, ptFontBmInfo->bWidth-bLoopWidth); i++)
            wOffset++;
        }// for (bLoopWidth = 0; bLoopWidth < ptFontBmInfo->bWidth; bLoopWidth+=16)
        wLcdPointIndex += (AL_PLCD_MAX_WIDTH - ptFontBmInfo->bWidth);
    }// for (bLoopHeight = 0; bLoopHeight < ptFontBmInfo->bHeight; bLoopHeight++)
    //Please add the detail comments at here!!
    Mmi_lcd_request_refresh(tRect);
}   




    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3