diff --git a/CHANGELOG.md b/CHANGELOG.md index 07eacc043..aa6e84ce6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to this project will be documented in this file. - AS1/2 new keyword on empty method name - AS2 getters and setters decoding - [#116] §§push at the end of switch branches +- Convolution matrix filter display and editing ## [19.0.0] - 2023-10-01 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index add17862d..ff2c883ee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -2219,11 +2219,9 @@ public class SWFInputStream implements AutoCloseable { ret.matrixY = readUI8("matrixY"); ret.divisor = readFLOAT("divisor"); ret.bias = readFLOAT("bias"); - ret.matrix = new float[ret.matrixX][ret.matrixY]; - for (int x = 0; x < ret.matrixX; x++) { - for (int y = 0; y < ret.matrixY; y++) { - ret.matrix[x][y] = readFLOAT("cell"); - } + ret.matrix = new float[ret.matrixX * ret.matrixY]; + for (int i = 0; i < ret.matrixX * ret.matrixY; i++) { + ret.matrix[i] = readFLOAT("cell"); } ret.defaultColor = readRGBA("defaultColor"); ret.reserved = (int) readUB(6, "reserved"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index 2908b7f00..a85b87f07 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -896,9 +896,9 @@ public class SWFOutputStream extends OutputStream { writeUI8(value.matrixY); writeFLOAT(value.divisor); writeFLOAT(value.bias); - for (int x = 0; x < value.matrixX; x++) { - for (int y = 0; y < value.matrixY; y++) { - writeFLOAT(value.matrix[x][y]); + for (int y = 0; y < value.matrixY; y++) { + for (int x = 0; x < value.matrixX; x++) { + writeFLOAT(value.matrix[y * value.matrixX + x]); } } writeRGBA(value.defaultColor); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index 541ea8dd4..270e9a34d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -816,13 +816,11 @@ public class FrameExporter { } if (filter instanceof CONVOLUTIONFILTER) { - CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) filter; - int height = cf.matrix.length; - int width = cf.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] = cf.matrix[x][y] * cf.divisor + cf.bias; + CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) filter; + float[] matrix2 = new float[cf.matrixX * cf.matrixY]; + for (int y = 0; y < cf.matrixY; y++) { + for (int x = 0; x < cf.matrixX; x++) { + matrix2[y * cf.matrixX + x] = cf.matrix[y * cf.matrixX + x] / cf.divisor + cf.bias; } } String mat = "["; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 2fed3b5f8..6d727b9ee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -766,10 +766,11 @@ public class Timeline { int dtime = time - dframe; ExportRectangle viewRect2 = new ExportRectangle(viewRect); + double deltaXMax = 0; + double deltaYMax = 0; + if (filters != null && filters.size() > 0) { // calculate size after applying the filters - double deltaXMax = 0; - double deltaYMax = 0; for (FILTER filter : filters) { double x = filter.getDeltaX(); double y = filter.getDeltaY(); @@ -786,10 +787,8 @@ public class Timeline { viewRect2.yMax += deltaYMax * SWF.unitDivisor; } - rect.xMin -= SWF.unitDivisor; - rect.yMin -= SWF.unitDivisor; - /*rect.xMin = Math.max(0, rect.xMin); - rect.yMin = Math.max(0, rect.yMin);*/ + //rect.xMin -= SWF.unitDivisor; + //rect.yMin -= SWF.unitDivisor; drawMatrix.translate(rect.xMin, rect.yMin); drawMatrix.translateX /= SWF.unitDivisor; drawMatrix.translateY /= SWF.unitDivisor; @@ -800,8 +799,8 @@ public class Timeline { 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; + newWidth = Math.min(image.getWidth() - deltaX, newWidth); + newHeight = Math.min(image.getHeight() - deltaY, newHeight); if (newWidth <= 0 || newHeight <= 0) { return; @@ -888,14 +887,8 @@ public class Timeline { } if (filters != null) { - /*try { - ImageIO.write(img.getBufferedImage(), "PNG", new File("c:\\FlashRelated\\gwint\\out.png")); - } catch (IOException ex) { - Logger.getLogger(Timeline.class.getName()).log(Level.SEVERE, null, ex); - } - System.exit(0);*/ for (FILTER filter : filters) { - img = filter.apply(img, unzoom); + img = filter.apply(img, unzoom, (int)deltaXMax, (int)deltaYMax, (int)Math.round(newWidth - 2 * deltaXMax), (int)Math.round(newHeight - 2 * deltaYMax)); } } if (blendMode > 1) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BEVELFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BEVELFILTER.java index 990a16156..e18839412 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BEVELFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BEVELFILTER.java @@ -102,7 +102,7 @@ public class BEVELFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { int type = Filtering.INNER; if (onTop && !innerShadow) { type = Filtering.FULL; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BLURFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BLURFILTER.java index 001a9a5ce..1d22239c3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BLURFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/BLURFILTER.java @@ -55,7 +55,7 @@ public class BLURFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { return Filtering.blur(src, (int) Math.round(blurX * zoom), (int) Math.round(blurY * zoom), passes); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/COLORMATRIXFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/COLORMATRIXFILTER.java index 70aabd5ef..ff091770d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/COLORMATRIXFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/COLORMATRIXFILTER.java @@ -41,7 +41,7 @@ public class COLORMATRIXFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { float[][] matrix2 = new float[4][5]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 5; x++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/CONVOLUTIONFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/CONVOLUTIONFILTER.java index 14f9cff0a..4379b4709 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/CONVOLUTIONFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/CONVOLUTIONFILTER.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.SerializableImage; +import java.awt.Color; /** * Two-dimensional discrete convolution filter. @@ -33,36 +34,36 @@ public class CONVOLUTIONFILTER extends FILTER { * Horizontal matrix size */ @SWFType(BasicType.UI8) - public int matrixX; + public int matrixX = 3; /** * Vertical matrix size */ @SWFType(BasicType.UI8) - public int matrixY; + public int matrixY = 3; /** * Divisor applied to the matrix values */ @SWFType(BasicType.FLOAT) - public float divisor; + public float divisor = 1f; /** * Bias applied to the matrix values */ @SWFType(BasicType.FLOAT) - public float bias; + public float bias = 0f; /** * Matrix values */ @SWFType(BasicType.FLOAT) - public float[][] matrix = new float[0][0]; + public float[] matrix = new float[9]; /** * Default color for pixels outside the image */ - public RGBA defaultColor; + public RGBA defaultColor = new RGBA(Color.BLACK); @Reserved @SWFType(value = BasicType.UB, count = 6) @@ -86,25 +87,17 @@ public class CONVOLUTIONFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { - 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); + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { + return Filtering.convolution(src, matrix, matrixX, matrixY, divisor, bias, defaultColor.toColor(), clamp, preserveAlpha, srcX, srcY, srcW, srcH); } @Override public double getDeltaX() { - return 0; + return ((matrixX-1)>>1) + 1; } @Override public double getDeltaY() { - return 0; + return ((matrixY-1)>>1) + 1; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ConvolveOp.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ConvolveOp.java new file mode 100644 index 000000000..c3a6d2e30 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ConvolveOp.java @@ -0,0 +1,269 @@ +package com.jpexs.decompiler.flash.types.filters; + +import java.awt.Color; +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; +import java.awt.image.ImagingOpException; +import java.awt.image.Kernel; +import java.awt.image.Raster; +import java.awt.image.RasterOp; +import java.awt.image.WritableRaster; + +/** + * Convolution filter. + */ +public class ConvolveOp implements BufferedImageOp, RasterOp { + + private final Kernel kernel; + private final RenderingHints hints; + private final boolean preserveAlpha; + private final float bias; + private final Color defaultColor; + private final boolean clamp; + private final float divisor; + private final int srcX; + private final int srcY; + private final int srcWidth; + private final int srcHeight; + + + public ConvolveOp(Kernel kernel, + RenderingHints hints, + float divisor, + float bias, + Color defaultColor, + boolean clamp, + boolean preserveAlpha, + int srcX, + int srcY, + int srcWidth, + int srcHeight + ) { + this.kernel = kernel; + this.hints = hints; + this.bias = bias; + this.defaultColor = defaultColor; + this.clamp = clamp; + this.preserveAlpha = preserveAlpha; + this.divisor = divisor; + this.srcX = srcX; + this.srcY = srcY; + this.srcWidth = srcWidth; + this.srcHeight = srcHeight; + } + + @Override + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == dst) { + throw new IllegalArgumentException("Source and destination images " + + "cannot be the same."); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, src.getColorModel()); + } + + BufferedImage src1 = src; + BufferedImage dst1 = dst; + if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType()) { + dst1 = createCompatibleDestImage(src, src.getColorModel()); + } + + filter(src1.getRaster(), dst1.getRaster()); + + if (dst1 != dst) { + new ColorConvertOp(hints).filter(dst1, dst); + } + + return dst; + } + + @Override + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) { + if (dstCM != null) { + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isAlphaPremultiplied(), null); + } + + return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); + } + + @Override + public final RenderingHints getRenderingHints() { + return hints; + } + + public final Kernel getKernel() { + return (Kernel) kernel.clone(); + } + + @Override + public final WritableRaster filter(Raster src, WritableRaster dest) { + if (src == dest) { + throw new IllegalArgumentException("src == dest is not allowed."); + } + if (dest == null) { + dest = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dest.getNumBands()) { + throw new ImagingOpException("src and dest have different band counts."); + } + + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + int left = kernel.getXOrigin(); + int top = kernel.getYOrigin(); + + int[] maxValue = src.getSampleModel().getSampleSize(); + for (int i = 0; i < maxValue.length; i++) { + maxValue[i] = (int) Math.pow(2, maxValue[i]) - 1; + } + + float[] kvals = kernel.getKernelData(null); + + for (int x = srcX - left; x < srcX + srcWidth + left + 1; x++) { + for (int y = srcY - top; y < srcY + srcHeight + top + 1; y++) { + float a; + if (preserveAlpha && (x < srcX || y < srcY || x >= srcX + srcWidth + 1 || y >= srcY + srcHeight + 1)) { + dest.setSample(x, y, 3, 255); + a = 255; + } else { + if (preserveAlpha) { + a = src.getSample(x, y, 3); + dest.setSample(x, y, 3, a); + } else { + a = calculateBand(src, dest, maxValue, kvals, kWidth, kHeight, left, top, x, y, 3, 255f, false); + } + } + + for (int b = 0; b < 3; b++) { + calculateBand(src, dest, maxValue, kvals, kWidth, kHeight, left, top, x, y, b, a, true); + } + } + } + return dest; + } + + private float calculateBand( + Raster src, + WritableRaster dest, + int[] maxValue, + float[] kvals, + int kWidth, + int kHeight, + int left, + int top, + int x, + int y, + int b, + float alpha, + boolean multiply + ) { + float nv = 0; + for (int i = 0; i < kHeight; i++) { + for (int j = 0; j < kWidth; j++) { + int nSrcX = x - left + j; + int nSrcY = y - top + i; + boolean outSide = false; + if (nSrcX < srcX) { + nSrcX = srcX; + outSide = true; + } + if (nSrcX >= srcX + srcWidth + 1) { + nSrcX = srcX + srcWidth - 1; + outSide = true; + } + if (nSrcY < srcY) { + nSrcY = srcY; + outSide = true; + } + if (nSrcY >= srcY + srcHeight + 1) { + nSrcY = srcY + srcHeight - 1; + outSide = true; + } + + float v = 0; + if (outSide && !clamp) { + switch (b) { + case 0: + v = defaultColor.getRed() * maxValue[0] / 255f; + break; + case 1: + v = defaultColor.getGreen() * maxValue[1] / 255f; + break; + case 2: + v = defaultColor.getBlue() * maxValue[2] / 255f; + break; + case 3: + v = defaultColor.getAlpha() * maxValue[3] / 255f; + break; + } + } else { + + int srcRealX = nSrcX; + int srcRealY = nSrcY; + + v = src.getSample(srcRealX, srcRealY, b); + + if (multiply) { + float sa = src.getSample(srcRealX, srcRealY, 3); + if (sa == 0f) { + v = 0; + } else { + v = v * 255f / sa; + } + } + } + + nv += v * kvals[i * kWidth + j]; + } + } + nv /= divisor; + nv += bias; + + if (nv > maxValue[b]) { + nv = maxValue[b]; + } else if (nv < 0) { + nv = 0; + } + if (multiply) { + nv = nv * alpha / 255f; + } + nv = Math.round(nv); + int destX = x; + int destY = y; + + dest.setSample(destX, destY, b, nv); + return nv; + } + + @Override + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + @Override + public final Rectangle2D getBounds2D(BufferedImage src) { + return src.getRaster().getBounds(); + } + + @Override + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + @Override + public final Point2D getPoint2D(Point2D src, Point2D dst) { + if (dst == null) { + return (Point2D) src.clone(); + } + dst.setLocation(src); + return dst; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/DROPSHADOWFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/DROPSHADOWFILTER.java index 422c424d3..e1c7de8d1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/DROPSHADOWFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/DROPSHADOWFILTER.java @@ -92,7 +92,7 @@ public class DROPSHADOWFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { return Filtering.dropShadow(src, (int) Math.round(blurX * zoom), (int) Math.round(blurY * zoom), (int) (angle * 180 / Math.PI), distance * zoom, dropShadowColor.toColor(), innerShadow, passes, strength, knockout, compositeSource); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/FILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/FILTER.java index a3afdd403..04e89d424 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/FILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/FILTER.java @@ -45,7 +45,7 @@ public abstract class FILTER implements Serializable { this.id = id; } - public abstract SerializableImage apply(SerializableImage src, double zoom); + public abstract SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH); public abstract double getDeltaX(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/Filtering.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/Filtering.java index 7d2e50639..3c601ef2c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/Filtering.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/Filtering.java @@ -28,7 +28,6 @@ import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; -import java.awt.image.ConvolveOp; import java.awt.image.DataBufferInt; import java.awt.image.Kernel; @@ -559,9 +558,36 @@ public class Filtering { return getRGB(retImg); } - public static SerializableImage convolution(SerializableImage 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)); + public static SerializableImage convolution( + SerializableImage src, + float[] matrix, + int w, + int h, + float divisor, + float bias, + Color defaultColor, + boolean clamp, + boolean preserveAlpha, + int srcX, + int srcY, + int srcWidth, + int srcHeight + ) { + Kernel kernel = new Kernel(w, h, matrix); + BufferedImage dst = new BufferedImage(src.getWidth() + 1, src.getHeight() + 1, src.getType()); + BufferedImageOp op = new ConvolveOp( + kernel, + new RenderingHints(null), + divisor, + bias, + defaultColor, + clamp, + preserveAlpha, + srcX, + srcY, + srcWidth, + srcHeight + ); op.filter(src.getBufferedImage(), dst); return new SerializableImage(dst); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GLOWFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GLOWFILTER.java index 2ab37e034..0dc6ffffc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GLOWFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GLOWFILTER.java @@ -80,7 +80,7 @@ public class GLOWFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { return Filtering.glow(src, (int) Math.round(blurX * zoom), (int) Math.round(blurY * zoom), strength, glowColor.toColor(), innerGlow, knockout, passes); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTBEVELFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTBEVELFILTER.java index ed043fb0d..d225b0cfc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTBEVELFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTBEVELFILTER.java @@ -104,7 +104,7 @@ public class GRADIENTBEVELFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { List colors = new ArrayList<>(); List ratios = new ArrayList<>(); for (int i = 0; i < gradientColors.length; i++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTGLOWFILTER.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTGLOWFILTER.java index 61ec95765..fd9dec1f4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTGLOWFILTER.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/GRADIENTGLOWFILTER.java @@ -107,7 +107,7 @@ public class GRADIENTGLOWFILTER extends FILTER { } @Override - public SerializableImage apply(SerializableImage src, double zoom) { + public SerializableImage apply(SerializableImage src, double zoom, int srcX, int srcY, int srcW, int srcH) { List colors = new ArrayList<>(); List ratios = new ArrayList<>(); for (int i = 0; i < gradientColors.length; i++) { diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java index cb62fee40..485b37f3a 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.generictageditors.Amf3ValueEditor; import com.jpexs.decompiler.flash.gui.generictageditors.BinaryDataEditor; import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.ChangeListener; import com.jpexs.decompiler.flash.gui.generictageditors.ColorEditor; import com.jpexs.decompiler.flash.gui.generictageditors.EnumEditor; import com.jpexs.decompiler.flash.gui.generictageditors.FullSized; @@ -55,6 +56,7 @@ import com.jpexs.decompiler.flash.types.annotations.Table; import com.jpexs.decompiler.flash.types.annotations.UUID; import com.jpexs.decompiler.flash.types.annotations.parser.AnnotationParseException; import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; +import com.jpexs.decompiler.flash.types.filters.CONVOLUTIONFILTER; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.ConcreteClasses; import com.jpexs.helpers.ReflectionTools; @@ -301,7 +303,7 @@ public class GenericTagTreePanel extends GenericTagPanel { for (int i = 0; i < fnode.fieldSet.size(); i++) { Field field = fnode.fieldSet.get(i); int index = fnode.index; - Object obj = fnode.obj; + final Object obj = fnode.obj; Class type; boolean isByteArray = field.getType().equals(byte[].class); try { @@ -361,7 +363,7 @@ public class GenericTagTreePanel extends GenericTagPanel { editors = new ArrayList<>(); } editors.add(editor); - } + } JPanel pan = new JPanel(); FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 0, 0); fl.setAlignOnBaseline(true); @@ -446,6 +448,24 @@ public class GenericTagTreePanel extends GenericTagPanel { try { editor.validateValue(); if (editor.save()) { + + if (editor.getObject() instanceof CONVOLUTIONFILTER) { + String fname = editor.getFieldName(); + if ("matrixX".equals(fname) || "matrixY".equals(fname)) { + CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) editor.getObject(); + if (cf.matrix.length != cf.matrixX * cf.matrixY) { + float[] newmatrix = new float[cf.matrixX * cf.matrixY]; + int copycount = cf.matrix.length; + if (copycount > cf.matrixX * cf.matrixY) { + copycount = cf.matrixX * cf.matrixY; + } + System.arraycopy(cf.matrix, 0, newmatrix, 0, copycount); + cf.matrix = newmatrix; + } + } + } + + modified = true; } } catch (IllegalArgumentException iex) { diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/Amf3ValueEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/Amf3ValueEditor.java index 089fcc55c..0f9e6b81c 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/Amf3ValueEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/Amf3ValueEditor.java @@ -261,4 +261,8 @@ public class Amf3ValueEditor extends JPanel implements GenericTagEditor, FullSiz return Helper.escapeHTML(getChangedValue().toString()); } + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/BinaryDataEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/BinaryDataEditor.java index d47883964..b4e343b61 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/BinaryDataEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/BinaryDataEditor.java @@ -195,4 +195,9 @@ public class BinaryDataEditor extends JPanel implements GenericTagEditor { public void added() { } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java index fb18e1545..6f5cb9072 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java @@ -114,4 +114,9 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor { public String getReadOnlyValue() { return getChangedValue().toString(); } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java index 4ee54b41d..89a7f2c15 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java @@ -280,4 +280,9 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe int h = System.identityHashCode(this); return "     " + getChangedValue().toString(); } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java index b6062679f..9eab66f51 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java @@ -155,4 +155,9 @@ public class EnumEditor extends JComboBox> implements Gene public String getReadOnlyValue() { return getChangedValue().toString(); } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/GenericTagEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/GenericTagEditor.java index 0d2a97409..16aab08ff 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/GenericTagEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/GenericTagEditor.java @@ -41,4 +41,6 @@ public interface GenericTagEditor { public String getReadOnlyValue(); public void validateValue(); + + public Object getObject(); } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java index b497b718b..086fa540e 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java @@ -244,4 +244,9 @@ public class NumberEditor extends JSpinner implements GenericTagEditor { public String getReadOnlyValue() { return getChangedValue().toString(); } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java index 208b28f79..6cc6e6b38 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java @@ -147,4 +147,9 @@ public class StringEditor extends JTextArea implements GenericTagEditor { @Override public void validateValue() { } + + @Override + public Object getObject() { + return obj; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/UUIDEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/UUIDEditor.java index 6af6dfe8a..4413e4b22 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/UUIDEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/UUIDEditor.java @@ -161,4 +161,9 @@ public class UUIDEditor extends JTextField implements GenericTagEditor { @Override public void validateValue() { } + + @Override + public Object getObject() { + return obj; + } }