001/*
002 * $RCSfile: TIFFNullDecompressor.java,v $
003 *
004 * 
005 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
006 * 
007 * Redistribution and use in source and binary forms, with or without
008 * modification, are permitted provided that the following conditions
009 * are met: 
010 * 
011 * - Redistribution of source code must retain the above copyright 
012 *   notice, this  list of conditions and the following disclaimer.
013 * 
014 * - Redistribution in binary form must reproduce the above copyright
015 *   notice, this list of conditions and the following disclaimer in 
016 *   the documentation and/or other materials provided with the
017 *   distribution.
018 * 
019 * Neither the name of Sun Microsystems, Inc. or the names of 
020 * contributors may be used to endorse or promote products derived 
021 * from this software without specific prior written permission.
022 * 
023 * This software is provided "AS IS," without a warranty of any 
024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035 * POSSIBILITY OF SUCH DAMAGES. 
036 * 
037 * You acknowledge that this software is not designed or intended for 
038 * use in the design, construction, operation or maintenance of any 
039 * nuclear facility. 
040 *
041 * $Revision: 1.1 $
042 * $Date: 2005/02/11 05:01:48 $
043 * $State: Exp $
044 */
045package com.github.jaiimageio.impl.plugins.tiff;
046
047import java.io.IOException;
048
049import com.github.jaiimageio.plugins.tiff.TIFFDecompressor;
050
051public class TIFFNullDecompressor extends TIFFDecompressor {
052
053    private static final boolean DEBUG = false; // XXX false for release!
054
055    /**
056     * Whether to read the active source region only.
057     */
058    private boolean isReadActiveOnly = false;
059
060    /** The original value of <code>srcMinX</code>. */
061    private int originalSrcMinX;
062
063    /** The original value of <code>srcMinY</code>. */
064    private int originalSrcMinY;
065
066    /** The original value of <code>srcWidth</code>. */
067    private int originalSrcWidth;
068
069    /** The original value of <code>srcHeight</code>. */
070    private int originalSrcHeight;
071
072    public TIFFNullDecompressor() {}
073
074    //
075    // This approach to reading the active reading is a hack of sorts
076    // as the original values of the entire source region are stored,
077    // overwritten, and then restored. It would probably be better to
078    // revise TIFFDecompressor such that this were not necessary, i.e.,
079    // change beginDecoding() and decode() to use the active region values
080    // when random access is easy and the entire region values otherwise.
081    //
082    public void beginDecoding() {
083        // Determine number of bits per pixel.
084        int bitsPerPixel = 0;
085        for(int i = 0; i < bitsPerSample.length; i++) {
086            bitsPerPixel += bitsPerSample[i];
087        }
088
089        // Can read active region only if row starts on a byte boundary.
090        if((activeSrcMinX != srcMinX || activeSrcMinY != srcMinY ||
091            activeSrcWidth != srcWidth || activeSrcHeight != srcHeight) &&
092           ((activeSrcMinX - srcMinX)*bitsPerPixel) % 8 == 0) {
093            // Set flag.
094            isReadActiveOnly = true;
095
096            // Cache original region.
097            originalSrcMinX = srcMinX;
098            originalSrcMinY = srcMinY;
099            originalSrcWidth = srcWidth;
100            originalSrcHeight = srcHeight;
101
102            // Replace region with active region.
103            srcMinX = activeSrcMinX;
104            srcMinY = activeSrcMinY;
105            srcWidth = activeSrcWidth;
106            srcHeight = activeSrcHeight;
107        } else {
108            // Clear flag.
109            isReadActiveOnly = false;
110        }
111
112        if(DEBUG) {
113            if(isReadActiveOnly) {
114                System.out.println("Reading active region.");
115                System.out.println("source region: "+
116                                   new java.awt.Rectangle(originalSrcMinX,
117                                                          originalSrcMinY,
118                                                          originalSrcWidth,
119                                                          originalSrcHeight));
120                System.out.println("active region: "+
121                                   new java.awt.Rectangle(activeSrcMinX,
122                                                          activeSrcMinY,
123                                                          activeSrcWidth,
124                                                          activeSrcHeight));
125            } else {
126                System.out.println("Reading entire region.");
127                System.out.println("source region: "+
128                                   new java.awt.Rectangle(srcMinX,
129                                                          srcMinY,
130                                                          srcWidth,
131                                                          srcHeight));
132            }
133            System.out.println("destination region: "+
134                               new java.awt.Rectangle(dstMinX,
135                                                      dstMinY,
136                                                      dstWidth,
137                                                      dstHeight));
138        }
139
140        super.beginDecoding();
141    }
142
143    public void decode() throws IOException {
144        super.decode();
145
146        // Reset state.
147        if(isReadActiveOnly) {
148            // Restore original source region values.
149            srcMinX = originalSrcMinX;
150            srcMinY = originalSrcMinY;
151            srcWidth = originalSrcWidth;
152            srcHeight = originalSrcHeight;
153
154            // Unset flag.
155            isReadActiveOnly = false;
156        }
157    }
158
159    public void decodeRaw(byte[] b,
160                          int dstOffset,
161                          int bitsPerPixel,
162                          int scanlineStride) throws IOException {
163        if(isReadActiveOnly) {
164            // Read the active source region only.
165
166            int activeBytesPerRow = (activeSrcWidth*bitsPerPixel + 7)/8;
167            int totalBytesPerRow = (originalSrcWidth*bitsPerPixel + 7)/8;
168            int bytesToSkipPerRow = totalBytesPerRow - activeBytesPerRow;
169
170            //
171            // Seek to the start of the active region:
172            //
173            // active offset = original offset +
174            //                 number of bytes to start of first active row +
175            //                 number of bytes to first active pixel within row
176            //
177            // Since the condition for reading from the active region only is
178            //
179            //     ((activeSrcMinX - srcMinX)*bitsPerPixel) % 8 == 0
180            //
181            // the bit offset to the first active pixel within the first
182            // active row is a multiple of 8.
183            //
184            stream.seek(offset +
185                        (activeSrcMinY - originalSrcMinY)*totalBytesPerRow +
186                        ((activeSrcMinX - originalSrcMinX)*bitsPerPixel)/8);
187
188            int lastRow = activeSrcHeight - 1;
189            for (int y = 0; y < activeSrcHeight; y++) {
190                stream.read(b, dstOffset, activeBytesPerRow);
191                dstOffset += scanlineStride;
192
193                // Skip unneeded bytes (row suffix + row prefix).
194                if(y != lastRow) {
195                    stream.skipBytes(bytesToSkipPerRow);
196                }
197            }
198        } else {
199            // Read the entire source region.
200            stream.seek(offset);
201            int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
202            if(bytesPerRow == scanlineStride) {
203                stream.read(b, dstOffset, bytesPerRow*srcHeight);
204            } else {
205                for (int y = 0; y < srcHeight; y++) {
206                    stream.read(b, dstOffset, bytesPerRow);
207                    dstOffset += scanlineStride;
208                }
209            }
210        }
211    }
212}