diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 763cdffe8..62f39f9cb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -19,42 +19,20 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; -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.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; 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.MORPHFILLSTYLE; import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2; 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.Reserved; 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.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; /** * @@ -63,13 +41,6 @@ import java.util.Set; */ public class DefineMorphShape2Tag extends MorphShapeTag { - @SWFType(BasicType.UI16) - public int characterId; - - public RECT startBounds; - - public RECT endBounds; - public RECT startEdgeBounds; public RECT endEdgeBounds; @@ -82,64 +53,8 @@ public class DefineMorphShape2Tag extends MorphShapeTag { public boolean usesScalingStrokes; - public MORPHFILLSTYLEARRAY morphFillStyles; - - public MORPHLINESTYLEARRAY morphLineStyles; - - public SHAPE startEdges; - - public SHAPE endEdges; - public static final int ID = 84; - public static final int MAX_RATIO = 65535; - - @Override - public void getNeededCharacters(Set 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 RECT getRect(Set 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; - } - - @Override - public int getCharacterId() { - return characterId; - } - /** * Gets data bytes * @@ -216,221 +131,15 @@ public class DefineMorphShape2Tag extends MorphShapeTag { reserved = (int) sis.readUB(6, "reserved"); usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; - long offset = sis.readUI32("offset"); + long offset = sis.readUI32("offset"); // ignore morphFillStyles = sis.readMORPHFILLSTYLEARRAY("morphFillStyles"); morphLineStyles = sis.readMORPHLINESTYLEARRAY(2, "morphLineStyles"); startEdges = sis.readSHAPE(2, true, "startEdges"); endEdges = sis.readSHAPE(2, true, "endEdges"); } - @Override - public RECT getStartBounds() { - return startBounds; - } - - @Override - public RECT getEndBounds() { - return endBounds; - } - - @Override - public MORPHFILLSTYLEARRAY getFillStyles() { - return morphFillStyles; - } - - @Override - public MORPHLINESTYLEARRAY getLineStyles() { - return morphLineStyles; - } - - @Override - public SHAPE getStartEdges() { - return startEdges; - } - - @Override - public SHAPE getEndEdges() { - return endEdges; - } - @Override public int getShapeNum() { return 2; } - - @Override - public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { - List 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 / 65535; - scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / 65535; - 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 / 65535; - cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / 65535; - cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / 65535; - cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / 65535; - 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 / 65535; - ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / 65535; - 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, Matrix transformation, ColorTransform colorTransform) { - SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); - // 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, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - if (ratio == -2) { - SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); - SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); - SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } else { - SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); - 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) { - return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); - cmse.export(); - return cmse.getShapeData(); - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 3539fdad2..c9b386f13 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -19,41 +19,17 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; -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.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -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.MORPHFILLSTYLE; import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; import com.jpexs.decompiler.flash.types.MORPHLINESTYLE; 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.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; /** * @@ -62,61 +38,8 @@ import java.util.Set; */ public class DefineMorphShapeTag extends MorphShapeTag { - @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 static final int ID = 46; - public static final int MAX_RATIO = 65535; - - @Override - public void getNeededCharacters(Set 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; - } - /** * Gets data bytes * @@ -136,11 +59,10 @@ public class DefineMorphShapeTag extends MorphShapeTag { sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 1); sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 1); sos2.writeSHAPE(startEdges, 1); - byte[] d = baos2.toByteArray(); - sos.writeUI32(d.length); - sos.write(d); + byte[] ba2 = baos2.toByteArray(); + sos.writeUI32(ba2.length); + sos.write(ba2); sos.writeSHAPE(endEdges, 1); - } catch (IOException e) { throw new Error("This should never happen.", e); } @@ -189,224 +111,8 @@ public class DefineMorphShapeTag extends MorphShapeTag { endEdges = sis.readSHAPE(1, true, "endEdges"); } - @Override - public RECT getRect(Set 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; - } - - @Override - public RECT getStartBounds() { - return startBounds; - } - - @Override - public RECT getEndBounds() { - return endBounds; - } - - @Override - public MORPHFILLSTYLEARRAY getFillStyles() { - return morphFillStyles; - } - - @Override - public MORPHLINESTYLEARRAY getLineStyles() { - return morphLineStyles; - } - - @Override - public SHAPE getStartEdges() { - return startEdges; - } - - @Override - public SHAPE getEndEdges() { - return endEdges; - } - @Override public int getShapeNum() { return 1; } - - @Override - public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { - List 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, Matrix transformation, ColorTransform colorTransform) { - SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); - // shapeNum: 3 - // 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, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - if (ratio == -2) { - SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); - SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); - SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } else { - SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); - 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) { - return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); - cmse.export(); - return cmse.getShapeData(); - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index 1181d8d01..be2764e7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -21,9 +21,11 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.tags.base.StaticTextTag; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; import java.util.ArrayList; +import java.util.List; /** * @@ -49,6 +51,16 @@ public class DefineTextTag extends StaticTextTag { advanceBits = 0; } + public DefineTextTag(SWF swf, int characterID, RECT textBounds, MATRIX textMatrix, List textRecords) { + super(swf, ID, "DefineText", null); + this.characterID = characterID; + this.textBounds = textBounds; + this.textMatrix = textMatrix; + this.textRecords = textRecords; + this.glyphBits = 0; + this.advanceBits = 0; + } + /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java index a1ca554c5..55f18f146 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java @@ -17,13 +17,35 @@ 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 static com.jpexs.decompiler.flash.tags.base.DrawableTag.PARAMETER_RATIO; +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; /** * @@ -31,28 +53,276 @@ import java.util.HashSet; */ public abstract class MorphShapeTag extends CharacterTag implements 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 RECT getStartBounds(); - - public abstract RECT getEndBounds(); - - public abstract MORPHFILLSTYLEARRAY getFillStyles(); - - public abstract MORPHLINESTYLEARRAY getLineStyles(); - - public abstract SHAPE getStartEdges(); - - public abstract SHAPE getEndEdges(); - public abstract int getShapeNum(); - public abstract SHAPEWITHSTYLE getShapeAtRatio(int ratio); - @Override public RECT getRect() { - return getRect(new HashSet()); + return getRect(new HashSet<>()); + } + + @Override + public void getNeededCharacters(Set 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 RECT getRect(Set 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 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, Matrix transformation, 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, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + if (ratio == -2) { + SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); + SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); + SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); + shapeExporter.export(); + } else { + SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); + 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) { + return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); + cmse.export(); + return cmse.getShapeData(); + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; } }