Примеры программирования на Java

Слайд-шоу
(ImgSequence.java)

Описание апплета
Пример работы апплета
//******************************************************************************
// ImgSequence.java:	Applet - смена последовтельности изображений. 
// Cледующее изображение медленно проявляется на фоне предыдущего.
//******************************************************************************
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.*;
	
//==============================================================================
// Основной класс - applet ImgSequence
//
//==============================================================================
public class ImgSequence extends Applet implements Runnable
{
	//нить загрузки изображений и смены изображений
	private Thread	 m_ImgSequence = null; 

	private Graphics  m_Graphics; //графический контекст рисования
	private Image	m_Images[]; //массив последовательности изображений 

	//изображение для рисования трансформаций на экране
	//формируется из пикселов m_nPaintPixels
	private Image   m_imgPaint=null; 

	//пикселы для m_imgPaint
	private int		m_nPaintPixels[]; 
	//пикселы следующего в последовательности изображения
	private int		m_nNextImgPixels[];
	//пикселы предыдущего в последовательности изображения
	private int		m_nPrevImgPixels[];
	//таблица для гладкого преобразования изображений
	private int 	m_nSmoothTransformTable[][]; 
	
	//индекс текущего изображения в последовательности
	private int 	m_nCurrImage; 

	private int 	m_nImgWidth  = 0; //ширина изображения
	private int 	m_nImgHeight = 0; //высота изображения
	private boolean	m_fAllLoaded = false; //флаг загрузки изображений

    // Члены класса - параметры
    //--------------------------------------------------------------------------
	//количество изображений
	private int	   m_nImages = 3;	
	//префикс имен изображений
	//по умолчанию первое изображение - images/img00001.jpg, 
	//второе - images/img00002.jpg и т.д.
	private String m_sImagePrefix        = "images/img00"; 
	//суффикс имен изображений
	private String m_sImageSuffix		 = ".jpg"; 
	//время показа одного изображения без трансформаций (в миллисекундах)
	private int    m_nTimeShowImage		 = 2500; 
	//количество шагов трансформации одного изображения в другое
	private int    m_nTransformSteps     = 53; 
	//задержка между шагами трансформации (в миллисекундах)
	private int    m_nTransformStepDelay = 5;

	//константа - дискретная трансформация (копированием пикселов)
	final   int	   TRANSFORM_DISCRET = 0; 
	//константа - гладкая трансформация (смешением значений пикселов)
	final   int	   TRANSFORM_SMOOTH  = 1; 

	//тип трансформации - дискретная или гладкая 
	private int	   m_nTransformType  = TRANSFORM_DISCRET; 
	//цвет фона апплета
	private Color  m_clrBk = Color.white; 

    //имена параметров
	private final String PARAM_ImgWidth = "ImgWidth";
	private final String PARAM_ImgHeight = "ImgHeight";
	private final String PARAM_NumImages = "NumImages";
	private final String PARAM_ImagePrefix = "ImagePrefix";
	private final String PARAM_ImageSuffix = "ImageSuffix";
	private final String PARAM_TimeShowImage = "TimeShowImage";
	private final String PARAM_TransformSteps = "TransformSteps";
	private final String PARAM_TransformStepDelay = "TransformStepDelay";
	private final String PARAM_TransformType = "TransformType";
	private final String PARAM_BkColor = "BkColor";

	// ImgSequence конструктор
	//--------------------------------------------------------------------------
	public ImgSequence()
	{
	}

	//---------------------------------------------------------------------------
	public String[][] getParameterInfo()
	{
		String[][] info =
		{
			{ PARAM_NumImages,     "int",	 "Quantity of images" },
			{ PARAM_ImagePrefix,   "String", "Base of image name" },
			{ PARAM_ImageSuffix,   "String", ".gif or .jpg" },
			{ PARAM_TimeShowImage, "int",    "time in msec to show image unchanged" },
			{ PARAM_TransformSteps, "int",   "number of steps of image transformation" },
			{ PARAM_TransformStepDelay, "int", "time to wait between transform steps (msec)" },
			{ PARAM_TransformType, "String", "type of transformation - smooth or discret" },
			{ PARAM_BkColor, "String", "Background color"}
		};
		return info;		
	}

	// В методе init() происходит первичная инициализация апплета
	// и получение значений параметров
	//--------------------------------------------------------------------------
	public void init()
	{
		String param;

		//количество изображений
		param = getParameter(PARAM_NumImages);
		if (param != null)
			m_nImages = Integer.parseInt(param);

		//префикс имен изображений
		param = getParameter(PARAM_ImagePrefix);
		if (param != null)
			m_sImagePrefix = param;

		// суффикс имен изображений: .GIF или JPG
		param = getParameter(PARAM_ImageSuffix);
		if (param != null)
			m_sImageSuffix = param;

		//время показа одного изображения без трансформаций (в миллисекундах)
		param = getParameter(PARAM_TimeShowImage);
		if (param != null)
			m_nTimeShowImage = Integer.parseInt(param);

		//количество шагов трансформации одного изображения в другое
		param = getParameter(PARAM_TransformSteps);
		if (param != null)
			m_nTransformSteps = Integer.parseInt(param);

		//задержка между шагами трансформации (в миллисекундах)
		param = getParameter(PARAM_TransformStepDelay);
		if (param != null)
			m_nTransformStepDelay = Integer.parseInt(param);

		//тип трансформации - "discret" или "smooth"
		param = getParameter(PARAM_TransformType);
		if (param != null)
		{
			if( param.indexOf("discret") >= 0 )
				m_nTransformType = TRANSFORM_DISCRET;
			else if( param.indexOf("smooth") >= 0 )
				m_nTransformType = TRANSFORM_SMOOTH;
		}

		//цвет фона
		param = getParameter(PARAM_BkColor);
		if (param != null)
		{
			//разбор строки цвета фона в форме "r,g,b" 
			StringTokenizer st = new  StringTokenizer(param, ",.");
			if( st.countTokens() == 3 )
			{
				int nRed   = Integer.parseInt(st.nextToken());
				int nGreen = Integer.parseInt(st.nextToken());
				int nBlue  = Integer.parseInt(st.nextToken());
				m_clrBk    = new Color(nRed, nGreen, nBlue);
			}
		}
		//установить цвет фона апплета
		setBackground(m_clrBk);
	}

	public void destroy()
	{
	}

    //displayImage - отрисовывает текущее изображение в середине апплета 
	//случае, если оно загружено
	//----------------------------------------------------------
	private  void displayImage(Graphics g)
	{
		if (!m_fAllLoaded)
				return;

		g.drawImage(m_imgPaint, (size().width - m_nImgWidth)   / 2,
						 (size().height - m_nImgHeight) / 2, null);
	}

	//doDiscretTransform выполняет очередной шаг дискретной трансформации
	//заданный параметром nStep (от 0 до m_TransformSteps -1)
	//----------------------------------------------------------------------------
	private void doDiscretTransform( int nStep )
	{
		int nEnd = m_nImgWidth * m_nImgHeight; //общее количество пикселов в изображении

		//цикл копирует пикселы следующего изображения в изображение для рисования 
		//c началом в nStep и шагом равным общему количеству шагов трансформации
		for( int i=nStep; i< nEnd; i += m_nTransformSteps)
		{
			m_nPaintPixels[i] = m_nNextImgPixels[i];
		}
	}

	//doSmoothTransform выполняет очередной шаг гладкой трансформации
	//заданный параметром nStep (от 0 до m_TransformSteps -1 )
	//Пиксел рисуемого изображения рассчитывается как разность 
	//пиксела предыдущего(исчезающего) и последующего(провляющегося) изображений
	//с весовым коэффициентом - шаг трансформации.
	//При nStep = 0, следующее изображение почти полностью скрыто предыдущим
	//При nStep = m_nTransformSteps - 1, следующее изображение полностью заменяет предыдущее
	//----------------------------------------------------------------------------
	private void doSmoothTransform( int nStep )
	{
		nStep++; //прибавляем единицу, так как nStep увеличивается от 0 
	
		int nHalfSteps =  m_nTransformSteps/2; //промежуточное значение для ускорения вычислений
		//nHalfSteps прибавляем к делимому, что позволяет избежать округления при делении на m_nTransformSteps.

		//Вычисляем таблицу преобразования пикселов для каждой пары предыдущий - cледущий 
		//первый индекс таблицы - значение Red, Green или Blue предыдущего изображения
		//второй индекс таблицы - значение Red, Green или Blue следующего изображения
		
		//Цикл по значениям R, G или B предыдущего от 0 до 255
		for( int p=0; p < 256; p++)
		{
			// цикл по значениям R, G или B следущего от 0 до 255	
			for( int n=0; n<256; n++ )
			{
              //Значение таблицы - разность значения R, G или B предыдущего и 
			  //следующего с весом - шаг транформации 
			  m_nSmoothTransformTable[p][n] = 
			  p + ( (n - p) * nStep + nHalfSteps) / m_nTransformSteps;
			}	   										  
		}

		int nEnd = m_nImgWidth * m_nImgHeight; //общее количество пикселов в изображении
		int nPrev, nNext; 

		//цикл по всем пикселам изображения
		//на каждом шаге формируем пиксел изображения для рисования
		//по таблице m_nSmoothTransformTable
		for( int i=0; i< nEnd; i ++)
		{
			nPrev = m_nPrevImgPixels[i]; // пиксел исчезающего изображения
			nNext = m_nNextImgPixels[i]; // пиксел проявляющегося изображения

			//формируем пиксел изображения для рисования как комбинацию RGB
			m_nPaintPixels[i] =	 0xff000000 | //атрибут прозрачности полностью выключен

				//Красная составляющая 
				//Берем значение из таблицы, первый индекс - Red составляющая 
				//пиксела исчезающей картинки, второй - Red составляющая 
				//пиксела появляющейся картинки
				( m_nSmoothTransformTable[ (nPrev & 0x00ff0000) >> 16 ]
					 				     [ (nNext & 0x00ff0000) >> 16 ] << 16 ) |


				//Зеленая составляющая 
				//Берем значение из таблицы, первый индекс - Green составляющая 
				//пиксела исчезающей картинки, второй - Green составляющая 
				//пиксела появляющейся картинки
			    ( m_nSmoothTransformTable[ (nPrev & 0x0000ff00) >> 8 ]
							 		     [ (nNext & 0x0000ff00) >> 8 ] << 8 ) |
				
				//Синяя составляющая 
				//Берем значение из таблицы, первый индекс - Cиняя составляющая 
				//пиксела исчезающей картинки, второй - Синяя составляющая 
				//пиксела появляющейся картинки
			    ( m_nSmoothTransformTable[ (nPrev & 0x000000ff) ]
									     [ (nNext & 0x000000ff) ] );
		}
	}

	// Paint рисует изображение для рисования или текстовую строку, 
	// если изображения еще не загружены
	//--------------------------------------------------------------------------
	public void paint(Graphics g)
	{
		if (m_fAllLoaded)
			displayImage(g);
		else
			g.drawString("Loading images...", 10, 20);
	}

    // showNextImage переходит к следущему изображению в последовательности через
	// трансформацию из текущего в следущее
	//--------------------------------------------------------------------------
	public void showNextImage(Graphics g)
	{
		//grab - объект для получения пикселов текущего изображения 
		//в качестве изображения для рисования и основы для трансформаций 
		PixelGrabber grab = new PixelGrabber(m_Images[m_nCurrImage].getSource(),
							0,0, m_nImgWidth, m_nImgHeight, 
							m_nPaintPixels, 0, m_nImgWidth);
		
		//iNext - индекс следующего изображения
		int iNext = m_nCurrImage + 1;
		if( iNext >= m_nImages )
			iNext = 0;

		//grabNext - объект для получения пикселов следущего изображения
		PixelGrabber grabNext= new PixelGrabber(m_Images[iNext].getSource(),
							0,0, m_nImgWidth, m_nImgHeight, 
							m_nNextImgPixels, 0, m_nImgWidth);
		try 
		{ 
		    //получаем пикселы обоих изображений
			grab.grabPixels();
			grabNext.grabPixels();

			//обновляем изображение для рисования 
			m_imgPaint.flush();

			//рисуем текущее изображение
			displayImage(g);

			//ждем заданное время без трансформаций
			Thread.sleep(m_nTimeShowImage);
		} 
		catch ( Exception e )
		{

		}
		
		if( m_nTransformType == TRANSFORM_SMOOTH )
		{
			//при гладкой трансформации необходимо иметь копию
			//пикселов текущего изображения, так как m_nPaintPixels
			//будут постоянно изменяться, отражая разницу - предыдущий/следущий
			System.arraycopy( m_nPaintPixels,    0,
							  m_nPrevImgPixels,  0, m_nImgHeight * m_nImgWidth );
		}

		//цикл по шагам трансформации
		for( int i=0; i< m_nTransformSteps; i++)
		{
			if( m_nTransformType == TRANSFORM_SMOOTH ) 
				doSmoothTransform(i);	
			else
				doDiscretTransform(i);	

			try 
			{
				//после трансформации обновляем изображение
				m_imgPaint.flush();
				//ждем заданное время между шагами
				Thread.sleep(m_nTransformStepDelay);
				//рисуем результат трансформации
				displayImage(g);
			}
			catch ( InterruptedException e)
			{
				
			}
		}
	}

	// Запуск апплета - запускаем нить (thread) m_ImgSequence, которая загружает 
	// изображения и выполняет трасформации 
	//--------------------------------------------------------------------------
	public void start()
	{
		if (m_ImgSequence == null)
		{
			m_ImgSequence = new Thread(this);
			m_ImgSequence.start();
		}
	}
	
	// Метод stop() - останавливаем выполненме нити m_ImgSequence
	//--------------------------------------------------------------------------
	public void stop()
	{
		if (m_ImgSequence != null)
		{
			m_ImgSequence.stop();
			m_ImgSequence = null;
		}
	}

	// run загружает изображения и входит в бесконечный цикл трансфорфмаций
	//--------------------------------------------------------------------------
	public void run()
	{
		m_nCurrImage = 0;
		
		// При повторном входе в страницу изображения уже загружены, поэтому
		// не делаем этого опять (m_fAllLoaded == TRUE).
        if (!m_fAllLoaded)
		{
    		//перерисовка, чтобы показать сообщение о загрузке
			repaint();

			//запоминаем контекст рисования
    		m_Graphics = getGraphics();
			//cоздаем массив изображений
    		m_Images   = new Image[m_nImages];

    		// Загружаем все изображения и ожидаем загрузки с помощью MediaTracker
    		MediaTracker tracker = new MediaTracker(this);
    		String strImage;

    		//цикл по всем изображениям
			for (int i = 1; i <= m_nImages; i++)
    		{
    			// формируем имя следущего изображения
    			strImage = m_sImagePrefix + ((i < 10) ? "0" : "") + i + m_sImageSuffix;
				// начинаем загрузку
			    m_Images[i-1] = getImage(getDocumentBase(), strImage);
                tracker.addImage(m_Images[i-1], 0);
    		}

    		// ожидаем загрузки 
			try
			{
				tracker.waitForAll();
				m_fAllLoaded = !tracker.isErrorAny();
			}
			catch (InterruptedException e)
			{
			}
			
			//если обнаружена ошибка при загрузке - остановить выполнение нити и 
			//вывести сообщение
			if (!m_fAllLoaded)
			{
			    stop();
			    m_Graphics.drawString("Error loading images!", 10, 40);
			    return;
			}
			
			// предполагается, что изображения одинакoвого размера
		    m_nImgWidth       = m_Images[0].getWidth(this);
		    m_nImgHeight      = m_Images[0].getHeight(this);

			//выделение памяти для пикселов рисуемого изображения
			m_nPaintPixels    = new int[m_nImgWidth * m_nImgHeight];
			//выделение памяти для пикселов следущего  изображения
			m_nNextImgPixels  = new int[m_nImgWidth * m_nImgHeight];

			if( m_nTransformType == TRANSFORM_SMOOTH )
			{
				//при гладкой трансформации нам необходима копия пикселов 
				//текущего изображения
				m_nPrevImgPixels       = new int[m_nImgWidth * m_nImgHeight];
				//и таблица преобразования
			    m_nSmoothTransformTable = new int[256][256];
			}

			//создаем изображения для рисования промежуточных этапов 
			m_imgPaint = createImage(new MemoryImageSource(m_nImgWidth,
					   m_nImgHeight, m_nPaintPixels, 0, m_nImgWidth));
        }		

		m_nCurrImage = 0;

		//перерисовка апплета после загрузки 
		repaint();

		while(true) //бесконецный цикл
		{
				// Осуществляем плавный переход от предыдущего к 
				// к следующему
				showNextImage(m_Graphics);
				
				m_nCurrImage++;
				
				//если последовательность закончилась - повторяем все сначала 
				if (m_nCurrImage == m_nImages)
					m_nCurrImage = 0;
		}
	}
}