package ch.werner_randelshofer.gui;/*Copyright (C) 1999 Werner Randelshoferwerner.randelshofer@mythen.chhttp://www.mythen.ch/w.randelshofer/    Permission to use this release of ImagePanel 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.*;import java.awt.image.*;import java.awt.event.*;import java.io.*;import java.net.*;import java.util.Vector;import java.util.Enumeration;import java.beans.PropertyChangeSupport;import java.beans.PropertyChangeListener;/**The MultiShow image viewer application can display imagesof type IFF ILBM, GIF and JPEG.@author	Werner Randelshofer, Staldenmattweg 2, CH-6405 Immensee, Switzerland.@version	0.4	1999-04-05	#setPixelAspectPolicy throws IllegalArgumentException							when passing invalid arguments. HARDSCALED_PIXEL_ASPECT							renamed into MULTIPLIED_PIXEL_ASPECT. Method #getPixelAspectPolicy							added.<br>history	0.3	1999-03-09	#getScaledImageSize waits for the image to							be loaded.<br>history	0.2	1999-02-04	New Method #setMessage allows the specification                            of a message text that will displayed on the                          	display area..<br>history	0.1	1999-02-02	First release.<br>history	0.0	1999-01-03	Created.*/public class ImagePanelextends Canvas	{	/**	Pixel aspect policy: Ignores pixel aspect.	*/	public final static int IGNORE_PIXEL_ASPECT = 0;	/**	Pixel aspect policy: Considers only extreme pixel aspects,	where one dimension is a multiple of the other dimension	of the pixel.	*/	public final static int MULTIPLIED_PIXEL_ASPECT = 1;	/**	Pixel aspect policy: Consider the exact pixel aspect.	*/	public final static int EXACT_PIXEL_ASPECT = 2;		/**	Image scaling policy: Scale as defined by #setScaleFactor	and the image aspect.	*/	public final static int SCALE_TO_IMAGE_SIZE = 0;	/**	Image scaling policy: Scale to panel size.	*/	public final static int SCALE_TO_VIEW_SIZE = 1;	/**	Image scaling policy: Scale to panel but keep the	image aspect. 	*/	public final static int SCALE_TO_IMAGE_ASPECT = 2;		private Image image_;	private double scaleX_ = 1.0;	private double scaleY_ = 1.0;	private int imageScalePolicy_ = SCALE_TO_VIEW_SIZE;	private int pixelAspectPolicy_ = EXACT_PIXEL_ASPECT;	private boolean keepExactPixelAspect_ = false;	private String message_;	/** Support for listeners. */	private PropertyChangeSupport propertyChangeSupport_ = new PropertyChangeSupport(this);	private Image offImage_;	private Dimension offDimension_;	private Graphics offGraphics_;	public ImagePanel()		{		super();		}	public void update(Graphics g)		{		paint(g);		}	public void paint(Graphics g)		{/*		Dimension d = getSize();		if (offGraphics_ == null ||			d.width != offDimension_.width ||			d.height != offDimension_.height)			{			offDimension_ = d;			offImage_ = createImage(d.width,d.height);			if (offGraphics_ != null)				{ offGraphics_.dispose(); }			offGraphics_ = offImage_.getGraphics();			}		drawTheImage(offGraphics_);		g.drawImage(offImage_,0,0,this);		}		public void drawTheImage(Graphics g)		{*/		Dimension size = getSize();		if (image_ == null || image_.getWidth(this) == -1)			{			g.setColor(getBackground());			g.fillRect(0, 0, size.width, size.height);			}		else			{			final int iw = image_.getWidth(this);			final int ih = image_.getHeight(this);			double xAspect = getPixelAspectX();			double yAspect = getPixelAspectY();			switch (imageScalePolicy_)				{				case SCALE_TO_VIEW_SIZE :					{					setScaleFactor0(size.width / (double)iw, size.height / (double)ih);					//drawCheckerboard(g,new Rectangle(0,0,size.width,size.height));					g.drawImage(						image_,						0,0,size.width,size.height,						0,0,iw-1,ih-1,						getBackground(),						this						);					break;					}				case SCALE_TO_IMAGE_ASPECT :					{					double factor = Math.min(size.width / (double)(iw*xAspect), size.height / (double)(ih*yAspect));					setScaleFactor0(factor,factor);					int w = (int)Math.ceil(iw*xAspect*factor);					int h = (int)Math.ceil(ih*yAspect*factor);					int x = (size.width - w)/2;					int y = (size.height - h)/2;					//drawCheckerboard(g,new Rectangle(x,y,w,h));					g.drawImage(						image_,						x,y,x+w,y+h,						0,0,iw-1,ih-1,						getBackground(),						this						);					if (size.width > w)						{						g.setColor(getForeground());						g.drawLine(x-1, 0, x-1, size.height-1);						g.drawLine(x+w, 0, x+w, size.height-1);						g.setColor(getBackground());						g.fillRect(0, 0, x-1, size.height);						g.fillRect(x+w+1, 0, size.width, size.height);						}					else if (size.height > h)						{						g.setColor(getForeground());						g.drawLine(0, y-1, size.width-1, y-1);						g.drawLine(0, y+h, size.width-1, y+h);						g.setColor(getBackground());						g.fillRect(0, 0, size.width, y-2);						g.fillRect(0,y+h+1, size.width, size.height);						}					break;					}				case SCALE_TO_IMAGE_SIZE :					{					int w = (int)(iw*xAspect*getScaleFactorX());					int h = (int)(ih*yAspect*getScaleFactorY());					int x = (size.width - w)/2;					int y = (size.height - h)/2;					//drawCheckerboard(g,new Rectangle(x,y,w,h));					g.drawImage(						image_,						x,y,x+w,y+h,						0,0,iw-1,ih-1,						getBackground(),						this						);					g.setColor(getBackground());					if (size.width > w)						{						g.fillRect(0, 0, x-1, size.height-1);						g.fillRect(x+w+1, 0, size.width-1, size.height-1);						}					if (size.height > h)						{						g.fillRect(0, 0, size.width-1, y-1);						g.fillRect(0,y+h+1, size.width-1, size.height-1);						}					g.setColor(getForeground());					g.drawRect(x-1,y-1,w+1,h+1);					break;					}				}			}		if (message_ != null)			{			g.setColor(getForeground());			g.drawString(message_,0,g.getFontMetrics().getMaxAscent());			}		}	/*	private void drawCheckerboard(Graphics g, Rectangle r)		{		g.setColor(Color.white);		g.fillRect(r.x,r.y,r.width,r.height);		final int squareSize = 8;		g.setColor(Color.lightGray);		// Draw from the left to the right.		int shift = 0;		for(int x = 0; x < r.width; x+=squareSize)			{			for(int y = shift*squareSize; y < r.height; y+=squareSize*2)				{				g.fillRect(r.x+x,r.y+y,squareSize,squareSize);				}			shift = shift == 0 ? 1 : 0;			}		}	*/	/**	Sets the pixel aspect policy.			@param	policy	PixelAspectPolicy must be one of IGNORE_PIXEL_ASPECT,					MULTIPLIED_PIXEL_ASPECT, EXACT_PIXEL_ASPECT.		@exception	IllegalArgumentException	When passing invalid policy.	*/	public synchronized void setPixelAspectPolicy(int policy)		{		if (policy != IGNORE_PIXEL_ASPECT &&			policy != MULTIPLIED_PIXEL_ASPECT &&			policy != EXACT_PIXEL_ASPECT)			{			throw new IllegalArgumentException("Invalid policy:"+policy);			}		pixelAspectPolicy_ = policy;		validate();		repaint();		}	/**	Returns the pixel aspect policy.	*/	public int getPixelAspectPolicy()		{		return pixelAspectPolicy_;		}	/**	Sets the image scale policy.		*/	public synchronized void setImageScalePolicy(int policy)		{		if (policy != SCALE_TO_IMAGE_SIZE &&			policy != SCALE_TO_VIEW_SIZE &&			policy != SCALE_TO_IMAGE_ASPECT)			{			throw new IllegalArgumentException("Invalid policy:"+policy);			}		imageScalePolicy_ = policy;		validate();		repaint();		}	/**	Returns the image scale policy.	*/	public int getImageScalePolicy()		{		return imageScalePolicy_;		}	/**	Gets the horizontal pixel aspect of the image according to the	pixel aspect policy that is in affect.		@return	Horizontal pixel aspect.	*/	public double getPixelAspectX()		{		if (image_ == null)			{ return 0; }					Object property = image_.getProperty("aspect",this);		if (property == null)			{ return 1; }		double ratio = (property == null || property == Image.UndefinedProperty) ? 1d : ((Double)property).doubleValue();		switch (pixelAspectPolicy_)			{			case IGNORE_PIXEL_ASPECT :				return 1d;			case EXACT_PIXEL_ASPECT :				return ratio >= 1d ? ratio : 1d;			case MULTIPLIED_PIXEL_ASPECT :				return ratio >= 1d ? Math.floor(ratio + 0.5d) : 1d;			default :				throw new InternalError("Invalid pixel aspect policy: " + pixelAspectPolicy_);			}		}	/**	Gets the vertical pixel aspect of the image according to the	pixel aspect policy that is in affect.		@return	Vertical pixel aspect.	*/	public double getPixelAspectY()		{		if (image_ == null)			{ return 0; }					Object property = image_.getProperty("aspect",this);		if (property == null)			{ return 1; }		double ratio = (property == null || property == Image.UndefinedProperty) ? 1d : ((Double)property).doubleValue();		switch (pixelAspectPolicy_)			{			case IGNORE_PIXEL_ASPECT :				return 1d;			case EXACT_PIXEL_ASPECT :				return ratio < 1d ? 1d / ratio : 1d;			case MULTIPLIED_PIXEL_ASPECT :				return ratio < 1d ? Math.floor(1d / ratio + 0.5d) : 1d;			default :				throw new InternalError("Invalid pixel aspect policy: " + pixelAspectPolicy_);			}		}	/**	Gets the preferred image size.		@return	Image dimension after applying the		pixel aspect policy.	*/	public Dimension getPreferredImageSize()		{		if (image_ == null)			{ return new Dimension(0,0); }					return new Dimension(			(int)Math.ceil(image_.getWidth(this)*getPixelAspectX()),			(int)Math.ceil(image_.getHeight(this)*getPixelAspectY())			);		}	/**	Gets the scaled and pixel aspect corrected image size.		@return	Image dimension after scaling and applying the		pixel aspect policy.	*/	public Dimension getScaledImageSize()		{		if (image_ == null)			{ return new Dimension(0,0); }		if (image_.getWidth(this) == -1)			{			try {				MediaTracker tracker = new MediaTracker(this);				tracker.addImage(image_,0);				tracker.waitForID(0);				}			catch(InterruptedException e)				{}			}		return new Dimension(			(int)Math.ceil(image_.getWidth(this)*getPixelAspectX()*getScaleFactorX()),			(int)Math.ceil(image_.getHeight(this)*getPixelAspectY()*getScaleFactorY())			);		}	/**	Sets the image and displays it in this	image panel.		@return image.	*/	public void setImage(Image image)		{		image_ = image;		invalidate();		if (getParent() != null)			{			getParent().validate();			getParent().repaint();			}		repaint();		}	/**	Gets the image that is displayed in this	image panel.		@return image.	*/	public Image getImage()		{		return image_;		}	/**	Sets the scale factor.	The scale factor scales images shown in 	this image panel.		@param	scaleX	Horizontal scale factor.	@param	scaleY	Vertical scale factor.	*/	public void setScaleFactor(double scaleX, double scaleY)		{		setScaleFactor0(scaleX,scaleY);		Component parent = getParent();		if (parent != null)			{			parent.invalidate();			parent.validate();			}		repaint();		}	protected void setScaleFactor0(double scaleX, double scaleY)		{		double oldScale = (scaleX_ + scaleY_) / 2d;		scaleX_ = scaleX;		scaleY_ = scaleY;		propertyChangeSupport_.firePropertyChange("scale",new Double((scaleX + scaleY)/2d),new Double(oldScale));		}	/**	Gets the horizontal scale factor that is	used to scale images shown in this image panel.		@return	Horizontal scale factor.	*/	public double getScaleFactorX()		{		return scaleX_;		}	/**	Gets the vertical scale factor that is	used to scale images shown in this image panel.		@return	Vertical scale factor.	*/	public double getScaleFactorY()		{		return scaleY_;		}	/**	Gets the preferred size of this image panel.	The preferred size depends on the image size,	the scale factor and the pixel aspect policy.	*/	public Dimension getPreferredSize()		{		if (image_ == null)			{ return new Dimension(50,15); }		else			{			return getScaledImageSize();			}		}	/**	Adds a listener who is interested in changes of this object. 	*/	public void addPropertyChangeListener(PropertyChangeListener listener)		{		propertyChangeSupport_.addPropertyChangeListener(listener);		}	/**	Removes a previously registerd listener. 	*/	public void removePropertyChangeListener(PropertyChangeListener listener)		{		propertyChangeSupport_.addPropertyChangeListener(listener);		}	public void setMessage(String message)		{		message_ = message;		repaint();		}/*	public void setBounds(int x, int y, int w, int h)		{		super.setBounds(x,y,w,h);				final int iw = image_.getWidth(this);		final int ih = image_.getHeight(this);		double xAspect = getPixelAspectX();		double yAspect = getPixelAspectY();				switch (imageScalePolicy_)			{			case SCALE_TO_VIEW_SIZE :				{				setScaleFactor0(iw / (double)w, ih / (double)h);				break;				}			case SCALE_TO_IMAGE_ASPECT :				{				double factor = Math.min(w / (double)(iw*xAspect), h / (double)(ih*yAspect));				setScaleFactor0(factor,factor);				break;				}			case SCALE_TO_IMAGE_SIZE :				{				break;				}			}		}*/	/**	Workaround: Netscape gets very slow when 	painting all SOMEBITS of an image.	*/    public boolean imageUpdate(Image img, int flags,			       int x, int y, int w, int h)		{		if (flags == SOMEBITS)			{ // suppress painting of SOMEBITS.			return true;			}		else			{			return super.imageUpdate(img,flags,x,y,w,h);			}		}	}