

import java.awt.Transparency;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.Raster;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;


/**
 * class RasImageDecoder
 * implements a sun Raster image file format decoder
 * @version 1.4 99/02/17
 * @since JDK 1.2
 */

public class RasImageDecoder  {
	
	public static int HEADER_MINSIZE=256;
	public static int R_MASK=0x00FF0000;
	public static int G_MASK=0x0000FF00;
	public static int B_MASK=0x000000FF;
	public static int A_MASK=0xFF000000;

	DataInputStream input_;
	RasParam param_;
	ColorModel colorModel_;
	WritableRaster raster_;
	BufferedImage bufferedImage_;

	/**
	 * <B>Constructor</B>
	 **/
	public RasImageDecoder(InputStream is)
	{
		input_=new DataInputStream(is);
	}

	/**
	 * <B>Constructor</B>
	 **/
	public RasImageDecoder(String imagepath) throws FileNotFoundException
	{
		this(new FileInputStream(imagepath));
	}

	/**
	 * test if the file has the correct magic number 
	 * (return true if the format doesn't have a magic number)
	 *
	 * @return true if the image has the correct Magic Number
	**/
	public boolean testMagicNumber()
	{
		if(param_==null)
			param_=new RasParam(input_);
		return (param_.magic==RasParam.MAGIC);
	}

	/**
	 * test if the file has the correct magic number 
	 * (return true if the format doesn't have a magic number)
	 *
	 * @return true if the image has the correct Magic Number
	**/
	public static boolean testMagicNumber(String path) throws FileNotFoundException
	{
		FileInputStream fis=new FileInputStream(path);
		DataInputStream dis=new DataInputStream(fis);
		byte[] header=new byte[HEADER_MINSIZE];
		try{
			dis.read(header,0,HEADER_MINSIZE);
		}
		catch(IOException ioe){return false;}
		return testMagicNumber(header);
	}

	/**
	 * test if the file has the correct magic number 
	 * (return true if the format doesn't have a magic number)
	 *
	 * @return true if the image has the correct Magic Number
	**/
	public static boolean testMagicNumber(byte[] header)
	{
		boolean res=true;
		for(int i=0;i<4;i++)
			res&=(header[i]==RasParam.MAGIC_BYTES[i]);
		return res;
	}


	/**
	 * decode the image and return this as a Raster 
	 *
	 * @return the image decoded
	**/
	public Raster decodeAsRaster()
	{
		if(raster_==null)
			decodeAsBufferedImage();
		return raster_;
	}

	/**
	 * decode the image and return this as a BufferedImage 
	 *
	 * @return the image decoded
	**/
	public BufferedImage decodeAsBufferedImage() 
	{
		if(param_==null)
			param_=new RasParam(input_);
		if(param_.maptype==RasParam.RMT_RAW)
			{
				genError();
				return null;
			}
		byte[] byteBuffer;
		DataBufferByte dbb;
		int lineByteSize;
		lineByteSize=calculLineSize(param_);
		switch(param_.depth){
		case 1:
		case 4:
		case 8:
			if(param_.maptype==RasParam.RMT_NONE){
				colorModel_=createColorModel(param_.depth);
			}
			else{
				colorModel_=readMapRGB(param_,input_);
			}				
			MultiPixelPackedSampleModel mpsm;
			mpsm=new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
											   param_.width,
											   param_.height,
											   param_.depth,
											   lineByteSize,
											   0);				
			byteBuffer=readBufferAll(param_,input_);
			if(byteBuffer==null){
				genError();
				return null;
			}
			dbb=new DataBufferByte(byteBuffer,byteBuffer.length,0);
			raster_=Raster.createWritableRaster(mpsm, dbb, null);
			bufferedImage_=new BufferedImage(colorModel_,raster_,true,null);				
			break;
		case 24:
			if(param_.maptype==RasParam.RMT_NONE && param_.maplength==0){
				ColorSpace cs =ColorSpace.getInstance(ColorSpace.CS_sRGB);
				int[] nBits={8,8,8};
				int[] bOffs={2,1,0};
			    colorModel_=new ComponentColorModel(cs,nBits,false,false,
													Transparency.OPAQUE,DataBuffer.TYPE_BYTE);
				byteBuffer=readBufferAll(param_,input_);
				if(byteBuffer==null){
					genError();
					return null;
				}
				dbb=new DataBufferByte(byteBuffer,byteBuffer.length,0);
				raster_=Raster.createInterleavedRaster(dbb,param_.width,param_.height,
													   lineByteSize,param_.depth/8,bOffs,null);
				bufferedImage_=new BufferedImage(colorModel_,raster_,true,null);				
			}
			else{
				genError();
			}
			break;
		}
		//colorModel_=initColorModel(input_, param_);
		return bufferedImage_;
	}
	
	private ColorModel readMapRGB(RasParam param, DataInputStream dis)
	{
		ColorModel colorModel=null;
		int tabSize=(int)Math.pow(2,param.depth);
		byte[] tabR=new byte[tabSize];
		byte[] tabG=new byte[tabSize];
		byte[] tabB=new byte[tabSize];
		try{
			dis.read(tabR,0,tabSize);
			dis.read(tabG,0,tabSize);
			dis.read(tabB,0,tabSize);
			colorModel=new IndexColorModel(param.depth,tabSize,tabR,tabG,tabB);
		}
		catch(IOException ioe){
			colorModel=null;
		}
		return colorModel;
	}

	private IndexColorModel createColorModel(int depth)
	{
		IndexColorModel colorModel=null;
		switch(depth){
		case 1:
			byte[] mapColor={(byte)0,(byte)0xff};
			colorModel=new IndexColorModel(1,2,mapColor,mapColor,mapColor);
			break;
		default:
			break;
		}
		return colorModel;
	}

	private byte[] readBufferAll(RasParam param, DataInputStream dis)
	{
		int nbBytes=calculLineSize(param)*param.height;
		byte[] tabVal=new byte[nbBytes];
		try{
		   dis.read(tabVal,0,nbBytes);
	   }
	   catch(IOException ioe){
		   return null;
	   }	   
	   return tabVal ;
	}


	private int calculLineSize(RasParam param)
	{		
	   int size=param.depth*param.width;	   
	   // PATCH
	   // test supplementaire pour cooriger certains convertisseurs (comme Paint Shop Pro)
	   // qui ne respectent pas l'arrondi des lignes a 16 bits
	   // normalement, 
	   if(param.length*8!=size*param.height)
		  size=((size+15)/16)*2;
	   else
		   size=(size+7)/8;
	   return size;
	}

	private void genError()
	{
	}

	// main pour les test
    public static void main(String[] args) 
	{
        String vers = System.getProperty ("java.version");
        System.out.println ("Example running with JDK " + vers);
		try {javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");}
		catch (Exception exc) {;}
		javax.swing.JFrame mf=new javax.swing.JFrame();
		mf.addWindowListener(new java.awt.event.WindowAdapter()
							 {
								 public void windowClosing(java.awt.event.WindowEvent e) {System.exit(0);}
							 });

		String path;
		path="basus16m.ras";
		Image img1=ImageLoader.getImage(path);
		Image imgScaled1=ImageLoader.getScaledImage(img1,100,100);
	
		path="E:/Images/basus256.ras";
		Image img2=ImageLoader.getImage(path);
		Image imgScaled2=ImageLoader.getScaledImage(img2,100,100);
		
		mf.getContentPane().setLayout(new java.awt.FlowLayout());

		mf.getContentPane().add(new javax.swing.JButton(new javax.swing.ImageIcon(img1)));
		mf.getContentPane().add(new javax.swing.JButton(new javax.swing.ImageIcon(imgScaled1)));
		mf.getContentPane().add(new javax.swing.JButton(new javax.swing.ImageIcon(img2)));
		mf.getContentPane().add(new javax.swing.JButton(new javax.swing.ImageIcon(imgScaled2)));
		
		mf.setSize(500,500);
		mf.setVisible(true);		
	}

} // ImageDecoder














