#1156 Flash Viewer - DefineScalingGrid (9 slice scaling)

This commit is contained in:
Jindra Petřík
2016-02-21 09:29:48 +01:00
parent 5b89b153f9
commit a9c2234bcf
15 changed files with 149 additions and 29 deletions

View File

@@ -741,10 +741,8 @@ public final class SWF implements SWFContainerItem, Timelined {
characters.put(characterId, (CharacterTag) t);
characterIdTags.put(characterId, new ArrayList<>());
}
} else {
if (characterIdTags.containsKey(characterId)) {
characterIdTags.get(characterId).add((CharacterIdTag) t);
}
} else if (characterIdTags.containsKey(characterId)) {
characterIdTags.get(characterId).add((CharacterIdTag) t);
}
}
@@ -2672,7 +2670,7 @@ public final class SWF implements SWFContainerItem, Timelined {
RenderContext renderContext = new RenderContext();
renderContext.cursorPosition = cursorPosition;
renderContext.mouseButton = mouseButton;
timeline.toImage(frame, time, renderContext, image, false, m, absoluteTransformation, colorTransform);
timeline.toImage(frame, time, renderContext, image, false, m, transformation, absoluteTransformation, colorTransform);
return image;
}
@@ -2834,13 +2832,15 @@ public final class SWF implements SWFContainerItem, Timelined {
timelined.setModified(true);
timelined.resetTimeline();
} else // timeline should be always the swf here
if (removeDependencies) {
removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline());
timelined.setModified(true);
} else {
boolean modified = removeTagFromTimeline(tag, timelined.getTimeline());
if (modified) {
{
if (removeDependencies) {
removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline());
timelined.setModified(true);
} else {
boolean modified = removeTagFromTimeline(tag, timelined.getTimeline());
if (modified) {
timelined.setModified(true);
}
}
}
}

View File

@@ -122,7 +122,7 @@ public class ShapeExporter {
Matrix m = new Matrix();
m.translate(-rect.Xmin, -rect.Ymin);
m.scale(settings.zoom);
st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, new CXFORMWITHALPHA());
st.toImage(0, 0, 0, new RenderContext(), img, false, m, new Matrix(), m, new CXFORMWITHALPHA());
if (settings.mode == ShapeExportMode.PNG) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file);
} else {

View File

@@ -86,4 +86,10 @@ public class ExportRectangle {
}
return false;
}
@Override
public String toString() {
return "[ExportRectangle x=" + xMin + ",y=" + yMin + ", w=" + getWidth() + ", h=" + getHeight() + "]";
}
}

View File

@@ -916,7 +916,7 @@ public class DefineEditTextTag extends TextTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
render(TextRenderMode.BITMAP, image, null, null, transformation, colorTransform, 1);
}

View File

@@ -366,8 +366,8 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, prevTransformation, absoluteTransformation, colorTransform);
}
@Override

View File

@@ -92,8 +92,8 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, prevTransformation, absoluteTransformation, colorTransform);
}
@Override

View File

@@ -39,7 +39,7 @@ public interface DrawableTag extends BoundedTag {
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform);
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException;

View File

@@ -323,7 +323,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
}

View File

@@ -283,7 +283,7 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShape(), null, image, transformation, colorTransform);
}

View File

@@ -279,7 +279,7 @@ public abstract class MorphShapeTag extends CharacterTag implements DrawableTag
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, 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

View File

@@ -132,7 +132,7 @@ public abstract class ShapeTag extends CharacterTag implements DrawableTag, Lazy
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform);
if (Configuration._debugMode.get()) { // show control points
List<GeneralPath> paths = PathExporter.export(swf, getShapes());

View File

@@ -652,7 +652,7 @@ public abstract class StaticTextTag extends TextTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
staticTextToImage(swf, textRecords, getTextNum(), image, textMatrix, transformation, colorTransform);
/*try {
TextTag originalTag = (TextTag) getOriginalTag();

View File

@@ -20,7 +20,9 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.FrameExporter;
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.Point;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.tags.DefineScalingGridTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
@@ -62,6 +64,8 @@ import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
@@ -545,7 +549,110 @@ public class Timeline {
return modified;
}
public void toImage(int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
private Matrix rectToRectMatrix(ExportRectangle fromRect, ExportRectangle toRect) {
Matrix toOrigin = Matrix.getTranslateInstance(-fromRect.xMin, -fromRect.yMin);
Matrix scale = new Matrix();
scale.scaleX = toRect.getWidth() / fromRect.getWidth();
scale.scaleY = toRect.getHeight() / fromRect.getHeight();
Matrix toDest = Matrix.getTranslateInstance(toRect.xMin, toRect.yMin);
return toOrigin.preConcatenate(scale).preConcatenate(toDest);
}
public double roundToPixel(double val) {
return Math.rint(val / SWF.unitDivisor) * SWF.unitDivisor;
}
public void toImage(int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
ExportRectangle scalingGrid = null;
if (timelined instanceof CharacterTag) {
List<CharacterIdTag> mtags = swf.getCharacterIdTags(((CharacterTag) timelined).getCharacterId());
for (CharacterIdTag ct : mtags) {
if (ct instanceof DefineScalingGridTag) {
scalingGrid = new ExportRectangle(((DefineScalingGridTag) ct).splitter);
}
}
}
if (scalingGrid == null || transformation.rotateSkew0 != 0 || transformation.rotateSkew1 != 0) {
toImage(frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform, null);
return;
}
//9-slice scaling using DefineScalingGrid
Matrix diffTransform = prevTransformation.inverse().preConcatenate(transformation);
transformation = diffTransform;
Matrix prevScale = new Matrix();
prevScale.scaleX = prevTransformation.scaleX;
prevScale.scaleY = prevTransformation.scaleY;
ExportRectangle boundsRect = new ExportRectangle(timelined.getRect());
/*
0 | 1 | 2
------------
3 | 4 | 5
------------
6 | 7 | 8
*/
ExportRectangle[] targetRect = new ExportRectangle[9];
ExportRectangle[] sourceRect = new ExportRectangle[9];
Matrix[] transforms = new Matrix[9];
sourceRect[0] = new ExportRectangle(0, 0, scalingGrid.xMin, scalingGrid.yMin);
targetRect[0] = new ExportRectangle(0, 0, scalingGrid.xMin, scalingGrid.yMin);
sourceRect[1] = new ExportRectangle(scalingGrid.xMin, 0, scalingGrid.xMax, scalingGrid.yMin);
targetRect[1] = new ExportRectangle(scalingGrid.xMin, 0, boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax), scalingGrid.yMin);
sourceRect[2] = new ExportRectangle(scalingGrid.xMax, 0, boundsRect.xMax, scalingGrid.yMin);
targetRect[2] = new ExportRectangle(
boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax),
0,
boundsRect.xMax * transformation.scaleX, scalingGrid.yMin);
sourceRect[3] = new ExportRectangle(0, scalingGrid.yMin, scalingGrid.xMin, scalingGrid.yMax);
targetRect[3] = new ExportRectangle(0, scalingGrid.yMin, scalingGrid.xMin, boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax));
sourceRect[4] = new ExportRectangle(scalingGrid.xMin, scalingGrid.yMin, scalingGrid.xMax, scalingGrid.yMax);
targetRect[4] = new ExportRectangle(scalingGrid.xMin, scalingGrid.yMin, boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax), boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax));
sourceRect[5] = new ExportRectangle(scalingGrid.xMax, scalingGrid.yMin, boundsRect.xMax, scalingGrid.yMax);
targetRect[5] = new ExportRectangle(
boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax),
scalingGrid.yMin,
boundsRect.xMax * transformation.scaleX,
boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax)
);
sourceRect[6] = new ExportRectangle(0, scalingGrid.yMax, scalingGrid.xMin, boundsRect.yMax);
targetRect[6] = new ExportRectangle(0, boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax), scalingGrid.xMin, boundsRect.yMax * transformation.scaleY);
sourceRect[7] = new ExportRectangle(scalingGrid.xMin, scalingGrid.yMax, scalingGrid.xMax, boundsRect.yMax);
targetRect[7] = new ExportRectangle(scalingGrid.xMin, boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax), boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax), boundsRect.yMax * transformation.scaleY);
sourceRect[8] = new ExportRectangle(scalingGrid.xMax, scalingGrid.yMax, boundsRect.xMax, boundsRect.yMax);
targetRect[8] = new ExportRectangle(
boundsRect.xMax * transformation.scaleX - (boundsRect.xMax - scalingGrid.xMax),
boundsRect.yMax * transformation.scaleY - (boundsRect.yMax - scalingGrid.yMax),
boundsRect.xMax * transformation.scaleX,
boundsRect.yMax * transformation.scaleY);
for (int i = 0; i < targetRect.length; i++) {
targetRect[i] = prevScale.transform(targetRect[i]);
//targetRect[i] = absDiffTransform.transform(targetRect[i]);
transforms[i] = rectToRectMatrix(sourceRect[i], targetRect[i]);
//Round to pixel boundary
targetRect[i].xMax = Math.rint(targetRect[i].xMax / SWF.unitDivisor);
targetRect[i].yMax = Math.rint(targetRect[i].yMax / SWF.unitDivisor);
targetRect[i].xMin = Math.rint(targetRect[i].xMin / SWF.unitDivisor);
targetRect[i].yMin = Math.rint(targetRect[i].yMin / SWF.unitDivisor);
}
for (int i = 0; i < targetRect.length; i++) {
toImage(frame, time, renderContext, image, isClip, transforms[i], absoluteTransformation, colorTransform, targetRect[i]);
}
}
public void toImage(int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, ExportRectangle clipRect) {
double unzoom = SWF.unitDivisor;
if (getFrameCount() <= frame) {
return;
@@ -555,6 +662,11 @@ public class Timeline {
Graphics2D g = (Graphics2D) image.getGraphics();
g.setPaint(frameObj.backgroundColor.toColor());
g.fill(new Rectangle(image.getWidth(), image.getHeight()));
Shape prevClip = g.getClip();
if (clipRect != null) {
g.setClip(new Rectangle2D.Double(clipRect.xMin, clipRect.yMin, clipRect.getWidth(), clipRect.getHeight()));
}
g.setTransform(transformation.toTransform());
List<Clip> clips = new ArrayList<>();
List<Shape> prevClips = new ArrayList<>();
@@ -671,7 +783,7 @@ public class Timeline {
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
img.fillTransparent();
drawable.toImage(dframe, time, layer.ratio, renderContext, img, isClip || layer.clipDepth > -1, m, absMat, clrTrans);
drawable.toImage(dframe, time, layer.ratio, renderContext, img, isClip || layer.clipDepth > -1, m, transformation, absMat, clrTrans);
if (cacheKey != null) {
renderContext.shapeCache.put(cacheKey, img);
@@ -833,6 +945,7 @@ public class Timeline {
}
g.setTransform(AffineTransform.getScaleInstance(1, 1));
g.setClip(prevClip);
}
public void toSVG(int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException {
@@ -906,6 +1019,7 @@ public class Timeline {
}
}
}
}
private static String getTagIdPrefix(Tag tag, SVGExporter exporter) {