All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.jaiimageio.stream.FileChannelImageInputStream Maven / Gradle / Ivy

Go to download

Java Advanced Imaging Image I/O Tools API core, but without the classes involved with javax.media.jai dependencies, JPEG2000 or codecLibJIIO, meaning that this library can be distributed under the modified BSD license and should be GPL compatible.

The newest version!
/*
 * $RCSfile: FileChannelImageInputStream.java,v $
 *
 * 
 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 * 
 * - Redistribution of source code must retain the above copyright 
 *   notice, this  list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of 
 * contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any 
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. 
 * 
 * You acknowledge that this software is not designed or intended for 
 * use in the design, construction, operation or maintenance of any 
 * nuclear facility. 
 *
 * $Revision: 1.2 $
 * $Date: 2007/09/14 22:57:55 $
 * $State: Exp $
 */
package com.github.jaiimageio.stream;

import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.MappedByteBuffer;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;

import javax.imageio.stream.ImageInputStreamImpl;

/**
 * A class which implements ImageInputStream using a
 * FileChannel as the eventual data source. The channel
 * contents are assumed to be stable during the lifetime of the object.
 *
 * 

Memory mapping and new I/O view Buffers are used to * read the data. Only methods which provide significant performance * improvement with respect to the superclass implementation are overridden. * Overridden methods are not commented individually unless some noteworthy * aspect of the implementation must be described.

* *

The methods of this class are not synchronized.

* * @see javax.imageio.stream.ImageInputStream * @see java.nio * @see java.nio.channels.FileChannel */ public class FileChannelImageInputStream extends ImageInputStreamImpl { /** The FileChannel data source. */ private FileChannel channel; /** A memory mapping of all or part of the channel. */ private MappedByteBuffer mappedBuffer; /** The stream position of the mapping. */ private long mappedPos; /** The stream position least upper bound of the mapping. */ private long mappedUpperBound; /** * Constructs a FileChannelImageInputStream from a * FileChannel. The initial position of the stream * stream is taken to be the position of the FileChannel * parameter when this constructor is invoked. The stream and flushed * positions are therefore both initialized to * channel.position(). * * @param channel the source FileChannel. * * @throws IllegalArgumentException if channel is * null or is not open. * @throws IOException if a method invoked on channel * throws an IOException. */ public FileChannelImageInputStream(FileChannel channel) throws IOException { // Check the parameter. if(channel == null) { throw new IllegalArgumentException("channel == null"); } else if(!channel.isOpen()) { throw new IllegalArgumentException("channel.isOpen() == false"); } // Save the channel reference. this.channel = channel; // Get the channel position. long channelPosition = channel.position(); // Set stream and flushed positions to initial channel position. this.streamPos = this.flushedPos = channelPosition; // Determine the size of the mapping. long fullSize = channel.size() - channelPosition; long mappedSize = Math.min(fullSize, Integer.MAX_VALUE); // Set the mapped position and upper bound. this.mappedPos = 0; this.mappedUpperBound = mappedPos + mappedSize; // Map the file. this.mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY, channelPosition, mappedSize); } /** * Returns a MappedByteBuffer which memory maps * at least from the channel position corresponding to the * current stream position to len bytes beyond. * A new buffer is created only if necessary. * * @param len The number of bytes required beyond the current stream * position. */ private MappedByteBuffer getMappedBuffer(int len) throws IOException { // If request is outside mapped region, map a new region. if(streamPos < mappedPos || streamPos + len >= mappedUpperBound) { // Set the map position. mappedPos = streamPos; // Determine the map size. long mappedSize = Math.min(channel.size() - mappedPos, Integer.MAX_VALUE); // Set the mapped upper bound. mappedUpperBound = mappedPos + mappedSize; // Map the file. mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY, mappedPos, mappedSize); mappedBuffer.order(super.getByteOrder()); } return mappedBuffer; } // --- Implementation of superclass abstract methods. --- public int read() throws IOException { checkClosed(); bitOffset = 0; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(1); // Check number of bytes left. if(byteBuffer.remaining() < 1) { // Return EOF. return -1; } // Get the byte from the buffer. int value = byteBuffer.get()&0xff; // Increment the stream position. streamPos++; //System.out.println("value = "+value); return value; } public int read(byte[] b, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > b.length) { // NullPointerException will be thrown before this if b is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > b.length"); } else if(len == 0) { return 0; } checkClosed(); bitOffset = 0; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(len); // Get the number of bytes remaining. int numBytesRemaining = byteBuffer.remaining(); // Check number of bytes left. if(numBytesRemaining < 1) { // Return EOF. return -1; } else if(len > numBytesRemaining) { // Clamp 'len' to number of bytes in Buffer. Apparently some // readers (JPEG) request data beyond the end of the file. len = numBytesRemaining; } // Read the data from the buffer. byteBuffer.get(b, off, len); // Increment the stream position. streamPos += len; return len; } // --- Overriding of superclass methods. --- /** * Invokes the superclass method and sets the internal reference * to the source FileChannel to null. * The source FileChannel is not closed. * * @exception IOException if an error occurs. */ public void close() throws IOException { super.close(); channel = null; } public void readFully(char[] c, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > c.length) { // NullPointerException will be thrown before this if c is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > c.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 2*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. CharBuffer viewBuffer = byteBuffer.asCharBuffer(); // Get the chars. viewBuffer.get(c, off, len); // Update the position. seek(streamPos + byteLen); } public void readFully(short[] s, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > s.length) { // NullPointerException will be thrown before this if s is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > s.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 2*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. ShortBuffer viewBuffer = byteBuffer.asShortBuffer(); // Get the shorts. viewBuffer.get(s, off, len); // Update the position. seek(streamPos + byteLen); } public void readFully(int[] i, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > i.length) { // NullPointerException will be thrown before this if i is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > i.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 4*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. IntBuffer viewBuffer = byteBuffer.asIntBuffer(); // Get the ints. viewBuffer.get(i, off, len); // Update the position. seek(streamPos + byteLen); } public void readFully(long[] l, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > l.length) { // NullPointerException will be thrown before this if l is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > l.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 8*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. LongBuffer viewBuffer = byteBuffer.asLongBuffer(); // Get the longs. viewBuffer.get(l, off, len); // Update the position. seek(streamPos + byteLen); } public void readFully(float[] f, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > f.length) { // NullPointerException will be thrown before this if f is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > f.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 4*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. FloatBuffer viewBuffer = byteBuffer.asFloatBuffer(); // Get the floats. viewBuffer.get(f, off, len); // Update the position. seek(streamPos + byteLen); } public void readFully(double[] d, int off, int len) throws IOException { if(off < 0 || len < 0 || off + len > d.length) { // NullPointerException will be thrown before this if d is null. throw new IndexOutOfBoundsException ("off < 0 || len < 0 || off + len > d.length"); } else if(len == 0) { return; } // Determine the requested length in bytes. int byteLen = 8*len; // Get the mapped buffer. ByteBuffer byteBuffer = getMappedBuffer(byteLen); // Ensure enough bytes remain. if(byteBuffer.remaining() < byteLen) { throw new EOFException(); } // Get the view Buffer. DoubleBuffer viewBuffer = byteBuffer.asDoubleBuffer(); // Get the doubles. viewBuffer.get(d, off, len); // Update the position. seek(streamPos + byteLen); } /** * Returns the number of bytes currently in the FileChannel. * If an IOException is encountered when querying the * channel's size, -1L will be returned. * * @return The number of bytes in the channel * -1L to indicate unknown length. */ public long length() { // Initialize to value indicating unknown length. long length = -1L; // Set length to current size with respect to initial position. try { length = channel.size(); } catch(IOException e) { // Default to unknown length. } return length; } /** * Invokes the superclass method and sets the position within the * memory mapped buffer. A new region is mapped if necessary. The * position of the source FileChannel is not changed, i.e., * {@link java.nio.channels.FileChannel#position(long)} is not invoked. */ public void seek(long pos) throws IOException { super.seek(pos); if(pos >= mappedPos && pos < mappedUpperBound) { // Seeking to location within mapped buffer: set buffer position. mappedBuffer.position((int)(pos - mappedPos)); } else { // Seeking to location outside mapped buffer: get a new mapped // buffer at current position with maximal size. int len = (int)Math.min(channel.size() - pos, Integer.MAX_VALUE); mappedBuffer = getMappedBuffer(len); } } public void setByteOrder(ByteOrder networkByteOrder) { super.setByteOrder(networkByteOrder); mappedBuffer.order(networkByteOrder); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy