1 /* 2 * Copyright (c) 1998, 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 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 36 package java.awt.image.renderable; 37 import java.awt.color.ColorSpace; 38 import java.awt.image.ColorModel; 39 import java.awt.image.DataBuffer; 40 import java.awt.image.DirectColorModel; 41 import java.awt.image.ImageConsumer; 42 import java.awt.image.ImageProducer; 43 import java.awt.image.Raster; 44 import java.awt.image.RenderedImage; 45 import java.awt.image.SampleModel; 46 import java.util.Enumeration; 47 import java.util.Vector; 48 49 /** 50 * An adapter class that implements ImageProducer to allow the 51 * asynchronous production of a RenderableImage. The size of the 52 * ImageConsumer is determined by the scale factor of the usr2dev 53 * transform in the RenderContext. If the RenderContext is null, the 54 * default rendering of the RenderableImage is used. This class 55 * implements an asynchronous production that produces the image in 56 * one thread at one resolution. This class may be subclassed to 57 * implement versions that will render the image using several 58 * threads. These threads could render either the same image at 59 * progressively better quality, or different sections of the image at 60 * a single resolution. 61 */ 62 public class RenderableImageProducer implements ImageProducer, Runnable { 63 64 /** The RenderableImage source for the producer. */ 65 RenderableImage rdblImage; 66 67 /** The RenderContext to use for producing the image. */ 68 RenderContext rc; 69 70 /** A Vector of image consumers. */ 71 Vector<ImageConsumer> ics = new Vector<>(); 72 73 /** 74 * Constructs a new RenderableImageProducer from a RenderableImage 75 * and a RenderContext. 76 * 77 * @param rdblImage the RenderableImage to be rendered. 78 * @param rc the RenderContext to use for producing the pixels. 79 */ 80 public RenderableImageProducer(RenderableImage rdblImage, 81 RenderContext rc) { 82 this.rdblImage = rdblImage; 83 this.rc = rc; 84 } 85 86 /** 87 * Sets a new RenderContext to use for the next startProduction() call. 88 * 89 * @param rc the new RenderContext. 90 */ 91 public synchronized void setRenderContext(RenderContext rc) { 92 this.rc = rc; 93 } 94 95 /** 96 * Adds an ImageConsumer to the list of consumers interested in 97 * data for this image. 98 * 99 * @param ic an ImageConsumer to be added to the interest list. 100 */ 101 public synchronized void addConsumer(ImageConsumer ic) { 102 if (!ics.contains(ic)) { 103 ics.addElement(ic); 104 } 105 } 106 107 /** 108 * Determine if an ImageConsumer is on the list of consumers 109 * currently interested in data for this image. 110 * 111 * @param ic the ImageConsumer to be checked. 112 * @return true if the ImageConsumer is on the list; false otherwise. 113 */ 114 public synchronized boolean isConsumer(ImageConsumer ic) { 115 return ics.contains(ic); 116 } 117 118 /** 119 * Remove an ImageConsumer from the list of consumers interested in 120 * data for this image. 121 * 122 * @param ic the ImageConsumer to be removed. 123 */ 124 public synchronized void removeConsumer(ImageConsumer ic) { 125 ics.removeElement(ic); 126 } 127 128 /** 129 * Adds an ImageConsumer to the list of consumers interested in 130 * data for this image, and immediately starts delivery of the 131 * image data through the ImageConsumer interface. 132 * 133 * @param ic the ImageConsumer to be added to the list of consumers. 134 */ 135 public synchronized void startProduction(ImageConsumer ic) { 136 addConsumer(ic); 137 // Need to build a runnable object for the Thread. 138 Thread thread = new Thread(this, "RenderableImageProducer Thread"); 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 }