View Javadoc

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