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