package uk.co.mmscomputing.imageio.sff;
import java.io.*;
import java.util.*;
import java.awt.image.*;
import javax.imageio.*;
import javax.imageio.spi.*;
import javax.imageio.stream.*;
import javax.imageio.metadata.*;
import uk.co.mmscomputing.io.*;
public class SFFImageReader extends ImageReader{
static private class IFD{
int width=0;
int height=0;
byte[] data=null;
}
private Vector ifds = null;
protected SFFImageReader(ImageReaderSpi originatingProvider){
super(originatingProvider);
}
public BufferedImage read(int imageIndex, ImageReadParam param)throws IOException{
readIFDs();
checkIndex(imageIndex);
return readImage((IFD)ifds.elementAt(imageIndex));
}
public int getHeight(int imageIndex)throws IOException{
readIFDs();
checkIndex(imageIndex);
return ((IFD)ifds.elementAt(imageIndex)).height;
}
public int getWidth(int imageIndex)throws IOException{
readIFDs();
checkIndex(imageIndex);
return ((IFD)ifds.elementAt(imageIndex)).width;
}
public Iterator getImageTypes(int imageIndex)throws IOException{
readIFDs();
checkIndex(imageIndex);
ImageTypeSpecifier imageType = null;
java.util.List l = new ArrayList();
imageType=ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_BINARY);
l.add(imageType);
return l.iterator();
}
public int getNumImages(boolean allowSearch)throws IOException{
readIFDs();
return ifds.size();
}
public IIOMetadata getImageMetadata(int imageIndex)throws IOException{
readIFDs();
checkIndex(imageIndex);
return null;
}
public IIOMetadata getStreamMetadata() throws IOException{
return null;
}
private void checkIndex(int imageIndex) {
if (imageIndex >= ifds.size()) {
throw new IndexOutOfBoundsException(getClass().getName()+".checkIndex:\n\tBad index in sff image reader");
}
}
private byte[] readImageData()throws IOException{ // read whole sff stream into memory
ImageInputStream iis=(ImageInputStream)getInput();
int len=(int)iis.length();
byte[] data;
if(len==-1){ // don't know length yet
ByteArrayOutputStream baos=new ByteArrayOutputStream();
data=new byte[1<<13];
while((len=iis.read(data))!=-1){
baos.write(data,0,len);
}
data=baos.toByteArray();
}else{
data=new byte[len];
iis.readFully(data,0,len);
}
return data;
}
private IFD readIFD(SFFInputStream in)throws IOException{
try{
/*
1. get page data (modified huffman)
evaluate height
*/
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] data=new byte[2048<<2];int len;
while(!in.isEndOfPage()&&(len=in.read(data))!=-1){ // read modified Huffman codes of page
baos.write(data,0,len);
}
IFD ifd=new IFD();
ifd.width =in.getWidth();
ifd.height =in.getHeight();
ifd.data =baos.toByteArray();
return ifd;
}catch(Exception e){
e.printStackTrace();
throw new IOException(getClass().getName()+".readIFD:\n\t"+e.getMessage());
}
}
private void readIFDs()throws IOException{
if(ifds==null){
ifds=new Vector();
byte[] data=readImageData();
SFFInputStream sffis = new SFFInputStream(new ByteArrayInputStream(data));
while(sffis.hasImage()){
ifds.add(readIFD(sffis));
}
}
}
/*
private BufferedImage readImage(IFD ifd)throws IOException{
try{
// 2. evaluate runlength
// convert into runs
// copy to image buffer
ByteArrayInputStream bais=new ByteArrayInputStream(ifd.data);
ModHuffmanInputStream mhis=new ModHuffmanInputStream(bais);
RLEInputStream rlis=new RLEInputStream(mhis);
BufferedImage image=new BufferedImage(ifd.width,ifd.height,BufferedImage.TYPE_BYTE_GRAY);
WritableRaster raster=image.getRaster();
DataBufferByte buffer=(DataBufferByte)raster.getDataBuffer();
byte[] imgdata=(byte[])buffer.getData();
byte[] buf=new byte[ifd.width];int off=0,len=0;
while(true){
try{
len=rlis.read(buf); // read one image line
if(len==-1){break;} // end of page
System.arraycopy(buf,0,imgdata,off,len); // copy line to image buffer
}catch(ModHuffmanInputStream.ModHuffmanCodingException mhce){
System.err.println(getClass().getName()+".readImage\n\t"+mhce.getMessage());
}
mhis.syncWithEOL(); // skip to eol synchronization bytes
rlis.resetToStartCodeWord(); // start next line with white
off+=ifd.width;
}
return image;
}catch(Exception e){
e.printStackTrace();
throw new IOException(getClass().getName()+".readImage:\n\t"+e.getMessage());
}
}
*/
private BufferedImage readImage(IFD ifd)throws IOException{
try{
// 2. evaluate runlength
// convert into runs
// copy to image buffer
ByteArrayInputStream bais=new ByteArrayInputStream(ifd.data);
ModHuffmanInputStream mhis=new ModHuffmanInputStream(bais);
RLEBitInputStream rlis=new RLEBitInputStream(mhis);
BufferedImage image=new BufferedImage(ifd.width,ifd.height,BufferedImage.TYPE_BYTE_BINARY);
WritableRaster raster=image.getRaster();
DataBufferByte buffer=(DataBufferByte)raster.getDataBuffer();
byte[] imgdata=(byte[])buffer.getData();
if((ifd.width%8)==0){
byte[] buf=new byte[ifd.width>>3];int off=0,len=0;
while(true){
try{
len=rlis.read(buf); // read one image line
if(len==-1){break;} // end of page
System.arraycopy(buf,0,imgdata,off,len); // copy line to image buffer
}catch(ModHuffmanInputStream.ModHuffmanCodingException mhce){
System.err.println(getClass().getName()+".readImage\n\t"+mhce.getMessage());
}
mhis.syncWithEOL(); // skip to eol synchronization bytes
rlis.resetToStartCodeWord(); // start next line with white
off+=len;
}
return image;
}else{
byte[] buf=new byte[(ifd.width+7)>>3];int off=0,len=0,ecw=8-(ifd.width&0x0007),bits;
while(true){
try{
len=rlis.read(buf,0,buf.length-1); // read one image line
if(len==-1){break;} // end of page
bits=rlis.readBits(7,ecw);
buf[len]=(byte)bits;
System.arraycopy(buf,0,imgdata,off,len+1); // copy line to image buffer
}catch(ModHuffmanInputStream.ModHuffmanCodingException mhce){
System.err.println(getClass().getName()+".readImage\n\t"+mhce.getMessage());
}
mhis.syncWithEOL(); // skip to eol synchronization bytes
rlis.resetToStartCodeWord(); // start next line with white
off+=len+1;
}
return image;
}
}catch(Exception e){
e.printStackTrace();
throw new IOException(getClass().getName()+".readImage:\n\t"+e.getMessage());
}
}
}