001    /* MemoryImageSource.java -- Java class for providing image data
002       Copyright (C) 1999, 2004, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt.image;
040    
041    import java.util.Hashtable;
042    import java.util.Vector;
043    
044    /**
045     * An image producer that delivers image data from an array.
046     */
047    public class MemoryImageSource implements ImageProducer
048    {
049      private boolean animated = false;
050      private boolean fullbuffers = false;
051      private int[] pixeli;
052      private int width;
053      private int height;
054      private int offset;
055      private int scansize;
056      private byte[] pixelb;
057      private ColorModel cm;
058      private Hashtable props = new Hashtable();
059      private Vector consumers = new Vector();
060    
061      /**
062       * Construct an image producer that reads image data from a byte
063       * array.
064       *
065       * @param w width of image
066       * @param h height of image
067       * @param cm the color model used to represent pixel values
068       * @param pix a byte array of pixel values
069       * @param off the offset into the array at which the first pixel is stored
070       * @param scan the number of array elements that represents a single pixel row
071       */
072      public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off,
073                               int scan)
074      {
075        this(w, h, cm, pix, off, scan, null);
076      }
077    
078      /**
079       * Constructs an ImageProducer from memory.
080       *
081       * @param w  the image width.
082       * @param h  the image height.
083       * @param cm  the color model.
084       * @param pix  the image data.
085       * @param off  the offset to the first pixel in the array.
086       * @param scan  the number of array elements from a pixel on one row to the
087       *     corresponding pixel on the next row.
088       * @param props  image properties (<code>null</code> permitted).
089       */
090      public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off,
091                               int scan, Hashtable<?,?> props)
092      {
093        width = w;
094        height = h;
095        this.cm = cm;
096        offset = off;
097        scansize = scan;
098        this.props = props;
099        int max = ((scansize > width) ? scansize : width);
100        pixelb = pix;
101      }
102    
103      /**
104       * Construct an image producer that reads image data from an
105       * integer array.
106       *
107       * @param w width of image
108       * @param h height of image
109       * @param cm the color model used to represent pixel values
110       * @param pix an integer array of pixel values
111       * @param off the offset into the array at which the first pixel is stored
112       * @param scan the number of array elements that represents a single pixel row
113       */
114      public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off,
115                               int scan)
116      {
117        this(w, h, cm, pix, off, scan, null);
118      }
119    
120      /**
121       * Constructs an ImageProducer from memory
122       *
123       * @param w  the image width.
124       * @param h  the image height.
125       * @param cm  the color model.
126       * @param pix  the image data.
127       * @param off  the offset to the first pixel in the array.
128       * @param scan  the number of array elements from a pixel on one row to the
129       *     corresponding pixel on the next row.
130       * @param props  image properties (<code>null</code> permitted).
131       */
132      public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off,
133                               int scan, Hashtable<?,?> props)
134      {
135        width = w;
136        height = h;
137        this.cm = cm;
138        offset = off;
139        scansize = scan;
140        this.props = props;
141        int max = ((scansize > width) ? scansize : width);
142        pixeli = pix;
143      }
144    
145      /**
146       * Constructs an ImageProducer from memory using the default RGB ColorModel.
147       *
148       * @param w  the image width.
149       * @param h  the image height.
150       * @param pix  the image data.
151       * @param off  the offset to the first pixel in the array.
152       * @param scan  the number of array elements from a pixel on one row to the
153       *     corresponding pixel on the next row.
154       * @param props  image properties (<code>null</code> permitted).
155    
156       */
157      public MemoryImageSource(int w, int h, int[] pix, int off, int scan,
158                               Hashtable<?,?> props)
159      {
160        this(w, h, ColorModel.getRGBdefault(), pix, off, scan, props);
161      }
162    
163      /**
164       * Constructs an ImageProducer from memory using the default RGB ColorModel.
165       *
166       * @param w  the image width.
167       * @param h  the image height.
168       * @param pix  the image data.
169       * @param off  the offset to the first pixel in the array.
170       * @param scan  the number of array elements from a pixel on one row to the
171       *     corresponding pixel on the next row.
172       */
173      public MemoryImageSource(int w, int h, int[] pix, int off, int scan)
174      {
175        this(w, h, ColorModel.getRGBdefault(), pix, off, scan, null);
176      }
177    
178      /**
179       * Used to register an <code>ImageConsumer</code> with this
180       * <code>ImageProducer</code>.
181       *
182       * @param ic  the image consumer.
183       */
184      public synchronized void addConsumer(ImageConsumer ic)
185      {
186        if (consumers.contains(ic))
187          return;
188    
189        consumers.addElement(ic);
190      }
191    
192      /**
193       * Used to determine if the given <code>ImageConsumer</code> is
194       * already registered with this <code>ImageProducer</code>.
195       *
196       * @param ic  the image consumer.
197       */
198      public synchronized boolean isConsumer(ImageConsumer ic)
199      {
200        if (consumers.contains(ic))
201          return true;
202        return false;
203      }
204    
205      /**
206       * Used to remove an <code>ImageConsumer</code> from the list of
207       * registered consumers for this <code>ImageProducer</code>.
208       *
209       * @param ic  the image consumer.
210       */
211      public synchronized void removeConsumer(ImageConsumer ic)
212      {
213        consumers.removeElement(ic);
214      }
215    
216      /**
217       * Used to register an <code>ImageConsumer</code> with this
218       * <code>ImageProducer</code> and then immediately start
219       * reconstruction of the image data to be delivered to all
220       * registered consumers.
221       */
222      public void startProduction(ImageConsumer ic)
223      {
224        if (! (consumers.contains(ic)))
225          consumers.addElement(ic);
226    
227        Vector list = (Vector) consumers.clone();
228        for (int i = 0; i < list.size(); i++)
229          {
230            ic = (ImageConsumer) list.elementAt(i);
231            sendPicture(ic);
232            if (animated)
233              ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
234            else
235              ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
236          }
237      }
238    
239      /**
240       * Used to register an <code>ImageConsumer</code> with this
241       * <code>ImageProducer</code> and then request that this producer
242       * resend the image data in the order top-down, left-right.
243       *
244       * @param ic  the image consumer.
245       */
246      public void requestTopDownLeftRightResend(ImageConsumer ic)
247      {
248        startProduction(ic);
249      }
250    
251      /**
252       * Changes a flag to indicate whether this MemoryImageSource supports
253       * animations.
254       *
255       * @param animated A flag indicating whether this class supports animations
256       */
257      public synchronized void setAnimated(boolean animated)
258      {
259        this.animated = animated;
260      }
261    
262      /**
263       * A flag to indicate whether or not to send full buffer updates when
264       * sending animation. If this flag is set then full buffers are sent
265       * in the newPixels methods instead of just regions.
266       *
267       * @param fullbuffers a flag indicating whether to send the full buffers
268       */
269      public synchronized void setFullBufferUpdates(boolean fullbuffers)
270      {
271        this.fullbuffers = fullbuffers;
272      }
273    
274      /**
275       * Send an animation frame to the image consumers.
276       */
277      public void newPixels()
278      {
279        if (animated == true)
280          {
281            ImageConsumer ic;
282            Vector list = (Vector) consumers.clone();
283            for (int i = 0; i < list.size(); i++)
284              {
285                ic = (ImageConsumer) list.elementAt(i);
286                sendPicture(ic);
287                ic.imageComplete(ImageConsumer.SINGLEFRAME);
288              }
289          }
290      }
291    
292      private void sendPicture(ImageConsumer ic)
293      {
294        ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT);
295        if (props != null)
296          ic.setProperties(props);
297        ic.setDimensions(width, height);
298        ic.setColorModel(cm);
299        if (pixeli != null)
300          ic.setPixels(0, 0, width, height, cm, pixeli, offset, scansize);
301        else
302          ic.setPixels(0, 0, width, height, cm, pixelb, offset, scansize);
303      }
304    
305      /**
306       * Send an animation frame to the image consumers containing the specified
307       * pixels unless setFullBufferUpdates is set.
308       *
309       * @param x  the x-coordinate.
310       * @param y  the y-coordinate.
311       * @param w  the width.
312       * @param h  the height.
313       */
314      public synchronized void newPixels(int x, int y, int w, int h)
315      {
316        if (animated == true)
317          {
318            if (fullbuffers)
319              newPixels();
320            else
321              {
322                ImageConsumer ic;
323                Vector list = (Vector) consumers.clone();
324                for (int i = 0; i < list.size(); i++)
325                  {
326                    ic = (ImageConsumer) list.elementAt(i);
327                    ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT);
328                    if (props != null)
329                      ic.setProperties(props);
330                    if (pixeli != null)
331                      {
332                        int[] pixelbuf = new int[w * h];
333                        for (int row = y; row < y + h; row++)
334                          System.arraycopy(pixeli, row * scansize + x + offset,
335                                           pixelbuf, 0, w * h);
336                        ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w);
337                      }
338                    else
339                      {
340                        byte[] pixelbuf = new byte[w * h];
341                        for (int row = y; row < y + h; row++)
342                          System.arraycopy(pixelb, row * scansize + x + offset,
343                                           pixelbuf, 0, w * h);
344    
345                        ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w);
346                      }
347                    ic.imageComplete(ImageConsumer.SINGLEFRAME);
348                  }
349              }
350          }
351      }
352    
353      /**
354       * Send an animation frame to the image consumers containing the specified
355       * pixels unless setFullBufferUpdates is set.
356       *
357       * If framenotify is set then a notification is sent when the frame
358       * is sent otherwise no status is sent.
359       *
360       * @param x  the x-coordinate.
361       * @param y  the y-coordinate.
362       * @param w  the width.
363       * @param h  the height.
364       * @param framenotify  send notification?
365       */
366      public synchronized void newPixels(int x, int y, int w, int h,
367                                         boolean framenotify)
368      {
369        if (animated == true)
370          {
371            if (fullbuffers)
372              newPixels();
373            else
374              {
375                ImageConsumer ic;
376                Vector list = (Vector) consumers.clone();
377                for (int i = 0; i < list.size(); i++)
378                  {
379                    ic = (ImageConsumer) list.elementAt(i);
380                    ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT);
381                    if (props != null)
382                      ic.setProperties(props);
383                    if (pixeli != null)
384                      {
385                        int[] pixelbuf = new int[w * h];
386                        for (int row = y; row < y + h; row++)
387                          System.arraycopy(pixeli, row * scansize + x + offset,
388                                           pixelbuf, 0, w * h);
389                        ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w);
390                      }
391                    else
392                      {
393                        byte[] pixelbuf = new byte[w * h];
394                        for (int row = y; row < y + h; row++)
395                          System.arraycopy(pixelb, row * scansize + x + offset,
396                                           pixelbuf, 0, w * h);
397                        ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w);
398                      }
399                    if (framenotify == true)
400                      ic.imageComplete(ImageConsumer.SINGLEFRAME);
401                  }
402              }
403          }
404      }
405    
406      public synchronized void newPixels(byte[] newpix, ColorModel newmodel,
407                                         int offset, int scansize)
408      {
409        pixeli = null;
410        pixelb = newpix;
411        cm = newmodel;
412        this.offset = offset;
413        this.scansize = scansize;
414        if (animated == true)
415          newPixels();
416      }
417    
418      public synchronized void newPixels(int[] newpix, ColorModel newmodel,
419                                         int offset, int scansize)
420      {
421        pixelb = null;
422        pixeli = newpix;
423        cm = newmodel;
424        this.offset = offset;
425        this.scansize = scansize;
426        if (animated == true)
427          newPixels();
428      }
429    }