关于图片字库的汉化
话不多说勒~经过长期郁闷后
仅以此贴~
贡献给像我一样
在汉化路口徘徊的新人们
....
在网上收集到的一些关于汉化手机游戏图片字库的教程和常识...
浅谈图片字库汉化-威力加强版
前几天写的文章很受大家欢迎,应大家要求写详细的,但你最好有编程的基础不然还是很难的
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);
}
} 这帖子字数快赶上水区的了:013 這是什麽東西啊:085 :吹吹 强大``支持下`` 看不懂...
纯支持. 向汉化工作者致敬…… 好难啊,没有这方面的基础就是困难~
页:
[1]
