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