mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-18 03:18:08 +00:00
displaying frames without flash player (partially)
This commit is contained in:
45
trunk/src/com/jpexs/decompiler/flash/Layer.java
Normal file
45
trunk/src/com/jpexs/decompiler/flash/Layer.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.CXFORM;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.filters.FILTER;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Layer {
|
||||
|
||||
public MATRIX matrix;
|
||||
public String instanceName = null;
|
||||
public CXFORM colorTransForm = null;
|
||||
public CXFORMWITHALPHA colorTransFormAlpha = null;
|
||||
public boolean cacheAsBitmap = false;
|
||||
public int blendMode = 0;
|
||||
public List<FILTER> filters = null;
|
||||
public boolean isVisible = true;
|
||||
public RGBA backGroundColor = null;
|
||||
public int characterId = -1;
|
||||
public int ratio = -1;
|
||||
public int duration = 0;
|
||||
public boolean visible = true;
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import com.jpexs.decompiler.flash.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.flash.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.flash.gui.FrameNode;
|
||||
import com.jpexs.decompiler.flash.gui.TagNode;
|
||||
import com.jpexs.decompiler.flash.helpers.Cache;
|
||||
import com.jpexs.decompiler.flash.helpers.Helper;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
@@ -61,6 +62,8 @@ import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
|
||||
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
|
||||
import com.jpexs.decompiler.flash.tags.ExportAssetsTag;
|
||||
import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
|
||||
import com.jpexs.decompiler.flash.tags.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
|
||||
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
|
||||
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
|
||||
import com.jpexs.decompiler.flash.tags.SoundStreamHeadTypeTag;
|
||||
@@ -68,14 +71,31 @@ import com.jpexs.decompiler.flash.tags.SymbolClassTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.VideoFrameTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.types.CXFORM;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.filters.BlendComposite;
|
||||
import com.jpexs.decompiler.flash.types.filters.FILTER;
|
||||
import com.jpexs.decompiler.flash.types.filters.Filtering;
|
||||
import com.jpexs.decompiler.flash.types.sound.AdpcmDecoder;
|
||||
import com.jpexs.decompiler.flash.xfl.XFLConverter;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -1329,4 +1349,320 @@ public class SWF {
|
||||
public void exportXfl(String outfile, String swfName) {
|
||||
XFLConverter.convertSWF(this, swfName, outfile, false);
|
||||
}
|
||||
|
||||
public static float twipToPixel(int twip) {
|
||||
return ((float) twip) / 20.0f;
|
||||
}
|
||||
|
||||
private static class CachedImage implements Serializable {
|
||||
|
||||
private int data[];
|
||||
private int width;
|
||||
private int height;
|
||||
private int type;
|
||||
|
||||
public CachedImage(BufferedImage img) {
|
||||
width = img.getWidth();
|
||||
height = img.getHeight();
|
||||
type = img.getType();
|
||||
data = Filtering.getRGB(img, 0, 0, width, height);
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
BufferedImage ret = new BufferedImage(width, height, type);
|
||||
Filtering.setRGB(ret, 0, 0, width, height, data);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static AffineTransform matrixToTransform(MATRIX mat) {
|
||||
return new AffineTransform(mat.getScaleXFloat(), mat.getRotateSkew0Float(),
|
||||
mat.getRotateSkew1Float(), mat.getScaleYFloat(),
|
||||
mat.translateX, mat.translateY);
|
||||
}
|
||||
private static Cache cache = new Cache(false);
|
||||
|
||||
public static RECT fixRect(RECT rect) {
|
||||
RECT ret = new RECT();
|
||||
ret.Xmin = rect.Xmin;
|
||||
ret.Xmax = rect.Xmax;
|
||||
ret.Ymin = rect.Ymin;
|
||||
ret.Ymax = rect.Ymax;
|
||||
if (ret.Xmin < 0) {
|
||||
ret.Xmax += (-ret.Xmin);
|
||||
ret.Xmin = 0;
|
||||
}
|
||||
if (ret.Ymin < 0) {
|
||||
ret.Ymax += (-ret.Ymin);
|
||||
ret.Ymin = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static BufferedImage frameToImage(int containerId, int maxDepth, HashMap<Integer, Layer> layers, Color backgroundColor, HashMap<Integer, CharacterTag> characters, int frame, List<Tag> allTags, List<Tag> controlTags, RECT displayRect) {
|
||||
displayRect = fixRect(displayRect);
|
||||
String key = "frame_" + frame + "_" + containerId;
|
||||
if (cache.contains(key)) {
|
||||
return ((CachedImage) cache.get(key)).getImage();
|
||||
}
|
||||
float unzoom = 20;
|
||||
BufferedImage ret = new BufferedImage((int) (displayRect.Xmax / unzoom), (int) (displayRect.Ymax / unzoom), BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
Graphics2D g = (Graphics2D) ret.getGraphics();
|
||||
g.setPaint(backgroundColor);
|
||||
g.fill(new Rectangle(ret.getWidth(), ret.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);
|
||||
|
||||
for (int i = 1; i <= maxDepth; i++) {
|
||||
if (!layers.containsKey(i)) {
|
||||
continue;
|
||||
}
|
||||
Layer layer = layers.get(i);
|
||||
if (!characters.containsKey(layer.characterId)) {
|
||||
continue;
|
||||
}
|
||||
if (!layer.visible) {
|
||||
continue;
|
||||
}
|
||||
CharacterTag character = characters.get(layer.characterId);
|
||||
MATRIX mat = new MATRIX(layer.matrix);
|
||||
if (mat == null) {
|
||||
mat = new MATRIX();
|
||||
}
|
||||
mat.translateX /= 20;
|
||||
mat.translateY /= 20;
|
||||
|
||||
AffineTransform trans = matrixToTransform(mat);
|
||||
|
||||
//trans.translate(transX, transY);
|
||||
g.setTransform(trans);
|
||||
if (character instanceof DrawableTag) {
|
||||
DrawableTag drawable = (DrawableTag) character;
|
||||
BufferedImage img = drawable.toImage(1/*layer.duration*/, allTags, displayRect, characters);
|
||||
|
||||
|
||||
if (layer.filters != null) {
|
||||
for (FILTER filter : layer.filters) {
|
||||
img = filter.apply(img);
|
||||
}
|
||||
}
|
||||
if (layer.colorTransForm != null) {
|
||||
img = layer.colorTransForm.apply(img);
|
||||
}
|
||||
|
||||
if (layer.colorTransFormAlpha != null) {
|
||||
img = layer.colorTransFormAlpha.apply(img);
|
||||
}
|
||||
Point imgPos = drawable.getImagePos(characters);
|
||||
if (imgPos.x < 0) {
|
||||
imgPos.x = 0;
|
||||
}
|
||||
if (imgPos.y < 0) {
|
||||
imgPos.y = 0;
|
||||
}
|
||||
switch (layer.blendMode) {
|
||||
case 0:
|
||||
case 1:
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
break;
|
||||
case 2: //TODO:Layer
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
break;
|
||||
case 3:
|
||||
g.setComposite(BlendComposite.Multiply);
|
||||
break;
|
||||
case 4:
|
||||
g.setComposite(BlendComposite.Screen);
|
||||
break;
|
||||
case 5:
|
||||
g.setComposite(BlendComposite.Lighten);
|
||||
break;
|
||||
case 6:
|
||||
g.setComposite(BlendComposite.Darken);
|
||||
break;
|
||||
case 7:
|
||||
g.setComposite(BlendComposite.Difference);
|
||||
break;
|
||||
case 8:
|
||||
g.setComposite(BlendComposite.Add);
|
||||
break;
|
||||
case 9:
|
||||
g.setComposite(BlendComposite.Subtract);
|
||||
break;
|
||||
case 10:
|
||||
g.setComposite(BlendComposite.Invert);
|
||||
break;
|
||||
case 11:
|
||||
g.setComposite(BlendComposite.Alpha);
|
||||
break;
|
||||
case 12:
|
||||
g.setComposite(BlendComposite.Erase);
|
||||
break;
|
||||
case 13:
|
||||
g.setComposite(BlendComposite.Overlay);
|
||||
break;
|
||||
case 14:
|
||||
g.setComposite(BlendComposite.HardLight);
|
||||
break;
|
||||
default: //Not implemented
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
break;
|
||||
}
|
||||
|
||||
g.drawImage(img, imgPos.x, imgPos.y, null);
|
||||
} else if (character instanceof BoundedTag) {
|
||||
BoundedTag b = (BoundedTag) character;
|
||||
g.setPaint(new Color(255, 255, 255, 128));
|
||||
g.setComposite(BlendComposite.Invert);
|
||||
RECT r = b.getRect(characters);
|
||||
g.drawString(character.toString(), (r.Xmin) / 20 + 3, (r.Ymin) / 20 + 15);
|
||||
g.draw(new Rectangle(r.Xmin / 20, r.Ymin / 20, r.getWidth() / 20, r.getHeight() / 20));
|
||||
g.drawLine(r.Xmin / 20, r.Ymin / 20, r.Xmax / 20, r.Ymax / 20);
|
||||
g.drawLine(r.Xmax / 20, r.Ymin / 20, r.Xmin / 20, r.Ymax / 20);
|
||||
g.setComposite(AlphaComposite.Dst);
|
||||
}
|
||||
}
|
||||
g.setTransform(AffineTransform.getScaleInstance(1, 1));
|
||||
/*g.setPaint(Color.yellow);
|
||||
g.draw(new Rectangle(ret.getWidth()-1,ret.getHeight()-1));*/
|
||||
cache.put(key, new CachedImage(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static BufferedImage frameToImage(int containerId, int frame, List<Tag> allTags, List<Tag> controlTags, RECT displayRect, int totalFrameCount) {
|
||||
List<BufferedImage> ret = new ArrayList<BufferedImage>();
|
||||
framesToImage(containerId, ret, frame, frame, allTags, controlTags, displayRect, totalFrameCount);
|
||||
if (ret.isEmpty()) {
|
||||
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
return ret.get(0);
|
||||
}
|
||||
|
||||
public static void framesToImage(int containerId, List<BufferedImage> ret, int startFrame, int stopFrame, List<Tag> allTags, List<Tag> controlTags, RECT displayRect, int totalFrameCount) {
|
||||
for (int i = startFrame; i <= stopFrame; i++) {
|
||||
String key = "frame_" + i + "_" + containerId;
|
||||
if (cache.contains(key)) {
|
||||
ret.add(((CachedImage) cache.get(key)).getImage());
|
||||
startFrame++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (startFrame > stopFrame) {
|
||||
return;
|
||||
}
|
||||
if (totalFrameCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (startFrame > totalFrameCount) {
|
||||
startFrame -= totalFrameCount;
|
||||
}
|
||||
|
||||
while (stopFrame > totalFrameCount) {
|
||||
stopFrame -= totalFrameCount;
|
||||
}
|
||||
|
||||
|
||||
HashMap<Integer, CharacterTag> characters = new HashMap<Integer, CharacterTag>();
|
||||
for (Tag t : allTags) {
|
||||
if (t instanceof CharacterTag) {
|
||||
CharacterTag ch = (CharacterTag) t;
|
||||
characters.put(ch.getCharacterID(), ch);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<Integer, Layer> layers = new HashMap<Integer, Layer>();
|
||||
|
||||
int maxDepth = 0;
|
||||
int f = 1;
|
||||
Color backgroundColor = new Color(0, 0, 0, 0);
|
||||
for (Tag t : controlTags) {
|
||||
if (t instanceof SetBackgroundColorTag) {
|
||||
SetBackgroundColorTag c = (SetBackgroundColorTag) t;
|
||||
backgroundColor = new Color(c.backgroundColor.red, c.backgroundColor.green, c.backgroundColor.blue);
|
||||
}
|
||||
|
||||
if (t instanceof PlaceObjectTypeTag) {
|
||||
PlaceObjectTypeTag po = (PlaceObjectTypeTag) t;
|
||||
int depth = po.getDepth();
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
}
|
||||
|
||||
if (!layers.containsKey(depth)) {
|
||||
layers.put(depth, new Layer());
|
||||
}
|
||||
Layer layer = layers.get(depth);
|
||||
int characterId = po.getCharacterId();
|
||||
if (characterId != -1) {
|
||||
layer.characterId = characterId;
|
||||
}
|
||||
layer.visible = po.isVisible();
|
||||
if (po.flagMove()) {
|
||||
MATRIX matrix2 = po.getMatrix();
|
||||
if (matrix2 != null) {
|
||||
layer.matrix = matrix2;
|
||||
}
|
||||
String instanceName = po.getInstanceName();
|
||||
if (instanceName != null) {
|
||||
layer.instanceName = instanceName;
|
||||
}
|
||||
CXFORM colorTransForm = po.getColorTransform();
|
||||
if (colorTransForm != null) {
|
||||
layer.colorTransForm = colorTransForm;
|
||||
}
|
||||
CXFORMWITHALPHA colorTransFormAlpha = po.getColorTransformWithAlpha();
|
||||
if (colorTransFormAlpha != null) {
|
||||
layer.colorTransFormAlpha = colorTransFormAlpha;
|
||||
}
|
||||
if (po.cacheAsBitmap()) {
|
||||
layer.cacheAsBitmap = true;
|
||||
}
|
||||
int blendMode = po.getBlendMode();
|
||||
if (blendMode != 0) {
|
||||
layer.blendMode = blendMode;
|
||||
}
|
||||
List<FILTER> filters = po.getFilters();
|
||||
if (filters != null) {
|
||||
layer.filters = filters;
|
||||
}
|
||||
int ratio = po.getRatio();
|
||||
if (ratio != -1) {
|
||||
layer.ratio = ratio;
|
||||
}
|
||||
} else {
|
||||
layer.matrix = po.getMatrix();
|
||||
layer.instanceName = po.getInstanceName();
|
||||
layer.colorTransForm = po.getColorTransform();
|
||||
layer.colorTransFormAlpha = po.getColorTransformWithAlpha();
|
||||
layer.cacheAsBitmap = po.cacheAsBitmap();
|
||||
layer.blendMode = po.getBlendMode();
|
||||
layer.filters = po.getFilters();
|
||||
layer.ratio = po.getRatio();
|
||||
}
|
||||
}
|
||||
|
||||
if (t instanceof RemoveTag) {
|
||||
RemoveTag rt = (RemoveTag) t;
|
||||
layers.remove(rt.getDepth());
|
||||
|
||||
}
|
||||
for (Layer l : layers.values()) {
|
||||
l.duration++;
|
||||
}
|
||||
if (t instanceof ShowFrameTag) {
|
||||
if (f > stopFrame) {
|
||||
break;
|
||||
}
|
||||
if ((f >= startFrame) && (f <= stopFrame)) {
|
||||
ret.add(frameToImage(containerId, maxDepth, layers, backgroundColor, characters, f, allTags, controlTags, displayRect));
|
||||
}
|
||||
f++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL
|
||||
private ABCPanel abcPanel;
|
||||
private int classIndex = -1;
|
||||
private boolean isStatic = false;
|
||||
private Cache cache = new Cache();
|
||||
private Cache cache = new Cache(true);
|
||||
|
||||
public ScriptPack getScriptLeaf() {
|
||||
return script;
|
||||
|
||||
@@ -107,7 +107,7 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
private String searchFor;
|
||||
private boolean searchIgnoreCase;
|
||||
private boolean searchRegexp;
|
||||
private Cache cache = new Cache();
|
||||
private Cache cache = new Cache(true);
|
||||
|
||||
private CachedScript getCached(ASMSource pack) {
|
||||
return (CachedScript) cache.get(pack);
|
||||
|
||||
@@ -74,9 +74,9 @@ import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
@@ -162,9 +162,11 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
public FlashPlayerPanel flashPanel;
|
||||
public JPanel displayPanel;
|
||||
public ImagePanel imagePanel;
|
||||
public ImagePanel shapeImagePanel;
|
||||
public ImagePanel previewImagePanel;
|
||||
public SWFPreviwPanel swfPreviewPanel;
|
||||
final static String CARDFLASHPANEL = "Flash card";
|
||||
final static String CARDSHAPEPANEL = "Shape card";
|
||||
final static String CARDSWFPREVIEWPANEL = "SWF card";
|
||||
final static String CARDDRAWPREVIEWPANEL = "Draw card";
|
||||
final static String CARDIMAGEPANEL = "Image card";
|
||||
final static String CARDEMPTYPANEL = "Empty card";
|
||||
final static String CARDACTIONSCRIPTPANEL = "ActionScript card";
|
||||
@@ -189,6 +191,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
private JSplitPane previewSplitPane;
|
||||
private JButton imageReplaceButton;
|
||||
private JPanel imageButtonsPanel;
|
||||
private JCheckBoxMenuItem miInternalViewer;
|
||||
|
||||
public void setPercent(int percent) {
|
||||
progressBar.setValue(percent);
|
||||
@@ -251,6 +254,12 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
setTitle(Main.applicationVerName + (Main.DISPLAY_FILENAME ? " - " + Main.getFileTitle() : ""));
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
|
||||
|
||||
try {
|
||||
flashPanel = new FlashPlayerPanel(this);
|
||||
} catch (FlashUnsupportedException fue) {
|
||||
}
|
||||
|
||||
JMenu menuFile = new JMenu("File");
|
||||
JMenuItem miOpen = new JMenuItem("Open...");
|
||||
miOpen.setIcon(View.getIcon("open16"));
|
||||
@@ -364,6 +373,13 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
miSearchScript.setIcon(View.getIcon("search16"));
|
||||
|
||||
menuTools.add(miSearchScript);
|
||||
|
||||
miInternalViewer = new JCheckBoxMenuItem("Use own Flash viewer");
|
||||
miInternalViewer.setSelected((Boolean) Configuration.getConfig("internalFlashViewer", (Boolean) (flashPanel == null)));
|
||||
miInternalViewer.setActionCommand("INTERNALVIEWERSWITCH");
|
||||
miInternalViewer.addActionListener(this);
|
||||
menuTools.add(miInternalViewer);
|
||||
|
||||
menuTools.add(miProxy);
|
||||
|
||||
//menuTools.add(menuDeobfuscation);
|
||||
@@ -431,7 +447,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
}
|
||||
|
||||
|
||||
tagTree = new JTree(new TagTreeModel(createTagList(objs, null), (new File(Main.file)).getName()));
|
||||
tagTree = new JTree(new TagTreeModel(createTagList(objs, null), new SWFRoot((new File(Main.file)).getName())));
|
||||
tagTree.addTreeSelectionListener(this);
|
||||
final JPopupMenu spritePopupMenu = new JPopupMenu();
|
||||
JMenuItem removeMenuItem = new JMenuItem("Remove");
|
||||
@@ -577,10 +593,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
|
||||
Component leftComponent = null;
|
||||
|
||||
try {
|
||||
flashPanel = new FlashPlayerPanel(this);
|
||||
} catch (FlashUnsupportedException fue) {
|
||||
}
|
||||
|
||||
displayPanel = new JPanel(new CardLayout());
|
||||
|
||||
if (flashPanel != null) {
|
||||
@@ -633,9 +646,21 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
displayPanel.add(imagesCard, CARDIMAGEPANEL);
|
||||
|
||||
JPanel shapesCard = new JPanel(new BorderLayout());
|
||||
shapeImagePanel = new ImagePanel();
|
||||
shapesCard.add(shapeImagePanel, BorderLayout.CENTER);
|
||||
displayPanel.add(shapesCard, CARDSHAPEPANEL);
|
||||
|
||||
JPanel previewPanel = new JPanel(new BorderLayout());
|
||||
|
||||
previewImagePanel = new ImagePanel();
|
||||
previewPanel.add(previewImagePanel, BorderLayout.CENTER);
|
||||
JLabel prevIntLabel = new JLabel("SWF preview (Internal viewer)");
|
||||
prevIntLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
prevIntLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
previewPanel.add(prevIntLabel, BorderLayout.NORTH);
|
||||
shapesCard.add(previewPanel, BorderLayout.CENTER);
|
||||
displayPanel.add(shapesCard, CARDDRAWPREVIEWPANEL);
|
||||
|
||||
swfPreviewPanel = new SWFPreviwPanel();
|
||||
displayPanel.add(swfPreviewPanel, CARDSWFPREVIEWPANEL);
|
||||
|
||||
|
||||
displayPanel.add(new JPanel(), CARDEMPTYPANEL);
|
||||
if (actionPanel != null) {
|
||||
@@ -1146,6 +1171,9 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
if (e.getActionCommand().equals("INTERNALVIEWERSWITCH")) {
|
||||
Configuration.setConfig("internalFlashViewer", (Boolean) miInternalViewer.isSelected());
|
||||
}
|
||||
if (e.getActionCommand().equals("SEARCHAS")) {
|
||||
if (searchDialog == null) {
|
||||
searchDialog = new SearchDialog();
|
||||
@@ -1810,7 +1838,12 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
} else {
|
||||
showDetail(DETAILCARDEMPTYPANEL);
|
||||
}
|
||||
if (tagObj instanceof DefineVideoStreamTag) {
|
||||
swfPreviewPanel.stop();
|
||||
if ((tagObj instanceof SWFRoot) && miInternalViewer.isSelected()) {
|
||||
showCard(CARDSWFPREVIEWPANEL);
|
||||
swfPreviewPanel.load(swf);
|
||||
swfPreviewPanel.play();
|
||||
} else if (tagObj instanceof DefineVideoStreamTag) {
|
||||
showCard(CARDEMPTYPANEL);
|
||||
} else if ((tagObj instanceof DefineSoundTag) || (tagObj instanceof SoundStreamHeadTag) || (tagObj instanceof SoundStreamHead2Tag)) {
|
||||
showCard(CARDEMPTYPANEL);
|
||||
@@ -1823,10 +1856,22 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
imageButtonsPanel.setVisible(((ImageTag) tagObj).importSupported());
|
||||
showCard(CARDIMAGEPANEL);
|
||||
imagePanel.setImage(((ImageTag) tagObj).getImage(swf.tags));
|
||||
} else if (tagObj instanceof ShapeTag) {
|
||||
showCard(CARDSHAPEPANEL);
|
||||
shapeImagePanel.setImage(((ShapeTag) tagObj).toImage(swf.tags));
|
||||
} else if ((tagObj instanceof FrameNode && ((FrameNode) tagObj).isDisplayed()) || (((tagObj instanceof CharacterTag) || (tagObj instanceof FontTag)) && (tagObj instanceof Tag))) {
|
||||
} else if ((tagObj instanceof DrawableTag) && (!(tagObj instanceof TextTag)) && (miInternalViewer.isSelected())) {
|
||||
showCard(CARDDRAWPREVIEWPANEL);
|
||||
previewImagePanel.setImage(((DrawableTag) tagObj).toImage(1, swf.tags, swf.displayRect, characters));
|
||||
} else if (tagObj instanceof FrameNode && ((FrameNode) tagObj).isDisplayed() && (miInternalViewer.isSelected())) {
|
||||
showCard(CARDDRAWPREVIEWPANEL);
|
||||
FrameNode fn = (FrameNode) tagObj;
|
||||
List<Tag> controlTags = swf.tags;
|
||||
int containerId = 0;
|
||||
RECT rect = swf.displayRect;
|
||||
if (fn.getParent() instanceof DefineSpriteTag) {
|
||||
controlTags = ((DefineSpriteTag) fn.getParent()).subTags;
|
||||
containerId = ((DefineSpriteTag) fn.getParent()).spriteId;
|
||||
rect = ((DefineSpriteTag) fn.getParent()).getRect(characters);
|
||||
}
|
||||
previewImagePanel.setImage(SWF.frameToImage(containerId, ((FrameNode) tagObj).getFrame(), swf.tags, controlTags, rect, swf.frameCount));
|
||||
} else if (((tagObj instanceof FrameNode) && ((FrameNode) tagObj).isDisplayed()) || ((tagObj instanceof CharacterTag) || (tagObj instanceof FontTag)) && (tagObj instanceof Tag)) {
|
||||
try {
|
||||
|
||||
if (tempFile != null) {
|
||||
@@ -2025,7 +2070,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
|
||||
public void refreshTree() {
|
||||
List<Object> objs = new ArrayList<Object>();
|
||||
objs.addAll(swf.tags);
|
||||
tagTree.setModel(new TagTreeModel(createTagList(objs, null), (new File(Main.file)).getName()));
|
||||
tagTree.setModel(new TagTreeModel(createTagList(objs, null), new SWFRoot((new File(Main.file)).getName())));
|
||||
}
|
||||
|
||||
public void setEditText(boolean edit) {
|
||||
|
||||
95
trunk/src/com/jpexs/decompiler/flash/gui/SWFPreviwPanel.java
Normal file
95
trunk/src/com/jpexs/decompiler/flash/gui/SWFPreviwPanel.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.SWF;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.BevelBorder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFPreviwPanel extends JPanel {
|
||||
|
||||
ImagePanel pan;
|
||||
Timer timer;
|
||||
int frame = 0;
|
||||
List<BufferedImage> frameImages = new ArrayList<BufferedImage>();
|
||||
JLabel buffering = new JLabel("Buffering...");
|
||||
|
||||
public SWFPreviwPanel() {
|
||||
pan = new ImagePanel();
|
||||
setLayout(new BorderLayout());
|
||||
add(pan, BorderLayout.CENTER);
|
||||
add(buffering, BorderLayout.SOUTH);
|
||||
buffering.setHorizontalAlignment(JLabel.CENTER);
|
||||
buffering.setVisible(false);
|
||||
JLabel prevLabel = new JLabel("SWF preview (Internal viewer)");
|
||||
prevLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
prevLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
add(prevLabel, BorderLayout.NORTH);
|
||||
}
|
||||
private SWF swf;
|
||||
|
||||
public void load(final SWF swf) {
|
||||
this.swf = swf;
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
buffering.setVisible(true);
|
||||
SWF.framesToImage(0, frameImages, 1, swf.frameCount, swf.tags, swf.tags, swf.displayRect, swf.frameCount);
|
||||
buffering.setVisible(false);
|
||||
}
|
||||
}.start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
if (swf == null) {
|
||||
return;
|
||||
}
|
||||
stop();
|
||||
timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
int newframe = (frame == swf.frameCount ? 1 : frame + 1);
|
||||
if (frameImages.size() >= newframe) {
|
||||
pan.setImage(frameImages.get(newframe - 1));
|
||||
frame = newframe;
|
||||
}
|
||||
}
|
||||
}, 0, 1000 / swf.frameRate);
|
||||
}
|
||||
}
|
||||
35
trunk/src/com/jpexs/decompiler/flash/gui/SWFRoot.java
Normal file
35
trunk/src/com/jpexs/decompiler/flash/gui/SWFRoot.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFRoot {
|
||||
|
||||
private String name;
|
||||
|
||||
public SWFRoot(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,10 @@ import javax.swing.tree.TreePath;
|
||||
|
||||
public class TagTreeModel implements TreeModel {
|
||||
|
||||
private String root = "";
|
||||
private Object root;
|
||||
private List<TagNode> list = new ArrayList<TagNode>();
|
||||
|
||||
public TagTreeModel(List<TagNode> list, String rootName) {
|
||||
public TagTreeModel(List<TagNode> list, Object rootName) {
|
||||
this.root = rootName;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
@@ -33,7 +34,15 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class Cache {
|
||||
|
||||
private Map<Object, File> cacheFiles = new WeakHashMap<Object, File>();
|
||||
private Map<Object, File> cacheFiles;
|
||||
|
||||
public Cache(boolean weak) {
|
||||
if (weak) {
|
||||
cacheFiles = new WeakHashMap<Object, File>();
|
||||
} else {
|
||||
cacheFiles = new HashMap<Object, File>();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object key) {
|
||||
return cacheFiles.containsKey(key);
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.Layer;
|
||||
import com.jpexs.decompiler.flash.Main;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
@@ -27,6 +29,9 @@ import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -212,4 +217,30 @@ public class DefineButton2Tag extends CharacterTag implements Container, Bounded
|
||||
public boolean trackAsMenu() {
|
||||
return trackAsMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
HashMap<Integer, Layer> layers = new HashMap<Integer, Layer>();
|
||||
int maxDepth = 0;
|
||||
for (BUTTONRECORD r : this.characters) {
|
||||
if (r.buttonStateUp) {
|
||||
Layer layer = new Layer();
|
||||
layer.colorTransFormAlpha = r.colorTransform;
|
||||
layer.blendMode = r.blendMode;
|
||||
layer.filters = r.filterList;
|
||||
layer.matrix = r.placeMatrix;
|
||||
layer.characterId = r.characterId;
|
||||
if (r.placeDepth > maxDepth) {
|
||||
maxDepth = r.placeDepth;
|
||||
}
|
||||
layers.put(r.placeDepth, layer);
|
||||
}
|
||||
}
|
||||
return SWF.frameToImage(buttonId, maxDepth, layers, new Color(0, 0, 0, 0), characters, 1, tags, tags, displayRect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,10 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.Configuration;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.Layer;
|
||||
import com.jpexs.decompiler.flash.Main;
|
||||
import com.jpexs.decompiler.flash.ReReadableInputStream;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
@@ -30,6 +32,9 @@ import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -227,4 +232,30 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT
|
||||
public boolean trackAsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
HashMap<Integer, Layer> layers = new HashMap<Integer, Layer>();
|
||||
int maxDepth = 0;
|
||||
for (BUTTONRECORD r : this.characters) {
|
||||
if (r.buttonStateUp) {
|
||||
Layer layer = new Layer();
|
||||
layer.colorTransFormAlpha = r.colorTransform;
|
||||
layer.blendMode = r.blendMode;
|
||||
layer.filters = r.filterList;
|
||||
layer.matrix = r.placeMatrix;
|
||||
layer.characterId = r.characterId;
|
||||
if (r.placeDepth > maxDepth) {
|
||||
maxDepth = r.placeDepth;
|
||||
}
|
||||
layers.put(r.placeDepth, layer);
|
||||
}
|
||||
}
|
||||
return SWF.frameToImage(buttonId, maxDepth, layers, new Color(0, 0, 0, 0), characters, 1, tags, tags, displayRect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
|
||||
import com.jpexs.decompiler.flash.tags.text.TextLexer;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -512,4 +513,9 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT
|
||||
}
|
||||
return needed;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return null; //FIXME
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,4 +270,33 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
public boolean isItalic() {
|
||||
return fontFlagsItalic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDivider() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAscent() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontAscent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDescent() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontDescent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLeading() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontLeading;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,4 +270,33 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
public boolean isItalic() {
|
||||
return fontFlagsItalic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDivider() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAscent() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontAscent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDescent() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontDescent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLeading() {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontLeading;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,4 +194,24 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAscent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDescent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLeading() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDivider() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,14 @@ 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 java.awt.geom.GeneralPath;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -169,4 +171,9 @@ public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, Mo
|
||||
public int getShapeNum() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return null; //FIXME
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,14 @@ 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 java.awt.geom.GeneralPath;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -156,4 +158,9 @@ public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, Mor
|
||||
public int getShapeNum() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// @Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return null; //FIXME
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -35,6 +38,11 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
public RECT shapeBounds;
|
||||
public SHAPEWITHSTYLE shapes;
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(shapeBounds.Xmin / 20, shapeBounds.Ymin / 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShapeNum() {
|
||||
return 2;
|
||||
@@ -56,7 +64,7 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(List<Tag> tags) {
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
return shapes.toImage(2, tags);
|
||||
}
|
||||
|
||||
@@ -77,4 +85,9 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
shapeBounds = sis.readRECT();
|
||||
shapes = sis.readSHAPEWITHSTYLE(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToPaths(tags, 2, shapes.shapeRecords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -35,6 +38,11 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
public RECT shapeBounds;
|
||||
public SHAPEWITHSTYLE shapes;
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(shapeBounds.Xmin / 20, shapeBounds.Ymin / 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShapeNum() {
|
||||
return 3;
|
||||
@@ -61,7 +69,7 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(List<Tag> tags) {
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
return shapes.toImage(3, tags);
|
||||
}
|
||||
|
||||
@@ -77,4 +85,9 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
shapeBounds = sis.readRECT();
|
||||
shapes = sis.readSHAPEWITHSTYLE(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToPaths(tags, 3, shapes.shapeRecords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -39,6 +42,11 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
public boolean usesScalingStrokes;
|
||||
public SHAPEWITHSTYLE shapes;
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(shapeBounds.Xmin / 20, shapeBounds.Ymin / 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShapeNum() {
|
||||
return 4;
|
||||
@@ -60,7 +68,7 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(List<Tag> tags) {
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
return shapes.toImage(4, tags);
|
||||
}
|
||||
|
||||
@@ -86,4 +94,9 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa
|
||||
usesScalingStrokes = sis.readUB(1) == 1;
|
||||
shapes = sis.readSHAPEWITHSTYLE(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToPaths(tags, 4, shapes.shapeRecords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -74,7 +77,17 @@ public class DefineShapeTag extends CharacterTag implements BoundedTag, ShapeTag
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(List<Tag> tags) {
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
return shapes.toImage(1, tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(shapeBounds.Xmin / 20, shapeBounds.Ymin / 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeneralPath> getPaths(List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToPaths(tags, 1, shapes.shapeRecords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.Main;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -39,7 +43,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Defines a sprite character
|
||||
*/
|
||||
public class DefineSpriteTag extends CharacterTag implements Container, BoundedTag {
|
||||
public class DefineSpriteTag extends CharacterTag implements Container, BoundedTag, DrawableTag {
|
||||
|
||||
/**
|
||||
* Character ID of sprite
|
||||
@@ -83,30 +87,43 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
|
||||
RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
HashMap<Integer, Integer> depthMap = new HashMap<Integer, Integer>();
|
||||
for (Tag t : subTags) {
|
||||
Set<Integer> needed = t.getNeededCharacters();
|
||||
MATRIX m = null;
|
||||
int characterId = -1;
|
||||
if (t instanceof PlaceObjectTypeTag) {
|
||||
PlaceObjectTypeTag pot = (PlaceObjectTypeTag) t;
|
||||
m = pot.getMatrix();
|
||||
int charId = pot.getCharacterId();
|
||||
if (charId > -1) {
|
||||
depthMap.put(pot.getDepth(), charId);
|
||||
characterId = (charId);
|
||||
} else {
|
||||
needed.add(depthMap.get(pot.getDepth()));
|
||||
characterId = (depthMap.get(pot.getDepth()));
|
||||
}
|
||||
}
|
||||
if (needed.isEmpty()) {
|
||||
if (characterId == -1) {
|
||||
continue;
|
||||
}
|
||||
RECT r = getCharacterBounds(characters, needed);
|
||||
HashSet<Integer> need = new HashSet<Integer>();
|
||||
need.add(characterId);
|
||||
RECT r = getCharacterBounds(characters, need);
|
||||
|
||||
if (m != null) {
|
||||
Point topleft = m.apply(new Point(r.Xmin, r.Ymin));
|
||||
Point bottomright = m.apply(new Point(r.Xmax, r.Ymax));
|
||||
r.Xmin = Math.min(topleft.x, bottomright.x);
|
||||
r.Ymin = Math.min(topleft.y, bottomright.y);
|
||||
r.Xmax = Math.max(topleft.x, bottomright.x);
|
||||
r.Ymax = Math.max(topleft.y, bottomright.y);
|
||||
AffineTransform trans = SWF.matrixToTransform(m);
|
||||
|
||||
Point topleft = new Point();
|
||||
trans.transform(new Point(r.Xmin, r.Ymin), topleft);
|
||||
Point topright = new Point();
|
||||
trans.transform(new Point(r.Xmax, r.Ymin), topright);
|
||||
Point bottomright = new Point();
|
||||
trans.transform(new Point(r.Xmax, r.Ymax), bottomright);
|
||||
Point bottomleft = new Point();
|
||||
trans.transform(new Point(r.Xmin, r.Ymax), bottomleft);
|
||||
|
||||
r.Xmin = Math.min(Math.min(Math.min(topleft.x, topright.x), bottomleft.x), bottomright.x);
|
||||
r.Ymin = Math.min(Math.min(Math.min(topleft.y, topright.y), bottomleft.y), bottomright.y);
|
||||
r.Xmax = Math.max(Math.max(Math.max(topleft.x, topright.x), bottomleft.x), bottomright.x);
|
||||
r.Ymax = Math.max(Math.max(Math.max(topleft.y, topright.y), bottomleft.y), bottomright.y);
|
||||
|
||||
}
|
||||
ret.Xmin = Math.min(r.Xmin, ret.Xmin);
|
||||
ret.Ymin = Math.min(r.Ymin, ret.Ymin);
|
||||
@@ -200,4 +217,23 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
/*
|
||||
rect.Xmax=displayRect.Xmin+rect.getWidth();
|
||||
rect.Ymax=displayRect.Ymin+rect.getWidth();
|
||||
rect.Xmin=displayRect.Xmin;
|
||||
rect.Ymin=displayRect.Ymin;
|
||||
RECT rect=getRect(characters);
|
||||
SWF.fixRect(rect);*/
|
||||
RECT rect = getRect(characters);
|
||||
return SWF.frameToImage(spriteId, frame, tags, subTags, rect, frameCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
RECT displayRect = getRect(characters);
|
||||
return new Point(0, 0); //displayRect.Xmin,displayRect.Ymin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.Helper;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
@@ -30,7 +31,15 @@ import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -52,7 +61,7 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag {
|
||||
public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, DrawableTag {
|
||||
|
||||
public int characterID;
|
||||
public RECT textBounds;
|
||||
@@ -427,4 +436,54 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
RECT bound = getBounds();
|
||||
BufferedImage ret = new BufferedImage(bound.Xmax / 20, bound.Ymax / 20, BufferedImage.TYPE_INT_ARGB);
|
||||
Color textColor = new Color(0, 0, 0);
|
||||
FontTag font = null;
|
||||
int textHeight = 12;
|
||||
int x = bound.Xmin;
|
||||
int y = 0;
|
||||
Graphics2D g = (Graphics2D) ret.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);
|
||||
SHAPE glyphs[] = new SHAPE[0];
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
if (rec.styleFlagsHasColor) {
|
||||
textColor = rec.textColorA.toColor();
|
||||
}
|
||||
if (rec.styleFlagsHasFont) {
|
||||
font = (FontTag) characters.get(rec.fontId);
|
||||
glyphs = font.getGlyphShapeTable();
|
||||
textHeight = rec.textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasXOffset) {
|
||||
x = rec.xOffset * 1000 / textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasYOffset) {
|
||||
y = rec.yOffset * 1000 / textHeight;
|
||||
}
|
||||
|
||||
for (GLYPHENTRY entry : rec.glyphEntries) {
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs[entry.glyphIndex].shapeRecords);
|
||||
rect.Xmax /= font.getDivider();
|
||||
rect.Xmin /= font.getDivider();
|
||||
rect.Ymax /= font.getDivider();
|
||||
rect.Ymin /= font.getDivider();
|
||||
BufferedImage img = SHAPERECORD.shapeToImage(tags, 4, null, null, glyphs[entry.glyphIndex].shapeRecords, textColor);
|
||||
g.setTransform(AffineTransform.getScaleInstance(textHeight / 1000f / 20, textHeight / 1000f / 20));
|
||||
g.drawImage(img, x, y + rect.Ymin, null);
|
||||
x += entry.glyphAdvance * 1000 / textHeight;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.Helper;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
@@ -30,7 +31,15 @@ import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -52,7 +61,7 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag {
|
||||
public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, DrawableTag {
|
||||
|
||||
public int characterID;
|
||||
public RECT textBounds;
|
||||
@@ -437,4 +446,56 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters) {
|
||||
RECT bound = getBounds();
|
||||
BufferedImage ret = new BufferedImage(bound.Xmax / 20, bound.Ymax / 20, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
Color textColor = new Color(0, 0, 0);
|
||||
FontTag font = null;
|
||||
int textHeight = 12;
|
||||
int x = bound.Xmin;
|
||||
int y = 0;
|
||||
Graphics2D g = (Graphics2D) ret.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);
|
||||
SHAPE glyphs[] = new SHAPE[0];
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
if (rec.styleFlagsHasColor) {
|
||||
textColor = rec.textColor.toColor();
|
||||
}
|
||||
if (rec.styleFlagsHasFont) {
|
||||
font = (FontTag) characters.get(rec.fontId);
|
||||
glyphs = font.getGlyphShapeTable();
|
||||
textHeight = rec.textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasXOffset) {
|
||||
x = rec.xOffset * 1000 / textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasYOffset) {
|
||||
y = rec.yOffset * 1000 / textHeight;
|
||||
}
|
||||
|
||||
for (GLYPHENTRY entry : rec.glyphEntries) {
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs[entry.glyphIndex].shapeRecords);
|
||||
rect.Xmax /= font.getDivider();
|
||||
rect.Xmin /= font.getDivider();
|
||||
rect.Ymax /= font.getDivider();
|
||||
rect.Ymin /= font.getDivider();
|
||||
BufferedImage img = SHAPERECORD.shapeToImage(tags, 1, null, null, glyphs[entry.glyphIndex].shapeRecords, textColor);
|
||||
g.setTransform(AffineTransform.getScaleInstance(textHeight / 1000f / 20, textHeight / 1000f / 20));
|
||||
|
||||
g.drawImage(img, x, y + rect.Ymin, null);
|
||||
x += entry.glyphAdvance * 1000 / textHeight;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters) {
|
||||
return new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,5 @@ import java.util.HashMap;
|
||||
public interface BoundedTag {
|
||||
|
||||
public RECT getRect(HashMap<Integer, CharacterTag> characters);
|
||||
//public List<GeneralPath> getPaths(List<Tag> tags);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface ButtonTag {
|
||||
public interface ButtonTag extends DrawableTag {
|
||||
|
||||
public List<BUTTONRECORD> getRecords();
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface DrawableTag {
|
||||
|
||||
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters);
|
||||
|
||||
public Point getImagePos(HashMap<Integer, CharacterTag> characters);
|
||||
}
|
||||
@@ -45,4 +45,12 @@ public interface FontTag extends AloneTag {
|
||||
public boolean isBold();
|
||||
|
||||
public boolean isItalic();
|
||||
|
||||
public int getDivider();
|
||||
|
||||
public int getAscent();
|
||||
|
||||
public int getDescent();
|
||||
|
||||
public int getLeading();
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface ShapeTag {
|
||||
public interface ShapeTag extends DrawableTag {
|
||||
|
||||
public SHAPEWITHSTYLE getShapes();
|
||||
|
||||
@@ -33,5 +33,5 @@ public interface ShapeTag {
|
||||
|
||||
public int getShapeNum();
|
||||
|
||||
public BufferedImage toImage(List<Tag> tags);
|
||||
public List<GeneralPath> getPaths(List<Tag> tags);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.filters.Filtering;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Defines a transform that can be applied to the color space of a graphic
|
||||
* object.
|
||||
@@ -57,4 +60,8 @@ public class CXFORM {
|
||||
* Blue addition value
|
||||
*/
|
||||
public int blueAddTerm;
|
||||
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return Filtering.colorEffect(src, hasAddTerms ? redAddTerm : 0, hasAddTerms ? greenAddTerm : 0, hasAddTerms ? blueAddTerm : 0, 0, hasMultTerms ? redMultTerm : 255, hasMultTerms ? greenMultTerm : 255, hasMultTerms ? blueMultTerm : 255, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.filters.Filtering;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Defines a transform that can be applied to the color space of a graphic
|
||||
* object.
|
||||
@@ -65,4 +68,8 @@ public class CXFORMWITHALPHA {
|
||||
*/
|
||||
public int alphaAddTerm;
|
||||
public int nbits;
|
||||
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return Filtering.colorEffect(src, hasAddTerms ? redAddTerm : 0, hasAddTerms ? greenAddTerm : 0, hasAddTerms ? blueAddTerm : 0, hasAddTerms ? alphaAddTerm : 0, hasMultTerms ? redMultTerm : 255, hasMultTerms ? greenMultTerm : 255, hasMultTerms ? blueMultTerm : 255, hasMultTerms ? alphaMultTerm : 255);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,23 @@ public class MATRIX implements Serializable {
|
||||
public int bitsRotate;
|
||||
public int bitsScale;
|
||||
|
||||
public MATRIX() {
|
||||
}
|
||||
|
||||
public MATRIX(MATRIX m) {
|
||||
if (m == null) {
|
||||
return;
|
||||
}
|
||||
hasScale = m.hasScale;
|
||||
hasRotate = m.hasRotate;
|
||||
scaleX = m.scaleX;
|
||||
scaleY = m.scaleY;
|
||||
rotateSkew0 = m.rotateSkew0;
|
||||
rotateSkew1 = m.rotateSkew1;
|
||||
translateX = m.translateX;
|
||||
translateY = m.translateY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[MATRIX scale:" + getScaleXFloat() + "," + getScaleYFloat() + ", rotate:" + getRotateSkew0Float() + "," + getRotateSkew1Float() + ", translate:" + translateX + "," + translateY + "]";
|
||||
|
||||
@@ -64,10 +64,10 @@ public class RECT {
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return Xmax - Xmin;
|
||||
return (Xmax - Xmin) < 0 ? 0 : Xmax - Xmin;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return Ymax - Ymin;
|
||||
return (Ymax - Ymin) < 0 ? 0 : Ymax - Ymin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents 24-bit red, green, blue value
|
||||
*
|
||||
@@ -60,4 +62,14 @@ public class RGB {
|
||||
}
|
||||
return "#" + rh + gh + bh;
|
||||
}
|
||||
|
||||
public Color toColor() {
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
public RGB(Color color) {
|
||||
this.red = color.getRed();
|
||||
this.green = color.getGreen();
|
||||
this.blue = color.getBlue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents 32-bit red, green, blue and alpha value
|
||||
*
|
||||
@@ -87,6 +89,17 @@ public class RGBA {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public RGBA(Color color) {
|
||||
this.red = color.getRed();
|
||||
this.green = color.getGreen();
|
||||
this.blue = color.getBlue();
|
||||
this.alpha = color.getAlpha();
|
||||
}
|
||||
|
||||
public RGBA() {
|
||||
}
|
||||
|
||||
public Color toColor() {
|
||||
return new Color(red, green, blue, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class SHAPE implements NeedsCharacters {
|
||||
}
|
||||
|
||||
public BufferedImage toImage(int shapeNum, List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToImage(tags, shapeNum, null, null, numFillBits, numLineBits, shapeRecords);
|
||||
return SHAPERECORD.shapeToImage(tags, shapeNum, null, null,/* numFillBits, numLineBits, */ shapeRecords);
|
||||
}
|
||||
|
||||
public RECT getBounds() {
|
||||
|
||||
@@ -57,7 +57,7 @@ public class SHAPEWITHSTYLE implements NeedsCharacters {
|
||||
}
|
||||
|
||||
public BufferedImage toImage(int shapeNum, List<Tag> tags) {
|
||||
return SHAPERECORD.shapeToImage(tags, shapeNum, fillStyles, lineStyles, numFillBits, numLineBits, shapeRecords);
|
||||
return SHAPERECORD.shapeToImage(tags, shapeNum, fillStyles, lineStyles, /*numFillBits, numLineBits,*/ shapeRecords);
|
||||
}
|
||||
|
||||
public RECT getBounds() {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* The Bevel filter creates a smooth bevel on display list objects.
|
||||
@@ -80,4 +81,15 @@ public class BEVELFILTER extends FILTER {
|
||||
public BEVELFILTER() {
|
||||
super(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
return Filtering.bevel(src, (int) blurX, (int) blurY, strength, type, highlightColor.toColor(), shadowColor.toColor(), (int) (angle * 180 / Math.PI), (float) distance, knockout, passes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Blur filter based on a sub-pixel precise median filter
|
||||
*
|
||||
@@ -39,4 +41,9 @@ public class BLURFILTER extends FILTER {
|
||||
public BLURFILTER() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return Filtering.blur(src, (int) blurX, (int) blurY, passes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.types.filters;
|
||||
|
||||
import java.awt.Composite;
|
||||
import java.awt.CompositeContext;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RasterFormatException;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public final class BlendComposite implements Composite {
|
||||
|
||||
public enum BlendingMode {
|
||||
|
||||
LAYER, //TODO!
|
||||
DARKEN,
|
||||
MULTIPLY,
|
||||
LIGHTEN,
|
||||
SCREEN,
|
||||
OVERLAY,
|
||||
HARD_LIGHT,
|
||||
ADD,
|
||||
SUBTRACT,
|
||||
DIFFERENCE,
|
||||
INVERT,
|
||||
ALPHA,
|
||||
ERASE
|
||||
}
|
||||
public static final BlendComposite Alpha = new BlendComposite(BlendingMode.ALPHA);
|
||||
public static final BlendComposite Erase = new BlendComposite(BlendingMode.ERASE);
|
||||
public static final BlendComposite Invert = new BlendComposite(BlendingMode.INVERT);
|
||||
public static final BlendComposite Multiply = new BlendComposite(BlendingMode.MULTIPLY);
|
||||
public static final BlendComposite Screen = new BlendComposite(BlendingMode.SCREEN);
|
||||
public static final BlendComposite Darken = new BlendComposite(BlendingMode.DARKEN);
|
||||
public static final BlendComposite Lighten = new BlendComposite(BlendingMode.LIGHTEN);
|
||||
public static final BlendComposite Overlay = new BlendComposite(BlendingMode.OVERLAY);
|
||||
public static final BlendComposite HardLight = new BlendComposite(BlendingMode.HARD_LIGHT);
|
||||
public static final BlendComposite Difference = new BlendComposite(BlendingMode.DIFFERENCE);
|
||||
public static final BlendComposite Add = new BlendComposite(BlendingMode.ADD);
|
||||
public static final BlendComposite Subtract = new BlendComposite(BlendingMode.SUBTRACT);
|
||||
private final float alpha;
|
||||
private final BlendingMode mode;
|
||||
|
||||
private BlendComposite(BlendingMode mode) {
|
||||
this(mode, 1.0f);
|
||||
}
|
||||
|
||||
private BlendComposite(BlendingMode mode, float alpha) {
|
||||
this.mode = mode;
|
||||
|
||||
if (alpha < 0.0f || alpha > 1.0f) {
|
||||
throw new IllegalArgumentException(
|
||||
"alpha must be comprised between 0.0f and 1.0f");
|
||||
}
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the blending mode of this composite.</p>
|
||||
*
|
||||
* @return the blending mode used by this object
|
||||
*/
|
||||
public BlendingMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.floatToIntBits(alpha) * 31 + mode.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof BlendComposite)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlendComposite bc = (BlendComposite) obj;
|
||||
return mode == bc.mode && alpha == bc.alpha;
|
||||
}
|
||||
|
||||
private static boolean checkComponentsOrder(ColorModel cm) {
|
||||
if (cm instanceof DirectColorModel
|
||||
&& cm.getTransferType() == DataBuffer.TYPE_INT) {
|
||||
DirectColorModel directCM = (DirectColorModel) cm;
|
||||
|
||||
return directCM.getRedMask() == 0x00FF0000
|
||||
&& directCM.getGreenMask() == 0x0000FF00
|
||||
&& directCM.getBlueMask() == 0x000000FF
|
||||
&& (directCM.getNumComponents() != 4
|
||||
|| directCM.getAlphaMask() == 0xFF000000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeContext createContext(ColorModel srcColorModel,
|
||||
ColorModel dstColorModel,
|
||||
RenderingHints hints) {
|
||||
if (!checkComponentsOrder(srcColorModel)
|
||||
|| !checkComponentsOrder(dstColorModel)) {
|
||||
throw new RasterFormatException("Incompatible color models");
|
||||
}
|
||||
|
||||
return new BlendingContext(this);
|
||||
}
|
||||
|
||||
private static final class BlendingContext implements CompositeContext {
|
||||
|
||||
private final Blender blender;
|
||||
private final BlendComposite composite;
|
||||
|
||||
private BlendingContext(BlendComposite composite) {
|
||||
this.composite = composite;
|
||||
this.blender = Blender.getBlenderFor(composite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||
int width = Math.min(src.getWidth(), dstIn.getWidth());
|
||||
int height = Math.min(src.getHeight(), dstIn.getHeight());
|
||||
|
||||
float alpha = composite.getAlpha();
|
||||
|
||||
int[] result = new int[4];
|
||||
int[] srcPixel = new int[4];
|
||||
int[] dstPixel = new int[4];
|
||||
int[] srcPixels = new int[width];
|
||||
int[] dstPixels = new int[width];
|
||||
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
src.getDataElements(0, y, width, 1, srcPixels);
|
||||
dstIn.getDataElements(0, y, width, 1, dstPixels);
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = srcPixels[x];
|
||||
srcPixel[0] = (pixel >> 16) & 0xFF;
|
||||
srcPixel[1] = (pixel >> 8) & 0xFF;
|
||||
srcPixel[2] = (pixel) & 0xFF;
|
||||
srcPixel[3] = (pixel >> 24) & 0xFF;
|
||||
|
||||
pixel = dstPixels[x];
|
||||
dstPixel[0] = (pixel >> 16) & 0xFF;
|
||||
dstPixel[1] = (pixel >> 8) & 0xFF;
|
||||
dstPixel[2] = (pixel) & 0xFF;
|
||||
dstPixel[3] = (pixel >> 24) & 0xFF;
|
||||
|
||||
blender.blend(srcPixel, dstPixel, result);
|
||||
|
||||
dstPixels[x] = ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24
|
||||
| ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16
|
||||
| ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8
|
||||
| (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;
|
||||
}
|
||||
dstOut.setDataElements(0, y, width, 1, dstPixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class Blender {
|
||||
|
||||
public abstract void blend(int[] src, int[] dst, int[] result);
|
||||
|
||||
public static Blender getBlenderFor(BlendComposite composite) {
|
||||
switch (composite.getMode()) {
|
||||
case ADD:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = Math.min(255, src[0] + dst[0]);
|
||||
result[1] = Math.min(255, src[1] + dst[1]);
|
||||
result[2] = Math.min(255, src[2] + dst[2]);
|
||||
result[3] = Math.min(255, src[3] + dst[3]);
|
||||
}
|
||||
};
|
||||
case INVERT:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = 255 - dst[0];
|
||||
result[1] = 255 - dst[1];
|
||||
result[2] = 255 - dst[2];
|
||||
result[3] = src[3];
|
||||
}
|
||||
};
|
||||
case ALPHA:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = src[0];
|
||||
result[1] = src[1];
|
||||
result[2] = src[2];
|
||||
result[3] = dst[3]; //?
|
||||
}
|
||||
};
|
||||
case ERASE:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = src[0];
|
||||
result[1] = src[1];
|
||||
result[2] = src[2];
|
||||
result[3] = 255 - dst[3]; //?
|
||||
}
|
||||
};
|
||||
|
||||
case DARKEN:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = Math.min(src[0], dst[0]);
|
||||
result[1] = Math.min(src[1], dst[1]);
|
||||
result[2] = Math.min(src[2], dst[2]);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
case DIFFERENCE:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = Math.abs(dst[0] - src[0]);
|
||||
result[1] = Math.abs(dst[1] - src[1]);
|
||||
result[2] = Math.abs(dst[2] - src[2]);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
|
||||
case HARD_LIGHT:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = src[0] < 128 ? dst[0] * src[0] >> 7
|
||||
: 255 - ((255 - src[0]) * (255 - dst[0]) >> 7);
|
||||
result[1] = src[1] < 128 ? dst[1] * src[1] >> 7
|
||||
: 255 - ((255 - src[1]) * (255 - dst[1]) >> 7);
|
||||
result[2] = src[2] < 128 ? dst[2] * src[2] >> 7
|
||||
: 255 - ((255 - src[2]) * (255 - dst[2]) >> 7);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
|
||||
case LIGHTEN:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = Math.max(src[0], dst[0]);
|
||||
result[1] = Math.max(src[1], dst[1]);
|
||||
result[2] = Math.max(src[2], dst[2]);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
case MULTIPLY:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = (src[0] * dst[0]) >> 8;
|
||||
result[1] = (src[1] * dst[1]) >> 8;
|
||||
result[2] = (src[2] * dst[2]) >> 8;
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
|
||||
case OVERLAY:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = dst[0] < 128 ? dst[0] * src[0] >> 7
|
||||
: 255 - ((255 - dst[0]) * (255 - src[0]) >> 7);
|
||||
result[1] = dst[1] < 128 ? dst[1] * src[1] >> 7
|
||||
: 255 - ((255 - dst[1]) * (255 - src[1]) >> 7);
|
||||
result[2] = dst[2] < 128 ? dst[2] * src[2] >> 7
|
||||
: 255 - ((255 - dst[2]) * (255 - src[2]) >> 7);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
case SCREEN:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8);
|
||||
result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8);
|
||||
result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
|
||||
case SUBTRACT:
|
||||
return new Blender() {
|
||||
@Override
|
||||
public void blend(int[] src, int[] dst, int[] result) {
|
||||
result[0] = Math.max(0, src[0] + dst[0] - 256);
|
||||
result[1] = Math.max(0, src[1] + dst[1] - 256);
|
||||
result[2] = Math.max(0, src[2] + dst[2] - 256);
|
||||
result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
|
||||
}
|
||||
};
|
||||
}
|
||||
throw new IllegalArgumentException("Blender not implemented for "
|
||||
+ composite.getMode().name());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Applies a color transformation on the pixels of a display list object
|
||||
*
|
||||
@@ -34,4 +36,16 @@ public class COLORMATRIXFILTER extends FILTER {
|
||||
public COLORMATRIXFILTER() {
|
||||
super(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
float matrix2[][] = new float[4][4];
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int x = 0; x < 4; x++) {
|
||||
matrix2[y][x] = matrix[y * 5 + x];
|
||||
}
|
||||
}
|
||||
//matrix2[4][4] = 1;
|
||||
return Filtering.colorMatrix(src, matrix2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Two-dimensional discrete convolution filter.
|
||||
@@ -64,4 +65,17 @@ public class CONVOLUTIONFILTER extends FILTER {
|
||||
public CONVOLUTIONFILTER() {
|
||||
super(5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
int height = matrix.length;
|
||||
int width = matrix[0].length;
|
||||
float matrix2[] = new float[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
matrix2[y * width + x] = matrix[x][y] * divisor + bias;
|
||||
}
|
||||
}
|
||||
return Filtering.convolution(src, matrix2, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Drop shadow filter based on the same median filter as the blur filter
|
||||
@@ -72,4 +73,9 @@ public class DROPSHADOWFILTER extends FILTER {
|
||||
public DROPSHADOWFILTER() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return Filtering.dropShadow(src, (int) blurX, (int) blurY, (int) (angle * 180 / Math.PI), distance, dropShadowColor.toColor(), innerShadow, passes, strength, knockout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Bitmap filter
|
||||
*
|
||||
@@ -36,4 +38,8 @@ public class FILTER {
|
||||
public FILTER(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2013 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.types.filters;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.LinearGradientPaint;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BandCombineOp;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ConvolveOp;
|
||||
import java.awt.image.Kernel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Filtering {
|
||||
|
||||
public static final int INNER = 1;
|
||||
public static final int OUTER = 2;
|
||||
public static final int FULL = 3;
|
||||
|
||||
private static void boxBlurHorizontal(int[] pixels, int mask[], int w, int h, int radius) {
|
||||
int index = 0;
|
||||
int[] newColors = new int[w];
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
int hits = 0;
|
||||
long r = 0;
|
||||
long g = 0;
|
||||
long b = 0;
|
||||
long a = 0;
|
||||
for (int x = -radius; x < w; x++) {
|
||||
int oldPixel = x - radius - 1;
|
||||
if (oldPixel >= 0) {
|
||||
|
||||
int color = pixels[index + oldPixel];
|
||||
if ((mask == null) || (((mask[index + oldPixel] >> 24) & 0xff) > 0)) {
|
||||
if (color != 0) {
|
||||
a -= (color >> 24) & 0xff;
|
||||
r -= ((color >> 16) & 0xff);
|
||||
g -= ((color >> 8) & 0xff);
|
||||
b -= ((color) & 0xff);
|
||||
|
||||
}
|
||||
hits--;
|
||||
}
|
||||
}
|
||||
|
||||
int newPixel = x + radius;
|
||||
if (newPixel < w) {
|
||||
int color = pixels[index + newPixel];
|
||||
if ((mask == null) || (((mask[index + newPixel] >> 24) & 0xff) > 0)) {
|
||||
if (color != 0) {
|
||||
a += (color >> 24) & 0xff;
|
||||
r += ((color >> 16) & 0xff);
|
||||
g += ((color >> 8) & 0xff);
|
||||
b += ((color) & 0xff);
|
||||
}
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
|
||||
if (x >= 0) {
|
||||
if ((mask == null) || (((mask[index + x] >> 24) & 0xff) > 0)) {
|
||||
if (hits == 0) {
|
||||
newColors[x] = 0;
|
||||
} else {
|
||||
newColors[x] = new Color((int) (r / hits) & 0xff, (int) (g / hits) & 0xff, (int) (b / hits) & 0xff, (int) (a / hits)).getRGB();
|
||||
|
||||
}
|
||||
} else {
|
||||
newColors[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
pixels[index + x] = newColors[x];
|
||||
}
|
||||
|
||||
index += w;
|
||||
}
|
||||
}
|
||||
|
||||
private static void boxBlurVertical(int[] pixels, int mask[], int w, int h, int radius) {
|
||||
int[] newColors = new int[h];
|
||||
int oldPixelOffset = -(radius + 1) * w;
|
||||
int newPixelOffset = (radius) * w;
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
int hits = 0;
|
||||
long r = 0;
|
||||
long g = 0;
|
||||
long b = 0;
|
||||
long a = 0;
|
||||
int index = -radius * w + x;
|
||||
for (int y = -radius; y < h; y++) {
|
||||
int oldPixel = y - radius - 1;
|
||||
if (oldPixel >= 0) {
|
||||
int color = pixels[index + oldPixelOffset];
|
||||
if ((mask == null) || (((mask[index + oldPixelOffset] >> 24) & 0xff) > 0)) {
|
||||
if (color != 0) {
|
||||
a -= (color >> 24) & 0xff;
|
||||
r -= ((color >> 16) & 0xff);
|
||||
g -= ((color >> 8) & 0xff);
|
||||
b -= ((color) & 0xff);
|
||||
|
||||
}
|
||||
hits--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int newPixel = y + radius;
|
||||
if (newPixel < h) {
|
||||
if ((mask == null) || (((mask[index + newPixelOffset] >> 24) & 0xff) > 0)) {
|
||||
int color = pixels[index + newPixelOffset];
|
||||
if (color != 0) {
|
||||
a += (color >> 24) & 0xff;
|
||||
r += ((color >> 16) & 0xff);
|
||||
g += ((color >> 8) & 0xff);
|
||||
b += ((color) & 0xff);
|
||||
|
||||
|
||||
}
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
|
||||
if (y >= 0) {
|
||||
if ((mask == null) || (((mask[y * w + x] >> 24) & 0xff) > 0)) {
|
||||
if (hits == 0) {
|
||||
newColors[y] = 0;
|
||||
} else {
|
||||
newColors[y] = new Color((int) (r / hits) & 0xff, (int) (g / hits) & 0xff, (int) (b / hits) & 0xff, (int) (a / hits) & 0xff).getRGB();
|
||||
}
|
||||
} else {
|
||||
newColors[y] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
index += w;
|
||||
}
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
pixels[y * w + x] = newColors[y];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void premultiply(int p[]) {
|
||||
int length = p.length;
|
||||
int offset = 0;
|
||||
length += offset;
|
||||
for (int i = offset; i < length; i++) {
|
||||
int rgb = p[i];
|
||||
int a = rgb >> 24 & 0xff;
|
||||
int r = rgb >> 16 & 0xff;
|
||||
int g = rgb >> 8 & 0xff;
|
||||
int b = rgb & 0xff;
|
||||
float f = (float) a * 0.003921569F;
|
||||
r = (int) ((float) r * f);
|
||||
g = (int) ((float) g * f);
|
||||
b = (int) ((float) b * f);
|
||||
p[i] = a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
}
|
||||
|
||||
private static void unpremultiply(int p[]) {
|
||||
int length = p.length;
|
||||
int offset = 0;
|
||||
length += offset;
|
||||
for (int i = offset; i < length; i++) {
|
||||
int rgb = p[i];
|
||||
int a = rgb >> 24 & 0xff;
|
||||
int r = rgb >> 16 & 0xff;
|
||||
int g = rgb >> 8 & 0xff;
|
||||
int b = rgb & 0xff;
|
||||
if (a == 0 || a == 255) {
|
||||
continue;
|
||||
}
|
||||
float f = 255F / (float) a;
|
||||
r = (int) ((float) r * f);
|
||||
g = (int) ((float) g * f);
|
||||
b = (int) ((float) b * f);
|
||||
if (r > 255) {
|
||||
r = 255;
|
||||
}
|
||||
if (g > 255) {
|
||||
g = 255;
|
||||
}
|
||||
if (b > 255) {
|
||||
b = 255;
|
||||
}
|
||||
p[i] = a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage blur(BufferedImage src, int hRadius, int vRadius, int iterations) {
|
||||
return blur(src, hRadius, vRadius, iterations, null);
|
||||
}
|
||||
|
||||
private static BufferedImage blur(BufferedImage src, int hRadius, int vRadius, int iterations, int[] mask) {
|
||||
int width = src.getWidth();
|
||||
int height = src.getHeight();
|
||||
|
||||
BufferedImage dst = new BufferedImage(width, height, src.getType());
|
||||
|
||||
int[] inPixels = getRGB(src, 0, 0, width, height);
|
||||
premultiply(inPixels);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
boxBlurHorizontal(inPixels, mask, width, height, hRadius / 2);
|
||||
boxBlurVertical(inPixels, mask, width, height, vRadius / 2);
|
||||
}
|
||||
unpremultiply(inPixels);
|
||||
setRGB(dst, 0, 0, width, height, inPixels);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static BufferedImage bevel(BufferedImage src, int blurX, int blurY, float strength, int type, Color highlightColor, Color shadowColor, float angle, float distance, boolean knockout, int iterations) {
|
||||
return gradientBevel(src, new Color[]{
|
||||
highlightColor,
|
||||
new Color(highlightColor.getRed(), highlightColor.getGreen(), highlightColor.getBlue(), 0),
|
||||
new Color(shadowColor.getRed(), shadowColor.getGreen(), shadowColor.getBlue(), 0),
|
||||
shadowColor
|
||||
}, new float[]{0, 127f / 255f, 128f / 255f, 1}, blurX, blurY, strength, type, angle, distance, knockout, iterations);
|
||||
}
|
||||
|
||||
public static BufferedImage gradientBevel(BufferedImage src, Color[] colors, float ratios[], int blurX, int blurY, float strength, int type, float angle, float distance, boolean knockout, int iterations) {
|
||||
int width = src.getWidth();
|
||||
int height = src.getHeight();
|
||||
BufferedImage retImg = new BufferedImage(width, height, src.getType());
|
||||
if (type == FULL) {
|
||||
BufferedImage partIn = gradientBevel(src, colors, ratios, blurX, blurY, strength, INNER, angle, distance, true, iterations);
|
||||
BufferedImage partOut = gradientBevel(src, colors, ratios, blurX, blurY, strength, OUTER, angle, distance, true, iterations);
|
||||
Graphics2D g = (Graphics2D) retImg.getGraphics();
|
||||
g.drawImage(partIn, 0, 0, null);
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.drawImage(partOut, 0, 0, null);
|
||||
} else {
|
||||
boolean inner = type == INNER;
|
||||
|
||||
int srcPixels[] = getRGB(src, 0, 0, width, height);
|
||||
BufferedImage gradient = new BufferedImage(512, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D gg = (Graphics2D) gradient.getGraphics();
|
||||
Point pnt1 = new Point(0, 0);
|
||||
Point pnt2 = new Point(512, 0);
|
||||
gg.setPaint(new LinearGradientPaint(inner ? pnt1 : pnt2, inner ? pnt2 : pnt1, ratios, colors));
|
||||
gg.fill(new Rectangle(512, 1));
|
||||
int gradientPixels[] = getRGB(gradient, 0, 0, gradient.getWidth(), gradient.getHeight());
|
||||
|
||||
BufferedImage hilightIm = dropShadow(src, blurX, blurY, angle, distance, Color.black, inner, iterations, strength, true);//new DropShadowFilter(blurX, blurY, strength, inner ? highlightColor : shadowColor, angle, distance, inner, true, iterations).filter(src);
|
||||
BufferedImage shadowIm = dropShadow(src, blurX, blurY, angle + 180, distance, Color.black, inner, iterations, strength, true); //new DropShadowFilter(blurX, blurY, strength, inner ? shadowColor : highlightColor, angle + 180, distance, inner, true, iterations).filter(src);
|
||||
int hilight[] = getRGB(hilightIm, 0, 0, width, height);
|
||||
int shadow[] = getRGB(shadowIm, 0, 0, width, height);
|
||||
for (int i = 0; i < srcPixels.length; i++) {
|
||||
int ha = (hilight[i] >> 24) & 0xff;
|
||||
int sa = (shadow[i] >> 24) & 0xff;
|
||||
hilight[i] = gradientPixels[255 - ha];
|
||||
shadow[i] = gradientPixels[256 + sa];
|
||||
}
|
||||
for (int i = 0; i < srcPixels.length; i++) {
|
||||
int ah = (hilight[i] >> 24) & 0xff;
|
||||
int as = (shadow[i] >> 24) & 0xff;
|
||||
int ao = (srcPixels[i] >> 24) & 0xff;
|
||||
if ((ao == 0) || ((ah > 0) && (as > 0))) {
|
||||
hilight[i] = (hilight[i] & 0x00ffffff) + ((255 - as) << 24);
|
||||
shadow[i] = (shadow[i] & 0x00ffffff) + ((255 - ah) << 24);
|
||||
}
|
||||
}
|
||||
setRGB(shadowIm, 0, 0, width, height, shadow);
|
||||
setRGB(hilightIm, 0, 0, width, height, hilight);
|
||||
shadow = getRGB(shadowIm, 0, 0, width, height);
|
||||
hilight = getRGB(hilightIm, 0, 0, width, height);
|
||||
int ret[] = new int[width * height];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
int ah = (hilight[i] >> 24) & 0xff;
|
||||
int as = (shadow[i] >> 24) & 0xff;
|
||||
if (as >= ah) {
|
||||
ret[i] = (shadow[i] & 0x00ffffff) + ((as - ah) << 24);
|
||||
} else {
|
||||
ret[i] = (hilight[i] & 0x00ffffff) + ((ah - as) << 24);
|
||||
}
|
||||
}
|
||||
setRGB(retImg, 0, 0, width, height, ret);
|
||||
}
|
||||
if (!knockout) {
|
||||
Graphics2D g = (Graphics2D) retImg.getGraphics();
|
||||
g.setComposite(AlphaComposite.DstOver);
|
||||
g.drawImage(src, 0, 0, null);
|
||||
}
|
||||
return retImg;
|
||||
}
|
||||
|
||||
public static BufferedImage glow(BufferedImage src, int blurX, int blurY, float strength, Color color, boolean inner, boolean knockout, int iterations) {
|
||||
return dropShadow(src, blurX, blurY, 45, 0, color, inner, iterations, strength, knockout);
|
||||
}
|
||||
|
||||
public static BufferedImage dropShadow(BufferedImage src, int blurX, int blurY, float angle, double distance, Color color, boolean inner, int iterations, float strength, boolean knockout) {
|
||||
return gradientGlow(src, blurX, blurY, angle, distance, new Color[]{new Color(color.getRed(), color.getGreen(), color.getBlue(), 0), color}, new float[]{0, 1}, inner ? INNER : OUTER, iterations, strength, knockout);
|
||||
}
|
||||
|
||||
public static BufferedImage gradientGlow(BufferedImage src, int blurX, int blurY, float angle, double distance, Color colors[], float ratios[], int type, int iterations, float strength, boolean knockout) {
|
||||
int width = src.getWidth();
|
||||
int height = src.getHeight();
|
||||
BufferedImage retImg = new BufferedImage(width, height, src.getType());
|
||||
|
||||
if (type == FULL) {
|
||||
BufferedImage partIn = gradientGlow(src, blurX, blurY, angle, distance, colors, ratios, INNER, iterations, strength, true);
|
||||
BufferedImage partOut = gradientGlow(src, blurX, blurY, angle, distance, colors, ratios, OUTER, iterations, strength, true);
|
||||
Graphics2D g = (Graphics2D) retImg.getGraphics();
|
||||
g.drawImage(partIn, 0, 0, null);
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.drawImage(partOut, 0, 0, null);
|
||||
} else {
|
||||
boolean inner = type == INNER;
|
||||
|
||||
BufferedImage gradient = new BufferedImage(256, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D gg = (Graphics2D) gradient.getGraphics();
|
||||
gg.setPaint(new LinearGradientPaint(new Point(0, 0), new Point(256, 0), ratios, colors));
|
||||
gg.fill(new Rectangle(256, 1));
|
||||
int gradientPixels[] = getRGB(gradient, 0, 0, gradient.getWidth(), gradient.getHeight());
|
||||
|
||||
|
||||
double angleRad = angle / 180 * Math.PI;
|
||||
double moveX = (distance * Math.cos(angleRad));
|
||||
double moveY = (distance * Math.sin(angleRad));
|
||||
|
||||
int srcPixels[] = getRGB(src, 0, 0, width, height);
|
||||
int revPixels[] = new int[srcPixels.length];
|
||||
for (int i = 0; i < srcPixels.length; i++) {
|
||||
int alpha = (srcPixels[i] >> 24) & 0xff;
|
||||
alpha = 255 - alpha;
|
||||
revPixels[i] = (srcPixels[i] & 0x00ffffff) + (alpha << 24);
|
||||
}
|
||||
int shadow[] = new int[srcPixels.length];
|
||||
for (int i = 0; i < srcPixels.length; i++) {
|
||||
int alpha = (srcPixels[i] >> 24) & 0xff;
|
||||
if (inner) {
|
||||
alpha = 255 - alpha;
|
||||
}
|
||||
shadow[i] = 0 + (Math.round(alpha * strength) << 24);
|
||||
}
|
||||
Color colorFirst = Color.black;
|
||||
Color colorAlpha = new Color(0, 0, 0, 0);
|
||||
shadow = moveRGB(width, height, shadow, moveX, moveY, inner ? colorFirst : colorAlpha);
|
||||
|
||||
|
||||
|
||||
|
||||
setRGB(retImg, 0, 0, width, height, shadow);
|
||||
|
||||
|
||||
retImg = blur(retImg, blurX, blurY, iterations, inner ? srcPixels : revPixels);//new BoxBlurFilter(blurX, blurY, iterations, inner ? srcPixels : revPixels).filter(ret);
|
||||
shadow = getRGB(retImg, 0, 0, width, height);
|
||||
|
||||
|
||||
for (int i = 0; i < shadow.length; i++) {
|
||||
int a = (shadow[i] >> 24) & 0xff;
|
||||
shadow[i] = gradientPixels[a];
|
||||
}
|
||||
|
||||
for (int i = 0; i < shadow.length; i++) {
|
||||
int srcA = (srcPixels[i] >> 24) & 0xff;
|
||||
if (!inner) {
|
||||
srcA = 255 - srcA;
|
||||
}
|
||||
int shadA = (shadow[i] >> 24) & 0xff;
|
||||
shadow[i] = (shadow[i] & 0x00ffffff) + (Math.min(srcA, shadA) << 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
setRGB(retImg, 0, 0, width, height, shadow);
|
||||
}
|
||||
if (!knockout) {
|
||||
Graphics2D g = (Graphics2D) retImg.getGraphics();
|
||||
//g.setComposite(inner ? AlphaComposite.DstOver : AlphaComposite.SrcOver);
|
||||
g.setComposite(AlphaComposite.DstOver);
|
||||
g.drawImage(src, 0, 0, null);
|
||||
}
|
||||
|
||||
return retImg;
|
||||
}
|
||||
|
||||
public static int[] getRGB(BufferedImage image, int x, int y, int width, int height) {
|
||||
int type = image.getType();
|
||||
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
|
||||
return (int[]) image.getRaster().getDataElements(x, y, width, height, null);
|
||||
}
|
||||
return image.getRGB(x, y, width, height, null, 0, width);
|
||||
}
|
||||
|
||||
public static void setRGB(BufferedImage image, int x, int y, int width, int height, int[] pixels) {
|
||||
int type = image.getType();
|
||||
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
|
||||
image.getRaster().setDataElements(x, y, width, height, pixels);
|
||||
} else {
|
||||
image.setRGB(x, y, width, height, pixels, 0, width);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] moveRGB(int width, int height, int rgb[], double deltaX, double deltaY, Color fill) {
|
||||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
setRGB(img, 0, 0, width, height, rgb);
|
||||
BufferedImage retImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = (Graphics2D) retImg.getGraphics();
|
||||
g.setPaint(fill);
|
||||
g.fillRect(0, 0, width, height);
|
||||
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(AffineTransform.getTranslateInstance(deltaX, deltaY));
|
||||
g.setComposite(AlphaComposite.Src);
|
||||
g.drawImage(img, 0, 0, null);
|
||||
return getRGB(retImg, 0, 0, width, height);
|
||||
}
|
||||
|
||||
public static BufferedImage convolution(BufferedImage src, float matrix[], int w, int h) {
|
||||
BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
|
||||
BufferedImageOp op = new ConvolveOp(new Kernel(w, h, matrix), ConvolveOp.EDGE_ZERO_FILL, new RenderingHints(null));
|
||||
op.filter(src, dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static BufferedImage colorMatrix(BufferedImage src, float[][] matrix) {
|
||||
BandCombineOp changeColors = new BandCombineOp(matrix, new RenderingHints(null));
|
||||
Raster sourceRaster = src.getRaster();
|
||||
WritableRaster displayRaster = sourceRaster.createCompatibleWritableRaster();
|
||||
changeColors.filter(sourceRaster, displayRaster);
|
||||
return new BufferedImage(src.getColorModel(), displayRaster, true, null);
|
||||
}
|
||||
|
||||
private static int cut(double val) {
|
||||
int i = (int) val;
|
||||
if (i < 0) {
|
||||
i = 0;
|
||||
}
|
||||
if (i > 255) {
|
||||
i = 255;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static BufferedImage colorEffect(BufferedImage src,
|
||||
int redAddTerm, int greenAddTerm, int blueAddTerm, int alphaAddTerm,
|
||||
int redMultTerm, int greenMultTerm, int blueMultTerm, int alphaMultTerm) {
|
||||
BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
|
||||
int rgb[] = getRGB(src, 0, 0, src.getWidth(), src.getHeight());
|
||||
for (int i = 0; i < rgb.length; i++) {
|
||||
int a = (rgb[i] >> 24) & 0xff;
|
||||
int r = (rgb[i] >> 16) & 0xff;
|
||||
int g = (rgb[i] >> 8) & 0xff;
|
||||
int b = (rgb[i]) & 0xff;
|
||||
r = Math.max(0, Math.min(((r * redMultTerm) / 256) + redAddTerm, 255));
|
||||
g = Math.max(0, Math.min(((g * greenMultTerm) / 256) + greenAddTerm, 255));
|
||||
b = Math.max(0, Math.min(((b * blueMultTerm) / 256) + blueAddTerm, 255));
|
||||
a = Math.max(0, Math.min(((a * alphaMultTerm) / 256) + alphaAddTerm, 255));
|
||||
rgb[i] = (a << 24) | (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
setRGB(dst, 0, 0, src.getWidth(), src.getHeight(), rgb);
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Glow filter
|
||||
@@ -64,4 +65,9 @@ public class GLOWFILTER extends FILTER {
|
||||
public GLOWFILTER() {
|
||||
super(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
return Filtering.glow(src, (int) blurX, (int) blurY, strength, glowColor.toColor(), innerGlow, knockout, passes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bevel filter with gradient instead of single color
|
||||
@@ -77,4 +81,29 @@ public class GRADIENTBEVELFILTER extends FILTER {
|
||||
public GRADIENTBEVELFILTER() {
|
||||
super(7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
List<Color> colors = new ArrayList<Color>();
|
||||
List<Float> ratios = new ArrayList<Float>();
|
||||
for (int i = 0; i < gradientColors.length; i++) {
|
||||
if ((i > 0) && (gradientRatio[i - 1] == gradientRatio[i])) {
|
||||
continue;
|
||||
}
|
||||
colors.add(gradientColors[i].toColor());
|
||||
ratios.add(gradientRatio[i] / 255f);
|
||||
}
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
|
||||
float ratiosAr[] = new float[ratios.size()];
|
||||
for (int i = 0; i < ratios.size(); i++) {
|
||||
ratiosAr[i] = ratios.get(i);
|
||||
}
|
||||
return Filtering.gradientBevel(src, colors.toArray(new Color[colors.size()]), ratiosAr, (int) blurX, (int) blurY, strength, type, (int) (angle * 180 / Math.PI), (float) distance, knockout, passes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Glow filter with gradient instead of single color
|
||||
@@ -80,4 +84,29 @@ public class GRADIENTGLOWFILTER extends FILTER {
|
||||
public GRADIENTGLOWFILTER() {
|
||||
super(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage apply(BufferedImage src) {
|
||||
List<Color> colors = new ArrayList<Color>();
|
||||
List<Float> ratios = new ArrayList<Float>();
|
||||
for (int i = 0; i < gradientColors.length; i++) {
|
||||
if ((i > 0) && (gradientRatio[i - 1] == gradientRatio[i])) {
|
||||
continue;
|
||||
}
|
||||
colors.add(gradientColors[i].toColor());
|
||||
ratios.add(gradientRatio[i] / 255f);
|
||||
}
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
|
||||
float ratiosAr[] = new float[ratios.size()];
|
||||
for (int i = 0; i < ratios.size(); i++) {
|
||||
ratiosAr[i] = ratios.get(i);
|
||||
}
|
||||
return Filtering.gradientGlow(src, (int) blurX, (int) blurY, (int) (angle * 180 / Math.PI), distance, colors.toArray(new Color[colors.size()]), ratiosAr, type, passes, strength, knockout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.shaperecords;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
@@ -37,7 +39,7 @@ public class CurvedEdgeRecord extends SHAPERECORD {
|
||||
|
||||
@Override
|
||||
public String toSWG(int oldX, int oldY) {
|
||||
return "Q " + twipToPixel(oldX + controlDeltaX) + " " + twipToPixel(oldY + controlDeltaY) + " " + twipToPixel(oldX + controlDeltaX + anchorDeltaX) + " " + twipToPixel(oldY + controlDeltaY + anchorDeltaY);
|
||||
return "Q " + SWF.twipToPixel(oldX + controlDeltaX) + " " + SWF.twipToPixel(oldY + controlDeltaY) + " " + SWF.twipToPixel(oldX + controlDeltaX + anchorDeltaX) + " " + SWF.twipToPixel(oldY + controlDeltaY + anchorDeltaY);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.shaperecords;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
@@ -25,7 +26,6 @@ import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
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.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
@@ -37,11 +37,13 @@ import java.awt.MultipleGradientPaint.CycleMethod;
|
||||
import java.awt.Point;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -54,9 +56,7 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
|
||||
public static float twipToPixel(int twip) {
|
||||
return ((float) twip) / 20.0f;
|
||||
}
|
||||
private static final float DESCALE = 20; //20
|
||||
|
||||
@Override
|
||||
public Set<Integer> getNeededCharacters() {
|
||||
@@ -75,7 +75,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
|
||||
public void draw(int startX, int startY, Graphics2D g, int shapeNum) {
|
||||
AffineTransform oldAf = g.getTransform();
|
||||
AffineTransform trans20 = AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0);
|
||||
AffineTransform trans20 = AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE);
|
||||
//g.setTransform(trans20);
|
||||
boolean ok = false;
|
||||
if (shapeNum == 4) {
|
||||
@@ -108,9 +108,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
break;
|
||||
}
|
||||
if (joinStyle == BasicStroke.JOIN_MITER) {
|
||||
g.setStroke(new BasicStroke(lineStyle2.width / 20, capStyle, joinStyle, lineStyle2.miterLimitFactor));
|
||||
g.setStroke(new BasicStroke(lineStyle2.width / DESCALE, capStyle, joinStyle, lineStyle2.miterLimitFactor));
|
||||
} else {
|
||||
g.setStroke(new BasicStroke(lineStyle2.width / 20, capStyle, joinStyle));
|
||||
g.setStroke(new BasicStroke(lineStyle2.width / DESCALE, capStyle, joinStyle));
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
if (lineStyle == null) {
|
||||
ok = false;
|
||||
} else {
|
||||
g.setStroke(new BasicStroke(lineStyle.width / 20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
|
||||
g.setStroke(new BasicStroke(lineStyle.width / DESCALE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
@@ -129,29 +129,11 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
g.setClip(null);
|
||||
}
|
||||
|
||||
private AffineTransform matrixToTransform(MATRIX mat) {
|
||||
return new AffineTransform(mat.getScaleXFloat(), mat.getRotateSkew0Float(),
|
||||
mat.getRotateSkew1Float(), mat.getScaleYFloat(),
|
||||
mat.translateX, mat.translateY);
|
||||
//mat.translateX,mat.translateY);
|
||||
/*AffineTransform move=AffineTransform.getTranslateInstance(mat.translateX, mat.translateY);
|
||||
AffineTransform rotate =AffineTransform.getRotateInstance(mat.getRotateSkew0Float(), mat.getRotateSkew1Float());
|
||||
AffineTransform scale=AffineTransform.getScaleInstance(mat.getScaleXFloat(), mat.getScaleYFloat());
|
||||
AffineTransform af=scale;
|
||||
AffineTransform scale20=AffineTransform.getScaleInstance(1/20.0, 1/20.0);
|
||||
|
||||
//af.concatenate(move);
|
||||
//af.concatenate(scale20);
|
||||
af.concatenate(rotate);
|
||||
af.concatenate(scale);
|
||||
return af;*/
|
||||
}
|
||||
|
||||
public void fill(List<Tag> tags, int startX, int startY, Graphics2D g, int shapeNum) {
|
||||
AffineTransform oldAf = g.getTransform();
|
||||
AffineTransform trans20 = AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0);
|
||||
AffineTransform trans20 = AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE);
|
||||
g.setTransform(trans20);
|
||||
int maxRepeat = 200;
|
||||
int maxRepeat = 10; //TODO:better handle gradient repeating
|
||||
boolean ok = false;
|
||||
switch (fillStyle0.fillStyleType) {
|
||||
case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP:
|
||||
@@ -170,9 +152,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
}
|
||||
if (image != null) {
|
||||
g.setClip(toGeneralPath(startX, startY));
|
||||
AffineTransform btrans = matrixToTransform(fillStyle0.bitmapMatrix);
|
||||
btrans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0));
|
||||
btrans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20));
|
||||
AffineTransform btrans = SWF.matrixToTransform(fillStyle0.bitmapMatrix);
|
||||
btrans.preConcatenate(AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE));
|
||||
btrans.preConcatenate(AffineTransform.getTranslateInstance(startX / DESCALE, startY / DESCALE));
|
||||
g.setTransform(btrans);
|
||||
BufferedImage img = image.getImage(tags);
|
||||
g.setPaint(new TexturePaint(img, new Rectangle(img.getWidth(), img.getHeight())));
|
||||
@@ -202,9 +184,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
GeneralPath focPath = toGeneralPath(startX, startY);
|
||||
g.fill(focPath);
|
||||
g.setClip(focPath);
|
||||
AffineTransform focTrans = matrixToTransform(fillStyle0.gradientMatrix);
|
||||
focTrans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0));
|
||||
focTrans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20));
|
||||
AffineTransform focTrans = SWF.matrixToTransform(fillStyle0.gradientMatrix);
|
||||
focTrans.preConcatenate(AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE));
|
||||
focTrans.preConcatenate(AffineTransform.getTranslateInstance(startX / DESCALE, startY / DESCALE));
|
||||
g.setTransform(focTrans);
|
||||
CycleMethod cm = CycleMethod.NO_CYCLE;
|
||||
if (fillStyle0.focalGradient.spreadMode == GRADIENT.SPREAD_PAD_MODE) {
|
||||
@@ -242,9 +224,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
GeneralPath path = toGeneralPath(startX, startY);
|
||||
g.fill(path);
|
||||
g.setClip(path);
|
||||
AffineTransform trans = matrixToTransform(fillStyle0.gradientMatrix);
|
||||
trans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0));
|
||||
trans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20));
|
||||
AffineTransform trans = SWF.matrixToTransform(fillStyle0.gradientMatrix);
|
||||
trans.preConcatenate(AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE));
|
||||
trans.preConcatenate(AffineTransform.getTranslateInstance(startX / DESCALE, startY / DESCALE));
|
||||
g.setTransform(trans);
|
||||
|
||||
CycleMethod cmRad = CycleMethod.NO_CYCLE;
|
||||
@@ -275,9 +257,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
GeneralPath pathLin = toGeneralPath(startX, startY);
|
||||
g.fill(pathLin);
|
||||
g.setClip(pathLin);
|
||||
AffineTransform transLin = matrixToTransform(fillStyle0.gradientMatrix);
|
||||
transLin.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0));
|
||||
transLin.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20));
|
||||
AffineTransform transLin = SWF.matrixToTransform(fillStyle0.gradientMatrix);
|
||||
transLin.preConcatenate(AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE));
|
||||
transLin.preConcatenate(AffineTransform.getTranslateInstance(startX / DESCALE, startY / DESCALE));
|
||||
g.setTransform(transLin);
|
||||
|
||||
CycleMethod cmLin = CycleMethod.NO_CYCLE;
|
||||
@@ -367,7 +349,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
params += " stroke=\"" + ((shapeNum >= 3) ? lineStyle.colorA.toHexRGB() : lineStyle.color.toHexRGB()) + "\"";
|
||||
}
|
||||
if (useLineStyle2 && lineStyle2 != null) {
|
||||
params += " stroke-width=\"" + twipToPixel(lineStyle2.width) + "\"" + (lineStyle2.color != null ? " stroke=\"" + lineStyle2.color.toHexRGB() + "\"" : "");
|
||||
params += " stroke-width=\"" + SWF.twipToPixel(lineStyle2.width) + "\"" + (lineStyle2.color != null ? " stroke=\"" + lineStyle2.color.toHexRGB() + "\"" : "");
|
||||
}
|
||||
String points = "";
|
||||
int x = 0;
|
||||
@@ -422,7 +404,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
return new RECT(min_x, max_x, min_y, max_y);
|
||||
}
|
||||
|
||||
private static List<Path> getPaths(RECT bounds, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List<SHAPERECORD> records) {
|
||||
private static List<Path> getPaths(RECT bounds, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, List<SHAPERECORD> records) {
|
||||
List<Path> paths = new ArrayList<Path>();
|
||||
Path path = new Path();
|
||||
int x = 0;
|
||||
@@ -441,18 +423,18 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
if (scr.stateNewStyles) {
|
||||
fillStyles = scr.fillStyles;
|
||||
lineStylesList = scr.lineStyles;
|
||||
numFillBits = scr.numFillBits;
|
||||
numLineBits = scr.numLineBits;
|
||||
//numFillBits = scr.numFillBits;
|
||||
//numLineBits = scr.numLineBits;
|
||||
}
|
||||
if (scr.stateFillStyle0) {
|
||||
if (scr.fillStyle0 == 0) {
|
||||
if ((scr.fillStyle0 == 0) || (fillStyles == null)) {
|
||||
path.fillStyle0 = null;
|
||||
} else {
|
||||
path.fillStyle0 = fillStyles.fillStyles[scr.fillStyle0 - 1];
|
||||
}
|
||||
}
|
||||
if (scr.stateFillStyle1) {
|
||||
if (scr.fillStyle1 == 0) {
|
||||
if ((scr.fillStyle1 == 0) || (fillStyles == null)) {
|
||||
path.fillStyle1 = null;
|
||||
} else {
|
||||
path.fillStyle1 = fillStyles.fillStyles[scr.fillStyle1 - 1];
|
||||
@@ -500,6 +482,9 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
paths.add(path);
|
||||
List<Path> paths2 = new ArrayList<Path>();
|
||||
for (Path p : paths) {
|
||||
if ((p.fillStyle0 == null) && (p.fillStyle1 == null)) {
|
||||
paths2.add(p);
|
||||
}
|
||||
if (p.fillStyle0 != null) {
|
||||
paths2.add(p);
|
||||
}
|
||||
@@ -570,32 +555,63 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
public static String shapeToSVG(int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List<SHAPERECORD> records) {
|
||||
String ret = "";
|
||||
RECT bounds = new RECT();
|
||||
List<Path> paths = getPaths(bounds, shapeNum, fillStyles, lineStylesList, numFillBits, numLineBits, records);
|
||||
List<Path> paths = getPaths(bounds, shapeNum, fillStyles, lineStylesList, /*numFillBits, numLineBits,*/ records);
|
||||
ret = "";
|
||||
for (Path p : paths) {
|
||||
ret += p.toSVG(shapeNum);
|
||||
}
|
||||
ret = "<?xml version='1.0' encoding='UTF-8' ?> \n"
|
||||
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
|
||||
+ "<svg width=\"" + (int) Math.ceil(twipToPixel(bounds.Xmax)) + "\"\n"
|
||||
+ " height=\"" + (int) Math.ceil(twipToPixel(bounds.Ymax)) + "\"\n"
|
||||
+ " viewBox=\"0 0 " + (int) Math.ceil(twipToPixel(bounds.Xmax)) + " " + (int) Math.ceil(twipToPixel(bounds.Ymax) + 50) + "\"\n"
|
||||
+ "<svg width=\"" + (int) Math.ceil(SWF.twipToPixel(bounds.Xmax)) + "\"\n"
|
||||
+ " height=\"" + (int) Math.ceil(SWF.twipToPixel(bounds.Ymax)) + "\"\n"
|
||||
+ " viewBox=\"0 0 " + (int) Math.ceil(SWF.twipToPixel(bounds.Xmax)) + " " + (int) Math.ceil(SWF.twipToPixel(bounds.Ymax) + 50) + "\"\n"
|
||||
+ " xmlns=\"http://www.w3.org/2000/svg\"\n"
|
||||
+ " xmlns:xlink=\"http://www.w3.org/1999/xlink\">" + ret + ""
|
||||
+ "</svg>";
|
||||
return ret;
|
||||
}
|
||||
private static HashMap<String, BufferedImage> cache = new HashMap<String, BufferedImage>();
|
||||
|
||||
public static BufferedImage shapeToImage(List<Tag> tags, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List<SHAPERECORD> records) {
|
||||
public static BufferedImage shapeToImage(List<Tag> tags, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, List<SHAPERECORD> records) {
|
||||
return shapeToImage(tags, shapeNum, fillStyles, lineStylesList, records, Color.black);
|
||||
}
|
||||
|
||||
public static List<GeneralPath> shapeToPaths(List<Tag> tags, int shapeNum, List<SHAPERECORD> records) {
|
||||
RECT rect = new RECT();
|
||||
List<Path> paths = getPaths(rect, shapeNum, fillStyles, lineStylesList, numFillBits, numLineBits, records);
|
||||
BufferedImage ret = new BufferedImage(rect.getWidth() / 20 + 2, rect.getHeight() / 20 + 2, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
Graphics2D g = (Graphics2D) ret.getGraphics();
|
||||
List<Path> paths = getPaths(rect, shapeNum, null, null, records);
|
||||
List<GeneralPath> ret = new ArrayList<GeneralPath>();
|
||||
for (Path p : paths) {
|
||||
p.drawTo(tags, -rect.Xmin, -rect.Ymin, g, shapeNum);
|
||||
ret.add(p.toGeneralPath(-rect.Xmin, -rect.Ymin));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static BufferedImage shapeToImage(List<Tag> tags, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, List<SHAPERECORD> records, Color defaultColor) {
|
||||
String key = "shape_" + records.hashCode() + "_" + defaultColor.hashCode();
|
||||
if (cache.containsKey(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
RECT rect = new RECT();
|
||||
List<Path> paths = getPaths(rect, shapeNum, fillStyles, lineStylesList, /*numFillBits, numLineBits,*/ records);
|
||||
BufferedImage ret = new BufferedImage(
|
||||
//(int)((rect.Xmax-rect.Xmin)/DESCALE),(int)((rect.Ymax-rect.Ymin)/DESCALE)
|
||||
(int) (rect.getWidth() / DESCALE + 2), (int) (rect.getHeight() / DESCALE + 2), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = (Graphics2D) ret.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);
|
||||
for (Path p : paths) {
|
||||
if (p.fillStyle0 == null) {
|
||||
p.fillStyle0 = new FILLSTYLE();
|
||||
p.fillStyle0.fillStyleType = FILLSTYLE.SOLID;
|
||||
p.fillStyle0.color = new RGB(defaultColor);
|
||||
p.fillStyle0.colorA = new RGBA(defaultColor);
|
||||
}
|
||||
p.drawTo(tags, -rect.Xmin, -rect.Ymin/*-rect.Xmin, -rect.Ymin*/, g, shapeNum);
|
||||
}
|
||||
cache.put(key, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public abstract boolean isMove();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.shaperecords;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
@@ -38,11 +40,11 @@ public class StraightEdgeRecord extends SHAPERECORD {
|
||||
@Override
|
||||
public String toSWG(int oldX, int oldY) {
|
||||
if (generalLineFlag) {
|
||||
return "L " + twipToPixel(oldX + deltaX) + " " + twipToPixel(oldY + deltaY);
|
||||
return "L " + SWF.twipToPixel(oldX + deltaX) + " " + SWF.twipToPixel(oldY + deltaY);
|
||||
} else if (vertLineFlag) {
|
||||
return "V " + twipToPixel(oldY + deltaY);
|
||||
return "V " + SWF.twipToPixel(oldY + deltaY);
|
||||
} else {
|
||||
return "H " + twipToPixel(oldX + deltaX);
|
||||
return "H " + SWF.twipToPixel(oldX + deltaX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.shaperecords;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import java.util.Set;
|
||||
@@ -62,7 +63,7 @@ public class StyleChangeRecord extends SHAPERECORD {
|
||||
@Override
|
||||
public String toSWG(int oldX, int oldY) {
|
||||
if (stateMoveTo) {
|
||||
return "M " + twipToPixel(moveDeltaX) + " " + twipToPixel(moveDeltaY);
|
||||
return "M " + SWF.twipToPixel(moveDeltaX) + " " + SWF.twipToPixel(moveDeltaY);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user