io.github.spair.byond.dmi.MetaExtractor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of byond-dmi-util Show documentation
Show all versions of byond-dmi-util Show documentation
Small set of util classes to work with BYOND dmi files.
package io.github.spair.byond.dmi;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final class MetaExtractor {
private static final String PNG_MIME = "image/png";
private static final String META_ELEMENT_TAG = "TextEntry";
private static final String META_ATTRIBUTE = "value";
private static final Pattern WIDTH_HEIGHT = Pattern.compile("(?:width\\s=\\s(\\d+))\n\t(?:height\\s=\\s(\\d+))");
private static final Pattern STATE_PATTERN = Pattern.compile("(?:state\\s=\\s\".*\"(?:\\n\\t.*)+)");
private static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)\\s=\\s(.+)");
private static final String STATE = "state";
private static final String DIRS = "dirs";
private static final String FRAMES = "frames";
private static final String DELAY = "delay";
private static final String LOOP = "loop";
private static final String MOVEMENT = "movement";
private static final String REWIND = "rewind";
private static final String HOTSPOT = "hotspot";
private static final String MOVEMENT_SUFFIX = " (M)";
static DmiMeta extractMetadata(final InputStream input) {
IIOMetadata metadata = readMetadata(input);
String metadataFormatName = IIOMetadataFormatImpl.standardMetadataFormatName;
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metadataFormatName);
IIOMetadataNode text = (IIOMetadataNode) root.getElementsByTagName(META_ELEMENT_TAG).item(0);
String metadataText = text.getAttribute(META_ATTRIBUTE);
return parseMetadataText(metadataText);
}
private static IIOMetadata readMetadata(final InputStream input) {
try (ImageInputStream imageInputStream = ImageIO.createImageInputStream(input)) {
ImageReader reader = ImageIO.getImageReadersByMIMEType(PNG_MIME).next();
reader.setInput(imageInputStream, true);
IIOImage image = reader.readAll(0, null);
return image.getMetadata();
} catch (IOException e) {
throw new IllegalArgumentException("DMI meta can't be read");
}
}
private static DmiMeta parseMetadataText(final String metadataText) {
DmiMeta metadata = new DmiMeta();
Matcher widthHeight = WIDTH_HEIGHT.matcher(metadataText);
if (widthHeight.find() && widthHeight.group(1) != null && widthHeight.group(2) != null) {
metadata.setSpritesWidth(Integer.parseInt(widthHeight.group(1)));
metadata.setSpritesHeight(Integer.parseInt(widthHeight.group(2)));
} else {
throw new IllegalArgumentException("DMI meta does't contain width and height properties");
}
Matcher state = STATE_PATTERN.matcher(metadataText);
if (state.find()) {
state.reset();
List entries = new ArrayList<>();
while (state.find()) {
Meta entry = parseState(state.group());
if (entry.isMovement()) {
entry.setName(entry.getName().concat(MOVEMENT_SUFFIX));
}
entries.add(entry);
}
metadata.setMetas(entries);
} else {
throw new IllegalArgumentException("DMI meta does't contain any state property value");
}
return metadata;
}
private static Meta parseState(final String stateText) {
Meta metaEntry = new Meta();
Matcher stateParam = PARAM_PATTERN.matcher(stateText);
while (stateParam.find()) {
final String paramName = stateParam.group(1);
final String paramValue = stateParam.group(2);
switch (paramName) {
case STATE:
String stateNameWithoutQuotes = paramValue.substring(1, paramValue.length() - 1);
metaEntry.setName(stateNameWithoutQuotes);
break;
case DIRS:
metaEntry.setDirs(Integer.parseInt(paramValue));
break;
case FRAMES:
metaEntry.setFrames(Integer.parseInt(paramValue));
break;
case DELAY:
metaEntry.setDelay(doubleArrayFromString(paramValue));
break;
case LOOP:
metaEntry.setLoop(isValueTrue(paramValue));
break;
case MOVEMENT:
metaEntry.setMovement(isValueTrue(paramValue));
break;
case REWIND:
metaEntry.setRewind(isValueTrue(paramValue));
break;
case HOTSPOT:
metaEntry.setHotspot(doubleArrayFromString(paramValue));
break;
default:
throw new IllegalArgumentException(
"Invalid meta format detected and can't be read. Param name: " + paramName);
}
}
return metaEntry;
}
private static boolean isValueTrue(final String value) {
return "1".equals(value);
}
private static double[] doubleArrayFromString(final String str) {
return Arrays.stream(str.split(",")).mapToDouble(Double::parseDouble).toArray();
}
private MetaExtractor() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy