package com.kreative.paint.material.sprite;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
public class SpriteSheetWriter {
public static final long PNG_MAGIC_NUMBER = 0x89504E470D0A1A0AL;
public static final int PNG_CHUNK_SPNF = 0x73704E46;
public static final int PNG_CHUNK_IEND = 0x49454E44;
public static void stripSPNF(DataInputStream in, DataOutputStream out) throws IOException {
long magic = in.readLong();
if (magic != PNG_MAGIC_NUMBER) throw new IOException("Not a PNG file.");
out.writeLong(magic);
while (in.available() > 0) {
int cl = in.readInt();
int ct = in.readInt();
byte[] cd = new byte[cl];
in.read(cd);
int cc = in.readInt();
if (ct != PNG_CHUNK_SPNF) {
out.writeInt(cl);
out.writeInt(ct);
out.write(cd);
out.writeInt(cc);
}
}
}
public static void injectSPNF(DataInputStream in, DataOutputStream out, SpriteSheet sheet) throws IOException {
long magic = in.readLong();
if (magic != PNG_MAGIC_NUMBER) throw new IOException("Not a PNG file.");
out.writeLong(magic);
while (in.available() > 0) {
int cl = in.readInt();
int ct = in.readInt();
byte[] cd = new byte[cl];
in.read(cd);
int cc = in.readInt();
if (ct == PNG_CHUNK_IEND) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream d = new DataOutputStream(b);
d.writeInt(PNG_CHUNK_SPNF);
writeSpriteSheet(d, sheet);
d.close();
b.close();
byte[] spnf = b.toByteArray();
out.writeInt(spnf.length - 4);
out.write(spnf);
out.writeInt(new CRCCalculator().calculateCRC(spnf));
}
if (ct != PNG_CHUNK_SPNF) {
out.writeInt(cl);
out.writeInt(ct);
out.write(cd);
out.writeInt(cc);
}
}
}
private static void writeSpriteSheet(DataOutputStream d, SpriteSheet sheet) throws IOException {
d.writeUTF((sheet.name == null) ? "" : sheet.name);
d.writeShort(sheet.intent);
d.writeShort(sheet.columns);
d.writeShort(sheet.rows);
d.writeShort(sheet.order.intValue);
d.writeShort(sheet.slices.size());
for (SpriteSheetSlice slice : sheet.slices) writeSlice(d, slice);
d.writeShort(sheet.root.children.size());
for (SpriteTreeNode node : sheet.root.children) writeTreeNode(d, node);
}
private static void writeSlice(DataOutputStream d, SpriteSheetSlice slice) throws IOException {
d.writeShort(slice.startX);
d.writeShort(slice.startY);
d.writeShort(slice.cellWidth);
d.writeShort(slice.cellHeight);
d.writeShort(slice.hotspotX);
d.writeShort(slice.hotspotY);
d.writeShort(slice.deltaX);
d.writeShort(slice.deltaY);
d.writeShort(slice.columns);
d.writeShort(slice.rows);
d.writeShort(slice.order.intValue);
d.writeShort(slice.transform.intValue);
}
private static void writeTreeNode(DataOutputStream d, SpriteTreeNode node) throws IOException {
d.writeUTF((node.name == null) ? "" : node.name);
d.writeShort(node.index);
d.writeShort(node.duration);
if (node instanceof SpriteTreeNode.Leaf) {
SpriteTreeNode.Leaf l = (SpriteTreeNode.Leaf)node;
d.writeShort(l.count);
} else if (node instanceof SpriteTreeNode.Branch) {
SpriteTreeNode.Branch b = (SpriteTreeNode.Branch)node;
d.writeShort(0x8000 + b.children.size());
for (SpriteTreeNode c : b.children) writeTreeNode(d, c);
} else {
d.writeShort(0);
}
}
public static void printSPNX(PrintStream out, SpriteSheet sheet) {
out.println(sheetToString(sheet));
}
public static void printSPNX(PrintWriter out, SpriteSheet sheet) {
out.println(sheetToString(sheet));
}
private static String sheetToString(SpriteSheet sheet) {
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
sb.append("<!DOCTYPE sprite-sheet PUBLIC \"-//Kreative//DTD SpriteInfo 1.0//EN\" \"http://www.kreativekorp.com/dtd/spnx.dtd\">\n");
List<String> props = new ArrayList<String>();
if (sheet.name != null && sheet.name.length() > 0) {
props.add("name=\"" + xmls(sheet.name) + "\"");
}
if (sheet.intent != 0) {
props.add("intent=\"" + xmls(SpriteIntent.toString(sheet.intent)) + "\"");
}
if (sheet.columns > 0 && sheet.rows > 0) {
props.add("cols=\"" + sheet.columns + "\" rows=\"" + sheet.rows + "\"");
} else if (sheet.columns > 0) {
props.add("cols=\"" + sheet.columns + "\"");
} else if (sheet.rows > 0) {
props.add("rows=\"" + sheet.rows + "\"");
}
if (sheet.columns > 0 || sheet.rows > 0 || sheet.order != ArrayOrdering.LTR_TTB) {
props.add("order=\"" + orderToString(sheet.order) + "\"");
}
if (props.isEmpty()) {
sb.append("<sprite-sheet>");
} else {
for (int i = 0, j = props.size() - 1; j >= 0; i++, j--) {
sb.append((i == 0) ? "<sprite-sheet " : " ");
sb.append(props.get(i));
sb.append((j == 0) ? ">" : "\n");
}
}
sb.append("\n");
for (SpriteSheetSlice slice : sheet.slices) {
sb.append("\n\t");
sb.append(sliceToString(slice, "\t"));
}
sb.append("\n");
for (SpriteTreeNode node : sheet.root.children) {
sb.append("\n\t");
sb.append(treeNodeToString(node, "\t"));
}
sb.append("\n\n");
sb.append("</sprite-sheet>");
return sb.toString();
}
private static String sliceToString(SpriteSheetSlice slice, String prefix) {
return "<slice sx=\""+slice.startX+"\" sy=\""+slice.startY+"\"\n"+
prefix+" cw=\""+slice.cellWidth+"\" ch=\""+slice.cellHeight+"\"\n"+
prefix+" chx=\""+slice.hotspotX+"\" chy=\""+slice.hotspotY+"\"\n"+
prefix+" cdx=\""+slice.deltaX+"\" cdy=\""+slice.deltaY+"\"\n"+
prefix+" cols=\""+slice.columns+"\" rows=\""+slice.rows+"\"\n"+
prefix+" order=\""+orderToString(slice.order)+"\"\n"+
prefix+" color-transform=\""+slice.transform.toString().replaceAll("\\s+","\n"+
prefix+" ")+"\"/>";
}
private static String treeNodeToString(SpriteTreeNode node, String prefix) {
StringBuffer sb = new StringBuffer();
sb.append("<sprite");
if (node instanceof SpriteTreeNode.Branch) {
sb.append("-set");
}
if (node.name != null && node.name.length() > 0) {
sb.append(" name=\"");
sb.append(xmls(node.name));
sb.append("\"");
}
sb.append(" index=\"");
sb.append(node.index);
sb.append("\"");
if (node.duration != 0) {
sb.append(" duration=\"");
sb.append(node.duration);
sb.append("\"");
}
if (node instanceof SpriteTreeNode.Leaf) {
int count = ((SpriteTreeNode.Leaf)node).count;
sb.append(" count=\"");
sb.append(count);
sb.append("\"");
}
if (node instanceof SpriteTreeNode.Branch) {
sb.append(">");
List<SpriteTreeNode> children = ((SpriteTreeNode.Branch)node).children;
if (!children.isEmpty()) {
if (children.size() == 1) {
sb.append(treeNodeToString(children.get(0), prefix));
} else {
String newPrefix = prefix + "\t";
for (SpriteTreeNode child : children) {
sb.append("\n");
sb.append(newPrefix);
sb.append(treeNodeToString(child, newPrefix));
}
sb.append("\n");
sb.append(prefix);
}
}
sb.append("</sprite-set>");
} else {
sb.append("/>");
}
return sb.toString();
}
private static String orderToString(ArrayOrdering order) {
return order.name().toLowerCase().replace('_', '-');
}
private static String xmls(String s) {
return s.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll("\"", """);
}
}