package uk.co.mmscomputing.imageio.tiff; import java.io.*; import java.util.*; import java.nio.ByteOrder; import javax.imageio.stream.*; import uk.co.mmscomputing.math.Rational; abstract class DE implements TIFFConstants{ // ImageFileDirectoryEntry private int tag; protected int type; protected long len; protected long val; DE(int tagid)throws IOException{ tag=tagid; } int getTag(){return tag;} int getType(){return type;} void setType(int type){this.type=type;} long getCount(){return (int)len;} void setCount(long count){this.len=count;} long getLength(){return (int)len;} void setLength(long len){this.len=len;} long getValue(){return val;} void setValue(long value){val=value;} void read(ImageInputStream in)throws IOException{ type=in.readUnsignedShort(); len=in.readUnsignedInt(); // count of items of tag type to follow val=readValue(in); // System.out.println(getClass().getName()+"\n\t Tag = "+tag+" Type = "+type+" Len = "+len+" Val = 0x"+Long.toHexString(val)+" Val = "+val); } private long readValue(ImageInputStream in)throws IOException{ long val=0; int sot=sizeOfType(); if(len*sot<=4){ val=in.readUnsignedInt(); if(in.getByteOrder()==ByteOrder.BIG_ENDIAN){ long v; switch(type){ case BYTE: case SBYTE: v = val &0x000000FF; val =(val>>24)&0x000000FF; val|=(v <<24)&0xFF000000; v = val &0x0000FF00; val|=(val>> 8)&0x0000FF00; val|=(v << 8)&0x00FF0000; break; case SHORT: case SSHORT: v = val &0x0000FFFF; val =(val>>16)&0x0000FFFF; val|=(v <<16)&0xFFFF0000; break; } } }else{ val=in.readUnsignedInt(); } return val; } void writeEntry(ImageOutputStream out) throws IOException { out.writeShort(tag); out.writeShort(type); out.writeInt((int)len); out.writeInt((int)val); } protected int sizeOfType(){ switch(type){ case BYTE: case SBYTE: case UNDEFINED: return 1; case SHORT: case SSHORT: return 2; case LONG: case SLONG: case FLOAT: return 4; case RATIONAL: case SRATIONAL: case DOUBLE: return 8; default:/*error*/return -1; } } protected long readInt(ImageInputStream in)throws IOException{ switch(type){ case BYTE: return in.readUnsignedByte(); case SHORT: return in.readUnsignedShort(); case LONG: return in.readUnsignedInt(); case SBYTE: return in.read(); case SSHORT: return in.readShort(); case SLONG: return in.readInt(); default:/*error*/return 0; } } protected void writeInt(ImageOutputStream out,long val)throws IOException{ switch(type){ case BYTE: out.writeByte((byte)val);break; case SHORT: out.writeShort((short)val);break; case LONG: out.writeInt((int)val);break; case SBYTE: out.write((byte)val);break; case SSHORT: out.writeShort((short)val);break; case SLONG: out.writeInt((int)val);break; default:/*error*/break; } } protected String[] readString(ImageInputStream in)throws IOException{ if(type!=ASCII){/*error*/return null;} in.mark(); in.seek(val); Vector v=new Vector(); int i=0; while(i<len){ String s=""; int b=in.read();i++; while((b!=0)&&(i<len)){ s+=(char)b; b=in.read();i++; } v.add(s); // System.out.println("S : "+s); } in.reset(); String[] sa=new String[v.size()]; for(int j=0;j<sa.length;j++){ sa[j]=(String)v.get(j); } return sa; } protected byte[] readByteArray(ImageInputStream in)throws IOException{ if(type!=UNDEFINED){/*error*/return null;} byte[] data=new byte[(int)len]; if(len<=4){ // todo System.out.println("9\b"+getClass().getName()+".readByteArray:\n\tCannot read byte array len<=4 yet."); }else{ in.mark(); in.seek(val); in.read(data); in.reset(); } return data; } private double read1Real(ImageInputStream in)throws IOException{ switch(type){ case RATIONAL: return new Rational((int)in.readUnsignedInt(),(int)in.readUnsignedInt()).doubleValue(); case SRATIONAL: return new Rational(in.readInt(),in.readInt()).doubleValue(); case FLOAT: return in.readFloat(); case DOUBLE: return in.readDouble(); default:/*error*/return 0; } } protected double readReal(ImageInputStream in)throws IOException{ if(type==FLOAT){ return read1Real(in); }else{ in.mark(); in.seek(val); double real=read1Real(in); in.reset(); // System.out.println("real = "+real); return real; } } protected void write1Real(ImageOutputStream out,double value)throws IOException{ switch(type){ case RATIONAL: Rational ur=new Rational(value); out.writeInt(ur.getNumerator()); out.writeInt(ur.getDenominator()); break; case SRATIONAL: Rational sr=new Rational(value); out.writeInt(sr.getNumerator()); out.writeInt(sr.getDenominator()); break; case FLOAT: val=Float.floatToIntBits((float)value); break; case DOUBLE: out.writeDouble(value); break; default:/*error*/return; } } protected void writeReal(ImageOutputStream out,double value)throws IOException{ switch(type){ case RATIONAL: val=out.getStreamPosition(); // address to rational Rational ur=new Rational(value); out.writeInt(ur.getNumerator()); out.writeInt(ur.getDenominator()); break; case SRATIONAL: val=out.getStreamPosition(); // address to rational Rational sr=new Rational(value); out.writeInt(sr.getNumerator()); out.writeInt(sr.getDenominator()); break; case FLOAT: val=Float.floatToIntBits((float)value); // size of float is 4 byte, hence we can save this in idf entry break; case DOUBLE: val=out.getStreamPosition(); // address to double out.writeDouble(value); break; default:/*error*/return; } } protected long[] readIntArray(ImageInputStream in)throws IOException{ long[] array=new long[(int)len]; int sot=sizeOfType(); if(len*sot<=4){ int shift=0; switch(sot){ case 1: for(int i=0;i<len;i++){ array[i]=(val>>shift)&0x000000FF;shift+=8; // System.out.println("["+i+"]= 0x"+Long.toHexString(array[i])); } break; case 2: for(int i=0;i<len;i++){ array[i]=(val>>shift)&0x0000FFFF;shift+=16; // System.out.println("["+i+"]= 0x"+Long.toHexString(array[i])); } break; case 4: array[0]=val; // System.out.println("[0]= 0x"+Long.toHexString(array[0])); break; } }else{ in.mark(); in.seek(val); for(int i=0;i<len;i++){ array[i]=readInt(in); // System.out.println("["+i+"]= 0x"+Long.toHexString(array[i])); } in.reset(); } return array; } protected void writeIntArray(ImageOutputStream out,long[] array)throws IOException{ int sot=sizeOfType(); if(len*sot<=4){ int shift=0; switch(sot){ case 1: val=0; for(int i=0;i<len;i++){ val|=(array[i]&0x000000FF)<<shift;shift+=8; } break; case 2: val=0; for(int i=0;i<len;i++){ val|=(array[i]&0x0000FFFF)<<shift;shift+=16; } break; case 4: val=array[0]; break; } }else{ val=out.getStreamPosition(); for(int i=0;i<len;i++){ writeInt(out,array[i]); } } } protected double[] readRealArray(ImageInputStream in)throws IOException{ double[] array=new double[(int)len]; int sot=sizeOfType(); if(len*sot<=4){ array[0]=Float.intBitsToFloat((int)val); }else{ in.mark(); in.seek(val); for(int i=0;i<len;i++){ array[i]=read1Real(in); // System.out.println("["+i+"]= "+array[i]); } in.reset(); } return array; } protected void writeRealArray(ImageOutputStream out,double[] array)throws IOException{ int sot=sizeOfType(); if(len*sot<=4){ write1Real(out,array[0]); }else{ val=out.getStreamPosition(); for(int i=0;i<len;i++){ write1Real(out,array[i]); } } } protected void writeByteArray(ImageOutputStream out,byte[] array)throws IOException{ int sot=sizeOfType(); if(sot!=1){throw new IOException(getClass().getName()+".writeByteArray:\n\tInternal error: size of type != 1.");} if(len<=4){ val=0;int shift=0; for(int i=0;i<len;i++){ val|=(array[i]&0x000000FF)<<shift;shift+=8; } }else{ val=out.getStreamPosition(); out.write(array,0,(int)len); if((len&0x01)==0x01){out.write(0);} // word align } } void write(ImageOutputStream out) throws IOException { // don't need to write anything } } // Adobe TIFF6.PDF