1/*
2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.awt.image;
27
28import java.awt.Image;
29import java.awt.image.ImageFilter;
30import java.awt.image.ImageConsumer;
31import java.awt.image.ImageProducer;
32import java.util.Hashtable;
33import java.awt.image.ColorModel;
34
35/**
36 * This class is an implementation of the ImageProducer interface which
37 * takes an existing image and a filter object and uses them to produce
38 * image data for a new filtered version of the original image.
39 * Here is an example which filters an image by swapping the red and
40 * blue components:
41 * <pre>
42 *
43 *      Image src = getImage("doc:///demo/images/duke/T1.gif");
44 *      ImageFilter colorfilter = new RedBlueSwapFilter();
45 *      Image img = createImage(new FilteredImageSource(src.getSource(),
46 *                                                      colorfilter));
47 *
48 * </pre>
49 *
50 * @see ImageProducer
51 *
52 * @author      Jim Graham
53 */
54public class FilteredImageSource implements ImageProducer {
55    ImageProducer src;
56    ImageFilter filter;
57
58    /**
59     * Constructs an ImageProducer object from an existing ImageProducer
60     * and a filter object.
61     * @param orig the specified {@code ImageProducer}
62     * @param imgf the specified {@code ImageFilter}
63     * @see ImageFilter
64     * @see java.awt.Component#createImage
65     */
66    public FilteredImageSource(ImageProducer orig, ImageFilter imgf) {
67        src = orig;
68        filter = imgf;
69    }
70
71    private Hashtable<ImageConsumer, ImageFilter> proxies;
72
73    /**
74     * Adds the specified {@code ImageConsumer}
75     * to the list of consumers interested in data for the filtered image.
76     * An instance of the original {@code ImageFilter}
77     * is created
78     * (using the filter's {@code getFilterInstance} method)
79     * to manipulate the image data
80     * for the specified {@code ImageConsumer}.
81     * The newly created filter instance
82     * is then passed to the {@code addConsumer} method
83     * of the original {@code ImageProducer}.
84     *
85     * <p>
86     * This method is public as a side effect
87     * of this class implementing
88     * the {@code ImageProducer} interface.
89     * It should not be called from user code,
90     * and its behavior if called from user code is unspecified.
91     *
92     * @param ic  the consumer for the filtered image
93     * @see ImageConsumer
94     */
95    public synchronized void addConsumer(ImageConsumer ic) {
96        if (proxies == null) {
97            proxies = new Hashtable<>();
98        }
99        if (!proxies.containsKey(ic)) {
100            ImageFilter imgf = filter.getFilterInstance(ic);
101            proxies.put(ic, imgf);
102            src.addConsumer(imgf);
103        }
104    }
105
106    /**
107     * Determines whether an ImageConsumer is on the list of consumers
108     * currently interested in data for this image.
109     *
110     * <p>
111     * This method is public as a side effect
112     * of this class implementing
113     * the {@code ImageProducer} interface.
114     * It should not be called from user code,
115     * and its behavior if called from user code is unspecified.
116     *
117     * @param ic the specified {@code ImageConsumer}
118     * @return true if the ImageConsumer is on the list; false otherwise
119     * @see ImageConsumer
120     */
121    public synchronized boolean isConsumer(ImageConsumer ic) {
122        return (proxies != null && proxies.containsKey(ic));
123    }
124
125    /**
126     * Removes an ImageConsumer from the list of consumers interested in
127     * data for this image.
128     *
129     * <p>
130     * This method is public as a side effect
131     * of this class implementing
132     * the {@code ImageProducer} interface.
133     * It should not be called from user code,
134     * and its behavior if called from user code is unspecified.
135     *
136     * @see ImageConsumer
137     */
138    public synchronized void removeConsumer(ImageConsumer ic) {
139        if (proxies != null) {
140            ImageFilter imgf =  proxies.get(ic);
141            if (imgf != null) {
142                src.removeConsumer(imgf);
143                proxies.remove(ic);
144                if (proxies.isEmpty()) {
145                    proxies = null;
146                }
147            }
148        }
149    }
150
151    /**
152     * Starts production of the filtered image.
153     * If the specified {@code ImageConsumer}
154     * isn't already a consumer of the filtered image,
155     * an instance of the original {@code ImageFilter}
156     * is created
157     * (using the filter's {@code getFilterInstance} method)
158     * to manipulate the image data
159     * for the {@code ImageConsumer}.
160     * The filter instance for the {@code ImageConsumer}
161     * is then passed to the {@code startProduction} method
162     * of the original {@code ImageProducer}.
163     *
164     * <p>
165     * This method is public as a side effect
166     * of this class implementing
167     * the {@code ImageProducer} interface.
168     * It should not be called from user code,
169     * and its behavior if called from user code is unspecified.
170     *
171     * @param ic  the consumer for the filtered image
172     * @see ImageConsumer
173     */
174    public void startProduction(ImageConsumer ic) {
175        if (proxies == null) {
176            proxies = new Hashtable<>();
177        }
178        ImageFilter imgf = proxies.get(ic);
179        if (imgf == null) {
180            imgf = filter.getFilterInstance(ic);
181            proxies.put(ic, imgf);
182        }
183        src.startProduction(imgf);
184    }
185
186    /**
187     * Requests that a given ImageConsumer have the image data delivered
188     * one more time in top-down, left-right order.  The request is
189     * handed to the ImageFilter for further processing, since the
190     * ability to preserve the pixel ordering depends on the filter.
191     *
192     * <p>
193     * This method is public as a side effect
194     * of this class implementing
195     * the {@code ImageProducer} interface.
196     * It should not be called from user code,
197     * and its behavior if called from user code is unspecified.
198     *
199     * @see ImageConsumer
200     */
201    public void requestTopDownLeftRightResend(ImageConsumer ic) {
202        if (proxies != null) {
203            ImageFilter imgf = proxies.get(ic);
204            if (imgf != null) {
205                imgf.resendTopDownLeftRight(src);
206            }
207        }
208    }
209}
210