【原创】我的修改S508字模心得

topkins

普通会员
2003-07-23
36
0
0
[FONT=宋体]很多人问我如何修改刷机文件的字模,其实这个没有什么神秘的,总结一下两个词:胆大、心细。

说实话,对于S508我也是新手,以前我一直用三星N188用了将近三年,看到彩屏手机在大街上多了起来,才请示我们家领导要换手机,比来比去,又在蓝色和我爱三星泡了一个多月,基本敲定水S508,在当地市场上转来转去,整个石家庄都找不到原装的座充,正好赶上蓝色搞S508特价,于是就从蓝色把我的小S请回了家,在此也要多谢AD仔。

拿到的当然是G2版,用了一阵子,除了短消息下面的数字重叠,还没有发现什么别的问题,后来8G大哥放出了最新的F1版,就想试试,只是试试,因为我本身就是做技术的,对软件这个东西向来不是要求最新,只是要求够用好使(我现在家里的计算机和单位的计算机一直在用Win2k,够用好使嘛),刷了之后,感觉果真修改了G2那个数字重叠的BUG,对于其他,我还真是没有看出来什么不同,因为我用手机也是一样的,够用好使,对于其他的一些功能,用得很少。至于F1和 G2的字体,好像大多数人说G2的好看,其实我认为这是见仁见智和观看习惯的问题,用G2的朋友试试把你的手机语言改成繁体中文,保证恶心死你,繁体中文感觉个个都没有长开。我对字体的看法是:G2的字体(简体中文)比F1的字体高度上要小一个点,可能看起来秀气一些,尤其是在菜单里面,多行汉字看起来比较舒服;F1的字体比较中统,照顾了繁体中文,总体感觉偏瘦偏高。于是也就有了把G2的字体换到F1上的想法。

有了理想,剩下的就是实践了,我在97年的时候经常做西文DOS下的汉字显示程序,对汉字的字模分析有一定的经验,这个也没有什么高深的,说明白一点,常见的字库有两种:点阵字库和矢量字库,点阵字库就是纪录一个汉字的点阵信息,矢量字库就是纪录汉字的笔划信息,很容易看出来,手机中用的是点阵字库,因为他没有放大,一个笔划就是由一行或一列点组成的,而且很容易看出来,用的是16*16的点阵字体,这也是最常用的点阵字体,因为一个字节就是8个二进制位,一个二进制位表示一个点,那么32个字节就正好保存一个汉字的16*16的点阵信息(32*8=16*16),关键是这32个字节的排列规则和在文件中的偏移地址。

上面的两个关键没有现成资料,只能靠经验了,我的想法是:要解决这两个关键只要尝试两次,就能看出最少半个汉字,下面给我的的程序:

#include     <graphics.h>
#include     <stdio.h>
#include     <stdlib.h>

main(int argc,char *argv[]) {
    FILE    *fp;
    int     GraphDriver;
    int     GraphMode;

    int     x,y,z;

    long    offset;
    int     ch;

    if(argc!=3) {
        printf("USUAL:graph filename offset\n\n");
        exit(0);
    }

    fp=fopen(argv[1],"rb");
        if(fp==NULL) {
        printf("FILE :[%s] open error\n\n",argv[1]);
        exit(0);
    }

    offset=atol(argv[2]);
    fseek(fp,offset,SEEK_SET);
    GraphDriver = DETECT;
    initgraph( &GraphDriver, &GraphMode, "" );
    x=y=z=0;

    while(1) {
        gotoxy(1,1);
        printf("[%9ld]",ftell(fp));
        for(y=0;y<26;y++) {
            for(x=0;x<40;x++) {
                for(z=0;z<16;z++) {
                    ch=fgetc(fp);
                    if(feof(fp))
                        goto end;

                    setlinestyle(4,(ch&0xff),1);
/* 画线方式 */
                    line(x*16+z,y*17+20,x*16+z,y*17+7+20);
                }

                for(z=0;z<16;z++) {
                ch=fgetc(fp);
                    if(feof(fp))
                        goto end;

                    setlinestyle(4,(ch&0xff),1);
/* 画线方式 */
                    line(x*16+z,y*17+8+20,x*16+z,y*17+15+20);
                }
            }
        }
        ch=getch();
        if(ch==&#39q&#39||ch==&#39Q&#39)
            goto end;
        cleardevice();
    }
end:
    fclose(fp);
    printf("endend");

    getch();

    closegraph();
}

以上程序在TC2.0下编译,程序写的比较乱,大体思路是从文件头开始读出每一个字节画线,需要尝试的只是两处/* 画线方式 */下面一行,也就是画线方向(可能要从左向右,也可能要从右向左,还可能要从上向下,还可能要从下向上)。

先拿F1版本的BIN1文件看看以上程序的执行结果:



看出来了吧,汉字出来了,记住最上面的偏移地址,当然,这是本页第一行的开始地址,汉字部分还需要往下找。虽然很难看,但仍然可以看出,第一个出现的汉字应该在第12行28列的位置,也就是((12-1)*40+28-1)*32+3161600=3176544=(0x307860)附近,前后均不超过32字节。

我喜欢用UE,打开文件,看偏移3176544附近:



看看我标出的地方,是不是很可疑?,记下地址0x307878换算成10进制3176568,带参数执行上面的程序



可以看到第一个汉字“一”(因为在UTF-8码中,一字的UTF-8码(0x E4B880)是最小的)出来了,怎么汉字还有错位?而且第一个汉字前面还有一个小点,应该是那个0x10的问题,想想,0x10就是16,应该就是标记以下的数据是一个16*16的点阵数据。再看上面的图,到后面又出现了混乱,看来是分段保存的,UE往下翻,当然还有两种方法:1、可以一直寻找标志0x10,每错32个字节就应该有一个0x10;2、用上面的方法算出结束位置。于是我们又找到了这里:



再看看标出的部分,想到了什么?这就是用UTF-8码的每个汉字的顺序标出的每个汉字相对段的偏移地址 0x 0000就是一字的,0x0021就是丁字的,正好相差0x21=33字节,这里要注意,因为在接下来的寻找G2的字模数据时很有用。根据这一段的大小,可以看出第一段一共存放了512个汉字,因为这里记录了512个汉字的段内偏移信息。

剩下的关于F1的不用说了,就是找出每一段的起始地址、结束地址、段内汉字数。

我一共找出了20个段,分别是:
1. START:307878H(3176568D) END:30BA77H(3193463D) LENGTH:4200H(16896D) 512*33(BYTE)
2. START:30BE78H(3194488D) END:314277H(3228279D) LENGTH:8400H(33792D) 1024*33(BYTE)
3. START:314A78H(3230328D) END:31CE77H(3264119D) LENGTH:8400H(33792D) 1024*33(BYTE)
4. START:31D678H(3266168D) END:325A77H(3299959D) LENGTH:8400H(33792D) 1024*33(BYTE)
5. START:326278H(3302008D) END:32E677H(3335799D) LENGTH:8400H(33792D) 1024*33(BYTE)
6. START:32EE78H(3337848D) END:337277H(3371639D) LENGTH:8400H(33792D) 1024*33(BYTE)
7. START:337A78H(3373688D) END:33FE77H(3407479D) LENGTH:8400H(33792D) 1024*33(BYTE)
8. START:340678H(3409528D) END:348A77H(3443319D) LENGTH:8400H(33792D) 1024*33(BYTE)
9. START:349278H(3445368D) END:351677H(3479159D) LENGTH:8400H(33792D) 1024*33(BYTE)
10.START:351E78H(3481208D) END:35A277H(3514999D) LENGTH:8400H(33792D) 1024*33(BYTE)
11.START:35AA78H(3517048D) END:362E77H(3550839D) LENGTH:8400H(33792D) 1024*33(BYTE)
12.START:363678H(3552888D) END:36BA77H(3586679D) LENGTH:8400H(33792D) 1024*33(BYTE)
13.START:36C278H(3588728D) END:374677H(3622519D) LENGTH:8400H(33792D) 1024*33(BYTE)
14.START:374E78H(3624568D) END:37D277H(3658359D) LENGTH:8400H(33792D) 1024*33(BYTE)
15.START:37DA78H(3660408D) END:385E77H(3694199D) LENGTH:8400H(33792D) 1024*33(BYTE)
16.START:386678H(3696248D) END:38EA77H(3730039D) LENGTH:8400H(33792D) 1024*33(BYTE)
17.START:38F278H(3732088D) END:397677H(3765879D) LENGTH:8400H(33792D) 1024*33(BYTE)
18.START:397E78H(3767928D) END:3A0277H(3801719D) LENGTH:8400H(33792D) 1024*33(BYTE)
19.START:3A0A78H(3803768D) END:3A8E77H(3837559D) LENGTH:8400H(33792D) 1024*33(BYTE)
20.START:3A9678H(3839608D) END:3B92DDH(3904221D) LENGTH:FC66H(64614D) 1958*33(BYTE)


接下来应该找G2的了,按照寻找F1的经验,我们很容易找到第一段的起始地址:3156988,



但是很奇怪,他的规律没有F1版那么明显,最起码不是33个字节一个汉字那么整齐,这个就要对照字模数据后面的段内地址表来看。



看我标出的部分,很奇怪,第三、四个汉字只想差1个字节,而且第三个汉字对应的字模起始地址不是0x10,是0x00,想了想明白了,这说明那个汉字没有字模数据,原因可能是为了减小字模数据占用宝贵的空间,所以取消了不常用汉字的字模数据,于是就采用了这种方式(我自己给他起名叫压缩字模)。

剩下的就是找出G2的每段的起始地址、结束地址、段内汉字数了:

1. START:302BFCH(3156988D) END:305BFBH(3169275D) LENGTH:3000H(12288D) 512( 368*33+144(BYTE))
2. START:305FFCH(3170300D) END:31215BH(3219803D) LENGTH:C160H(49504D) 2048(1483*33+565(BYTE))
3. START:31315CH(3223900D) END:31F19BH(3273115D) LENGTH:C040H(49216D) 2048(1474*33+574(BYTE))
4. START:32019CH(3277212D) END:32CBFBH(3329019D) LENGTH:CA60H(51808D) 2048(1555*33+493(BYTE))
5. START:32DBFCH(3333116D) END:33A67BH(3384955D) LENGTH:CA80H(51840D) 2048(1556*33+492(BYTE))
6. START:33B67CH(3389052D) END:34795BH(3438939D) LENGTH:C2E0H(49888D) 2048(1495*33+553(BYTE))
7. START:34895CH(3443036D) END:354D7AH(3493243D) LENGTH:C420H(50208D) 2048(1505*33+543(BYTE))
8. START:355D7CH(3497340D) END:362F7BH(3551099D) LENGTH:D200H(53760D) 2048(1616*33+432(BYTE))
9. START:363F7CH(3555196D) END:370FDBH(3608539D) LENGTH:D060H(53344D) 2048(1603*33+445(BYTE))
10.START:371FDCH(3612636D) END:37ED9BH(3665307D) LENGTH:CDC0H(52672D) 2048(1582*33+466(BYTE))
11.START:37FD9CH(3669404D) END:38B541H(3716417D) LENGTH:B7A6H(47014D) 1958(1408*33+550(BYTE))

到这里,我们基本大功告成了,只剩转换了,这里不用多说,下面是我的转换程序,懂点计算机语言的朋友都能看懂。

#include <stdio.h>
#include <stdlib.h>

long g2_sta[12]=    {
            3156988L,    /* 512 */
            3170300L,
            3223900L,
            3277212L,
            3333116L,
            3389052L,
            3443036L,
            3497340L,
            3555196L,
            3612636L,
            3669404L,    /* 1958 */
        } ;

long f1_sta[21]={
            3176568L,    /* 512 */
            3194488L,
            3230328L,
            3266168L,
            3302008L,
            3337848L,
            3373688L,
            3409528L,
            3445368L,
            3481208L,
            3517048L,
            3552888L,
            3588728L,
            3624568L,
            3660408L,
            3696248L,
            3732088L,
            3767928L,
            3803768L,
            3839608L,        /* 1958 */
            3839700L
        } ;

int f1_seg[21]=    {
            512,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1024,
            1958
        } ;

main() {

    FILE *f1,*g2,*newf1;

    long now_cur;
    int now_seg=0;
    int now_zi;
    int ch;
    int ttt;

    int ch_f1,ch_g2;
    
    f1=fopen("d:\\f1_1.bin","rb");
    if(f1==NULL) {
        printf("file [d:\\f1_1.bin open error \n");
        exit(0);
    }

    g2=fopen("d:\\g2_1.bin","rb");
    if(g2==NULL) {
        printf("file [d:\\g2_1.bin open error \n");
        fclose(f1);
        exit(0);
    }
    
    newf1=fopen("d:\\newf1_1.bin","wb");
    if(g2==NULL) {
        printf("file [d:\\newf1_1.bin create error \n");
        fclose(f1);
        fclose(g2);
        exit(0);
    }
    
    now_cur=0;

    while(now_cur<f1_sta[0]) {
        ch=fgetc(f1);
        fputc(ch,newf1);
        now_cur+=1L;
    }

    while(now_seg<20) {
        if(now_seg==0)
            fseek(g2,g2_sta[0],SEEK_SET);
        if(now_seg==1)
            fseek(g2,g2_sta[1],SEEK_SET);
        if(now_seg==3)
            fseek(g2,g2_sta[2],SEEK_SET);
        if(now_seg==5)
            fseek(g2,g2_sta[3],SEEK_SET);
        if(now_seg==7)
            fseek(g2,g2_sta[4],SEEK_SET);
        if(now_seg==9)
            fseek(g2,g2_sta[5],SEEK_SET);
        if(now_seg==11)
            fseek(g2,g2_sta[6],SEEK_SET);
        if(now_seg==13)
            fseek(g2,g2_sta[7],SEEK_SET);
        if(now_seg==15)
            fseek(g2,g2_sta[8],SEEK_SET);
        if(now_seg==17)
            fseek(g2,g2_sta[9],SEEK_SET);
        if(now_seg==19)
            fseek(g2,g2_sta[10],SEEK_SET);

        now_zi=0;
        while(now_zi<f1_seg[now_seg]) {
            ch_g2=fgetc(g2);
            ch_f1=fgetc(f1);
            if(now_zi==0)
                printf("ch_gw=[%d]\n",ch_g2);
            fputc(ch_f1,newf1);

            if(ch_g2==0x10) {
                for(ttt=0;ttt<32;ttt++) {
                    ch_g2=fgetc(g2);
                    ch_f1=fgetc(f1);
                    fputc(ch_g2,newf1);
                }
            }
            else {
                for(ttt=0;ttt<32;ttt++) {
                    ch_f1=fgetc(f1);
                    fputc(ch_f1,newf1);
                }
            }

            now_zi++;
        }

        while(ftell(f1)<f1_sta[now_seg+1]) {
            ch_f1=fgetc(f1);
            fputc(ch_f1,newf1);
        }

        now_seg++;
    }

    while(1) {
        ch_f1=fgetc(f1);
        if(feof(f1))
            break;
        fputc(ch_f1,newf1);
    }

    fclose(f1);
    fclose(g2);
    fclose(newf1);
}

写完了,剩下就是享受成果了,告诉大家一个秘密,我虽然改了F1的字模数据,但我刷了之后用了一天,就又刷回到了原版的F1,只是改了一个一个汉字的字模数据:“中”,因为每天从屏幕上看到中国移动通信,而原来的F1的中字太瘦了,新的中字的字模数据我也没有用G2的,只是手工增加了一下宽度,把偏移地址3178053的
00 00 F0 10 10 10 10 FF 10 10 10 10 F0 00 00 00
00 00 07 02 02 02 02 FF 02 02 02 02 07 00 00 00

改成
00 F0 10 10 10 10 10 FF 10 10 10 10 10 F0 00 00
00 07 02 02 02 02 02 FF 02 02 02 02 02 07 00 00

就好看多了。

以上的东西,如果你看不懂我的程序,也不用深究,这里只是告诉大家一个方法,程序只不过是自己制造的一个提高效率的工具。另外,希望大家看了这些文字和图片以后,对S508的认识又进了一步,对于新手来说,共同学习,对于老手来说,抛砖引玉,对于高手来说,班门弄斧罢了。

另外,以上只是拿S508做模特,相信对于其它手机来说,同样的方法应该也是可行的。
[/FONT]
 

elaugh

普通会员
2004-04-10
129
0
16
真不错,受教育,程序我是看不懂了,呵呵,N年前学过BASIC,汗~~~~~~~~~~加声望先~~~~~~~~
 

wangjh

普通会员
2004-05-22
125
0
0
老兄你真的太厉害了,偶佩服得全体投地!但偶看了N遍还是不懂啊! :$ :$ :$