Merge pull request #9807 from mwerezak/tailicons

Fixes unathi tail overlays
This commit is contained in:
Zuhayr
2015-06-14 03:01:50 +09:30
5 changed files with 187 additions and 7 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.
+94
View File
@@ -0,0 +1,94 @@
""" Python 2.7 wrapper for dmitool.
"""
import os
from subprocess import Popen, PIPE
_JAVA_PATH = ["java"]
_DMITOOL_CMD = ["-jar", "dmitool.jar"]
def _dmitool_call(*dmitool_args, **popen_args):
return Popen(_JAVA_PATH + _DMITOOL_CMD + [str(arg) for arg in dmitool_args], **popen_args)
def _safe_parse(dict, key, deferred_value):
try:
dict[key] = deferred_value()
except Exception as e:
print "Could not parse property '%s': %s"%(key, e)
return e
return False
def version():
""" Returns the version as a string. """
stdout, stderr = _dmitool_call("version", stdout=PIPE).communicate()
return str(stdout).strip()
def help():
""" Returns the help text as a string. """
stdout, stderr = _dmitool_call("help", stdout=PIPE).communicate()
return str(stdout).strip()
def info(filepath):
""" Totally not a hack that parses the output from dmitool into a dictionary.
May break at any moment.
"""
subproc = _dmitool_call("info", filepath, stdout=PIPE)
stdout, stderr = subproc.communicate()
result = {}
data = stdout.split(os.linesep)[1:]
#for s in data: print s
#parse header line
if len(data) > 0:
header = data.pop(0).split(",")
#don't need to parse states, it's redundant
_safe_parse(result, "images", lambda: int(header[0].split()[0].strip()))
_safe_parse(result, "size", lambda: header[2].split()[1].strip())
#parse state information
states = []
for item in data:
if not len(item): continue
stateinfo = {}
item = item.split(",", 3)
_safe_parse(stateinfo, "name", lambda: item[0].split()[1].strip(" \""))
_safe_parse(stateinfo, "dirs", lambda: int(item[1].split()[0].strip()))
_safe_parse(stateinfo, "frames", lambda: int(item[2].split()[0].strip()))
if len(item) > 3:
stateinfo["misc"] = item[3]
states.append(stateinfo)
result["states"] = states
return result
def extract_state(input_path, output_path, icon_state, direction=None, frame=None):
""" Extracts an icon state as a png to a given path.
If provided direction should be a string, one of S, N, E, W, SE, SW, NE, NW.
If provided frame should be a frame number or a string of two frame number separated by a dash.
"""
args = ["extract", input_path, icon_state, output_path]
if direction is not None: args.extend(("direction" , str(direction)))
if frame is not None: args.extend(("frame" , str(frame)))
return _dmitool_call(*args)
def import_state(target_path, input_path, icon_state, replace=False, delays=None, rewind=False, loop=None, ismovement=False, direction=None, frame=None):
""" Inserts an input png given by the input_path into the target_path.
"""
args = ["import", target_path, icon_state, input_path]
if replace: args.append("nodup")
if rewind: args.append("rewind")
if ismovement: args.append("movement")
if delays: args.extend(("delays", ",".join(delays)))
if direction is not None: args.extend(("direction", direction))
if frame is not None: args.extend(("frame", frame))
if loop in ("inf", "infinity"):
args.append("loop")
elif loop:
args.extend(("loopn", loop))
return _dmitool_call(*args)
@@ -175,7 +175,7 @@ public class IconState {
}
int pxW = in.imgInfo.cols;
int pxH = in.imgInfo.rows;
int frames = pxW / w;
int frames = pxW / w; //frames are read along the X axis, dirs along the Y, much like export.
int dirs = pxH / h;
// make sure the size is an integer multiple
@@ -203,7 +203,7 @@ public class IconState {
px[bY][bX + 3]);
}
}
images[imageY + imageX*dirs] = new NonPalettedImage(w, h, pixels);
images[_getIndex(imageY, imageX, dirs)] = new NonPalettedImage(w, h, pixels);
}
}
@@ -211,6 +211,38 @@ public class IconState {
return new IconState(name, dirs, frames, images, delays, rewind, loop, hotspot, movement);
}
//Converts a desired dir and frame to an index into the images array.
public int getIndex(int dir, int frame) {
return _getIndex(dir, frame, dirs);
}
private static int _getIndex(int dir, int frame, int totalDirs) {
return dir + frame*totalDirs;
}
public void insertDir(int dir, Image[] splice) {
int maxFrame = frames < splice.length? frames: splice.length;
for(int frameIdx = 0; frameIdx < maxFrame; frameIdx++) {
insertImage(dir, frameIdx, splice[frameIdx]);
}
}
public void insertFrame(int frame, Image[] splice) {
int maxDir = dirs < splice.length? dirs: splice.length;
for(int dirIdx = 0; dirIdx < maxDir; dirIdx++) {
insertImage(dirIdx, frame, splice[dirIdx]);
}
}
public void insertImage(int dir, int frame, Image splice) {
if(frame < 0 || frame >= frames)
throw new IllegalArgumentException("Provided frame is out of range: " + frame);
if(dir < 0 || dir >= dirs)
throw new IllegalArgumentException("Provided dir is out of range: " + dir);
images[getIndex(dir, frame)] = splice;
}
}
@@ -244,6 +276,5 @@ public class IconState {
+59 -4
View File
@@ -59,6 +59,7 @@ public class Main {
"\t movement | move | mov | m : [state] should be marked as a movement state\n" +
"\t delays L | delay L | del L | d L : use the list L as a comma-separated list of delays (e.g. '1,1,2,2,1')\n" +
"\t hotspot H | hs H | h H : use H as the hotspot for this state\n" +
"\t direction D | dir D : replaces D with the image from [in], instead of the entire state. D can be 0-7 or S, N, E, etc. If the state does not already exist, this is ignored\n" +
"";
public static void main(String[] args) throws FileNotFoundException, IOException, DMIException {
@@ -270,6 +271,8 @@ public class Main {
boolean movement = false;
String hotspot = null;
float[] delays = null;
String replaceDir = null;
String replaceFrame = null;
while(!argq.isEmpty()) {
String s = argq.pollFirst();
switch(s.toLowerCase()) {
@@ -341,6 +344,24 @@ public class Main {
return;
}
break;
case "dir":
case "direction":
if(!argq.isEmpty()) {
replaceDir = argq.pollFirst();
} else {
System.out.println("Argument '" + s + "' requires a direction argument following it!");
return;
}
break;
case "f":
case "frame":
if(!argq.isEmpty()) {
replaceFrame = argq.pollFirst();
} else {
System.out.println("Argument '" + s + "' requires a frame argument following it!");
return;
}
break;
default:
System.out.println("Unknown import argument '" + s + "', ignoring.");
break;
@@ -352,12 +373,46 @@ public class Main {
if(VERBOSITY >= 0) toImportTo.printInfo();
IconState is = IconState.importFromPNG(toImportTo, new FileInputStream(pngFile), stateName, delays, rewind, loop, hotspot, movement);
if(noDup) {
if(!toImportTo.setIconState(is)) {
//image insertion
if(replaceDir != null || replaceFrame != null) {
IconState targetIs = toImportTo.getIconState(stateName);
if(targetIs == null) {
System.out.println("'direction' or 'frame' specified and no icon state '" + stateName + "' found, aborting!");
return;
}
if(is.images.length == 0) {
System.out.println("'direction' or 'frame' specified and imported is empty, aborting!");
return;
}
if(!noDup) targetIs = targetIs.clone();
int dirToReplace, frameToReplace;
if(replaceDir != null && replaceFrame != null) {
frameToReplace = parseFrame(replaceFrame, targetIs);
dirToReplace = parseDir(replaceDir, targetIs);
targetIs.insertImage(dirToReplace, frameToReplace, is.images[0]);
}
else if(replaceDir != null) {
dirToReplace = parseDir(replaceDir, targetIs);
targetIs.insertDir(dirToReplace, is.images);
}
else if(replaceFrame != null) {
frameToReplace = parseFrame(replaceFrame, targetIs);
targetIs.insertFrame(frameToReplace, is.images);
}
if(!noDup) toImportTo.addIconState(null, targetIs);
}
else {
if(noDup) {
if(!toImportTo.setIconState(is)) {
toImportTo.addIconState(null, is);
}
} else {
toImportTo.addIconState(null, is);
}
} else {
toImportTo.addIconState(null, is);
}
if(VERBOSITY >= 0) toImportTo.printInfo();