/Users/lyon/j4p/src/ip/JPM/Encoders/ImageEncoder.java
|
1 // ImageEncoder - abstract class for writing out an image
2 //
3 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 // SUCH DAMAGE.
25 //
26 // Visit the ACME Labs Java page for up-to-date versions of this and other
27 // fine Java utilities: http://www.acme.com/java/
28
29 package ip.JPM.Encoders;
30
31 import java.awt.Image;
32 import java.awt.image.ColorModel;
33 import java.awt.image.ImageConsumer;
34 import java.awt.image.ImageProducer;
35 import java.io.IOException;
36 import java.io.OutputStream;
37 import java.util.Hashtable;
38
39 /// Abstract class for writing out an image.
40 // <P>
41 // A framework for classes that encode and write out an image in
42 // a particular file format.
43 // <P>
44 // This provides a simplified rendition of the ImageConsumer interface.
45 // It always delivers the pixels as ints in the RGBdefault color model.
46 // It always provides them in top-down left-right order.
47 // If you want more flexibility you can always implement ImageConsumer
48 // directly.
49 // <P>
50 // <A HREF="/resources/classes/Acme/JPM/Encoders/ImageEncoder.java">Fetch the software.</A><BR>
51 // <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
52 // <P>
53 // @see GifEncoder
54 // @see PpmEncoder
55 // @see Acme.JPM.Decoders.ImageDecoder
56
57 public abstract class ImageEncoder
58 implements ImageConsumer {
59
60 protected OutputStream out;
61
62 private ImageProducer producer;
63 private int width = -1;
64 private int height = -1;
65 private int hintflags = 0;
66 private boolean started = false;
67 private boolean encoding;
68 private IOException iox;
69 private static final ColorModel rgbModel = ColorModel.getRGBdefault();
70 private Hashtable props = null;
71
72 /// Constructor.
73 // @param img The image to encode.
74 // @param out The stream to write the bytes to.
75 public ImageEncoder(Image img,
76 OutputStream out)
77 throws IOException {
78 this(img.getSource(), out);
79 }
80
81 /// Constructor.
82 // @param producer The ImageProducer to encode.
83 // @param out The stream to write the bytes to.
84 public ImageEncoder(ImageProducer producer,
85 OutputStream out)
86 throws IOException {
87 this.producer = producer;
88 this.out = out;
89 }
90
91
92 // Methods that subclasses implement.
93
94 /// Subclasses implement this to initialize an encoding.
95 abstract void encodeStart(int w, int h)
96 throws IOException;
97
98 /// Subclasses implement this to actually write out some bits. They
99 // are guaranteed to be delivered in top-down-left-right order.
100 // One int per pixel, index is row * scansize + off + col,
101 // RGBdefault (AARRGGBB) color model.
102 abstract void encodePixels(int x,
103 int y,
104 int w,
105 int h,
106 int[] rgbPixels,
107 int off,
108 int scansize)
109 throws IOException;
110
111 /// Subclasses implement this to finish an encoding.
112 abstract void encodeDone()
113 throws IOException;
114
115
116 // Our own methods.
117
118 /// Call this after initialization to get things going.
119 public synchronized void encode()
120 throws IOException {
121 encoding = true;
122 iox = null;
123 producer.startProduction(this);
124 while (encoding)
125 try {
126 wait();
127 } catch (InterruptedException e) {
128 }
129 if (iox != null)
130 throw iox;
131 }
132
133 private boolean accumulate = false;
134 private int[] accumulator;
135
136 private void encodePixelsWrapper(int x,
137 int y,
138 int w,
139 int h,
140 int[] rgbPixels,
141 int off,
142 int scansize)
143 throws IOException {
144 if (!started) {
145 started = true;
146 encodeStart(width, height);
147 if ((hintflags & TOPDOWNLEFTRIGHT) ==
148 0) {
149 accumulate = true;
150 accumulator =
151 new int[width * height];
152 }
153 }
154 if (accumulate)
155 for (int row = 0; row < h; ++row)
156 System.arraycopy(rgbPixels, row *
157 scansize +
158 off,
159 accumulator, (y +
160 row) *
161 width +
162 x,
163 w);
164 else
165 encodePixels(x,
166 y,
167 w,
168 h,
169 rgbPixels,
170 off,
171 scansize);
172 }
173
174 private void encodeFinish()
175 throws IOException {
176 if (accumulate) {
177 encodePixels(0,
178 0,
179 width,
180 height,
181 accumulator,
182 0,
183 width);
184 accumulator = null;
185 accumulate = false;
186 }
187 }
188
189 private synchronized void stop() {
190 encoding = false;
191 notifyAll();
192 }
193
194
195 // Methods from ImageConsumer.
196
197 public void setDimensions(int width,
198 int height) {
199 this.width = width;
200 this.height = height;
201 }
202
203 public void setProperties(Hashtable props) {
204 this.props = props;
205 }
206
207 public void setColorModel(ColorModel model) {
208 // Ignore.
209 }
210
211 public void setHints(int hintflags) {
212 this.hintflags = hintflags;
213 }
214
215 public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels,
216 int off, int scansize) {
217 int[] rgbPixels = new int[w];
218 for (int row = 0; row < h; ++row) {
219 int rowOff = off + row * scansize;
220 for (int col = 0; col < w; ++col)
221 rgbPixels[col] =
222 model.getRGB(
223 pixels[rowOff + col] &
224 0xff);
225 try {
226 encodePixelsWrapper(x,
227 y + row,
228 w,
229 1,
230 rgbPixels,
231 0,
232 w);
233 } catch (IOException e) {
234 iox = e;
235 stop();
236 return;
237 }
238 }
239 }
240
241 public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels,
242 int off, int scansize) {
243 if (model == rgbModel) {
244 try {
245 encodePixelsWrapper(x,
246 y,
247 w,
248 h,
249 pixels,
250 off,
251 scansize);
252 } catch (IOException e) {
253 iox = e;
254 stop();
255 return;
256 }
257 } else {
258 int[] rgbPixels = new int[w];
259 for (int row = 0; row < h; ++row) {
260 int rowOff = off +
261 row * scansize;
262 for (int col = 0; col < w; ++col)
263 rgbPixels[col] =
264 model.getRGB(
265 pixels[rowOff + col]);
266 try {
267 encodePixelsWrapper(x,
268 y + row,
269 w,
270 1,
271 rgbPixels,
272 0,
273 w);
274 } catch (IOException e) {
275 iox = e;
276 stop();
277 return;
278 }
279 }
280 }
281 }
282
283 public void imageComplete(int status) {
284 producer.removeConsumer(this);
285 if (status == ImageConsumer.IMAGEABORTED)
286 iox =
287 new IOException("image aborted");
288 else {
289 try {
290 encodeFinish();
291 encodeDone();
292 } catch (IOException e) {
293 iox = e;
294 }
295 }
296 stop();
297 }
298
299 }
300