/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2011 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.transform; import org.jwildfire.base.Property; import org.jwildfire.base.PropertyCategory; import org.jwildfire.base.Tools; import org.jwildfire.base.mathparser.JEPWrapper; import org.jwildfire.image.Pixel; import org.jwildfire.image.SimpleImage; import org.jwildfire.image.WFImage; import org.jwildfire.swing.Buffer; import org.jwildfire.swing.NonHDRImageBufferComboBoxEditor; import org.nfunk.jep.Node; import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor; public class FormulaComposeTransformer extends Mesh2DTransformer { public enum HAlignment { OFF, CENTRE, LEFT, RIGHT } public enum VAlignment { OFF, CENTRE, TOP, BOTTOM } @Property(category = PropertyCategory.PRIMARY, description = "Image to put in foreground", editorClass = NonHDRImageBufferComboBoxEditor.class) private Buffer foreground; private SimpleImage foregroundImage; // Alternative way to specify the foreground image directly @Property(category = PropertyCategory.SECONDARY, description = "Left offset of the foreground image") private int left; @Property(category = PropertyCategory.SECONDARY, description = "Top offset of the foreground image") private int top; @Property(category = PropertyCategory.PRIMARY, description = "Horizontal alignment of the foreground image", editorClass = HAlignmentEditor.class) private HAlignment hAlign; @Property(category = PropertyCategory.PRIMARY, description = "Vertical alignment of the foreground image", editorClass = VAlignmentEditor.class) private VAlignment vAlign; @Property(description = "Formula of the red channel (Parameters: fgR, fgG, fgB, fgWidth, fgHeight, bgR, bgG, bgB, bgWidth, bgHeight, fgLeft, fgTop, fgX, fgY)") private String formula1Red; @Property(description = "Formula of the green channel") private String formula2Green; @Property(description = "Formula of the blue channel") private String formula3Blue; @Override protected void performPixelTransformation(WFImage pImg) { SimpleImage bgImg = (SimpleImage) pImg; SimpleImage fgImg = (foregroundImage != null) ? foregroundImage : foreground.getImage(); if (fgImg == bgImg) fgImg = fgImg.clone(); Pixel fgPixel = new Pixel(); Pixel bgPixel = new Pixel(); // calculate left and top edge int fgLeft, fgTop; int bgWidth = bgImg.getImageWidth(); int bgHeight = bgImg.getImageHeight(); int fgWidth = fgImg.getImageWidth(); int fgHeight = fgImg.getImageHeight(); if (hAlign == HAlignment.CENTRE) { fgLeft = (bgWidth - fgWidth) / 2; } else if (hAlign == HAlignment.LEFT) { fgLeft = 0; } else if (hAlign == HAlignment.RIGHT) { fgLeft = bgWidth - fgWidth; } else { fgLeft = this.left; } if (vAlign == VAlignment.CENTRE) { fgTop = (bgHeight - fgHeight) / 2; } else if (vAlign == VAlignment.TOP) { fgTop = 0; } else if (vAlign == VAlignment.BOTTOM) { fgTop = bgHeight - fgHeight; } else { fgTop = this.top; } // Initialize the parser JEPWrapper parser = new JEPWrapper(); parser.addVariable("fgR", 0.0); parser.addVariable("fgG", 0.0); parser.addVariable("fgB", 0.0); parser.addVariable("fgWidth", (double) fgWidth); parser.addVariable("fgHeight", (double) fgHeight); parser.addVariable("bgR", 0.0); parser.addVariable("bgG", 0.0); parser.addVariable("bgB", 0.0); parser.addVariable("bgWidth", (double) bgWidth); parser.addVariable("bgHeight", (double) bgHeight); parser.addVariable("fgLeft", (double) fgLeft); parser.addVariable("fgTop", (double) fgTop); parser.addVariable("fgX", 0.0); parser.addVariable("fgY", 0.0); Node redNode = parser.parse(formula1Red); Node greenNode = parser.parse(formula2Green); Node blueNode = parser.parse(formula3Blue); // compose the images for (int i = 0; i < fgHeight; i++) { int top = fgTop + i; if (top >= 0 && top < bgHeight) { parser.setVarValue("fgY", (double) i / 255.0); for (int j = 0; j < fgWidth; j++) { int left = fgLeft + j; if (left >= 0 && left < bgWidth) { parser.setVarValue("fgX", (double) j / 255.0); bgPixel.setARGBValue(bgImg.getARGBValue(left, top)); fgPixel.setARGBValue(fgImg.getARGBValue(j, i)); parser.setVarValue("bgR", (double) bgPixel.r / 255.0); parser.setVarValue("bgG", (double) bgPixel.g / 255.0); parser.setVarValue("bgB", (double) bgPixel.b / 255.0); parser.setVarValue("fgR", (double) fgPixel.r / 255.0); parser.setVarValue("fgG", (double) fgPixel.g / 255.0); parser.setVarValue("fgB", (double) fgPixel.b / 255.0); // TODO Genlock: z. B. Testen, ob Intensitat 0 oder grober 0 // genlockFormula, genlockOperator (gleich, grober), genlockRefValue bgPixel.r = Tools.roundColor((Double) parser.evaluate(redNode) * 255.0); bgPixel.g = Tools.roundColor((Double) parser.evaluate(greenNode) * 255.0); bgPixel.b = Tools.roundColor((Double) parser.evaluate(blueNode) * 255.0); bgImg.setRGB(left, top, bgPixel); } } } } } @Override public void initDefaultParams(WFImage pImg) { left = 0; top = 0; hAlign = HAlignment.CENTRE; vAlign = VAlignment.CENTRE; formula1Red = "(0.13*exp(2*fgR)+0.02*exp(4*bgR))*1.9"; formula2Green = "(0.13*exp(2*fgG)+0.02*exp(4*bgG))*1.2"; formula3Blue = "(0.05*exp(3*fgG)+0.13*exp(2*bgG))*0.5"; } public static class HAlignmentEditor extends ComboBoxPropertyEditor { public HAlignmentEditor() { super(); setAvailableValues(new HAlignment[] { HAlignment.OFF, HAlignment.CENTRE, HAlignment.LEFT, HAlignment.RIGHT }); } } public static class VAlignmentEditor extends ComboBoxPropertyEditor { public VAlignmentEditor() { super(); setAvailableValues(new VAlignment[] { VAlignment.OFF, VAlignment.CENTRE, VAlignment.TOP, VAlignment.BOTTOM }); } } public Buffer getForeground() { return foreground; } public void setForeground(Buffer foreground) { this.foreground = foreground; } public int getLeft() { return left; } public void setLeft(int left) { this.left = left; } public int getTop() { return top; } public void setTop(int top) { this.top = top; } public HAlignment getHAlign() { return hAlign; } public void setHAlign(HAlignment hAlign) { this.hAlign = hAlign; } public VAlignment getVAlign() { return vAlign; } public void setVAlign(VAlignment vAlign) { this.vAlign = vAlign; } public String getFormula1Red() { return formula1Red; } public void setFormula1Red(String formula1Red) { this.formula1Red = formula1Red; } public String getFormula2Green() { return formula2Green; } public void setFormula2Green(String formula2Green) { this.formula2Green = formula2Green; } public String getFormula3Blue() { return formula3Blue; } public void setFormula3Blue(String formula3Blue) { this.formula3Blue = formula3Blue; } public void setForegroundImage(SimpleImage foregroundImage) { this.foregroundImage = foregroundImage; } }