Source code: com/arranger/jarl/filter/BaseFilter.java
1 package com.arranger.jarl.filter;
2
3 import com.arranger.jarl.base.BaseTimedJarlObject;
4 import com.arranger.jarl.base.IContext;
5 import com.arranger.jarl.util.ImageUtil;
6 import com.arranger.jarl.widget.IWidget;
7 import org.w3c.dom.Element;
8
9 import java.awt.*;
10 import java.awt.image.*;
11
12 /**
13 * BaseFilter created on Mar 20, 2003
14 */
15 public abstract class BaseFilter extends BaseTimedJarlObject implements IFilter, IFilterDef {
16
17 protected ImageFilter m_imageFilter;
18 protected boolean m_isLocal = false;
19
20 protected transient Image m_image;
21 protected transient Graphics2D m_graphics;
22
23 /**
24 * Prepare the filter with any changes as necessary
25 * @param context the current context
26 */
27 protected abstract void prepareFilter(IContext context);
28
29 /**
30 * @return the name of the underlying filter class
31 */
32 protected abstract String getImageFilterClassName();
33
34 public ImageFilter getImageFilter() {
35 return m_imageFilter;
36 }
37
38 /**
39 * @return true if this is local to a widget, false if it is global to the whole image
40 */
41 public boolean isLocal() {
42 return (m_startTime == null && m_endTime == null) ||
43 (m_startTime.getFrame() == -1 && m_endTime.getFrame() == -1);
44 }
45
46 public void init(IContext context, Element element) {
47 super.init(context, element);
48 if (!isLocal()) {
49 context.getRenderManager().register(this);
50 }
51 }
52
53 /**
54 * Based off of the actual def, get a real instance
55 * @param context
56 * @param element
57 * @return an initialized filter
58 */
59 public IFilter initInstance(IContext context, Element element) {
60 IFilter filter = (IFilter)clone();
61 filter.init(context, element);
62 return filter;
63 }
64
65 /**
66 * Instead of being a global filter, this is a local filter
67 *
68 * Pre process the filter by creating a temp image, and returning a custom graphics2D
69 * @param widget
70 * @param context
71 * @param graphics2D
72 * @return
73 */
74 public Graphics2D preFilterWidget(IWidget widget, IContext context, Graphics2D graphics2D) {
75 if (!isLocal()) {
76 throw new IllegalStateException("This is a global filter. preFilterWidget should not be called");
77 }
78
79 //create new image
80 m_image = context.createImage();
81
82 //copy/store graphics2D
83 Graphics2D newGraphics2D = (Graphics2D)m_image.getGraphics();
84 ImageUtil.copyGraphics(graphics2D, newGraphics2D);
85 m_graphics = graphics2D;
86
87 //set times
88 m_startTime = widget.getStartTime();
89 m_endTime = widget.getEndTime();
90
91 //return new graphics2D
92 return newGraphics2D;
93 }
94
95 /**
96 * Instead of being a global filter, this is a local filter
97 *
98 * Post filter applying the transparent overlay as well as returning the stored graphics
99 * @param widget
100 * @param context
101 * @param graphics
102 * @return the restored graphics
103 */
104 public Graphics2D postFilterWidget(IWidget widget, IContext context, Graphics2D graphics) {
105 //perform the actual filter
106 m_image = filterImage(context, m_image);
107
108 //copy transparent to the stored graphics
109 m_image = ImageUtil.createTransparentImage(m_image, Color.black);
110 ImageUtil.overlayTransparentImage(m_graphics, m_image);
111
112 //dispose old graphics
113 graphics.dispose();
114 m_image = null;
115
116 //restore times
117 m_startTime = null;
118 m_endTime = null;
119
120 //return graphics
121 return m_graphics;
122 }
123
124 /**
125 * Filter this image
126 * @param context current context
127 * @param srcImage the source of this image
128 * @return the filtered image
129 */
130 public Image filterImage(IContext context, Image srcImage) {
131 checkTime(context.getTime());
132
133 Image resImage = null;
134 try {
135 resImage = _filterImage(context, srcImage);
136 } catch (Exception e) {
137 e.printStackTrace();
138 }
139
140 //are we done rendering? only check if we're not local
141 if (!isLocal() && (context.getTime().isGreater(m_endTime) || context.getTime().equals(m_endTime))) {
142 context.getRenderManager().unregister(this);
143 }
144
145 return resImage;
146 }
147
148 /**
149 * Filter this image
150 * @param context current context
151 * @param srcImage the source of this image
152 * @return the filtered image
153 */
154 protected Image _filterImage(IContext context, Image srcImage) throws Exception {
155 prepareFilter(context);
156 return dofilter(context, srcImage);
157 }
158
159 protected Image dofilter(IContext context, Image image) throws InterruptedException {
160 image = prepareImage(context, image);
161 FilteredImageSource filteredImageSource = new FilteredImageSource(image.getSource(), m_imageFilter);
162 image = Toolkit.getDefaultToolkit().createImage(filteredImageSource);
163 return image;
164 }
165
166 protected Image prepareImage(IContext context, Image image) throws InterruptedException {
167 int width = context.getWidth();
168 int height = context.getHeight();
169 PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, width, height, true);
170 pixelGrabber.grabPixels();
171 return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width,
172 height,
173 (int [])pixelGrabber.getPixels(),
174 0,
175 width));
176 }
177
178 /**
179 * Always remember some attrs might not be there
180 * @param context
181 */
182 protected void initAttributes(IContext context) {
183 super.initAttributes(context);
184
185 //create Filter
186 try {
187 m_imageFilter = (ImageFilter)Class.forName(getImageFilterClassName()).newInstance();
188 } catch (Exception e) {
189 context.onError(e);
190 }
191 }
192
193 protected static void renderImage(Image image) {
194 ImageFilterObserver myObserver = new ImageFilterObserver();
195 if (image.getWidth(myObserver) != -1) {
196 return;
197 }
198 while (!myObserver.m_done) {
199 try {
200 Thread.sleep(100);
201 } catch (InterruptedException e) {
202 throw new IllegalStateException(e.getMessage());
203 }
204 }
205 }
206
207 protected static class ImageFilterObserver implements ImageObserver {
208 protected boolean m_done = false;
209 public boolean imageUpdate(Image img, int infoflags,
210 int x, int y, int width, int height) {
211 m_done = true;
212 return false;
213 }
214 }
215 }