用texturepacker打包了素材,不小心把原来的素材丢掉了;或则打开了别人的apk,想用里面的素材做一些练习。针对这些场景,我写了个小工具分享给大家。
附录是个打包好的jar文件(需要java环境才能够运行),解压后目录中有3个文件,jar和两个素材。切换到目录,运行如下命令就可以把素材还原到result目录下:
java -jar DeTexturepacker.jar Common1
下面是工具的源代码:
package com.detp;
import java.awt.Graphics;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
public class Decoder {
public static String pngname = "";
public static String plistname = "";
public static void main(String[] args) throws Exception {
if(args.length==1) {
pngname = args[0] + ".png";
plistname = args[0] + ".plist";
} else if(args.length==2) {
for(String arg : args) {
if(arg.contains("png")) {
pngname = arg;
} else if(arg.contains("plist")) {
plistname = arg;
}
}
} else {
System.out.println("Usage: 1) DeTexturepacker name 2) DeTexturepacker name.plist name.png\n");
return;
}
delImg();
}
private static void delImg() throws Exception {
InputStream is = new FileInputStream( pngname );
BufferedImage image = ImageIO.read(is);
File fold = new File("result");
if(fold.exists()) {
fold.delete();
}
fold.mkdir();
ArrayList<Frame> frames = exactData().frames;
for(Frame f : frames) {
System.out.print(".");
try {
f.split(image, "result");
}catch(Exception e) {
System.err.print("===>" +f.toString());
e.printStackTrace();
}
}
System.out.println("Done!\n");
}
private static PlistData exactData() throws Exception {
PlistData pd = new PlistData();
String con = getContent();
Pattern p = Pattern.compile("<key>frames</key>[^<]+<[^<]+(.+)");
Matcher m = p.matcher(con);
if(m.find()) {
con = m.group(1);
p = Pattern.compile("<key>([^<]+)<[^<]+<dict>(.*?)</dict>");
m = p.matcher(con);
Pattern pc = Pattern.compile("<key>([^<]+)</key>[^<]+<([^<]+)");
while(m.find()) {
if(m.group(1).equals("metadata")) {
} else {
Frame f = new Frame();
pd.add(f);
f.filename = m.group(1);
Matcher mc = pc.matcher(m.group(2));
while(mc.find()){
f.set(mc.group(1), mc.group(2));
}
}
}
}
return pd;
}
private static String getContent() throws IOException {
InputStream is = new FileInputStream( plistname);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
while((line=reader.readLine())!=null) {
sb.append(line);
// System.out.println(line);
}
return sb.toString();
}
}
class Frame {
public String filename;
public Rect frame, sourceColorRect;
public Vec2 offset, size;
public boolean rotated;
public void set(String key, String val) {
if(key.equals("frame")) {
frame = new Rect(val);
} else if(key.equals("offset")) {
offset = new Vec2(val);
} else if(key.equals("rotated")) {
rotated = val.contains("true");
} else if(key.equals("sourceColorRect")) {
sourceColorRect = new Rect(val);
} else if(key.equals("sourceSize")) {
size = new Vec2(val);
}
}
public void split(BufferedImage image, String root) throws IOException {
if(filename.contains("/")) {
String[] fs = filename.split("/");
String ff = root;
for(int i=0; i<fs.length-1; i++) {
ff += "/" + fs[i];
File mf = new File(ff);
if(!mf.exists()) {
mf.mkdir();
}
}
}
BufferedImage si = null;
if(rotated) {
si = rotateImg(image.getSubimage(frame.x1, frame.y1, frame.y2, frame.x2));
} else {
si = image.getSubimage(frame.x1, frame.y1, frame.x2, frame.y2);
}
si = changeSize(si);
ImageIO.write(si, "png", new File(String.format("%s/%s", root, filename)));
}
private BufferedImage rotateImg(BufferedImage bufferedImage) {
int width = bufferedImage.getWidth(), height = bufferedImage.getHeight();
int max = width > height ? width : height;
BufferedImage tmp = new BufferedImage(max, max, BufferedImage.TYPE_INT_ARGB);
Graphics g = tmp.getGraphics();
g.drawImage(bufferedImage, (max-width)/2, (max-height)/2, null);
AffineTransform transform = new AffineTransform();
transform.rotate(-Math.PI/2, max/2, max/2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
tmp = op.filter(tmp, null);
try {
tmp = tmp.getSubimage((max-height)/2, (max-width)/2, height, width);
}catch(Exception e) {
tmp = tmp.getSubimage((max-height)/2, (max-width)/2, height-1, width-1);
System.err.println("Frame#rotateImg fix");
}
return tmp;
}
private BufferedImage changeSize(BufferedImage bufferedImage){
BufferedImage tmp = new BufferedImage(size.x, size.y, BufferedImage.TYPE_INT_ARGB);
Graphics g = tmp.getGraphics();
int x = (size.x - bufferedImage.getWidth())/2 + offset.x;
int y = (size.y - bufferedImage.getHeight())/2 - offset.y;
g.drawImage(bufferedImage, x, y, null);
return tmp;
}
public String toString() {
return String.format("%s\tframe:%s, offset:%s, rotated:%s, sourceColorRect:%s, sourceSize:%s\n",
filename, frame, offset, rotated?"true":"false", sourceColorRect, size);
}
}
class PlistData {
public ArrayList<Frame> frames = new ArrayList<Frame>();
public void add(Frame f) {
frames.add(f);
}
}
class Vec2 {
static Pattern p = Pattern.compile("(-?\\d+),(-?\\d+)");
public int x, y;
public Vec2(String val) {
Matcher m = p.matcher(val);
if(m.find()) {
x = Integer.parseInt(m.group(1));
y = Integer.parseInt(m.group(2));
}else {
System.err.println(val + " is not a Vec2!!");
}
}
public Vec2(int _x, int _y) {
x = _x;
y = _y;
}
public String toString() {
return "(" + x + "," + y + ")";
}
}
class Rect {
static Pattern p = Pattern.compile("(-?\\d+),(-?\\d+)[^\\d]+(-?\\d+),(-?\\d+)");
public int x1,y1, x2, y2;
public Rect(String val) {
Matcher m = p.matcher(val);
if(m.find()) {
x1 = Integer.parseInt(m.group(1));
y1 = Integer.parseInt(m.group(2));
x2 = Integer.parseInt(m.group(3));
y2 = Integer.parseInt(m.group(4));
}else {
System.err.println(val + " is not a Rect!!");
}
}
public Rect(int _x1, int _y1,int _x2, int _y2) {
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
}
public String toString() {
return String.format("((%d,%d),(%d,%d))", x1,y1, x2, y2);
}
}
工具下载地址: