用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); } }
工具下载地址:
http://download.csdn.net/detail/stalendp/6783755