mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-24 19:14:34 +00:00
feat: add advanced multi sample anti-aliased shape renderer
Multi sample anti-alias renderer with configurable grid. It can be turned on with icon under render window, and with checkbox for export.
This commit is contained in:
@@ -5035,8 +5035,8 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
|
||||
int originalHeight = (int) Math.ceil(rect.getHeight() * zoom / SWF.unitDivisor);
|
||||
|
||||
SerializableImage image = new SerializableImage(
|
||||
originalWidth * aaScale,
|
||||
originalHeight * aaScale,
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
SerializableImage.TYPE_INT_ARGB_PRE
|
||||
);
|
||||
if (backGroundColor == null) {
|
||||
@@ -5049,25 +5049,17 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
|
||||
}
|
||||
|
||||
Matrix m = transformation.clone();
|
||||
m.translate(-rect.Xmin * zoom * aaScale, -rect.Ymin * zoom * aaScale);
|
||||
m.scale(zoom * aaScale);
|
||||
m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom);
|
||||
m.scale(zoom);
|
||||
RenderContext renderContext = new RenderContext();
|
||||
renderContext.cursorPosition = cursorPosition;
|
||||
renderContext.mouseButton = mouseButton;
|
||||
|
||||
ExportRectangle viewRect = new ExportRectangle(rect);
|
||||
|
||||
viewRect.xMin *= aaScale;
|
||||
viewRect.yMin *= aaScale;
|
||||
viewRect.xMax *= aaScale;
|
||||
viewRect.yMax *= aaScale;
|
||||
|
||||
timeline.toImage(frame, time, renderContext, image, image, false, m, new Matrix(), m, colorTransform, zoom * aaScale, true, viewRect, viewRect, m, true, Timeline.DRAW_MODE_ALL, 0, canUseSmoothing, new ArrayList<>(), aaScale);
|
||||
|
||||
if (aaScale > 1) {
|
||||
image = new SerializableImage(ImageResizer.resizeImage(image.getBufferedImage(), originalWidth, originalHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true));
|
||||
}
|
||||
|
||||
|
||||
timeline.toImage(frame, time, renderContext, image, image, false, m, new Matrix(), m, colorTransform, zoom, true, viewRect, viewRect, m, true, Timeline.DRAW_MODE_ALL, 0, canUseSmoothing, new ArrayList<>(), aaScale);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -6476,6 +6468,6 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
|
||||
|
||||
@Override
|
||||
public RECT getRectWithFilters() {
|
||||
return getRect();
|
||||
return getRectWithStrokes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,18 +844,22 @@ public final class Configuration {
|
||||
|
||||
@ConfigurationDefaultBoolean(false)
|
||||
@ConfigurationCategory("display")
|
||||
@ConfigurationRemoved
|
||||
public static ConfigurationItem<Boolean> reduceAntialiasConflationByScalingForDisplay = null;
|
||||
|
||||
@ConfigurationDefaultInt(4)
|
||||
@ConfigurationCategory("display")
|
||||
@ConfigurationRemoved
|
||||
public static ConfigurationItem<Integer> reduceAntialiasConflationByScalingValueForDisplay = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(false)
|
||||
@ConfigurationCategory("export")
|
||||
@ConfigurationRemoved
|
||||
public static ConfigurationItem<Boolean> reduceAntialiasConflationByScalingForExport = null;
|
||||
|
||||
@ConfigurationDefaultInt(10)
|
||||
@ConfigurationDefaultInt(4)
|
||||
@ConfigurationCategory("export")
|
||||
@ConfigurationRemoved
|
||||
public static ConfigurationItem<Integer> reduceAntialiasConflationByScalingValueForExport = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@@ -1213,6 +1217,22 @@ public final class Configuration {
|
||||
@ConfigurationCategory("export")
|
||||
public static ConfigurationItem<Boolean> exportFlaAs3DisableScriptLayer = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(false)
|
||||
@ConfigurationCategory("display")
|
||||
public static ConfigurationItem<Boolean> useMsaaForDisplay = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(false)
|
||||
@ConfigurationCategory("export")
|
||||
public static ConfigurationItem<Boolean> useMsaaForExport = null;
|
||||
|
||||
@ConfigurationDefaultInt(4)
|
||||
@ConfigurationCategory("display")
|
||||
public static ConfigurationItem<Integer> msaaGridForDisplay = null;
|
||||
|
||||
@ConfigurationDefaultInt(4)
|
||||
@ConfigurationCategory("export")
|
||||
public static ConfigurationItem<Integer> msaaGridForExport = null;
|
||||
|
||||
private static Map<String, String> configurationDescriptions = new LinkedHashMap<>();
|
||||
private static Map<String, String> configurationTitles = new LinkedHashMap<>();
|
||||
|
||||
@@ -1865,20 +1885,5 @@ public final class Configuration {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int calculateRealAaScale(int imageWidth, int imageHeight, double zoom, int initialAaScale) {
|
||||
|
||||
final int MAX_IMAGE_DIMENSION = 10000;
|
||||
|
||||
int aaScale = initialAaScale;
|
||||
while (
|
||||
aaScale > 1
|
||||
&& (((long) imageWidth * zoom * aaScale / SWF.unitDivisor) > MAX_IMAGE_DIMENSION
|
||||
|| ((long) imageHeight * zoom * aaScale / SWF.unitDivisor) > MAX_IMAGE_DIMENSION)
|
||||
) {
|
||||
aaScale--;
|
||||
}
|
||||
return aaScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,8 +268,7 @@ public class FrameExporter {
|
||||
|
||||
int fframe = subFrameMode ? fframes.get(0) : fframes.get(pos++);
|
||||
RECT displayRect = tim.getDisplayRectWithFilters();
|
||||
int realAaScale = Configuration.calculateRealAaScale(displayRect.getWidth(), displayRect.getHeight(), settings.zoom, settings.aaScale);
|
||||
BufferedImage result = SWF.frameToImageGet(tim, fframe, subFrameMode ? pos++ : 0, null, 0, displayRect, new Matrix(), null, backgroundColor == null && !usesTransparency ? Color.white : backgroundColor, settings.zoom, true, realAaScale).getBufferedImage();
|
||||
BufferedImage result = SWF.frameToImageGet(tim, fframe, subFrameMode ? pos++ : 0, null, 0, displayRect, new Matrix(), null, backgroundColor == null && !usesTransparency ? Color.white : backgroundColor, settings.zoom, true, settings.aaScale).getBufferedImage();
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -171,13 +171,11 @@ public class MorphShapeExporter {
|
||||
st = mst.getStartShapeTag();
|
||||
rect = st.getRect();
|
||||
|
||||
int realAaScale = Configuration.calculateRealAaScale(rect.getWidth(), rect.getHeight(), settings.zoom, settings.aaScale);
|
||||
|
||||
int originalWidth = (int) Math.ceil(rect.getWidth() * settings.zoom / SWF.unitDivisor);
|
||||
int originalHeight = (int) Math.ceil(rect.getHeight() * settings.zoom / SWF.unitDivisor);
|
||||
|
||||
int newWidth = originalWidth * realAaScale;
|
||||
int newHeight = originalHeight * realAaScale;
|
||||
int newWidth = originalWidth;
|
||||
int newHeight = originalHeight;
|
||||
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
img.fillTransparent();
|
||||
if (settings.mode == MorphShapeExportMode.BMP_START_END) {
|
||||
@@ -188,16 +186,11 @@ public class MorphShapeExporter {
|
||||
g.fillRect(0, 0, img.getWidth(), img.getHeight());
|
||||
}
|
||||
}
|
||||
m = Matrix.getScaleInstance(settings.zoom * realAaScale);
|
||||
m = Matrix.getScaleInstance(settings.zoom);
|
||||
m.translate(-rect.Xmin, -rect.Ymin);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom * realAaScale, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, realAaScale);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale);
|
||||
|
||||
BufferedImage bim = img.getBufferedImage();
|
||||
|
||||
if (realAaScale > 1) {
|
||||
bim = ImageResizer.resizeImage(bim, originalWidth, originalHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true);
|
||||
}
|
||||
|
||||
if (settings.mode == MorphShapeExportMode.PNG_START_END) {
|
||||
ImageHelper.write(bim, ImageFormat.PNG, fileStart);
|
||||
} else if (settings.mode == MorphShapeExportMode.WEBP_START_END) {
|
||||
@@ -210,13 +203,12 @@ public class MorphShapeExporter {
|
||||
|
||||
st = mst.getEndShapeTag();
|
||||
rect = st.getRect();
|
||||
realAaScale = Configuration.calculateRealAaScale(rect.getWidth(), rect.getHeight(), settings.zoom, settings.aaScale);
|
||||
|
||||
|
||||
originalWidth = (int) Math.ceil(rect.getWidth() * settings.zoom / SWF.unitDivisor);
|
||||
originalHeight = (int) Math.ceil(rect.getHeight() * settings.zoom / SWF.unitDivisor);
|
||||
|
||||
newWidth = originalWidth * realAaScale;
|
||||
newHeight = originalHeight * realAaScale;
|
||||
newWidth = originalWidth;
|
||||
newHeight = originalHeight;
|
||||
|
||||
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
img.fillTransparent();
|
||||
@@ -228,16 +220,12 @@ public class MorphShapeExporter {
|
||||
g.fillRect(0, 0, img.getWidth(), img.getHeight());
|
||||
}
|
||||
}
|
||||
m = Matrix.getScaleInstance(settings.zoom * realAaScale);
|
||||
m = Matrix.getScaleInstance(settings.zoom);
|
||||
m.translate(-rect.Xmin, -rect.Ymin);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale);
|
||||
|
||||
bim = img.getBufferedImage();
|
||||
|
||||
if (realAaScale > 1) {
|
||||
bim = ImageResizer.resizeImage(bim, originalWidth, originalHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true);
|
||||
}
|
||||
|
||||
if (settings.mode == MorphShapeExportMode.PNG_START_END) {
|
||||
ImageHelper.write(bim, ImageFormat.PNG, fileEnd);
|
||||
} else if (settings.mode == MorphShapeExportMode.WEBP_START_END) {
|
||||
@@ -452,11 +440,8 @@ public class MorphShapeExporter {
|
||||
private final Color backgroundColor;
|
||||
private final MorphShapeExportSettings settings;
|
||||
private final RECT rect;
|
||||
private final int realAaScale;
|
||||
private final int originalWidth;
|
||||
private final int originalHeight;
|
||||
private final int newWidth;
|
||||
private final int newHeight;
|
||||
|
||||
public MyFrameIterator(
|
||||
MorphShapeTag mst,
|
||||
@@ -474,11 +459,8 @@ public class MorphShapeExporter {
|
||||
this.settings = settings;
|
||||
|
||||
rect = mst.getRect();
|
||||
realAaScale = Configuration.calculateRealAaScale(rect.getWidth(), rect.getHeight(), settings.zoom, settings.aaScale);
|
||||
originalWidth = (int) Math.ceil(rect.getWidth() * settings.zoom / SWF.unitDivisor);
|
||||
originalHeight = (int) Math.ceil(rect.getHeight() * settings.zoom / SWF.unitDivisor);
|
||||
newWidth = originalWidth * realAaScale;
|
||||
newHeight = originalHeight * realAaScale;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@@ -514,7 +496,7 @@ public class MorphShapeExporter {
|
||||
|
||||
ShapeTag st = mst.getShapeTagAtRatio(ratio);
|
||||
|
||||
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
SerializableImage img = new SerializableImage(originalWidth, originalHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
img.fillTransparent();
|
||||
if (!usesTransparency) {
|
||||
Graphics2D g = (Graphics2D) img.getGraphics();
|
||||
@@ -525,16 +507,12 @@ public class MorphShapeExporter {
|
||||
}
|
||||
g.fillRect(0, 0, img.getWidth(), img.getHeight());
|
||||
}
|
||||
Matrix m = Matrix.getScaleInstance(settings.zoom * realAaScale);
|
||||
Matrix m = Matrix.getScaleInstance(settings.zoom);
|
||||
m.translate(-rect.Xmin, -rect.Ymin);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), settings.zoom * realAaScale, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, realAaScale);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), settings.zoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale);
|
||||
|
||||
BufferedImage result = img.getBufferedImage();
|
||||
|
||||
if (realAaScale > 1) {
|
||||
result = ImageResizer.resizeImage(result, originalWidth, originalHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true);
|
||||
}
|
||||
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -132,11 +132,10 @@ public class ShapeExporter {
|
||||
case PNG:
|
||||
case BMP:
|
||||
case WEBP:
|
||||
int realAaScale = Configuration.calculateRealAaScale(rect.getWidth(), rect.getHeight(), settings.zoom, aaScale);
|
||||
int originalWidth = (int) Math.ceil(rect.getWidth() * settings.zoom / SWF.unitDivisor);
|
||||
int originalHeight = (int) Math.ceil(rect.getHeight() * settings.zoom / SWF.unitDivisor);
|
||||
int newWidth = originalWidth * realAaScale;
|
||||
int newHeight = originalHeight * realAaScale;
|
||||
int newWidth = originalWidth;
|
||||
int newHeight = originalHeight;
|
||||
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
img.fillTransparent();
|
||||
if (settings.mode == ShapeExportMode.BMP) {
|
||||
@@ -147,15 +146,13 @@ public class ShapeExporter {
|
||||
g.fillRect(0, 0, img.getWidth(), img.getHeight());
|
||||
}
|
||||
}
|
||||
Matrix m2 = Matrix.getScaleInstance(settings.zoom * realAaScale);
|
||||
Matrix m2 = Matrix.getScaleInstance(settings.zoom);
|
||||
m2.translate(-rect.Xmin, -rect.Ymin);
|
||||
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m2, m2, m2, m2, new CXFORMWITHALPHA(), unzoom * realAaScale, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, realAaScale);
|
||||
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m2, m2, m2, m2, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, aaScale);
|
||||
|
||||
BufferedImage bim = img.getBufferedImage();
|
||||
if (realAaScale > 1) {
|
||||
bim = ImageResizer.resizeImage(bim, originalWidth, originalHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true);
|
||||
}
|
||||
|
||||
|
||||
if (settings.mode == ShapeExportMode.PNG) {
|
||||
ImageHelper.write(bim, ImageFormat.PNG, file);
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package com.jpexs.decompiler.flash.exporters.shape;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.ImageTagBufferedImage;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.aa.AntialiasedBitmapExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
@@ -66,49 +66,49 @@ public class BitmapExporter extends ShapeExporterBase {
|
||||
|
||||
private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
|
||||
|
||||
private SerializableImage image;
|
||||
protected SerializableImage image;
|
||||
|
||||
private Graphics2D graphics;
|
||||
protected Graphics2D graphics;
|
||||
|
||||
private final Color defaultColor;
|
||||
protected final Color defaultColor;
|
||||
|
||||
private final SWF swf;
|
||||
protected final SWF swf;
|
||||
|
||||
private final GeneralPath path;
|
||||
protected final GeneralPath path;
|
||||
|
||||
private Paint fillPaint;
|
||||
protected Paint fillPaint;
|
||||
|
||||
private boolean fillRepeat;
|
||||
protected boolean fillRepeat;
|
||||
|
||||
private boolean fillSmooth;
|
||||
protected boolean fillSmooth;
|
||||
|
||||
private AffineTransform fillTransform;
|
||||
protected AffineTransform fillTransform;
|
||||
|
||||
private Paint linePaint;
|
||||
protected Paint linePaint;
|
||||
|
||||
private AffineTransform lineTransform;
|
||||
protected AffineTransform lineTransform;
|
||||
|
||||
private Color lineColor;
|
||||
protected Color lineColor;
|
||||
|
||||
private Stroke lineStroke;
|
||||
protected Stroke lineStroke;
|
||||
|
||||
private Stroke defaultStroke;
|
||||
protected Stroke defaultStroke;
|
||||
|
||||
private Matrix strokeTransformation;
|
||||
protected Matrix strokeTransformation;
|
||||
|
||||
private double thicknessScale;
|
||||
private double thicknessScaleX;
|
||||
private double thicknessScaleY;
|
||||
protected double thicknessScale;
|
||||
protected double thicknessScaleX;
|
||||
protected double thicknessScaleY;
|
||||
|
||||
private double unzoom;
|
||||
protected double unzoom;
|
||||
|
||||
private int aaScale;
|
||||
protected int aaScale;
|
||||
|
||||
private static boolean linearGradientColorWarningShown = false;
|
||||
protected static boolean linearGradientColorWarningShown = false;
|
||||
|
||||
private boolean scaleStrokes;
|
||||
|
||||
private class TransformedStroke implements Stroke {
|
||||
protected boolean scaleStrokes;
|
||||
|
||||
protected class TransformedStroke implements Stroke {
|
||||
|
||||
/**
|
||||
* To make this serializable without problems.
|
||||
@@ -176,41 +176,49 @@ public class BitmapExporter extends ShapeExporterBase {
|
||||
* @param aaScale Antialias conflation reducing scale coefficient
|
||||
*/
|
||||
public static void export(int windingRule, int shapeNum, SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, double unzoom, Matrix transformation, Matrix strokeTransformation, ColorTransform colorTransform, boolean scaleStrokes, boolean canUseSmoothing, int aaScale) {
|
||||
BitmapExporter exporter = new BitmapExporter(windingRule, shapeNum, swf, shape, defaultColor, colorTransform);
|
||||
exporter.setCanUseSmoothing(canUseSmoothing);
|
||||
exporter.exportTo(shapeNum, image, unzoom, transformation, strokeTransformation, scaleStrokes, aaScale);
|
||||
if (aaScale > 1) {
|
||||
AntialiasedBitmapExporter.export(windingRule, shapeNum, swf, shape, defaultColor, image, unzoom, transformation, strokeTransformation, colorTransform, scaleStrokes, canUseSmoothing, aaScale);
|
||||
} else {
|
||||
BitmapExporter exporter = new BitmapExporter(windingRule, shapeNum, swf, shape, defaultColor, colorTransform);
|
||||
exporter.setCanUseSmoothing(canUseSmoothing);
|
||||
exporter.exportTo(shapeNum, image, unzoom, transformation, strokeTransformation, scaleStrokes, aaScale);
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapExporter(int windingRule, int shapeNum, SWF swf, SHAPE shape, Color defaultColor, ColorTransform colorTransform) {
|
||||
protected BitmapExporter(int windingRule, int shapeNum, SWF swf, SHAPE shape, Color defaultColor, ColorTransform colorTransform) {
|
||||
super(windingRule, shapeNum, swf, shape, colorTransform);
|
||||
this.swf = swf;
|
||||
this.defaultColor = defaultColor;
|
||||
path = new GeneralPath(windingRule == ShapeTag.WIND_NONZERO ? GeneralPath.WIND_NON_ZERO : GeneralPath.WIND_EVEN_ODD);
|
||||
}
|
||||
|
||||
private void exportTo(int shapeNum, SerializableImage image, double unzoom, Matrix transformation, Matrix strokeTransformation, boolean scaleStrokes, int aaScale) {
|
||||
protected void exportTo(int shapeNum, SerializableImage image, double unzoom, Matrix transformation, Matrix strokeTransformation, boolean scaleStrokes, int aaScale) {
|
||||
this.image = image;
|
||||
this.scaleStrokes = scaleStrokes;
|
||||
ExportRectangle bounds = new ExportRectangle(shape.getBounds(shapeNum));
|
||||
this.strokeTransformation = strokeTransformation;
|
||||
calculateThicknessScale(bounds, transformation);
|
||||
calculateThicknessScale();
|
||||
|
||||
graphics = (Graphics2D) image.getGraphics();
|
||||
AffineTransform at = transformation.toTransform();
|
||||
at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor));
|
||||
graphics.setTransform(at);
|
||||
setTransform(graphics, transformation);
|
||||
defaultStroke = graphics.getStroke();
|
||||
this.unzoom = unzoom;
|
||||
this.aaScale = aaScale;
|
||||
super.export();
|
||||
}
|
||||
|
||||
protected void setTransform(Graphics2D g, Matrix transformation) {
|
||||
AffineTransform at = transformation.toTransform();
|
||||
at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor));
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
|
||||
private void calculateThicknessScale(ExportRectangle bounds, Matrix transformation) {
|
||||
protected void calculateThicknessScale() {
|
||||
com.jpexs.decompiler.flash.exporters.commonshape.Point p00 = strokeTransformation.transform(0, 0);
|
||||
com.jpexs.decompiler.flash.exporters.commonshape.Point p11 = strokeTransformation.transform(1, 1);
|
||||
thicknessScale = p00.distanceTo(p11) / Math.sqrt(2);
|
||||
thicknessScaleX = Math.abs(p11.x - p00.x);
|
||||
thicknessScaleY = Math.abs(p11.y - p00.y);
|
||||
thicknessScaleY = Math.abs(p11.y - p00.y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,19 +425,9 @@ public class BitmapExporter extends ShapeExporterBase {
|
||||
//always display minimum stroke of 1 pixel, no matter how zoomed it is
|
||||
if (thickness * unzoom / aaScale < 1 * SWF.unitDivisor) {
|
||||
thickness = 1 * SWF.unitDivisor / (unzoom / aaScale);
|
||||
}
|
||||
|
||||
/*
|
||||
if (Configuration.fixAntialiasConflation.get()) {
|
||||
thickness += 1 * SWF.unitDivisor / unzoom;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
if (joinStyle == BasicStroke.JOIN_MITER) {
|
||||
//lineStroke = new BasicStroke((float) thickness, capStyle, joinStyle, miterLimit);
|
||||
/*if (Configuration.allowMiterClipLinestyle.get()) {
|
||||
lineStroke = new MiterClipBasicStroke((BasicStroke) lineStroke);
|
||||
}*/
|
||||
lineStroke = new ExtendedBasicStroke((float) thickness, capStyle, ExtendedBasicStroke.JOIN_MITER_CLIP, miterLimit);
|
||||
} else {
|
||||
lineStroke = new BasicStroke((float) thickness, capStyle, joinStyle);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,426 @@
|
||||
package com.jpexs.decompiler.flash.exporters.shape.aa;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
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.graphics.ExtendedBasicStroke;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.MultipleGradientPaint;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Antialiased Shape Bitmap Exporter
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AntialiasedBitmapExporter extends BitmapExporter {
|
||||
|
||||
private final List<List<Vec2>> contours = new ArrayList<>();
|
||||
|
||||
private AntialiasTools.SceneRasterizerMSAA rz;
|
||||
|
||||
private Vec2 lastPos = null;
|
||||
|
||||
private Matrix vecTrans;
|
||||
private Matrix vecTransLines;
|
||||
|
||||
private ExportRectangle viewRect;
|
||||
|
||||
private boolean inLines = false;
|
||||
|
||||
private boolean closeLine = false;
|
||||
|
||||
private double curveFlattness = 1.0;
|
||||
|
||||
/**
|
||||
* Exports a shape to a bitmap.
|
||||
*
|
||||
* @param windingRule Winding rule
|
||||
* @param shapeNum Shape number
|
||||
* @param swf SWF
|
||||
* @param shape Shape
|
||||
* @param defaultColor Default color
|
||||
* @param image Image
|
||||
* @param unzoom Unzoom
|
||||
* @param transformation Transformation
|
||||
* @param strokeTransformation Stroke transformation
|
||||
* @param colorTransform Color transform
|
||||
* @param scaleStrokes Scale strokes
|
||||
* @param canUseSmoothing Can use smoothing
|
||||
* @param aaScale Antialias conflation reducing scale coefficient
|
||||
*/
|
||||
public static void export(int windingRule, int shapeNum, SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, double unzoom, Matrix transformation, Matrix strokeTransformation, ColorTransform colorTransform, boolean scaleStrokes, boolean canUseSmoothing, int aaScale) {
|
||||
AntialiasedBitmapExporter exporter = new AntialiasedBitmapExporter(windingRule, shapeNum, swf, shape, defaultColor, colorTransform, (int) Math.round(20 / unzoom));
|
||||
exporter.setCanUseSmoothing(canUseSmoothing);
|
||||
exporter.exportTo(shapeNum, image, unzoom, transformation, strokeTransformation, scaleStrokes, aaScale);
|
||||
}
|
||||
|
||||
protected AntialiasedBitmapExporter(int windingRule, int shapeNum, SWF swf, SHAPE shape, Color defaultColor, ColorTransform colorTransform, int thicknessDivisor) {
|
||||
super(windingRule, shapeNum, swf, shape, defaultColor, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportTo(int shapeNum, SerializableImage image, double unzoom, Matrix transformation, Matrix strokeTransformation, boolean scaleStrokes, int aaScale) {
|
||||
|
||||
this.strokeTransformation = strokeTransformation;
|
||||
calculateThicknessScale();
|
||||
//double s = Math.max(transformation.scaleX,transformation.scaleY);
|
||||
|
||||
RECT bounds = new RECT(shape.getBounds(shapeNum));
|
||||
|
||||
int maxStrokeWidth = shape.getMaxStrokeWidth(shapeNum);
|
||||
|
||||
bounds.Xmin -= maxStrokeWidth;
|
||||
bounds.Ymin -= maxStrokeWidth;
|
||||
bounds.Xmax += maxStrokeWidth;
|
||||
bounds.Ymax += maxStrokeWidth;
|
||||
|
||||
vecTrans = transformation.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor));
|
||||
viewRect = vecTrans.transform(new ExportRectangle(bounds));
|
||||
|
||||
/*viewRect.xMin -= 1;
|
||||
viewRect.yMin -= 1;
|
||||
viewRect.yMax += 1;
|
||||
viewRect.xMax += 1;*/
|
||||
viewRect.xMin = Math.floor(viewRect.xMin - unzoom - 0.5);
|
||||
viewRect.yMin = Math.floor(viewRect.yMin - unzoom - 0.5);
|
||||
viewRect.xMax = Math.ceil(viewRect.xMax + unzoom);
|
||||
viewRect.yMax = Math.ceil(viewRect.yMax + unzoom);
|
||||
|
||||
int width = (int) viewRect.getWidth();
|
||||
int height = (int) viewRect.getHeight();
|
||||
vecTrans = vecTrans.preConcatenate(Matrix.getTranslateInstance(-viewRect.xMin, -viewRect.yMin));
|
||||
vecTransLines = vecTrans.preConcatenate(Matrix.getTranslateInstance(-0.5, -0.5));
|
||||
Graphics2D g = (Graphics2D) image.getGraphics();
|
||||
|
||||
//g.setTransform(t);
|
||||
if (width <= 0 || height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
curveFlattness = 1.0 / aaScale;
|
||||
|
||||
BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
Graphics2D g2 = (Graphics2D) image2.getGraphics();
|
||||
g2.setComposite(AlphaComposite.Src);
|
||||
g2.setColor(new Color(0, 0, 0, 0));
|
||||
g2.fillRect(0, 0, width, height);
|
||||
try {
|
||||
rz = new AntialiasTools.SceneRasterizerMSAA(width, height, aaScale);
|
||||
} catch (OutOfMemoryError er) {
|
||||
System.gc();
|
||||
return;
|
||||
}
|
||||
rz.clear(0x00000000);
|
||||
Shape clip = g.getClip();
|
||||
if (clip != null) {
|
||||
AffineTransform t = new AffineTransform(g.getTransform());
|
||||
t.preConcatenate(AffineTransform.getTranslateInstance(-viewRect.xMin, -viewRect.yMin));
|
||||
clip = t.createTransformedShape(clip);
|
||||
List<List<Vec2>> clipContours = AntialiasTools.shapeToContours(clip, curveFlattness);
|
||||
rz.setClipContours(clipContours, Path2D.WIND_EVEN_ODD);
|
||||
}
|
||||
|
||||
this.image = image;
|
||||
this.scaleStrokes = scaleStrokes;
|
||||
|
||||
graphics = (Graphics2D) image.getGraphics();
|
||||
setTransform(graphics, transformation);
|
||||
defaultStroke = graphics.getStroke();
|
||||
this.unzoom = unzoom;
|
||||
this.aaScale = 1; //aaScale;
|
||||
super.export();
|
||||
|
||||
//super.exportTo(shapeNum, image, unzoom, transformation, strokeTransformation, scaleStrokes, aaScale);
|
||||
//rz.resolveToReplace(image2);
|
||||
rz.resolveTo(image2);
|
||||
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.setTransform(new AffineTransform());
|
||||
g.drawImage(image2, (int) viewRect.xMin, (int) viewRect.yMin, null);
|
||||
|
||||
/*
|
||||
g.setColor(new Color(0,0,0,128));
|
||||
g.setStroke(new BasicStroke(1));
|
||||
g.drawRect((int) viewRect.xMin, (int) viewRect.yMin, (int) viewRect.getWidth(), (int) viewRect.getHeight());
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setTransform(Graphics2D g, Matrix transformation) {
|
||||
AffineTransform at = transformation.toTransform();
|
||||
at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor));
|
||||
at.preConcatenate(AffineTransform.getTranslateInstance(-viewRect.xMin, -viewRect.yMin));
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image.
|
||||
*
|
||||
* @return Image
|
||||
*/
|
||||
public SerializableImage getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFills() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFills() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginLines() {
|
||||
inLines = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endLines(boolean close) {
|
||||
closeLine = close;
|
||||
/*if (close) {
|
||||
//path.closePath();
|
||||
}*/
|
||||
|
||||
finalizePath();
|
||||
|
||||
inLines = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(double x, double y) {
|
||||
Point2D src = new Point2D.Double(x, y);
|
||||
Point2D dst = new Point2D.Double();
|
||||
dst = (inLines ? vecTransLines : vecTrans).transform(src);
|
||||
contours.add(new ArrayList<>());
|
||||
lastPos = new Vec2(dst.getX(), dst.getY());
|
||||
contours.get(contours.size() - 1).add(lastPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineTo(double x, double y) {
|
||||
Point2D src = new Point2D.Double(x, y);
|
||||
Point2D dst = new Point2D.Double();
|
||||
dst = (inLines ? vecTransLines : vecTrans).transform(src);
|
||||
|
||||
lastPos = new Vec2(dst.getX(), dst.getY());
|
||||
contours.get(contours.size() - 1).add(lastPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void curveTo(double controlX, double controlY, double anchorX, double anchorY) {
|
||||
Point2D src = new Point2D.Double(controlX, controlY);
|
||||
Point2D dst = new Point2D.Double();
|
||||
dst = (inLines ? vecTransLines : vecTrans).transform(src);
|
||||
Vec2 controlVec2 = new Vec2(dst.getX(), dst.getY());
|
||||
src = new Point2D.Double(anchorX, anchorY);
|
||||
dst = (inLines ? vecTransLines : vecTrans).transform(src);
|
||||
Vec2 anchorVec2 = new Vec2(dst.getX(), dst.getY());
|
||||
|
||||
List<Vec2> contour = contours.get(contours.size() - 1);
|
||||
AntialiasTools.append(contour, AntialiasTools.flattenQuadraticBezier(lastPos, controlVec2, anchorVec2, curveFlattness), true);
|
||||
lastPos = anchorVec2;
|
||||
}
|
||||
|
||||
private void drawImage(BufferedImage image, int dx, int dy, int dx2, int dy2, int sx, int sy, int sx2, int sy2, ImageObserver obs, boolean smooth) {
|
||||
List<List<Vec2>> cs = new ArrayList<>();
|
||||
List<Vec2> c = new ArrayList<>();
|
||||
Point2D dst = new Point2D.Double();
|
||||
|
||||
fillTransform.transform(new Point2D.Double(dx, dy), dst);
|
||||
c.add(new Vec2(dst.getX(), dst.getY()));
|
||||
|
||||
fillTransform.transform(new Point2D.Double(dx2, dy), dst);
|
||||
c.add(new Vec2(dst.getX(), dst.getY()));
|
||||
|
||||
fillTransform.transform(new Point2D.Double(dx2, dy2), dst);
|
||||
c.add(new Vec2(dst.getX(), dst.getY()));
|
||||
|
||||
fillTransform.transform(new Point2D.Double(dx, dy2), dst);
|
||||
c.add(new Vec2(dst.getX(), dst.getY()));
|
||||
|
||||
for (int i = 0; i < c.size(); i++) {
|
||||
double x = Math.round(c.get(i).x);
|
||||
double y = Math.round(c.get(i).y);
|
||||
c.set(i, new Vec2(x, y));
|
||||
}
|
||||
|
||||
cs.add(c);
|
||||
|
||||
AffineTransform t = new AffineTransform();
|
||||
if (dx2 != dx && dy2 != dy) {
|
||||
double scaleX = (sx2 - sx) / (double) (dx2 - dx);
|
||||
double scaleY = (sy2 - sy) / (double) (dy2 - dy);
|
||||
|
||||
t = AffineTransform.getScaleInstance(scaleX, scaleY);
|
||||
t.preConcatenate(fillTransform);
|
||||
}
|
||||
|
||||
/*int w = sx2 - sx;
|
||||
int h = sy2 - sy;
|
||||
|
||||
int one = (int) (1 * unzoom);
|
||||
BufferedImage imgTrans = new BufferedImage(w + 2, h + 2, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
Graphics2D g = (Graphics2D) imgTrans.getGraphics();
|
||||
g.setComposite(AlphaComposite.Src);
|
||||
g.setColor(new Color(0,255,0,255));
|
||||
g.fillRect(0, 0, w + 2, h + 2);
|
||||
|
||||
g.drawImage(image, 1, 1, 1 + w, 1 + h, sx,sy,sx2,sy2, null);
|
||||
*/
|
||||
//t.concatenate(AffineTransform.getTranslateInstance(-1, -1));
|
||||
//t.preConcatenate(AffineTransform.getTranslateInstance(-1 * unzoom, -1 * unzoom));
|
||||
//new Rectangle2D.Double(sx, sy, sx2 - sx, sy2 - sy)
|
||||
//rz.fillContoursWithPaint(cs, windingRule, new TexturePaint(imgTrans, new Rectangle2D.Double(0,0,w+2,h+2)), t, smooth);
|
||||
//new TexturePaint(image, new Rectangle2D.Double(sx, sy, sx2 - sx, sy2 - sy))
|
||||
rz.fillContoursWithPaint(cs, windingRule, Color.black, t, smooth, image);
|
||||
}
|
||||
|
||||
private void drawImage(BufferedImage image, int x, int y, ImageObserver obs, boolean smooth) {
|
||||
drawImage(image, x, y, x + image.getWidth(), y + image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), obs, smooth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the path.
|
||||
*/
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (fillPaint != null) {
|
||||
if (fillPaint instanceof MultipleGradientPaint) {
|
||||
fillTransform.preConcatenate(graphics.getTransform());
|
||||
rz.fillContoursWithPaint(contours, Path2D.WIND_EVEN_ODD, fillPaint, fillTransform);
|
||||
} else if (fillPaint instanceof TexturePaint) {
|
||||
//rz.setClipContours(contours, Path2D.WIND_EVEN_ODD);
|
||||
fillTransform.preConcatenate(graphics.getTransform());
|
||||
|
||||
if (fillRepeat) {
|
||||
rz.fillContoursWithPaint(contours, Path2D.WIND_EVEN_ODD, fillPaint, fillTransform, fillSmooth, null);
|
||||
} else {
|
||||
drawImage(((TexturePaint) fillPaint).getImage(), 0, 0, null, fillSmooth);
|
||||
}
|
||||
} else {
|
||||
rz.fillContoursWithPaint(contours, Path2D.WIND_EVEN_ODD, fillPaint);
|
||||
}
|
||||
}
|
||||
|
||||
if ((linePaint != null && lineStroke != null) || lineColor != null) {
|
||||
Stroke stroke = lineStroke == null ? defaultStroke : lineStroke;
|
||||
Shape shape = AntialiasTools.contoursToShape(contours, Path2D.WIND_EVEN_ODD, closeLine);
|
||||
Shape strokedShape = stroke.createStrokedShape(shape);
|
||||
List<List<Vec2>> strokeContours = AntialiasTools.shapeToContours(strokedShape, curveFlattness);
|
||||
|
||||
if (linePaint != null && lineStroke != null) {
|
||||
if (linePaint instanceof MultipleGradientPaint) {
|
||||
lineTransform.preConcatenate(graphics.getTransform());
|
||||
rz.fillContoursWithPaint(strokeContours, Path2D.WIND_NON_ZERO, linePaint, lineTransform);
|
||||
} else if (linePaint instanceof TexturePaint) {
|
||||
lineTransform.preConcatenate(graphics.getTransform());
|
||||
rz.fillContoursWithPaint(strokeContours, Path2D.WIND_NON_ZERO, linePaint, lineTransform);
|
||||
} else {
|
||||
rz.fillContoursWithPaint(strokeContours, Path2D.WIND_NON_ZERO, linePaint);
|
||||
}
|
||||
} else if (lineColor != null) {
|
||||
rz.fillContoursWithPaint(strokeContours, Path2D.WIND_NON_ZERO, lineColor);
|
||||
}
|
||||
}
|
||||
|
||||
contours.clear();
|
||||
lineStroke = null;
|
||||
lineColor = null;
|
||||
fillPaint = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit, boolean noClose) {
|
||||
finalizePath();
|
||||
linePaint = null;
|
||||
lineTransform = null;
|
||||
|
||||
if (thickness == 0) {
|
||||
lineColor = null;
|
||||
return;
|
||||
}
|
||||
|
||||
lineColor = color == null ? null : color.toColor();
|
||||
int capStyle = BasicStroke.CAP_ROUND;
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
capStyle = BasicStroke.CAP_BUTT;
|
||||
break;
|
||||
case LINESTYLE2.ROUND_CAP:
|
||||
capStyle = BasicStroke.CAP_ROUND;
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
capStyle = BasicStroke.CAP_SQUARE;
|
||||
break;
|
||||
}
|
||||
int joinStyle = BasicStroke.JOIN_ROUND;
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
joinStyle = BasicStroke.JOIN_BEVEL;
|
||||
break;
|
||||
case LINESTYLE2.MITER_JOIN:
|
||||
joinStyle = BasicStroke.JOIN_MITER;
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
joinStyle = BasicStroke.JOIN_ROUND;
|
||||
break;
|
||||
}
|
||||
if (scaleStrokes) {
|
||||
switch (scaleMode) {
|
||||
case "VERTICAL":
|
||||
thickness *= thicknessScaleY;
|
||||
break;
|
||||
case "HORIZONTAL":
|
||||
thickness *= thicknessScaleX;
|
||||
break;
|
||||
case "NORMAL":
|
||||
thickness *= thicknessScale;
|
||||
break;
|
||||
case "NONE":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
thickness *= unzoom / SWF.unitDivisor;
|
||||
|
||||
//always display minimum stroke of 1 pixel, no matter how zoomed it is
|
||||
if (thickness < 1) {
|
||||
thickness = 1;
|
||||
}
|
||||
|
||||
if (joinStyle == BasicStroke.JOIN_MITER) {
|
||||
lineStroke = new ExtendedBasicStroke((float) thickness, capStyle, ExtendedBasicStroke.JOIN_MITER_CLIP, miterLimit);
|
||||
} else {
|
||||
lineStroke = new BasicStroke((float) thickness, capStyle, joinStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.jpexs.decompiler.flash.exporters.shape.aa;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Vec2 {
|
||||
public final double x;
|
||||
public final double y;
|
||||
|
||||
public Vec2(double x, double y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + x + ", " + y + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 71 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
|
||||
hash = 71 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Vec2 other = (Vec2) obj;
|
||||
if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
|
||||
return false;
|
||||
}
|
||||
return Double.doubleToLongBits(this.y) == Double.doubleToLongBits(other.y);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -145,7 +145,7 @@ public abstract class DrawableTag extends CharacterTag implements BoundedTag {
|
||||
|
||||
@Override
|
||||
public RECT getRectWithFilters() {
|
||||
RECT r = new RECT(getRect());
|
||||
RECT r = new RECT(getRectWithStrokes());
|
||||
Dimension filterDimension = getFilterDimensions();
|
||||
r.Xmin -= filterDimension.width;
|
||||
r.Xmax += filterDimension.width;
|
||||
|
||||
@@ -219,6 +219,9 @@ public abstract class ShapeTag extends DrawableTag implements LazyObject {
|
||||
r.Ymin -= maxWidth;
|
||||
r.Xmax += maxWidth;
|
||||
r.Ymax += maxWidth;
|
||||
|
||||
r.Xmin -= SWF.unitDivisor / 2;
|
||||
r.Ymin -= SWF.unitDivisor / 2;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class SHAPE implements NeedsCharacters, Serializable {
|
||||
public RECT getEdgeBounds() {
|
||||
return SHAPERECORD.getBounds(shapeRecords, null, 1, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears cached outline.
|
||||
*/
|
||||
@@ -206,4 +206,8 @@ public class SHAPE implements NeedsCharacters, Serializable {
|
||||
ret.shapeRecords.add(new EndShapeRecord());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int getMaxStrokeWidth(int shapeNum) {
|
||||
return SHAPERECORD.getMaxStrokeWidth(shapeRecords, null, shapeNum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab
|
||||
@Override
|
||||
public RECT getBounds(int shapeNum) {
|
||||
return SHAPERECORD.getBounds(shapeRecords, lineStyles, shapeNum, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates morph shape tag.
|
||||
@@ -291,4 +291,9 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStrokeWidth(int shapeNum) {
|
||||
return SHAPERECORD.getMaxStrokeWidth(shapeRecords, lineStyles, shapeNum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +186,13 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min_x == Integer.MAX_VALUE) {
|
||||
min_x = 0;
|
||||
}
|
||||
if (min_y == Integer.MAX_VALUE) {
|
||||
min_y = 0;
|
||||
}
|
||||
return new RECT(min_x, max_x, min_y, max_y);
|
||||
}
|
||||
|
||||
@@ -537,4 +544,33 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali
|
||||
}
|
||||
|
||||
public abstract boolean isTooLarge();
|
||||
|
||||
public static int getMaxStrokeWidth(List<SHAPERECORD> records, LINESTYLEARRAY baseLineStyles, int shapeNum) {
|
||||
LINESTYLEARRAY lineStyles = baseLineStyles;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
for (SHAPERECORD rec : records) {
|
||||
if (rec instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord scr = (StyleChangeRecord) rec;
|
||||
if (scr.stateNewStyles) {
|
||||
lineStyles = scr.lineStyles;
|
||||
}
|
||||
if (scr.stateLineStyle) {
|
||||
if (scr.lineStyle > 0) {
|
||||
int width;
|
||||
if (shapeNum <= 3) {
|
||||
width = lineStyles.lineStyles[scr.lineStyle - 1].width;
|
||||
} else {
|
||||
width = lineStyles.lineStyles2[scr.lineStyle - 1].width;
|
||||
}
|
||||
if (width > ret) {
|
||||
ret = width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user