Java bitmap font: blitting 1-bit image with different colors

后端 未结 2 1693
长发绾君心
长发绾君心 2021-01-18 10:28

I\'d like to implement a simple bitmap font drawing in Java AWT-based application. Application draws on a Graphics object, where I\'d like to implement a simple

2条回答
  •  萌比男神i
    2021-01-18 11:22

    Okay, looks like I've found the best solution. The key to success was accessing raw pixel arrays in underlying AWT structures. Initialization goes something like that:

    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);
        }
    }
    

    After this one, you've got both a buffer that you can blit on canvas updates and underlying array of ARGB 4-byte ints - data.

    Single character can be drawn like that:

    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;
        }
    }
    

    This one uses a simple boolean[][] array, where first index chooses character and second index iterates over raw 1-bit character pixel data (true => foreground, false => background).

    I'll try to publish a complete solution as a part of my Java terminal emulation class set soon.

    This solution benchmarks for impressive 26007 strings / sec or 1846553 chars / sec - that's 2.3x times faster than previous best non-colorized drawImage().

提交回复
热议问题