1/*
2 * Copyright (c) 1998, 2015, 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
26/* ********************************************************************
27 **********************************************************************
28 **********************************************************************
29 *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
30 *** As  an unpublished  work pursuant to Title 17 of the United    ***
31 *** States Code.  All rights reserved.                             ***
32 **********************************************************************
33 **********************************************************************
34 **********************************************************************/
35
36package java.awt.image.renderable;
37
38import java.awt.image.ColorModel;
39import java.awt.image.DataBuffer;
40import java.awt.image.ImageConsumer;
41import java.awt.image.ImageProducer;
42import java.awt.image.Raster;
43import java.awt.image.RenderedImage;
44import java.awt.image.SampleModel;
45import java.util.Enumeration;
46import java.util.Vector;
47
48/**
49 * An adapter class that implements ImageProducer to allow the
50 * asynchronous production of a RenderableImage.  The size of the
51 * ImageConsumer is determined by the scale factor of the usr2dev
52 * transform in the RenderContext.  If the RenderContext is null, the
53 * default rendering of the RenderableImage is used.  This class
54 * implements an asynchronous production that produces the image in
55 * one thread at one resolution.  This class may be subclassed to
56 * implement versions that will render the image using several
57 * threads.  These threads could render either the same image at
58 * progressively better quality, or different sections of the image at
59 * a single resolution.
60 */
61public class RenderableImageProducer implements ImageProducer, Runnable {
62
63    /** The RenderableImage source for the producer. */
64    RenderableImage rdblImage;
65
66    /** The RenderContext to use for producing the image. */
67    RenderContext rc;
68
69    /** A Vector of image consumers. */
70    Vector<ImageConsumer> ics = new Vector<>();
71
72    /**
73     * Constructs a new RenderableImageProducer from a RenderableImage
74     * and a RenderContext.
75     *
76     * @param rdblImage the RenderableImage to be rendered.
77     * @param rc the RenderContext to use for producing the pixels.
78     */
79    public RenderableImageProducer(RenderableImage rdblImage,
80                                   RenderContext rc) {
81        this.rdblImage = rdblImage;
82        this.rc = rc;
83    }
84
85    /**
86     * Sets a new RenderContext to use for the next startProduction() call.
87     *
88     * @param rc the new RenderContext.
89     */
90    public synchronized void setRenderContext(RenderContext rc) {
91        this.rc = rc;
92    }
93
94   /**
95     * Adds an ImageConsumer to the list of consumers interested in
96     * data for this image.
97     *
98     * @param ic an ImageConsumer to be added to the interest list.
99     */
100    public synchronized void addConsumer(ImageConsumer ic) {
101        if (!ics.contains(ic)) {
102            ics.addElement(ic);
103        }
104    }
105
106    /**
107     * Determine if an ImageConsumer is on the list of consumers
108     * currently interested in data for this image.
109     *
110     * @param ic the ImageConsumer to be checked.
111     * @return true if the ImageConsumer is on the list; false otherwise.
112     */
113    public synchronized boolean isConsumer(ImageConsumer ic) {
114        return ics.contains(ic);
115    }
116
117    /**
118     * Remove an ImageConsumer from the list of consumers interested in
119     * data for this image.
120     *
121     * @param ic the ImageConsumer to be removed.
122     */
123    public synchronized void removeConsumer(ImageConsumer ic) {
124        ics.removeElement(ic);
125    }
126
127    /**
128     * Adds an ImageConsumer to the list of consumers interested in
129     * data for this image, and immediately starts delivery of the
130     * image data through the ImageConsumer interface.
131     *
132     * @param ic the ImageConsumer to be added to the list of consumers.
133     */
134    public synchronized void startProduction(ImageConsumer ic) {
135        addConsumer(ic);
136        // Need to build a runnable object for the Thread.
137        String name = "RenderableImageProducer Thread";
138        Thread thread = new Thread(null, this, name, 0, false);
139        thread.start();
140    }
141
142    /**
143     * Requests that a given ImageConsumer have the image data delivered
144     * one more time in top-down, left-right order.
145     *
146     * @param ic the ImageConsumer requesting the resend.
147     */
148    public void requestTopDownLeftRightResend(ImageConsumer ic) {
149        // So far, all pixels are already sent in TDLR order
150    }
151
152    /**
153     * The runnable method for this class. This will produce an image using
154     * the current RenderableImage and RenderContext and send it to all the
155     * ImageConsumer currently registered with this class.
156     */
157    public void run() {
158        // First get the rendered image
159        RenderedImage rdrdImage;
160        if (rc != null) {
161            rdrdImage = rdblImage.createRendering(rc);
162        } else {
163            rdrdImage = rdblImage.createDefaultRendering();
164        }
165
166        // And its ColorModel
167        ColorModel colorModel = rdrdImage.getColorModel();
168        Raster raster = rdrdImage.getData();
169        SampleModel sampleModel = raster.getSampleModel();
170        DataBuffer dataBuffer = raster.getDataBuffer();
171
172        if (colorModel == null) {
173            colorModel = ColorModel.getRGBdefault();
174        }
175        int minX = raster.getMinX();
176        int minY = raster.getMinY();
177        int width = raster.getWidth();
178        int height = raster.getHeight();
179
180        Enumeration<ImageConsumer> icList;
181        ImageConsumer ic;
182        // Set up the ImageConsumers
183        icList = ics.elements();
184        while (icList.hasMoreElements()) {
185            ic = icList.nextElement();
186            ic.setDimensions(width,height);
187            ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
188                        ImageConsumer.COMPLETESCANLINES |
189                        ImageConsumer.SINGLEPASS |
190                        ImageConsumer.SINGLEFRAME);
191        }
192
193        // Get RGB pixels from the raster scanline by scanline and
194        // send to consumers.
195        int pix[] = new int[width];
196        int i,j;
197        int numBands = sampleModel.getNumBands();
198        int tmpPixel[] = new int[numBands];
199        for (j = 0; j < height; j++) {
200            for(i = 0; i < width; i++) {
201                sampleModel.getPixel(i, j, tmpPixel, dataBuffer);
202                pix[i] = colorModel.getDataElement(tmpPixel, 0);
203            }
204            // Now send the scanline to the Consumers
205            icList = ics.elements();
206            while (icList.hasMoreElements()) {
207                ic = icList.nextElement();
208                ic.setPixels(0, j, width, 1, colorModel, pix, 0, width);
209            }
210        }
211
212        // Now tell the consumers we're done.
213        icList = ics.elements();
214        while (icList.hasMoreElements()) {
215            ic = icList.nextElement();
216            ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
217        }
218    }
219}
220