Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java位图字体:以不同颜色显示1位图像_Java_Fonts_Bitmap_Awt_Lwjgl - Fatal编程技术网

Java位图字体:以不同颜色显示1位图像

Java位图字体:以不同颜色显示1位图像,java,fonts,bitmap,awt,lwjgl,Java,Fonts,Bitmap,Awt,Lwjgl,我想在基于JavaAWT的应用程序中实现一个简单的位图字体绘制。应用程序基于图形对象,我想在其中实现一个简单的算法: 1) 加载一个文件(可能使用ImageIO.read(新文件(文件名))),它是1位PNG,看起来像: int posX = ch % 16; int posY = ch / 16; int fontX = posX * CHAR_WIDTH; int fontY = posY * CHAR_HEIGHT; g.drawImage(

我想在基于JavaAWT的应用程序中实现一个简单的位图字体绘制。应用程序基于
图形
对象,我想在其中实现一个简单的算法:

1) 加载一个文件(可能使用
ImageIO.read(新文件(文件名))
),它是1位PNG,看起来像:

    int posX = ch % 16;
    int posY = ch / 16;

    int fontX = posX * CHAR_WIDTH;
    int fontY = posY * CHAR_HEIGHT;

    g.drawImage(
            font,
            dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
            fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
            null
    );
public class ConsoleCanvas extends Canvas {
    protected BufferedImage buffer;
    protected int w;
    protected int h;
    protected int[] data;

    public ConsoleCanvas(int w, int h) {
        super();
        this.w = w;
        this.h = h;
    }

    public void initialize() {
        data = new int[h * w];

        // Fill data array with pure solid black
        Arrays.fill(data, 0xff000000);

        // Java's endless black magic to get it working
        DataBufferInt db = new DataBufferInt(data, h * w);
        ColorModel cm = ColorModel.getRGBdefault();
        SampleModel sm = cm.createCompatibleSampleModel(w, h);
        WritableRaster wr = Raster.createWritableRaster(sm, db, null);
        buffer = new BufferedImage(cm, wr, false, null);
    }

    @Override
    public void paint(Graphics g) {
        update(g);
    }

    @Override
    public void update(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
    }
}
private void putChar(int dx, int dy, char ch, int fore, int back) {
    int charIdx = 0;
    int canvasIdx = dy * canvas.w + dx;
    for (int i = 0; i < CHAR_HEIGHT; i++) {
        for (int j = 0; j < CHAR_WIDTH; j++) {
            canvas.data[canvasIdx] = font[ch][charIdx] ? fore : back;
            charIdx++;
            canvasIdx++;
        }
        canvasIdx += canvas.w - CHAR_WIDTH;
    }
}

也就是说,它是由8*8个字符组成的16*16(如果我想支持Unicode的话,也可以是16*多)矩阵。黑色对应背景色,白色对应前景色

2) 一个字符一个字符地绘制字符串,将此位图的相关部分布点到目标
图形
。到目前为止,我只在以下方面取得了成功:

    int posX = ch % 16;
    int posY = ch / 16;

    int fontX = posX * CHAR_WIDTH;
    int fontY = posY * CHAR_HEIGHT;

    g.drawImage(
            font,
            dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
            fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
            null
    );
public class ConsoleCanvas extends Canvas {
    protected BufferedImage buffer;
    protected int w;
    protected int h;
    protected int[] data;

    public ConsoleCanvas(int w, int h) {
        super();
        this.w = w;
        this.h = h;
    }

    public void initialize() {
        data = new int[h * w];

        // Fill data array with pure solid black
        Arrays.fill(data, 0xff000000);

        // Java's endless black magic to get it working
        DataBufferInt db = new DataBufferInt(data, h * w);
        ColorModel cm = ColorModel.getRGBdefault();
        SampleModel sm = cm.createCompatibleSampleModel(w, h);
        WritableRaster wr = Raster.createWritableRaster(sm, db, null);
        buffer = new BufferedImage(cm, wr, false, null);
    }

    @Override
    public void paint(Graphics g) {
        update(g);
    }

    @Override
    public void update(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
    }
}
private void putChar(int dx, int dy, char ch, int fore, int back) {
    int charIdx = 0;
    int canvasIdx = dy * canvas.w + dx;
    for (int i = 0; i < CHAR_HEIGHT; i++) {
        for (int j = 0; j < CHAR_WIDTH; j++) {
            canvas.data[canvasIdx] = font[ch][charIdx] ? fore : back;
            charIdx++;
            canvasIdx++;
        }
        canvasIdx += canvas.w - CHAR_WIDTH;
    }
}
它可以工作,但是,唉,它可以按原样显示文本,也就是说,我不能用所需的前景色和背景色替换黑色和白色,甚至不能使背景透明

因此,问题是:在Java中是否有一种简单(且快速)的方法将一个1位位图的一部分blit到另一个位图,并在blit过程中对其着色(即用一种给定颜色替换所有0像素,用另一种颜色替换所有1像素)

我研究了几个解决方案,所有这些方案在我看来都不太理想:

  • 如中所述,使用自定义着色应该可以工作,但在每次blit操作之前重新设置位图的颜色似乎效率很低
  • 使用多个32位RGBA PNG,黑色像素的alpha通道设置为0,前景设置为最大值。每个所需的前景色都应该有自己的预渲染位图。通过这种方式,我可以使背景透明,并在blitting之前将其单独绘制为矩形,然后使用我的字体选择一个位图,使用所需颜色预着色,并在该矩形上绘制一部分。对我来说,这似乎是一个巨大的杀伤力-是什么让这个选项更糟糕-它将前景颜色的数量限制在相对较小的数量(即,我可以真实地加载和保存数百或数千张位图,而不是数百万张)
  • 绑定和加载自定义字体(如中所述)可能有效,但据我在文档中看到的,AWT的
    font
    似乎只适用于基于矢量的字体,而不适用于基于位图的字体
可能已经有任何库实现了这样的功能?或者我该换一种更高级的图形库了,比如

基准测试结果 我在一个简单的测试中测试了两个算法:我有两个字符串,每个字符串有71个字符,并在同一个位置连续地绘制它们:

    for (int i = 0; i < N; i++) {
        cv.putString(5, 5, STR, Color.RED, Color.BLUE);
        cv.putString(5, 5, STR2, Color.RED, Color.BLUE);
    }
for(int i=0;i
然后我测量所花费的时间并计算速度:每秒字符串数和每秒字符数。到目前为止,我测试的各种实现产生了以下结果:

  • 位图字体,16*16个字符位图:10991个字符串/秒,780391个字符/秒
  • 位图字体,预分割图像:11048个字符串/秒,784443个字符/秒
  • g、 drawString():8952个字符串/秒,635631个字符/秒
  • 彩色位图字体,使用LookupOp和ByteLookupTable着色:404字符串/秒,28741字符/秒

您可以将每个位图转换为
形状(或其中许多),然后绘制
形状。有关获取
形状的过程,请参见

例如。

import java.awt.*;
导入java.awt.event.*;
导入java.awt.image.*;
导入java.awt.geom.*;
导入javax.swing.*;
导入javax.swing.border.*;
导入javax.swing.event.*;
导入java.util.Random;
/*获取图像的轮廓以便进一步处理*/
类ImageShape{
私有缓冲图像;
私有缓冲区图像形状;
私人区域areaOutline=null;
专用JLabel labelOutline;
专用JLabel输出;
私有缓冲图像动画;
私有随机=新随机();
私有整数计数=0;
private long time=System.currentTimeMillis();
私有字符串速率=”;
公共图像形状(BuffereImage图像){
这个图像=图像;
}
公共图书馆(大纲){
如果(areaOutline!=null){
Graphics2D g=ImageShape.createGraphics();
g、 setColor(Color.WHITE);
g、 fillRect(0,0,ImageShape.getWidth(),ImageShape.getHeight());
g、 setColor(Color.RED);
g、 setClip(区域轮廓);
g、 fillRect(0,0,ImageShape.getWidth(),ImageShape.getHeight());
g、 设置颜色(颜色为黑色);
g、 setClip(空);
g、 绘制(区域轮廓);
g、 处置();
}
}
公共区域getOutline(颜色目标、BuffereImage bi){
//构造通用路径
GeneralPath gp=新的GeneralPath();
布尔控制=假;
int targetRGB=target.getRGB();

对于(int xx=0;xx好的,看来我找到了最好的解决方案。成功的关键是访问底层AWT结构中的原始像素阵列。初始化如下:

    int posX = ch % 16;
    int posY = ch / 16;

    int fontX = posX * CHAR_WIDTH;
    int fontY = posY * CHAR_HEIGHT;

    g.drawImage(
            font,
            dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
            fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
            null
    );
public class ConsoleCanvas extends Canvas {
    protected BufferedImage buffer;
    protected int w;
    protected int h;
    protected int[] data;

    public ConsoleCanvas(int w, int h) {
        super();
        this.w = w;
        this.h = h;
    }

    public void initialize() {
        data = new int[h * w];

        // Fill data array with pure solid black
        Arrays.fill(data, 0xff000000);

        // Java's endless black magic to get it working
        DataBufferInt db = new DataBufferInt(data, h * w);
        ColorModel cm = ColorModel.getRGBdefault();
        SampleModel sm = cm.createCompatibleSampleModel(w, h);
        WritableRaster wr = Raster.createWritableRaster(sm, db, null);
        buffer = new BufferedImage(cm, wr, false, null);
    }

    @Override
    public void paint(Graphics g) {
        update(g);
    }

    @Override
    public void update(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
    }
}
private void putChar(int dx, int dy, char ch, int fore, int back) {
    int charIdx = 0;
    int canvasIdx = dy * canvas.w + dx;
    for (int i = 0; i < CHAR_HEIGHT; i++) {
        for (int j = 0; j < CHAR_WIDTH; j++) {
            canvas.data[canvasIdx] = font[ch][charIdx] ? fore : back;
            charIdx++;
            canvasIdx++;
        }
        canvasIdx += canvas.w - CHAR_WIDTH;
    }
}
在这一次之后,您既有一个
缓冲区,可以在画布上进行blit更新,也有一个ARGB 4字节整数的底层数组-
数据

可以这样绘制单个字符:

    int posX = ch % 16;
    int posY = ch / 16;

    int fontX = posX * CHAR_WIDTH;
    int fontY = posY * CHAR_HEIGHT;

    g.drawImage(
            font,
            dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
            fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
            null
    );
public class ConsoleCanvas extends Canvas {
    protected BufferedImage buffer;
    protected int w;
    protected int h;
    protected int[] data;

    public ConsoleCanvas(int w, int h) {
        super();
        this.w = w;
        this.h = h;
    }

    public void initialize() {
        data = new int[h * w];

        // Fill data array with pure solid black
        Arrays.fill(data, 0xff000000);

        // Java's endless black magic to get it working
        DataBufferInt db = new DataBufferInt(data, h * w);
        ColorModel cm = ColorModel.getRGBdefault();
        SampleModel sm = cm.createCompatibleSampleModel(w, h);
        WritableRaster wr = Raster.createWritableRaster(sm, db, null);
        buffer = new BufferedImage(cm, wr, false, null);
    }

    @Override
    public void paint(Graphics g) {
        update(g);
    }

    @Override
    public void update(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
    }
}
private void putChar(int dx, int dy, char ch, int fore, int back) {
    int charIdx = 0;
    int canvasIdx = dy * canvas.w + dx;
    for (int i = 0; i < CHAR_HEIGHT; i++) {
        for (int j = 0; j < CHAR_WIDTH; j++) {
            canvas.data[canvasIdx] = font[ch][charIdx] ? fore : back;
            charIdx++;
            canvasIdx++;
        }
        canvasIdx += canvas.w - CHAR_WIDTH;
    }
}
private void putChar(int-dx,int-dy,char-ch,int-fore,int-back){
int charIdx=0;
int canvasIdx=dy*canvas.w+dx;
对于(int i=0;i
这一个使用一个简单的
布尔[][]
数组,其中第一个索引选择字符,第二个索引迭代原始1位字符像素数据(true=>前景,false=>背景)

我会试着发表一篇综合文章