faster imagepanel

This commit is contained in:
Honfika
2014-03-16 14:42:55 +01:00
parent c6e8c8bea6
commit d48e6b1ccf
30 changed files with 450 additions and 328 deletions

View File

@@ -94,7 +94,6 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.Container;
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
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.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
@@ -102,6 +101,7 @@ import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.timeline.Clip;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Frame;
import com.jpexs.decompiler.flash.timeline.Timeline;
@@ -177,7 +177,6 @@ import java.util.zip.InflaterInputStream;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import net.kroo.elliot.GifSequenceWriter;
import org.monte.media.VideoFormatKeys;
import org.monte.media.avi.AVIWriter;
@@ -2389,18 +2388,6 @@ public final class SWF implements TreeItem, Timelined {
}
}
private static class Clip {
public Shape shape;
public int clipDepth;
public Clip(Shape clip, int clipDepth) {
this.shape = clip;
this.clipDepth = clipDepth;
}
}
public static void frameToImage(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
float unzoom = (float) SWF.unitDivisor;
if (timeline.frames.size() <= frame) {
@@ -2416,7 +2403,7 @@ public final class SWF implements TreeItem, Timelined {
for (int i = 1; i <= timeline.getMaxDepth(); i++) {
for (int c = 0; c < clips.size(); c++) {
if (clips.get(c).clipDepth == i) {
if (clips.get(c).depth == i) {
g.setClip(prevClips.get(c));
prevClips.remove(c);
clips.remove(c);
@@ -2450,7 +2437,7 @@ public final class SWF implements TreeItem, Timelined {
DrawableTag drawable = (DrawableTag) character;
SerializableImage img;
Matrix drawMatrix = new Matrix();
int dframe = 0 + (time + layer.time) % drawable.getNumFrames();
int dframe = (time + layer.time) % drawable.getNumFrames();
if (character instanceof ButtonTag) {
ButtonTag bt = (ButtonTag) character;
dframe = ButtonTag.FRAME_UP;
@@ -2463,64 +2450,56 @@ public final class SWF implements TreeItem, Timelined {
}
}
if (drawable instanceof BoundedTag) {
BoundedTag bounded = (BoundedTag) drawable;
RECT boundRect = bounded.getRect();
ExportRectangle rect = new ExportRectangle(boundRect);
rect = mat.transform(rect);
Matrix m = mat.clone();
if (layer.filters != null) {
// calculate size after applying the filters
double deltaXMax = 0;
double deltaYMax = 0;
for (FILTER filter : layer.filters) {
double x = filter.getDeltaX();
double y = filter.getDeltaY();
deltaXMax = Math.max(x, deltaXMax);
deltaYMax = Math.max(y, deltaYMax);
}
rect.xMin -= deltaXMax * SWF.unitDivisor;
rect.xMax += deltaXMax * SWF.unitDivisor;
rect.yMin -= deltaYMax * SWF.unitDivisor;
rect.yMax += deltaYMax * SWF.unitDivisor;
RECT boundRect = drawable.getRect();
ExportRectangle rect = new ExportRectangle(boundRect);
rect = mat.transform(rect);
Matrix m = mat.clone();
if (layer.filters != null) {
// calculate size after applying the filters
double deltaXMax = 0;
double deltaYMax = 0;
for (FILTER filter : layer.filters) {
double x = filter.getDeltaX();
double y = filter.getDeltaY();
deltaXMax = Math.max(x, deltaXMax);
deltaYMax = Math.max(y, deltaYMax);
}
rect.xMin = Math.max(0, rect.xMin);
rect.yMin = Math.max(0, rect.yMin);
int newWidth = (int) (rect.getWidth() / SWF.unitDivisor);
int newHeight = (int) (rect.getHeight() / SWF.unitDivisor);
int deltaX = (int) (rect.xMin / SWF.unitDivisor);
int deltaY = (int) (rect.yMin / SWF.unitDivisor);
newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1;
newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1;
if (newWidth <= 0 || newHeight <= 0) {
continue;
}
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
img.fillTransparent();
m.translate(-rect.xMin, -rect.yMin);
drawMatrix.translate(rect.xMin, rect.yMin);
drawable.toImage(dframe, layer.time + time, layer.ratio, stateUnderCursor, mouseButton, img, m, clrTrans);
//if(stateUnderCursor == layer){
/* if(true){
Graphics2D gg = (Graphics2D)img.getGraphics();
gg.setStroke(new BasicStroke(3));
gg.setPaint(Color.red);
gg.setTransform(AffineTransform.getTranslateInstance(0, 0));
gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(frame, layer.ratio, stateUnderCursor, mouseButton, m)));
}*/
} else if (drawable instanceof FontTag) {
// only DefineFont tags
FontTag fontTag = (FontTag) drawable;
img = fontTag.toImage(dframe, layer.ratio, transformation, clrTrans);
} else {
throw new Error("Unsupported drawable.");
rect.xMin -= deltaXMax * SWF.unitDivisor;
rect.xMax += deltaXMax * SWF.unitDivisor;
rect.yMin -= deltaYMax * SWF.unitDivisor;
rect.yMax += deltaYMax * SWF.unitDivisor;
}
rect.xMin = Math.max(0, rect.xMin);
rect.yMin = Math.max(0, rect.yMin);
int newWidth = (int) (rect.getWidth() / SWF.unitDivisor);
int newHeight = (int) (rect.getHeight() / SWF.unitDivisor);
int deltaX = (int) (rect.xMin / SWF.unitDivisor);
int deltaY = (int) (rect.yMin / SWF.unitDivisor);
newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1;
newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1;
if (newWidth <= 0 || newHeight <= 0) {
continue;
}
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
img.fillTransparent();
m.translate(-rect.xMin, -rect.yMin);
drawMatrix.translate(rect.xMin, rect.yMin);
drawable.toImage(dframe, layer.time + time, layer.ratio, stateUnderCursor, mouseButton, img, m, clrTrans);
//if(stateUnderCursor == layer){
/* if(true){
Graphics2D gg = (Graphics2D)img.getGraphics();
gg.setStroke(new BasicStroke(3));
gg.setPaint(Color.red);
gg.setTransform(AffineTransform.getTranslateInstance(0, 0));
gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(frame, layer.ratio, stateUnderCursor, mouseButton, m)));
}*/
if (layer.filters != null) {
for (FILTER filter : layer.filters) {
img = filter.apply(img);

View File

@@ -23,13 +23,9 @@ import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.FILLSTYLE;
import com.jpexs.decompiler.flash.types.GRADIENT;
import com.jpexs.decompiler.flash.types.GRADRECORD;
import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLE2;
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.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.SerializableImage;
import java.awt.BasicStroke;
import java.awt.Color;
@@ -67,13 +63,7 @@ public class BitmapExporter extends ShapeExporterBase implements IShapeExporter
private Stroke defaultStroke;
private double unitDivisor;
public static SerializableImage export(SWF swf, SHAPE shape, Color defaultColor, ColorTransform colorTransform) {
BitmapExporter exporter = new BitmapExporter(swf, shape, defaultColor, colorTransform);
exporter.export();
return exporter.getImage();
}
public static void exportTo(SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public static void export(SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
BitmapExporter exporter = new BitmapExporter(swf, shape, defaultColor, colorTransform);
exporter.exportTo(image, transformation);
}
@@ -84,34 +74,6 @@ public class BitmapExporter extends ShapeExporterBase implements IShapeExporter
this.defaultColor = defaultColor;
}
@Override
public void export() {
List<SHAPERECORD> records = shape.shapeRecords;
RECT bounds = SHAPERECORD.getBounds(records);
int maxLineWidthTwips = 0;
if (shape instanceof SHAPEWITHSTYLE) {
SHAPEWITHSTYLE shapeWithStyle = (SHAPEWITHSTYLE) shape;
for (LINESTYLE lineStyle : shapeWithStyle.lineStyles.lineStyles) {
if (lineStyle.width > maxLineWidthTwips) {
maxLineWidthTwips = lineStyle.width;
}
}
}
unitDivisor = SWF.unitDivisor;
double maxLineWidth = maxLineWidthTwips / unitDivisor / 2;
deltaX = bounds.Xmin / unitDivisor - maxLineWidth;
deltaY = bounds.Ymin / unitDivisor - maxLineWidth;
double width = bounds.getWidth() / unitDivisor + 2 * (maxLineWidth + 1);
double height = bounds.getHeight() / unitDivisor + 2 * (maxLineWidth + 1);
image = new SerializableImage((int) width, (int) height, SerializableImage.TYPE_INT_ARGB);
image.fillTransparent();
graphics = (Graphics2D) image.getGraphics();
defaultStroke = graphics.getStroke();
super.export();
}
private void exportTo(SerializableImage image, Matrix transformation) {
this.image = image;
graphics = (Graphics2D) image.getGraphics();

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2010-2014 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.exporters;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.GRADRECORD;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.SHAPE;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public class PathExporter extends ShapeExporterBase {
private final List<GeneralPath> paths = new ArrayList<>();
private GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
private final double unitDivisor = 1;
public static List<GeneralPath> export(SHAPE shape) {
PathExporter exporter = new PathExporter(shape, new ColorTransform());
exporter.export();
return exporter.paths;
}
private PathExporter(SHAPE shape, ColorTransform colorTransform) {
super(shape, colorTransform);
}
@Override
public void export() {
super.export();
}
@Override
public void beginShape() {
}
@Override
public void endShape(double xMin, double yMin, double xMax, double yMax) {
}
@Override
public void beginFills() {
}
@Override
public void endFills() {
}
@Override
public void beginLines() {
}
@Override
public void endLines() {
finalizePath();
}
@Override
public void beginFill(RGB color) {
finalizePath();
}
@Override
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
finalizePath();
}
@Override
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
finalizePath();
}
@Override
public void endFill() {
finalizePath();
}
@Override
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
finalizePath();
}
@Override
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
}
@Override
public void moveTo(double x, double y) {
path.moveTo(x / unitDivisor, y / unitDivisor);
}
@Override
public void lineTo(double x, double y) {
path.lineTo(x / unitDivisor, y / unitDivisor);
}
@Override
public void curveTo(double controlX, double controlY, double anchorX, double anchorY) {
path.quadTo(controlX / unitDivisor, controlY / unitDivisor,
anchorX / unitDivisor, anchorY / unitDivisor);
}
protected void finalizePath() {
paths.add(path);
path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); //For correct intersections display
}
}

View File

@@ -14,7 +14,6 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-97,0,0,1,-39"/>
</AuxValues>
<Layout>

View File

@@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Timeline;
@@ -52,7 +51,6 @@ import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -122,6 +120,9 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
public Point toImagePoint(Point p) {
if (img == null) {
return null;
}
return new Point((p.x - rect.x) * img.getWidth() / rect.width, (p.y - rect.y) * img.getHeight() / rect.height);
}
@@ -150,6 +151,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
rect = new Rectangle(getWidth() / 2 - w / 2, getHeight() / 2 - h / 2, w, h);
} else {
rect = null;
}
}
@@ -221,13 +224,15 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
m.scale(scale);
Point p = e.getPoint();
p = iconPanel.toImagePoint(p);
int x = p.x;
int y = p.y;
List<DepthState> objs = new ArrayList<>();
objs = iconPanel.getObjectsUnderPoint(p);
String ret = "";
if (p != null) {
int x = p.x;
int y = p.y;
objs = iconPanel.getObjectsUnderPoint(p);
ret += " [" + x + "," + y + "] : ";
ret += " [" + x + "," + y + "] : ";
}
boolean first = true;
for (int i = 0; i < objs.size(); i++) {
@@ -468,7 +473,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
soundPlayers.clear();
}
private void nextFrame() {
private void nextFrame(boolean first) {
int newframe = frame == timelined.getTimeline().frames.size() - 1 ? 0 : frame + 1;
if (stillFrame) {
newframe = frame;
@@ -480,13 +485,16 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
frame = newframe;
time = 0;
} else {
if (!first && timelined.getTimeline().isSingleFrame()) {
return;
}
time++;
}
drawFrame();
}
private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton) {
String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode()) + "_" + time;
String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode());
SerializableImage img = SWF.getFromCache(key);
if (img == null) {
if (drawable instanceof BoundedTag) {
@@ -497,7 +505,6 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
int width = rect.getWidth();
int height = rect.getHeight();
double scale = 1.0;
SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1,
(int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB);
image.fillTransparent();
@@ -519,18 +526,16 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}*/
img = image;
} else if (drawable instanceof FontTag) {
// only DefineFont tags
FontTag fontTag = (FontTag) drawable;
img = fontTag.toImage(frame, frame, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform());
}
SWF.putToCache(key, img);
if (drawable.getTimeline().isSingleFrame()) {
SWF.putToCache(key, img);
}
}
return img;
}
private void drawFrame() {
if (timelined == null) {
if (timelined == null || timelined.getTimeline().getFrameCount() <= frame) {
return;
}
@@ -539,7 +544,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
mat.translateX = swf.displayRect.Xmin;
mat.translateY = swf.displayRect.Ymin;
updatePos(lastMouseEvent, false);
BufferedImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton).getBufferedImage();
SerializableImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton);
List<Integer> sounds = new ArrayList<>();
List<String> soundClasses = new ArrayList<>();
timelined.getTimeline().getSounds(frame, time, stateUnderCursor, mouseButton, sounds, soundClasses);
@@ -559,7 +564,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
}
iconPanel.setImg(new SerializableImage(img));
iconPanel.setImg(img);
}
private void playSound(SoundTag st) {
@@ -613,9 +618,12 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
if (timelined != null) {
timer = new Timer();
timer.schedule(new TimerTask() {
boolean first = true;
@Override
public void run() {
nextFrame();
nextFrame(first);
first = false;
}
}, 0, 1000 / timelined.getTimeline().frameRate);
} else {

View File

@@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.tags.Tag;
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.ImageTag;
import com.jpexs.decompiler.flash.treeitems.FrameNodeItem;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
@@ -157,12 +156,7 @@ public class PreviewImage extends JPanel {
int height = 0;
SerializableImage imgSrc = null;
Matrix m = new Matrix();
if (treeItem instanceof FontTag) {
FontTag fontTag = (FontTag) treeItem;
imgSrc = fontTag.toImage(0, 0, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform());
width = (imgSrc.getWidth());
height = (imgSrc.getHeight());
} else if (treeItem instanceof FrameNodeItem) {
if (treeItem instanceof FrameNodeItem) {
FrameNodeItem fn = (FrameNodeItem) treeItem;
RECT rect = swf.displayRect;
imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.getFrame() - 1, 0, null, 0, rect, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform(), null);

View File

@@ -83,6 +83,9 @@ public class DefineButton2Tag extends ButtonTag implements Container {
private Timeline timeline;
private boolean isSingleFrameInitialized;
private boolean isSingleFrame;
@Override
public int getCharacterId() {
return buttonId;
@@ -252,6 +255,21 @@ public class DefineButton2Tag extends ButtonTag implements Container {
return 1;
}
@Override
public boolean isSingleFrame() {
if (!isSingleFrameInitialized) {
initialiteIsSingleFrame();
}
return isSingleFrame;
}
private synchronized void initialiteIsSingleFrame() {
if (!isSingleFrameInitialized) {
isSingleFrame = getTimeline().isSingleFrame();
isSingleFrameInitialized = true;
}
}
@Override
public Timeline getTimeline() {
if (timeline != null) {

View File

@@ -87,6 +87,9 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
private Timeline timeline;
private boolean isSingleFrameInitialized;
private boolean isSingleFrame;
@Override
public List<BUTTONRECORD> getRecords() {
return characters;
@@ -275,6 +278,21 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
return 1;
}
@Override
public boolean isSingleFrame() {
if (!isSingleFrameInitialized) {
initialiteIsSingleFrame();
}
return isSingleFrame;
}
private synchronized void initialiteIsSingleFrame() {
if (!isSingleFrameInitialized) {
isSingleFrame = getTimeline().isSingleFrame();
isSingleFrameInitialized = true;
}
}
@Override
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
return writer;

View File

@@ -957,4 +957,9 @@ public class DefineEditTextTag extends TextTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.Matrix;
import com.jpexs.decompiler.flash.exporters.Point;
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.MorphShapeTag;
@@ -59,7 +58,7 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, MorphShapeTag, DrawableTag {
public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag, DrawableTag {
@SWFType(BasicType.UI16)
public int characterId;
@@ -322,7 +321,7 @@ public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, Mo
// todo: Currently the generated image is not cached, because the cache
// key contains the hashCode of the finalRecord object, and it is always
// recreated
BitmapExporter.exportTo(swf, shape, null, image, transformation, colorTransform);
BitmapExporter.export(swf, shape, null, image, transformation, colorTransform);
}
@Override
@@ -337,6 +336,12 @@ public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, Mo
return 65536;
}
@Override
public boolean isSingleFrame() {
// Morpshape is a single frame specified with the ratio
return true;
}
@Override
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline());

View File

@@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.Matrix;
import com.jpexs.decompiler.flash.exporters.Point;
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.MorphShapeTag;
@@ -58,7 +57,7 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, MorphShapeTag, DrawableTag {
public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag, DrawableTag {
@SWFType(BasicType.UI16)
public int characterId;
@@ -305,7 +304,7 @@ public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, Mor
// todo: Currently the generated image is not cached, because the cache
// key contains the hashCode of the finalRecord object, and it is always
// recreated
BitmapExporter.exportTo(swf, shape, null, image, transformation, colorTransform);
BitmapExporter.export(swf, shape, null, image, transformation, colorTransform);
}
@Override
@@ -320,6 +319,12 @@ public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, Mor
return 65536;
}
@Override
public boolean isSingleFrame() {
// Morpshape is a single frame specified with the ratio
return true;
}
@Override
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline());

View File

@@ -87,4 +87,9 @@ public class DefineShape2Tag extends ShapeTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -91,4 +91,9 @@ public class DefineShape3Tag extends ShapeTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -100,4 +100,9 @@ public class DefineShape4Tag extends ShapeTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -111,4 +111,9 @@ public class DefineShapeTag extends ShapeTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -54,7 +54,7 @@ import java.util.Set;
/**
* Defines a sprite character
*/
public class DefineSpriteTag extends CharacterTag implements Container, BoundedTag, DrawableTag, Timelined {
public class DefineSpriteTag extends CharacterTag implements Container, DrawableTag, Timelined {
/**
* Character ID of sprite
@@ -75,6 +75,9 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
private Timeline timeline;
private boolean isSingleFrameInitialized;
private boolean isSingleFrame;
@Override
public Timeline getTimeline() {
if (timeline == null) {
@@ -282,6 +285,26 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
return frameCount;
}
@Override
public boolean isSingleFrame() {
if (!isSingleFrameInitialized) {
initialiteIsSingleFrame();
}
return isSingleFrame;
}
private synchronized void initialiteIsSingleFrame() {
if (!isSingleFrameInitialized) {
if (frameCount > 1) {
isSingleFrameInitialized = true;
return;
}
isSingleFrame = getTimeline().isSingleFrame();
isSingleFrameInitialized = true;
}
}
@Override
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
return getTimeline().getOutline(frame, time, ratio, stateUnderCursor, mouseButton, transformation);

View File

@@ -501,4 +501,9 @@ public class DefineText2Tag extends TextTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -517,4 +517,9 @@ public class DefineTextTag extends TextTag {
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
}

View File

@@ -32,7 +32,7 @@ import java.util.List;
*
* @author JPEXS
*/
public abstract class ButtonTag extends CharacterTag implements BoundedTag, DrawableTag, Timelined {
public abstract class ButtonTag extends CharacterTag implements DrawableTag, Timelined {
public static int FRAME_UP = 0;
public static int FRAME_OVER = 1;

View File

@@ -27,7 +27,7 @@ import java.awt.Shape;
*
* @author JPEXS
*/
public interface DrawableTag {
public interface DrawableTag extends BoundedTag {
public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform);
@@ -35,5 +35,7 @@ public interface DrawableTag {
public int getNumFrames();
public boolean isSingleFrame();
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation);
}

View File

@@ -32,10 +32,8 @@ import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.SerializableImage;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
@@ -51,7 +49,9 @@ import java.util.Map;
*
* @author JPEXS
*/
public abstract class FontTag extends CharacterTag implements AloneTag, BoundedTag, DrawableTag {
public abstract class FontTag extends CharacterTag implements AloneTag, DrawableTag {
protected final int previewSize = 500;
public FontTag(SWF swf, int id, String name, byte[] data, long pos) {
super(swf, id, name, data, pos);
@@ -252,15 +252,9 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT
return defaultFontName;
}
public SerializableImage toImage(int frame, int ratio, Matrix transformation, ColorTransform colorTransform) {
return SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), 500, 500, Color.black, colorTransform);
}
@Override
public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
Graphics2D g = (Graphics2D) image.getGraphics();
g.setComposite(AlphaComposite.SrcOver);
g.drawImage(toImage(0, 0, new Matrix(), colorTransform).getBufferedImage(), transformation.toTransform(), null);
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, Color.black, colorTransform);
}
@Override
@@ -273,6 +267,11 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
@Override
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
RECT r = getRect();
@@ -281,7 +280,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT
@Override
public RECT getRect() {
return new RECT(0, (int) (500 * SWF.unitDivisor), 0, (int) (500 * SWF.unitDivisor));
return new RECT(0, (int) (previewSize * SWF.unitDivisor), 0, (int) (previewSize * SWF.unitDivisor));
}
}

View File

@@ -48,6 +48,6 @@ public abstract class ShapeTag extends CharacterTag implements BoundedTag, Drawa
@Override
public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
BitmapExporter.exportTo(swf, getShapes(), null, image, transformation, colorTransform);
BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform);
}
}

View File

@@ -252,7 +252,7 @@ public abstract class TextTag extends CharacterTag implements BoundedTag, Drawab
shape.shapeRecords.add(bottom);
shape.shapeRecords.add(left);
shape.shapeRecords.add(new EndShapeRecord());
BitmapExporter.exportTo(swf, shape, null, image, mat, colorTransform);
BitmapExporter.export(swf, shape, null, image, mat, colorTransform);
}
public static void staticTextToImage(SWF swf, List<TEXTRECORD> textRecords, int numText, SerializableImage image, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) {
@@ -294,7 +294,7 @@ public abstract class TextTag extends CharacterTag implements BoundedTag, Drawab
if (entry.glyphIndex != -1) {
// shapeNum: 1
SHAPE shape = glyphs.get(entry.glyphIndex);
BitmapExporter.exportTo(swf, shape, textColor, image, mat, colorTransform);
BitmapExporter.export(swf, shape, textColor, image, mat, colorTransform);
x += entry.glyphAdvance;
}
}

View File

@@ -19,13 +19,11 @@ package com.jpexs.decompiler.flash.tags.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.Matrix;
import com.jpexs.decompiler.flash.exporters.Point;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.RECT;
@@ -41,8 +39,6 @@ import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.awt.Font;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -111,21 +107,6 @@ public final class DefineCompactedFont extends FontTag implements DrawableTag {
shapeCache = fonts.get(0).getGlyphShapes();
}
@Override
public SerializableImage toImage(int frame, int ratio, Matrix transformation, ColorTransform colorTransform) {
List<SHAPE> shapes = new ArrayList<>();
for (int i = 0; i < shapeCache.size(); i++) {
shapes.add(SHAPERECORD.resizeSHAPE(shapeCache.get(i), SWF.unitDivisor));
}
int cols = (int) Math.ceil(Math.sqrt(shapes.size()));
int size = 500;
if (size / cols < 30) {
size = cols * 30;
}
SerializableImage ret = SHAPERECORD.shapeListToImage(swf, shapes, size, size, Color.black, colorTransform);
return ret;
}
@Override
public Point getImagePos(int frame) {
return new Point(0, 0);

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2010-2014 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.timeline;
import java.awt.Shape;
/**
*
* @author JPEXS
*/
public class Clip {
public Shape shape;
public int depth;
public Clip(Shape shape, int depth) {
this.shape = shape;
this.depth = depth;
}
}

View File

@@ -65,7 +65,6 @@ public class DepthState {
public DepthState(DepthState obj, Frame frame, boolean sameInstance) {
this.frame = frame;
swf = obj.swf;
frame = obj.frame;
characterId = obj.characterId;
matrix = obj.matrix;
instanceName = obj.instanceName;

View File

@@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.timeline;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import java.awt.Shape;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
@@ -50,16 +49,4 @@ public class Frame {
}
//Do not copy sounds
}
private class Clip {
public Shape shape;
public int depth;
public Clip(Shape shape, int depth) {
this.shape = shape;
this.depth = depth;
}
}
}

View File

@@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.StartSound2Tag;
import com.jpexs.decompiler.flash.tags.StartSoundTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
@@ -171,18 +170,6 @@ public class Timeline {
SWF.frameToImage(this, frame, time, stateUnderCursor, mouseButton, image, transformation, colorTransform);
}
private class Clip {
public Shape shape;
public int depth;
public Clip(Shape shape, int depth) {
this.shape = shape;
this.depth = depth;
}
}
public void getSounds(int frame, int time, DepthState stateUnderCursor, int mouseButton, List<Integer> sounds, List<String> soundClasses) {
Frame fr = this.frames.get(frame);
sounds.addAll(fr.sounds);
@@ -232,7 +219,7 @@ public class Timeline {
continue;
}
CharacterTag c = swf.characters.get(ds.characterId);
if ((c instanceof DrawableTag) && (c instanceof BoundedTag)) {
if (c instanceof DrawableTag) {
Matrix m = new Matrix(ds.matrix);
m = m.preConcatenate(transformation);
@@ -297,7 +284,7 @@ public class Timeline {
continue;
}
CharacterTag c = swf.characters.get(ds.characterId);
if ((c instanceof DrawableTag) && (c instanceof BoundedTag)) {
if (c instanceof DrawableTag) {
Matrix m = new Matrix(ds.matrix);
m = m.preConcatenate(transformation);
@@ -334,4 +321,29 @@ public class Timeline {
}
return area;
}
public boolean isSingleFrame() {
Frame frameObj = frames.get(0);
for (int i = 1; i <= getMaxDepth(); i++) {
if (!frameObj.layers.containsKey(i)) {
continue;
}
DepthState layer = frameObj.layers.get(i);
if (!swf.characters.containsKey(layer.characterId)) {
continue;
}
if (!layer.isVisible) {
continue;
}
CharacterTag character = swf.characters.get(layer.characterId);
if (character instanceof DrawableTag) {
DrawableTag drawable = (DrawableTag) character;
if (!drawable.isSingleFrame()) {
return false;
}
}
}
return true;
}
}

View File

@@ -16,8 +16,7 @@
*/
package com.jpexs.decompiler.flash.types;
import com.jpexs.decompiler.flash.exporters.Matrix;
import com.jpexs.decompiler.flash.exporters.ShapeExporterBase;
import com.jpexs.decompiler.flash.exporters.PathExporter;
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
@@ -25,7 +24,6 @@ import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -56,101 +54,7 @@ public class SHAPE implements NeedsCharacters, Serializable {
}
public Shape getOutline() {
final List<GeneralPath> paths = new ArrayList<>();
ShapeExporterBase se = new ShapeExporterBase(this, new ColorTransform()) {
private GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
private double unitDivisor;
@Override
public void export() {
unitDivisor = 1;
super.export();
}
@Override
public void beginShape() {
}
@Override
public void endShape(double xMin, double yMin, double xMax, double yMax) {
}
@Override
public void beginFills() {
}
@Override
public void endFills() {
}
@Override
public void beginLines() {
}
@Override
public void endLines() {
finalizePath();
}
@Override
public void beginFill(RGB color) {
finalizePath();
}
@Override
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
finalizePath();
}
@Override
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
finalizePath();
}
@Override
public void endFill() {
finalizePath();
}
@Override
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
finalizePath();
}
@Override
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
}
@Override
public void moveTo(double x, double y) {
path.moveTo(x / unitDivisor, y / unitDivisor);
}
@Override
public void lineTo(double x, double y) {
path.lineTo(x / unitDivisor, y / unitDivisor);
}
@Override
public void curveTo(double controlX, double controlY, double anchorX, double anchorY) {
path.quadTo(controlX / unitDivisor, controlY / unitDivisor,
anchorX / unitDivisor, anchorY / unitDivisor);
}
protected void finalizePath() {
paths.add(path);
path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); //For correct intersections display
}
};
se.export();
List<GeneralPath> paths = PathExporter.export(this);
Area area = new Area();
for (GeneralPath path : paths) {
area.add(new Area(path));

View File

@@ -19,23 +19,26 @@ package com.jpexs.decompiler.flash.types.shaperecords;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.Matrix;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.types.ColorTransform;
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;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
@@ -50,6 +53,7 @@ import javax.swing.JPanel;
public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Serializable {
public static final int MAX_CHARACTERS_IN_FONT_PREVIEW = 400;
private static final boolean DRAW_BOUNDING_BOX = false;
public abstract void calculateBits();
@@ -125,34 +129,42 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali
return ret;
}
public static SerializableImage shapeListToImage(SWF swf, List<SHAPE> shapes, int prevWidth, int prevHeight, Color color, ColorTransform colorTransform) {
public static void shapeListToImage(SWF swf, List<SHAPE> shapes, SerializableImage image, Color color, ColorTransform colorTransform) {
if (shapes.isEmpty()) {
SerializableImage image = new SerializableImage(1, 1, BufferedImage.TYPE_INT_RGB);
image.fillTransparent();
return image;
return;
}
SerializableImage ret = new SerializableImage(prevWidth, prevHeight, SerializableImage.TYPE_INT_ARGB);
Graphics g = ret.getGraphics();
int prevWidth = image.getWidth();
int prevHeight = image.getHeight();
int maxw = 0;
int maxh = 0;
int minXMin = 0;
int minYMin = 0;
for (SHAPE s : shapes) {
RECT r = SHAPERECORD.getBounds(s.shapeRecords);
if (r.Xmax < r.Xmin || r.Ymax < r.Ymin) {
continue;
}
if (r.getWidth() > maxw) {
maxw = r.getWidth();
}
if (r.getHeight() > maxh) {
maxh = r.getHeight();
}
if (r.Xmin < minXMin) {
minXMin = r.Xmin;
}
if (r.Ymin < minYMin) {
minYMin = r.Ymin;
}
}
maxw /= SWF.unitDivisor;
maxh /= SWF.unitDivisor;
int shapeCount = Math.min(MAX_CHARACTERS_IN_FONT_PREVIEW, shapes.size());
int cols = (int) Math.ceil(Math.sqrt(shapeCount));
int pos = 0;
int w2 = prevWidth / cols;
int h2 = prevHeight / cols;
int w2 = (int) (prevWidth * SWF.unitDivisor / cols);
int h2 = (int) (prevHeight * SWF.unitDivisor / cols);
int mh = maxh * w2 / maxw;
int mw;
@@ -173,21 +185,33 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali
}
// shapeNum: 1
SerializableImage img = BitmapExporter.export(swf, shapes.get(pos), color, colorTransform);
SHAPE shape = shapes.get(pos);
List<SHAPERECORD> records = shape.shapeRecords;
RECT bounds = SHAPERECORD.getBounds(records);
int w1 = img.getWidth();
int h1 = img.getHeight();
int w1 = bounds.getWidth();
int h1 = bounds.getHeight();
int w = Math.round(ratio * w1);
int h = Math.round(ratio * h1);
int px = x * w2 + w2 / 2 - w / 2;
int py = y * h2 + w2 - h;
g.drawImage(img.getBufferedImage(), px, py, px + w, py + h, 0, 0, w1, h1, null);
double w = ratio * w1;
double h = ratio * h1;
double px = x * w2 + w2 / 2 - w / 2 - minXMin * ratio;
double py = y * h2 - minYMin * ratio;
Matrix transformation = new Matrix();
transformation.translate(px, py);
transformation = transformation.concatenate(Matrix.getScaleInstance(ratio));
BitmapExporter.export(swf, shape, color, image, transformation, colorTransform);
// draw bounding boxes
if (DRAW_BOUNDING_BOX) {
RGB borderColor = new RGBA(Color.black);
RGB fillColor = new RGBA(new Color(255, 255, 255, 0));
transformation = Matrix.getTranslateInstance(bounds.Xmin, bounds.Ymin).preConcatenate(transformation);
TextTag.drawBorder(swf, image, borderColor, fillColor, bounds, new MATRIX(), transformation, colorTransform);
}
pos++;
}
}
return ret;
}
public abstract boolean isMove();