001/* MemoryImageSource.java -- Java class for providing image data
002   Copyright (C) 1999, 2004, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt.image;
040
041import java.util.Hashtable;
042import java.util.Vector;
043
044/**
045 * An image producer that delivers image data from an array.
046 */
047public 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}