001    /*
002     * TIFFDecoderLogLuv
003     *
004     * Copyright (c) 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.codecs.tiff;
009    
010    import java.io.DataInput;
011    import java.io.IOException;
012    import net.sourceforge.jiu.codecs.tiff.TIFFConstants;
013    import net.sourceforge.jiu.codecs.tiff.TIFFDecoder;
014    import net.sourceforge.jiu.codecs.InvalidFileStructureException;
015    import net.sourceforge.jiu.ops.MissingParameterException;
016    
017    /**
018     * A TIFF decoder for files compressed with the <em>LogLuv RLE</em> method.
019     * This compression algorithm has the value <code>34676</code> 
020     * ({@link TIFFConstants#COMPRESSION_SGI_LOG_RLE})
021     * in the compression tag of an image file directory.
022     * Only image data with a photometric interpretation value of 
023     * {@link TIFFConstants#PHOTOMETRIC_TRUECOLOR_LOGLUV} can be compressed with this method.
024     * <p>
025     * This implementation is based on the file <code>tif_luv.c</code> which
026     * is part of the TIFF library <a target="_top" href="http://www.libtiff.org">libtiff</a>.
027     * The original implementation was written by Greg W. Larson.
028     * <p>
029     * Learn more about the color type and its encoding on Greg's page
030     * <a target="_top" href="http://positron.cs.berkeley.edu/~gwlarson/pixformat/tiffluv.html">LogLuv 
031     * Encoding for TIFF Images</a>.
032     * You will also find numerous sample image files there.
033     * @author Marco Schmidt
034     * @since 0.10.0
035     */
036    public class TIFFDecoderLogLuv extends TIFFDecoder
037    {
038            private DataInput in;
039            private int compressedSize;
040            private int tileWidth;
041            private boolean rle;
042    
043            public void decode() throws 
044                    InvalidFileStructureException,
045                    IOException
046            {
047                    byte[] row = new byte[getBytesPerRow()];
048                    rle = getImageFileDirectory().getCompression() == TIFFConstants.COMPRESSION_SGI_LOG_RLE;
049                    for (int y = getY1(); y <= getY2(); y++)
050                    {
051                            decodeRow(row);
052                            putBytes(row, 0, row.length);
053                    }
054            }
055    
056            private void decodeRow(byte[] row) throws
057                    InvalidFileStructureException,
058                    IOException
059            {
060                    if (rle)
061                    {
062                            decodeRowRLE(row);
063                    }
064                    else
065                    {
066                            decodeRowPacked24(row);
067                    }
068            }
069    
070            private void decodeRowPacked24(byte[] row) throws 
071                    InvalidFileStructureException,
072                    IOException
073            {
074                    int num = getImageFileDirectory().getTileWidth() * 3;
075                    in.readFully(row, 0, num);
076            }
077    
078            private void decodeRowRLE(byte[] row) throws 
079                    InvalidFileStructureException,
080                    IOException
081            {
082                    final int BYTES_PER_PIXEL;
083                    if (getImageFileDirectory().getPhotometricInterpretation() == TIFFConstants.PHOTOMETRIC_LOGL)
084                    {
085                            BYTES_PER_PIXEL = 2; // LogL
086                    }
087                    else
088                    {
089                            BYTES_PER_PIXEL = 4; // LogLuv
090                    }
091                    for (int initialOffset = 0; initialOffset < BYTES_PER_PIXEL; initialOffset++)
092                    {
093                            int offset = initialOffset;
094                            int numPixels = tileWidth;
095                            do
096                            {
097                                    int v1 = in.readUnsignedByte();
098                                    if ((v1 & 128) != 0)
099                                    {
100                                            // run
101                                            int runCount = v1 + (2 - 128);
102                                            numPixels -= runCount;
103                                            compressedSize -= 2;
104                                            byte v2 = in.readByte();
105                                            while (runCount-- != 0)
106                                            {
107                                                    row[offset] = v2;
108                                                    offset += BYTES_PER_PIXEL;
109                                            }
110                                    }
111                                    else
112                                    {
113                                            // non-run, copy data
114                                            int runCount = v1;
115                                            numPixels -= runCount;
116                                            compressedSize = compressedSize - runCount - 1;
117                                            while (runCount-- != 0)
118                                            {
119                                                    row[offset] = in.readByte();
120                                                    offset += BYTES_PER_PIXEL;
121                                            }
122                                    }
123                                    if (compressedSize < 0)
124                                    {
125                                            throw new InvalidFileStructureException("Ran out of compressed input bytes before completing the decoding process.");
126                                    }
127                            }
128                            while (numPixels > 0);
129                    }
130            }
131    
132            public Integer[] getCompressionTypes()
133            {
134                    return new Integer[] {new Integer(TIFFConstants.COMPRESSION_SGI_LOG_RLE), new Integer(TIFFConstants.COMPRESSION_SGI_LOG_24_PACKED)};
135            }
136    
137            public void initialize() throws
138                    IOException, 
139                    MissingParameterException
140            {
141                    super.initialize();
142                    in = getInput();
143                    compressedSize = getImageFileDirectory().getByteCount(getTileIndex());
144                    tileWidth = getImageFileDirectory().getTileWidth();
145            }       
146    }