使用的是暴力拼接(从左向右,从上到下,先放矮的图片进去)
对于后缀为_strip[数字]的图片会再次分割提高图集密度
效果
拼接前
拼接后
对应子图的偏移信息记录类(自动生成)
单张图片信息类(可能有多张图片因为有后面名为_strip[数字]的情况)
public class ImageInfo implements Comparable<ImageInfo>{
private int[] xs;
private int[] ys;
private int index;
private int width;
private int height;
private int num;
private String name;
private BufferedImage image;
private static final Pattern NAME_COMPILE = Pattern.compile("(.*)_strip(\\d+)\\.");
public ImageInfo(File file) throws IOException {
initNameAndNum(file.getName());
initImage(file);
}
private void initImage(File file) throws IOException {
image= ImageIO.read(file);
width= image.getWidth()/num;
height=image.getHeight();
}
private void initNameAndNum(String fullName) {
Matcher matcher = NAME_COMPILE.matcher(fullName);
if(matcher.find()){
name=matcher.group(1);
num=Integer.parseInt(matcher.group(2));
}else {
name=fullName.substring(0,fullName.lastIndexOf('.'));
num=1;
}
xs=new int[num];
ys=new int[num];
index=0;
}
public boolean hasSetAll(){
return index==num;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
@Override
public int compareTo(ImageInfo tar) {
return tar.height-this.height;
}
public void setPos(int x, int y) {
xs[index]=x;
ys[index]=y;
index++;
}
public void processSelf(Graphics g, ClassMaker classMaker) {
g.drawImage(image,xs[index],ys[index],xs[index]+width,ys[index]+height,index*width,
0,(index+1)*width,height,null);
String name=this.name;
if(num>1){
name+=index;
}
classMaker.addInfo(xs[index],ys[index],xs[index]+width,ys[index]+height,name);
index++;
}
public void reset() {
index=0;
}
}
单个图集信息(可能数据量太大,打出多个图集)
public class BigImage {
private List<ImageInfo> imageInfos;
private int width;
private int height;
private int x;
private int y;
private int offsetH;
public BigImage(int width, int height) {
this.width = width;
this.height = height;
initData();
}
private void initData() {
x=0;
y=0;
offsetH=0;
imageInfos=new ArrayList<>();
}
public boolean addImage(ImageInfo imageInfo) {
if(offsetH==0)offsetH=imageInfo.getHeight();
while (y+imageInfo.getHeight()<=height){
if(x+imageInfo.getWidth()>width){
y+=offsetH;
x=0;
offsetH=imageInfo.getHeight();
}else {//横向放入
imageInfo.setPos(x,y);
imageInfos.add(imageInfo);
x+=imageInfo.getWidth();
return true;
}
}
return false;
}
public void processImage(String tarPath, int index, ClassMaker classMaker) throws IOException {
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = image.getGraphics();
String fileName="create_"+index+".png";
classMaker.setImageName(fileName);
for (ImageInfo imageInfo:imageInfos){
imageInfo.processSelf(g,classMaker);
}
ImageIO.write(image,"png",new File(tarPath,fileName));
}
}
主处理类
public class ImageProcessor {
public static void main(String[] args) throws IOException {
// 资源目录 目标目录 图集大小
processImage("src/testGame/res","src/testGame/tar",1024,1024);
}
private static void processImage(String srcPath,String tarPath, int width, int height) throws IOException {
File[] files = new File(srcPath).listFiles();
ImageInfo[] imageInfos=new ImageInfo[files.length];
for (int i = 0; i < imageInfos.length; i++) {
imageInfos[i]=new ImageInfo(files[i]);
}
Arrays.sort(imageInfos);
putBigImage(imageInfos,width,height,tarPath);
}
private static void putBigImage(ImageInfo[] imageInfos, int width, int height,String tarPath) throws IOException {
Stack<BigImage> stack=new Stack<>();
stack.push(new BigImage(width,height));
int index=0;
while (index<imageInfos.length){
while (!imageInfos[index].hasSetAll()){
if(!stack.peek().addImage(imageInfos[index])){
stack.push(new BigImage(width,height));
}
}
imageInfos[index].reset();
index++;
}
index=0;
ClassMaker classMaker = new ClassMaker();
while (!stack.isEmpty()){
stack.pop().processImage(tarPath,index++,classMaker);
}
classMaker.create(tarPath);
}
}
资源类生成器
public class ClassMaker {
private List<Integer> x1s;
private List<Integer> y1s;
private List<Integer> x2s;
private List<Integer> y2s;
private List<String> names;
private List<String> imageNames;
private String imageName;
public ClassMaker() {
initData();
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
private void initData() {
x1s=new ArrayList<>();
y1s=new ArrayList<>();
x2s=new ArrayList<>();
y2s=new ArrayList<>();
names=new ArrayList<>();
imageNames=new ArrayList<>();
}
public void addInfo(int x1,int y1,int x2,int y2,String name){
x1s.add(x1);
y1s.add(y1);
x2s.add(x2);
y2s.add(y2);
names.add(name);
imageNames.add(imageName);
}
public void create(String tarPath) throws IOException {
String classContent=buildContent();
FileOutputStream out = new FileOutputStream(tarPath + "/Res.java");
out.write(classContent.getBytes());
out.close();
}
private String buildContent() {
StringBuilder builder = new StringBuilder("package testGame.tar;\n\npublic final class Res {\n\n");
builderInt(builder,x1s,"x1s");
builderInt(builder,y1s,"y1s");
builderInt(builder,x2s,"x2s");
builderInt(builder,y2s,"y2s");
builderString(builder);
builder.append("\n");
for (int i=0;i<names.size();i++){
builder.append("\tpublic final static int ").append(names.get(i)).append("=").append(i)
.append(";\n");
}
builder.append("\n}");
return builder.toString();
}
private void builderString(StringBuilder builder) {
builder.append("\tpublic final static String[] imageNames={");
for (String imageName:imageNames){
builder.append("\"").append(imageName).append("\",");
}
builder.append("};\n");
}
private void builderInt(StringBuilder builder, List<Integer> nums,String name) {
builder.append("\tpublic final static int[] ").append(name).append("={");
for (Integer integer:nums){
builder.append(integer).append(",");
}
builder.append("};\n");
}
@Override
public String toString() {
return "ClassMaker{" +
"x1s=" + x1s +
", \ny1s=" + y1s +
", \nx2s=" + x2s +
", \ny2s=" + y2s +
", \nnames=" + names +
", \nimageNames=" + imageNames +
", \nimageName='" + imageName + '\'' +
'}';
}
}
对于太过极端的不太适合,要设置合适的图集大小,若设置的宽度太小可能造成死循环