001    /*
002     * ImageCreator
003     * 
004     * Copyright (c) 2001, 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.gui.awt;
009    
010    import net.sourceforge.jiu.data.BilevelImage;
011    import net.sourceforge.jiu.data.Gray16Image;
012    import net.sourceforge.jiu.data.Gray8Image;
013    import net.sourceforge.jiu.data.MemoryRGB24Image;
014    import net.sourceforge.jiu.data.Palette;
015    import net.sourceforge.jiu.data.Paletted8Image;
016    import net.sourceforge.jiu.data.PixelImage;
017    import net.sourceforge.jiu.data.RGB24Image;
018    import net.sourceforge.jiu.data.RGB48Image;
019    import net.sourceforge.jiu.data.RGBIndex;
020    import java.awt.Frame;
021    import java.awt.Image;
022    import java.awt.Toolkit;
023    import java.awt.image.ImageObserver;
024    import java.awt.image.MemoryImageSource;
025    import java.awt.image.PixelGrabber;
026    
027    /**
028     * A class to create java.awt.Image objects from various JIU image data types
029     * and vice versa.
030     * java.awt.Image objects can be used with the AWT and Swing GUI environments.
031     *
032     * @author Marco Schmidt
033     */
034    public class ImageCreator
035    {
036            /**
037             * The default transparency value to be used: full opacity.
038             */
039            public static final int DEFAULT_ALPHA = 0xff000000;
040            private static Frame frame;
041    
042            private ImageCreator()
043            {
044            }
045    
046            /**
047             * Creates a {@link java.awt.Image} object from a pixel array.
048             * Internally, a {@link java.awt.Frame} object is used to call its 
049             * {@link java.awt.Frame#createImage} method
050             * with a {@link java.awt.image.MemoryImageSource} object.
051             *
052             * @param pixels the image pixel data in the typical RGBA 32-bit format, one int per pixel
053             * @param width the horizontal resolution in pixels of the image to be created
054             * @param height the vertical resolution in pixels of the image to be created
055             */
056            public static Image createImage(int[] pixels, int width, int height)
057            {
058                    if (width < 1 || height < 1)
059                    {
060                            throw new IllegalArgumentException("Error -- width and height " +
061                                    "must both be larger than zero.");
062                    }
063                    if (pixels == null)
064                    {
065                            throw new IllegalArgumentException("Error -- the pixel array " +
066                                    "must be non-null.");
067                    }
068                    if (pixels.length < width * height)
069                    {
070                            throw new IllegalArgumentException("Error -- the pixel array " +
071                                    "must contain at least width times height items.");
072                    }
073                    if (frame == null)
074                    {
075                            frame = new Frame();
076                    }
077                    return frame.createImage(new MemoryImageSource(width, height, pixels, 0, width));
078            }
079    
080            /**
081             * Creates an instance of {@link java.awt.Image} from an instance of
082             * {@link RGB24Image}.
083             * This will require <code>image.getWidth() * image.getHeight() * 4</code>
084             * bytes of free memory.
085             * This method checks the type of the argument image via instanceof
086             * and the calls the right convertToAwtImage method of this class.
087             * @param image the RGB24Image to be converted
088             * @return newly-created AWT image instance
089             */
090            public static Image convertToAwtImage(PixelImage image, int alpha)
091            {
092                    if (image == null)
093                    {
094                            return null;
095                    }
096                    if (image instanceof RGB24Image)
097                    {
098                            return convertToAwtImage((RGB24Image)image, alpha);
099                    }
100                    else
101                    if (image instanceof RGB48Image)
102                    {
103                            return convertToAwtImage((RGB48Image)image, alpha);
104                    }
105                    else
106                    if (image instanceof Gray8Image)
107                    {
108                            return convertToAwtImage((Gray8Image)image, alpha);
109                    }
110                    else
111                    if (image instanceof Gray16Image)
112                    {
113                            return convertToAwtImage((Gray16Image)image, alpha);
114                    }
115                    else
116                    if (image instanceof Paletted8Image)
117                    {
118                            return convertToAwtImage((Paletted8Image)image, alpha);
119                    }
120                    else
121                    if (image instanceof BilevelImage)
122                    {
123                            return convertToAwtImage((BilevelImage)image, alpha);
124                    }
125                    else
126                    {
127                            return null;
128                    }
129            }
130    
131            /**
132             * Convert a BilevelImage object to an AWT image object.
133             * @param image the image to be converted
134             * @param alpha the transparency value to be written to each
135             *  pixel in the resulting image
136             * @return newly-created AWT image
137             */
138            public static Image convertToAwtImage(BilevelImage image, int alpha)
139            {
140                    if (image == null)
141                    {
142                            return null;
143                    }
144                    Toolkit toolkit = Toolkit.getDefaultToolkit();
145                    if (toolkit == null)
146                    {
147                            return null;
148                    }
149                    int width = image.getWidth();
150                    int height = image.getHeight();
151                    if (width < 1 || height < 1)
152                    {
153                            return null;
154                    }
155                    int bytesPerRow = (width + 7) / 8;
156                    int[] pixels = new int[width * height];
157                    byte[] row = new byte[bytesPerRow];
158                    int destOffset = 0;
159                    for (int y = 0; y < height; y++)
160                    {
161                            image.getPackedBytes(0, y, width, row, 0, 0);
162                            RGBA.convertFromPackedBilevel(row, 0, alpha, pixels, destOffset, width);
163                            destOffset += width;
164                    }
165                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
166            }
167    
168            /**
169             * Creates an AWT Image object from a Gray16Image object and an alpha value.
170             * This is done by allocating a new int array with image.getWidth() times
171             * image.getHeight() elements, copying the data to those ints (using transparency
172             * information from the top eight bits of the alpha argument) and calling
173             * Toolkit.createImage with a MemoryImageSource of those int[] pixels.
174             * @param image the grayscale image to be converted
175             * @param alpha the alpha value, bits must only be set in the top eight bits
176             * @return AWT image created from the argument input image
177             */
178            public static Image convertToAwtImage(Gray16Image image, int alpha)
179            {
180                    if (image == null)
181                    {
182                            return null;
183                    }
184                    Toolkit toolkit = Toolkit.getDefaultToolkit();
185                    if (toolkit == null)
186                    {
187                            return null;
188                    }
189                    int width = image.getWidth();
190                    int height = image.getHeight();
191                    if (width < 1 || height < 1)
192                    {
193                            return null;
194                    }
195                    int[] pixels = new int[width * height];
196                    short[] gray = new short[width];
197                    int destOffset = 0;
198                    for (int y = 0; y < height; y++)
199                    {
200                            image.getShortSamples(0, 0, y, width, 1, gray, 0);
201                            RGBA.convertFromGray16(gray, 0, alpha, pixels, destOffset, width);
202                            destOffset += width;
203                    }
204                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
205            }
206    
207            /**
208             * Creates an AWT Image object from a Gray8Image object and an alpha value.
209             * This is done by allocating a new int array with image.getWidth() times
210             * image.getHeight() elements, copying the data to those ints (using transparency
211             * information from the top eight bits of the alpha argument) and calling
212             * Toolkit.createImage with a MemoryImageSource of those int[] pixels.
213             *
214             * @param image the grayscale image to be converted
215             * @param alpha the alpha value, bits must only be set in the top eight bits
216             * @return AWT image created from the argument input image
217             */
218            public static Image convertToAwtImage(Gray8Image image, int alpha)
219            {
220                    if (image == null)
221                    {
222                            return null;
223                    }
224                    Toolkit toolkit = Toolkit.getDefaultToolkit();
225                    if (toolkit == null)
226                    {
227                            return null;
228                    }
229                    int width = image.getWidth();
230                    int height = image.getHeight();
231                    if (width < 1 || height < 1)
232                    {
233                            return null;
234                    }
235                    int[] pixels = new int[width * height];
236                    byte[] gray = new byte[width];
237                    int destOffset = 0;
238                    for (int y = 0; y < height; y++)
239                    {
240                            image.getByteSamples(0, 0, y, width, 1, gray, 0);
241                            RGBA.convertFromGray8(gray, 0, alpha, pixels, destOffset, width);
242                            destOffset += width;
243                    }
244                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
245            }
246    
247            public static Image convertToAwtImage(Paletted8Image image, int alpha)
248            {
249                    if (image == null)
250                    {
251                            return null;
252                    }
253                    Toolkit toolkit = Toolkit.getDefaultToolkit();
254                    if (toolkit == null)
255                    {
256                            return null;
257                    }
258                    int width = image.getWidth();
259                    int height = image.getHeight();
260                    Palette palette = image.getPalette();
261                    if (width < 1 || height < 1 || palette == null)
262                    {
263                            return null;
264                    }
265                    int[] red = new int[palette.getNumEntries()];
266                    int[] green = new int[palette.getNumEntries()];
267                    int[] blue = new int[palette.getNumEntries()];
268                    for (int i = 0; i < palette.getNumEntries(); i++)
269                    {
270                            red[i] = palette.getSample(RGBIndex.INDEX_RED, i);
271                            green[i] = palette.getSample(RGBIndex.INDEX_GREEN, i);
272                            blue[i] = palette.getSample(RGBIndex.INDEX_BLUE, i);
273                    }
274                    int[] pixels = new int[width * height];
275                    byte[] data = new byte[width];
276                    int destOffset = 0;
277                    for (int y = 0; y < height; y++)
278                    {
279                            image.getByteSamples(0, 0, y, width, 1, data, 0);
280                            RGBA.convertFromPaletted8(data, 0, alpha, red, green, blue, pixels, destOffset, width);
281                            destOffset += width;
282                    }
283                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
284                    
285            }
286    
287            public static Image convertToAwtImage(RGB24Image image, int alpha)
288            {
289                    if (image == null)
290                    {
291                            return null;
292                    }
293                    Toolkit toolkit = Toolkit.getDefaultToolkit();
294                    if (toolkit == null)
295                    {
296                            return null;
297                    }
298                    int width = image.getWidth();
299                    int height = image.getHeight();
300                    if (width < 1 || height < 1)
301                    {
302                            return null;
303                    }
304                    int[] pixels = new int[width * height];
305                    byte[] red = new byte[width];
306                    byte[] green = new byte[width];
307                    byte[] blue = new byte[width];
308                    int destOffset = 0;
309                    for (int y = 0; y < height; y++)
310                    {
311                            image.getByteSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0);
312                            image.getByteSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0);
313                            image.getByteSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0);
314                            RGBA.convertFromRGB24(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width);
315                            destOffset += width;
316                    }
317                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
318                    
319            }
320    
321            public static Image convertToAwtImage(RGB48Image image, int alpha)
322            {
323                    if (image == null)
324                    {
325                            return null;
326                    }
327                    Toolkit toolkit = Toolkit.getDefaultToolkit();
328                    if (toolkit == null)
329                    {
330                            return null;
331                    }
332                    int width = image.getWidth();
333                    int height = image.getHeight();
334                    if (width < 1 || height < 1)
335                    {
336                            return null;
337                    }
338                    int[] pixels = new int[width * height];
339                    short[] red = new short[width];
340                    short[] green = new short[width];
341                    short[] blue = new short[width];
342                    int destOffset = 0;
343                    for (int y = 0; y < height; y++)
344                    {
345                            image.getShortSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0);
346                            image.getShortSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0);
347                            image.getShortSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0);
348                            RGBA.convertFromRGB48(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width);
349                            destOffset += width;
350                    }
351                    return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
352            }
353    
354            /**
355             * Creates an {@link RGB24Image} from the argument AWT image instance.
356             * @param image AWT image object to be converted to a {@link RGB24Image}
357             * @return a {@link RGB24Image} object holding the image data from the argument image
358             */
359            public static RGB24Image convertImageToRGB24Image(Image image)
360            {
361                    if (image == null)
362                    {
363                            return null;
364                    }
365                    int width = image.getWidth(null);
366                    int height = image.getHeight(null);
367                    if (width < 1 || height < 1)
368                    {
369                            return null;
370                    }
371                    int[] pixels = new int[width * height];
372                    PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
373                    try
374                    {
375                            pg.grabPixels();
376                    }
377                    catch (InterruptedException e)
378                    {
379                            return null;
380                    }
381                    if ((pg.getStatus() & ImageObserver.ABORT) != 0)
382                    {
383                            return null;
384                    }
385                    RGB24Image result = new MemoryRGB24Image(width, height);
386                    int offset = 0;
387                    for (int y = 0; y < height; y++)
388                    {
389                            for (int x = 0; x < width; x++)
390                            {
391                                    int pixel = pixels[offset++] & 0xffffff;
392                                    // TODO: store alpha value; requires some sort of 
393                                    // transparency channel data type yet to be implemented
394                                    result.putSample(RGBIndex.INDEX_RED, x, y, pixel >> 16);
395                                    result.putSample(RGBIndex.INDEX_GREEN, x, y, (pixel >> 8) & 0xff);
396                                    result.putSample(RGBIndex.INDEX_BLUE, x, y, pixel & 0xff);
397                            }
398                    }
399                    return result;
400            }
401    }