Графика на Visual C++ и Java ч.1. Обработка изображений
Литература и ресурсы
WF-сети
Сеть Петри называется сетью потоков работ (Work Flow-сетью), если выполняются следующие условия:
· существует только одна исходная позиция i, такая что отсутствуют переходы входящие в i;
· существует только одна конечная позиция o, такая что отсутствуют переходы выходящие из o;
· каждый узел данной сети расположен на пути от i к о.
WF-сети используются для проверки графов потоков работ на наличие таких структурных конфликтов, как «тупики» ( deadlocks) и «недостатки синхронизации» ( lack of synchronization).
Структурные конфликты отсутствуют, если WF-сеть является бездефектной.
Свойство бездефектности или правильной завершаемости соответствует следующим требованиям:
· конечная позиция o достижима при любой последовательности переходов от позиции i;
· WF-сеть не содержит лишних переходов (которые никогда не будут выполнены);
· при достижении конечной позиции данной сети не должно оставаться фишек в промежуточных позициях.
1. Котов В.Е. Сети Петри. - М.: Наука, 1984. - 160 с
2. Д.Питерсон Теория сетей Петри и моделирование систем Пер. с анг. М.: МИР. 1984
3. http://www.informatik.uni-hamburg.de/TGI/PetriNets/
Petri Nets World - services for the international Petri Nets community
4. http://pipe2.sourceforge.net/
Platform Independent Petri net Editor - a tool for creating and analyzing Petri nets
Задачи обработки графики:
а) загрузка изображения из файла в требуемое место формы
с преобразованием (изменение размеров ...) , в том числе
и поверх существующего изображения.
б) преобразование загруженного изображения целиком по отдельным точкам
в) рисование по изображению различных геометрических фигур
г) сохранение изображения
1)Использование pictureBox ля работы с графикой в Visual C++.
Загрузка изображений
а)
Добавление pictureBox:
Отклик на событие Form1->Load:
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
{
Work();
}
Функция Work после конструктора Form1:
Form1(void)
{
InitializeComponent();
//
//TODO: добавьте код конструктора
//
}
void Work()
{
Bitmap^ bmp = gcnew Bitmap(450,350); // битовая карта для закрепления к pictureBox
// размеры как у pictureBox
Graphics^ g = Graphics::FromImage(bmp); // холст для рисования
pictureBox1->Image = bmp; // закрепление к pictureBox
Bitmap^ image1; // фото загрузки в pictureBox
image1 = gcnew Bitmap( "photo1.jpg"); // инициализация файл с фото
g->DrawImage(image1,10,20); // размещение фото left=10, top=20 в pictureBox
}
Вывод части рисунка:
Изменение Work – вывод рисунка в заданный прямоугольник:
void Work()
{
Bitmap^ bmp = gcnew Bitmap(450,350); // битовая карта для закрепления к pictureBox
// размеры как у pictureBox
Graphics^ g = Graphics::FromImage(bmp); // холст для рисования
pictureBox1->Image = bmp; // закрепление к pictureBox
Bitmap^ image1; // фото загрузки в pictureBox
image1 = gcnew Bitmap( "photo1.jpg"); // инициализация sфайл с фото
Rectangle r;
double p;
r.X=10;
r.Y=20;
r.Width=300;
r.Height=100;
g->DrawImage(image1,r);
}
Вывод без сохранения соотношения сторон:
Корректировка – вычисление пропорциональной высоты прямоугольника:
#include <math.h>
......
void Work()
{
Bitmap^ bmp = gcnew Bitmap(450,350); // битовая карта для закрепления к pictureBox
// размеры как у pictureBox
Graphics^ g = Graphics::FromImage(bmp); // холст для рисования
pictureBox1->Image = bmp; // закрепление к pictureBox
Bitmap^ image1; // фото загрузки в pictureBox
image1 = gcnew Bitmap( "photo1.jpg"); // инициализация sфайл с фото
Rectangle r;
double p;
int w,h;
w=image1->Width;
h=image1->Height;
r.X=10;
r.Y=20;
p=h;
r.Width=300;
r.Height=floor(p/w*r.Width);
g->DrawImage(image1,r);
}
Вывод в прямоугольник:
Модификация Work – вывод прямоугольной части второго изображения
поверх первого в заданный прямоугольник
void Work()
{
Bitmap^ bmp = gcnew Bitmap(450,350); // битовая карта для закрепления к pictureBox
// размеры как у pictureBox
Graphics^ g = Graphics::FromImage(bmp); // холст для рисования
pictureBox1->Image = bmp; // закрепление к pictureBox
Bitmap^ image1; // 1 фото загрузки в pictureBox
Bitmap^ image2; // 2 фото загрузки в pictureBox
image1 = gcnew Bitmap( "photo1.jpg"); // инициализация sфайл с фото 1
image2 = gcnew Bitmap( "photo2.jpg"); // файл с фото 2
Rectangle r;
double p;
int w,h;
w=image1->Width;
h=image1->Height;
r.X=10;
r.Y=20;
p=h;
r.Width=300;
r.Height=floor(p/w*r.Width);
g->DrawImage(image1,r); // вывод 1 фото в прямоугольник r
Rectangle r1; // прямоугольник исходного изображения,
// куда помещать второе
r1.X=200;
r1.Y=200;
p=h;
r1.Width=50;
r1.Height=floor(p/w*r1.Width);
Rectangle r2; // прямоугольник для части второго изображения
r2.X=2000;
r2.Y=1500;
r2.Width=2000;
r2.Height=floor(p/w*r2.Width);
GraphicsUnit u = GraphicsUnit::Pixel; // единицы измерения - пикселы
g->DrawImage(image2,r1,r2,u);
}
2)Использование JPanel для работы с графикой в Java SE.
Загрузка изображений
В java рисование происходит на компоненте и выполняет рисование
метод paintComponent. Для вывода изображений необходимо
перегрузить paintComponent.
Пример графики на SE:
Выводится изображение из файла в JPanel на форме
Вывод части рисунка:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class lab10
{
JFrame form;
pictureBox pc; // подкласс от JPanel
lab10()
{
form = new JFrame();
form.setBounds (10,20,500,500);
form.setTitle ("лабораторная 10");
form.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
form.setLayout(null);
pc=new pictureBox();
pc.setBounds(0, 0, 300, 300);
form.add(pc);
form.show();
}
public static void main (String args[])
{
lab10 f;
f= new lab10();
}
class pictureBox extends JPanel // наследник от JPanel
{
public BufferedImage im1; // image для загрузки 1 фото
public pictureBox ()
{
try
{
im1 = ImageIO.read(new File("photo1.jpg")); // чтение image из файла
}
catch (IOException e)
{
}
}
public void paintComponent(Graphics g) // метод рисования
{
g.drawImage(im1, 10, 20, null); // вывести часть изображения
repaint();
}
}
}
Вывод изображениея в заданный прямоугольник без сохранения пропорций
g.drawImage(im1, 10, 20,200,100, null);
вывод прямоугольной части второго изображения
поверх первого в заданный прямоугольник
class pictureBox extends JPanel // наследник от JPanel
{
public BufferedImage im1; // image для загрузки 1 фото
public BufferedImage im2; // image для загрузки 1 фото
public pictureBox ()
{
try
{
im1 = ImageIO.read(new File("photo1.jpg")); // чтение image из файла
}
catch (IOException e)
{
}
try
{
im1 = ImageIO.read(new File("photo2.jpg")); // чтение image из файла
}
catch (IOException e)
{
}
}
int w,h;
int wd,hd;
double p;
w=im1.getWidth(); // размер изображения
h=im1.getHeight();
wd=300; // ширина прямоугольника для вывода 1 фото
p=h;
hd=(int)Math.round(p/w*wd);
g.drawImage(im1, 10, 20,wd,hd, null); // вывод 1 фото
// в прямоугольник с сохранением пропорций
int dx1,dy1,dx2,dy2;
int sx1,sy1,sx2,sy2;
dx1=200;
dy1=200;
dx2=250;
p=h;
hd=(int)Math.round(p/w*(dx2-dx1));
dy2=dy1+hd; // dx1, dy1 , dx2,dy2 верхний левый – правый нижний,
// куда вставлять .
sx1=2000;
sy1=1500;
sx2=4000;
hd=(int)Math.round(p/w*(sx2-sx1));
sy2=sy1+hd; // sx1, sy1 , sx2,sy2 верхний левый – правый нижний,
// прямоугольник от вставляемого изображения
g.drawImage(im2,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2, null);
3)Использование ресурсов в Java ME.
Ресурсы в Java – часть архива jar, которые содержат текстовые файлы,
графические, звуковые и т.д. Предназначены только для чтения и
служат частичной компенсацией отсутствия файловой системы.
Пример чтения текстового файла из ресурса.
В папку \MobileApplication1\src где находится программа
lab10.java добавить папку TextFiles , в ней создать файл test.txt
с тремя строками:
first
qwerty
В ресурсы приложения добавляется папка TextFiles
Файл test.txt дополнительно скопировать в корень приложения mobileapplication1
Чтение строк из файла ресурса и вывод их в label.
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.geom.*;
import com.sun.lwuit.layouts.*;
import java.io.InputStream;
import java.io.IOException;
public class lab10 extends MIDlet
{
Form form;
Label lb;
String [] Ac=new String[5]; // строки для чтения
public void startApp()
{
int w,h;
Dimension d=new Dimension(200,200);
Display.init(this);
form = new Form();
form.setPreferredSize(d); // пытаться установить 200x200,
form.setTitle("лабораторная 10 ч.1");
w=form.getWidth();
h=form.getHeight();
CoordinateLayout ee = new CoordinateLayout(w,h);
form.setLayout(ee);
// положение и надпись label
lb=new Label();
lb.setX(20); // слева 20
lb.setY(30); // сверху 30
lb.setText("тест строковых ресурсов");
form.addComponent(lb);
form.show();
InputStream is = getClass().getResourceAsStream("test.txt"); // поток ввода из ресурса
try
{
char ch=0;
int rd=0;
int i=0;
Ac[0]="";
while ((rd = is.read()) !=-1) // чтение посимвольно
{
ch=(char)rd; // прочитанный символ
if(ch != '\r')
Ac[i]=Ac[i]+ch;
else
{
rd = is.read(); // прочитать '\n'
i++;
Ac[i]=""; // следующая строка
}
}
}
catch (Exception e)
{
}
String s=new String();
s=Ac[0]+" "+Ac[1]+" "+Ac[2];
lb.setText(s);
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
}
4)Использование ресурсов для работы с графикой в Java ME.
Загрузка изображений
В папку \MobileApplication1\src где находится программа lab10.java
добавить папку, Images и в ней добавить два файла photo1.jpg, photo2.jpg ,
затем к ресурсам добавить папку:
Изображение части рисунка на форме lwuit:
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.geom.*;
import com.sun.lwuit.layouts.*;
public class lab10 extends MIDlet
{
pictureBox form;
public void startApp()
{
int w,h;
Dimension d=new Dimension(200,200);
Display.init(this);
form = new pictureBox();
form.setPreferredSize(d);
w=form.getWidth();
h=form.getHeight();
CoordinateLayout ee = new CoordinateLayout(w,h);
form.setLayout(ee);
form.show();
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
class pictureBox extends Form // наследник form
{
public void paint(Graphics g)
{
Image im = null;
try
{
im=Image.createImage("/Images/photo1.jpg");
}
catch (Exception e)
{
}
g.drawImage(im, 0, 0);
}
}
}
Возможность рисования на форме ограничена, небольшое число
команд, нет возможности загрузки части изображения и т.д.
класс Canvas позволяет рисовать и обрабатывать изображения, но нет
label, textfield, button и т.д.
Вывод части изображения в canvas:
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.*;
public class lab10 extends MIDlet
{
private Display dsp;
private MyCanvas cv; // MyCanvas наследник Canvas
public void startApp()
{
cv= new MyCanvas();
dsp=Display.getDisplay(this);
dsp.setCurrent(cv); // вкючить display на Canvas
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
class MyCanvas extends Canvas
{
protected void paint(Graphics g) // перегрузка метода paint
{
Image im = null;
try
{
im=Image.createImage("/Images/photo1.jpg"); // из ресурсов
}
catch (Exception e)
{
}
g.drawImage(im, 10, 20, Graphics.LEFT | Graphics.TOP);
// left=10, top=20 выравнивать (якорь) по левому верхнему углу
}
}
}
Вывод части изображения в область, начинающуюся с
заданного верхнего угла:
g.drawRegion(im, 10, 20, 200, 150, 0, 15, 25,
Graphics.LEFT | Graphics.TOP);
Прямоугольная часть фотографии (left=10, top=20, width=200,
height=150) без преобразований (0 – без поворотов и зеркальных
отображений) выводится начиная с точки (left=15, top=25).
Вывод части второго изображения в область, начинающуюся с
заданного верхнего угла поверх первого:
protected void paint(Graphics g)
{
Image im1 = null;
Image im2 = null;
try
{
im1=Image.createImage("/Images/photo1.jpg"); // из ресурсов
im2=Image.createImage("/Images/photo2.jpg"); // из ресурсов
}
catch (Exception e)
{
}
g.drawImage(im1, 10, 20, Graphics.LEFT | Graphics.TOP);
g.drawRegion(im2, 330, 190, 70, 40, 0, 15, 270,
Graphics.LEFT | Graphics.TOP);
}
5) Обработка событий мыши для компонент
На Visual C++ MouseDown – событие, когда нажата кнопка мыши,
MouseMove – когда сместился курсор мыши
MouseUp – когда кнопка мыши отпущена
public ref class Form1 : public System::Windows::Forms::Form
{
public:
int Regim; // режим работы мыши
int MouseX,MouseY,OldX,OldY; // координаты мыши
Form1(void)
..............................
void Work()
{
Regim=0; // нач. зачение
Дополнение - обработка событий мыши для pictureBox
private: System::Void pictureBox1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
if(e->Button == System::Windows::Forms::MouseButtons::Left)
// right – правая кнопка
{
OldX=e->X; // начальные координаты
OldY=e->Y;
MouseX=OldX; // текущие координаты
MouseY=OldY;
Regim=1; // клавиша нажата
}
}
private: System::Void pictureBox1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
if(Regim==1)
{
// новые текущие координаты
MouseX=e->X;
MouseY=e->Y;
}
}
private: System::Void pictureBox1_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
if(Regim==1)
{
MouseX=e->X;
MouseY=e->Y;
Regim=0; // клавиша отпущена
// выделен прямоугольник OldX,OldY, MouseX,MouseY
}
}