mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-24 23:00:46 +00:00
Saving files before refreshing line endings
This commit is contained in:
+2286
-2286
File diff suppressed because it is too large
Load Diff
@@ -1,182 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedText;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.helpers.ImmediateFuture;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DecompilerPool {
|
||||
|
||||
private final ThreadPoolExecutor executor;
|
||||
|
||||
public DecompilerPool() {
|
||||
int threadCount = Configuration.getParallelThreadCount();
|
||||
executor = new ThreadPoolExecutor(threadCount, threadCount,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>());
|
||||
}
|
||||
|
||||
public Future<HighlightedText> submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
public HighlightedText call() throws Exception {
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
|
||||
writer.startFunction("!script");
|
||||
src.getActionScriptSource(writer, actions);
|
||||
writer.endFunction();
|
||||
|
||||
HighlightedText result = new HighlightedText(writer);
|
||||
SWF swf = src.getSwf();
|
||||
if (swf != null) {
|
||||
swf.as2Cache.put(src, result);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onComplete(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
public Future<HighlightedText> submitTask(ScriptPack pack, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
public HighlightedText call() throws Exception {
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
int scriptIndex = pack.scriptIndex;
|
||||
ScriptInfo script = null;
|
||||
if (scriptIndex > -1) {
|
||||
script = pack.abc.script_info.get(scriptIndex);
|
||||
}
|
||||
boolean parallel = Configuration.parallelSpeedUp.get();
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
|
||||
pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel);
|
||||
|
||||
HighlightedText result = new HighlightedText(writer);
|
||||
SWF swf = pack.getSwf();
|
||||
if (swf != null) {
|
||||
swf.as3Cache.put(pack, result);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onComplete(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
private Future<HighlightedText> submit(Callable<HighlightedText> callable) {
|
||||
boolean parallel = Configuration.parallelSpeedUp.get();
|
||||
if (parallel) {
|
||||
Future<HighlightedText> f = executor.submit(callable);
|
||||
return f;
|
||||
} else {
|
||||
boolean cancelled = false;
|
||||
Throwable throwable = null;
|
||||
HighlightedText result = null;
|
||||
try {
|
||||
result = callable.call();
|
||||
} catch (InterruptedException ex) {
|
||||
cancelled = true;
|
||||
} catch (Exception ex) {
|
||||
throwable = ex;
|
||||
}
|
||||
|
||||
return new ImmediateFuture<>(result, throwable, cancelled);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStat() {
|
||||
return "core: " + executor.getCorePoolSize()
|
||||
+ " size: " + executor.getPoolSize()
|
||||
+ " largest: " + executor.getLargestPoolSize()
|
||||
+ " max: " + executor.getMaximumPoolSize()
|
||||
+ " active: " + executor.getActiveCount()
|
||||
+ " count: " + executor.getTaskCount()
|
||||
+ " completed: " + executor.getCompletedTaskCount();
|
||||
}
|
||||
|
||||
public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(src, actions, null);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException ex) {
|
||||
future.cancel(true);
|
||||
throw ex;
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HighlightedText decompile(ScriptPack pack) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(pack, null);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException ex) {
|
||||
future.cancel(true);
|
||||
throw ex;
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void shutdown() throws InterruptedException {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(100, TimeUnit.SECONDS)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedText;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.helpers.ImmediateFuture;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DecompilerPool {
|
||||
|
||||
private final ThreadPoolExecutor executor;
|
||||
|
||||
public DecompilerPool() {
|
||||
int threadCount = Configuration.getParallelThreadCount();
|
||||
executor = new ThreadPoolExecutor(threadCount, threadCount,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>());
|
||||
}
|
||||
|
||||
public Future<HighlightedText> submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
public HighlightedText call() throws Exception {
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
|
||||
writer.startFunction("!script");
|
||||
src.getActionScriptSource(writer, actions);
|
||||
writer.endFunction();
|
||||
|
||||
HighlightedText result = new HighlightedText(writer);
|
||||
SWF swf = src.getSwf();
|
||||
if (swf != null) {
|
||||
swf.as2Cache.put(src, result);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onComplete(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
public Future<HighlightedText> submitTask(ScriptPack pack, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
public HighlightedText call() throws Exception {
|
||||
if (listener != null) {
|
||||
listener.onStart();
|
||||
}
|
||||
|
||||
int scriptIndex = pack.scriptIndex;
|
||||
ScriptInfo script = null;
|
||||
if (scriptIndex > -1) {
|
||||
script = pack.abc.script_info.get(scriptIndex);
|
||||
}
|
||||
boolean parallel = Configuration.parallelSpeedUp.get();
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
|
||||
pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel);
|
||||
|
||||
HighlightedText result = new HighlightedText(writer);
|
||||
SWF swf = pack.getSwf();
|
||||
if (swf != null) {
|
||||
swf.as3Cache.put(pack, result);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onComplete(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
private Future<HighlightedText> submit(Callable<HighlightedText> callable) {
|
||||
boolean parallel = Configuration.parallelSpeedUp.get();
|
||||
if (parallel) {
|
||||
Future<HighlightedText> f = executor.submit(callable);
|
||||
return f;
|
||||
} else {
|
||||
boolean cancelled = false;
|
||||
Throwable throwable = null;
|
||||
HighlightedText result = null;
|
||||
try {
|
||||
result = callable.call();
|
||||
} catch (InterruptedException ex) {
|
||||
cancelled = true;
|
||||
} catch (Exception ex) {
|
||||
throwable = ex;
|
||||
}
|
||||
|
||||
return new ImmediateFuture<>(result, throwable, cancelled);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStat() {
|
||||
return "core: " + executor.getCorePoolSize()
|
||||
+ " size: " + executor.getPoolSize()
|
||||
+ " largest: " + executor.getLargestPoolSize()
|
||||
+ " max: " + executor.getMaximumPoolSize()
|
||||
+ " active: " + executor.getActiveCount()
|
||||
+ " count: " + executor.getTaskCount()
|
||||
+ " completed: " + executor.getCompletedTaskCount();
|
||||
}
|
||||
|
||||
public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(src, actions, null);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException ex) {
|
||||
future.cancel(true);
|
||||
throw ex;
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HighlightedText decompile(ScriptPack pack) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(pack, null);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException ex) {
|
||||
future.cancel(true);
|
||||
throw ex;
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void shutdown() throws InterruptedException {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(100, TimeUnit.SECONDS)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+269
-269
@@ -1,269 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.commonshape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.awt.Color;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.CDATASection;
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.DocumentType;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SVGExporter {
|
||||
|
||||
protected static final String sNamespace = "http://www.w3.org/2000/svg";
|
||||
|
||||
protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink";
|
||||
|
||||
protected Document _svg;
|
||||
|
||||
protected Element _svgDefs;
|
||||
|
||||
protected CDATASection _svgStyle;
|
||||
|
||||
protected Stack<Element> _svgGs = new Stack<>();
|
||||
|
||||
public List<Element> gradients;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
public Map<Tag, String> exportedTags = new HashMap<>();
|
||||
|
||||
public Map<Tag, Map<Integer, String>> exportedChars = new HashMap<>();
|
||||
|
||||
private final Map<String, Integer> lastIds = new HashMap<>();
|
||||
|
||||
private final HashSet<String> fontFaces = new HashSet<>();
|
||||
|
||||
public boolean useTextTag = Configuration.textExportExportFontFace.get();
|
||||
|
||||
public SVGExporter(ExportRectangle bounds, double zoom) {
|
||||
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
DOMImplementation impl = docBuilder.getDOMImplementation();
|
||||
DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN",
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
|
||||
_svg = impl.createDocument(sNamespace, "svg", svgDocType);
|
||||
Element svgRoot = _svg.getDocumentElement();
|
||||
svgRoot.setAttribute("xmlns:xlink", xlinkNamespace);
|
||||
if (bounds != null) {
|
||||
svgRoot.setAttribute("width", (bounds.getWidth() / SWF.unitDivisor) + "px");
|
||||
svgRoot.setAttribute("height", (bounds.getHeight() / SWF.unitDivisor) + "px");
|
||||
createDefGroup(bounds, null, zoom);
|
||||
}
|
||||
} catch (ParserConfigurationException ex) {
|
||||
Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
gradients = new ArrayList<>();
|
||||
}
|
||||
|
||||
private Element getDefs() {
|
||||
if (_svgDefs == null) {
|
||||
_svgDefs = _svg.createElement("defs");
|
||||
_svg.getDocumentElement().appendChild(_svgDefs);
|
||||
}
|
||||
return _svgDefs;
|
||||
}
|
||||
|
||||
private CDATASection getStyle() {
|
||||
if (_svgStyle == null) {
|
||||
Element style = _svg.createElement("style");
|
||||
_svgStyle = _svg.createCDATASection("");
|
||||
style.appendChild(_svgStyle);
|
||||
getDefs().appendChild(style);
|
||||
}
|
||||
return _svgStyle;
|
||||
}
|
||||
|
||||
public final void createDefGroup(ExportRectangle bounds, String id) {
|
||||
createDefGroup(bounds, id, 1);
|
||||
}
|
||||
|
||||
public final void createDefGroup(ExportRectangle bounds, String id, double zoom) {
|
||||
Element g = _svg.createElement("g");
|
||||
if (bounds != null) {
|
||||
Matrix mat = Matrix.getTranslateInstance(-bounds.xMin, -bounds.yMin);
|
||||
mat.scale(zoom);
|
||||
g.setAttribute("transform", mat.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
}
|
||||
if (id != null) {
|
||||
g.setAttribute("id", id);
|
||||
}
|
||||
if (_svgGs.size() == 0) {
|
||||
_svg.getDocumentElement().appendChild(g);
|
||||
} else {
|
||||
getDefs().appendChild(g);
|
||||
}
|
||||
_svgGs.add(g);
|
||||
}
|
||||
|
||||
public boolean endGroup() {
|
||||
Element g = _svgGs.pop();
|
||||
if (g.getChildNodes().getLength() == 0) {
|
||||
g.getParentNode().removeChild(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public final Element createSubGroup(Matrix transform, String id) {
|
||||
Element group = createSubGroup(id, "g");
|
||||
if (transform != null) {
|
||||
group.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public final Element createClipPath(Matrix transform, String id) {
|
||||
Element group = createSubGroup(id, "clipPath");
|
||||
Node parent = group.getParentNode();
|
||||
if (parent instanceof Element) {
|
||||
Element parentElement = (Element) parent;
|
||||
group.setAttribute("transform", parentElement.getAttribute("transform"));
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private Element createSubGroup(String id, String tagName) {
|
||||
Element group = _svg.createElement(tagName);
|
||||
if (id != null) {
|
||||
group.setAttribute("id", id);
|
||||
}
|
||||
_svgGs.peek().appendChild(group);
|
||||
_svgGs.add(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
public void addToGroup(Node newChild) {
|
||||
_svgGs.peek().appendChild(newChild);
|
||||
}
|
||||
|
||||
public void addToDefs(Node newChild) {
|
||||
getDefs().appendChild(newChild);
|
||||
}
|
||||
|
||||
public Element createElement(String tagName) {
|
||||
return _svg.createElement(tagName);
|
||||
}
|
||||
|
||||
public String getSVG() {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
DOMSource source = new DOMSource(_svg);
|
||||
StreamResult result = new StreamResult(writer);
|
||||
transformer.transform(source, result);
|
||||
} catch (TransformerException ex) {
|
||||
Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public void setBackGroundColor(Color backGroundColor) {
|
||||
Attr attr = _svg.createAttribute("style");
|
||||
attr.setValue("background: " + new RGBA(backGroundColor).toHexARGB());
|
||||
}
|
||||
|
||||
public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName) {
|
||||
Element image = _svg.createElement("use");
|
||||
if (transform != null) {
|
||||
image.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
image.setAttribute("width", Double.toString(boundRect.getWidth() / (double) SWF.unitDivisor));
|
||||
image.setAttribute("height", Double.toString(boundRect.getHeight() / (double) SWF.unitDivisor));
|
||||
}
|
||||
if (instanceName != null) {
|
||||
image.setAttribute("id", instanceName);
|
||||
}
|
||||
image.setAttribute("xlink:href", "#" + href);
|
||||
_svgGs.peek().appendChild(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
public void addStyle(String fontFace, byte[] data, FontExportMode mode) {
|
||||
if (!fontFaces.contains(fontFace)) {
|
||||
fontFaces.add(fontFace);
|
||||
String base64Data = Helper.byteArrayToBase64String(data);
|
||||
String value = getStyle().getTextContent();
|
||||
value += Helper.newLine;
|
||||
value += " @font-face {" + Helper.newLine;
|
||||
value += " font-family: \"" + fontFace + "\";" + Helper.newLine;
|
||||
switch (mode) {
|
||||
case TTF:
|
||||
value += " src: url('data:font/truetype;base64," + base64Data + "') format(\"truetype\");" + Helper.newLine;
|
||||
break;
|
||||
case WOFF:
|
||||
value += " src: url('data:font/woff;base64," + base64Data + "') format(\"woff\");" + Helper.newLine;
|
||||
break;
|
||||
}
|
||||
value += " }" + Helper.newLine;
|
||||
getStyle().setTextContent(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUniqueId(String prefix) {
|
||||
Integer lastId = lastIds.get(prefix);
|
||||
if (lastId == null) {
|
||||
lastId = 0;
|
||||
} else {
|
||||
lastId++;
|
||||
}
|
||||
lastIds.put(prefix, lastId);
|
||||
return prefix + lastId;
|
||||
}
|
||||
|
||||
protected static double roundPixels20(double pixels) {
|
||||
return Math.round(pixels * 100) / 100.0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.commonshape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.awt.Color;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.CDATASection;
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.DocumentType;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SVGExporter {
|
||||
|
||||
protected static final String sNamespace = "http://www.w3.org/2000/svg";
|
||||
|
||||
protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink";
|
||||
|
||||
protected Document _svg;
|
||||
|
||||
protected Element _svgDefs;
|
||||
|
||||
protected CDATASection _svgStyle;
|
||||
|
||||
protected Stack<Element> _svgGs = new Stack<>();
|
||||
|
||||
public List<Element> gradients;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
public Map<Tag, String> exportedTags = new HashMap<>();
|
||||
|
||||
public Map<Tag, Map<Integer, String>> exportedChars = new HashMap<>();
|
||||
|
||||
private final Map<String, Integer> lastIds = new HashMap<>();
|
||||
|
||||
private final HashSet<String> fontFaces = new HashSet<>();
|
||||
|
||||
public boolean useTextTag = Configuration.textExportExportFontFace.get();
|
||||
|
||||
public SVGExporter(ExportRectangle bounds, double zoom) {
|
||||
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
DOMImplementation impl = docBuilder.getDOMImplementation();
|
||||
DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN",
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
|
||||
_svg = impl.createDocument(sNamespace, "svg", svgDocType);
|
||||
Element svgRoot = _svg.getDocumentElement();
|
||||
svgRoot.setAttribute("xmlns:xlink", xlinkNamespace);
|
||||
if (bounds != null) {
|
||||
svgRoot.setAttribute("width", (bounds.getWidth() / SWF.unitDivisor) + "px");
|
||||
svgRoot.setAttribute("height", (bounds.getHeight() / SWF.unitDivisor) + "px");
|
||||
createDefGroup(bounds, null, zoom);
|
||||
}
|
||||
} catch (ParserConfigurationException ex) {
|
||||
Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
gradients = new ArrayList<>();
|
||||
}
|
||||
|
||||
private Element getDefs() {
|
||||
if (_svgDefs == null) {
|
||||
_svgDefs = _svg.createElement("defs");
|
||||
_svg.getDocumentElement().appendChild(_svgDefs);
|
||||
}
|
||||
return _svgDefs;
|
||||
}
|
||||
|
||||
private CDATASection getStyle() {
|
||||
if (_svgStyle == null) {
|
||||
Element style = _svg.createElement("style");
|
||||
_svgStyle = _svg.createCDATASection("");
|
||||
style.appendChild(_svgStyle);
|
||||
getDefs().appendChild(style);
|
||||
}
|
||||
return _svgStyle;
|
||||
}
|
||||
|
||||
public final void createDefGroup(ExportRectangle bounds, String id) {
|
||||
createDefGroup(bounds, id, 1);
|
||||
}
|
||||
|
||||
public final void createDefGroup(ExportRectangle bounds, String id, double zoom) {
|
||||
Element g = _svg.createElement("g");
|
||||
if (bounds != null) {
|
||||
Matrix mat = Matrix.getTranslateInstance(-bounds.xMin, -bounds.yMin);
|
||||
mat.scale(zoom);
|
||||
g.setAttribute("transform", mat.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
}
|
||||
if (id != null) {
|
||||
g.setAttribute("id", id);
|
||||
}
|
||||
if (_svgGs.size() == 0) {
|
||||
_svg.getDocumentElement().appendChild(g);
|
||||
} else {
|
||||
getDefs().appendChild(g);
|
||||
}
|
||||
_svgGs.add(g);
|
||||
}
|
||||
|
||||
public boolean endGroup() {
|
||||
Element g = _svgGs.pop();
|
||||
if (g.getChildNodes().getLength() == 0) {
|
||||
g.getParentNode().removeChild(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public final Element createSubGroup(Matrix transform, String id) {
|
||||
Element group = createSubGroup(id, "g");
|
||||
if (transform != null) {
|
||||
group.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public final Element createClipPath(Matrix transform, String id) {
|
||||
Element group = createSubGroup(id, "clipPath");
|
||||
Node parent = group.getParentNode();
|
||||
if (parent instanceof Element) {
|
||||
Element parentElement = (Element) parent;
|
||||
group.setAttribute("transform", parentElement.getAttribute("transform"));
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private Element createSubGroup(String id, String tagName) {
|
||||
Element group = _svg.createElement(tagName);
|
||||
if (id != null) {
|
||||
group.setAttribute("id", id);
|
||||
}
|
||||
_svgGs.peek().appendChild(group);
|
||||
_svgGs.add(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
public void addToGroup(Node newChild) {
|
||||
_svgGs.peek().appendChild(newChild);
|
||||
}
|
||||
|
||||
public void addToDefs(Node newChild) {
|
||||
getDefs().appendChild(newChild);
|
||||
}
|
||||
|
||||
public Element createElement(String tagName) {
|
||||
return _svg.createElement(tagName);
|
||||
}
|
||||
|
||||
public String getSVG() {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
DOMSource source = new DOMSource(_svg);
|
||||
StreamResult result = new StreamResult(writer);
|
||||
transformer.transform(source, result);
|
||||
} catch (TransformerException ex) {
|
||||
Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public void setBackGroundColor(Color backGroundColor) {
|
||||
Attr attr = _svg.createAttribute("style");
|
||||
attr.setValue("background: " + new RGBA(backGroundColor).toHexARGB());
|
||||
}
|
||||
|
||||
public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName) {
|
||||
Element image = _svg.createElement("use");
|
||||
if (transform != null) {
|
||||
image.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1));
|
||||
image.setAttribute("width", Double.toString(boundRect.getWidth() / (double) SWF.unitDivisor));
|
||||
image.setAttribute("height", Double.toString(boundRect.getHeight() / (double) SWF.unitDivisor));
|
||||
}
|
||||
if (instanceName != null) {
|
||||
image.setAttribute("id", instanceName);
|
||||
}
|
||||
image.setAttribute("xlink:href", "#" + href);
|
||||
_svgGs.peek().appendChild(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
public void addStyle(String fontFace, byte[] data, FontExportMode mode) {
|
||||
if (!fontFaces.contains(fontFace)) {
|
||||
fontFaces.add(fontFace);
|
||||
String base64Data = Helper.byteArrayToBase64String(data);
|
||||
String value = getStyle().getTextContent();
|
||||
value += Helper.newLine;
|
||||
value += " @font-face {" + Helper.newLine;
|
||||
value += " font-family: \"" + fontFace + "\";" + Helper.newLine;
|
||||
switch (mode) {
|
||||
case TTF:
|
||||
value += " src: url('data:font/truetype;base64," + base64Data + "') format(\"truetype\");" + Helper.newLine;
|
||||
break;
|
||||
case WOFF:
|
||||
value += " src: url('data:font/woff;base64," + base64Data + "') format(\"woff\");" + Helper.newLine;
|
||||
break;
|
||||
}
|
||||
value += " }" + Helper.newLine;
|
||||
getStyle().setTextContent(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUniqueId(String prefix) {
|
||||
Integer lastId = lastIds.get(prefix);
|
||||
if (lastId == null) {
|
||||
lastId = 0;
|
||||
} else {
|
||||
lastId++;
|
||||
}
|
||||
lastIds.put(prefix, lastId);
|
||||
return prefix + lastId;
|
||||
}
|
||||
|
||||
protected static double roundPixels20(double pixels) {
|
||||
return Math.round(pixels * 100) / 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
+463
-463
@@ -1,463 +1,463 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.morphshape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
|
||||
|
||||
protected Element path;
|
||||
|
||||
protected int id;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
private final Color defaultColor;
|
||||
|
||||
private final SWF swf;
|
||||
|
||||
private final SVGExporter exporter;
|
||||
|
||||
public SVGMorphShapeExporter(SWF swf, SHAPE shape, SHAPE endShape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) {
|
||||
super(shape, endShape, colorTransform, zoom);
|
||||
this.swf = swf;
|
||||
this.id = id;
|
||||
this.defaultColor = defaultColor;
|
||||
this.exporter = exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color, RGB colorEnd) {
|
||||
if (color == null) {
|
||||
color = new RGB(defaultColor == null ? Color.black : defaultColor);
|
||||
}
|
||||
if (colorEnd == null) {
|
||||
colorEnd = new RGB(defaultColor == null ? Color.black : defaultColor);
|
||||
}
|
||||
finalizePath();
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", color.toHexRGB());
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
path.appendChild(createAnimateElement("fill", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) {
|
||||
finalizePath();
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
ImageTag image = swf.getImage(bitmapId);
|
||||
if (image != null) {
|
||||
SerializableImage img = image.getImageCached();
|
||||
if (img != null) {
|
||||
if (colorTransform != null) {
|
||||
colorTransform.apply(img);
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
lastPatternId++;
|
||||
String patternId = "PatternID_" + id + "_" + lastPatternId;
|
||||
ImageFormat format = image.getImageFormat();
|
||||
byte[] imageData = Helper.readStream(image.getImageData());
|
||||
String base64ImgData = Helper.byteArrayToBase64String(imageData);
|
||||
path.setAttribute("style", "fill:url(#" + patternId + ")");
|
||||
Element pattern = exporter.createElement("pattern");
|
||||
pattern.setAttribute("id", patternId);
|
||||
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
||||
pattern.setAttribute("overflow", "visible");
|
||||
pattern.setAttribute("width", "" + width);
|
||||
pattern.setAttribute("height", "" + height);
|
||||
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
|
||||
if (matrix != null) {
|
||||
matrix = matrix.clone();
|
||||
matrix.rotateSkew0 *= zoom / SWF.unitDivisor;
|
||||
matrix.rotateSkew1 *= zoom / SWF.unitDivisor;
|
||||
matrix.scaleX *= zoom / SWF.unitDivisor;
|
||||
matrix.scaleY *= zoom / SWF.unitDivisor;
|
||||
matrixEnd = matrixEnd.clone();
|
||||
matrixEnd.rotateSkew0 *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.rotateSkew1 *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.scaleX *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.scaleY *= zoom / SWF.unitDivisor;
|
||||
addMatrixAnimation(pattern, "patternTransform", matrix, matrixEnd);
|
||||
}
|
||||
Element imageElement = exporter.createElement("image");
|
||||
imageElement.setAttribute("width", "" + width);
|
||||
imageElement.setAttribute("height", "" + height);
|
||||
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
|
||||
pattern.appendChild(imageElement);
|
||||
exporter.addToGroup(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) {
|
||||
finalizePath();
|
||||
thickness *= zoom / SWF.unitDivisor;
|
||||
thicknessEnd *= zoom / SWF.unitDivisor;
|
||||
path.setAttribute("fill", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("stroke", color.toHexRGB());
|
||||
path.appendChild(createAnimateElement("stroke", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
}
|
||||
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
|
||||
path.appendChild(createAnimateElement("stroke-width", thickness, thicknessEnd));
|
||||
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
path.setAttribute("stroke-linecap", "butt");
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
path.setAttribute("stroke-linecap", "square");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
break;
|
||||
}
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "bevel");
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "round");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linejoin", "miter");
|
||||
if (miterLimit >= 1 && miterLimit != 4f) {
|
||||
path.setAttribute("stroke-miterlimit", Double.toString(miterLimit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) {
|
||||
path.removeAttribute("stroke-opacity");
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill", "none");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
private Element createAnimateElement(String attributeName, Object startValue, Object endValue) {
|
||||
Element animate = exporter.createElement("animate");
|
||||
animate.setAttribute("dur", "2s"); // todo
|
||||
animate.setAttribute("repeatCount", "indefinite");
|
||||
animate.setAttribute("attributeName", attributeName);
|
||||
animate.setAttribute("values", startValue + ";" + endValue);
|
||||
return animate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && pathData != null && pathData.length() > 0) {
|
||||
path.setAttribute("d", pathData.toString().trim());
|
||||
path.appendChild(createAnimateElement("d", pathData.toString().trim(), pathDataEnd.toString().trim()));
|
||||
exporter.addToGroup(path);
|
||||
}
|
||||
path = exporter.createElement("path");
|
||||
super.finalizePath();
|
||||
}
|
||||
|
||||
private void addMatrixAnimation(Element element, String attribute, Matrix matrix, Matrix matrixEnd) {
|
||||
final int animationLength = 2; // todo
|
||||
final String animationLengthStr = animationLength + "s";
|
||||
|
||||
element.setAttribute(attribute, matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1));
|
||||
|
||||
// QR decomposition
|
||||
double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
|
||||
double a = matrix.scaleX;
|
||||
double b = matrix.rotateSkew0;
|
||||
double c = matrix.rotateSkew1;
|
||||
double d = matrix.scaleY;
|
||||
double r = Math.sqrt(a * a + b * b);
|
||||
double det = a * d - b * c;
|
||||
double rotate = roundPixels400(Math.signum(b) * Math.acos(a / r) * 180 / Math.PI);
|
||||
double scaleX = roundPixels400(r);
|
||||
double scaleY = roundPixels400(det / r);
|
||||
double skewX = roundPixels400(Math.atan((a * c + b * d) / (r * r)) * 180 / Math.PI);
|
||||
|
||||
double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor);
|
||||
double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor);
|
||||
a = matrixEnd.scaleX;
|
||||
b = matrixEnd.rotateSkew0;
|
||||
c = matrixEnd.rotateSkew1;
|
||||
d = matrixEnd.scaleY;
|
||||
double rEnd = Math.sqrt(a * a + b * b);
|
||||
double detEnd = a * d - b * c;
|
||||
double rotateEnd = roundPixels400(Math.signum(b) * Math.acos(a / rEnd) * 180 / Math.PI);
|
||||
double scaleXEnd = roundPixels400(rEnd);
|
||||
double scaleYEnd = roundPixels400(detEnd / rEnd);
|
||||
double skewXEnd = roundPixels400(Math.atan((a * c + b * d) / (rEnd * rEnd)) * 180 / Math.PI);
|
||||
|
||||
Element animateClear = exporter.createElement("animateTransform");
|
||||
animateClear.setAttribute("dur", animationLengthStr);
|
||||
animateClear.setAttribute("repeatCount", "indefinite");
|
||||
animateClear.setAttribute("attributeName", attribute);
|
||||
animateClear.setAttribute("type", "scale");
|
||||
animateClear.setAttribute("additive", "replace");
|
||||
animateClear.setAttribute("from", "1");
|
||||
animateClear.setAttribute("to", "1");
|
||||
|
||||
Element animateTranslate = exporter.createElement("animateTransform");
|
||||
animateTranslate.setAttribute("dur", animationLengthStr);
|
||||
animateTranslate.setAttribute("repeatCount", "indefinite");
|
||||
animateTranslate.setAttribute("attributeName", attribute);
|
||||
animateTranslate.setAttribute("type", "translate");
|
||||
animateTranslate.setAttribute("additive", "sum");
|
||||
animateTranslate.setAttribute("from", translateX + " " + translateY);
|
||||
animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd);
|
||||
|
||||
Element animateRotate = exporter.createElement("animateTransform");
|
||||
animateRotate.setAttribute("dur", animationLengthStr);
|
||||
animateRotate.setAttribute("repeatCount", "indefinite");
|
||||
animateRotate.setAttribute("attributeName", attribute);
|
||||
animateRotate.setAttribute("type", "rotate");
|
||||
animateRotate.setAttribute("additive", "sum");
|
||||
animateRotate.setAttribute("from", Double.toString(rotate));
|
||||
animateRotate.setAttribute("to", Double.toString(rotateEnd));
|
||||
|
||||
Element animateScale = exporter.createElement("animateTransform");
|
||||
animateScale.setAttribute("dur", animationLengthStr);
|
||||
animateScale.setAttribute("repeatCount", "indefinite");
|
||||
animateScale.setAttribute("attributeName", attribute);
|
||||
animateScale.setAttribute("type", "scale");
|
||||
animateScale.setAttribute("additive", "sum");
|
||||
animateScale.setAttribute("from", scaleX + " " + scaleY);
|
||||
animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd);
|
||||
|
||||
Element animateSkewX = exporter.createElement("animateTransform");
|
||||
animateSkewX.setAttribute("dur", animationLengthStr);
|
||||
animateSkewX.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewX.setAttribute("attributeName", attribute);
|
||||
animateSkewX.setAttribute("type", "skewX");
|
||||
animateSkewX.setAttribute("additive", "sum");
|
||||
animateSkewX.setAttribute("from", Double.toString(skewX));
|
||||
animateSkewX.setAttribute("to", Double.toString(skewXEnd));
|
||||
|
||||
element.appendChild(animateClear);
|
||||
element.appendChild(animateTranslate);
|
||||
element.appendChild(animateRotate);
|
||||
element.appendChild(animateScale);
|
||||
element.appendChild(animateSkewX);
|
||||
|
||||
/*
|
||||
// LDU decomposition
|
||||
|
||||
double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
|
||||
double a = matrix.scaleX;
|
||||
double b = matrix.rotateSkew0;
|
||||
double c = matrix.rotateSkew1;
|
||||
double d = matrix.scaleY;
|
||||
double det = a * d - b * c;
|
||||
double skewY = roundPixels400(Math.atan2(b, a) * 180 / Math.PI);
|
||||
double scaleX = roundPixels400(a);
|
||||
double scaleY = roundPixels400(det / a);
|
||||
double skewX = roundPixels400(Math.atan2(c, a) * 180 / Math.PI);
|
||||
|
||||
double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor);
|
||||
double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor);
|
||||
a = matrixEnd.scaleX;
|
||||
b = matrixEnd.rotateSkew0;
|
||||
c = matrixEnd.rotateSkew1;
|
||||
d = matrixEnd.scaleY;
|
||||
double detEnd = a * d - b * c;
|
||||
double skewYEnd = roundPixels400(Math.atan2(b, a) * 180 / Math.PI);
|
||||
double scaleXEnd = roundPixels400(a);
|
||||
double scaleYEnd = roundPixels400(detEnd / a);
|
||||
double skewXEnd = roundPixels400(Math.atan2(c, a) * 180 / Math.PI);
|
||||
|
||||
Element animateClear = exporter.createElement("animateTransform");
|
||||
animateClear.setAttribute("dur", animationLengthStr);
|
||||
animateClear.setAttribute("repeatCount", "indefinite");
|
||||
animateClear.setAttribute("attributeName", attribute);
|
||||
animateClear.setAttribute("type", "scale");
|
||||
animateClear.setAttribute("additive", "replace");
|
||||
animateClear.setAttribute("from", "1");
|
||||
animateClear.setAttribute("to", "1");
|
||||
|
||||
Element animateTranslate = exporter.createElement("animateTransform");
|
||||
animateTranslate.setAttribute("dur", animationLengthStr);
|
||||
animateTranslate.setAttribute("repeatCount", "indefinite");
|
||||
animateTranslate.setAttribute("attributeName", attribute);
|
||||
animateTranslate.setAttribute("type", "translate");
|
||||
animateTranslate.setAttribute("additive", "sum");
|
||||
animateTranslate.setAttribute("from", translateX + " " + translateY);
|
||||
animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd);
|
||||
|
||||
Element animateSkewY = exporter.createElement("animateTransform");
|
||||
animateSkewY.setAttribute("dur", animationLengthStr);
|
||||
animateSkewY.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewY.setAttribute("attributeName", attribute);
|
||||
animateSkewY.setAttribute("type", "skewY");
|
||||
animateSkewY.setAttribute("additive", "sum");
|
||||
animateSkewY.setAttribute("from", Double.toString(skewY));
|
||||
animateSkewY.setAttribute("to", Double.toString(skewYEnd));
|
||||
|
||||
Element animateScale = exporter.createElement("animateTransform");
|
||||
animateScale.setAttribute("dur", animationLengthStr);
|
||||
animateScale.setAttribute("repeatCount", "indefinite");
|
||||
animateScale.setAttribute("attributeName", attribute);
|
||||
animateScale.setAttribute("type", "scale");
|
||||
animateScale.setAttribute("additive", "sum");
|
||||
animateScale.setAttribute("from", scaleX + " " + scaleY);
|
||||
animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd);
|
||||
|
||||
Element animateSkewX = exporter.createElement("animateTransform");
|
||||
animateSkewX.setAttribute("dur", animationLengthStr);
|
||||
animateSkewX.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewX.setAttribute("attributeName", attribute);
|
||||
animateSkewX.setAttribute("type", "skewX");
|
||||
animateSkewX.setAttribute("additive", "sum");
|
||||
animateSkewX.setAttribute("from", Double.toString(skewX));
|
||||
animateSkewX.setAttribute("to", Double.toString(skewXEnd));
|
||||
|
||||
element.appendChild(animateClear);
|
||||
element.appendChild(animateTranslate);
|
||||
element.appendChild(animateSkewY);
|
||||
element.appendChild(animateScale);
|
||||
element.appendChild(animateSkewX);*/
|
||||
}
|
||||
|
||||
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
||||
if (type == FILLSTYLE.LINEAR_GRADIENT) {
|
||||
gradient.setAttribute("x1", "-819.2");
|
||||
gradient.setAttribute("x2", "819.2");
|
||||
} else {
|
||||
gradient.setAttribute("r", "819.2");
|
||||
gradient.setAttribute("cx", "0");
|
||||
gradient.setAttribute("cy", "0");
|
||||
if (focalPointRatio != 0) {
|
||||
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
|
||||
gradient.setAttribute("fy", "0");
|
||||
}
|
||||
}
|
||||
switch (spreadMethod) {
|
||||
case GRADIENT.SPREAD_PAD_MODE:
|
||||
gradient.setAttribute("spreadMethod", "pad");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REFLECT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "reflect");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REPEAT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "repeat");
|
||||
break;
|
||||
}
|
||||
if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
|
||||
gradient.setAttribute("color-interpolation", "linearRGB");
|
||||
}
|
||||
if (matrix != null) {
|
||||
addMatrixAnimation(gradient, "gradientTransform", matrix, matrixEnd);
|
||||
}
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
GRADRECORD record = gradientRecords[i];
|
||||
GRADRECORD recordEnd = gradientRecordsEnd[i];
|
||||
Element gradientEntry = exporter.createElement("stop");
|
||||
gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0));
|
||||
gradientEntry.appendChild(createAnimateElement("offset", record.ratio / 255.0, recordEnd.ratio / 255.0));
|
||||
RGB color = record.color;
|
||||
RGB colorEnd = recordEnd.color;
|
||||
//if(colors.get(i) != 0) {
|
||||
gradientEntry.setAttribute("stop-color", color.toHexRGB());
|
||||
gradientEntry.appendChild(createAnimateElement("stop-color", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
//}
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
gradientEntry.appendChild(createAnimateElement("stop-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
gradient.appendChild(gradientEntry);
|
||||
}
|
||||
}
|
||||
|
||||
protected double roundPixels400(double pixels) {
|
||||
return Math.round(pixels * 10000) / 10000.0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.morphshape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
|
||||
|
||||
protected Element path;
|
||||
|
||||
protected int id;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
private final Color defaultColor;
|
||||
|
||||
private final SWF swf;
|
||||
|
||||
private final SVGExporter exporter;
|
||||
|
||||
public SVGMorphShapeExporter(SWF swf, SHAPE shape, SHAPE endShape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) {
|
||||
super(shape, endShape, colorTransform, zoom);
|
||||
this.swf = swf;
|
||||
this.id = id;
|
||||
this.defaultColor = defaultColor;
|
||||
this.exporter = exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color, RGB colorEnd) {
|
||||
if (color == null) {
|
||||
color = new RGB(defaultColor == null ? Color.black : defaultColor);
|
||||
}
|
||||
if (colorEnd == null) {
|
||||
colorEnd = new RGB(defaultColor == null ? Color.black : defaultColor);
|
||||
}
|
||||
finalizePath();
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", color.toHexRGB());
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
path.appendChild(createAnimateElement("fill", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) {
|
||||
finalizePath();
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
ImageTag image = swf.getImage(bitmapId);
|
||||
if (image != null) {
|
||||
SerializableImage img = image.getImageCached();
|
||||
if (img != null) {
|
||||
if (colorTransform != null) {
|
||||
colorTransform.apply(img);
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
lastPatternId++;
|
||||
String patternId = "PatternID_" + id + "_" + lastPatternId;
|
||||
ImageFormat format = image.getImageFormat();
|
||||
byte[] imageData = Helper.readStream(image.getImageData());
|
||||
String base64ImgData = Helper.byteArrayToBase64String(imageData);
|
||||
path.setAttribute("style", "fill:url(#" + patternId + ")");
|
||||
Element pattern = exporter.createElement("pattern");
|
||||
pattern.setAttribute("id", patternId);
|
||||
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
||||
pattern.setAttribute("overflow", "visible");
|
||||
pattern.setAttribute("width", "" + width);
|
||||
pattern.setAttribute("height", "" + height);
|
||||
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
|
||||
if (matrix != null) {
|
||||
matrix = matrix.clone();
|
||||
matrix.rotateSkew0 *= zoom / SWF.unitDivisor;
|
||||
matrix.rotateSkew1 *= zoom / SWF.unitDivisor;
|
||||
matrix.scaleX *= zoom / SWF.unitDivisor;
|
||||
matrix.scaleY *= zoom / SWF.unitDivisor;
|
||||
matrixEnd = matrixEnd.clone();
|
||||
matrixEnd.rotateSkew0 *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.rotateSkew1 *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.scaleX *= zoom / SWF.unitDivisor;
|
||||
matrixEnd.scaleY *= zoom / SWF.unitDivisor;
|
||||
addMatrixAnimation(pattern, "patternTransform", matrix, matrixEnd);
|
||||
}
|
||||
Element imageElement = exporter.createElement("image");
|
||||
imageElement.setAttribute("width", "" + width);
|
||||
imageElement.setAttribute("height", "" + height);
|
||||
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
|
||||
pattern.appendChild(imageElement);
|
||||
exporter.addToGroup(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) {
|
||||
finalizePath();
|
||||
thickness *= zoom / SWF.unitDivisor;
|
||||
thicknessEnd *= zoom / SWF.unitDivisor;
|
||||
path.setAttribute("fill", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("stroke", color.toHexRGB());
|
||||
path.appendChild(createAnimateElement("stroke", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
}
|
||||
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
|
||||
path.appendChild(createAnimateElement("stroke-width", thickness, thicknessEnd));
|
||||
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
path.setAttribute("stroke-linecap", "butt");
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
path.setAttribute("stroke-linecap", "square");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
break;
|
||||
}
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "bevel");
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "round");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linejoin", "miter");
|
||||
if (miterLimit >= 1 && miterLimit != 4f) {
|
||||
path.setAttribute("stroke-miterlimit", Double.toString(miterLimit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) {
|
||||
path.removeAttribute("stroke-opacity");
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill", "none");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
private Element createAnimateElement(String attributeName, Object startValue, Object endValue) {
|
||||
Element animate = exporter.createElement("animate");
|
||||
animate.setAttribute("dur", "2s"); // todo
|
||||
animate.setAttribute("repeatCount", "indefinite");
|
||||
animate.setAttribute("attributeName", attributeName);
|
||||
animate.setAttribute("values", startValue + ";" + endValue);
|
||||
return animate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && pathData != null && pathData.length() > 0) {
|
||||
path.setAttribute("d", pathData.toString().trim());
|
||||
path.appendChild(createAnimateElement("d", pathData.toString().trim(), pathDataEnd.toString().trim()));
|
||||
exporter.addToGroup(path);
|
||||
}
|
||||
path = exporter.createElement("path");
|
||||
super.finalizePath();
|
||||
}
|
||||
|
||||
private void addMatrixAnimation(Element element, String attribute, Matrix matrix, Matrix matrixEnd) {
|
||||
final int animationLength = 2; // todo
|
||||
final String animationLengthStr = animationLength + "s";
|
||||
|
||||
element.setAttribute(attribute, matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1));
|
||||
|
||||
// QR decomposition
|
||||
double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
|
||||
double a = matrix.scaleX;
|
||||
double b = matrix.rotateSkew0;
|
||||
double c = matrix.rotateSkew1;
|
||||
double d = matrix.scaleY;
|
||||
double r = Math.sqrt(a * a + b * b);
|
||||
double det = a * d - b * c;
|
||||
double rotate = roundPixels400(Math.signum(b) * Math.acos(a / r) * 180 / Math.PI);
|
||||
double scaleX = roundPixels400(r);
|
||||
double scaleY = roundPixels400(det / r);
|
||||
double skewX = roundPixels400(Math.atan((a * c + b * d) / (r * r)) * 180 / Math.PI);
|
||||
|
||||
double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor);
|
||||
double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor);
|
||||
a = matrixEnd.scaleX;
|
||||
b = matrixEnd.rotateSkew0;
|
||||
c = matrixEnd.rotateSkew1;
|
||||
d = matrixEnd.scaleY;
|
||||
double rEnd = Math.sqrt(a * a + b * b);
|
||||
double detEnd = a * d - b * c;
|
||||
double rotateEnd = roundPixels400(Math.signum(b) * Math.acos(a / rEnd) * 180 / Math.PI);
|
||||
double scaleXEnd = roundPixels400(rEnd);
|
||||
double scaleYEnd = roundPixels400(detEnd / rEnd);
|
||||
double skewXEnd = roundPixels400(Math.atan((a * c + b * d) / (rEnd * rEnd)) * 180 / Math.PI);
|
||||
|
||||
Element animateClear = exporter.createElement("animateTransform");
|
||||
animateClear.setAttribute("dur", animationLengthStr);
|
||||
animateClear.setAttribute("repeatCount", "indefinite");
|
||||
animateClear.setAttribute("attributeName", attribute);
|
||||
animateClear.setAttribute("type", "scale");
|
||||
animateClear.setAttribute("additive", "replace");
|
||||
animateClear.setAttribute("from", "1");
|
||||
animateClear.setAttribute("to", "1");
|
||||
|
||||
Element animateTranslate = exporter.createElement("animateTransform");
|
||||
animateTranslate.setAttribute("dur", animationLengthStr);
|
||||
animateTranslate.setAttribute("repeatCount", "indefinite");
|
||||
animateTranslate.setAttribute("attributeName", attribute);
|
||||
animateTranslate.setAttribute("type", "translate");
|
||||
animateTranslate.setAttribute("additive", "sum");
|
||||
animateTranslate.setAttribute("from", translateX + " " + translateY);
|
||||
animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd);
|
||||
|
||||
Element animateRotate = exporter.createElement("animateTransform");
|
||||
animateRotate.setAttribute("dur", animationLengthStr);
|
||||
animateRotate.setAttribute("repeatCount", "indefinite");
|
||||
animateRotate.setAttribute("attributeName", attribute);
|
||||
animateRotate.setAttribute("type", "rotate");
|
||||
animateRotate.setAttribute("additive", "sum");
|
||||
animateRotate.setAttribute("from", Double.toString(rotate));
|
||||
animateRotate.setAttribute("to", Double.toString(rotateEnd));
|
||||
|
||||
Element animateScale = exporter.createElement("animateTransform");
|
||||
animateScale.setAttribute("dur", animationLengthStr);
|
||||
animateScale.setAttribute("repeatCount", "indefinite");
|
||||
animateScale.setAttribute("attributeName", attribute);
|
||||
animateScale.setAttribute("type", "scale");
|
||||
animateScale.setAttribute("additive", "sum");
|
||||
animateScale.setAttribute("from", scaleX + " " + scaleY);
|
||||
animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd);
|
||||
|
||||
Element animateSkewX = exporter.createElement("animateTransform");
|
||||
animateSkewX.setAttribute("dur", animationLengthStr);
|
||||
animateSkewX.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewX.setAttribute("attributeName", attribute);
|
||||
animateSkewX.setAttribute("type", "skewX");
|
||||
animateSkewX.setAttribute("additive", "sum");
|
||||
animateSkewX.setAttribute("from", Double.toString(skewX));
|
||||
animateSkewX.setAttribute("to", Double.toString(skewXEnd));
|
||||
|
||||
element.appendChild(animateClear);
|
||||
element.appendChild(animateTranslate);
|
||||
element.appendChild(animateRotate);
|
||||
element.appendChild(animateScale);
|
||||
element.appendChild(animateSkewX);
|
||||
|
||||
/*
|
||||
// LDU decomposition
|
||||
|
||||
double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
|
||||
double a = matrix.scaleX;
|
||||
double b = matrix.rotateSkew0;
|
||||
double c = matrix.rotateSkew1;
|
||||
double d = matrix.scaleY;
|
||||
double det = a * d - b * c;
|
||||
double skewY = roundPixels400(Math.atan2(b, a) * 180 / Math.PI);
|
||||
double scaleX = roundPixels400(a);
|
||||
double scaleY = roundPixels400(det / a);
|
||||
double skewX = roundPixels400(Math.atan2(c, a) * 180 / Math.PI);
|
||||
|
||||
double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor);
|
||||
double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor);
|
||||
a = matrixEnd.scaleX;
|
||||
b = matrixEnd.rotateSkew0;
|
||||
c = matrixEnd.rotateSkew1;
|
||||
d = matrixEnd.scaleY;
|
||||
double detEnd = a * d - b * c;
|
||||
double skewYEnd = roundPixels400(Math.atan2(b, a) * 180 / Math.PI);
|
||||
double scaleXEnd = roundPixels400(a);
|
||||
double scaleYEnd = roundPixels400(detEnd / a);
|
||||
double skewXEnd = roundPixels400(Math.atan2(c, a) * 180 / Math.PI);
|
||||
|
||||
Element animateClear = exporter.createElement("animateTransform");
|
||||
animateClear.setAttribute("dur", animationLengthStr);
|
||||
animateClear.setAttribute("repeatCount", "indefinite");
|
||||
animateClear.setAttribute("attributeName", attribute);
|
||||
animateClear.setAttribute("type", "scale");
|
||||
animateClear.setAttribute("additive", "replace");
|
||||
animateClear.setAttribute("from", "1");
|
||||
animateClear.setAttribute("to", "1");
|
||||
|
||||
Element animateTranslate = exporter.createElement("animateTransform");
|
||||
animateTranslate.setAttribute("dur", animationLengthStr);
|
||||
animateTranslate.setAttribute("repeatCount", "indefinite");
|
||||
animateTranslate.setAttribute("attributeName", attribute);
|
||||
animateTranslate.setAttribute("type", "translate");
|
||||
animateTranslate.setAttribute("additive", "sum");
|
||||
animateTranslate.setAttribute("from", translateX + " " + translateY);
|
||||
animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd);
|
||||
|
||||
Element animateSkewY = exporter.createElement("animateTransform");
|
||||
animateSkewY.setAttribute("dur", animationLengthStr);
|
||||
animateSkewY.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewY.setAttribute("attributeName", attribute);
|
||||
animateSkewY.setAttribute("type", "skewY");
|
||||
animateSkewY.setAttribute("additive", "sum");
|
||||
animateSkewY.setAttribute("from", Double.toString(skewY));
|
||||
animateSkewY.setAttribute("to", Double.toString(skewYEnd));
|
||||
|
||||
Element animateScale = exporter.createElement("animateTransform");
|
||||
animateScale.setAttribute("dur", animationLengthStr);
|
||||
animateScale.setAttribute("repeatCount", "indefinite");
|
||||
animateScale.setAttribute("attributeName", attribute);
|
||||
animateScale.setAttribute("type", "scale");
|
||||
animateScale.setAttribute("additive", "sum");
|
||||
animateScale.setAttribute("from", scaleX + " " + scaleY);
|
||||
animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd);
|
||||
|
||||
Element animateSkewX = exporter.createElement("animateTransform");
|
||||
animateSkewX.setAttribute("dur", animationLengthStr);
|
||||
animateSkewX.setAttribute("repeatCount", "indefinite");
|
||||
animateSkewX.setAttribute("attributeName", attribute);
|
||||
animateSkewX.setAttribute("type", "skewX");
|
||||
animateSkewX.setAttribute("additive", "sum");
|
||||
animateSkewX.setAttribute("from", Double.toString(skewX));
|
||||
animateSkewX.setAttribute("to", Double.toString(skewXEnd));
|
||||
|
||||
element.appendChild(animateClear);
|
||||
element.appendChild(animateTranslate);
|
||||
element.appendChild(animateSkewY);
|
||||
element.appendChild(animateScale);
|
||||
element.appendChild(animateSkewX);*/
|
||||
}
|
||||
|
||||
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
||||
if (type == FILLSTYLE.LINEAR_GRADIENT) {
|
||||
gradient.setAttribute("x1", "-819.2");
|
||||
gradient.setAttribute("x2", "819.2");
|
||||
} else {
|
||||
gradient.setAttribute("r", "819.2");
|
||||
gradient.setAttribute("cx", "0");
|
||||
gradient.setAttribute("cy", "0");
|
||||
if (focalPointRatio != 0) {
|
||||
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
|
||||
gradient.setAttribute("fy", "0");
|
||||
}
|
||||
}
|
||||
switch (spreadMethod) {
|
||||
case GRADIENT.SPREAD_PAD_MODE:
|
||||
gradient.setAttribute("spreadMethod", "pad");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REFLECT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "reflect");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REPEAT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "repeat");
|
||||
break;
|
||||
}
|
||||
if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
|
||||
gradient.setAttribute("color-interpolation", "linearRGB");
|
||||
}
|
||||
if (matrix != null) {
|
||||
addMatrixAnimation(gradient, "gradientTransform", matrix, matrixEnd);
|
||||
}
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
GRADRECORD record = gradientRecords[i];
|
||||
GRADRECORD recordEnd = gradientRecordsEnd[i];
|
||||
Element gradientEntry = exporter.createElement("stop");
|
||||
gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0));
|
||||
gradientEntry.appendChild(createAnimateElement("offset", record.ratio / 255.0, recordEnd.ratio / 255.0));
|
||||
RGB color = record.color;
|
||||
RGB colorEnd = recordEnd.color;
|
||||
//if(colors.get(i) != 0) {
|
||||
gradientEntry.setAttribute("stop-color", color.toHexRGB());
|
||||
gradientEntry.appendChild(createAnimateElement("stop-color", color.toHexRGB(), colorEnd.toHexRGB()));
|
||||
//}
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
RGBA colorAEnd = (RGBA) colorEnd;
|
||||
gradientEntry.appendChild(createAnimateElement("stop-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
|
||||
}
|
||||
gradient.appendChild(gradientEntry);
|
||||
}
|
||||
}
|
||||
|
||||
protected double roundPixels400(double pixels) {
|
||||
return Math.round(pixels * 10000) / 10000.0;
|
||||
}
|
||||
}
|
||||
|
||||
+264
-264
@@ -1,264 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.shape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
|
||||
protected Element path;
|
||||
|
||||
protected int id;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
private final Color defaultColor;
|
||||
|
||||
private final SWF swf;
|
||||
|
||||
private final SVGExporter exporter;
|
||||
|
||||
public SVGShapeExporter(SWF swf, SHAPE shape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) {
|
||||
super(swf, shape, colorTransform, zoom);
|
||||
this.swf = swf;
|
||||
this.id = id;
|
||||
this.defaultColor = defaultColor;
|
||||
this.exporter = exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color) {
|
||||
if (color == null && defaultColor != null) {
|
||||
color = new RGB(defaultColor);
|
||||
}
|
||||
finalizePath();
|
||||
path.setAttribute("stroke", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("fill", color.toHexRGB());
|
||||
}
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
finalizePath();
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
String gradientId = "gradient" + id;
|
||||
gradient.setAttribute("id", gradientId);
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", "url(#" + gradientId + ")");
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
ImageTag image = swf.getImage(bitmapId);
|
||||
if (image != null) {
|
||||
SerializableImage img = image.getImageCached();
|
||||
if (img != null) {
|
||||
if (colorTransform != null) {
|
||||
colorTransform.apply(img);
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
lastPatternId++;
|
||||
String patternId = "PatternID_" + id + "_" + lastPatternId;
|
||||
ImageFormat format = image.getImageFormat();
|
||||
byte[] imageData = Helper.readStream(image.getImageData());
|
||||
String base64ImgData = Helper.byteArrayToBase64String(imageData);
|
||||
path.setAttribute("style", "fill:url(#" + patternId + ")");
|
||||
Element pattern = exporter.createElement("pattern");
|
||||
pattern.setAttribute("id", patternId);
|
||||
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
||||
pattern.setAttribute("overflow", "visible");
|
||||
pattern.setAttribute("width", "" + width);
|
||||
pattern.setAttribute("height", "" + height);
|
||||
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
|
||||
if (matrix != null) {
|
||||
pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom));
|
||||
}
|
||||
Element imageElement = exporter.createElement("image");
|
||||
imageElement.setAttribute("width", "" + width);
|
||||
imageElement.setAttribute("height", "" + height);
|
||||
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
|
||||
pattern.appendChild(imageElement);
|
||||
exporter.addToGroup(pattern);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
path.setAttribute("fill", "#ff0000");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) {
|
||||
finalizePath();
|
||||
thickness *= zoom / SWF.unitDivisor;
|
||||
path.setAttribute("fill", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("stroke", color.toHexRGB());
|
||||
}
|
||||
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
path.setAttribute("stroke-linecap", "butt");
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
path.setAttribute("stroke-linecap", "square");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
break;
|
||||
}
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "bevel");
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "round");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linejoin", "miter");
|
||||
if (miterLimit >= 1 && miterLimit != 4f) {
|
||||
path.setAttribute("stroke-miterlimit", Double.toString(miterLimit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
path.removeAttribute("stroke-opacity");
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill", "none");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && pathData != null && pathData.length() > 0) {
|
||||
path.setAttribute("d", pathData.toString().trim());
|
||||
exporter.addToGroup(path);
|
||||
}
|
||||
path = exporter.createElement("path");
|
||||
super.finalizePath();
|
||||
}
|
||||
|
||||
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
||||
if (type == FILLSTYLE.LINEAR_GRADIENT) {
|
||||
gradient.setAttribute("x1", "-819.2");
|
||||
gradient.setAttribute("x2", "819.2");
|
||||
} else {
|
||||
gradient.setAttribute("r", "819.2");
|
||||
gradient.setAttribute("cx", "0");
|
||||
gradient.setAttribute("cy", "0");
|
||||
if (focalPointRatio != 0) {
|
||||
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
|
||||
gradient.setAttribute("fy", "0");
|
||||
}
|
||||
}
|
||||
switch (spreadMethod) {
|
||||
case GRADIENT.SPREAD_PAD_MODE:
|
||||
gradient.setAttribute("spreadMethod", "pad");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REFLECT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "reflect");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REPEAT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "repeat");
|
||||
break;
|
||||
}
|
||||
if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
|
||||
gradient.setAttribute("color-interpolation", "linearRGB");
|
||||
}
|
||||
if (matrix != null) {
|
||||
gradient.setAttribute("gradientTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1));
|
||||
}
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
GRADRECORD record = gradientRecords[i];
|
||||
Element gradientEntry = exporter.createElement("stop");
|
||||
gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0));
|
||||
RGB color = record.color;
|
||||
//if(colors.get(i) != 0) {
|
||||
gradientEntry.setAttribute("stop-color", color.toHexRGB());
|
||||
//}
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
gradient.appendChild(gradientEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.shape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
|
||||
protected Element path;
|
||||
|
||||
protected int id;
|
||||
|
||||
protected int lastPatternId;
|
||||
|
||||
private final Color defaultColor;
|
||||
|
||||
private final SWF swf;
|
||||
|
||||
private final SVGExporter exporter;
|
||||
|
||||
public SVGShapeExporter(SWF swf, SHAPE shape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) {
|
||||
super(swf, shape, colorTransform, zoom);
|
||||
this.swf = swf;
|
||||
this.id = id;
|
||||
this.defaultColor = defaultColor;
|
||||
this.exporter = exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color) {
|
||||
if (color == null && defaultColor != null) {
|
||||
color = new RGB(defaultColor);
|
||||
}
|
||||
finalizePath();
|
||||
path.setAttribute("stroke", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("fill", color.toHexRGB());
|
||||
}
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
finalizePath();
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
String gradientId = "gradient" + id;
|
||||
gradient.setAttribute("id", gradientId);
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", "url(#" + gradientId + ")");
|
||||
path.setAttribute("fill-rule", "evenodd");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
ImageTag image = swf.getImage(bitmapId);
|
||||
if (image != null) {
|
||||
SerializableImage img = image.getImageCached();
|
||||
if (img != null) {
|
||||
if (colorTransform != null) {
|
||||
colorTransform.apply(img);
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
lastPatternId++;
|
||||
String patternId = "PatternID_" + id + "_" + lastPatternId;
|
||||
ImageFormat format = image.getImageFormat();
|
||||
byte[] imageData = Helper.readStream(image.getImageData());
|
||||
String base64ImgData = Helper.byteArrayToBase64String(imageData);
|
||||
path.setAttribute("style", "fill:url(#" + patternId + ")");
|
||||
Element pattern = exporter.createElement("pattern");
|
||||
pattern.setAttribute("id", patternId);
|
||||
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
||||
pattern.setAttribute("overflow", "visible");
|
||||
pattern.setAttribute("width", "" + width);
|
||||
pattern.setAttribute("height", "" + height);
|
||||
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
|
||||
if (matrix != null) {
|
||||
pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom));
|
||||
}
|
||||
Element imageElement = exporter.createElement("image");
|
||||
imageElement.setAttribute("width", "" + width);
|
||||
imageElement.setAttribute("height", "" + height);
|
||||
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
|
||||
pattern.appendChild(imageElement);
|
||||
exporter.addToGroup(pattern);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
path.setAttribute("fill", "#ff0000");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) {
|
||||
finalizePath();
|
||||
thickness *= zoom / SWF.unitDivisor;
|
||||
path.setAttribute("fill", "none");
|
||||
if (color != null) {
|
||||
path.setAttribute("stroke", color.toHexRGB());
|
||||
}
|
||||
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
path.setAttribute("stroke-linecap", "butt");
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
path.setAttribute("stroke-linecap", "square");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
break;
|
||||
}
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "bevel");
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "round");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linejoin", "miter");
|
||||
if (miterLimit >= 1 && miterLimit != 4f) {
|
||||
path.setAttribute("stroke-miterlimit", Double.toString(miterLimit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
path.removeAttribute("stroke-opacity");
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? exporter.createElement("linearGradient")
|
||||
: exporter.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = exporter.gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = exporter.gradients.size();
|
||||
exporter.gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill", "none");
|
||||
exporter.addToDefs(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && pathData != null && pathData.length() > 0) {
|
||||
path.setAttribute("d", pathData.toString().trim());
|
||||
exporter.addToGroup(path);
|
||||
}
|
||||
path = exporter.createElement("path");
|
||||
super.finalizePath();
|
||||
}
|
||||
|
||||
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
||||
if (type == FILLSTYLE.LINEAR_GRADIENT) {
|
||||
gradient.setAttribute("x1", "-819.2");
|
||||
gradient.setAttribute("x2", "819.2");
|
||||
} else {
|
||||
gradient.setAttribute("r", "819.2");
|
||||
gradient.setAttribute("cx", "0");
|
||||
gradient.setAttribute("cy", "0");
|
||||
if (focalPointRatio != 0) {
|
||||
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
|
||||
gradient.setAttribute("fy", "0");
|
||||
}
|
||||
}
|
||||
switch (spreadMethod) {
|
||||
case GRADIENT.SPREAD_PAD_MODE:
|
||||
gradient.setAttribute("spreadMethod", "pad");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REFLECT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "reflect");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REPEAT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "repeat");
|
||||
break;
|
||||
}
|
||||
if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
|
||||
gradient.setAttribute("color-interpolation", "linearRGB");
|
||||
}
|
||||
if (matrix != null) {
|
||||
gradient.setAttribute("gradientTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1));
|
||||
}
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
GRADRECORD record = gradientRecords[i];
|
||||
Element gradientEntry = exporter.createElement("stop");
|
||||
gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0));
|
||||
RGB color = record.color;
|
||||
//if(colors.get(i) != 0) {
|
||||
gradientEntry.setAttribute("stop-color", color.toHexRGB());
|
||||
//}
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
gradient.appendChild(gradientEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,281 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.TagInfo;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Shape;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ImageTag extends DrawableTag {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterID;
|
||||
|
||||
protected SerializableImage cachedImage;
|
||||
|
||||
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract InputStream getOriginalImageData();
|
||||
|
||||
protected abstract SerializableImage getImage();
|
||||
|
||||
public abstract Dimension getImageDimension();
|
||||
|
||||
public abstract void setImage(byte[] data) throws IOException;
|
||||
|
||||
public abstract ImageFormat getImageFormat();
|
||||
|
||||
public abstract ImageFormat getOriginalImageFormat();
|
||||
|
||||
public boolean importSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ImageFormat getImageFormat(byte[] data) {
|
||||
return getImageFormat(new ByteArrayRange(data));
|
||||
}
|
||||
|
||||
public static ImageFormat getImageFormat(ByteArrayRange data) {
|
||||
if (hasErrorHeader(data)) {
|
||||
return ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) {
|
||||
return ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) {
|
||||
return ImageFormat.GIF;
|
||||
}
|
||||
|
||||
if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
return ImageFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
public SerializableImage getImageCached() {
|
||||
if (cachedImage != null) {
|
||||
return cachedImage;
|
||||
}
|
||||
|
||||
SerializableImage image = getImage();
|
||||
if (Configuration.cacheImages.get()) {
|
||||
cachedImage = image;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public InputStream getImageData() {
|
||||
InputStream is = getOriginalImageData();
|
||||
if (is != null) {
|
||||
return is;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos);
|
||||
return new ByteArrayInputStream(baos.toByteArray());
|
||||
}
|
||||
|
||||
public static boolean hasErrorHeader(byte[] data) {
|
||||
return hasErrorHeader(new ByteArrayRange(data));
|
||||
}
|
||||
|
||||
public static boolean hasErrorHeader(ByteArrayRange data) {
|
||||
if (data.getLength() > 4) {
|
||||
if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9
|
||||
&& (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private SHAPEWITHSTYLE getShape() {
|
||||
RECT rect = getRect();
|
||||
return getShape(rect, false);
|
||||
}
|
||||
|
||||
public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) {
|
||||
boolean translated = rect.Xmin != 0 || rect.Ymin != 0;
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = new FILLSTYLEARRAY();
|
||||
shape.fillStyles.fillStyles = new FILLSTYLE[1];
|
||||
FILLSTYLE fillStyle = new FILLSTYLE();
|
||||
fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get()
|
||||
? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP;
|
||||
fillStyle.bitmapId = getCharacterId();
|
||||
MATRIX matrix = new MATRIX();
|
||||
matrix.hasScale = true;
|
||||
if (fill) {
|
||||
RECT imageRect = getRect();
|
||||
matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth());
|
||||
matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight());
|
||||
} else {
|
||||
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
|
||||
matrix.scaleY = matrix.scaleX;
|
||||
}
|
||||
if (translated) {
|
||||
matrix.translateX = rect.Xmin;
|
||||
matrix.translateY = rect.Ymin;
|
||||
}
|
||||
fillStyle.bitmapMatrix = matrix;
|
||||
shape.fillStyles.fillStyles[0] = fillStyle;
|
||||
|
||||
shape.lineStyles = new LINESTYLEARRAY();
|
||||
shape.lineStyles.lineStyles = new LINESTYLE[0];
|
||||
shape.shapeRecords = new ArrayList<>();
|
||||
StyleChangeRecord style = new StyleChangeRecord();
|
||||
style.stateFillStyle0 = true;
|
||||
style.fillStyle0 = 1;
|
||||
style.stateMoveTo = true;
|
||||
if (translated) {
|
||||
style.moveDeltaX = rect.Xmin;
|
||||
style.moveDeltaY = rect.Ymin;
|
||||
}
|
||||
shape.shapeRecords.add(style);
|
||||
StraightEdgeRecord top = new StraightEdgeRecord();
|
||||
top.generalLineFlag = true;
|
||||
top.deltaX = rect.getWidth();
|
||||
StraightEdgeRecord right = new StraightEdgeRecord();
|
||||
right.generalLineFlag = true;
|
||||
right.deltaY = rect.getHeight();
|
||||
StraightEdgeRecord bottom = new StraightEdgeRecord();
|
||||
bottom.generalLineFlag = true;
|
||||
bottom.deltaX = -rect.getWidth();
|
||||
StraightEdgeRecord left = new StraightEdgeRecord();
|
||||
left.generalLineFlag = true;
|
||||
left.deltaY = -rect.getHeight();
|
||||
shape.shapeRecords.add(top);
|
||||
shape.shapeRecords.add(right);
|
||||
shape.shapeRecords.add(bottom);
|
||||
shape.shapeRecords.add(left);
|
||||
shape.shapeRecords.add(new EndShapeRecord());
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
Dimension dimension = getImageDimension();
|
||||
int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor);
|
||||
int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor);
|
||||
return new RECT(0, widthInTwips, 0, heightInTwips);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0);
|
||||
cse.export();
|
||||
result.append(cse.getShapeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
cachedImage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTagInfo(TagInfo tagInfo) {
|
||||
super.getTagInfo(tagInfo);
|
||||
Dimension dimension = getImageDimension();
|
||||
tagInfo.addInfo("general", "width", dimension.getWidth());
|
||||
tagInfo.addInfo("general", "height", dimension.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterID = characterId;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.TagInfo;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Shape;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ImageTag extends DrawableTag {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterID;
|
||||
|
||||
protected SerializableImage cachedImage;
|
||||
|
||||
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract InputStream getOriginalImageData();
|
||||
|
||||
protected abstract SerializableImage getImage();
|
||||
|
||||
public abstract Dimension getImageDimension();
|
||||
|
||||
public abstract void setImage(byte[] data) throws IOException;
|
||||
|
||||
public abstract ImageFormat getImageFormat();
|
||||
|
||||
public abstract ImageFormat getOriginalImageFormat();
|
||||
|
||||
public boolean importSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ImageFormat getImageFormat(byte[] data) {
|
||||
return getImageFormat(new ByteArrayRange(data));
|
||||
}
|
||||
|
||||
public static ImageFormat getImageFormat(ByteArrayRange data) {
|
||||
if (hasErrorHeader(data)) {
|
||||
return ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) {
|
||||
return ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) {
|
||||
return ImageFormat.GIF;
|
||||
}
|
||||
|
||||
if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
return ImageFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
public SerializableImage getImageCached() {
|
||||
if (cachedImage != null) {
|
||||
return cachedImage;
|
||||
}
|
||||
|
||||
SerializableImage image = getImage();
|
||||
if (Configuration.cacheImages.get()) {
|
||||
cachedImage = image;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public InputStream getImageData() {
|
||||
InputStream is = getOriginalImageData();
|
||||
if (is != null) {
|
||||
return is;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos);
|
||||
return new ByteArrayInputStream(baos.toByteArray());
|
||||
}
|
||||
|
||||
public static boolean hasErrorHeader(byte[] data) {
|
||||
return hasErrorHeader(new ByteArrayRange(data));
|
||||
}
|
||||
|
||||
public static boolean hasErrorHeader(ByteArrayRange data) {
|
||||
if (data.getLength() > 4) {
|
||||
if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9
|
||||
&& (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private SHAPEWITHSTYLE getShape() {
|
||||
RECT rect = getRect();
|
||||
return getShape(rect, false);
|
||||
}
|
||||
|
||||
public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) {
|
||||
boolean translated = rect.Xmin != 0 || rect.Ymin != 0;
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = new FILLSTYLEARRAY();
|
||||
shape.fillStyles.fillStyles = new FILLSTYLE[1];
|
||||
FILLSTYLE fillStyle = new FILLSTYLE();
|
||||
fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get()
|
||||
? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP;
|
||||
fillStyle.bitmapId = getCharacterId();
|
||||
MATRIX matrix = new MATRIX();
|
||||
matrix.hasScale = true;
|
||||
if (fill) {
|
||||
RECT imageRect = getRect();
|
||||
matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth());
|
||||
matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight());
|
||||
} else {
|
||||
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
|
||||
matrix.scaleY = matrix.scaleX;
|
||||
}
|
||||
if (translated) {
|
||||
matrix.translateX = rect.Xmin;
|
||||
matrix.translateY = rect.Ymin;
|
||||
}
|
||||
fillStyle.bitmapMatrix = matrix;
|
||||
shape.fillStyles.fillStyles[0] = fillStyle;
|
||||
|
||||
shape.lineStyles = new LINESTYLEARRAY();
|
||||
shape.lineStyles.lineStyles = new LINESTYLE[0];
|
||||
shape.shapeRecords = new ArrayList<>();
|
||||
StyleChangeRecord style = new StyleChangeRecord();
|
||||
style.stateFillStyle0 = true;
|
||||
style.fillStyle0 = 1;
|
||||
style.stateMoveTo = true;
|
||||
if (translated) {
|
||||
style.moveDeltaX = rect.Xmin;
|
||||
style.moveDeltaY = rect.Ymin;
|
||||
}
|
||||
shape.shapeRecords.add(style);
|
||||
StraightEdgeRecord top = new StraightEdgeRecord();
|
||||
top.generalLineFlag = true;
|
||||
top.deltaX = rect.getWidth();
|
||||
StraightEdgeRecord right = new StraightEdgeRecord();
|
||||
right.generalLineFlag = true;
|
||||
right.deltaY = rect.getHeight();
|
||||
StraightEdgeRecord bottom = new StraightEdgeRecord();
|
||||
bottom.generalLineFlag = true;
|
||||
bottom.deltaX = -rect.getWidth();
|
||||
StraightEdgeRecord left = new StraightEdgeRecord();
|
||||
left.generalLineFlag = true;
|
||||
left.deltaY = -rect.getHeight();
|
||||
shape.shapeRecords.add(top);
|
||||
shape.shapeRecords.add(right);
|
||||
shape.shapeRecords.add(bottom);
|
||||
shape.shapeRecords.add(left);
|
||||
shape.shapeRecords.add(new EndShapeRecord());
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
Dimension dimension = getImageDimension();
|
||||
int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor);
|
||||
int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor);
|
||||
return new RECT(0, widthInTwips, 0, heightInTwips);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0);
|
||||
cse.export();
|
||||
result.append(cse.getShapeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
cachedImage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTagInfo(TagInfo tagInfo) {
|
||||
super.getTagInfo(tagInfo);
|
||||
Dimension dimension = getImageDimension();
|
||||
tagInfo.addInfo("general", "width", dimension.getWidth());
|
||||
tagInfo.addInfo("general", "height", dimension.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterID = characterId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,327 +1,327 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Shape;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class MorphShapeTag extends DrawableTag {
|
||||
|
||||
public static final int MAX_RATIO = 65535;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterId;
|
||||
|
||||
public RECT startBounds;
|
||||
|
||||
public RECT endBounds;
|
||||
|
||||
public MORPHFILLSTYLEARRAY morphFillStyles;
|
||||
|
||||
public MORPHLINESTYLEARRAY morphLineStyles;
|
||||
|
||||
public SHAPE startEdges;
|
||||
|
||||
public SHAPE endEdges;
|
||||
|
||||
public MorphShapeTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract int getShapeNum();
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(new HashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
morphFillStyles.getNeededCharacters(needed);
|
||||
startEdges.getNeededCharacters(needed);
|
||||
endEdges.getNeededCharacters(needed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = false;
|
||||
modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = false;
|
||||
modified |= morphFillStyles.removeCharacter(characterId);
|
||||
modified |= startEdges.removeCharacter(characterId);
|
||||
modified |= endEdges.removeCharacter(characterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
RECT rect = new RECT();
|
||||
rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin);
|
||||
rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin);
|
||||
rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax);
|
||||
rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax);
|
||||
return rect;
|
||||
}
|
||||
|
||||
public RECT getStartBounds() {
|
||||
return startBounds;
|
||||
}
|
||||
|
||||
public RECT getEndBounds() {
|
||||
return endBounds;
|
||||
}
|
||||
|
||||
public MORPHFILLSTYLEARRAY getFillStyles() {
|
||||
return morphFillStyles;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLEARRAY getLineStyles() {
|
||||
return morphLineStyles;
|
||||
}
|
||||
|
||||
public SHAPE getStartEdges() {
|
||||
return startEdges;
|
||||
}
|
||||
|
||||
public SHAPE getEndEdges() {
|
||||
return endEdges;
|
||||
}
|
||||
|
||||
public SHAPEWITHSTYLE getShapeAtRatio(int ratio) {
|
||||
List<SHAPERECORD> finalRecords = new ArrayList<>();
|
||||
FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio);
|
||||
LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio);
|
||||
|
||||
int startPosX = 0, startPosY = 0;
|
||||
int endPosX = 0, endPosY = 0;
|
||||
int posX = 0, posY = 0;
|
||||
|
||||
for (int startIndex = 0, endIndex = 0;
|
||||
startIndex < startEdges.shapeRecords.size()
|
||||
&& endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) {
|
||||
|
||||
SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex);
|
||||
SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex);
|
||||
if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord scr1;
|
||||
if (edge1 instanceof StyleChangeRecord) {
|
||||
scr1 = (StyleChangeRecord) edge1;
|
||||
if (scr1.stateMoveTo) {
|
||||
startPosX = scr1.moveDeltaX;
|
||||
startPosY = scr1.moveDeltaY;
|
||||
}
|
||||
} else {
|
||||
scr1 = new StyleChangeRecord();
|
||||
startIndex--;
|
||||
}
|
||||
StyleChangeRecord scr2;
|
||||
if (edge2 instanceof StyleChangeRecord) {
|
||||
scr2 = (StyleChangeRecord) edge2;
|
||||
if (scr2.stateMoveTo) {
|
||||
endPosX = scr2.moveDeltaX;
|
||||
endPosY = scr2.moveDeltaY;
|
||||
}
|
||||
} else {
|
||||
scr2 = new StyleChangeRecord();
|
||||
endIndex--;
|
||||
}
|
||||
StyleChangeRecord scr = scr1.clone();
|
||||
if (scr1.stateMoveTo || scr2.stateMoveTo) {
|
||||
scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO;
|
||||
scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO;
|
||||
scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY;
|
||||
}
|
||||
finalRecords.add(scr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (edge1 instanceof EndShapeRecord) {
|
||||
finalRecords.add(edge1);
|
||||
break;
|
||||
}
|
||||
if (edge2 instanceof EndShapeRecord) {
|
||||
finalRecords.add(edge2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) {
|
||||
CurvedEdgeRecord cer1 = null;
|
||||
if (edge1 instanceof CurvedEdgeRecord) {
|
||||
cer1 = (CurvedEdgeRecord) edge1;
|
||||
} else if (edge1 instanceof StraightEdgeRecord) {
|
||||
cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1);
|
||||
}
|
||||
CurvedEdgeRecord cer2 = null;
|
||||
if (edge2 instanceof CurvedEdgeRecord) {
|
||||
cer2 = (CurvedEdgeRecord) edge2;
|
||||
} else if (edge2 instanceof StraightEdgeRecord) {
|
||||
cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2);
|
||||
}
|
||||
if ((cer2 == null) || (cer1 == null)) {
|
||||
continue;
|
||||
}
|
||||
CurvedEdgeRecord cer = new CurvedEdgeRecord();
|
||||
cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO;
|
||||
cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO;
|
||||
cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO;
|
||||
cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO;
|
||||
startPosX += cer1.controlDeltaX + cer1.anchorDeltaX;
|
||||
startPosY += cer1.controlDeltaY + cer1.anchorDeltaY;
|
||||
endPosX += cer2.controlDeltaX + cer2.anchorDeltaX;
|
||||
endPosY += cer2.controlDeltaY + cer2.anchorDeltaY;
|
||||
posX += cer.controlDeltaX + cer.anchorDeltaX;
|
||||
posY += cer.controlDeltaY + cer.anchorDeltaY;
|
||||
finalRecords.add(cer);
|
||||
} else {
|
||||
StraightEdgeRecord ser1 = null;
|
||||
if (edge1 instanceof StraightEdgeRecord) {
|
||||
ser1 = (StraightEdgeRecord) edge1;
|
||||
}
|
||||
StraightEdgeRecord ser2 = null;
|
||||
if (edge2 instanceof StraightEdgeRecord) {
|
||||
ser2 = (StraightEdgeRecord) edge2;
|
||||
}
|
||||
if ((ser2 == null) || (ser1 == null)) {
|
||||
continue;
|
||||
}
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.generalLineFlag = true;
|
||||
ser.vertLineFlag = false;
|
||||
ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO;
|
||||
ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO;
|
||||
startPosX += ser1.deltaX;
|
||||
startPosY += ser1.deltaY;
|
||||
endPosX += ser2.deltaX;
|
||||
endPosY += ser2.deltaY;
|
||||
posX += ser.deltaX;
|
||||
posY += ser.deltaX;
|
||||
finalRecords.add(ser);
|
||||
}
|
||||
}
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = fillStyles;
|
||||
shape.lineStyles = lineStyles;
|
||||
shape.shapeRecords = finalRecords;
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return PARAMETER_RATIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
SHAPEWITHSTYLE shape = getShapeAtRatio(ratio);
|
||||
// morphShape using shapeNum=3, morphShape2 using shapeNum=4
|
||||
// todo: Currently the generated image is not cached, because the cache
|
||||
// key contains the hashCode of the finalRecord object, and it is always
|
||||
// recreated
|
||||
BitmapExporter.export(swf, shape, null, image, transformation, strokeTransformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
if (ratio == -2) {
|
||||
SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0);
|
||||
SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535);
|
||||
SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
} else {
|
||||
SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio);
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 65536;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
// Morpshape is a single frame specified with the ratio
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), null, unitDivisor, 0, 0);
|
||||
cmse.export();
|
||||
result.append(cmse.getShapeData());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Shape;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class MorphShapeTag extends DrawableTag {
|
||||
|
||||
public static final int MAX_RATIO = 65535;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterId;
|
||||
|
||||
public RECT startBounds;
|
||||
|
||||
public RECT endBounds;
|
||||
|
||||
public MORPHFILLSTYLEARRAY morphFillStyles;
|
||||
|
||||
public MORPHLINESTYLEARRAY morphLineStyles;
|
||||
|
||||
public SHAPE startEdges;
|
||||
|
||||
public SHAPE endEdges;
|
||||
|
||||
public MorphShapeTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract int getShapeNum();
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(new HashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
morphFillStyles.getNeededCharacters(needed);
|
||||
startEdges.getNeededCharacters(needed);
|
||||
endEdges.getNeededCharacters(needed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = false;
|
||||
modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = false;
|
||||
modified |= morphFillStyles.removeCharacter(characterId);
|
||||
modified |= startEdges.removeCharacter(characterId);
|
||||
modified |= endEdges.removeCharacter(characterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
RECT rect = new RECT();
|
||||
rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin);
|
||||
rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin);
|
||||
rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax);
|
||||
rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax);
|
||||
return rect;
|
||||
}
|
||||
|
||||
public RECT getStartBounds() {
|
||||
return startBounds;
|
||||
}
|
||||
|
||||
public RECT getEndBounds() {
|
||||
return endBounds;
|
||||
}
|
||||
|
||||
public MORPHFILLSTYLEARRAY getFillStyles() {
|
||||
return morphFillStyles;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLEARRAY getLineStyles() {
|
||||
return morphLineStyles;
|
||||
}
|
||||
|
||||
public SHAPE getStartEdges() {
|
||||
return startEdges;
|
||||
}
|
||||
|
||||
public SHAPE getEndEdges() {
|
||||
return endEdges;
|
||||
}
|
||||
|
||||
public SHAPEWITHSTYLE getShapeAtRatio(int ratio) {
|
||||
List<SHAPERECORD> finalRecords = new ArrayList<>();
|
||||
FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio);
|
||||
LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio);
|
||||
|
||||
int startPosX = 0, startPosY = 0;
|
||||
int endPosX = 0, endPosY = 0;
|
||||
int posX = 0, posY = 0;
|
||||
|
||||
for (int startIndex = 0, endIndex = 0;
|
||||
startIndex < startEdges.shapeRecords.size()
|
||||
&& endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) {
|
||||
|
||||
SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex);
|
||||
SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex);
|
||||
if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord scr1;
|
||||
if (edge1 instanceof StyleChangeRecord) {
|
||||
scr1 = (StyleChangeRecord) edge1;
|
||||
if (scr1.stateMoveTo) {
|
||||
startPosX = scr1.moveDeltaX;
|
||||
startPosY = scr1.moveDeltaY;
|
||||
}
|
||||
} else {
|
||||
scr1 = new StyleChangeRecord();
|
||||
startIndex--;
|
||||
}
|
||||
StyleChangeRecord scr2;
|
||||
if (edge2 instanceof StyleChangeRecord) {
|
||||
scr2 = (StyleChangeRecord) edge2;
|
||||
if (scr2.stateMoveTo) {
|
||||
endPosX = scr2.moveDeltaX;
|
||||
endPosY = scr2.moveDeltaY;
|
||||
}
|
||||
} else {
|
||||
scr2 = new StyleChangeRecord();
|
||||
endIndex--;
|
||||
}
|
||||
StyleChangeRecord scr = scr1.clone();
|
||||
if (scr1.stateMoveTo || scr2.stateMoveTo) {
|
||||
scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO;
|
||||
scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO;
|
||||
scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY;
|
||||
}
|
||||
finalRecords.add(scr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (edge1 instanceof EndShapeRecord) {
|
||||
finalRecords.add(edge1);
|
||||
break;
|
||||
}
|
||||
if (edge2 instanceof EndShapeRecord) {
|
||||
finalRecords.add(edge2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) {
|
||||
CurvedEdgeRecord cer1 = null;
|
||||
if (edge1 instanceof CurvedEdgeRecord) {
|
||||
cer1 = (CurvedEdgeRecord) edge1;
|
||||
} else if (edge1 instanceof StraightEdgeRecord) {
|
||||
cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1);
|
||||
}
|
||||
CurvedEdgeRecord cer2 = null;
|
||||
if (edge2 instanceof CurvedEdgeRecord) {
|
||||
cer2 = (CurvedEdgeRecord) edge2;
|
||||
} else if (edge2 instanceof StraightEdgeRecord) {
|
||||
cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2);
|
||||
}
|
||||
if ((cer2 == null) || (cer1 == null)) {
|
||||
continue;
|
||||
}
|
||||
CurvedEdgeRecord cer = new CurvedEdgeRecord();
|
||||
cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO;
|
||||
cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO;
|
||||
cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO;
|
||||
cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO;
|
||||
startPosX += cer1.controlDeltaX + cer1.anchorDeltaX;
|
||||
startPosY += cer1.controlDeltaY + cer1.anchorDeltaY;
|
||||
endPosX += cer2.controlDeltaX + cer2.anchorDeltaX;
|
||||
endPosY += cer2.controlDeltaY + cer2.anchorDeltaY;
|
||||
posX += cer.controlDeltaX + cer.anchorDeltaX;
|
||||
posY += cer.controlDeltaY + cer.anchorDeltaY;
|
||||
finalRecords.add(cer);
|
||||
} else {
|
||||
StraightEdgeRecord ser1 = null;
|
||||
if (edge1 instanceof StraightEdgeRecord) {
|
||||
ser1 = (StraightEdgeRecord) edge1;
|
||||
}
|
||||
StraightEdgeRecord ser2 = null;
|
||||
if (edge2 instanceof StraightEdgeRecord) {
|
||||
ser2 = (StraightEdgeRecord) edge2;
|
||||
}
|
||||
if ((ser2 == null) || (ser1 == null)) {
|
||||
continue;
|
||||
}
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.generalLineFlag = true;
|
||||
ser.vertLineFlag = false;
|
||||
ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO;
|
||||
ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO;
|
||||
startPosX += ser1.deltaX;
|
||||
startPosY += ser1.deltaY;
|
||||
endPosX += ser2.deltaX;
|
||||
endPosY += ser2.deltaY;
|
||||
posX += ser.deltaX;
|
||||
posY += ser.deltaX;
|
||||
finalRecords.add(ser);
|
||||
}
|
||||
}
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = fillStyles;
|
||||
shape.lineStyles = lineStyles;
|
||||
shape.shapeRecords = finalRecords;
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return PARAMETER_RATIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
SHAPEWITHSTYLE shape = getShapeAtRatio(ratio);
|
||||
// morphShape using shapeNum=3, morphShape2 using shapeNum=4
|
||||
// todo: Currently the generated image is not cached, because the cache
|
||||
// key contains the hashCode of the finalRecord object, and it is always
|
||||
// recreated
|
||||
BitmapExporter.export(swf, shape, null, image, transformation, strokeTransformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
if (ratio == -2) {
|
||||
SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0);
|
||||
SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535);
|
||||
SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
} else {
|
||||
SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio);
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 65536;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
// Morpshape is a single frame specified with the ratio
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), null, unitDivisor, 0, 0);
|
||||
cmse.export();
|
||||
result.append(cmse.getShapeData());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,213 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.PathExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.LazyObject;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ShapeTag extends DrawableTag implements LazyObject {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int shapeId;
|
||||
|
||||
public RECT shapeBounds;
|
||||
|
||||
public SHAPEWITHSTYLE shapes;
|
||||
|
||||
protected ByteArrayRange shapeData;
|
||||
|
||||
private final int markerSize = 10;
|
||||
|
||||
public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
getShapes();
|
||||
}
|
||||
|
||||
public abstract int getShapeNum();
|
||||
|
||||
public SHAPEWITHSTYLE getShapes() {
|
||||
if (shapes == null && shapeData != null) {
|
||||
try {
|
||||
SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength());
|
||||
sis.seek(shapeData.getPos());
|
||||
shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes");
|
||||
shapeData = null; // not needed anymore, give it to GC
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
SHAPEWITHSTYLE shapes = getShapes();
|
||||
if (shapes != null) {
|
||||
getShapes().getNeededCharacters(needed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = getShapes().removeCharacter(characterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShapes().getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform);
|
||||
if (Configuration._debugMode.get()) { // show control points
|
||||
List<GeneralPath> paths = PathExporter.export(swf, getShapes());
|
||||
double[] coords = new double[6];
|
||||
AffineTransform at = transformation.toTransform();
|
||||
at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor));
|
||||
|
||||
// get the graphics from the inner image object, because it creates a new Graphics object
|
||||
Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics();
|
||||
graphics.setPaint(Color.black);
|
||||
for (GeneralPath path : paths) {
|
||||
PathIterator iterator = path.getPathIterator(at);
|
||||
while (!iterator.isDone()) {
|
||||
int type = iterator.currentSegment(coords);
|
||||
double x = coords[0];
|
||||
double y = coords[1];
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
x = coords[2];
|
||||
y = coords[3];
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
System.out.print("CUBICTO NOT SUPPORTED. ");
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
System.out.print("CLOSE NOT SUPPORTED. ");
|
||||
break;
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), null, 0, 0);
|
||||
cse.export();
|
||||
result.append(cse.getShapeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return shapeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.shapeId = characterId;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.PathExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.LazyObject;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ShapeTag extends DrawableTag implements LazyObject {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int shapeId;
|
||||
|
||||
public RECT shapeBounds;
|
||||
|
||||
public SHAPEWITHSTYLE shapes;
|
||||
|
||||
protected ByteArrayRange shapeData;
|
||||
|
||||
private final int markerSize = 10;
|
||||
|
||||
public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
getShapes();
|
||||
}
|
||||
|
||||
public abstract int getShapeNum();
|
||||
|
||||
public SHAPEWITHSTYLE getShapes() {
|
||||
if (shapes == null && shapeData != null) {
|
||||
try {
|
||||
SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength());
|
||||
sis.seek(shapeData.getPos());
|
||||
shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes");
|
||||
shapeData = null; // not needed anymore, give it to GC
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
SHAPEWITHSTYLE shapes = getShapes();
|
||||
if (shapes != null) {
|
||||
getShapes().getNeededCharacters(needed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = getShapes().removeCharacter(characterId);
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
return transformation.toTransform().createTransformedShape(getShapes().getOutline(swf, stroked));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform);
|
||||
if (Configuration._debugMode.get()) { // show control points
|
||||
List<GeneralPath> paths = PathExporter.export(swf, getShapes());
|
||||
double[] coords = new double[6];
|
||||
AffineTransform at = transformation.toTransform();
|
||||
at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor));
|
||||
|
||||
// get the graphics from the inner image object, because it creates a new Graphics object
|
||||
Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics();
|
||||
graphics.setPaint(Color.black);
|
||||
for (GeneralPath path : paths) {
|
||||
PathIterator iterator = path.getPathIterator(at);
|
||||
while (!iterator.isDone()) {
|
||||
int type = iterator.currentSegment(coords);
|
||||
double x = coords[0];
|
||||
double y = coords[1];
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
x = coords[2];
|
||||
y = coords[3];
|
||||
graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
System.out.print("CUBICTO NOT SUPPORTED. ");
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
System.out.print("CLOSE NOT SUPPORTED. ");
|
||||
break;
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), getCharacterId(), exporter, null, colorTransform, 1);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), null, 0, 0);
|
||||
cse.export();
|
||||
result.append(cse.getShapeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return shapeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.shapeId = characterId;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,386 +1,386 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
|
||||
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.timeline.Frame;
|
||||
import com.jpexs.decompiler.flash.treeitems.TreeItem;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ExportDialog extends AppDialog {
|
||||
|
||||
private int result = ERROR_OPTION;
|
||||
|
||||
String[] optionNames = {
|
||||
TagTreeModel.FOLDER_SHAPES,
|
||||
TagTreeModel.FOLDER_TEXTS,
|
||||
TagTreeModel.FOLDER_IMAGES,
|
||||
TagTreeModel.FOLDER_MOVIES,
|
||||
TagTreeModel.FOLDER_SOUNDS,
|
||||
TagTreeModel.FOLDER_SCRIPTS,
|
||||
TagTreeModel.FOLDER_BINARY_DATA,
|
||||
TagTreeModel.FOLDER_FRAMES,
|
||||
TagTreeModel.FOLDER_SPRITES,
|
||||
TagTreeModel.FOLDER_BUTTONS,
|
||||
TagTreeModel.FOLDER_FONTS,
|
||||
TagTreeModel.FOLDER_MORPHSHAPES,
|
||||
"symbolclass"
|
||||
};
|
||||
|
||||
//Display options only when these classes found
|
||||
Class[][] objClasses = {
|
||||
{ShapeTag.class},
|
||||
{TextTag.class},
|
||||
{ImageTag.class},
|
||||
{DefineVideoStreamTag.class},
|
||||
{SoundTag.class},
|
||||
{ASMSource.class, ScriptPack.class},
|
||||
{DefineBinaryDataTag.class},
|
||||
{Frame.class},
|
||||
{Frame.class},
|
||||
{ButtonTag.class},
|
||||
{FontTag.class},
|
||||
{MorphShapeTag.class},
|
||||
{SymbolClassTypeTag.class},
|
||||
};
|
||||
|
||||
//Enum classes for values
|
||||
Class[] optionClasses = {
|
||||
ShapeExportMode.class,
|
||||
TextExportMode.class,
|
||||
ImageExportMode.class,
|
||||
MovieExportMode.class,
|
||||
SoundExportMode.class,
|
||||
ScriptExportMode.class,
|
||||
BinaryDataExportMode.class,
|
||||
FrameExportMode.class,
|
||||
SpriteExportMode.class,
|
||||
ButtonExportMode.class,
|
||||
FontExportMode.class,
|
||||
MorphShapeExportMode.class,
|
||||
SymbolClassExportMode.class,
|
||||
};
|
||||
|
||||
Class[] zoomClasses = {
|
||||
ShapeExportMode.class,
|
||||
MorphShapeExportMode.class,
|
||||
TextExportMode.class,
|
||||
FrameExportMode.class,
|
||||
SpriteExportMode.class,
|
||||
ButtonExportMode.class,
|
||||
};
|
||||
|
||||
private final JComboBox[] combos;
|
||||
|
||||
private final JCheckBox[] checkBoxes;
|
||||
|
||||
private final JCheckBox selectAllCheckBox;
|
||||
|
||||
private JTextField zoomTextField = new JTextField();
|
||||
|
||||
public <E> E getValue(Class<E> option) {
|
||||
for (int i = 0; i < optionClasses.length; i++) {
|
||||
if (option == optionClasses[i]) {
|
||||
E[] values = option.getEnumConstants();
|
||||
return values[combos[i].getSelectedIndex()];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isOptionEnabled(Class<?> option) {
|
||||
for (int i = 0; i < optionClasses.length; i++) {
|
||||
if (option == optionClasses[i]) {
|
||||
return checkBoxes[i].isSelected();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public double getZoom() {
|
||||
return Double.parseDouble(zoomTextField.getText()) / 100;
|
||||
}
|
||||
|
||||
private void saveConfig() {
|
||||
StringBuilder cfg = new StringBuilder();
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
int selIndex = combos[i].getSelectedIndex();
|
||||
Class c = optionClasses[i];
|
||||
Object[] vals = c.getEnumConstants();
|
||||
String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase();
|
||||
if (i > 0) {
|
||||
cfg.append(",");
|
||||
}
|
||||
cfg.append(key);
|
||||
}
|
||||
|
||||
Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100);
|
||||
Configuration.lastSelectedExportFormats.set(cfg.toString());
|
||||
}
|
||||
|
||||
private boolean optionCanHandle(int optionIndex, Object e) {
|
||||
for (int i = 0; i < objClasses[optionIndex].length; i++) {
|
||||
Class c = objClasses[optionIndex][i];
|
||||
if (c.isInstance(e)) {
|
||||
if (c == Frame.class) { //Frame class can be SWF frame or Sprite frame
|
||||
Frame f = (Frame) e;
|
||||
boolean isSprite = (f.timeline.timelined instanceof DefineSpriteTag);
|
||||
boolean spritesWanted = optionClasses[optionIndex] == SpriteExportMode.class;
|
||||
if (spritesWanted == isSprite) { //both true or both false
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ExportDialog(List<TreeItem> exportables) {
|
||||
setTitle(translate("dialog.title"));
|
||||
setResizable(false);
|
||||
|
||||
Container cnt = getContentPane();
|
||||
cnt.setLayout(new BorderLayout());
|
||||
JPanel comboPanel = new JPanel(null);
|
||||
int labWidth = 0;
|
||||
boolean[] exportableExistsArray = new boolean[optionNames.length];
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
boolean exportableExists = false;
|
||||
if (exportables == null) {
|
||||
exportableExists = true;
|
||||
} else {
|
||||
for (TreeItem e : exportables) {
|
||||
if (optionCanHandle(i, e)) {
|
||||
exportableExists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exportableExists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exportableExistsArray[i] = true;
|
||||
|
||||
JLabel label = new JLabel(translate(optionNames[i]));
|
||||
if (label.getPreferredSize().width > labWidth) {
|
||||
labWidth = label.getPreferredSize().width;
|
||||
}
|
||||
}
|
||||
|
||||
String exportFormatsStr = Configuration.lastSelectedExportFormats.get();
|
||||
if ("".equals(exportFormatsStr)) {
|
||||
exportFormatsStr = null;
|
||||
}
|
||||
|
||||
String[] exportFormatsArr = new String[0];
|
||||
if (exportFormatsStr != null) {
|
||||
if (exportFormatsStr.contains(",")) {
|
||||
exportFormatsArr = exportFormatsStr.split(",");
|
||||
} else {
|
||||
exportFormatsArr = new String[]{exportFormatsStr};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int comboWidth = 200;
|
||||
int checkBoxWidth;
|
||||
int top = 10;
|
||||
|
||||
List<String> exportFormats = Arrays.asList(exportFormatsArr);
|
||||
combos = new JComboBox[optionNames.length];
|
||||
checkBoxes = new JCheckBox[optionNames.length];
|
||||
selectAllCheckBox = new JCheckBox();
|
||||
checkBoxWidth = selectAllCheckBox.getPreferredSize().width;
|
||||
selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height);
|
||||
selectAllCheckBox.setSelected(true);
|
||||
selectAllCheckBox.addActionListener((ActionEvent e) -> {
|
||||
boolean selected = selectAllCheckBox.isSelected();
|
||||
for (JCheckBox checkBox : checkBoxes) {
|
||||
if (checkBox != null) {
|
||||
checkBox.setSelected(selected);
|
||||
}
|
||||
}
|
||||
});
|
||||
comboPanel.add(selectAllCheckBox);
|
||||
top += selectAllCheckBox.getHeight();
|
||||
|
||||
boolean zoomable = false;
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
Class c = optionClasses[i];
|
||||
Object[] vals = c.getEnumConstants();
|
||||
String[] names = new String[vals.length];
|
||||
int itemIndex = -1;
|
||||
for (int j = 0; j < vals.length; j++) {
|
||||
|
||||
String key = optionNames[i] + "." + vals[j].toString().toLowerCase();
|
||||
if (exportFormats.contains(key)) {
|
||||
itemIndex = j;
|
||||
}
|
||||
names[j] = translate(key);
|
||||
}
|
||||
|
||||
combos[i] = new JComboBox<>(names);
|
||||
if (itemIndex > -1) {
|
||||
combos[i].setSelectedIndex(itemIndex);
|
||||
}
|
||||
|
||||
combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height);
|
||||
|
||||
checkBoxes[i] = new JCheckBox();
|
||||
checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height);
|
||||
checkBoxes[i].setSelected(true);
|
||||
|
||||
if (!exportableExistsArray[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Arrays.asList(zoomClasses).contains(c)) {
|
||||
zoomable = true;
|
||||
}
|
||||
|
||||
JLabel lab = new JLabel(translate(optionNames[i]));
|
||||
lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height);
|
||||
comboPanel.add(lab);
|
||||
comboPanel.add(checkBoxes[i]);
|
||||
comboPanel.add(combos[i]);
|
||||
top += combos[i].getHeight();
|
||||
}
|
||||
|
||||
int zoomWidth = 50;
|
||||
if (zoomable) {
|
||||
top += 2;
|
||||
JLabel zlab = new JLabel(translate("zoom"));
|
||||
zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height);
|
||||
zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height);
|
||||
JLabel pctLabel = new JLabel(translate("zoom.percent"));
|
||||
pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height);
|
||||
|
||||
comboPanel.add(zlab);
|
||||
comboPanel.add(zoomTextField);
|
||||
comboPanel.add(pctLabel);
|
||||
top += zoomTextField.getHeight();
|
||||
}
|
||||
|
||||
Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10);
|
||||
comboPanel.setMinimumSize(dim);
|
||||
comboPanel.setPreferredSize(dim);
|
||||
cnt.add(comboPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonsPanel = new JPanel(new FlowLayout());
|
||||
JButton okButton = new JButton(translate("button.ok"));
|
||||
okButton.addActionListener(this::okButtonActionPerformed);
|
||||
|
||||
JButton cancelButton = new JButton(translate("button.cancel"));
|
||||
cancelButton.addActionListener(this::cancelButtonActionPerformed);
|
||||
|
||||
buttonsPanel.add(okButton);
|
||||
buttonsPanel.add(cancelButton);
|
||||
|
||||
cnt.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
pack();
|
||||
View.centerScreen(this);
|
||||
View.setWindowIcon(this);
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
setModal(true);
|
||||
String pct = "" + Configuration.lastSelectedExportZoom.get() * 100;
|
||||
if (pct.endsWith(".0")) {
|
||||
pct = pct.substring(0, pct.length() - 2);
|
||||
}
|
||||
|
||||
zoomTextField.setText(pct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
if (b) {
|
||||
result = ERROR_OPTION;
|
||||
}
|
||||
super.setVisible(b);
|
||||
}
|
||||
|
||||
private void okButtonActionPerformed(ActionEvent evt) {
|
||||
result = OK_OPTION;
|
||||
try {
|
||||
saveConfig();
|
||||
} catch (NumberFormatException nfe) {
|
||||
JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
zoomTextField.requestFocusInWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
private void cancelButtonActionPerformed(ActionEvent evt) {
|
||||
result = CANCEL_OPTION;
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public int showExportDialog() {
|
||||
setVisible(true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
|
||||
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.timeline.Frame;
|
||||
import com.jpexs.decompiler.flash.treeitems.TreeItem;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ExportDialog extends AppDialog {
|
||||
|
||||
private int result = ERROR_OPTION;
|
||||
|
||||
String[] optionNames = {
|
||||
TagTreeModel.FOLDER_SHAPES,
|
||||
TagTreeModel.FOLDER_TEXTS,
|
||||
TagTreeModel.FOLDER_IMAGES,
|
||||
TagTreeModel.FOLDER_MOVIES,
|
||||
TagTreeModel.FOLDER_SOUNDS,
|
||||
TagTreeModel.FOLDER_SCRIPTS,
|
||||
TagTreeModel.FOLDER_BINARY_DATA,
|
||||
TagTreeModel.FOLDER_FRAMES,
|
||||
TagTreeModel.FOLDER_SPRITES,
|
||||
TagTreeModel.FOLDER_BUTTONS,
|
||||
TagTreeModel.FOLDER_FONTS,
|
||||
TagTreeModel.FOLDER_MORPHSHAPES,
|
||||
"symbolclass"
|
||||
};
|
||||
|
||||
//Display options only when these classes found
|
||||
Class[][] objClasses = {
|
||||
{ShapeTag.class},
|
||||
{TextTag.class},
|
||||
{ImageTag.class},
|
||||
{DefineVideoStreamTag.class},
|
||||
{SoundTag.class},
|
||||
{ASMSource.class, ScriptPack.class},
|
||||
{DefineBinaryDataTag.class},
|
||||
{Frame.class},
|
||||
{Frame.class},
|
||||
{ButtonTag.class},
|
||||
{FontTag.class},
|
||||
{MorphShapeTag.class},
|
||||
{SymbolClassTypeTag.class},
|
||||
};
|
||||
|
||||
//Enum classes for values
|
||||
Class[] optionClasses = {
|
||||
ShapeExportMode.class,
|
||||
TextExportMode.class,
|
||||
ImageExportMode.class,
|
||||
MovieExportMode.class,
|
||||
SoundExportMode.class,
|
||||
ScriptExportMode.class,
|
||||
BinaryDataExportMode.class,
|
||||
FrameExportMode.class,
|
||||
SpriteExportMode.class,
|
||||
ButtonExportMode.class,
|
||||
FontExportMode.class,
|
||||
MorphShapeExportMode.class,
|
||||
SymbolClassExportMode.class,
|
||||
};
|
||||
|
||||
Class[] zoomClasses = {
|
||||
ShapeExportMode.class,
|
||||
MorphShapeExportMode.class,
|
||||
TextExportMode.class,
|
||||
FrameExportMode.class,
|
||||
SpriteExportMode.class,
|
||||
ButtonExportMode.class,
|
||||
};
|
||||
|
||||
private final JComboBox[] combos;
|
||||
|
||||
private final JCheckBox[] checkBoxes;
|
||||
|
||||
private final JCheckBox selectAllCheckBox;
|
||||
|
||||
private JTextField zoomTextField = new JTextField();
|
||||
|
||||
public <E> E getValue(Class<E> option) {
|
||||
for (int i = 0; i < optionClasses.length; i++) {
|
||||
if (option == optionClasses[i]) {
|
||||
E[] values = option.getEnumConstants();
|
||||
return values[combos[i].getSelectedIndex()];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isOptionEnabled(Class<?> option) {
|
||||
for (int i = 0; i < optionClasses.length; i++) {
|
||||
if (option == optionClasses[i]) {
|
||||
return checkBoxes[i].isSelected();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public double getZoom() {
|
||||
return Double.parseDouble(zoomTextField.getText()) / 100;
|
||||
}
|
||||
|
||||
private void saveConfig() {
|
||||
StringBuilder cfg = new StringBuilder();
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
int selIndex = combos[i].getSelectedIndex();
|
||||
Class c = optionClasses[i];
|
||||
Object[] vals = c.getEnumConstants();
|
||||
String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase();
|
||||
if (i > 0) {
|
||||
cfg.append(",");
|
||||
}
|
||||
cfg.append(key);
|
||||
}
|
||||
|
||||
Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100);
|
||||
Configuration.lastSelectedExportFormats.set(cfg.toString());
|
||||
}
|
||||
|
||||
private boolean optionCanHandle(int optionIndex, Object e) {
|
||||
for (int i = 0; i < objClasses[optionIndex].length; i++) {
|
||||
Class c = objClasses[optionIndex][i];
|
||||
if (c.isInstance(e)) {
|
||||
if (c == Frame.class) { //Frame class can be SWF frame or Sprite frame
|
||||
Frame f = (Frame) e;
|
||||
boolean isSprite = (f.timeline.timelined instanceof DefineSpriteTag);
|
||||
boolean spritesWanted = optionClasses[optionIndex] == SpriteExportMode.class;
|
||||
if (spritesWanted == isSprite) { //both true or both false
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ExportDialog(List<TreeItem> exportables) {
|
||||
setTitle(translate("dialog.title"));
|
||||
setResizable(false);
|
||||
|
||||
Container cnt = getContentPane();
|
||||
cnt.setLayout(new BorderLayout());
|
||||
JPanel comboPanel = new JPanel(null);
|
||||
int labWidth = 0;
|
||||
boolean[] exportableExistsArray = new boolean[optionNames.length];
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
boolean exportableExists = false;
|
||||
if (exportables == null) {
|
||||
exportableExists = true;
|
||||
} else {
|
||||
for (TreeItem e : exportables) {
|
||||
if (optionCanHandle(i, e)) {
|
||||
exportableExists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exportableExists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exportableExistsArray[i] = true;
|
||||
|
||||
JLabel label = new JLabel(translate(optionNames[i]));
|
||||
if (label.getPreferredSize().width > labWidth) {
|
||||
labWidth = label.getPreferredSize().width;
|
||||
}
|
||||
}
|
||||
|
||||
String exportFormatsStr = Configuration.lastSelectedExportFormats.get();
|
||||
if ("".equals(exportFormatsStr)) {
|
||||
exportFormatsStr = null;
|
||||
}
|
||||
|
||||
String[] exportFormatsArr = new String[0];
|
||||
if (exportFormatsStr != null) {
|
||||
if (exportFormatsStr.contains(",")) {
|
||||
exportFormatsArr = exportFormatsStr.split(",");
|
||||
} else {
|
||||
exportFormatsArr = new String[]{exportFormatsStr};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int comboWidth = 200;
|
||||
int checkBoxWidth;
|
||||
int top = 10;
|
||||
|
||||
List<String> exportFormats = Arrays.asList(exportFormatsArr);
|
||||
combos = new JComboBox[optionNames.length];
|
||||
checkBoxes = new JCheckBox[optionNames.length];
|
||||
selectAllCheckBox = new JCheckBox();
|
||||
checkBoxWidth = selectAllCheckBox.getPreferredSize().width;
|
||||
selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height);
|
||||
selectAllCheckBox.setSelected(true);
|
||||
selectAllCheckBox.addActionListener((ActionEvent e) -> {
|
||||
boolean selected = selectAllCheckBox.isSelected();
|
||||
for (JCheckBox checkBox : checkBoxes) {
|
||||
if (checkBox != null) {
|
||||
checkBox.setSelected(selected);
|
||||
}
|
||||
}
|
||||
});
|
||||
comboPanel.add(selectAllCheckBox);
|
||||
top += selectAllCheckBox.getHeight();
|
||||
|
||||
boolean zoomable = false;
|
||||
for (int i = 0; i < optionNames.length; i++) {
|
||||
Class c = optionClasses[i];
|
||||
Object[] vals = c.getEnumConstants();
|
||||
String[] names = new String[vals.length];
|
||||
int itemIndex = -1;
|
||||
for (int j = 0; j < vals.length; j++) {
|
||||
|
||||
String key = optionNames[i] + "." + vals[j].toString().toLowerCase();
|
||||
if (exportFormats.contains(key)) {
|
||||
itemIndex = j;
|
||||
}
|
||||
names[j] = translate(key);
|
||||
}
|
||||
|
||||
combos[i] = new JComboBox<>(names);
|
||||
if (itemIndex > -1) {
|
||||
combos[i].setSelectedIndex(itemIndex);
|
||||
}
|
||||
|
||||
combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height);
|
||||
|
||||
checkBoxes[i] = new JCheckBox();
|
||||
checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height);
|
||||
checkBoxes[i].setSelected(true);
|
||||
|
||||
if (!exportableExistsArray[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Arrays.asList(zoomClasses).contains(c)) {
|
||||
zoomable = true;
|
||||
}
|
||||
|
||||
JLabel lab = new JLabel(translate(optionNames[i]));
|
||||
lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height);
|
||||
comboPanel.add(lab);
|
||||
comboPanel.add(checkBoxes[i]);
|
||||
comboPanel.add(combos[i]);
|
||||
top += combos[i].getHeight();
|
||||
}
|
||||
|
||||
int zoomWidth = 50;
|
||||
if (zoomable) {
|
||||
top += 2;
|
||||
JLabel zlab = new JLabel(translate("zoom"));
|
||||
zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height);
|
||||
zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height);
|
||||
JLabel pctLabel = new JLabel(translate("zoom.percent"));
|
||||
pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height);
|
||||
|
||||
comboPanel.add(zlab);
|
||||
comboPanel.add(zoomTextField);
|
||||
comboPanel.add(pctLabel);
|
||||
top += zoomTextField.getHeight();
|
||||
}
|
||||
|
||||
Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10);
|
||||
comboPanel.setMinimumSize(dim);
|
||||
comboPanel.setPreferredSize(dim);
|
||||
cnt.add(comboPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonsPanel = new JPanel(new FlowLayout());
|
||||
JButton okButton = new JButton(translate("button.ok"));
|
||||
okButton.addActionListener(this::okButtonActionPerformed);
|
||||
|
||||
JButton cancelButton = new JButton(translate("button.cancel"));
|
||||
cancelButton.addActionListener(this::cancelButtonActionPerformed);
|
||||
|
||||
buttonsPanel.add(okButton);
|
||||
buttonsPanel.add(cancelButton);
|
||||
|
||||
cnt.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
pack();
|
||||
View.centerScreen(this);
|
||||
View.setWindowIcon(this);
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
setModal(true);
|
||||
String pct = "" + Configuration.lastSelectedExportZoom.get() * 100;
|
||||
if (pct.endsWith(".0")) {
|
||||
pct = pct.substring(0, pct.length() - 2);
|
||||
}
|
||||
|
||||
zoomTextField.setText(pct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
if (b) {
|
||||
result = ERROR_OPTION;
|
||||
}
|
||||
super.setVisible(b);
|
||||
}
|
||||
|
||||
private void okButtonActionPerformed(ActionEvent evt) {
|
||||
result = OK_OPTION;
|
||||
try {
|
||||
saveConfig();
|
||||
} catch (NumberFormatException nfe) {
|
||||
JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
zoomTextField.requestFocusInWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
private void cancelButtonActionPerformed(ActionEvent evt) {
|
||||
result = CANCEL_OPTION;
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public int showExportDialog() {
|
||||
setVisible(true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,137 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitType;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.search.ABCSearchResult;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TraitsListItem {
|
||||
|
||||
private final TraitType type;
|
||||
|
||||
private final boolean isStatic;
|
||||
|
||||
private final ABC abc;
|
||||
|
||||
private final int classIndex;
|
||||
|
||||
private final int index;
|
||||
|
||||
private final int scriptIndex;
|
||||
|
||||
public static String STR_INSTANCE_INITIALIZER = ABCSearchResult.STR_INSTANCE_INITIALIZER;
|
||||
|
||||
public static String STR_CLASS_INITIALIZER = ABCSearchResult.STR_CLASS_INITIALIZER;
|
||||
|
||||
public static String STR_SCRIPT_INITIALIZER = ABCSearchResult.STR_SCRIPT_INITIALIZER;
|
||||
|
||||
public TraitsListItem(TraitType type, int index, boolean isStatic, ABC abc, int classIndex, int scriptIndex) {
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
this.isStatic = isStatic;
|
||||
this.abc = abc;
|
||||
this.classIndex = classIndex;
|
||||
this.scriptIndex = scriptIndex;
|
||||
}
|
||||
|
||||
public int getGlobalTraitId() {
|
||||
return abc.getGlobalTraitId(type, isStatic, classIndex, index);
|
||||
}
|
||||
|
||||
public String toStringName() {
|
||||
|
||||
if (type == TraitType.INITIALIZER) {
|
||||
if (!isStatic) {
|
||||
return "__" + STR_INSTANCE_INITIALIZER;
|
||||
} else {
|
||||
return "__" + STR_CLASS_INITIALIZER;
|
||||
}
|
||||
}
|
||||
if (type == TraitType.SCRIPT_INITIALIZER) {
|
||||
return "__" + STR_SCRIPT_INITIALIZER;
|
||||
}
|
||||
if (isStatic) {
|
||||
return abc.class_info.get(classIndex).static_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true);
|
||||
} else {
|
||||
return abc.instance_info.get(classIndex).instance_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = "";
|
||||
try {
|
||||
if (type == TraitType.SCRIPT_INITIALIZER) {
|
||||
s = STR_SCRIPT_INITIALIZER;
|
||||
} else if (type == TraitType.INITIALIZER) {
|
||||
if (!isStatic) {
|
||||
s = STR_INSTANCE_INITIALIZER;
|
||||
} else {
|
||||
s = STR_CLASS_INITIALIZER;
|
||||
}
|
||||
} else if (isStatic) {
|
||||
ConvertData convertData = new ConvertData();
|
||||
Trait trait = abc.class_info.get(classIndex).static_traits.traits.get(index);
|
||||
trait.convertHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
|
||||
trait.toStringHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false);
|
||||
s = writer.toString();
|
||||
} else {
|
||||
ConvertData convertData = new ConvertData();
|
||||
Trait trait = abc.instance_info.get(classIndex).instance_traits.traits.get(index);
|
||||
trait.convertHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
|
||||
trait.toStringHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false);
|
||||
s = writer.toString();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(TraitsListItem.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
s = s.replaceAll("[ \r\n]+", " ");
|
||||
return s;
|
||||
}
|
||||
|
||||
public TraitType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isStatic() {
|
||||
return isStatic;
|
||||
}
|
||||
|
||||
public int getClassIndex() {
|
||||
return classIndex;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitType;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.search.ABCSearchResult;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TraitsListItem {
|
||||
|
||||
private final TraitType type;
|
||||
|
||||
private final boolean isStatic;
|
||||
|
||||
private final ABC abc;
|
||||
|
||||
private final int classIndex;
|
||||
|
||||
private final int index;
|
||||
|
||||
private final int scriptIndex;
|
||||
|
||||
public static String STR_INSTANCE_INITIALIZER = ABCSearchResult.STR_INSTANCE_INITIALIZER;
|
||||
|
||||
public static String STR_CLASS_INITIALIZER = ABCSearchResult.STR_CLASS_INITIALIZER;
|
||||
|
||||
public static String STR_SCRIPT_INITIALIZER = ABCSearchResult.STR_SCRIPT_INITIALIZER;
|
||||
|
||||
public TraitsListItem(TraitType type, int index, boolean isStatic, ABC abc, int classIndex, int scriptIndex) {
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
this.isStatic = isStatic;
|
||||
this.abc = abc;
|
||||
this.classIndex = classIndex;
|
||||
this.scriptIndex = scriptIndex;
|
||||
}
|
||||
|
||||
public int getGlobalTraitId() {
|
||||
return abc.getGlobalTraitId(type, isStatic, classIndex, index);
|
||||
}
|
||||
|
||||
public String toStringName() {
|
||||
|
||||
if (type == TraitType.INITIALIZER) {
|
||||
if (!isStatic) {
|
||||
return "__" + STR_INSTANCE_INITIALIZER;
|
||||
} else {
|
||||
return "__" + STR_CLASS_INITIALIZER;
|
||||
}
|
||||
}
|
||||
if (type == TraitType.SCRIPT_INITIALIZER) {
|
||||
return "__" + STR_SCRIPT_INITIALIZER;
|
||||
}
|
||||
if (isStatic) {
|
||||
return abc.class_info.get(classIndex).static_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true);
|
||||
} else {
|
||||
return abc.instance_info.get(classIndex).instance_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = "";
|
||||
try {
|
||||
if (type == TraitType.SCRIPT_INITIALIZER) {
|
||||
s = STR_SCRIPT_INITIALIZER;
|
||||
} else if (type == TraitType.INITIALIZER) {
|
||||
if (!isStatic) {
|
||||
s = STR_INSTANCE_INITIALIZER;
|
||||
} else {
|
||||
s = STR_CLASS_INITIALIZER;
|
||||
}
|
||||
} else if (isStatic) {
|
||||
ConvertData convertData = new ConvertData();
|
||||
Trait trait = abc.class_info.get(classIndex).static_traits.traits.get(index);
|
||||
trait.convertHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
|
||||
trait.toStringHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false);
|
||||
s = writer.toString();
|
||||
} else {
|
||||
ConvertData convertData = new ConvertData();
|
||||
Trait trait = abc.instance_info.get(classIndex).instance_traits.traits.get(index);
|
||||
trait.convertHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
|
||||
trait.toStringHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false);
|
||||
s = writer.toString();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(TraitsListItem.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
s = s.replaceAll("[ \r\n]+", " ");
|
||||
return s;
|
||||
}
|
||||
|
||||
public TraitType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isStatic() {
|
||||
return isStatic;
|
||||
}
|
||||
|
||||
public int getClassIndex() {
|
||||
return classIndex;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,438 +1,438 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.player;
|
||||
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.gui.FlashUnsupportedException;
|
||||
import com.jpexs.decompiler.flash.gui.Main;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.javactivex.ActiveX;
|
||||
import com.jpexs.javactivex.ActiveXEvent;
|
||||
import com.jpexs.javactivex.ActiveXException;
|
||||
import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash;
|
||||
import com.sun.jna.Platform;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public final class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FlashPlayerPanel.class.getName());
|
||||
|
||||
private final int setMovieDelay = Configuration.setMovieDelay.get();
|
||||
|
||||
private final List<MediaDisplayListener> listeners = new ArrayList<>();
|
||||
|
||||
private final ShockwaveFlash flash;
|
||||
|
||||
private final Timer timer;
|
||||
|
||||
private boolean stopped = true;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
private float frameRate;
|
||||
|
||||
@Override
|
||||
public boolean loopAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean screenAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoomAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getZoomToFit() {
|
||||
//TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Zoom getZoom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private double zoom = 1.0;
|
||||
|
||||
@Override
|
||||
public synchronized void zoom(Zoom zoom) {
|
||||
double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value;
|
||||
int zoomint = (int) Math.round(100 / (zoomDouble / this.zoom));
|
||||
if (zoomint == 0) {
|
||||
zoomint = 1;
|
||||
}
|
||||
if (zoomint > 32767) {
|
||||
zoomint = 32767;
|
||||
}
|
||||
if (zoomint == 100) {
|
||||
zoomint = 0;
|
||||
}
|
||||
|
||||
flash.Zoom(0); // hack, but this call is needed otherwise unzoom will fail for larger zoom values
|
||||
flash.Zoom(zoomint);
|
||||
}
|
||||
|
||||
public synchronized String getVariable(String name) throws IOException {
|
||||
return flash.GetVariable(name);
|
||||
}
|
||||
|
||||
public synchronized void setVariable(String name, String value) throws IOException {
|
||||
flash.SetVariable(name, value);
|
||||
}
|
||||
|
||||
public synchronized String call(String callString) throws IOException {
|
||||
|
||||
return flash.CallFunction(callString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getCurrentFrame() {
|
||||
if (flash == null) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return flash.getFrameNum();
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getTotalFrames() {
|
||||
if (flash == null) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
if (flash.getReadyState() == 4) {
|
||||
return flash.getTotalFrames();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBackground(Color color) {
|
||||
try {
|
||||
flash.setBackgroundColor((color.getRed() << 16) + (color.getGreen() << 8) + color.getBlue());
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
public FlashPlayerPanel(Component frame) {
|
||||
if (!Platform.isWindows()) {
|
||||
throw new FlashUnsupportedException();
|
||||
}
|
||||
|
||||
try {
|
||||
Callable<ShockwaveFlash> callable = new Callable<ShockwaveFlash>() {
|
||||
@Override
|
||||
public ShockwaveFlash call() throws InterruptedException {
|
||||
return ActiveX.createObject(ShockwaveFlash.class, FlashPlayerPanel.this);
|
||||
}
|
||||
};
|
||||
|
||||
// hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in ActiveXControl static constructor
|
||||
flash = CancellableWorker.call(callable, 5, TimeUnit.SECONDS);
|
||||
} catch (ActiveXException | TimeoutException | InterruptedException | ExecutionException ex) {
|
||||
logger.log(Level.WARNING, "Cannot initialize flash panel", ex);
|
||||
throw new FlashUnsupportedException();
|
||||
}
|
||||
|
||||
flash.setAllowScriptAccess("always");
|
||||
try {
|
||||
flash.setAllowNetworking("all");
|
||||
} catch (ActiveXException ex) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
flash.addOnReadyStateChangeListener((ActiveXEvent axe) -> {
|
||||
fireMediaDisplayStateChanged();
|
||||
});
|
||||
|
||||
flash.addFlashCallListener((ActiveXEvent axe) -> {
|
||||
String req = (String) axe.args.get("request");
|
||||
Matcher m = Pattern.compile("<invoke name=\"([^\"]+)\" returntype=\"xml\"><arguments><string>(.*)</string></arguments></invoke>").matcher(req);
|
||||
if (m.matches()) {
|
||||
String funname = m.group(1);
|
||||
String msg = m.group(2);
|
||||
if (funname.equals("alert") || funname.equals("console.log")) {
|
||||
if (Main.debugDialog != null) {
|
||||
Main.debugDialog.log(funname + ":" + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
private boolean isPlaying = false;
|
||||
|
||||
private int currentFrame = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ShockwaveFlash flash1 = flash;
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
if (flash1.getReadyState() >= 3) {
|
||||
boolean isPlaying = flash1.IsPlaying();
|
||||
if (this.isPlaying != isPlaying) {
|
||||
this.isPlaying = isPlaying;
|
||||
}
|
||||
|
||||
int currentFrame = flash1.CurrentFrame();
|
||||
if (this.currentFrame != currentFrame) {
|
||||
this.currentFrame = currentFrame;
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}, 100, 100);
|
||||
}
|
||||
|
||||
public synchronized void stopSWF() {
|
||||
displaySWF("-", null, 1);
|
||||
stopped = true;
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
|
||||
public synchronized boolean isStopped() {
|
||||
return stopped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage printScreen() {
|
||||
Point screenloc = getLocationOnScreen();
|
||||
try {
|
||||
return new Robot().createScreenCapture(new Rectangle(screenloc.x, screenloc.y, getWidth(), getHeight()));
|
||||
} catch (AWTException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String movieToPlay = null;
|
||||
|
||||
private Thread playQueue;
|
||||
|
||||
private final Object queueLock = new Object();
|
||||
|
||||
public synchronized void displaySWF(final String flashName, final Color bgColor, final float frameRate) {
|
||||
|
||||
// Minimum of 1000 ms (setMovieDelay) delay before calling flash.setMovie to avoid illegalAccess errors
|
||||
if (playQueue == null) {
|
||||
playQueue = new Thread() {
|
||||
long lastTime;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
boolean empty;
|
||||
synchronized (queueLock) {
|
||||
empty = movieToPlay == null;
|
||||
if (empty) {
|
||||
try {
|
||||
queueLock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty) {
|
||||
flash.setMovie(movieToPlay);
|
||||
synchronized (queueLock) {
|
||||
movieToPlay = null;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(setMovieDelay);
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
playQueue.start();
|
||||
}
|
||||
zoom = 1.0;
|
||||
this.frameRate = frameRate;
|
||||
if (bgColor != null) {
|
||||
setBackground(bgColor);
|
||||
}
|
||||
synchronized (queueLock) {
|
||||
movieToPlay = flashName;
|
||||
queueLock.notify();
|
||||
}
|
||||
|
||||
//play
|
||||
stopped = false;
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
timer.cancel();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Stop();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Stop();
|
||||
flash.Rewind();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Rewind();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Play();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlaying() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
return flash.IsPlaying();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoop(boolean loop
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gotoFrame(int frame
|
||||
) {
|
||||
if (frame < 0) {
|
||||
return;
|
||||
}
|
||||
if (frame >= getTotalFrames()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.GotoFrame(frame);
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFrameRate() {
|
||||
return frameRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return !isStopped();
|
||||
}
|
||||
|
||||
public void fireMediaDisplayStateChanged() {
|
||||
for (MediaDisplayListener l : listeners) {
|
||||
l.mediaDisplayStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventListener(MediaDisplayListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventListener(MediaDisplayListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui.player;
|
||||
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.gui.FlashUnsupportedException;
|
||||
import com.jpexs.decompiler.flash.gui.Main;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.javactivex.ActiveX;
|
||||
import com.jpexs.javactivex.ActiveXEvent;
|
||||
import com.jpexs.javactivex.ActiveXException;
|
||||
import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash;
|
||||
import com.sun.jna.Platform;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public final class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FlashPlayerPanel.class.getName());
|
||||
|
||||
private final int setMovieDelay = Configuration.setMovieDelay.get();
|
||||
|
||||
private final List<MediaDisplayListener> listeners = new ArrayList<>();
|
||||
|
||||
private final ShockwaveFlash flash;
|
||||
|
||||
private final Timer timer;
|
||||
|
||||
private boolean stopped = true;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
private float frameRate;
|
||||
|
||||
@Override
|
||||
public boolean loopAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean screenAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoomAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getZoomToFit() {
|
||||
//TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Zoom getZoom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private double zoom = 1.0;
|
||||
|
||||
@Override
|
||||
public synchronized void zoom(Zoom zoom) {
|
||||
double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value;
|
||||
int zoomint = (int) Math.round(100 / (zoomDouble / this.zoom));
|
||||
if (zoomint == 0) {
|
||||
zoomint = 1;
|
||||
}
|
||||
if (zoomint > 32767) {
|
||||
zoomint = 32767;
|
||||
}
|
||||
if (zoomint == 100) {
|
||||
zoomint = 0;
|
||||
}
|
||||
|
||||
flash.Zoom(0); // hack, but this call is needed otherwise unzoom will fail for larger zoom values
|
||||
flash.Zoom(zoomint);
|
||||
}
|
||||
|
||||
public synchronized String getVariable(String name) throws IOException {
|
||||
return flash.GetVariable(name);
|
||||
}
|
||||
|
||||
public synchronized void setVariable(String name, String value) throws IOException {
|
||||
flash.SetVariable(name, value);
|
||||
}
|
||||
|
||||
public synchronized String call(String callString) throws IOException {
|
||||
|
||||
return flash.CallFunction(callString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getCurrentFrame() {
|
||||
if (flash == null) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return flash.getFrameNum();
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getTotalFrames() {
|
||||
if (flash == null) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
if (flash.getReadyState() == 4) {
|
||||
return flash.getTotalFrames();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBackground(Color color) {
|
||||
try {
|
||||
flash.setBackgroundColor((color.getRed() << 16) + (color.getGreen() << 8) + color.getBlue());
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
public FlashPlayerPanel(Component frame) {
|
||||
if (!Platform.isWindows()) {
|
||||
throw new FlashUnsupportedException();
|
||||
}
|
||||
|
||||
try {
|
||||
Callable<ShockwaveFlash> callable = new Callable<ShockwaveFlash>() {
|
||||
@Override
|
||||
public ShockwaveFlash call() throws InterruptedException {
|
||||
return ActiveX.createObject(ShockwaveFlash.class, FlashPlayerPanel.this);
|
||||
}
|
||||
};
|
||||
|
||||
// hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in ActiveXControl static constructor
|
||||
flash = CancellableWorker.call(callable, 5, TimeUnit.SECONDS);
|
||||
} catch (ActiveXException | TimeoutException | InterruptedException | ExecutionException ex) {
|
||||
logger.log(Level.WARNING, "Cannot initialize flash panel", ex);
|
||||
throw new FlashUnsupportedException();
|
||||
}
|
||||
|
||||
flash.setAllowScriptAccess("always");
|
||||
try {
|
||||
flash.setAllowNetworking("all");
|
||||
} catch (ActiveXException ex) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
flash.addOnReadyStateChangeListener((ActiveXEvent axe) -> {
|
||||
fireMediaDisplayStateChanged();
|
||||
});
|
||||
|
||||
flash.addFlashCallListener((ActiveXEvent axe) -> {
|
||||
String req = (String) axe.args.get("request");
|
||||
Matcher m = Pattern.compile("<invoke name=\"([^\"]+)\" returntype=\"xml\"><arguments><string>(.*)</string></arguments></invoke>").matcher(req);
|
||||
if (m.matches()) {
|
||||
String funname = m.group(1);
|
||||
String msg = m.group(2);
|
||||
if (funname.equals("alert") || funname.equals("console.log")) {
|
||||
if (Main.debugDialog != null) {
|
||||
Main.debugDialog.log(funname + ":" + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
private boolean isPlaying = false;
|
||||
|
||||
private int currentFrame = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ShockwaveFlash flash1 = flash;
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
if (flash1.getReadyState() >= 3) {
|
||||
boolean isPlaying = flash1.IsPlaying();
|
||||
if (this.isPlaying != isPlaying) {
|
||||
this.isPlaying = isPlaying;
|
||||
}
|
||||
|
||||
int currentFrame = flash1.CurrentFrame();
|
||||
if (this.currentFrame != currentFrame) {
|
||||
this.currentFrame = currentFrame;
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}, 100, 100);
|
||||
}
|
||||
|
||||
public synchronized void stopSWF() {
|
||||
displaySWF("-", null, 1);
|
||||
stopped = true;
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
|
||||
public synchronized boolean isStopped() {
|
||||
return stopped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage printScreen() {
|
||||
Point screenloc = getLocationOnScreen();
|
||||
try {
|
||||
return new Robot().createScreenCapture(new Rectangle(screenloc.x, screenloc.y, getWidth(), getHeight()));
|
||||
} catch (AWTException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String movieToPlay = null;
|
||||
|
||||
private Thread playQueue;
|
||||
|
||||
private final Object queueLock = new Object();
|
||||
|
||||
public synchronized void displaySWF(final String flashName, final Color bgColor, final float frameRate) {
|
||||
|
||||
// Minimum of 1000 ms (setMovieDelay) delay before calling flash.setMovie to avoid illegalAccess errors
|
||||
if (playQueue == null) {
|
||||
playQueue = new Thread() {
|
||||
long lastTime;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
boolean empty;
|
||||
synchronized (queueLock) {
|
||||
empty = movieToPlay == null;
|
||||
if (empty) {
|
||||
try {
|
||||
queueLock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty) {
|
||||
flash.setMovie(movieToPlay);
|
||||
synchronized (queueLock) {
|
||||
movieToPlay = null;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(setMovieDelay);
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
playQueue.start();
|
||||
}
|
||||
zoom = 1.0;
|
||||
this.frameRate = frameRate;
|
||||
if (bgColor != null) {
|
||||
setBackground(bgColor);
|
||||
}
|
||||
synchronized (queueLock) {
|
||||
movieToPlay = flashName;
|
||||
queueLock.notify();
|
||||
}
|
||||
|
||||
//play
|
||||
stopped = false;
|
||||
fireMediaDisplayStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
timer.cancel();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Stop();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Stop();
|
||||
flash.Rewind();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Rewind();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.Play();
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlaying() {
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
return flash.IsPlaying();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoop(boolean loop
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gotoFrame(int frame
|
||||
) {
|
||||
if (frame < 0) {
|
||||
return;
|
||||
}
|
||||
if (frame >= getTotalFrames()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (flash.getReadyState() >= 3) {
|
||||
flash.GotoFrame(frame);
|
||||
}
|
||||
} catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception"
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFrameRate() {
|
||||
return frameRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return !isStopped();
|
||||
}
|
||||
|
||||
public void fireMediaDisplayStateChanged() {
|
||||
for (MediaDisplayListener l : listeners) {
|
||||
l.mediaDisplayStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventListener(MediaDisplayListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventListener(MediaDisplayListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user