1 package com.atlassian.core.util.thumbnail;
2
3 import java.awt.Transparency;
4 import java.awt.image.BufferedImage;
5 import java.awt.image.ColorModel;
6 import java.awt.image.ImageConsumer;
7 import java.awt.image.WritableRaster;
8 import java.util.Hashtable;
9
10 public class SimpleImageConsumer implements ImageConsumer
11 {
12 private final Object holder;
13
14 private ColorModel colorModel;
15 private WritableRaster raster;
16 private int width;
17 private int height;
18
19 private BufferedImage image;
20 private int[] intBuffer;
21 private volatile boolean loadComplete;
22
23 public SimpleImageConsumer()
24 {
25 holder = new Object();
26 width = -1;
27 height = -1;
28 loadComplete = false;
29 }
30
31 public void imageComplete(int status)
32 {
33 synchronized(holder)
34 {
35 loadComplete = true;
36 holder.notify();
37 }
38 }
39
40 public void setColorModel(ColorModel model)
41 {
42 colorModel = model;
43 createImage();
44 }
45
46 /**
47 * Notification of the dimensions of the source image.
48 *
49 * @param w The width of the source image
50 * @param h The height of the source image
51 */
52 public void setDimensions(int w, int h)
53 {
54 width = w;
55 height = h;
56 createImage();
57 }
58
59 /**
60 * Notification of load hints that may be useful. Not used in this
61 * implementation.
62 *
63 * @param flags The hints
64 */
65 public void setHints(int flags)
66 {
67 }
68
69 /**
70 * Notification of a bunch of pixel values in byte form. Used for
71 * 256 color or less images (eg GIF, greyscale etc).
72 *
73 * @param x The starting x position of the pixels
74 * @param y The starting y position of the pixels
75 * @param w The number of pixels in the width
76 * @param h The number of pixels in the height
77 * @param model The color model used with these pixel values
78 * @param offset The offset into the source array to copy from
79 * @param scansize The number of pixel values between rows
80 */
81 public void setPixels(int x,
82 int y,
83 int w,
84 int h,
85 ColorModel model,
86 byte[] pixels,
87 int offset,
88 int scansize)
89 {
90 if((intBuffer == null) || (pixels.length > intBuffer.length))
91 intBuffer = new int[pixels.length];
92
93 for(int i = pixels.length; --i >= 0 ; )
94 intBuffer[i] = (int)pixels[i] & 0xFF;
95
96 raster.setPixels(x, y, w, h, intBuffer);
97 }
98
99 /**
100 * Notification of a bunch of pixel values as ints. These will be
101 * full 3 or 4 component images.
102 *
103 * @param x The starting x position of the pixels
104 * @param y The starting y position of the pixels
105 * @param w The number of pixels in the width
106 * @param h The number of pixels in the height
107 * @param model The color model used with these pixel values
108 * @param offset The offset into the source array to copy from
109 * @param scansize The number of pixel values between rows
110 */
111 public void setPixels(int x,
112 int y,
113 int w,
114 int h,
115 ColorModel model,
116 int[] pixels,
117 int offset,
118 int scansize)
119 {
120 image.setRGB(x, y, w, h, pixels, offset, scansize);
121 }
122
123 /**
124 * Notification of the properties of the image to use. Not used in this implementation.
125 *
126 * @param props The map of properties for this image
127 */
128 public void setProperties(Hashtable props)
129 {
130 createImage();
131 }
132
133 //------------------------------------------------------------------------
134 // Local methods
135 //------------------------------------------------------------------------
136
137 /**
138 * Fetch the image. This image is not necessarily completely rendered
139 * although we do try to guarantee it.
140 *
141 * Torsten Römer: Changed to public
142 *
143 * @return The image that has been created for the current input
144 */
145 public BufferedImage getImage()
146 {
147 if(!loadComplete)
148 {
149 synchronized(holder)
150 {
151 try
152 {
153 holder.wait();
154 }
155 catch(InterruptedException ie)
156 {
157 }
158 }
159 }
160
161 return image;
162 }
163
164 /**
165 * Convenience method used to create the output image based on the data
166 * that has been given to us so far. Will not create the image until all
167 * the necessary information is given, and once created, will not overwrite
168 * the current image.
169 *
170 * Torsten Römer: Use another constructor of BufferedImage. With the one used
171 * here the resulting jpg was extremely blueish.
172 */
173 private void createImage()
174 {
175 // meet the preconditions first.
176 if((image != null) ||
177 (width == -1) ||
178 (colorModel == null))
179 return;
180
181 boolean hasAlpha = colorModel.hasAlpha() || colorModel.getTransparency() != Transparency.OPAQUE;
182 image = new BufferedImage(width, height, hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
183 }
184 }