]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Render elements using custom color filters
authorJussi Koskela <jussi.koskela@semantum.fi>
Thu, 2 Jul 2020 09:25:51 +0000 (12:25 +0300)
committerAntti Villberg <antti.villberg@semantum.fi>
Wed, 29 Jul 2020 15:16:18 +0000 (18:16 +0300)
WIP: Still lacks a mechanism to read color filters for elements from DB.
Currently filters can be set manually for elements with the
ElementHints.KEY_COLOR_FILTER hint.

gitlab simantics/platform#569

Change-Id: Id0bbbdeea3d4c9a27f2778f7bdcab74f5f784322

bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainter.java
bundles/org.simantics.g2d/src/org/simantics/g2d/element/ElementHints.java
bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DRenderingHints.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/BWColorFilter.java [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/ColorFilter.java [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/Graphics2DWithColorFilter.java [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SingleElementNode.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/BufferedImage.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/MipMapBufferedImage.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/MipMapVRamBufferedImage.java

index a8fee9582aa61e520faa86d5c122ca06f8b284cb..d4d0609b2766a3c9b616bba03b8a9f050d06a56b 100644 (file)
@@ -84,6 +84,7 @@ import org.simantics.scenegraph.Node;
 import org.simantics.scenegraph.g2d.G2DParentNode;
 import org.simantics.scenegraph.g2d.G2DSceneGraph;
 import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
 import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
 import org.simantics.scenegraph.g2d.nodes.DataNode;
 import org.simantics.scenegraph.g2d.nodes.LinkNode;
@@ -787,6 +788,9 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             }
             holder.setVisible(visible);
 
+            ColorFilter colorFilter = e.getHint(ElementHints.KEY_COLOR_FILTER);
+            holder.setColorFilter(colorFilter);
+
             for (SceneGraph n : nodeHandlers) {
                 n.init(e, holder);
             }
index 35f3a8591fb3de903c94e8d69f3ca3f24d3090f6..53cac820ef6f376a37a0432e84ec8278a001f356 100644 (file)
@@ -33,6 +33,7 @@ import org.simantics.g2d.element.handler.SceneGraph;
 import org.simantics.g2d.image.Image;
 import org.simantics.g2d.utils.Alignment;
 import org.simantics.scenegraph.Node;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
 import org.simantics.utils.datastructures.hints.IHintContext.Key;
 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
 
@@ -184,6 +185,11 @@ public class ElementHints {
      */
     public static final Key KEY_ELEMENT_PROPERTIES = new KeyOf(Properties.class, "ELEMENT_PROPERTIES");
 
+    /**
+     * Color filter to be applied when rendering nodes.
+     */
+    public static final Key KEY_COLOR_FILTER = new KeyOf(ColorFilter.class, "COLOR_FILTER");
+
     public static class Properties extends HashMap<String, Object> {
         private static final long serialVersionUID = 6986415032113675720L;
     }
index ebaffc23460316e3234345ff8302b6b72db4b1e0..99ebb152e8b89d7cb570fb329a4beeb137d3367e 100644 (file)
@@ -24,6 +24,7 @@ Export-Package: com.kitfox.svg,
  org.simantics.scenegraph,
  org.simantics.scenegraph.adapters,
  org.simantics.scenegraph.g2d,
+ org.simantics.scenegraph.g2d.color,
  org.simantics.scenegraph.g2d.events,
  org.simantics.scenegraph.g2d.events.adapter,
  org.simantics.scenegraph.g2d.events.command,
index 992213c4595f8dfa5f375af72b00750e00ce71bf..a01654ce2a6a4bb7e5ed4f5c04845eb525662fcd 100644 (file)
@@ -16,6 +16,8 @@ import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.util.Map;
 
+import org.simantics.scenegraph.g2d.color.ColorFilter;
+
 /**
  * @author Tuukka Lehtonen
  * See {@link G2DPDFRenderingHints}
@@ -121,4 +123,15 @@ public final class G2DRenderingHints {
         }
     };
 
+    /*
+     * A rendering hint for storing the active ColorFilter which can be used e.g. 
+     * for coloring BufferedImages.  
+     */
+    public static final Key KEY_COLOR_FILTER = new Key(2007) {
+        @Override
+        public boolean isCompatibleValue(Object val) {
+            return val instanceof ColorFilter || val == null;
+        }
+    };
+
 }
\ No newline at end of file
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/BWColorFilter.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/BWColorFilter.java
new file mode 100644 (file)
index 0000000..a98c0ff
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d.color;
+
+import java.awt.Color;
+
+public class BWColorFilter implements ColorFilter {
+
+    @Override
+    public Color filter(Color c) {
+        int avg = (c.getRed() + c.getGreen() + c.getBlue()) / 3; 
+        Color c2 = new Color(avg, avg, avg, c.getAlpha());
+        return c2;
+    }
+
+    @Override
+    public int hashCode() {
+        return getClass().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        return true;
+    }
+}
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/ColorFilter.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/ColorFilter.java
new file mode 100644 (file)
index 0000000..105f8f7
--- /dev/null
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d.color;
+
+import java.awt.Color;
+
+public interface ColorFilter {
+    public Color filter(Color c);
+}
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/Graphics2DWithColorFilter.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/color/Graphics2DWithColorFilter.java
new file mode 100644 (file)
index 0000000..91e3cc0
--- /dev/null
@@ -0,0 +1,354 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d.color;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.RenderingHints.Key;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import com.kitfox.svg.batik.LinearGradientPaint;
+import com.kitfox.svg.batik.RadialGradientPaint;
+
+/**
+ * Modified methods: setPaint, setColor.
+ * Colors of bitmap images must be handled externally.
+ */
+public class Graphics2DWithColorFilter extends Graphics2D {
+    private Graphics2D g2d;
+    private ColorFilter colorFilter;
+
+    public Graphics2DWithColorFilter(Graphics2D g2d, ColorFilter colorFilter) {
+        this.g2d = g2d;
+        this.colorFilter = colorFilter;
+    }
+
+    public void setColorFilter(ColorFilter colorFilter) {
+        this.colorFilter = colorFilter;
+    }
+
+    public Color filter(Color c) {
+        if (colorFilter != null) {
+            return colorFilter.filter(c);
+        } else {
+            return c;
+        }
+    }
+
+    public void setColor(Color c) {
+        g2d.setColor(filter(c));
+    }
+
+    public void setPaint(Paint paint) {
+        if (paint instanceof Color) {
+            g2d.setColor(filter((Color)paint));
+        } else if (paint instanceof LinearGradientPaint) {
+            LinearGradientPaint lgp = (LinearGradientPaint)paint;
+            Color[] colors = new Color[lgp.getColors().length];
+            for (int i = 0; i < lgp.getColors().length; i++) {
+                colors[i] = filter(lgp.getColors()[i]);
+            }
+            LinearGradientPaint lgp2 = new LinearGradientPaint(lgp.getStartPoint(), lgp.getEndPoint(), lgp.getFractions(), colors);
+            g2d.setPaint(lgp2);
+        } else if (paint instanceof RadialGradientPaint) {
+            RadialGradientPaint rgp = (RadialGradientPaint)paint;
+            Color[] colors = new Color[rgp.getColors().length];
+            for (int i = 0; i < rgp.getColors().length; i++) {
+                colors[i] = filter(rgp.getColors()[i]);
+            }
+            RadialGradientPaint rgp2 = new RadialGradientPaint(rgp.getCenterPoint(), rgp.getRadius(), rgp.getFractions(), colors);
+            g2d.setPaint(rgp2);
+        } else {
+            // Not implemented yet. Show red!
+            Color c2 = new Color(255, 0, 0, 255);
+            g2d.setPaint(c2);
+        }
+    }
+
+    public int hashCode() {
+        return g2d.hashCode();
+    }
+    public boolean equals(Object obj) {
+        return g2d.equals(obj);
+    }
+    public Graphics create() {
+        return g2d.create();
+    }
+    public Graphics create(int x, int y, int width, int height) {
+        return g2d.create(x, y, width, height);
+    }
+    public Color getColor() {
+        return g2d.getColor();
+    }
+    public void setPaintMode() {
+        g2d.setPaintMode();
+    }
+    public void setXORMode(Color c1) {
+        g2d.setXORMode(c1);
+    }
+    public Font getFont() {
+        return g2d.getFont();
+    }
+    public void setFont(Font font) {
+        g2d.setFont(font);
+    }
+    public FontMetrics getFontMetrics() {
+        return g2d.getFontMetrics();
+    }
+    public FontMetrics getFontMetrics(Font f) {
+        return g2d.getFontMetrics(f);
+    }
+    public Rectangle getClipBounds() {
+        return g2d.getClipBounds();
+    }
+    public void clipRect(int x, int y, int width, int height) {
+        g2d.clipRect(x, y, width, height);
+    }
+    public void setClip(int x, int y, int width, int height) {
+        g2d.setClip(x, y, width, height);
+    }
+    public Shape getClip() {
+        return g2d.getClip();
+    }
+    public void setClip(Shape clip) {
+        g2d.setClip(clip);
+    }
+    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+        g2d.copyArea(x, y, width, height, dx, dy);
+    }
+    public void drawLine(int x1, int y1, int x2, int y2) {
+        g2d.drawLine(x1, y1, x2, y2);
+    }
+    public void fillRect(int x, int y, int width, int height) {
+        g2d.fillRect(x, y, width, height);
+    }
+    public void drawRect(int x, int y, int width, int height) {
+        g2d.drawRect(x, y, width, height);
+    }
+    public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+        g2d.draw3DRect(x, y, width, height, raised);
+    }
+    public void clearRect(int x, int y, int width, int height) {
+        g2d.clearRect(x, y, width, height);
+    }
+    public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        g2d.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
+    }
+    public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+        g2d.fill3DRect(x, y, width, height, raised);
+    }
+    public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        g2d.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
+    }
+    public void draw(Shape s) {
+        g2d.draw(s);
+    }
+    public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
+        return g2d.drawImage(img, xform, obs);
+    }
+    public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
+        g2d.drawImage(img, op, x, y);
+    }
+    public void drawOval(int x, int y, int width, int height) {
+        g2d.drawOval(x, y, width, height);
+    }
+    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+        g2d.drawRenderedImage(img, xform);
+    }
+    public void fillOval(int x, int y, int width, int height) {
+        g2d.fillOval(x, y, width, height);
+    }
+    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+        g2d.drawRenderableImage(img, xform);
+    }
+    public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+        g2d.drawArc(x, y, width, height, startAngle, arcAngle);
+    }
+    public void drawString(String str, int x, int y) {
+        g2d.drawString(str, x, y);
+    }
+    public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+        g2d.fillArc(x, y, width, height, startAngle, arcAngle);
+    }
+    public void drawString(String str, float x, float y) {
+        g2d.drawString(str, x, y);
+    }
+    public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+        g2d.drawString(iterator, x, y);
+    }
+    public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
+        g2d.drawPolyline(xPoints, yPoints, nPoints);
+    }
+    public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+        g2d.drawPolygon(xPoints, yPoints, nPoints);
+    }
+    public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+        g2d.drawString(iterator, x, y);
+    }
+    public void drawPolygon(Polygon p) {
+        g2d.drawPolygon(p);
+    }
+    public void drawGlyphVector(GlyphVector g, float x, float y) {
+        g2d.drawGlyphVector(g, x, y);
+    }
+    public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+        g2d.fillPolygon(xPoints, yPoints, nPoints);
+    }
+    public void fill(Shape s) {
+        g2d.fill(s);
+    }
+    public void fillPolygon(Polygon p) {
+        g2d.fillPolygon(p);
+    }
+    public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+        return g2d.hit(rect, s, onStroke);
+    }
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return g2d.getDeviceConfiguration();
+    }
+    public void setComposite(Composite comp) {
+        g2d.setComposite(comp);
+    }
+    public void drawChars(char[] data, int offset, int length, int x, int y) {
+        g2d.drawChars(data, offset, length, x, y);
+    }
+    public void drawBytes(byte[] data, int offset, int length, int x, int y) {
+        g2d.drawBytes(data, offset, length, x, y);
+    }
+    public void setStroke(Stroke s) {
+        g2d.setStroke(s);
+    }
+    public void setRenderingHint(Key hintKey, Object hintValue) {
+        g2d.setRenderingHint(hintKey, hintValue);
+    }
+    public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+        return g2d.drawImage(img, x, y, observer);
+    }
+    public Object getRenderingHint(Key hintKey) {
+        return g2d.getRenderingHint(hintKey);
+    }
+    public void setRenderingHints(Map<?, ?> hints) {
+        g2d.setRenderingHints(hints);
+    }
+    public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
+        return g2d.drawImage(img, x, y, width, height, observer);
+    }
+    public void addRenderingHints(Map<?, ?> hints) {
+        g2d.addRenderingHints(hints);
+    }
+    public RenderingHints getRenderingHints() {
+        return g2d.getRenderingHints();
+    }
+    public void translate(int x, int y) {
+        g2d.translate(x, y);
+    }
+    public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
+        return g2d.drawImage(img, x, y, bgcolor, observer);
+    }
+    public void translate(double tx, double ty) {
+        g2d.translate(tx, ty);
+    }
+    public void rotate(double theta) {
+        g2d.rotate(theta);
+    }
+    public void rotate(double theta, double x, double y) {
+        g2d.rotate(theta, x, y);
+    }
+    public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
+        return g2d.drawImage(img, x, y, width, height, bgcolor, observer);
+    }
+    public void scale(double sx, double sy) {
+        g2d.scale(sx, sy);
+    }
+    public void shear(double shx, double shy) {
+        g2d.shear(shx, shy);
+    }
+    public void transform(AffineTransform Tx) {
+        g2d.transform(Tx);
+    }
+    public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+            ImageObserver observer) {
+        return g2d.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
+    }
+    public void setTransform(AffineTransform Tx) {
+        g2d.setTransform(Tx);
+    }
+    public AffineTransform getTransform() {
+        return g2d.getTransform();
+    }
+    public Paint getPaint() {
+        return g2d.getPaint();
+    }
+    public Composite getComposite() {
+        return g2d.getComposite();
+    }
+    public void setBackground(Color color) {
+        g2d.setBackground(color);
+    }
+    public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+            Color bgcolor, ImageObserver observer) {
+        return g2d.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
+    }
+    public Color getBackground() {
+        return g2d.getBackground();
+    }
+    public Stroke getStroke() {
+        return g2d.getStroke();
+    }
+    public void clip(Shape s) {
+        g2d.clip(s);
+    }
+    public FontRenderContext getFontRenderContext() {
+        return g2d.getFontRenderContext();
+    }
+    public void dispose() {
+        g2d.dispose();
+    }
+    @SuppressWarnings("deprecation")
+    public void finalize() {
+        g2d.finalize();
+    }
+    public String toString() {
+        return g2d.toString();
+    }
+    @SuppressWarnings("deprecation")
+    public Rectangle getClipRect() {
+        return g2d.getClipRect();
+    }
+    public boolean hitClip(int x, int y, int width, int height) {
+        return g2d.hitClip(x, y, width, height);
+    }
+    public Rectangle getClipBounds(Rectangle r) {
+        return g2d.getClipBounds(r);
+    }
+}
index 29ef9954eb37a604a1ca593439e9614a1e3d4510..b45e7493a686fa4ea61286b0e57580d422ea6935 100644 (file)
@@ -21,6 +21,8 @@ import java.util.Map;
 import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.g2d.G2DRenderingHints;
 import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
+import org.simantics.scenegraph.g2d.color.Graphics2DWithColorFilter;
 import org.simantics.scenegraph.g2d.events.EventTypes;
 import org.simantics.scenegraph.g2d.events.MouseEvent;
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
@@ -33,6 +35,7 @@ public class SingleElementNode extends TransformNode implements InitValueSupport
 
     private TransferableProvider transferableProvider;
     protected Composite composite;
+    private ColorFilter colorFilter;
     protected Boolean visible = Boolean.TRUE;
     protected Boolean hidden = Boolean.FALSE;
     private transient Object key;
@@ -91,6 +94,10 @@ public class SingleElementNode extends TransformNode implements InitValueSupport
     public void setComposite(Composite composite) {
         this.composite = composite;
     }
+    
+    public void setColorFilter(ColorFilter colorFilter) {
+        this.colorFilter = colorFilter;
+    }
 
     @SyncField("visible")
     public void setVisible(Boolean visible) {
@@ -111,10 +118,18 @@ public class SingleElementNode extends TransformNode implements InitValueSupport
     }
 
     @Override
-    public void render(Graphics2D g) {
+    public void render(Graphics2D g2d) {
         if (!visible || hidden)
             return;
 
+        Graphics2D g;
+        if (colorFilter != null) {
+            g = new Graphics2DWithColorFilter(g2d, colorFilter);
+            g.setRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER, colorFilter);
+        } else {
+            g = g2d;
+        }
+
         Composite oldComposite = null;
         if(composite != null) {
             oldComposite = g.getComposite();
@@ -130,6 +145,10 @@ public class SingleElementNode extends TransformNode implements InitValueSupport
 
         if (oldComposite != null)
             g.setComposite(oldComposite);
+
+        if (colorFilter != null) {
+            g.setRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER, null);
+        }
     }
 
     @Override
index 5401fa757411f5248694647d6a536032c2121c7d..7904c3f4ab9cf8905aecb374ebf788c14a645ac0 100644 (file)
@@ -17,6 +17,11 @@ import java.awt.Point;
 import java.awt.RenderingHints;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
+import java.util.Objects;
+
+import org.simantics.scenegraph.g2d.G2DRenderingHints;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
+import org.simantics.scenegraph.g2d.color.Graphics2DWithColorFilter;
 
 import com.kitfox.svg.SVGDiagram;
 import com.kitfox.svg.SVGException;
@@ -31,6 +36,7 @@ public class BufferedImage  {
 
     java.awt.image.BufferedImage   buffer = null;
     AffineTransform previousTransform = null;
+    ColorFilter previousColorFilter = null;
 
     /**
      * @param original
@@ -70,7 +76,7 @@ public class BufferedImage  {
         }
     }
 
-    public void paintToBuffer(AffineTransform transform, float margin) throws SVGException {
+    public void paintToBuffer(AffineTransform transform, ColorFilter colorFilter, float margin) throws SVGException {
 
         int w = (int)((imageBounds.getWidth()+margin*2) * transform.getScaleX());
         int h = (int)((imageBounds.getHeight()+margin*2) * transform.getScaleY());
@@ -90,18 +96,24 @@ public class BufferedImage  {
         b2g.translate(margin, margin);
         b2g.scale(transform.getScaleX(), transform.getScaleY());
         b2g.translate(-imageBounds.getMinX(), -imageBounds.getMinY());
-        source.render(b2g);
+        if (colorFilter != null) {
+            source.render(new Graphics2DWithColorFilter(b2g, colorFilter));
+        } else {
+            source.render(b2g);
+        }
 
     }
     
     public void paint(Graphics2D g) {
         float margin = 5;
 
-        if(previousTransform == null || previousTransform.getScaleX() != g.getTransform().getScaleX() || previousTransform.getScaleY() != g.getTransform().getScaleY()) {
+        ColorFilter colorFilter = (ColorFilter) g.getRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER);
+        if(previousTransform == null || previousTransform.getScaleX() != g.getTransform().getScaleX() || previousTransform.getScaleY() != g.getTransform().getScaleY() || !Objects.equals(colorFilter, previousColorFilter)) {
 //             setupSourceRender(g);
             try {
+                previousColorFilter = colorFilter;
                 previousTransform = (AffineTransform)g.getTransform().clone();
-               paintToBuffer(previousTransform, margin);
+                paintToBuffer(previousTransform, previousColorFilter, margin);
             } catch (SVGException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
index 7e5f09949ad0e44af5151e3889814d36daadf650..b249275540a39979be3370080cc6c7d22e36794b 100644 (file)
@@ -22,7 +22,11 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
+import org.simantics.scenegraph.g2d.G2DRenderingHints;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
+import org.simantics.scenegraph.g2d.color.Graphics2DWithColorFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -166,12 +170,18 @@ public class MipMapBufferedImage extends BufferedImage {
 
     @Override
     public void paint(Graphics2D g) {
+        ColorFilter colorFilter = (ColorFilter) g.getRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER);
+
         // Quality rendering requested, do not render from cache
         //QualityHints.HIGH_QUALITY_HINTS.setQuality(g);
         if (g.getRenderingHint(RenderingHints.KEY_RENDERING) == RenderingHints.VALUE_RENDER_QUALITY)
         {
             try {
-                source.render(g);
+                if (colorFilter != null) {
+                    source.render(new Graphics2DWithColorFilter(g, colorFilter));
+                } else {
+                    source.render(g);
+                }
             } catch (Exception e) {
                 // NOTE: Catching Exception instead of SVGException due to an
                 // NPE when encountering invalid color SVG definitions (e.g.
@@ -192,7 +202,11 @@ public class MipMapBufferedImage extends BufferedImage {
             Graphics2D g2d = (Graphics2D) g.create();
             setupSourceRender(g2d);
             try {
-                source.render(g2d);
+                if (colorFilter != null) {
+                    source.render(new Graphics2DWithColorFilter(g, colorFilter));
+                } else {
+                    source.render(g);
+                }
             } catch (Exception e) {
                 // NOTE: Catching Exception instead of SVGException due to an
                 // NPE when encountering invalid color SVG definitions (e.g.
@@ -271,6 +285,7 @@ public class MipMapBufferedImage extends BufferedImage {
         java.awt.image.BufferedImage image;
         //int widMargin, heiMargin;
         int wid, hei;
+        private ColorFilter previousColorFilter = null;
 
         BufferedRaster(double resolution) {
             super(resolution);
@@ -282,8 +297,12 @@ public class MipMapBufferedImage extends BufferedImage {
 //            heiMargin = (int) (hei * resolution * (MARGIN_PERCENT/100)) +1;
         }
 
-        synchronized java.awt.image.BufferedImage getOrCreate()
+        synchronized java.awt.image.BufferedImage getOrCreate(ColorFilter colorFilter)
         {
+            if (!Objects.equals(colorFilter, previousColorFilter)) {
+                previousColorFilter = colorFilter;
+                image = null;
+            }
             if (image!=null) return image;
             image = new java.awt.image.BufferedImage(
                     (wid+0*2+1),
@@ -303,7 +322,11 @@ public class MipMapBufferedImage extends BufferedImage {
             target.scale(resolution, resolution);
             target.translate(-imageBounds.getMinX(), -imageBounds.getMinY());
             try {
-                source.render(target);
+                if (colorFilter != null) {
+                    source.render(new Graphics2DWithColorFilter(target, colorFilter));
+                } else {
+                    source.render(target);
+                }
             } catch (Exception e) {
                 // TODO Auto-generated catch block
                 // NOTE: Catching Exception instead of SVGException due to an
@@ -320,11 +343,12 @@ public class MipMapBufferedImage extends BufferedImage {
         }
 
         public void paint(Graphics2D g) {
-            java.awt.image.BufferedImage image = getOrCreate();
+            ColorFilter colorFilter = (ColorFilter) g.getRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER); 
+            java.awt.image.BufferedImage image = getOrCreate(colorFilter);
             if (image==null)
             {
                 try {
-                    source.render(g);
+                    source.render(new Graphics2DWithColorFilter(g, colorFilter));
                 } catch (Exception e) {
                     // TODO Auto-generated catch block
                     // NOTE: Catching Exception instead of SVGException due to an
index 54323097badd9d77463d3dfe5497013e83ac93a9..69b4e337bf0e119207be52bfb2a356c2d5225650 100644 (file)
@@ -19,8 +19,12 @@ import java.awt.RenderingHints;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.VolatileImage;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.simantics.scenegraph.g2d.G2DRenderingHints;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
+import org.simantics.scenegraph.g2d.color.Graphics2DWithColorFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -99,7 +103,7 @@ public class MipMapVRamBufferedImage extends MipMapBufferedImage {
          * @param image
          * @return
          */
-        private VolatileImage sourceRender(VolatileImage image) {
+        private VolatileImage sourceRender(VolatileImage image, ColorFilter colorFilter) {
             Graphics2D target = image.createGraphics();
             target.setBackground(new Color(255,255,255,0));
             target.clearRect(0, 0, image.getWidth(), image.getHeight());
@@ -113,7 +117,11 @@ public class MipMapVRamBufferedImage extends MipMapBufferedImage {
             target.scale(resolution, resolution);
             target.translate(-imageBounds.getMinX(), -imageBounds.getMinY());
             try {
-                source.render(target);
+                if (colorFilter != null) {
+                    source.render(new Graphics2DWithColorFilter(target, colorFilter));
+                } else {
+                    source.render(target);
+                }
             } catch (Exception e) {
                 e.printStackTrace();
                 target.dispose();
@@ -125,7 +133,7 @@ public class MipMapVRamBufferedImage extends MipMapBufferedImage {
             return image;
         }
 
-        synchronized VolatileImage restore(GraphicsConfiguration gc2) {
+        synchronized VolatileImage restore(GraphicsConfiguration gc2, ColorFilter colorFilter) {
             //System.out.println("restoring provider " + imageProvider);
             VolatileImage image = imageProvider.get(gc2, this.validateResult);
 
@@ -144,12 +152,15 @@ public class MipMapVRamBufferedImage extends MipMapBufferedImage {
 //            }
 
             boolean contentsLost = validateResult != VolatileImage.IMAGE_OK || image.contentsLost();
-            return contentsLost ? sourceRender(image) : image;
+            boolean changed = !Objects.equals(colorFilter, previousColorFilter);
+            previousColorFilter = colorFilter;
+            return contentsLost || changed ? sourceRender(image, colorFilter) : image;
             //return contentsLost ? sourceRender(image) : sourceRender(image);
         }
 
         public void paint(Graphics2D g) {
-            VolatileImage image = restore(g.getDeviceConfiguration());
+            ColorFilter colorFilter = (ColorFilter) g.getRenderingHint(G2DRenderingHints.KEY_COLOR_FILTER);
+            VolatileImage image = restore(g.getDeviceConfiguration(), colorFilter);
             if (image==null)
             {
                 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
@@ -158,7 +169,7 @@ public class MipMapVRamBufferedImage extends MipMapBufferedImage {
                 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
 
                 try {
-                    source.render(g);
+                    source.render(new Graphics2DWithColorFilter(g, colorFilter));
                 } catch (Exception e) {
                     // TODO Auto-generated catch block
                     // NOTE: Catching Exception instead of SVGException due to an