1/*
2 * Copyright (c) 1995, 2016, 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 sun.awt.image;
27
28import java.util.Hashtable;
29import java.awt.image.ImageConsumer;
30import java.awt.image.ImageProducer;
31import java.awt.image.Raster;
32import java.awt.image.WritableRaster;
33import java.awt.image.ColorModel;
34import java.awt.image.IndexColorModel;
35import java.awt.image.DirectColorModel;
36import java.awt.image.BufferedImage;
37import java.awt.image.DataBuffer;
38
39public class OffScreenImageSource implements ImageProducer {
40    BufferedImage image;
41    int width;
42    int height;
43    Hashtable<?, ?> properties;
44
45    public OffScreenImageSource(BufferedImage image,
46                                Hashtable<?, ?> properties) {
47        this.image = image;
48        if (properties != null) {
49            this.properties = properties;
50        } else {
51            this.properties = new Hashtable<String, Object>();
52        }
53        width  = image.getWidth();
54        height = image.getHeight();
55    }
56
57    public OffScreenImageSource(BufferedImage image) {
58        this(image, null);
59    }
60
61    // We can only have one consumer since we immediately return the data...
62    private ImageConsumer theConsumer;
63
64    public synchronized void addConsumer(ImageConsumer ic) {
65        theConsumer = ic;
66        produce();
67    }
68
69    public synchronized boolean isConsumer(ImageConsumer ic) {
70        return (ic == theConsumer);
71    }
72
73    public synchronized void removeConsumer(ImageConsumer ic) {
74        if (theConsumer == ic) {
75            theConsumer = null;
76        }
77    }
78
79    public void startProduction(ImageConsumer ic) {
80        addConsumer(ic);
81    }
82
83    public void requestTopDownLeftRightResend(ImageConsumer ic) {
84    }
85
86    private void sendPixels() {
87        ColorModel cm = image.getColorModel();
88        WritableRaster raster = image.getRaster();
89        int numDataElements = raster.getNumDataElements();
90        int dataType = raster.getDataBuffer().getDataType();
91        int[] scanline = new int[width*numDataElements];
92        boolean needToCvt = true;
93
94        if (cm instanceof IndexColorModel) {
95            byte[] pixels = new byte[width];
96            theConsumer.setColorModel(cm);
97
98            if (raster instanceof ByteComponentRaster) {
99                needToCvt = false;
100                for (int y=0; y < height; y++) {
101                    raster.getDataElements(0, y, width, 1, pixels);
102                    theConsumer.setPixels(0, y, width, 1, cm, pixels, 0,
103                                          width);
104                }
105            }
106            else if (raster instanceof BytePackedRaster) {
107                needToCvt = false;
108                // Binary image.  Need to unpack it
109                for (int y=0; y < height; y++) {
110                    raster.getPixels(0, y, width, 1, scanline);
111                    for (int x=0; x < width; x++) {
112                        pixels[x] = (byte) scanline[x];
113                    }
114                    theConsumer.setPixels(0, y, width, 1, cm, pixels, 0,
115                                          width);
116                }
117            }
118            else if (dataType == DataBuffer.TYPE_SHORT ||
119                     dataType == DataBuffer.TYPE_INT)
120            {
121                // Probably a short or int "GRAY" image
122                needToCvt = false;
123                for (int y=0; y < height; y++) {
124                    raster.getPixels(0, y, width, 1, scanline);
125                    theConsumer.setPixels(0, y, width, 1, cm, scanline, 0,
126                                          width);
127                }
128            }
129        }
130        else if (cm instanceof DirectColorModel) {
131            theConsumer.setColorModel(cm);
132            needToCvt = false;
133            switch (dataType) {
134            case DataBuffer.TYPE_INT:
135                for (int y=0; y < height; y++) {
136                    raster.getDataElements(0, y, width, 1, scanline);
137                    theConsumer.setPixels(0, y, width, 1, cm, scanline, 0,
138                                          width);
139                }
140                break;
141            case DataBuffer.TYPE_BYTE:
142                byte[] bscanline = new byte[width];
143                for (int y=0; y < height; y++) {
144                    raster.getDataElements(0, y, width, 1, bscanline);
145                    for (int x=0; x < width; x++) {
146                        scanline[x] = bscanline[x]&0xff;
147                    }
148                    theConsumer.setPixels(0, y, width, 1, cm, scanline, 0,
149                                          width);
150                }
151                break;
152            case DataBuffer.TYPE_USHORT:
153                short[] sscanline = new short[width];
154                for (int y=0; y < height; y++) {
155                    raster.getDataElements(0, y, width, 1, sscanline);
156                    for (int x=0; x < width; x++) {
157                        scanline[x] = sscanline[x]&0xffff;
158                    }
159                    theConsumer.setPixels(0, y, width, 1, cm, scanline, 0,
160                                          width);
161                }
162                break;
163            default:
164                needToCvt = true;
165            }
166        }
167
168        if (needToCvt) {
169            // REMIND: Need to add other types of CMs here
170            ColorModel newcm = ColorModel.getRGBdefault();
171            theConsumer.setColorModel(newcm);
172
173            for (int y=0; y < height; y++) {
174                for (int x=0; x < width; x++) {
175                    scanline[x] = image.getRGB(x, y);
176                }
177                theConsumer.setPixels(0, y, width, 1, newcm, scanline, 0,
178                                      width);
179            }
180        }
181    }
182
183    private void produce() {
184        try {
185            theConsumer.setDimensions(image.getWidth(), image.getHeight());
186            theConsumer.setProperties(properties);
187            sendPixels();
188            theConsumer.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
189
190            // If 'theconsumer' has not unregistered itself after previous call
191            if (theConsumer != null) {
192                try {
193                    theConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
194                } catch (RuntimeException e) {
195                    // We did not previously call this method here and
196                    // some image consumer filters were not prepared for it to be
197                    // called at this time. We allow them to have runtime issues
198                    // for this one call only without triggering the IMAGEERROR
199                    // condition below.
200                    e.printStackTrace();
201                }
202            }
203        } catch (NullPointerException e) {
204            e.printStackTrace();
205
206            if (theConsumer != null) {
207                theConsumer.imageComplete(ImageConsumer.IMAGEERROR);
208            }
209        }
210    }
211}
212