]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/image/impl/Shadow.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / image / impl / Shadow.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g2d.image.impl;\r
13 \r
14 import java.awt.AlphaComposite;\r
15 import java.awt.Color;\r
16 import java.awt.Graphics2D;\r
17 import java.awt.geom.Point2D;\r
18 import java.awt.geom.Rectangle2D;\r
19 import java.awt.image.BufferedImage;\r
20 import java.awt.image.ConvolveOp;\r
21 import java.awt.image.Kernel;\r
22 import java.util.Arrays;\r
23 import java.util.EnumSet;\r
24 \r
25 import org.simantics.g2d.image.Image;\r
26 import org.simantics.scenegraph.Node;\r
27 import org.simantics.scenegraph.g2d.G2DParentNode;\r
28 \r
29 /**\r
30  * Reflects to a shadow of a symbol.\r
31  * \r
32  * @author Toni Kalajainen\r
33  */\r
34 public class Shadow extends ImageProxy implements Image {\r
35 \r
36     public static final ShadowParameters SHADOW = new ShadowParameters(0.5, Color.BLACK, 2);\r
37     public static final class ShadowParameters {\r
38         public final double alpha;\r
39         public final Color color;\r
40         public final int size;\r
41         public ShadowParameters(double alpha, Color color, int size) {\r
42             this.alpha = alpha;\r
43             this.color = color;\r
44             this.size = size;\r
45         }\r
46     }\r
47 \r
48     public final ShadowParameters shadow;\r
49     Point2D size;\r
50     ConvolveOp horiz, vert;\r
51     int shadowSizeX, shadowSizeY;\r
52     EnumSet<Feature> feats;\r
53     public ImageListener origListener;\r
54 \r
55     /**\r
56      * \r
57      * @param source\r
58      * @param shadow\r
59      * @param shadowOnly\r
60      */\r
61     public Shadow(Image source, ShadowParameters shadow)\r
62     {\r
63         super(source);\r
64         this.shadow = shadow;\r
65         shadowSizeX = shadow.size;\r
66         shadowSizeY = shadow.size;\r
67         horiz           = createBlurOp(shadow.size, 1);\r
68         vert            = createBlurOp(1, shadow.size);\r
69         if (source.getFeatures().contains(Feature.Volatile)) {\r
70             feats =     EnumSet.of(Feature.Volatile);\r
71         } else\r
72             feats = EnumSet.noneOf(Feature.class);\r
73     }\r
74 \r
75     public Shadow(Image source, ShadowParameters shadow, double width, double height)\r
76     {\r
77         this(source, shadow);\r
78         this.size       = new Point2D.Double(width, height);\r
79         shadowSizeX = (int) Math.round( shadow.size * width  / source.getBounds().getWidth()  );\r
80         shadowSizeY = (int) Math.round( shadow.size * height / source.getBounds().getHeight() );\r
81         if (shadowSizeX<1) shadowSizeX = 1;\r
82         if (shadowSizeY<1) shadowSizeY = 1;\r
83         horiz           = createBlurOp(shadowSizeX, 1);\r
84         vert            = createBlurOp(1, shadowSizeY);\r
85     }\r
86 \r
87     @Override\r
88     public Rectangle2D getBounds() {\r
89         Rectangle2D rect = source.getBounds();\r
90         return new Rectangle2D.Double(rect.getX() - shadowSizeX, rect.getY() - shadowSizeY, rect.getWidth() + shadowSizeX*2, rect.getHeight() + shadowSizeY*2);\r
91     }\r
92 \r
93     private BufferedImage createImage() {\r
94         Rectangle2D origBounds = source.getBounds();\r
95         double width =  size==null?origBounds.getWidth() :size.getX();\r
96         double height = size==null?origBounds.getHeight():size.getY();\r
97         BufferedImage subject = new BufferedImage(\r
98                 (int)Math.ceil( width  + shadowSizeX * 2 ),\r
99                 (int)Math.ceil( height + shadowSizeY * 2 ),\r
100                 BufferedImage.TYPE_INT_ARGB);\r
101 \r
102         Graphics2D g = subject.createGraphics();\r
103         g.translate(shadowSizeX, shadowSizeY);\r
104         if (size!=null)\r
105             g.scale(size.getX()/origBounds.getWidth(), size.getY()/origBounds.getHeight());\r
106         g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
107 \r
108         Rectangle2D bounds = new Rectangle2D.Double(0, 0, subject.getWidth(), subject.getHeight());\r
109 //        GraphicsContextImpl gc = new GraphicsContextImpl(bounds, null);\r
110 //        try {\r
111 //              source.paint(gc);\r
112 //        } finally {\r
113 //              gc.dispose();\r
114 //        }\r
115 \r
116         g.dispose();\r
117         return subject;\r
118     }\r
119 \r
120     private BufferedImage createShadowMask(BufferedImage image) {\r
121         BufferedImage mask = new BufferedImage(image.getWidth(),\r
122                 image.getHeight(),\r
123                 BufferedImage.TYPE_INT_ARGB);\r
124 \r
125         Graphics2D g2d = mask.createGraphics();\r
126         g2d.drawImage(image, 0, 0, null);\r
127         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN,\r
128                 (float)shadow.alpha));\r
129         g2d.setColor(shadow.color);\r
130         g2d.fillRect(0, 0, image.getWidth(), image.getHeight());\r
131         g2d.dispose();\r
132 \r
133         return mask;\r
134     }\r
135 \r
136     public BufferedImage createShadow() {\r
137         BufferedImage i1 = createImage();\r
138         BufferedImage i2 = new BufferedImage(i1.getWidth(), i1.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
139         BufferedImage shadowMask = createShadowMask(i1);\r
140         horiz.filter(shadowMask, i2);\r
141         vert.filter(i2, shadowMask);\r
142         return shadowMask;\r
143     }\r
144 \r
145     private ConvolveOp createBlurOp(int width, int height) {\r
146         float[] data = new float[width * height];\r
147         float value = 1.0f / (width * height);\r
148         Arrays.fill(data, value);\r
149         return new ConvolveOp(new Kernel(width, height, data));\r
150     }\r
151 \r
152 \r
153     @Override\r
154     public Node init(G2DParentNode parent) {\r
155         return null;\r
156 //              Graphics2D g = gc.getGraphics2D();\r
157 //              BufferedImage bi = createShadow();\r
158 //\r
159 //      Rectangle2D origBounds = source.getBounds();\r
160 //      if (size!=null) {\r
161 //                      g.translate(origBounds.getMinX(), origBounds.getMinY());\r
162 //                      g.scale(origBounds.getWidth()/size.getX(), origBounds.getHeight()/size.getY());\r
163 //                      g.translate(-shadowSizeX, -shadowSizeY);\r
164 //                      g.drawImage(bi, 0, 0, null);\r
165 //                      g.translate(shadowSizeX, shadowSizeY);\r
166 //                      g.scale(size.getX()/origBounds.getWidth(), size.getY()/origBounds.getHeight());\r
167 //                      g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
168 //              } else {\r
169 //                      g.translate(-shadowSizeX, -shadowSizeY);\r
170 //                      g.translate(origBounds.getMinX(), origBounds.getMinY());\r
171 //                      g.drawImage(bi, 0, 0, null);\r
172 //                      g.translate(shadowSizeX, shadowSizeY);\r
173 //                      g.translate(-origBounds.getMinX(), -origBounds.getMinY());\r
174 //              }\r
175     }\r
176 \r
177     @Override\r
178     public EnumSet<Feature> getFeatures() {\r
179         return feats;\r
180     }\r
181 \r
182 \r
183 }\r