package uk.co.mmscomputing.imageio.sff; import java.io.*; import java.awt.*; import java.awt.image.*; import javax.imageio.*; import javax.imageio.spi.*; import javax.imageio.stream.*; import javax.imageio.metadata.*; import uk.co.mmscomputing.io.*; import uk.co.mmscomputing.image.operators.*; public class SFFImageWriter extends ImageWriter{ /* Assume bilevel image (black/white,BufferedImage.TYPE_BYTE_BINARY,one bit per pixel) Start of sequence: Write sff header Each image: count run length encode into modified huffman codes encode into sff file format save to byte array End of Sequence: write sff end write to image file */ private RLEBit1OutputStream rlos; private ModHuffmanOutputStream mhos; private SFFOutputStream sffos; private ByteArrayOutputStream baos; protected SFFImageWriter(ImageWriterSpi originatingProvider){ super(originatingProvider); } public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param){ return null; } public IIOMetadata convertStreamMetadata(IIOMetadata inData,ImageWriteParam param){ return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType,ImageWriteParam param){ return null; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param){ return null; } public ImageWriteParam getDefaultWriteParam(){ return new ImageWriteParam(getLocale()); } public boolean canInsertImage(int imageIndex)throws IOException{ return (imageIndex==0); // use sequence for more than one picture } public void write(IIOMetadata streamMetadata,IIOImage img,ImageWriteParam param)throws IOException{ prepareWriteSequence(streamMetadata); writeToSequence(img,param); // just one page ! endWriteSequence(); } public boolean canWriteSequence(){ return true; } public void prepareWriteSequence(IIOMetadata streamMetadata)throws IOException{ baos = new ByteArrayOutputStream(); sffos= new SFFOutputStream(baos); mhos = new ModHuffmanOutputStream(sffos); rlos = new RLEBit1OutputStream(mhos); } public void writeToSequence(IIOImage img,ImageWriteParam param)throws IOException{ if(!(img.getRenderedImage() instanceof BufferedImage)){ throw new IOException(getClass().getName()+"writeToSequence: Can only write BufferedImage objects"); } BufferedImage image =(BufferedImage)img.getRenderedImage(); ColorModel cm =image.getColorModel(); if((image.getType()!=BufferedImage.TYPE_BYTE_BINARY)||(cm.getPixelSize()!=1)){ throw new IOException(getClass().getName()+"writeToSequence:\n\tPlease convert image to black and white picture [TYPE_BYTE_BINARY,1 bps]"); } try{ int width =image.getWidth(); sffos.writePageHeader(width); // start sff encoding writeBinaryImage(image,width); sffos.writePageEnd(); }catch(Exception e){ e.printStackTrace(); throw new IOException(getClass().getName()+".writeToSequence:\n\tCouldn't write data to SFF File."+e.getMessage()); } } private void writeBinaryImage(BufferedImage image,int width)throws IOException{ WritableRaster raster=image.getRaster(); DataBufferByte buffer=(DataBufferByte)raster.getDataBuffer(); byte[] imgdata=(byte[])buffer.getData(); int height=image.getHeight(); int len=width/8; // eight pixel per byte int end=7-(width%8); // how many bits of last byte represent image data int off=0; if(end==7){ // image row ends at byte boundary for(int y=0;y<height;y++){ rlos.setStartCodeWord(0x0001); // white run first rlos.write(imgdata,off,len); rlos.flush(); // write padding after every image row mhos.writeEOL(); // signal SFFOutputStream new line off+=len; } }else{ for(int y=0;y<height;y++){ rlos.setStartCodeWord(0x0001); // white run first rlos.write(imgdata,off,len); rlos.writeBits(imgdata[off+len],7,end); // write end of line pixel rlos.flush(); // write padding after every image row mhos.writeEOL(); // signal SFFOutputStream new line off+=len+1; } } } public void endWriteSequence()throws IOException{ sffos.writeDocumentEnd(); ((ImageOutputStream)getOutput()).write(baos.toByteArray()); } }