Слайд-шоу
|
Описание апплета Пример работы апплета |
//******************************************************************************
// 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;
}
}
}