package uk.co.mmscomputing.imageio.jpeg; import java.io.*; public class JPEGOutputStream extends OutputStream implements JPEGConstants{ private int spp=0; private int qtprecision=0; // 8 bit private JPEGBitOutputStream out; private JPEGDCTOutputStream[] dcts; private JPEGComponentsOutputStream cout; public JPEGOutputStream(OutputStream out)throws IOException{ this.out=new JPEGBitOutputStream(out); startOfImage(); } protected int[][] qts = new int[4][]; // available quantization tables protected JPEGHuffmanOutputStream[] dcouts = new JPEGHuffmanOutputStream[4]; protected JPEGHuffmanOutputStream[] acouts = new JPEGHuffmanOutputStream[4]; public void setZZQuantizationTable(int index,int[] qt){ qts[index]=qt; } public void setZZQuantizationTable(int index,int[] qt,int quality){ if((0<quality)&&(quality<=100)){ int[] t=new int[64]; System.arraycopy(qt,0,t,0,64); for(int i=0;i<64;i++){ t[i]=(t[i]*25)/quality; // System.out.println("qt["+i+"]="+t[i]); } setZZQuantizationTable(index,t); }else{ throw new IllegalArgumentException(getClass().getName()+".setZZQuantizationTable:\n\tParameter quality out of range ["+quality+"]"); } } public void setRawDCHuffmanTable(int index,byte[] table)throws IOException{ dcouts[index]=new JPEGHuffmanOutputStream(out,new ByteArrayInputStream(table)); } public void setRawACHuffmanTable(int index,byte[] table)throws IOException{ acouts[index]=new JPEGHuffmanOutputStream(out,new ByteArrayInputStream(table)); } public void startOfFrame(int height,int width,int[] HV,int[] Q)throws IOException{ // 0xC0 out.write(0xFF);out.write(0xC0); spp=HV.length; int len=8+spp*3; out.write((len>>8)&0x00FF); out.write(len&0x00FF); out.write(8); // 8 bits per sample out.write((height>>8)&0x00FF); out.write(height&0x00FF); out.write((width>>8)&0x00FF); out.write(width&0x00FF); out.write(spp); // samples per pixel dcts=new JPEGDCTOutputStream[spp]; for(int i=0;i<spp;i++){ out.write(i+1); out.write(HV[i]); // (Hi<<4)|Vi out.write(Q[i]); dcts[i]=new JPEGDCTOutputStream(qts[Q[i]]); } cout=new JPEGComponentsOutputStream(dcts,HV,width); } public void defineHuffmanTables()throws IOException{ // 0xC4 out.write(0xFF);out.write(0xC4); int len=2; for(int n=0;n<dcouts.length;n++){ if(dcouts[n]!=null){ len+=dcouts[n].getTableDataLength()+1; } if(acouts[n]!=null){ len+=acouts[n].getTableDataLength()+1; } } out.write((len>>8)&0x00FF); out.write(len&0x00FF); for(int n=0;n<dcouts.length;n++){ if(dcouts[n]!=null){ out.write(n); dcouts[n].writeTableData(out); } } for(int n=0;n<acouts.length;n++){ if(acouts[n]!=null){ out.write((1<<4)|n); acouts[n].writeTableData(out); } } } public void startOfImage()throws IOException{ // 0xD8 out.write(0xFF);out.write(0xD8); } public void endOfImage()throws IOException{ // 0xD9 out.write(0xFF);out.write(0xD9); } public void defineQuantizationTables()throws IOException{ // 0xDB out.write(0xFF);out.write(0xDB); int len=2; for(int n=0;n<qts.length;n++){ if(qts[n]!=null){len+=65;} } out.write((len>>8)&0x00FF); out.write(len&0x00FF); int[] qt; for(int n=0;n<qts.length;n++){ // max 4 tables qt=qts[n]; if(qt!=null){ out.write((qtprecision<<4)|n); // 8 bit for(int i=0;i<64;i++){out.write(qt[i]);} // are in zigzag scan order [1]p.40 } } } public void startOfScan(int[] sel)throws IOException{ // 0xDA out.write(0xFF);out.write(0xDA); spp=sel.length; int len=6+spp*2; out.write((len>>8)&0x00FF); out.write(len&0x00FF); out.write(spp); for(int i=0;i<spp;i++){ out.write(i+1); // component id out.write(sel[i]); // dc<<4|ac int dci=(sel[i]>>4)&0x0F; int aci= sel[i] &0x0F; dcts[i].setHuffmanOutputStreams(dcouts[dci],acouts[aci]); } out.write(0); // ss out.write(63); // se out.write(0); // ah,al } public void write(int b)throws IOException{ cout.write(b); } public void flush()throws IOException{ if(cout!=null){cout.flush();} out.flush(); } public void close()throws IOException{ flush(); endOfImage(); out.close(); } }