|
|||
|
Вступление Примеры Словарь Вопросы Sun Microsystems |
Примеры программирования на Java
//******************************************************************************
//
// ImageView.java: Applet - изменение параметров изображения - яркость, контрастность,
// цветность, цветовые тона
//
//******************************************************************************
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.StringTokenizer;
//==============================================================================
// Основной класс - апплет ImageView
//
//==============================================================================
public class ImageView extends Applet implements Runnable
{
private Image m_imgOriginal = null; //оригинальное изображение
private ImgFilter m_Filter = null; //фильтр изображения
private ImageDraw m_ImageDraw = null; //вспомогательный объект для рисования изображения
private MediaTracker m_Tracker = null; //вспомогательный объект для отслеживания загрузки изображения
private Thread m_Thread = null; //нить ожидания загрузки изображения
//имена изображений для иконок
private final String m_sIco[] = { "bright.gif", "contr.gif", "saturat.gif",
"red.gif", "green.gif", "blue.gif" };
//контролы - текстовые поля для ввода параметров
private TextField m_editBr;
private TextField m_editContr;
private TextField m_editSat;
private TextField m_editRed;
private TextField m_editGreen;
private TextField m_editBlue;
//кнопки
private Button m_btnReset;
private Button m_btnApply;
// Члены класса - параметры
//--------------------------------------------------------------------------
private String m_sPict = "test.jpg"; //имя изображения
private Color m_clrBk = Color.white; //цвет фона
private boolean m_fShowCtrls = true; //наличие контролов
private boolean m_fFrame = true; //наличие рамки вокруг аплета
private boolean m_fLoadingBits = false; //true, если апплет загружает изображение и еще не получил его первые биты
private boolean m_fFiltering = false; //true, если апплет фильтрует изображение
//имена параметров
private final String PARAM_Picture = "Picture";
private final String PARAM_Brightness = "Brightness";
private final String PARAM_Contrast = "Contrast";
private final String PARAM_Saturation = "Saturation";
private final String PARAM_Red = "Red";
private final String PARAM_Green = "Green";
private final String PARAM_Blue = "Blue";
private final String PARAM_Controls = "Controls";
private final String PARAM_Frame = "Frame";
private final String PARAM_BkColor = "BkColor";
//размеры контролов и отступы
final int nCtrlLeft = 5;
final int nCtrlTop = 5;
final int nCtrlGap = 5;
int m_nCtrlWidth = 50;
int m_nCtrlHeight = 20;
// размеры поля контролов
int m_nDimCtrlsX = 60;
int m_nDimCtrlsY = 200;
//размеры иконок
final int nIcoWidth = 15;
final int nIcoHeight = 15;
// ImageView конструктор, создает члены объекта
//--------------------------------------------------------------------------
public ImageView()
{
//вспомогательный объект для рисования изображения
m_ImageDraw = new ImageDraw(this, true);
//текстовые поля для ввода параметров
m_editBr = new TextField();
m_editContr = new TextField();
m_editSat = new TextField();
m_editRed = new TextField();
m_editGreen = new TextField();
m_editBlue = new TextField();
//кнопки
m_btnReset = new Button("Reset");
m_btnApply = new Button("Apply");
//фильтр изображения
m_Filter = new ImgFilter();
//вспомогательный объект для отслеживания загрузки изображения
m_Tracker = new MediaTracker(this);
}
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_Picture, "String", "Image for viewing" },
{ PARAM_Brightness, "int", "Intial brightnes" },
{ PARAM_Contrast, "int", "Initial contrast" },
{ PARAM_Saturation, "int", "Inital saturation" },
{ PARAM_Red, "int", "Initial red factor" },
{ PARAM_Green, "int", "Initial green factor" },
{ PARAM_Blue, "int", "Initial blue factor" },
{ PARAM_Controls, "boolean", "Optional controls" },
{ PARAM_Frame, "boolean", "Optional frame" },
{ PARAM_BkColor, "String", "Background color"}
};
return info;
}
// В методе init() происходит первичная инициализация апплета,
// получение значений параметров и добавление контролов
//--------------------------------------------------------------------------
public void init()
{
// Получение значений параметров и запоминание их в членах класса
//----------------------------------------------------------------------
String param;
//имя изображения
param = getParameter(PARAM_Picture);
if (param != null)
m_sPict = param;
//яркость
param = getParameter(PARAM_Brightness);
if (param != null)
m_Filter.setBr(Integer.parseInt(param));
//контраст
param = getParameter(PARAM_Contrast);
if (param != null)
m_Filter.setContr(Integer.parseInt(param));
//насыщенность
param = getParameter(PARAM_Saturation);
if (param != null)
m_Filter.setSat(Integer.parseInt(param));
//фактор красного
param = getParameter(PARAM_Red);
if (param != null)
m_Filter.setRed(Integer.parseInt(param));
//фактор зеленого
param = getParameter(PARAM_Green);
if (param != null)
m_Filter.setGreen(Integer.parseInt(param));
//фактор синего
param = getParameter(PARAM_Blue);
if (param != null)
m_Filter.setBlue(Integer.parseInt(param));
//наличие контролов
param = getParameter(PARAM_Controls);
if (param != null)
m_fShowCtrls = Boolean.valueOf(param).booleanValue();
//наличие рамки вокруг аплета
param = getParameter(PARAM_Frame);
if (param != null)
m_fFrame = Boolean.valueOf(param).booleanValue();
//цвет фона
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);
//добавить контролы в контейнер
if( m_fShowCtrls )
{
setLayout (null);
//инициировать контролы значениями по умолчанию
setControlsData();
//добавление текстовых полей
add (m_editBr);
add (m_editContr);
add (m_editSat);
add (m_editRed);
add (m_editGreen);
add (m_editBlue);
//создание и загрузка 6 иконок
for( int i = 0; i<6; i++)
{
ImageDraw Ico = new ImageDraw();
Ico.m_img = getImage(getDocumentBase(), m_sIco[i]);
//Tracker будет ждать загрузки изображений иконок
m_Tracker.addImage(Ico.m_img, 1);
//установить цвет фона иконок
Ico.setBackground(m_clrBk);
add(Ico);
}
//добавление кнопок
add (m_btnReset);
add (m_btnApply);
//вычислить размеры контролов на основе параметров шрифта
FontMetrics fm = getFontMetrics(m_editBr.getFont());
m_nCtrlHeight = fm.getAscent() + fm.getDescent();
m_nCtrlHeight = fm.stringWidth(" Reset ");
m_nDimCtrlsX = m_nCtrlWidth + nCtrlLeft * 2;
m_nDimCtrlsY = (m_nCtrlHeight + nCtrlGap) * 8 + nCtrlTop;
}
//компонент для рисования изображения
add (m_ImageDraw);
m_ImageDraw.setBackground(m_clrBk);
}
// Метод resize вызывается системой каждый раз при изменении размеров
// апплета. При изменении размеров переразмещаем контролы с помощью reshapeAll
//--------------------------------------------------------------------------
public void resize(int width, int height)
{
super.resize(width, height);
reshapeAll(size().width, size().height);
}
// Метод reshapeAll размещает контролы в соответствии
// c размерами апплета
//----------------------------------------------------------
private void reshapeAll(int width, int height)
{
int x = 0;
int y = 0;
int nW = width;
int nH = height;
if( m_fFrame )
{
//выделяем по 2 пиксела с каждой стороны для рамки
x+=2; nW -=4;
y+=2; nH -=4;
}
if( m_fShowCtrls )
{
int nXCtrl = x;
int nYCtrl = y;
if( m_fFrame )
{
//если есть рамка - размещаем контролы с отступом от края
nXCtrl += nCtrlLeft;
nYCtrl += nCtrlTop;
}
//ширина текстового поля меньше на размер иконки
int nEditWidth = m_nCtrlWidth - nIcoWidth - 2;
//переразмещаем текстовые поля и иконки слева от них
if( countComponents() > 12 )
{
for( int i=0 ; i<6 ; i++)
{
getComponent(i).reshape(nXCtrl + nIcoWidth + 2, nYCtrl, nEditWidth, m_nCtrlHeight);
getComponent(i+6).reshape(nXCtrl, nYCtrl + 2, nIcoWidth, nIcoHeight);
nYCtrl += m_nCtrlHeight + nCtrlGap;
}
}
//размещаем кнопки
nYCtrl += nCtrlGap;
m_btnApply.reshape(nXCtrl, nYCtrl, m_nCtrlWidth, m_nCtrlHeight);
nYCtrl += m_nCtrlHeight + nCtrlGap;
m_btnReset.reshape(nXCtrl, nYCtrl, m_nCtrlWidth, m_nCtrlHeight);
nW -= m_nDimCtrlsX;
x += m_nDimCtrlsX;
}
//на оставшемся поле размещаем изображение
m_ImageDraw.reshape( x, y, nW, nH);
}
// Paint - рисуем рамку вокруг апплета, если задан этот параметр
//--------------------------------------------------------------------------
public void paint(Graphics g)
{
if( m_fFrame )
{
g.setColor(m_clrBk);
g.draw3DRect(0, 0, size().width-1, size().height-1, true);
}
}
// Запуск апплета - загружаем изображение для обработки и
// запускаем нить (thread), которая ждет полной загрузки
// изображения с помощью MediaTracker
//--------------------------------------------------------------------------
public void start()
{
m_fLoadingBits = true;
m_ImageDraw.m_img = m_imgOriginal = getImage(getDocumentBase(), m_sPict);
if( m_fShowCtrls )
{
m_Tracker.addImage(m_ImageDraw.m_img, 1);
m_Thread = new Thread(this);
m_Thread.start();
}
}
// Нить ожидания загрузки изображений с помощью m_Tracker.
//--------------------------------------------------------------------------
public void run()
{
try
{
m_Tracker.waitForAll();
}
catch (InterruptedException e)
{
}
// после того как все изображения загружены и компоненты созданы,
// перерисовываем иконки.
if( countComponents() > 12 )
{
for( int i=6 ; i<12 ; i++)
{
getComponent(i).repaint();
}
}
}
// Метод stop() - останавливаем выполнение нити Thread
//--------------------------------------------------------------------------
public void stop()
{
if( m_Thread != null )
m_Thread.stop();
}
// imageUpdate - если получены первые биты изображения и необходимо фильтрование,
// то накладываем фильтр на изображение
//--------------------------------------------------------------------------
public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h)
{
if( m_fLoadingBits )
{
if( (infoflags & ImageObserver.SOMEBITS) != 0 )
{
m_fLoadingBits = false;
if( !m_fFiltering &&
(m_Filter.getBr() != 0 || m_Filter.getContr() !=0 || m_Filter.getSat() != 0 ||
m_Filter.getRed() != 0 || m_Filter.getBlue() !=0 || m_Filter.getGreen() != 0) )
{
doFilter();
}
}
}
else
{ //если отрисовано все изображение, сбрасываем флаг фильтрации
if( (infoflags & ImageObserver.ALLBITS) != 0 )
m_fFiltering = false;
}
return true;
}
// action вызывается системой при возникновении событий. Мы реагируем
// на нажатие кнопок 'Apply' и 'Reset'.
//------------------------------------------------------------------------
public boolean action(Event e, Object o)
{
if( e.target instanceof Button )
{
// Нажата кнопка 'Apply'
if( e.target == m_btnApply )
{
if( m_fFiltering == false ) //запрещаем повторный вход в фильтр
{
// Взять значения параметров из контролов
getControlsData();
// Применить фильтр
doFilter();
// Перерисовать изображение
m_ImageDraw.repaint();
}
return true;
}
// Нажата кнопка 'Reset'
else if( e.target == m_btnReset )
{
//Сбрасываем все параметры в 0
m_Filter.setBr(0);
m_Filter.setContr(0);
m_Filter.setSat(0);
m_Filter.setRed(0);
m_Filter.setGreen(0);
m_Filter.setBlue(0);
//Устанавливаем значения контролов
setControlsData();
//Будем рисовать оригинальное изображение
m_ImageDraw.m_img = m_imgOriginal;
m_ImageDraw.repaint();
return true;
}
}
return super.action(e, o);
}
// getControlsData берет значения параметров фильтрования из контролов
// и помещает их в фильтр изображения
//------------------------------------------------------------------------
private void getControlsData()
{
m_Filter.setBr(Integer.parseInt(m_editBr.getText()));
m_Filter.setContr(Integer.parseInt(m_editContr.getText()));
m_Filter.setSat(Integer.parseInt(m_editSat.getText()));
m_Filter.setRed(Integer.parseInt(m_editRed.getText()));
m_Filter.setGreen(Integer.parseInt(m_editGreen.getText()));
m_Filter.setBlue(Integer.parseInt(m_editBlue.getText()));
}
// setControlsData берет значения параметров из фильтра и
// и помещает их в текстовые поля
//------------------------------------------------------------------------
private void setControlsData()
{
m_editBr.setText(String.valueOf(m_Filter.getBr()));
m_editContr.setText(String.valueOf(m_Filter.getContr()));
m_editSat.setText(String.valueOf(m_Filter.getSat()));
m_editRed.setText(String.valueOf(m_Filter.getRed()));
m_editGreen.setText(String.valueOf(m_Filter.getGreen()));
m_editBlue.setText(String.valueOf(m_Filter.getBlue()));
}
// doFilter очищает старое изображение и создает новое, применяя фильтр
// к оригинальной картинке
//------------------------------------------------------------------------
private void doFilter()
{
if( !m_fFiltering ) //запрещаем повторный вход в фильтр
{
//освобождаем память предыдущего изображения
if( m_ImageDraw.m_img != null && m_ImageDraw.m_img != m_imgOriginal)
m_ImageDraw.m_img.flush();
m_fFiltering = true;
m_ImageDraw.m_img = createImage(new FilteredImageSource(m_imgOriginal.getSource(),
m_Filter));
}
}
}
//------------------------------------------------------------------------
// class ImageDraw - вспомогательный обьект для рисования изображения
//------------------------------------------------------------------------
class ImageDraw extends Canvas
{
public Image m_img = null; //картинка для рисования
private ImageObserver m_ImgObserver = null; //наблюдатель рисования
boolean m_fIncrementalUpdate = false; //флаг пошаговой отрисовки
// ImageDraw конструктор. Позволяет задать объект - наблюдатель рисования
// Второй параметр конструктора отвечает за способ перерисовки - инкрементальная
// или одношаговая
//------------------------------------------------------------------------
public ImageDraw(ImageObserver ImgObserver, boolean fIncrementalUpdate)
{
m_ImgObserver = ImgObserver;
m_fIncrementalUpdate = fIncrementalUpdate;
}
public ImageDraw()
{
this(null,false);
}
// imageUpdate вызывает наблюдатель рисования заданный в конструкторе
// Если задана инкрементальная перерисовка - вызывает imageUpdate
// базового класса
//------------------------------------------------------------------------
public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h)
{
boolean fRet = false;
if( m_ImgObserver != null)
fRet = m_ImgObserver.imageUpdate(img, infoflags, x, y, w, h);
if( m_fIncrementalUpdate )
fRet = super.imageUpdate(img, infoflags, x, y, w, h);
return fRet;
}
// update - рисуем изображение без перерисовки фона под изображением
public void update(Graphics g)
{
if( m_img != null )
{
int nX = 0;
int nY = 0;
int nW, nH;
nW = m_img.getWidth(null);
nH = m_img.getHeight(null);
//если доступны размеры изображения
if( nW > 0 && nH > 0 )
{
Dimension dimS = size();
//располагаем изображение в середине компонента
nX = dimS.width/2 - nW / 2;
nY = dimS.height/2 - nH / 2;
//заполняем фон вокруг изображения
if( nW < dimS.width )
{
g.clearRect(0, 0, nX, dimS.height);
g.clearRect(nX + nW, 0, dimS.width - (nX + nW), dimS.height);
}
if( nH < dimS.height )
{
g.clearRect(0, 0, dimS.width, nY );
g.clearRect(0, nY + nH, dimS.width, dimS.height - (nY + nH) );
}
}
//рисуем cамо изображение
g.drawImage( m_img, nX, nY,
(m_ImgObserver == null || m_fIncrementalUpdate)? this : m_ImgObserver );
}
else
{
// если изображения нет - просто рисуем фон
Rectangle rc = g.getClipRect();
g.clearRect(rc.x, rc.y, rc.width, rc.height);
}
}
// paint - вызываем метод update
public void paint(Graphics g)
{
update(g);
}
}
//------------------------------------------------------------------------
// class ImgFilter - фильтр обработки изображения
//------------------------------------------------------------------------
class ImgFilter extends RGBImageFilter
{
private int m_nBr = 0; //яркость -100, 100
private int m_nContr = 0; //контраст -100, 100
private int m_nSat = 0; //насыщенность -100, 100
private int m_nRed = 0; //фактор красного -100, 100
private int m_nGreen = 0; //фактор зеленого -100, 100
private int m_nBlue = 0; //фактор синего -100, 100
private double m_dAvgIntensity; //средняя интенсивность изображения
private int m_nContrTable[]; //таблица преобразования контрастности
private int m_nRedTable[]; //таблица преобразования красного цвета
private int m_nGreenTable[]; //таблица преобразования зеленого цвета
private int m_nBlueTable[]; //таблица преобразования синего цвета
private float m_fHSBvals[]; //буфер для оттенка, насыщенности, яркости
// ImgFilter конструктор - создает члены класса и инициирует
// значения параметров по умолчанию
//-----------------------------------------------
public ImgFilter()
{
canFilterIndexColorModel = true;
m_fHSBvals = new float[3];
m_nContrTable = new int[256];
m_nRedTable = new int[256];
m_nGreenTable = new int[256];
m_nBlueTable = new int[256];
m_dAvgIntensity = 127.5; //средняя интенсивность в середине диапазона 0-255
}
// Установка яркости. Параметр проверяется на
// граничные значения -100, 100
//-----------------------------------------------
public void setBr(int nBr)
{
m_nBr = validateParam(nBr);
}
// Установка контрастности. Параметр проверяется на
// граничные значения -100, 100
// Вычисляется коэффициент изменения контрастности dGamma (от 0.01 до m_dAvgIntesity).
// Затем формируется таблица преобразования контрастности для каждого
// значения цвета ( 0 - 255)
//-----------------------------------------------
public void setContr(int nContr)
{
m_nContr = validateParam(nContr);
if( m_nContr != 0 )
{
double dGamma;
if( m_nContr > 0 )
{
// при увеличении контрастности dGamma > 1 и <= m_dAvgIntensity;
// расчитываем как tan(проценты увеличения контрастности) + 1
dGamma = Math.tan( ( Math.PI/2 * (double)m_nContr) / 100 ) + 1;
}
else
{
// при уменьшении контрастности dGamma < 1 и >= 0.01
// расчитываем пропорцинально m_nContr
dGamma = ( (double)m_nContr ) / 100 + 1;
}
//проверка граничных значений коэффициента
dGamma = Math.min(m_dAvgIntensity, dGamma);
dGamma = Math.max(0.01, dGamma);
int nVal;
// формируется таблица преобразования контрастности для каждого
// значения цвета ( 0 - 255) как отклонение от средней интенсивности
// пропорциональное dGamma
for( int i=0; i<256; i++ )
{
nVal = (int) ( m_dAvgIntensity + (i - m_dAvgIntensity) * dGamma );
if( nVal > 255 )
nVal = 255;
else if( nVal < 0 )
nVal = 0;
m_nContrTable[i] = nVal;
}
}
}
// Установка насыщенности. Параметр проверяется на
// граничные значения -100, 100
//-----------------------------------------------
public void setSat(int nSat)
{
m_nSat = validateParam(nSat);
}
// Установка фактора красного. Параметр проверяется на
// граничные значения -100, 100
// Затем формируется таблица преобразования красного цвета для каждого
// значения ( 0 - 255)
//-----------------------------------------------
public void setRed(int nRed)
{
m_nRed = validateParam(nRed);
fillBiasTable(m_nRedTable, m_nRed);
}
// Установка фактора синего. Параметр проверяется на
// граничные значения -100, 100
// Затем формируется таблица преобразования синего цвета для каждого
// значения ( 0 - 255)
//-----------------------------------------------
public void setGreen(int nGreen)
{
m_nGreen = validateParam(nGreen);
fillBiasTable(m_nGreenTable, m_nGreen);
}
// Установка фактора зеленого. Параметр проверяется на
// граничные значения -100, 100
// Затем формируется таблица преобразования зеленого цвета для каждого
// значения ( 0 - 255)
//-----------------------------------------------
public void setBlue(int nBlue)
{
m_nBlue = validateParam(nBlue);
fillBiasTable(m_nBlueTable, m_nBlue);
}
// fillBiasTable формирует таблицу преобразования цвета для каждого
// из возможных знечений (0 -255). Если nBias = -100 - уменьшаем цвет
// на 100%, если nBias = 100 - увеличиваем на 100%
//-----------------------------------------------
private void fillBiasTable(int nTable[], int nBias)
{
int nVal;
for( int i=0; i<256; i++ )
{
nVal = i + (i * nBias) / 100;
if( nVal > 255 )
nVal = 255;
else if( nVal < 0 )
nVal = 0;
nTable[i] = nVal;
}
}
// Функции получения параметров фильтрования
public int getSat() { return m_nSat; }
public int getContr() { return m_nContr; }
public int getBr() { return m_nBr; }
public int getRed() { return m_nRed; }
public int getGreen() { return m_nGreen; }
public int getBlue() { return m_nBlue; }
// filterRGB преобразует пикселы (или цвета палитры)
// исходного изображения в соотвествии с заданными параметрами
//-----------------------------------------------
public int filterRGB(int x, int y, int rgb)
{
if( m_nSat != 0 || m_nBr != 0 )
{
//преобразуем RGB модель цвета в модель HSB
Color.RGBtoHSB( (rgb & 0x00ff0000) >> 16, //red
(rgb & 0x0000ff00) >> 8, //green
(rgb & 0x000000ff), //blue
m_fHSBvals );
//пропорционально изменяем насыщенность и яркость
m_fHSBvals[1] += ( m_fHSBvals[1] * m_nSat) / 100;
m_fHSBvals[2] += ( m_fHSBvals[2] * m_nBr ) / 100;
//проверяем граничные значения (0 - 1) насыщенности и яркости
m_fHSBvals[1] = (float)Math.min(m_fHSBvals[1], 1 );
m_fHSBvals[2] = (float)Math.min(m_fHSBvals[2], 1 );
//обратное преобразование HSB к RGB
rgb = Color.HSBtoRGB(m_fHSBvals[0], m_fHSBvals[1], m_fHSBvals[2]) | (rgb & 0xff000000);
}
// выделяем красный, синий и зеленый компоненты
int nRed = (rgb & 0x00ff0000) >>16;
int nGreen = (rgb & 0x0000ff00) >> 8;
int nBlue = rgb & 0x000000ff;
if( m_nContr != 0 )
{
//если задано изменение котрастности - изменяем
//цвет по каждому каналу в соответствии с таблицей
nRed = m_nContrTable [ nRed ];
nGreen = m_nContrTable [ nGreen ];
nBlue = m_nContrTable [ nBlue ];
}
//отклоняем цвета в соответсвии с таблицами изменения цветов
nRed = m_nRedTable [ nRed ];
nGreen = m_nGreenTable [ nGreen ];
nBlue = m_nBlueTable [ nBlue ];
//возвращаем упакованный результат в виде Int
return (rgb & 0xff000000) | ( nRed << 16 ) | (nGreen << 8) | nBlue;
}
// validateParam ограничивает значение входного параметра
// в пределах -100 - +100
//-----------------------------------------------
private int validateParam(int nParam)
{
if( nParam < -100 )
nParam = -100;
else if( nParam > 100 )
nParam = 100;
return nParam;
}
}
|
||