diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe8ab99b..0af276e00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ All notable changes to this project will be documented in this file. - Option to enter custom zoom level by clicking on zoom percentage label - Show in Simple editor context menu item for timelined items (sprites, buttons, swfs) - Simple editor - change background color -- Simple editor - filters (without editing convolution, colormatrix) +- Simple editor - filters (without editing convolution) ### Fixed - [#2424] DefineEditText handling of letterSpacing, font size on incorrect values @@ -72,6 +72,7 @@ All notable changes to this project will be documented in this file. - Simple editor - white square on top left corner of the timeline - Bevel and Glow filters incorrect rendering - Incorrect cursor handling when placed object has filters +- FLA export - Rounding errors on COLORMATRIXFILTER contrast ### Removed - Option to preview flash items via ActiveX component is no longer available. diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ColorMatrixConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ColorMatrixConvertor.java new file mode 100644 index 000000000..6cdac4898 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/filters/ColorMatrixConvertor.java @@ -0,0 +1,350 @@ +package com.jpexs.decompiler.flash.types.filters; + +/** + * Converts brightness, saturation, contrast and hue to color matrix and + * vice-versa + * + * @author JPEXS + */ +public class ColorMatrixConvertor { + + private static double[] contrastMap = { + // 0 1 2 3 4 5 6 7 8 9 + /*0*/0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, + /*1*/ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, + /*2*/ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, + /*3*/ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, + /*4*/ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, + /*5*/ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, + /*6*/ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, + /*7*/ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, + /*8*/ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, + /*9*/ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, + /*10*/ 10.0}; + private float[] matrix = new float[]{ + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0 + }; + + private int brightness = 0; + private int saturation = 0; + private int contrast = 0; + private int hue = 0; + + public ColorMatrixConvertor(float[] matrix) { + this.matrix = matrix; + convertFromMatrix(); + } + + public ColorMatrixConvertor() { + } + + public int getBrightness() { + return brightness; + } + + public int getSaturation() { + return saturation; + } + + public int getContrast() { + return contrast; + } + + public int getHue() { + return hue; + } + + public void setBrightness(int brightness) { + if (brightness < -100) { + brightness = -100; + } + if (brightness > 100) { + brightness = 100; + } + this.brightness = brightness; + convertToMatrix(); + } + + public void setContrast(int contrast) { + if (contrast < -100) { + contrast = -100; + } + if (contrast > 100) { + contrast = 100; + } + + this.contrast = contrast; + convertToMatrix(); + } + + public void setHue(int hue) { + if (hue < -180) { + hue = -180; + } + if (hue > 180) { + hue = 180; + } + this.hue = hue; + convertToMatrix(); + } + + public void setSaturation(int saturation) { + if (saturation < -100) { + saturation = -100; + } + if (saturation > 100) { + saturation = 100; + } + + this.saturation = saturation; + convertToMatrix(); + } + + public void setMatrix(float[] matrix) { + this.matrix = matrix; + + convertFromMatrix(); + } + + public float[] getMatrix() { + return matrix; + } + + private void convertToMatrix() { + + float b = brightness; + + float c; + if (contrast == 0) { + c = 1; + } else if (contrast > 0) { + c = (float) contrastMap[contrast] + 1; + } else { + c = contrast / 100f + 1; + } + + float s; + if (saturation == 0) { + s = 1; + } else if (saturation > 0) { + s = 1.0f + (3 * saturation / 100f); // max value is 4 + } else { + s = saturation / 100f + 1; + } + float h = (float) Math.toRadians(hue); + + float[][] mBrightness = new float[][]{ + {1, 0, 0, 0, b}, + {0, 1, 0, 0, b}, + {0, 0, 1, 0, b}, + {0, 0, 0, 1, 0}, + {0, 0, 0, 0, 1} + }; + + float t = 0.5f * (1f - c) * 127f; + float[][] mContrast = new float[][]{ + {c, 0, 0, 0, t}, + {0, c, 0, 0, t}, + {0, 0, c, 0, t}, + {0, 0, 0, 1, 0}, + {0, 0, 0, 0, 1} + }; + + float lumSatR = 0.3086f; + float lumSatG = 0.6094f; + float lumSatB = 0.0820f; + + float[][] mSaturation = new float[][]{ + {s + (1 - s) * lumSatR, (1 - s) * lumSatG, (1 - s) * lumSatB, 0, 0}, + {(1 - s) * lumSatR, s + (1 - s) * lumSatG, (1 - s) * lumSatB, 0, 0}, + {(1 - s) * lumSatR, (1 - s) * lumSatG, s + (1 - s) * lumSatB, 0, 0}, + {0, 0, 0, 1, 0}, + {0, 0, 0, 0, 1} + }; + + float lumHueR = 0.213f; + float lumHueG = 0.715f; + float lumHueB = 0.072f; + + float cosH = (float) Math.cos(h); + float sinH = (float) Math.sin(h); + + float[][] mHue = new float[][]{ + { + lumHueR + cosH * (1 - lumHueR) + sinH * (-lumHueR), + lumHueG + cosH * (-lumHueG) + sinH * (-lumHueG), + lumHueB + cosH * (-lumHueB) + sinH * (1 - lumHueB), + 0f, + 0f + }, + { + lumHueR + cosH * (-lumHueR) + sinH * 0.143f, + lumHueG + cosH * (1 - lumHueG) + sinH * 0.140f, + lumHueB + cosH * (-lumHueB) + sinH * (-0.283f), + 0f, + 0f + }, + { + lumHueR + cosH * (-lumHueR) + sinH * (-(1 - lumHueR)), + lumHueG + cosH * (-lumHueG) + sinH * lumHueG, + lumHueB + cosH * (1 - lumHueB) + sinH * lumHueB, + 0f, + 0f + }, + {0f, 0f, 0f, 1f, 0f}, + {0f, 0f, 0f, 0f, 1f} + }; + + float[][] result2d = multiplyMatrices(mContrast, mBrightness); + result2d = multiplyMatrices(mSaturation, result2d); + result2d = multiplyMatrices(mHue, result2d); + + float[] result = new float[5 * 4]; + int i = 0; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 5; x++) { + result[i] = result2d[y][x]; + i++; + } + } + + this.matrix = result; + } + + public static float[][] multiplyMatrices(float[][] a, float[][] b) { + float[][] result = new float[5][5]; + + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + result[i][j] = 0; + for (int k = 0; k < 5; k++) { + result[i][j] += a[i][k] * b[k][j]; + } + } + } + return result; + } + + private static int normHue(double h) { + if (Double.isNaN(h)) { + h = -Math.PI; + } + int ret = (int) Math.round(h * 180 / Math.PI); + while (ret > 180) { + ret -= 360; + } + while (ret < -180) { + ret += 360; + } + return ret; + } + + private static int normBrightness(double b) { + if (Double.isNaN(b)) { + b = -100; + } + return (int) Math.round(b); + } + + private static int normSaturation(double s) { + if (Double.isNaN(s)) { + return -100; + } else if (s == 1) { + return 0; + } else if (s - 1 < 0) { + return (int) Math.round((s - 1) * 100); + } else { + return (int) Math.round(((s - 1) * 100) / 3); + } + } + + private static int normContrast(double c) { + if (c == 127) { + return 0; + } else if (c - 127 < 0) { + return (int) Math.round((c - 127) * 100.0 / 127.0); + } else { + c = (c - 127) / 127; + c = Math.round(c * 100.0) / 100.0; + for (int i = 0; i < contrastMap.length; i++) { + if (contrastMap[i] >= c) { + return i; + } + } + } + return contrastMap.length - 1; + } + + private static boolean sameDouble(double a, double b) { + final double EPSILON = 0.00001; + return a == b ? true : Math.abs(a - b) < EPSILON; + } + + private void convertFromMatrix() { + float[][] matrix2d = new float[5][5]; + int index = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + matrix2d[j][i] = this.matrix[index]; + index++; + } + } + double a11 = matrix2d[0][0]; + double a12 = matrix2d[0][1]; + double a13 = matrix2d[0][2]; + double a21 = matrix2d[1][0]; + double a22 = matrix2d[1][1]; + double a23 = matrix2d[1][2]; + double a31 = matrix2d[2][0]; + double a32 = matrix2d[2][1]; + double a33 = matrix2d[2][2]; + double a41 = matrix2d[4][0]; + + double b; + double c; + double h; + double s; + + //Magic formulas calculated long time ago with Wolphram Alpha. + b = (24872168661075.0 * a11 * a11 - 151430415740925.0 * a12 + 341095051289483.0 * a12 * a12 - 15302094789450.0 * a13 + 82428663495404.0 * a12 * a13 + - 4592294873812.0 * a13 * a13 + 43556251470.0 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13)) + 2384730956550.0 * a12 * a41 + 240977870700.0 * a13 * a41 + - 685925220 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + * a41 + 465 * a11 * (466201717582.0 * a12 + 55756962908.0 * a13 + 764132175 * (-127 + 2 * a41))) + / (391687695450.0 * a11 * a11 + 5371575610858.0 * a12 * a12 + 1298089188904.0 * a12 * a13 - 72319604312.0 * a13 * a13 + + 1860 * a11 * (1835439833 * a12 + 219515602 * a13)); + c = (127 * (495225 * a11 + 1661845 * a12 + 167930 * a13 + + 478 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)))) + / 717495; + h = 2 * (Math.atan((-465 * a11 + 287 * a12 + 178 * a13 + Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13))) / (500. * (a12 - a13))) + Math.PI/*+ Pi*C(1)*/); + s = (1543 * (-103355550 * a11 * a11 - 158872382 * a12 * a12 + 190161784 * a12 * a13 - 134644952 * a13 * a13 + + 1661845 * a12 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13)) + 167930 * a13 + * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + + 465 * a11 * (274372 * a12 + 170168 * a13 + 1065 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))))) + / (195843847725.0 * a11 * a11 + 2685787805429.0 * a12 * a12 + 649044594452.0 * a12 * a13 - 36159802156.0 * a13 * a13 + + 930 * a11 * (1835439833 * a12 + 219515602 * a13)); + + if (sameDouble(410 * a12, 1543 * a31) && sameDouble(410 * a12, 1543 * a32) && sameDouble(3047 * a12, 1543 * a21) && sameDouble(3047 * a12, 1543 * a23) + && sameDouble(a22, a11 + (1504 * a12) / 1543.) && sameDouble((1133 * a12) / 1543. + a33, a11) + && !sameDouble(a11, a12) && !sameDouble(1543 * a11 + 3457 * a12, 0)) { + h = 0; + } + + brightness = normBrightness(b); + contrast = normContrast(c); + saturation = normSaturation(s); + hue = normHue(h); + } + + @Override + public String toString() { + return "[brightness: " + brightness + ", contrast:" + contrast + ", saturation:" + saturation + ", hue: " + hue + "]"; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 8e4248eed..113b5ac64 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -137,6 +137,7 @@ import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; import com.jpexs.decompiler.flash.types.filters.BLURFILTER; import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; +import com.jpexs.decompiler.flash.types.filters.ColorMatrixConvertor; import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; import com.jpexs.decompiler.flash.types.filters.FILTER; import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; @@ -6037,129 +6038,15 @@ public class XFLConverter { } - private static int normHue(double h) { - if (Double.isNaN(h)) { - h = -Math.PI; - } - int ret = (int) Math.round(h * 180 / Math.PI); - while (ret > 180) { - ret -= 360; - } - while (ret < -180) { - ret += 360; - } - return ret; - } - - private static int normBrightness(double b) { - if (Double.isNaN(b)) { - b = -100; - } - return (int) Math.round(b); - } - - private static int normSaturation(double s) { - if (Double.isNaN(s)) { - return -100; - } else if (s == 1) { - return 0; - } else if (s - 1 < 0) { - return (int) Math.round((s - 1) * 100); - } else { - return (int) Math.round(((s - 1) * 100) / 3); - } - } - - private static int normContrast(double c) { - double[] ctrMap = { - // 0 1 2 3 4 5 6 7 8 9 - /*0*/0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, - /*1*/ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, - /*2*/ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, - /*3*/ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, - /*4*/ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, - /*5*/ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, - /*6*/ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, - /*7*/ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, - /*8*/ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, - /*9*/ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, - /*10*/ 10.0}; - if (c == 127) { - return 0; - } else if (c - 127 < 0) { - return (int) Math.round((c - 127) * 100.0 / 127.0); - } else { - c = (c - 127) / 127; - for (int i = 0; i < ctrMap.length; i++) { - if (ctrMap[i] >= c) { - return i; - } - } - } - return ctrMap.length - 1; - } - - private static boolean sameDouble(double a, double b) { - final double EPSILON = 0.00001; - return a == b ? true : Math.abs(a - b) < EPSILON; - } private static void convertAdjustColorFilter(COLORMATRIXFILTER filter, XFLXmlWriter writer) throws XMLStreamException { - float[][] matrix = new float[5][5]; - int index = 0; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 5; j++) { - matrix[j][i] = filter.matrix[index]; - index++; - } - } - double a11 = matrix[0][0]; - double a12 = matrix[0][1]; - double a13 = matrix[0][2]; - double a21 = matrix[1][0]; - double a22 = matrix[1][1]; - double a23 = matrix[1][2]; - double a31 = matrix[2][0]; - double a32 = matrix[2][1]; - double a33 = matrix[2][2]; - double a41 = matrix[4][0]; - - double b; - double c; - double h; - double s; - b = (24872168661075.0 * a11 * a11 - 151430415740925.0 * a12 + 341095051289483.0 * a12 * a12 - 15302094789450.0 * a13 + 82428663495404.0 * a12 * a13 - - 4592294873812.0 * a13 * a13 + 43556251470.0 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13)) + 2384730956550.0 * a12 * a41 + 240977870700.0 * a13 * a41 - - 685925220 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) - * a41 + 465 * a11 * (466201717582.0 * a12 + 55756962908.0 * a13 + 764132175 * (-127 + 2 * a41))) - / (391687695450.0 * a11 * a11 + 5371575610858.0 * a12 * a12 + 1298089188904.0 * a12 * a13 - 72319604312.0 * a13 * a13 - + 1860 * a11 * (1835439833 * a12 + 219515602 * a13)); - c = (127 * (495225 * a11 + 1661845 * a12 + 167930 * a13 - + 478 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)))) - / 717495; - h = 2 * (Math.atan((-465 * a11 + 287 * a12 + 178 * a13 + Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13))) / (500. * (a12 - a13))) + Math.PI/*+ Pi*C(1)*/); - s = (1543 * (-103355550 * a11 * a11 - 158872382 * a12 * a12 + 190161784 * a12 * a13 - 134644952 * a13 * a13 - + 1661845 * a12 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13)) + 167930 * a13 - * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) - + 465 * a11 * (274372 * a12 + 170168 * a13 + 1065 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 - + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))))) - / (195843847725.0 * a11 * a11 + 2685787805429.0 * a12 * a12 + 649044594452.0 * a12 * a13 - 36159802156.0 * a13 * a13 - + 930 * a11 * (1835439833 * a12 + 219515602 * a13)); - - if (sameDouble(410 * a12, 1543 * a31) && sameDouble(410 * a12, 1543 * a32) && sameDouble(3047 * a12, 1543 * a21) && sameDouble(3047 * a12, 1543 * a23) - && sameDouble(a22, a11 + (1504 * a12) / 1543.) && sameDouble((1133 * a12) / 1543. + a33, a11) - && !sameDouble(a11, a12) && !sameDouble(1543 * a11 + 3457 * a12, 0)) { - h = 0; - } - + ColorMatrixConvertor colorMatrixConvertor = new ColorMatrixConvertor(filter.matrix); + writer.writeEmptyElement("AdjustColorFilter", new String[]{ - "brightness", Integer.toString(normBrightness(b)), - "contrast", Integer.toString(normContrast(c)), - "saturation", Integer.toString(normSaturation(s)), - "hue", Integer.toString(normHue(h))}); + "brightness", Integer.toString(colorMatrixConvertor.getBrightness()), + "contrast", Integer.toString(colorMatrixConvertor.getContrast()), + "saturation", Integer.toString(colorMatrixConvertor.getSaturation()), + "hue", Integer.toString(colorMatrixConvertor.getHue())}); } private static String convertHTMLText(Set characterTags, DefineEditTextTag det, String html, Map characterImportLinkageURL, Reference lastImportedId, Map characterNameMap, SWF swf) { diff --git a/src/com/jpexs/decompiler/flash/easygui/FiltersTreeTable.java b/src/com/jpexs/decompiler/flash/easygui/FiltersTreeTable.java index 412e13e2b..16a1c9fb2 100644 --- a/src/com/jpexs/decompiler/flash/easygui/FiltersTreeTable.java +++ b/src/com/jpexs/decompiler/flash/easygui/FiltersTreeTable.java @@ -29,10 +29,13 @@ import com.jpexs.decompiler.flash.gui.generictageditors.FloatEditor; import com.jpexs.decompiler.flash.gui.generictageditors.GenericTagEditor; import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor; import com.jpexs.decompiler.flash.gui.generictageditors.ValueNormalizer; +import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.RGB; 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.decompiler.flash.types.filters.COLORMATRIXFILTER; +import com.jpexs.decompiler.flash.types.filters.ColorMatrixConvertor; import com.jpexs.decompiler.flash.types.filters.FILTER; import de.javagl.treetable.JTreeTable; import de.javagl.treetable.TreeTableModel; @@ -46,6 +49,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.ArrayList; @@ -305,7 +309,89 @@ public class FiltersTreeTable extends JTreeTable { FilterField filterField = filterValue.filterField; editor = null; - if ("gradientColors".equals(filterField.field.getName())) { + if (filterField.special > 0) { + editor = new NumberEditor(filterField.toString(), filterField.filter, filterField.field, -1, int.class, new SWFType() { + @Override + public BasicType value() { + return BasicType.SI16; + } + + @Override + public BasicType alternateValue() { + return null; + } + + @Override + public String alternateCondition() { + return ""; + } + + @Override + public int count() { + return 0; + } + + @Override + public String countField() { + return ""; + } + + @Override + public int countAdd() { + return 0; + } + + @Override + public boolean canAdd() { + return false; + } + + @Override + public Class annotationType() { + return SWFType.class; + } + + }) { + @Override + protected void saveValue(Object newValue) { + float[] matrix = (float[]) super.loadValue(); + ColorMatrixConvertor convertor = new ColorMatrixConvertor(matrix); + switch (filterField.special) { + case FilterField.SPECIAL_BRIGHTNESS: + convertor.setBrightness((int) newValue); + break; + case FilterField.SPECIAL_CONTRAST: + convertor.setContrast((int) newValue); + break; + case FilterField.SPECIAL_SATURATION: + convertor.setSaturation((int) newValue); + break; + case FilterField.SPECIAL_HUE: + convertor.setHue((int) newValue); + break; + } + matrix = convertor.getMatrix(); + super.saveValue(matrix); + } + + @Override + protected Object loadValue() { + float[] matrix = (float[]) super.loadValue(); + ColorMatrixConvertor convertor = new ColorMatrixConvertor(matrix); + switch (filterField.special) { + case FilterField.SPECIAL_BRIGHTNESS: + return convertor.getBrightness(); + case FilterField.SPECIAL_CONTRAST: + return convertor.getContrast(); + case FilterField.SPECIAL_SATURATION: + return convertor.getSaturation(); + case FilterField.SPECIAL_HUE: + return convertor.getHue(); + } + return 0; + } + }; + } else if ("gradientColors".equals(filterField.field.getName())) { editor = new GradientEditor(filterField.filter); } else if (realValue.getClass() == Boolean.class) { editor = new BooleanEditor(filterField.toString(), filterField.filter, filterField.field, -1, Boolean.class); @@ -340,13 +426,12 @@ public class FiltersTreeTable extends JTreeTable { if (editor != null) { - editor.addChangeListener(new ChangeListener() { + /*editor.addChangeListener(new ChangeListener() { @Override public void change(PropertyEditor editor) { - editor.save(); - filtersTable.fireFilterChanged(); + editor.save(); } - }); + });*/ if (table instanceof JTreeTable) { JTreeTable treeTable = (JTreeTable) table; @@ -390,6 +475,10 @@ public class FiltersTreeTable extends JTreeTable { if (realValue.getClass() == Double.class || realValue.getClass() == Float.class) { return true; } + + if (filterValue.filterField.special > 0) { + return true; + } if (realValue.getClass() == Boolean.class) { return false; } @@ -399,10 +488,12 @@ public class FiltersTreeTable extends JTreeTable { @Override public boolean stopCellEditing() { editor.save(); + filtersTable.fireFilterChanged(); List listeners2 = new ArrayList<>(listeners); - for (CellEditorListener l : listeners2) { + for (CellEditorListener l : listeners2) { l.editingStopped(new ChangeEvent(editor)); } + filtersTable.repaint(); return true; } @@ -422,7 +513,7 @@ public class FiltersTreeTable extends JTreeTable { @Override public void removeCellEditorListener(CellEditorListener l) { - listeners.remove(l); + listeners.remove(l); } } @@ -452,9 +543,30 @@ public class FiltersTreeTable extends JTreeTable { case "blurY": case "distance": units = " px"; - } - label.setText(value.toString() + units); + } + Object fieldValue = filterValue.getValue(); + + if (filterValue.filterField.special > 0) { + float[] matrix = (float[]) fieldValue; + ColorMatrixConvertor convertor = new ColorMatrixConvertor(matrix); + switch (filterValue.filterField.special) { + case FilterField.SPECIAL_BRIGHTNESS: + label.setText("" + convertor.getBrightness()); + break; + case FilterField.SPECIAL_CONTRAST: + label.setText("" + convertor.getContrast()); + break; + case FilterField.SPECIAL_SATURATION: + label.setText("" + convertor.getSaturation()); + break; + case FilterField.SPECIAL_HUE: + label.setText("" + convertor.getHue()); + break; + } + } else { + label.setText(value.toString() + units); + } if (fieldValue != null) { if ("gradientColors".equals(filterValue.filterField.field.getName())) { component = new GradientEditor(filterValue.filterField.filter); @@ -532,12 +644,28 @@ public class FiltersTreeTable extends JTreeTable { private final FILTER filter; private final Field field; + private final int special; + public static final int SPECIAL_BRIGHTNESS = 1; + public static final int SPECIAL_CONTRAST = 2; + public static final int SPECIAL_SATURATION = 3; + public static final int SPECIAL_HUE = 4; + + public FilterField(FILTER filter, Field property) { - this.filter = filter; - this.field = property; + this(filter, property, 0); } + public FilterField(FILTER filter, Field property, int special) { + this.filter = filter; + this.field = property; + this.special = special; + } + + public int getSpecial() { + return special; + } + public FILTER getFilter() { return filter; } @@ -556,6 +684,16 @@ public class FiltersTreeTable extends JTreeTable { @Override public String toString() { + switch (special) { + case SPECIAL_BRIGHTNESS: + return "brightness"; + case SPECIAL_CONTRAST: + return "contrast"; + case SPECIAL_SATURATION: + return "saturation"; + case SPECIAL_HUE: + return "hue"; + } if ("gradientColors".equals(field.getName())) { return "gradient"; } @@ -683,6 +821,32 @@ public class FiltersTreeTable extends JTreeTable { if ("gradientRatio".equals(field.getName())) { continue; } + if (filter instanceof COLORMATRIXFILTER) { + if ("matrix".equals(field.getName())) { + + DefaultMutableTreeNode fieldNode; + FilterField filterField; + + + filterField = new FilterField(filter, field, FilterField.SPECIAL_BRIGHTNESS); + fieldNode = new DefaultMutableTreeNode(filterField); + filterNode.add(fieldNode); + + filterField = new FilterField(filter, field, FilterField.SPECIAL_CONTRAST); + fieldNode = new DefaultMutableTreeNode(filterField); + filterNode.add(fieldNode); + + filterField = new FilterField(filter, field, FilterField.SPECIAL_SATURATION); + fieldNode = new DefaultMutableTreeNode(filterField); + filterNode.add(fieldNode); + + filterField = new FilterField(filter, field, FilterField.SPECIAL_HUE); + fieldNode = new DefaultMutableTreeNode(filterField); + filterNode.add(fieldNode); + + continue; + } + } Reserved reserved = field.getAnnotation(Reserved.class); if (reserved != null) { continue; diff --git a/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java b/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java index ad2338401..29e688f21 100644 --- a/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java +++ b/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java @@ -440,6 +440,7 @@ public class InstancePropertiesPanel extends AbstractPropertiesPanel { @Override public void doPlaceOperation(PlaceObjectTypeTag placeObject, DepthState depthState) { placeObject.setFilters(applyFilters); + depthState.filters = applyFilters; } }, swfPanel.getSwf()); } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java index fa5002138..984703449 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java @@ -30,6 +30,7 @@ import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; import javax.swing.text.DefaultFormatter; /** @@ -48,9 +49,9 @@ public class NumberEditor extends JPanel implements GenericTagEditor { private final SWFType swfType; private String fieldName; - + private ValueNormalizer normalizer; - + private JSpinner spinner; @Override @@ -78,56 +79,66 @@ public class NumberEditor extends JPanel implements GenericTagEditor { this.swfType = swfType; this.fieldName = fieldName; spinner = new JSpinner(); - + setLayout(new BorderLayout()); add(spinner, BorderLayout.WEST); setOpaque(false); - reset(); + reset(); ((JSpinner.NumberEditor) spinner.getEditor()).getFormat().setGroupingUsed(false); JFormattedTextField jtf = ((JSpinner.NumberEditor) spinner.getEditor()).getTextField(); DefaultFormatter formatter = (DefaultFormatter) jtf.getFormatter(); formatter.setCommitsOnValidEdit(true); - + } @Override - public void reset() { - try { - Object value = ReflectionTools.getValue(obj, field, index); - if (normalizer != null) { - value = normalizer.toViewValue(value); - } - spinner.setModel(getModel(swfType, value)); - } catch (IllegalArgumentException | IllegalAccessException ex) { - // ignore + public void reset() { + Object value = loadValue(); + if (normalizer != null) { + value = normalizer.toViewValue(value); } + spinner.setModel(getModel(swfType, value)); } @Override public boolean save() { + Object oldValue = loadValue(); + Object oldViewValue = oldValue; + if (normalizer != null) { + oldViewValue = normalizer.toViewValue(oldValue); + } + Object newViewValue = getChangedValue(); + if (newViewValue == null) { + return false; + } + if (Objects.equals(oldViewValue, newViewValue)) { + return false; + } + Object newValue = newViewValue; + if (normalizer != null) { + newValue = normalizer.toFieldValue(newViewValue); + } + saveValue(newValue); + + return true; + } + + protected Object loadValue() { + try { + return ReflectionTools.getValue(obj, field, index); + } catch (IllegalArgumentException | IllegalAccessException ex) { + // ignore + } + return null; + } + + protected void saveValue(Object newValue) { try { - Object oldValue = ReflectionTools.getValue(obj, field, index); - Object oldViewValue = oldValue; - if (normalizer != null) { - oldViewValue = normalizer.toViewValue(oldValue); - } - Object newViewValue = getChangedValue(); - if (newViewValue == null) { - return false; - } - if (Objects.equals(oldViewValue, newViewValue)) { - return false; - } - Object newValue = newViewValue; - if (normalizer != null) { - newValue = normalizer.toFieldValue(newViewValue); - } ReflectionTools.setValue(obj, field, index, newValue); } catch (IllegalArgumentException | IllegalAccessException ex) { // ignore } - return true; } private SpinnerModel getModel(SWFType swfType, Object value) { @@ -264,9 +275,9 @@ public class NumberEditor extends JPanel implements GenericTagEditor { public Object getObject() { return obj; } - + @Override public void setValueNormalizer(ValueNormalizer normalizer) { this.normalizer = normalizer; - } + } }