libGDX-2.3:Pixmap 像素图-进阶

1,088 阅读4分钟

前言

本节是第二节的番外,介绍在第二节中出现过的com.badlogic.gdx.graphics.pixmap类。

回顾

回顾一下第二节的介绍:

Pixmap 像素图

我们可以通过com.badlogic.gdx.graphics.Pixmap类来构建简单的像素纹理。Pixmap常用的构造函数有:

  • Pixmap(FileHande) : 传入一个 FileHande ,读取图片到 Pixmap 中
  • Pixmap(int,int,Pixmap.Format) : 传入图片宽高(像素单位是整数)和 Format 对象(图片编码,在 Pixmap.Format 中,一般使用 Format.RGBA8888)

这时的图片还是空白的,我们需要在图片中绘制图形:

设置后面绘制图形的颜色:

//两种都是设置黑色
pixmap.setColor(com.badloc.gdx.graphics.Color.BLACK);
pixmap.setColor(0,0,0,1);

绘制图形,坐标基于图片(左上为0,0),新图形将覆盖旧图形:

pixmap.fill();  //填充整个图片
pixmap.fillCircle(10,10,10);  //画一个(10,10),半径10的实心圆
pixmap.fillRectangle(30,10,10,20);  //画一个(30,10),大小10*20的实心矩形
Pixmap.fillTriangle(0,10,5,0,10,10); //画一个(0,10),(5,0),(10,10)(三角形三个点的坐标)的实心三角形
pixmap.drawCircle(10,10,10);  //画一个空心圆
pixmap.draRectangle(30,10,10,20);  //画一个空心矩形
pixmap.drawLine(0,0,100,100);  //画从(0,0)到(100,100)的直线(1像素)
pixmap.drawPixmap(pixmap2,0,0);  //将另一个 Pixmap 绘制在图片上(套娃 doge)

Pixmap 进阶

回顾结束,正文开始。

下面是基于像素的方法:

//获取像素颜色
int color=pixmap.getPixel(pixelX,pixelY);
//绘制一个像素
pixmap.drawPixel(pixelX,pixelY,Color.BLACK);
pixmap.setColor(Color.BLACK);
pixmap.drawPixel(pixelX,pixelY);

使用int 存储 RGBA 颜色

那么,Pixmap.getPixel()返回的 int 值代表了 RGBA 颜色,这里就要科普一下了:

RGBA 颜色是由四个八位二进制数 表示的,一共32位,而 Java 中 int 类型刚好32位,所以,使用 int 表示 RGBA 颜色再合适不过了

libGDX 中的 Color 类中的常量是 int 类型,也是使用 int 存储 RGBA 颜色,也就是说,可以:

if(color==Color.Black){/*...*/}

那么,如何存储/读取 RGBA 颜色呢?很简单:

//从 color 到 RGBA
public int[] colorToRGBA(int color){
    //alpha为最高位
    int alpha=color>>>24;
    //其它按顺序次之
    int r=( color & 0xff0000 ) >> 16 ;
    int g=( color & 0xff00 ) >> 8;
    int b= color & 0xff ;
    int colors[] =new int[4];
    //... RGBA 依次赋值给colors,这里略
    return colors; 
}

//从 RGBA 到 color
public int RGBAtoColor(int r,int g,int b,int alpna){
    //alpha 为最高位
    int color = (alpha<<24) | (r<<16) | (g<<8) | b;
    return color;
}

PixmapIO 图片流

com.badlogic.gdx.graphics.PixmapIO 类的静态方法 提供了图片的读取和写入:

//读取文件到 pixmap
Pixmap pixmap = PixmapIO.readCIM(fileHander);

//将pixmap 写到文件中
PixmapIO.wirteCIM(fileHander,pixmap);
PixmapIO.writePNG(fileHander,pixmap);

.png to .cim

我们注意到,PixmapIO 只能读取 .cim 文件,不能读取 .png 文件,这就很鸡肋了。不过我们可以卡一下 "Bug" :

  1. Pixmap 有个构造函数可以读取 .png 文件  

  2. PixmapIO 可以保存 .cim文件

嘿嘿,想到了吧,我们可以制作一个** .png to .cim** 的工具。

jar下载:点此,提取码:wood

源码下载:点此,提取码:wood

界面如下:

libGDX2-3run.png

关键源码如下:

Pixmap pixmap=new Pixmap(loadFile);
PixmapIO.writeCIM(saveFile, pixmap);

然鹅事实上,直接使用 pixmap.drawPixmap(new Pixmap(PNGpath)) 效果更好 :D

尝试 :绘图小程序

不管怎样,我们现在都大概学会了 Pixmap 的进阶使用。那么接下来,我们将制作一个绘图小程序,它可以更改画笔大小和颜色,还可以保存文件

package com.libGDX.test;
import java.awt.Container;
import java.io.File;
import java.util.Date;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

//应用主类
public class Test extends ApplicationAdapter {
    private SpriteBatch batch;
    private Pixmap pixmap;    //画板
    private Texture texture;    //绘制载体
    private int r;    //画笔半径
    /*
     * 保存文件的对话框。
     * libGDX 本身不包含文件选择框,
     * 因此需要联动 java swing 的 文件选择框
     */
    private JFileChooser saveDirecrotyChooser;    
    @Override
    public void create() {
        batch=new SpriteBatch();
        //创建一个500*500屏幕大小的 Pixmap 作画板,皆画笔
        pixmap=new Pixmap(500,500,Pixmap.Format.RGBA8888);
        //白色做画板背景
        pixmap.setColor(Color.WHITE);
        pixmap.fill();
        //默认是黑色画笔
        pixmap.setColor(Color.BLACK);
        //默认画笔半径是5,小号
        r=5;
        //初始化 texture
        texture=new Texture(pixmap);
        
        //设置输入反馈
        Gdx.input.setInputProcessor(new InputAdapter() {
            //松开(点击)键盘事件
            @Override
            public boolean keyUp(int keycode) {
                //查看是否更改属性
                setColor(keycode);
                setSize(keycode);
                
                //如果按下 S 则保存文件
                if(keycode==Keys.S)save();
                return false;
            }
            
            //点击和拖动时在画板上绘制
            @Override
            public boolean touchDown(int screenX, int screenY, int pointer, int button) {
                draw(screenX,screenY);
                return false;
            }
            @Override
            public boolean touchDragged(int screenX, int screenY, int pointer) {
                draw(screenX,screenY);
                return false;
            }
        });
        //初始化文件选择框
        saveDirecrotyChooser=new JFileChooser("");
        //设置存储 .png 图片
        saveDirecrotyChooser.setAcceptAllFileFilterUsed(false);
        saveDirecrotyChooser.addChoosableFileFilter(new FileNameExtensionFilter("PNG","png"));
    }
    @Override
    public void render() {
        //白色清屏
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        //绘制
        batch.draw(texture, 0, 0);
        
        batch.end();
    }
    
    //画笔绘制
    private void draw(int x,int y) {
        //画笔其实是个圆
        pixmap.fillCircle(x, y, r);
        //刷新
        texture.draw(pixmap, 0, 0);
    }
    
    //设置画笔颜色
    private void setColor(int keycode) {
        switch(keycode) {
            case Keys.R:pixmap.setColor(Color.RED);break;    //红色
            case Keys.G:pixmap.setColor(Color.GREEN);break;    //绿色
            case Keys.B:pixmap.setColor(Color.BLUE);break;    //蓝色
            case Keys.A:pixmap.setColor(Color.BLACK);break;    //黑色
            case Keys.W:pixmap.setColor(Color.WHITE);break;    //白色,橡皮擦
        }
    }
    
    //设置画笔大小
    private void setSize(int keycode) {
        switch(keycode) {
            case Keys.F1:r=5;break;        //小号
            case Keys.F2:r=10;break;    //中号
            case Keys.F3:r=20;break;    //大号
        }
    }
    
    //保存文件
    private void save() {
        //设置默认文件名 photo年-月-日.png
        saveDirecrotyChooser.setSelectedFile(new File("photo-"+String.format("%tF",new Date())+".png"));
        //显示文件保存对话框
        int i =saveDirecrotyChooser.showSaveDialog(new Container());
        
        //如果按下 确定/保存
        if(i==JFileChooser.APPROVE_OPTION) {
            //以选择路径创建 FileHande
            FileHandle saveFile=newFileHandle(saveDirecrotyChooser.getSelectedFile().getPath());
            PixmapIO.writePNG(saveFile, pixmap);
        }
    }
    
    @Override
    public void dispose() {
        pixmap.dispose();
        texture.dispose();
        batch.dispose();
    }
}

运行结果:

libGDX2-3run2.png

libGDX2-3run3.png

llibGDX2-3run4.png