mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-26 19:50:54 +00:00
Morphashape replacing - correct bitmap handling
SVG import - duplicated image on bitmap fill style
This commit is contained in:
+24
-6
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.importers.morphshape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.math.BezierEdge;
|
||||
import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
|
||||
@@ -46,6 +47,9 @@ import java.util.Set;
|
||||
public class MorphShapeGenerator {
|
||||
|
||||
public void generate(DefineMorphShape2Tag morphShape, ShapeTag startShape, ShapeTag endShape) throws StyleMismatchException {
|
||||
|
||||
SWF swf = morphShape.getSwf();
|
||||
|
||||
ShapeForMorphExporter startExport = new ShapeForMorphExporter(startShape);
|
||||
startExport.export();
|
||||
ShapeForMorphExporter endExport = new ShapeForMorphExporter(endShape);
|
||||
@@ -86,11 +90,11 @@ public class MorphShapeGenerator {
|
||||
if (((endFillStyle == null && startFillStyle == null)
|
||||
|| (startFillStyle != null
|
||||
&& endFillStyle != null
|
||||
&& startFillStyle.isCompatibleFillStyle(endFillStyle)))
|
||||
&& startFillStyle.isCompatibleFillStyle(endFillStyle, swf)))
|
||||
&& ((endLineStyle == null && startLineStyle == null)
|
||||
|| (startLineStyle != null
|
||||
&& endLineStyle != null
|
||||
&& startLineStyle.isCompatibleLineStyle(endLineStyle)))) {
|
||||
&& startLineStyle.isCompatibleLineStyle(endLineStyle, swf)))) {
|
||||
double distance = startExport.centralPos.get(a).distance(endExport.centralPos.get(b));
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
@@ -135,11 +139,11 @@ public class MorphShapeGenerator {
|
||||
if (((endFillStyle == null && startFillStyle == null)
|
||||
|| (startFillStyle != null
|
||||
&& endFillStyle != null
|
||||
&& startFillStyle.isCompatibleFillStyle(endFillStyle)))
|
||||
&& startFillStyle.isCompatibleFillStyle(endFillStyle, swf)))
|
||||
&& ((endLineStyle == null && startLineStyle == null)
|
||||
|| (startLineStyle != null
|
||||
&& endLineStyle != null
|
||||
&& startLineStyle.isCompatibleLineStyle(endLineStyle)))) {
|
||||
&& startLineStyle.isCompatibleLineStyle(endLineStyle, swf)))) {
|
||||
double distance = startExport.centralPos.get(a).distance(endExport.centralPos.get(b));
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
@@ -199,17 +203,24 @@ public class MorphShapeGenerator {
|
||||
for (int i = 0; i < startFillStyles.size(); i++) {
|
||||
FILLSTYLE fsStart = startFillStyles.get(i);
|
||||
FILLSTYLE fsEnd = endFillStyles.get(i);
|
||||
MORPHFILLSTYLE morphFillStyle = fsStart.toMorphStyle(fsEnd);
|
||||
MORPHFILLSTYLE morphFillStyle = fsStart.toMorphStyle(fsEnd, swf);
|
||||
if (morphFillStyle == null) {
|
||||
throw new StyleMismatchException();
|
||||
}
|
||||
morphFillStyleArray.fillStyles[i] = morphFillStyle;
|
||||
}
|
||||
|
||||
for (int i = 0; i < endFillStyles.size(); i++) {
|
||||
FILLSTYLE fsEnd = endFillStyles.get(i);
|
||||
if (fsEnd.hasBitmap()) {
|
||||
swf.removeTag(swf.getImage(fsEnd.bitmapId));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < startLineStyles.size(); i++) {
|
||||
LINESTYLE2 lsStart = startLineStyles.get(i);
|
||||
LINESTYLE2 lsEnd = endLineStyles.get(i);
|
||||
MORPHLINESTYLE2 morphLineStyle = lsStart.toMorphLineStyle2(lsEnd);
|
||||
MORPHLINESTYLE2 morphLineStyle = lsStart.toMorphLineStyle2(lsEnd, swf);
|
||||
if (morphLineStyle == null) {
|
||||
throw new StyleMismatchException();
|
||||
}
|
||||
@@ -221,6 +232,13 @@ public class MorphShapeGenerator {
|
||||
morphShape.usesScalingStrokes = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < startLineStyles.size(); i++) {
|
||||
LINESTYLE2 lsEnd = endLineStyles.get(i);
|
||||
if (lsEnd.hasFillFlag && lsEnd.fillType.hasBitmap()) {
|
||||
swf.removeTag(swf.getImage(lsEnd.fillType.bitmapId));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < startBeziers.size(); i++) {
|
||||
List<BezierEdge> beList = startBeziers.get(i);
|
||||
|
||||
@@ -217,7 +217,8 @@ public class SvgImporter {
|
||||
|
||||
this.viewBox = viewBox;
|
||||
|
||||
SvgStyle style = new SvgStyle(this, idMap, rootElement);
|
||||
Map<String, SvgFill> cachedFills = new HashMap<>();
|
||||
SvgStyle style = new SvgStyle(this, idMap, rootElement, cachedFills);
|
||||
Matrix transform = new Matrix();
|
||||
|
||||
if (fill) {
|
||||
@@ -232,7 +233,7 @@ public class SvgImporter {
|
||||
transform = transform.preConcatenate(Matrix.getScaleInstance(width / viewBox.width, height / viewBox.height));
|
||||
}
|
||||
|
||||
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape);
|
||||
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape, cachedFills);
|
||||
} catch (SAXException | IOException | ParserConfigurationException ex) {
|
||||
Logger.getLogger(ShapeImporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
@@ -318,7 +319,7 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
|
||||
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
||||
Node childNode = element.getChildNodes().item(i);
|
||||
if (childNode instanceof Element) {
|
||||
@@ -329,31 +330,31 @@ public class SvgImporter {
|
||||
if (childElement.hasAttribute("systemLanguage")) {
|
||||
String systemLanguage = childElement.getAttribute("systemLanguage");
|
||||
if (systemLanguage.equals("en-us") || systemLanguage.equals("en")) {
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
|
||||
if (element.hasAttribute("requiredExtensions") && !element.getAttribute("requiredExtensions").isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String tagName = element.getTagName();
|
||||
SvgStyle newStyle = new SvgStyle(this, idMap, element);
|
||||
SvgStyle newStyle = new SvgStyle(this, idMap, element, cachedFills);
|
||||
Matrix m = Matrix.parseSvgMatrix(element.getAttribute("transform"), 1, 1);
|
||||
Matrix m2 = m == null ? transform : transform.concatenate(m);
|
||||
if ("switch".equals(tagName)) {
|
||||
processSwitch(element, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
processSwitch(element, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills);
|
||||
} else if ("style".equals(tagName)) {
|
||||
processStyle(element);
|
||||
} else if ("g".equals(tagName)) {
|
||||
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape, cachedFills);
|
||||
} else if ("path".equals(tagName)) {
|
||||
processPath(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("circle".equals(tagName)) {
|
||||
@@ -378,12 +379,12 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
|
||||
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
||||
Node childNode = element.getChildNodes().item(i);
|
||||
if (childNode instanceof Element) {
|
||||
Element childElement = (Element) childNode;
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,15 +46,18 @@ class SvgStyle {
|
||||
private final SvgImporter importer;
|
||||
|
||||
private final Map<String, Element> idMap;
|
||||
|
||||
private final Map<String, SvgFill> cachedFills;
|
||||
|
||||
private final double epsilon = 0.001;
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element) {
|
||||
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element, Map<String, SvgFill> cachedFills) {
|
||||
this.importer = importer;
|
||||
this.idMap = idMap;
|
||||
this.element = element;
|
||||
this.cachedFills = cachedFills;
|
||||
}
|
||||
|
||||
private Map<String, String> getStyleAttributeValues(Element element) {
|
||||
@@ -467,7 +470,7 @@ class SvgStyle {
|
||||
Node node = stopNodes.item(i);
|
||||
if (node instanceof Element) {
|
||||
Element stopEl = (Element) node;
|
||||
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl);
|
||||
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl, cachedFills);
|
||||
|
||||
String offsetStr = stopEl.getAttribute("offset");
|
||||
double offset = importer.parseNumberOrPercent(offsetStr);
|
||||
@@ -560,15 +563,22 @@ class SvgStyle {
|
||||
|
||||
if (mPat.matches()) {
|
||||
String elementId = mPat.group(1);
|
||||
if (cachedFills.containsKey(elementId)) {
|
||||
return cachedFills.get(elementId);
|
||||
}
|
||||
Element e = idMap.get(elementId);
|
||||
if (e != null) {
|
||||
String tagName = e.getTagName();
|
||||
if ("linearGradient".equals(tagName)) {
|
||||
return parseGradient(idMap, e);
|
||||
SvgFill ret = parseGradient(idMap, e);
|
||||
cachedFills.put(elementId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ("radialGradient".equals(tagName)) {
|
||||
return parseGradient(idMap, e);
|
||||
SvgFill ret = parseGradient(idMap, e);
|
||||
cachedFills.put(elementId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ("pattern".equals(tagName)) {
|
||||
@@ -599,6 +609,7 @@ class SvgStyle {
|
||||
bitmapFill.patternTransform = e.getAttribute("patternTransform");
|
||||
}
|
||||
|
||||
cachedFills.put(elementId, bitmapFill);
|
||||
return bitmapFill;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SvgStyle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class ImageTag extends DrawableTag {
|
||||
public abstract Dimension getImageDimension();
|
||||
|
||||
public abstract void setImage(byte[] data) throws IOException;
|
||||
|
||||
|
||||
public abstract ImageFormat getOriginalImageFormat();
|
||||
|
||||
public boolean importSupported() {
|
||||
@@ -315,4 +315,25 @@ public abstract class ImageTag extends DrawableTag {
|
||||
public RECT getRectWithStrokes() {
|
||||
return getRect();
|
||||
}
|
||||
|
||||
public boolean isSameImage(ImageTag otherImage) {
|
||||
SerializableImage imgA = getImageCached();
|
||||
SerializableImage imgB = otherImage.getImageCached();
|
||||
if (imgA.getWidth() != imgB.getWidth() || imgA.getHeight() != imgB.getHeight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int width = imgA.getWidth();
|
||||
int height = imgA.getHeight();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +151,30 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
gradient = g;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCompatibleFillStyle(FILLSTYLE otherFillStyle) {
|
||||
}
|
||||
|
||||
public boolean hasBitmap() {
|
||||
switch (fillStyleType) {
|
||||
case CLIPPED_BITMAP:
|
||||
case NON_SMOOTHED_CLIPPED_BITMAP:
|
||||
case NON_SMOOTHED_REPEATING_BITMAP:
|
||||
case REPEATING_BITMAP:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasGradient() {
|
||||
switch (fillStyleType) {
|
||||
case LINEAR_GRADIENT:
|
||||
case RADIAL_GRADIENT:
|
||||
case FOCAL_RADIAL_GRADIENT:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCompatibleFillStyle(FILLSTYLE otherFillStyle, SWF swf) {
|
||||
if (fillStyleType != otherFillStyle.fillStyleType) {
|
||||
return false;
|
||||
}
|
||||
@@ -163,7 +184,9 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
case NON_SMOOTHED_REPEATING_BITMAP:
|
||||
case REPEATING_BITMAP:
|
||||
if (bitmapId != otherFillStyle.bitmapId) {
|
||||
return false;
|
||||
ImageTag imgThis = swf.getImage(bitmapId);
|
||||
ImageTag imgOther = swf.getImage(otherFillStyle.bitmapId);
|
||||
return imgThis.isSameImage(imgOther);
|
||||
}
|
||||
break;
|
||||
case LINEAR_GRADIENT:
|
||||
@@ -176,7 +199,7 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public MORPHFILLSTYLE toMorphStyle() {
|
||||
MORPHFILLSTYLE morphFillStyle = new MORPHFILLSTYLE();
|
||||
morphFillStyle.bitmapId = bitmapId;
|
||||
@@ -191,19 +214,19 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
morphFillStyle.fillStyleType = fillStyleType;
|
||||
if (gradient != null) {
|
||||
morphFillStyle.gradient = gradient.toMorphGradient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return morphFillStyle;
|
||||
}
|
||||
|
||||
public MORPHFILLSTYLE toMorphStyle(FILLSTYLE endFillStyle) {
|
||||
if (!isCompatibleFillStyle(endFillStyle)) {
|
||||
|
||||
public MORPHFILLSTYLE toMorphStyle(FILLSTYLE endFillStyle, SWF swf) {
|
||||
if (!isCompatibleFillStyle(endFillStyle, swf)) {
|
||||
return null;
|
||||
}
|
||||
MORPHFILLSTYLE morphFillStyle = new MORPHFILLSTYLE();
|
||||
morphFillStyle.bitmapId = bitmapId;
|
||||
if (bitmapMatrix != null) {
|
||||
morphFillStyle.startBitmapMatrix = new MATRIX(bitmapMatrix);
|
||||
morphFillStyle.startBitmapMatrix = new MATRIX(bitmapMatrix);
|
||||
}
|
||||
if (endFillStyle.bitmapMatrix != null) {
|
||||
morphFillStyle.endBitmapMatrix = new MATRIX(endFillStyle.bitmapMatrix);
|
||||
@@ -217,8 +240,8 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
morphFillStyle.fillStyleType = fillStyleType;
|
||||
if (gradient != null) {
|
||||
morphFillStyle.gradient = gradient.toMorphGradient(endFillStyle.gradient);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return morphFillStyle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public boolean isCompatibleLineStyle(LINESTYLE2 otherLineStyle) {
|
||||
public boolean isCompatibleLineStyle(LINESTYLE2 otherLineStyle, SWF swf) {
|
||||
if (startCapStyle != otherLineStyle.startCapStyle) {
|
||||
return false;
|
||||
}
|
||||
@@ -173,7 +173,7 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
}
|
||||
|
||||
if (hasFillFlag) {
|
||||
if (!fillType.isCompatibleFillStyle(otherLineStyle.fillType)) {
|
||||
if (!fillType.isCompatibleFillStyle(otherLineStyle.fillType, swf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -204,8 +204,8 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
return morphLineStyle2;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLE2 toMorphLineStyle2(LINESTYLE2 endLineStyle) {
|
||||
if (!isCompatibleLineStyle(endLineStyle)) {
|
||||
public MORPHLINESTYLE2 toMorphLineStyle2(LINESTYLE2 endLineStyle, SWF swf) {
|
||||
if (!isCompatibleLineStyle(endLineStyle, swf)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
morphLineStyle2.endColor = new RGBA(endLineStyle.color);
|
||||
}
|
||||
if (hasFillFlag) {
|
||||
morphLineStyle2.fillType = fillType.toMorphStyle(endLineStyle.fillType);
|
||||
morphLineStyle2.fillType = fillType.toMorphStyle(endLineStyle.fillType, swf);
|
||||
}
|
||||
return morphLineStyle2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user