前言
本节是第二节的番外,介绍在第二节中出现过的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" :
Pixmap 有个构造函数可以读取 .png 文件
PixmapIO 可以保存 .cim文件
嘿嘿,想到了吧,我们可以制作一个** .png to .cim** 的工具。
jar下载:点此,提取码:wood
源码下载:点此,提取码:wood
界面如下:
关键源码如下:
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();
}
}
运行结果: