jj2000.j2k.util.CodestreamManipulator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jai-imageio-jpeg2000 Show documentation
Show all versions of jai-imageio-jpeg2000 Show documentation
JPEG2000 support for Java Advanced Imaging Image I/O Tools API core.
This module is licensed under the [JJ2000 license](LICENSE.txt) and
is therefore NOT compatible with the GPL 3 license. It should be
compatible with the LGPL 2.1 license.
/*
* $RCSfile: CodestreamManipulator.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:24 $
* $State: Exp $
*
* Class: CodestreamManipulator
*
* Description: Manipulates codestream to create tile-parts etc
*
*
*
* 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.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import jj2000.j2k.codestream.Markers;
import jj2000.j2k.io.BEBufferedRandomAccessFile;
import jj2000.j2k.io.BufferedRandomAccessFile;
/**
* This class takes a legal JPEG 2000 codestream and performs some
* manipulation on it. Currently the manipulations supported are: Tile-parts
* */
public class CodestreamManipulator{
/** Flag indicating whether packed packet headers in main header is used
* */
private boolean ppmUsed;
/** Flag indicating whether packed packet headers in tile headers is used
* */
private boolean pptUsed;
/** Flag indicating whether SOP marker was only intended for parsing in
* This class and should be removed */
private boolean tempSop;
/** Flag indicating whether EPH marker was only intended for parsing in
* This class and should be removed */
private boolean tempEph;
/** The number of tiles in the image */
private int nt;
/** The number of packets per tile-part */
private int pptp;
/** The name of the outfile */
private File file;
/** The length of a SOT plus a SOD marker */
private static int TP_HEAD_LEN = 14;
/** The maximum number of a tile part index (TPsot) */
private static int MAX_TPSOT = 16;
/** The maximum number of tile parts in any tile */
private int maxtp;
/** The number of packets per tile */
private int[] ppt = new int[nt];
/** The positions of the SOT, SOP and EPH markers */
private Integer[] positions;
/** The main header */
private byte[] mainHeader;
/** Buffers containing the tile parts */
private byte[][][] tileParts;
/** Buffers containing the original tile headers */
private byte[][] tileHeaders;
/** Buffers contaning the packet headers */
private byte[][][] packetHeaders;
/** Buffers containing the packet data */
private byte[][][] packetData;
/** Buffers containing the SOP marker segments */
private byte[][][] sopMarkSeg;
/**
* Instantiates a codestream manipulator..
*
* @param outname The name of the original outfile
*
* @param nt The number of tiles in the image
*
* @param pptp Packets per tile-part. If zero, no division into tileparts
* is performed
*
* @param ppm Flag indicating that PPM marker is used
*
* @param ppt Flag indicating that PPT marker is used
*
* @param tempSop Flag indicating whether SOP merker should be removed
*
* @param tempEph Flag indicating whether EPH merker should be removed
* */
public CodestreamManipulator(File file, int nt, int pptp, boolean ppm,
boolean ppt, boolean tempSop,
boolean tempEph) {
this.file = file;
this.nt=nt;
this.pptp = pptp;
this.ppmUsed = ppm;
this.pptUsed = ppt;
this.tempSop = tempSop;
this.tempEph = tempEph;
}
/**
* This method performs the actual manipulation of the codestream which is
* the reparsing for tile parts and packed packet headers
*
* @return The number of bytes that the file has increased by
*
* @exception java.io.IOException If an I/O error ocurred.
* */
public int doCodestreamManipulation() throws IOException{
int addedHeaderBytes=0;
ppt = new int[nt];
tileParts = new byte[nt][][];
tileHeaders = new byte[nt][];
packetHeaders = new byte[nt][][];
packetData = new byte[nt][][];
sopMarkSeg = new byte[nt][][];
// If neither packed packet header nor tile parts are used, return 0
if( ppmUsed == false && pptUsed == false && pptp == 0)
return 0;
// Open file for reading and writing
BEBufferedRandomAccessFile fi =
new BEBufferedRandomAccessFile(file, "rw+");
addedHeaderBytes -= fi.length();
// Parse the codestream for SOT, SOP and EPH markers
parseAndFind(fi);
// Read and buffer the tile headers, packet headers and packet data
readAndBuffer(fi);
// Close file and overwrite with new file
fi.close();
fi = new BEBufferedRandomAccessFile(file, "rw");
// Create tile-parts
createTileParts();
// Write new codestream
writeNewCodestream(fi);
// Close file
fi.flush();
addedHeaderBytes += fi.length();
fi.close();
return addedHeaderBytes;
}
/**
* This method parses the codestream for SOT, SOP and EPH markers and
* removes header header bits signalling SOP and EPH markers if packed
* packet headers are used
*
* @param fi The file to parse the markers from
*
* @exception java.io.IOException If an I/O error ocurred.
* */
private void parseAndFind(BufferedRandomAccessFile fi) throws IOException{
int length,pos,i,t,sop=0,eph=0;
short marker;
int halfMarker;
int tileEnd;
Vector markPos = new Vector();
// Find position of first SOT marker
marker = (short)fi.readUnsignedShort(); // read SOC marker
marker = (short)fi.readUnsignedShort();
while(marker != Markers.SOT){
pos = fi.getPos();
length = fi.readUnsignedShort();
// If SOP and EPH markers were only used for parsing in this
// class remove SOP and EPH markers from Scod field
if(marker == Markers.COD){
int scod = fi.readUnsignedByte();
if(tempSop)
scod &= 0xfd; // Remove bits indicating SOP
if(tempEph)
scod &= 0xfb; // Remove bits indicating SOP
fi.seek(pos +2);
fi.write(scod);
}
fi.seek(pos + length);
marker = (short)fi.readUnsignedShort();
}
pos = fi.getPos();
fi.seek(pos-2);
// Find all packet headers, packed data and tile headers
for(t=0;tmaxtp) ? numTileParts:maxtp;
tileParts[t] = new byte[numTileParts][];
// Create all the tile parts for tile t
tppStart = 0;
pIndex = 0;
p=0;
phIndex = 0;
for(tilePart=0;tilePart prem) ? prem:pptp;
np = nomnp;
// Write tile part header
if(tilePart == 0){
// Write original tile part header up to SOD marker
temp.write(tileHeaders[t],0,
tileHeaders[t].length-2);
}else{
// Write empty header of length TP_HEAD_LEN-2
temp.write(new byte[TP_HEAD_LEN-2],0,TP_HEAD_LEN-2);
}
// Write PPT marker segments if PPT used
if(pptUsed){
int pptLength = 3; // Zppt and Lppt
int pptIndex = 0;
int phLength;
p = pIndex;
while(np > 0){
phLength = packetHeaders[t][p].length;
// If the total legth of the packet headers is greater
// than MAX_LPPT, several PPT markers are needed
if(pptLength + phLength > Markers.MAX_LPPT){
temp.write(Markers.PPT>>>8);
temp.write(Markers.PPT);
temp.write(pptLength>>>8);
temp.write(pptLength);
temp.write(pptIndex++);
for(i=pIndex; i < p ; i++){
temp.write(packetHeaders[t][i],0,
packetHeaders[t][i].length);
}
pptLength = 3; // Zppt and Lppt
pIndex = p;
}
pptLength += phLength;
p++;
np--;
}
// Write last PPT marker
temp.write(Markers.PPT>>>8);
temp.write(Markers.PPT);
temp.write(pptLength>>>8);
temp.write(pptLength);
temp.write(pptIndex);
for(i=pIndex; i < p ; i++){
temp.write(packetHeaders[t][i],0,
packetHeaders[t][i].length);
}
}
pIndex = p;
np = nomnp;
// Write SOD marker
temp.write(Markers.SOD>>>8);
temp.write(Markers.SOD);
// Write packet data and packet headers if PPT and PPM not used
for(p=tppStart; p>>24); // Psot
tempByteArr[7] = (byte)(length>>>16);
tempByteArr[8] = (byte)(length>>>8);
tempByteArr[9] = (byte)(length);
tempByteArr[10] = (byte)(0); // TPsot
tempByteArr[11] = (byte)(numTileParts); // TNsot
}else{
// Edit tile part header
tempByteArr[0] = (byte)(Markers.SOT>>>8); // SOT
tempByteArr[1] = (byte)(Markers.SOT);
tempByteArr[2] = (byte)(0); // Lsot
tempByteArr[3] = (byte)(10);
tempByteArr[4] = (byte)(t >> 8); // Lsot
tempByteArr[5] = (byte)(t); // Isot
tempByteArr[6] = (byte)(length>>>24); // Psot
tempByteArr[7] = (byte)(length>>>16);
tempByteArr[8] = (byte)(length>>>8);
tempByteArr[9] = (byte)(length);
tempByteArr[10] = (byte)(tilePart); //TPsot
tempByteArr[11] = (byte)(numTileParts); // TNsot
}
temp.reset();
prem -= np;
}
}
temp.close();
}
/**
* This method writes the new codestream to the file.
*
* @param fi The file to write the new codestream to
*
* @exception java.io.IOException If an I/O error ocurred.
* */
private void writeNewCodestream(BufferedRandomAccessFile fi)
throws IOException{
int i,t,p,tp;
int numTiles = tileParts.length;
int[][] packetHeaderLengths = new int[numTiles][maxtp];
byte[] temp;
int length;
// Write main header up to SOT marker
fi.write(mainHeader,0,mainHeader.length);
// If PPM used write all packet headers in PPM markers
if(ppmUsed){
ByteArrayOutputStream ppmMarkerSegment =
new ByteArrayOutputStream();
int numPackets;
int totNumPackets;
int ppmIndex=0;
int ppmLength;
int pStart,pStop;
int prem[] = new int[numTiles];
// Set number of remaining packets
for(t=0 ; t tp){
totNumPackets = packetHeaders[t].length;
// Calculate number of packets in this tilepart
numPackets =
(tp == tileParts[t].length-1) ?
prem[t] : pptp;
pStart = totNumPackets - prem[t];
pStop = pStart + numPackets;
// Calculate number of packet header bytes for this
// tile part
for(p=pStart ; p < pStop ; p++)
packetHeaderLengths[t][tp] +=
packetHeaders[t][p].length;
prem[t] -= numPackets;
}
}
}
// Write first PPM marker
ppmMarkerSegment.write(Markers.PPM >>> 8);
ppmMarkerSegment.write(Markers.PPM);
ppmMarkerSegment.write(0); // Temporary Lppm value
ppmMarkerSegment.write(0); // Temporary Lppm value
ppmMarkerSegment.write(0); // zppm
ppmLength = 3;
ppmIndex++;
// Set number of remaining packets
for(t=0 ; t tp){
totNumPackets = packetHeaders[t].length;
// Calculate number of packets in this tilepart
numPackets =
(tp == tileParts[t].length-1) ? prem[t] : pptp;
pStart = totNumPackets - prem[t];
pStop = pStart + numPackets;
// If Nppm value wont fit in current PPM marker segment
// write current PPM marker segment and start new
if(ppmLength + 4 > Markers.MAX_LPPM){
// Write current PPM marker
temp = ppmMarkerSegment.toByteArray();
length = temp.length-2;
temp[2] = (byte)(length >>> 8);
temp[3] = (byte)length;
fi.write(temp,0,length+2);
// Start new PPM marker segment
ppmMarkerSegment.reset();
ppmMarkerSegment.write(Markers.PPM >>> 8);
ppmMarkerSegment.write(Markers.PPM);
ppmMarkerSegment.write(0); // Temporary Lppm value
ppmMarkerSegment.write(0); // Temporary Lppm value
ppmMarkerSegment.write(ppmIndex++); // zppm
ppmLength = 3;
}
// Write Nppm value
length = packetHeaderLengths[t][tp];
ppmMarkerSegment.write(length>>>24);
ppmMarkerSegment.write(length>>>16);
ppmMarkerSegment.write(length>>>8);
ppmMarkerSegment.write(length);
ppmLength += 4;
// Write packet headers
for(p=pStart ; p < pStop ; p++){
length = packetHeaders[t][p].length;
// If next packet header value wont fit in
// current PPM marker segment write current PPM
// marker segment and start new
if(ppmLength + length > Markers.MAX_LPPM){
// Write current PPM marker
temp = ppmMarkerSegment.toByteArray();
length = temp.length-2;
temp[2] = (byte)(length >>> 8);
temp[3] = (byte)length;
fi.write(temp,0,length+2);
// Start new PPM marker segment
ppmMarkerSegment.reset();
ppmMarkerSegment.write(Markers.PPM >>> 8);
ppmMarkerSegment.write(Markers.PPM);
ppmMarkerSegment.write(0); // Temp Lppm value
ppmMarkerSegment.write(0); // Temp Lppm value
ppmMarkerSegment.write(ppmIndex++); // zppm
ppmLength = 3;
}
// write packet header
ppmMarkerSegment.write(packetHeaders[t][p],0,
packetHeaders[t][p].length);
ppmLength+=packetHeaders[t][p].length;
}
prem[t]-=numPackets;
}
}
}
// Write last PPM marker segment
temp = ppmMarkerSegment.toByteArray();
length = temp.length-2;
temp[2] = (byte)(length >>> 8);
temp[3] = (byte)length;
fi.write(temp,0,length+2);
}
// Write tile parts interleaved
for(tp=0;tp= tp){
temp = tileParts[t][tp];
length = temp.length;
fi.write(temp,0,length);
}
}
fi.writeShort(Markers.EOC);
}
}