jj2000.j2k.codestream.writer.BitOutputBuffer Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: BitOutputBuffer.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:02 $
* $State: Exp $
*
* Class: BitOutputBuffer
*
* Description:
*
*
*
* COPYRIGHT:
*
* This software module was originally developed by Raphaël Grosbois and
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
* Centre France S.A) in the course of development of the JPEG2000
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
* software module is an implementation of a part of the JPEG 2000
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
* Partners) agree not to assert against ISO/IEC and users of the JPEG
* 2000 Standard (Users) any of their rights under the copyright, not
* including other intellectual property rights, for this software module
* with respect to the usage by ISO/IEC and Users of this software module
* or modifications thereof for use in hardware or software products
* claiming conformance to the JPEG 2000 Standard. Those intending to use
* this software module in hardware or software products are advised that
* their use may infringe existing patents. The original developers of
* this software module, JJ2000 Partners and ISO/IEC assume no liability
* for use of this software module or modifications thereof. No license
* or right to this software module is granted for non JPEG 2000 Standard
* conforming products. JJ2000 Partners have full right to use this
* software module for his/her own purpose, assign or donate this
* software module to any third party and to inhibit third parties from
* using this software module for non JPEG 2000 Standard conforming
* products. This copyright notice must be included in all copies or
* derivative works of this software module.
*
* Copyright (c) 1999/2000 JJ2000 Partners.
* */
package jj2000.j2k.codestream.writer;
import jj2000.j2k.util.ArrayUtil;
/**
* This class implements a buffer for writing bits, with the required bit
* stuffing policy for the packet headers. The bits are stored in a byte array
* in the order in which they are written. The byte array is automatically
* reallocated and enlarged whenever necessary. A BitOutputBuffer object may
* be reused by calling its 'reset()' method.
*
* NOTE: The methods implemented in this class are intended to be used only
* in writing packet heads, since a special bit stuffing procedure is used, as
* required for the packet heads.
* */
public class BitOutputBuffer {
/** The buffer where we store the data */
byte buf[];
/** The position of the current byte to write */
int curbyte;
/** The number of available bits in the current byte */
int avbits = 8;
/** The increment size for the buffer, 16 bytes. This is the
* number of bytes that are added to the buffer each time it is
* needed to enlarge it.*/
// This must be always 6 or larger.
public final static int SZ_INCR = 16;
/** The initial size for the buffer, 32 bytes. */
public final static int SZ_INIT = 32;
/**
* Creates a new BitOutputBuffer width a buffer of length
* 'SZ_INIT'.
* */
public BitOutputBuffer() {
buf = new byte[SZ_INIT];
}
/**
* Resets the buffer. This rewinds the current position to the start of
* the buffer and sets all tha data to 0. Note that no new buffer is
* allocated, so this will affect any data that was returned by the
* 'getBuffer()' method.
* */
public void reset() {
int i;
// Reinit pointers
curbyte = 0;
avbits = 8;
ArrayUtil.byteArraySet(buf,(byte)0);
}
/**
* Writes a bit to the buffer at the current position. The value 'bit'
* must be either 0 or 1, otherwise it corrupts the bits that have been
* already written. The buffer is enlarged, by 'SZ_INCR' bytes, if
* necessary.
*
*
This method is declared final to increase performance.
*
* @param bit The bit to write, 0 or 1.
* */
public final void writeBit(int bit) {
buf[curbyte] |= bit << --avbits;
if (avbits > 0) {
// There is still place in current byte for next bit
return;
}
else { // End of current byte => goto next
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
avbits = 8;
}
else { // We need to stuff a bit (next MSBit is 0)
avbits = 7;
}
curbyte++;
if (curbyte == buf.length) {
// We are at end of 'buf' => extend it
byte oldbuf[] = buf;
buf = new byte[oldbuf.length+SZ_INCR];
System.arraycopy(oldbuf,0,buf,0,oldbuf.length);
}
}
}
/**
* Writes the n least significant bits of 'bits' to the buffer at the
* current position. The least significant bit is written last. The 32-n
* most significant bits of 'bits' must be 0, otherwise corruption of the
* buffer will result. The buffer is enlarged, by 'SZ_INCR' bytes, if
* necessary.
*
*
This method is declared final to increase performance.
*
* @param bits The bits to write.
*
* @param n The number of LSBs in 'bits' to write.
* */
public final void writeBits(int bits, int n) {
// Check that we have enough place in 'buf' for n bits, and that we do
// not fill last byte, taking into account possibly stuffed bits (max
// 2)
if (((buf.length-curbyte)<<3)-8+avbits <= n+2) {
// Not enough place, extend it
byte oldbuf[] = buf;
buf = new byte[oldbuf.length+SZ_INCR];
System.arraycopy(oldbuf,0,buf,0,oldbuf.length);
// SZ_INCR is always 6 or more, so it is enough to hold all the
// new bits plus the ones to come after
}
// Now write the bits
if (n >= avbits) {
// Complete the current byte
n -= avbits;
buf[curbyte] |= bits >> n;
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
avbits = 8;
}
else { // We need to stuff a bit (next MSBit is 0)
avbits = 7;
}
curbyte++;
// Write whole bytes
while (n >= avbits) {
n -= avbits;
buf[curbyte] |= (bits >> n) & (~(1 << avbits));
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit
// stuffing
avbits = 8;
}
else { // We need to stuff a bit (next MSBit is 0)
avbits = 7;
}
curbyte++;
}
}
// Finish last byte (we know that now n < avbits)
if (n > 0) {
avbits -= n;
buf[curbyte] |= (bits & ((1<This method is declared final to increase performance.
*
* @return The currebt length of the buffer in bytes.
* */
public final int getLength() {
if (avbits == 8) { // A integral number of bytes
return curbyte;
}
else { // Some bits in last byte
return curbyte+1;
}
}
/**
* Returns the byte buffer. This is the internal byte buffer so it should
* not be modified. Only the first N elements have valid data, where N is
* the value returned by 'getLength()'
*
* This method is declared final to increase performance.
*
* @return The internal byte buffer.
* */
public final byte[] getBuffer() {
return buf;
}
/**
* Returns the byte buffer data in a new array. This is a copy of the
* internal byte buffer. If 'data' is non-null it is used to return the
* data. This array should be large enough to contain all the data,
* otherwise a IndexOutOfBoundsException is thrown by the Java system. The
* number of elements returned is what 'getLength()' returns.
*
* @param data If non-null this array is used to return the data, which
* mus be large enough. Otherwise a new one is created and returned.
*
* @return The byte buffer data.
* */
public byte[] toByteArray(byte data[]) {
if (data == null) {
data = new byte[(avbits==8)?curbyte:curbyte+1];
}
System.arraycopy(buf,0,data,0,(avbits==8)?curbyte:curbyte+1);
return data;
}
/**
* Prints information about this object for debugging purposes
*
* @return Information about the object.
* */
public String toString() {
return "bits written = "+(curbyte*8+(8-avbits))+
", curbyte = "+curbyte+", avbits = "+avbits;
}
}