package ch.werner_randelshofer.gui.image;/*Copyright (C) 1999 Werner Randelshoferwerner.randelshofer@mythen.chhttp://www.mythen.ch/w.randelshofer/    Permission to use this release of ANIMDeltaFrame is herebygranted without fee provided that the complete copyrightnotice and this permission notice appear in all copiesand in supporting documentation.*/import java.awt.image.ColorModel;import java.awt.image.IndexColorModel;import java.awt.image.DirectColorModel;import java.util.Hashtable;/** * @author	Werner Randelshofer, Staldenmattweg 2, CH-6405 Immensee, Switzerland * @version	1999-02-14	Created. */public class ANIMDeltaFrameextends ANIMFrame	{	private ColorModel colorModel_;	private byte[] data_;	private int leftBound_,topBound_,rightBound_,bottomBound_;	private final static int		DECODER_BYTE_VERTICAL = 5,		DECODER_VERTICAL_7_SHORT = 6,		DECODER_VERTICAL_7_LONG = 7,		DECODER_VERTICAL_8_SHORT = 8,		DECODER_VERTICAL_8_LONG = 9;	private final static int		OP_Direct = 0,		OP_XOR = 1,		OP_LongDelta = 2,		OP_ShortDelta = 3,		OP_GeneralDelta = 4,		OP_ByteVertical = 5,		OP_StereoDelta = 6,		OP_Vertical7 = 7,		OP_Vertical8 = 8,		OP_J = 74;	public ANIMDeltaFrame()		{		}	public void setColorModel(ColorModel cm) { colorModel_ = cm; }	public void setData(byte[] data) { data_ = data; }	public ColorModel getColorModel() { return colorModel_; }		private int getDecoder()		{		switch	(getOperation())			{			case OP_Direct : // Key Frame (Data stored in ILBM BODY Chunk)				throw new InternalError("Key Frames not yet supported (Anim Op0)");			case OP_ByteVertical :				if ((getBits() & BadBitsOP_ByteVertical) != 0)					{ throw new InternalError("Unknown Bits fŸr Anim Op5 in ANHD; Bits:" + getBits()); }				return DECODER_BYTE_VERTICAL;			case OP_Vertical7 :				if ((getBits() & BIT_LongData) == 0)					{ return DECODER_VERTICAL_7_SHORT; }				else					{ return DECODER_VERTICAL_7_LONG; }			case OP_Vertical8 :				if ((getBits() & BIT_LongData) == 0)					{ return DECODER_VERTICAL_8_SHORT; }				else					{ return DECODER_VERTICAL_8_LONG; }			default :				throw new InternalError("ANIM Op" + getOperation() + " not supported.");			}		}		public void decode(Bitmap bitmap, ANIMMovieTrack track)		{		switch (getDecoder())			{			case DECODER_BYTE_VERTICAL :				decodeByteVertical(bitmap,track);				break;			case DECODER_VERTICAL_7_SHORT :				decodeVertical7Short(bitmap,track);				break;			case DECODER_VERTICAL_7_LONG :				decodeVertical7Long(bitmap,track);				break;			case DECODER_VERTICAL_8_SHORT :				decodeVertical8Short(bitmap,track);				break;			case DECODER_VERTICAL_8_LONG :				decodeVertical8Long(bitmap,track);				break;			default :								throw new InternalError("Unsupported decoder.");			}		}	private void decodeByteVertical(Bitmap bitmap, ANIMMovieTrack track) 		{		int columns = 0;		int iOp = 0;		byte[] planeBytes = bitmap.getBitmap();		int iPl = 0;		int widthInBytes = bitmap.getBitplaneStride();		int interleave = track.getNbPlanes()*widthInBytes;		int opCode = 0;		int opCount = 0;		byte copyByte = 0;		leftBound_ = widthInBytes;		rightBound_ = 0;		topBound_ = track.getHeight();		bottomBound_ = 0;		int height = track.getHeight();		// Repeat for each plane.		for (int i = 0;i < track.getNbPlanes();i++)			{							// iOp is the pointer (index) to the op-codes.			iOp = ((data_[i*4]&0xff)<<24)+			      ((data_[i*4+1]&0xff)<<16)+			      ((data_[i*4+2]&0xff)<<8)+		    	  (data_[i*4+3]&0xff);			if (iOp > 0)				{				// Each column of the plane is coded on its own.				for (columns = 0;columns < widthInBytes;columns++)					{											// Set iPl to the beginning of the column in the plane.					iPl = columns+i*widthInBytes;					opCount = data_[iOp++] & 0xff;						if (opCount > 0)						{						if (columns < leftBound_)							{ leftBound_ = columns; }						if (columns > rightBound_)							{ rightBound_ = columns; }						opCode = data_[iOp];						if (opCode <= 0)							{ topBound_ = 0; }						else							{							if (opCode < topBound_)								{ topBound_ = opCode; }							}						for (;opCount > 0;opCount--)							{							opCode = data_[iOp++];							if (opCode > 0)								{ // Skip ops								iPl+=opCode*interleave;								}							else if (opCode < 0)								{ // Uniq ops								opCode &= 0x7f;								while (opCode-- > 0)									{									planeBytes[iPl] = data_[iOp++];									iPl+=interleave;									}								}							else								{ // Repeat ops								opCode = data_[iOp++] & 0xff;								if (opCode == 0)									{ return; } //throw new InterpretException("Error in Delta Chunk: copy bytes with count 0.");								copyByte = data_[iOp++];								while (opCode-- > 0)									{									planeBytes[iPl] = copyByte;									iPl+=interleave;									}								}							}												if (opCode <= 0)							{							int bottom = (iPl - (columns+i*widthInBytes)) / interleave;							if (bottom > bottomBound_) 								{ bottomBound_ = bottom; }							}						else							{							if (height - opCode > bottomBound_)								{ bottomBound_ = height - opCode; }							}						}					}				}			}		if (leftBound_ <= rightBound_)			{			leftBound_ *= 8;			rightBound_ = rightBound_*8 + 8;			}		}	protected void decodeVertical8Short(Bitmap bitmap, ANIMMovieTrack track) 		{		int columns = 0;		int iOp = 0;		byte[] planeBytes = bitmap.getBitmap();		int iPl = 0;		int widthInBytes = bitmap.getBitplaneStride();		int interleave = track.getNbPlanes()*widthInBytes;		int opCode = 0;		int opCount = 0;		byte copyByte1 = 0;		byte copyByte2 = 0;		leftBound_ = widthInBytes;		rightBound_ = 0;		topBound_ = track.getHeight();		bottomBound_ = 0;		int height = track.getHeight();		// Repeat for each plane.		for (int i = 0;i < track.getNbPlanes();i++)			{							// iOp points to the Op-Codes.			iOp = ((data_[i*4]&0xff)<<24)+			      ((data_[i*4+1]&0xff)<<16)+			      ((data_[i*4+2]&0xff)<<8)+		    	  (data_[i*4+3]&0xff);			if (iOp > 0)				{				// Each column has its own Op-codes.				for (columns = 0;columns < widthInBytes;columns+=2)					{					// iPl points to the column in the bitmap.					iPl = columns+i*widthInBytes;					opCount = ((data_[iOp++] &0xff) << 8) | (data_[iOp++] & 0xff);						if (opCount > 0)						{						if (columns < leftBound_)							{ leftBound_ = columns; }						if (columns > rightBound_)							{ rightBound_ = columns; }						opCode = (data_[iOp] << 8) | (data_[iOp+1] & 0xff);						if (opCode <= 0)							{ topBound_ = 0; }						else							{							if (opCode < topBound_)								{ topBound_ = opCode; }							}						for (;opCount > 0;opCount--)							{							opCode = (data_[iOp++] << 8) | (data_[iOp++] & 0xff);							if (opCode > 0)								{ // Skip ops								iPl+=opCode*interleave;								}							else if (opCode < 0)								{ // Uniq ops								opCode &= 0x7fff;								while (opCode-- > 0)									{									planeBytes[iPl] = data_[iOp++];									planeBytes[iPl+1] = data_[iOp++];									iPl+=interleave;									}								}							else								{ // Repeat ops								opCode = ((data_[iOp++] << 8) | (data_[iOp++] & 0xff)) & 0xffff;								if (opCode == 0)									{ return; } //throw new InterpretException("Error in Delta Chunk: copy bytes with count 0.");								copyByte1 = data_[iOp++];								copyByte2 = data_[iOp++];								while (opCode-- > 0)									{									planeBytes[iPl] = copyByte1;									planeBytes[iPl+1] = copyByte2;									iPl+=interleave;									}								}							}													if (opCode <= 0)							{							int bottom = (iPl - (columns+i*widthInBytes)) / interleave;							if (bottom > bottomBound_) 								{ bottomBound_ = bottom; }							}						else							{							if (height - opCode > bottomBound_)								{ bottomBound_ = height - opCode; }							}						}					}				}			}		if (leftBound_ <= rightBound_)			{			leftBound_ *= 8;			rightBound_ = rightBound_*8 + 16;			}		}	protected void decodeVertical8Long(Bitmap bitmap, ANIMMovieTrack track) 		{		int columns = 0;		int iOp = 0;		byte[] planeBytes = bitmap.getBitmap();		int iPl = 0;		int widthInBytes = bitmap.getBitplaneStride();		int interleave = track.getNbPlanes()*widthInBytes;		int opCode = 0;		int opCount = 0;		byte copyByte1 = 0;		byte copyByte2 = 0;		byte copyByte3 = 0;		byte copyByte4 = 0;		leftBound_ = widthInBytes;		rightBound_ = 0;		topBound_ = track.getHeight();		bottomBound_ = 0;		int height = track.getHeight();		// Repeat for each plane		for (int i = 0;i < track.getNbPlanes();i++)			{							// iOp points to the op-codes.			iOp = ((data_[i*4]&0xff)<<24)+			      ((data_[i*4+1]&0xff)<<16)+			      ((data_[i*4+2]&0xff)<<8)+		    	  (data_[i*4+3]&0xff);			if (iOp > 0)				{				// Decode each column of the plane separately.				for (columns = 0;columns < widthInBytes;columns+=4)					{											// iPl points to the column in the bitmap.					iPl = columns+i*widthInBytes;					opCount = ((data_[iOp++]&0xff)<<24)+							  ((data_[iOp++]&0xff)<<16)+						      ((data_[iOp++]&0xff)<<8)+					    	  (data_[iOp++]&0xff);						if (opCount > 0)						{						if (columns < leftBound_)							{ leftBound_ = columns; }						if (columns > rightBound_)							{ rightBound_ = columns; }						opCode = ((data_[iOp]&0xff)<<24)+								 ((data_[iOp+1]&0xff)<<16)+							     ((data_[iOp+2]&0xff)<<8)+						    	 (data_[iOp+3]&0xff);						if (opCode <= 0)							{ topBound_ = 0; }						else							{							if (opCode < topBound_)								{ topBound_ = opCode; }							}						for (;opCount > 0;opCount--)							{							opCode = ((data_[iOp++]&0xff)<<24)+									 ((data_[iOp++]&0xff)<<16)+								     ((data_[iOp++]&0xff)<<8)+							    	 (data_[iOp++]&0xff);							if (opCode > 0)								{ // Skip ops								iPl+=opCode*interleave;								}							else if (opCode < 0)								{ // Uniq ops								opCode &= 0x7fffffff;								while (opCode-- > 0)									{									planeBytes[iPl] = data_[iOp++];									planeBytes[iPl+1] = data_[iOp++];									planeBytes[iPl+2] = data_[iOp++];									planeBytes[iPl+3] = data_[iOp++];									iPl+=interleave;									}								}							else								{ // Repeat ops								opCode = ((data_[iOp++]&0xff)<<24)+										 ((data_[iOp++]&0xff)<<16)+									     ((data_[iOp++]&0xff)<<8)+								    	 (data_[iOp++]&0xff);								if (opCode == 0)									{ return; } //throw new InterpretException("Error in Delta Chunk: copy bytes with count 0.");								copyByte1 = data_[iOp++];								copyByte2 = data_[iOp++];								copyByte3 = data_[iOp++];								copyByte4 = data_[iOp++];								while (opCode-- > 0)									{									planeBytes[iPl] = copyByte1;									planeBytes[iPl+1] = copyByte2;									planeBytes[iPl+2] = copyByte3;									planeBytes[iPl+3] = copyByte4;									iPl+=interleave;									}								}							}													if (opCode <= 0)							{							int bottom = (iPl - (columns+i*widthInBytes)) / interleave;							if (bottom > bottomBound_) 								{ bottomBound_ = bottom; }							}						else							{							if (height - opCode > bottomBound_)								{ bottomBound_ = height - opCode; }							}						}					}				}			}		if (leftBound_ <= rightBound_)			{			leftBound_ *= 8;			rightBound_ = rightBound_*8 + 32;			}		}	protected void decodeVertical7Short(Bitmap bitmap, ANIMMovieTrack track)		{		int columns = 0;		int iOp = 0;		int iData = 0;		byte[] planeBytes = bitmap.getBitmap();		int iPl = 0;		int widthInBytes = bitmap.getBitplaneStride();		int interleave = bitmap.getScanlineStride();		int opCode = 0;		int opCount = 0;		byte copyByte1 = 0;		byte copyByte2 = 0;		leftBound_ = widthInBytes;		rightBound_ = 0;		topBound_ = track.getHeight();		bottomBound_ = 0;		int height = track.getHeight();		for (int i = 0;i < track.getNbPlanes();i++)			{			iOp = ((data_[i*4]&0xff)<<24)+			      ((data_[i*4+1]&0xff)<<16)+			      ((data_[i*4+2]&0xff)<<8)+		    	  (data_[i*4+3]&0xff);			iData = ((data_[i*4+32]&0xff)<<24)+			      ((data_[i*4+33]&0xff)<<16)+			      ((data_[i*4+34]&0xff)<<8)+		    	  (data_[i*4+35]&0xff);			if (iOp > 0)				{				for (columns = 0;columns < widthInBytes;columns+=2)					{					iPl = columns+i*widthInBytes;					opCount = data_[iOp++] & 0xff;						if (opCount > 0)						{						if (columns < leftBound_)							{ leftBound_ = columns; }						if (columns > rightBound_)							{ rightBound_ = columns; }						opCode = data_[iOp];						if (opCode <= 0)							{ topBound_ = 0; }						else							{							if (opCode < topBound_)								{ topBound_ = opCode; }							}						for (;opCount > 0;opCount--)							{							opCode = data_[iOp++];							if (opCode > 0)								{ // Skip ops								iPl+=opCode*interleave;								}							else if (opCode < 0)								{ // Uniq ops								opCode &= 0x7f;								while (opCode-- > 0)									{									planeBytes[iPl] = data_[iData++];									planeBytes[iPl+1] = data_[iData++];									iPl+=interleave;									}								}							else								{ // Repeat ops								opCode = data_[iOp++] & 0xff;								if (opCode == 0)									{ return; } //throw new InterpretException("Error in Delta Chunk: copy bytes with count 0.");								copyByte1 = data_[iData++];								copyByte2 = data_[iData++];								while (opCode-- > 0)									{									planeBytes[iPl] = copyByte1;									planeBytes[iPl+1] = copyByte2;									iPl+=interleave;									}								}							}													if (opCode <= 0)							{							int bottom = (iPl - (columns+i*widthInBytes)) / interleave;							if (bottom > bottomBound_) 								{ bottomBound_ = bottom; }							}						else							{							if (height - opCode > bottomBound_)								{ bottomBound_ = height - opCode; }							}						}					}				}			}		if (leftBound_ <= rightBound_)			{			leftBound_ *= 8;			rightBound_ = rightBound_*8 + 32;			}		}	protected void decodeVertical7Long(Bitmap bitmap, ANIMMovieTrack track) 		{		int columns = 0;		int iOp = 0;		int iData = 0;		byte[] planeBytes = bitmap.getBitmap();		int iPl = 0;		int widthInBytes = bitmap.getBitplaneStride();		int interleave = track.getNbPlanes()*widthInBytes;		int opCode = 0;		int opCount = 0;		byte copyByte1 = 0;		byte copyByte2 = 0;		byte copyByte3 = 0;		byte copyByte4 = 0;		leftBound_ = widthInBytes;		rightBound_ = 0;		topBound_ = track.getHeight();		bottomBound_ = 0;		int height = track.getHeight();		for (int i = 0;i < track.getNbPlanes();i++)			{			iOp = ((data_[i*4]&0xff)<<24)+			      ((data_[i*4+1]&0xff)<<16)+			      ((data_[i*4+2]&0xff)<<8)+		    	  (data_[i*4+3]&0xff);			iData = ((data_[i*4+32]&0xff)<<24)+			      ((data_[i*4+33]&0xff)<<16)+			      ((data_[i*4+34]&0xff)<<8)+		    	  (data_[i*4+35]&0xff);			if (iOp > 0)				{				for (columns = 0;columns < widthInBytes;columns+=4)					{					iPl = columns+i*widthInBytes;					opCount = data_[iOp++] & 0xff;					if (opCount > 0)						{						if (columns < leftBound_)							{ leftBound_ = columns; }						if (columns > rightBound_)							{ rightBound_ = columns; }						opCode = data_[iOp];						if (opCode <= 0)							{ topBound_ = 0; }						else							{							if (opCode < topBound_)								{ topBound_ = opCode; }							}						for (;opCount > 0;opCount--)							{							opCode = data_[iOp++];							if (opCode > 0)								{ // Skip ops								iPl+=opCode*interleave;								}							else if (opCode < 0)								{ // Uniq ops								opCode &= 0x7f;								while (opCode-- > 0)									{									planeBytes[iPl] = data_[iData++];									planeBytes[iPl+1] = data_[iData++];									planeBytes[iPl+2] = data_[iData++];									planeBytes[iPl+3] = data_[iData++];									iPl+=interleave;									}								}							else								{ // Repeat ops								opCode = data_[iOp++] & 0xff;								if (opCode == 0) 									{ return; } //throw new InterpretException("Error in Delta Chunk: copy bytes with count 0.");								copyByte1 = data_[iData++];								copyByte2 = data_[iData++];								copyByte3 = data_[iData++];								copyByte4 = data_[iData++];								while (opCode-- > 0)									{									planeBytes[iPl] = copyByte1;									planeBytes[iPl+1] = copyByte2;									planeBytes[iPl+2] = copyByte3;									planeBytes[iPl+3] = copyByte4;									iPl+=interleave;									}								}							}													if (opCode <= 0)							{							int bottom = (iPl - (columns+i*widthInBytes)) / interleave;							if (bottom > bottomBound_) 								{ bottomBound_ = bottom; }							}						else							{							if (height - opCode > bottomBound_)								{ bottomBound_ = height - opCode; }							}						}					}				}			}		if (leftBound_ <= rightBound_)			{			leftBound_ *= 8;			rightBound_ = rightBound_*8 + 64;			}		}	public int getTopBound(ANIMMovieTrack track) { return topBound_; }	public int getBottomBound(ANIMMovieTrack track) { return bottomBound_; }	public int getLeftBound(ANIMMovieTrack track) { return leftBound_; }	public int getRightBound(ANIMMovieTrack track) { return rightBound_; }	}