Back to index

moin  1.9.0~rc2
ImageEncoder.java
Go to the documentation of this file.
00001 // ImageEncoder - abstract class for writing out an image
00002 // http://www.acme.com/java/software/Acme.JPM.Encoders.ImageEncoder.html
00003 //
00004 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions
00008 // are met:
00009 // 1. Redistributions of source code must retain the above copyright
00010 //    notice, this list of conditions and the following disclaimer.
00011 // 2. Redistributions in binary form must reproduce the above copyright
00012 //    notice, this list of conditions and the following disclaimer in the
00013 //    documentation and/or other materials provided with the distribution.
00014 //
00015 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00016 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00019 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00021 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00023 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00024 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00025 // SUCH DAMAGE.
00026 //
00027 // Visit the ACME Labs Java page for up-to-date versions of this and other
00028 // fine Java utilities: http://www.acme.com/java/
00029 
00030 package Acme.JPM.Encoders;
00031 
00032 import java.util.*;
00033 import java.io.*;
00034 import java.awt.Image;
00035 import java.awt.image.*;
00036 
00038 // <P>
00039 // A framework for classes that encode and write out an image in
00040 // a particular file format.
00041 // <P>
00042 // This provides a simplified rendition of the ImageConsumer interface.
00043 // It always delivers the pixels as ints in the RGBdefault color model.
00044 // It always provides them in top-down left-right order.
00045 // If you want more flexibility you can always implement ImageConsumer
00046 // directly.
00047 // <P>
00048 // <A HREF="/resources/classes/Acme/JPM/Encoders/ImageEncoder.java">Fetch the software.</A><BR>
00049 // <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
00050 // <P>
00051 // @see GifEncoder
00052 // @see PpmEncoder
00053 // @see Acme.JPM.Decoders.ImageDecoder
00054 
00055 public abstract class ImageEncoder implements ImageConsumer
00056     {
00057 
00058     protected OutputStream out;
00059 
00060     private ImageProducer producer;
00061     private int width = -1;
00062     private int height = -1;
00063     private int hintflags = 0;
00064     private boolean started = false;
00065     private boolean encoding;
00066     private IOException iox;
00067     private static final ColorModel rgbModel = ColorModel.getRGBdefault();
00068     private Hashtable props = null;
00069 
00071     // @param img The image to encode.
00072     // @param out The stream to write the bytes to.
00073     public ImageEncoder( Image img, OutputStream out ) throws IOException
00074        {
00075        this( img.getSource(), out );
00076        }
00077 
00079     // @param producer The ImageProducer to encode.
00080     // @param out The stream to write the bytes to.
00081     public ImageEncoder( ImageProducer producer, OutputStream out ) throws IOException
00082        {
00083        this.producer = producer;
00084        this.out = out;
00085        }
00086 
00087 
00088     // Methods that subclasses implement.
00089 
00091     abstract void encodeStart( int w, int h ) throws IOException;
00092 
00094     // are guaranteed to be delivered in top-down-left-right order.
00095     // One int per pixel, index is row * scansize + off + col,
00096     // RGBdefault (AARRGGBB) color model.
00097     abstract void encodePixels(
00098        int x, int y, int w, int h, int[] rgbPixels, int off, int scansize )
00099        throws IOException;
00100 
00102     abstract void encodeDone() throws IOException;
00103 
00104 
00105     // Our own methods.
00106 
00108     public synchronized void encode() throws IOException
00109        {
00110        encoding = true;
00111        iox = null;
00112        producer.startProduction( this );
00113        while ( encoding )
00114            try
00115               {
00116               wait();
00117               }
00118            catch ( InterruptedException e ) {}
00119        if ( iox != null )
00120            throw iox;
00121        }
00122 
00123     private boolean accumulate = false;
00124     private int[] accumulator;
00125 
00126     private void encodePixelsWrapper(
00127        int x, int y, int w, int h, int[] rgbPixels, int off, int scansize )
00128        throws IOException
00129        {
00130        if ( ! started )
00131            {
00132            started = true;
00133            encodeStart( width, height );
00134            if ( ( hintflags & TOPDOWNLEFTRIGHT ) == 0 )
00135               {
00136               accumulate = true;
00137               accumulator = new int[width * height];
00138               }
00139            }
00140        if ( accumulate )
00141            for ( int row = 0; row < h; ++row )
00142               System.arraycopy(
00143                   rgbPixels, row * scansize + off,
00144                   accumulator, ( y + row ) * width + x,
00145                   w );
00146        else
00147            encodePixels( x, y, w, h, rgbPixels, off, scansize );
00148        }
00149 
00150     private void encodeFinish() throws IOException
00151        {
00152        if ( accumulate )
00153            {
00154            encodePixels( 0, 0, width, height, accumulator, 0, width );
00155            accumulator = null;
00156            accumulate = false;
00157            }
00158        }
00159 
00160     private synchronized void stop()
00161        {
00162        encoding = false;
00163        notifyAll();
00164        }
00165 
00166 
00167     // Methods from ImageConsumer.
00168 
00169     public void setDimensions( int width, int height )
00170        {
00171        this.width = width;
00172        this.height = height;
00173        }
00174 
00175     public void setProperties( Hashtable props )
00176        {
00177        this.props = props;
00178        }
00179 
00180     public void setColorModel( ColorModel model )
00181        {
00182        // Ignore.
00183        }
00184 
00185     public void setHints( int hintflags )
00186        {
00187        this.hintflags = hintflags;
00188        }
00189 
00190     public void setPixels(
00191        int x, int y, int w, int h, ColorModel model, byte[] pixels,
00192        int off, int scansize )
00193        {
00194        int[] rgbPixels = new int[w];
00195        for ( int row = 0; row < h; ++row )
00196            {
00197            int rowOff = off + row * scansize;
00198            for ( int col = 0; col < w; ++col )
00199               rgbPixels[col] = model.getRGB( pixels[rowOff + col] & 0xff );
00200            try
00201               {
00202               encodePixelsWrapper( x, y + row, w, 1, rgbPixels, 0, w );
00203               }
00204            catch ( IOException e )
00205               {
00206               iox = e;
00207               stop();
00208               return;
00209               }
00210            }
00211        }
00212 
00213     public void setPixels(
00214        int x, int y, int w, int h, ColorModel model, int[] pixels,
00215        int off, int scansize )
00216        {
00217        if ( model == rgbModel )
00218            {
00219            try
00220               {
00221               encodePixelsWrapper( x, y, w, h, pixels, off, scansize );
00222               }
00223            catch ( IOException e )
00224               {
00225               iox = e;
00226               stop();
00227               return;
00228               }
00229            }
00230        else
00231            {
00232            int[] rgbPixels = new int[w];
00233             for ( int row = 0; row < h; ++row )
00234               {
00235               int rowOff = off + row * scansize;
00236                 for ( int col = 0; col < w; ++col )
00237                     rgbPixels[col] = model.getRGB( pixels[rowOff + col] );
00238               try
00239                   {
00240                   encodePixelsWrapper( x, y + row, w, 1, rgbPixels, 0, w );
00241                   }
00242               catch ( IOException e )
00243                   {
00244                   iox = e;
00245                   stop();
00246                   return;
00247                   }
00248               }
00249            }
00250        }
00251 
00252     public void imageComplete( int status )
00253        {
00254        producer.removeConsumer( this );
00255        if ( status == ImageConsumer.IMAGEABORTED )
00256            iox = new IOException( "image aborted" );
00257        else
00258            {
00259            try
00260               {
00261               encodeFinish();
00262               encodeDone();
00263               }
00264            catch ( IOException e )
00265               {
00266               iox = e;
00267               }
00268            }
00269        stop();
00270        }
00271 
00272     }