From 317b9bfd47e629fb25a3085aad6665da8e276904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sat, 1 Mar 2014 10:31:09 +0100 Subject: [PATCH] internal renderer - clipping (masks) --- .../src/com/jpexs/decompiler/flash/Layer.java | 1 + trunk/src/com/jpexs/decompiler/flash/SWF.java | 80 +++++++++++++++---- trunk/src/com/jpexs/helpers/Helper.java | 37 ++++++++- 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/Layer.java b/trunk/src/com/jpexs/decompiler/flash/Layer.java index b99060712..b0abb0738 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Layer.java +++ b/trunk/src/com/jpexs/decompiler/flash/Layer.java @@ -42,4 +42,5 @@ public class Layer { public int ratio = -1; public int duration = 0; public boolean visible = true; + public int clipDepth = -1; } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 09ea3ea47..6e4ae46f7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -125,7 +125,10 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; +import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -340,6 +343,7 @@ public final class SWF implements TreeItem { /** * Faster constructor to check SWF only + * * @param is * @throws java.io.IOException */ @@ -412,7 +416,7 @@ public final class SWF implements TreeItem { } } } - + /** * Construct SWF from stream * @@ -2221,12 +2225,12 @@ public final class SWF implements TreeItem { image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1, (int) (rect.getHeight() / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); //Make all pixels transparent - Graphics2D g = (Graphics2D)image.getGraphics(); + Graphics2D g = (Graphics2D) image.getGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setComposite(AlphaComposite.Src); - g.setColor(new Color(0,0,0,0f)); + g.setColor(new Color(0, 0, 0, 0f)); g.fillRect(0, 0, image.getWidth(), image.getHeight()); Matrix m = new Matrix(); m.translate(-rect.Xmin, -rect.Ymin); @@ -2319,6 +2323,10 @@ public final class SWF implements TreeItem { if (ratio != -1) { layer.ratio = ratio; } + int clipDepth = po.getClipDepth(); + if (clipDepth != -1) { + layer.clipDepth = clipDepth; + } } else { layer.matrix = po.getMatrix(); layer.instanceName = po.getInstanceName(); @@ -2328,6 +2336,7 @@ public final class SWF implements TreeItem { layer.blendMode = po.getBlendMode(); layer.filters = po.getFilters(); layer.ratio = po.getRatio(); + layer.clipDepth = po.getClipDepth(); } } @@ -2366,12 +2375,12 @@ public final class SWF implements TreeItem { SerializableImage image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1, (int) (rect.getHeight() / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); //Make all pixels transparent - Graphics2D g = (Graphics2D)image.getGraphics(); + Graphics2D g = (Graphics2D) image.getGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setComposite(AlphaComposite.Src); - g.setColor(new Color(0,0,0,0f)); + g.setColor(new Color(0, 0, 0, 0f)); g.fillRect(0, 0, image.getWidth(), image.getHeight()); Matrix m = new Matrix(); m.translate(-rect.Xmin, -rect.Ymin); @@ -2380,18 +2389,37 @@ public final class SWF implements TreeItem { } } + private static class Clip { + + public Shape shape; + public int clipDepth; + + public Clip(Shape clip, int clipDepth) { + this.shape = clip; + this.clipDepth = clipDepth; + } + + } + public static void frameToImage(int containerId, int maxDepth, Map layers, Color backgroundColor, Map characters, int frame, List allTags, List controlTags, RECT displayRect, Stack visited, SerializableImage image, Matrix transformation) { float unzoom = (float) SWF.unitDivisor; Graphics2D g = (Graphics2D) image.getGraphics(); g.setPaint(backgroundColor); g.fill(new Rectangle(image.getWidth(), image.getHeight())); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setTransform(transformation.toTransform()); + List clips = new ArrayList<>(); + List prevClips = new ArrayList<>(); for (int i = 1; i <= maxDepth; i++) { + + for (int c = 0; c < clips.size(); c++) { + if (clips.get(c).clipDepth == i) { + g.setClip(prevClips.get(c)); + prevClips.remove(c); + clips.remove(c); + } + } if (!layers.containsKey(i)) { continue; } @@ -2426,13 +2454,13 @@ public final class SWF implements TreeItem { m.translate(-rect.xMin, -rect.yMin); drawMatrix.translate(rect.xMin, rect.yMin); } - //Make all pixels transparent - Graphics2D gr = (Graphics2D)img.getGraphics(); + //Make all pixels transparent + Graphics2D gr = (Graphics2D) img.getGraphics(); gr.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); gr.setComposite(AlphaComposite.Src); - gr.setColor(new Color(0,0,0,0f)); + gr.setColor(new Color(0, 0, 0, 0f)); gr.fillRect(0, 0, img.getWidth(), image.getHeight()); drawable.toImage(layer.ratio < 0 ? 0 : layer.ratio/*layer.duration*/, allTags, characters, visited, img, m); } else { @@ -2502,8 +2530,28 @@ public final class SWF implements TreeItem { drawMatrix.translateX /= unzoom; drawMatrix.translateY /= unzoom; - g.setTransform(drawMatrix.toTransform()); - g.drawImage(img.getBufferedImage(), 0, 0, null); + AffineTransform trans = drawMatrix.toTransform(); + + if (layer.clipDepth > -1) { + BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType()); + Graphics2D gm = (Graphics2D) mask.getGraphics(); + gm.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + gm.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + gm.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gm.setComposite(AlphaComposite.Src); + gm.setColor(new Color(0, 0, 0, 0f)); + gm.fillRect(0, 0, image.getWidth(), image.getHeight()); + gm.setTransform(trans); + gm.drawImage(img.getBufferedImage(), 0, 0, null); + Clip clip = new Clip(Helper.imageToShape(mask), layer.clipDepth); //Maybe we can get corrent outline instead converting from image (?) + clips.add(clip); + prevClips.add(g.getClip()); + g.setTransform(AffineTransform.getTranslateInstance(0, 0)); + g.setClip(clip.shape); + } else { + g.setTransform(trans); + g.drawImage(img.getBufferedImage(), 0, 0, null); + } } else if (character instanceof BoundedTag) { showPlaceholder = true; } diff --git a/trunk/src/com/jpexs/helpers/Helper.java b/trunk/src/com/jpexs/helpers/Helper.java index 6f06a4faa..6070817f5 100644 --- a/trunk/src/com/jpexs/helpers/Helper.java +++ b/trunk/src/com/jpexs/helpers/Helper.java @@ -25,6 +25,10 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.utf8.Utf8Helper; import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -415,7 +419,7 @@ public class Helper { if (is instanceof MemoryInputStream) { return ((MemoryInputStream) is).getAllRead(); } - + ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buf = new byte[4096]; @@ -785,4 +789,35 @@ public class Helper { } return text; } + + public static Shape imageToShape(BufferedImage image) { + Area area = new Area(); + Rectangle rectangle = new Rectangle(); + int y1, y2; + for (int x = 0; x < image.getWidth(); x++) { + y1 = 99; + y2 = -1; + for (int y = 0; y < image.getHeight(); y++) { + int rgb = image.getRGB(x, y); + rgb = rgb >>> 24; + if (rgb > 0) { + if (y1 == 99) { + y1 = y; + y2 = y; + } + if (y > (y2 + 1)) { + rectangle.setBounds(x, y1, 1, y2 - y1); + area.add(new Area(rectangle)); + y1 = y; + } + y2 = y; + } + } + if ((y2 - y1) >= 0) { + rectangle.setBounds(x, y1, 1, y2 - y1); + area.add(new Area(rectangle)); + } + } + return area; + } }