Minisoyo社区's Archiver

欢迎注册泡面三国

¥贱ヴMAN 发表于 2008-6-21 12:07

关于图片字库的汉化

话不多说勒~
经过长期郁闷后
仅以此贴~
贡献给像我一样
在汉化路口徘徊的新人们
....
在网上收集到的一些关于汉化手机游戏图片字库的教程和常识...


浅谈图片字库汉化-威力加强版
前几天写的文章很受大家欢迎,应大家要求写详细的,但你最好有编程的基础不然还是很难的
1)首先无论什么方法你要看到游戏的源代码(我通常是反汇编dj java decompiler 2.9或小颖java源代码反编译专家,上网很好找到的,安装后找到class点右键打开就行了)
2)艰苦的除错工作(就是说反汇编并不能100%的还原为原始的java文件,多少都会有错误,至于错误是1个还是100个就是人品问题了:),太多就放弃吧,这部分你多少要懂点程序不然你只能撞大运碰上1个bug也没有的程序了)
3)用ctrl+f找到所有带"font"文字的内容(顾名思义font就是有关文字的内容,有个别bt的人写程序时放到其他地方 那...)
4)里面一定有一行或几行里有"drawimage"(drawimage听名字就知道是绘制图片的意思)如下
public void print(graphics g, int i, int j, string s1)
    {
        if(g == null)
            return;
        if(!init)
            return;
        int l = 0;
        int j2 = s1.length();//<-计算了一下文字的长度
        int i1 = i;
        int j1 = j;
        for(int i2 = 0; i2 < j2; i2++)
        {
            char c = s1.charat(i2);//<-字串转为字符
            int k = 0;
            if(c >= 'a' && c <= 'z')//<-计算"a"-"z"的位置
                k = c - 97;
            if(c >= 'a' && c <= 'z')//<-计算"a"-"z"的位置
                k = c - 65;
            if(c >= '0' && c <= '9')//<-计算"0"-"9"的位置
                k = (c - 48) + 26;
            int k1 = (k % 12) * charxsize;
            int l1 = (k / 12) * charysize;
            if(c != ' ' && j1 >= -charysize && j1 <= screenheight)
            {
                g.setclip(i1, j1, charxsize, charysize);//<-财切(相当于蒙板)
                g.drawimage(font, i1 - k1, j1 - l1, 0);//画图(每次只画一个字的图)
            }
            i1 += charxspacing;
            if(++l == linewidth)
            {
                i1 = i;
                j1 += charyspacing;
                l = 0;
            }
        }

    }
  看到没g.drawimage(font, i1 - k1, j1 - l1, 0);就是绘制图片的
5)把这个方法的内容全去掉,也可能只去部分具体情况具体分析(我们要重新改写上面这部分的内容,叫他显示中文)
6)改为g.drawstring(string类的字串,x坐标,y坐标,锚点);(drawstring绘制字符串的意思)
7)当然在他前面加上g.setcolor(0x颜色数值);(setcolor设置颜色的意思)
                加上g.setfont(font.getfont(font.face_system, font.style_plain,font.size_small));(setfont设置文字的意思)
         加上g.setclip(0,0,128,128);(setclip设置可见区域的意思)
8)还原原来的文件就可以用大家常用的其他方法继续做了

总结g.drawstring(string, x, y, 0);中string是要显示的字符串,x是要显示的字符串的左上顶点的横坐标位置(以像素为单位40最大是128),y是要显示的字符串的左上顶点的纵坐标位置(以像素为单位40最大是128),最后的0就不要管了(60里是20)
ps:x,y两点大多不是在此处决定位置的,只要把这个方法的参数,如public void print(graphics g, int i, int j, string s1)中的i和j直接写上就可以了,注意i和j前面标明他的类型是int整数型的或byte位

    g.setcolor(0x000000);设置颜色为黑
  g.setcolor(0xffffff);设置颜色为白
  其中0x后面跟的数值决定颜色,一共6个数前2个决定红色,中间2个决定绿色,后2个决定蓝色(00-ff由深到浅,试一下就知道了)






另类图片字库的汉化——图片字汉图片字
开始了,今天要给大家说的是图片字库的汉化,一般说来使用了图片字库的游戏都不能简单汉化,如果不对class文件进行修改的话,只有用反编译的方法啦。那么我们就用一个比较经典的益智类游戏nuts为例来讲讲图片字库的汉化了。游戏就在网上搜索下吧,这里暂时不提供啦。

首先是反编译了,这个游戏反编译来的代码错误比较少,大部分都是异常没有被catch的这种错误,改一下就ok啦,有一处出现了goto语句,注意下反编译的注释,也很容易搞定,那么,最重要的部分就完成了。

接下来,我们开始寻找相关代码了,看看图片字库的关键所在。很快在helfer这个类中,我们看到了:

public static int textout(int i, int j, string s, int k, int l)

public static int textoutmulti(int i, int j, string as[], int k, int l, int i1, int j1)

public static int drawchar(int i, int j, int k)

这几个相关的方法,按照常规的方法,要把这些方法改成graphics.drawstring(string s,int x,int y,int d)这样直接调用系统的画字方法,但是这里的方法都有返回值,虽然开始我们不知道它返回的值有什么用,但是直接这样做就很可能出现问题。接下来再看看游戏的读入方式,图片字库大部分都采用的是单字节读入方式,这样方便它把图片位置与字母一一对应。我们看到了以下几个方法:

public static void loadrules(inputstream inputstream)

public static void loadcredits(inputstream inputstream)

public static void loadtext(inputstream inputstream)

单字节的方法有了源代码就比较容易搞定了,因为最简单的方法是比如我们在

public static void loadrules(inputstream inputstream)

    {

        int i;

        rules = new string[(i = readnextvalue(inputstream)) - 1];

        for(int j = 0; j < i - 1; j++)

            rules[j] = readnextstringplain(inputstream);







    }

方法的最后一段加上一句:system.out.println(“rules[” + j + “] =  ” + rules[j] );

把程序运行一下,信息就会打印出来:

rules[0] =  #






rules[1] =  game






rules[2] =  goal:






rules[3] =  $






rules[4] =  a






rules[5] =  nut






rules[6] =  is






rules[7] =  hidden






rules[8] =  in






rules[9] =  each






rules[10] =  level






rules[11] =  and






……






rules[187] =  have






rules[188] =  a






rules[189] =  better






rules[190] =  overview.






怎么样,那么最简单方法是把






public static string rules[];






这个量直接写成






public static string rules[] =






{






“#”,” game”,……






};






然后把public static void loadrules(inputstream inputstream)这个方法留空或者直接删除掉。到此单字节的问题就解决了。然后再看图片字库。

public static int textout(int i, int j, string s, int k, int l)

public static int textoutmulti(int i, int j, string as[], int k, int l, int i1, int j1)

这两个方法通过看代码,发现一个是画单个字,一个是画字数组的,而且textoutmulti通过返回值如果是0就表示字全部画完,而且中间穿插了大量字符判断换行等等操作,很复杂,如果用传统的方式来修改,需要对运算进行大量修改,而且不同机型号的字体高度不一样,对不同机型来还得把字符背后的背景条高度同时修改,还有很多坐标要重新定义……想起来就觉得头大而且偶也没那么多时间(更重要是水平不够哈)。那么我们再投机取巧一下吧:)textout这个方法画的字符全部是public static string text[];这个,那么我们把text里面的字打印出来,然后翻译好(这个工作自然由无名大侠来做啦)(无名:一年前不是就翻译好了吗?kim:这个……那个……酒……自然越久越香了……)然后把字做成图片,每行就是一个组。记得用ps做图的时候要固定行高,不然后面不好计算。(这种方法是无视内存的,创建这么大一张图片会占很大内存空间)

然后把public static int textout(int i, int j, string s, int k, int l)

修改成:

public static image fontimagecn = null;

public static void textout(int i, int j, int id, int k, int l)

    {

           if(fontimagecn == null)

            try

            {

                fontimagecn = image.createimage(imagepath + "fontcn");

                fontbackimage = image.createimage(imagepath + "font_b");

            }

            catch(ioexception _ex) { }

            drawcharback(i, j, 240, 16, l);

            acanvas.c.drawregion(fontimagecn , 0 , 14 * id, 94 , 14 ,0 , i, j - 2 , 0);

            

    }

同时为了画数字的时候还能继续使用图片字,我们把原来的方法保留。同时把所有用到了public static int textout(int i, int j, string s, int k, int l)这个方法的地方都改掉,其实也简单,就把类似:helfer.textout(g, d - 12, helfer.text[1], helfer.c, 0);这种改成:helfer.textout(g, d - 12, 1, helfer.c, 0);当然有几个地方,比如关卡数,音量调整,这种text + i这种就必须用两行代码来实现,第一行是text,第二行用旧的方法来写i这样,并且把坐标向右移一点,保证不重叠。最后再把textoutmulti这个方法改成两个方法,一个是介绍,一个是帮助,用两张图片搞定,方法如下:

public static image rules = null;

public static image credits = null;

public static int textoutmulticredits()

    {

           if(credits == null)

           {

                  try

            {

                   credits = image.createimage(imagepath + "credits");

            }

            catch(ioexception _ex) { }

           }

            acanvas.c.setcolor(0);

            acanvas.c.fillrect(0,0,board.width,board.height);

            acanvas.c.drawimage(credits,0 , 16 , 0);

           return 0;

    }

public static int textoutmultirules()

    { if(rules == null)

           {

                  try

            {

                   rules = image.createimage(imagepath + "rules");

            }

            catch(ioexception _ex) { }

           }

            acanvas.c.setcolor(0);

            acanvas.c.fillrect(0,0,board.width,board.height);

            acanvas.c.drawimage(rules,0 , 16 , 0);

        return 0;

    }

剩下的就是调整坐标,最后运行,测试,打包,ok!哈哈




自定义游戏字体(基于像素字)
Izual 发表于: 2008-1-15 13:43 来源: 手机游戏开发网

package com.Izual.ThreeKingdoms;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
/**
*
* @author Izual
*/
public class GameFont {
    private int style;   /*字体类型*/
    private int size;    /*字体大小*/
    private int baseline;/*基线*/
    private int height;  /*单个字符高度*/
    private int width;   /*单个字符宽度*/
    private Image image;
   
    /**
     * 返回一个自定义字体的对象
     */
    public static GameFont getFont(String inName, int inStyle, int inSize){
        
        Image i;
        String filename = inName;
        try{
            
            i = Image.createImage(filename);
        }catch(Throwable t){
            
            t.printStackTrace();
            throw new IllegalArgumentException("Could not locate font:" + filename + ":" + t);
        }
        
        return new GameFont(i, inStyle, inSize);
    }
   
    private GameFont(Image inImage, int inStyle, int inSize){
        
        image = inImage;
        style = inStyle;
        size = inSize;
        
        /*计算字符需要显示的高度和宽度,图片的假设一共有128个字符*/
        try{
            
            height = image.getHeight();
            width = image.getWidth() / 128;
            /*计算字符需要显示的最下面非背景色的坐标位置*/
            baseline = calculateBaseline();
        }catch(Throwable t){
            
            t.printStackTrace();
            throw new IllegalArgumentException("Specified font is invalid:" + t);
        }
    }
   
    /*计算字符需要显示的最下面非背景色的坐标位置*/
    private int calculateBaseline(){
        
        int result = height;
        int imageWidth = image.getWidth();
        int max = 0;
        int total;
        int[] row = new int[imageWidth];
        int background;
        
        /*确定背景色,假设(0, 0)坐标的像素为北京颜色*/
        image.getRGB(row, 0, 1, 0, 0, 1, 1);
        background = row[0];
        
        /*按每行搜索像素*/
        for(int y = height / 2; y < height; y++){
            
            total = 0;
            image.getRGB(row, 0, imageWidth, 0, y, imageWidth, 1);
            for(int x = 0; x < imageWidth; x++){
               
                if (row[x] != background){
                    
                    total ++;
                }
            }
            
            if (total > max){
               
                max = total;
                result = y;
            }
        }
        
        return result;
    }
   
    public int charsWidth(char[] ch, int offset, int length){
        
        /*确定字符间的距离*/
        return length * width;
    }
   
    public int charWidth(char ch){
        
        return width;
    }
   
    public int getBaselindPosition(){
        
        return baseline;
    }
   
    /*获得字符高度*/
    public int getHeight(){
        
        return height;
    }
   
    /*获得字符串的宽度*/
    public int stringWidth(String str){
        
        return charsWidth(str.toCharArray(), 0, str.length());
    }
   
    /*获得子字符串的宽度*/
    public int substringWidth(String str, int offset, int len){
        
        return charsWidth(str.toCharArray(), offset, len);
    }
   
    /*获得字体大小*/
    public int getSize(){
        
        return size;
    }
   
    /*获得字体类型*/
    public int getStyle(){
        
        return style;
    }
   
    /*是否已经加粗*/
    public boolean isBold(){
        
        return ((style & Font.STYLE_BOLD) != 0);
    }
   
    /*是否已经倾斜*/
    public boolean isItalic(){
        
        return ((style & Font.STYLE_ITALIC) != 0);
    }
   
    /*是否普通类型*/
    public boolean isPlain(){
        
        return (style == 0);
    }
   
    /*是否添加了下划线*/
    public boolean isUnderlined(){
        
        return ((style & Font.STYLE_UNDERLINED) != 0);
    }
   
    /*画单个字符*/
    public void drawChar(Graphics g, char character, int x, int y, int anchor){
        
        int clipX = g.getClipX();
        int clipY = g.getClipY();
        int clipW = g.getClipWidth();
        int clipH = g.getClipHeight();
        
        /*使用setClip方式绘制单个字符到屏幕上*/
        drawCharInternal(g, character, x, y, anchor);
        g.setClip(clipX, clipY, clipW, clipH);
    }
   
    /*画字符数组*/
    public void drawChars(Graphics g, char[] data, int offset, int length, int x, int y, int anchor){
        
        if((anchor & Graphics.RIGHT) != 0){
            
            x -= charsWidth(data, offset, length);
        }else if((anchor & Graphics.HCENTER) != 0){
            
            x -= (charsWidth(data, offset, length) / 2);
        }
        
        /*判断需要绘制的字体位置*/
        if((anchor & Graphics.BOTTOM) != 0){
            
            y -= height;
        }else if((anchor & Graphics.VCENTER) != 0){
            
            y -= height / 2;
        }
        
        /*保存原来的裁减区数据*/
        int clipX = g.getClipX();
        int clipY = g.getClipY();
        int clipW = g.getClipWidth();
        int clipH = g.getClipHeight();
        
        char c;
        for(int i = 0; i < length; i++){
            
            c = data[offset + i];
            drawCharInternal(g, c, x, y, Graphics.TOP | Graphics.LEFT);
            x += width;
        }
        
        /*在裁减区绘制*/
        g.setClip(clipX, clipY, clipW, clipH);
    }
   
    /*绘制时间图片的字符,不用考虑内存等各种因素*/
    private void drawCharInternal(Graphics g, char character, int x, int y, int anchor){
        
        if((style & Font.STYLE_ITALIC) != 0){
            
            /*绘制倾斜类型的字体*/
            g.setClip(x + 1, y, width, height / 2);
            g.drawImage(image, x - width * character + 1, y, anchor);
            g.setClip(x, y + height / 2, width, height / 2);
            g.drawImage(image, x - width * character, y, anchor);
            
            /*绘制加粗类型的字体*/
            if((style & Font.STYLE_BOLD) != 0){
               
                g.setClip(x, y, width, height / 2);           
                g.drawImage(image, x - width * character + 2, y, anchor);      
                g.setClip(x, y + height / 2, width, height / 2);           
                g.drawImage(image, x - width * character + 1, y, anchor);
            }
        }else {
            
            /*绘制正常类型的字体*/
            g.setClip(x, y, width, height / 2);
            g.drawImage(image, x - width * character, y, anchor);
            if((style & Font.STYLE_BOLD) != 0){
               
                 g.drawImage(image, x - width * character + 1, y, anchor);
            }
           
        }
        
        /*绘制下划线的字体*/
        if((style & Font.STYLE_UNDERLINED) != 0){
            
            g.drawLine(x, y + baseline + 2, x + width, y + baseline + 2);
        }
        
    }
   
    /*绘制字符串*/
    public void drawString(Graphics g, String str, int x, int y, int anchor){
        
        drawChars(g, str.toCharArray(), 0, str.length(), x, y, anchor);
    }
   
    /*绘制子字符串*/
    public void drawSubstring(Graphics g, String str, int offset, int len, int x, int y, int anchor){
        
        drawChars(g, str.toCharArray(), offset, len, x, y, anchor);
    }
}

bsbforever 发表于 2008-6-21 12:12

这帖子字数快赶上水区的了:013

000011112222 发表于 2008-6-21 12:19

這是什麽東西啊:085

发表于 2008-6-21 16:06

:吹吹 强大``支持下``

理緒 发表于 2008-6-21 19:39

看不懂...
纯支持.

285004453 发表于 2008-6-21 22:03

向汉化工作者致敬……

liujin121442 发表于 2008-6-21 23:09

好难啊,没有这方面的基础就是困难~

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.