GRAFIKA 2D I
3D -
TUTORIAL
Marcin Turek, Dawid Szymczyk,
Ryszard Szwajlik
Wprowadzenie
Java2D API w sposób znaczny rozszerza
możliwości graficzne AWT. Po pierwsze
umożliwia zarządzanie i rysowanie
elementów graficznych o współrzędnych
zmiennoprzecinkowych (float i double).
Własność ta jest niezwykle przydatna dla
różnych aplikacji.
Ta podstawowa zmiana podejścia do
rysowania
obiektów
graficznych
i
geometrycznych powoduje powstanie,
nowych, licznych klas i metod…
Graphics i Graphics 2D
Graphics — bazowa klasa abstrakcyjna dla wszystkich
kontekstów
graficznych
umożliwiających
rysowanie
na
komponentach.
Graphics2D
—
rozszerzenie
dostarczające
bardziej
zaawansowanej kontroli nad rysowaniem:
rysowanie i wypełnianie:
tekstu: drawText(),
obrazów: drawImage(),
kształtów geometrycznych: drawLine(), drawArc(), drawRect(),
drawOval(), drawPolygon(), fill();
konfiguracja atrybutów: setFont(), setColor(), setStroke(),
setPaint();
*** PRZYKŁADY ZAMIESZCZONE W PRZESŁANYCH PLIKACH ***
Zaczynamy…
Aby
stworzyć
aplikację
pozwalającą
na
rysowanie figur geomoetrycznych (jak również
innych elementów grafiki 2D – np. obrazów)
musimy:
stworzyć klasę ramki (potomek JFrame)
stworzyć panel na którym będziemu umieszczać
graficzne elementy. (pochodna JPanel)
„narysować” i umieścić w panelu elementy
graficzne (przeciążamy metody paint(Graphics
g); lub paintComponent(Graphics g) );
W metodach przedstawionych metodach
(paint() lub paintComponent()), zachodzi
cały proces rysowania. W sposób
szczególny należy wyróżnić tutaj sposób
rysowania nowych elementów. Odbywa
się to poprzez zastosowanie jednej
metody:
Graphics2D g2;
//stworzenie obiektu
g2.draw(Shape s);
//wywołanie metody draw();
Draw(…);
Metoda draw() umożliwia narysowanie
dowolnego
obiektu
implementującego
interfejs Shape (kształt). Przykładowo
narysowanie linii o współrzędnych typu
float można wykonać w następujący
sposób:
Line2D linia = new Line2D.Float(20.0f, 10.0f, 100.0f, 10.0f);
g2.draw(linia);
*** PRZYKŁADY ZAMIESZCZONE W PRZESŁANYCH PLIKACH ***
Kształty
Podstawowe kształty:
Point2D,
Line2D,
krzywe:
QuadCurve2D,
CubicCurve2D,
Rectangle2D,
RoundedRectangle2D,
Ellipse2D,
Arc2D,
podklasy:
Name2D.Name — publicznie pola typu int,
Name2D.Double — publiczne pola typu double,
Name2D.Float — publiczne pola typu float
Złożone kształty
GeneralPath — implementuje interfejs Shape,
reprezentuje geometryczną ścieżkę stworzoną z
linii
i krzywych:
new GeneralPath(),
moveTo(),
lineTo(),
quadTo(),
curveTo(),
closePath(),
append().
GeneralPath oddShape = new GeneralPath();
...
public GeneralPath createPath(int x, int y) {
x2 = x;
y2 = y;
oddShape.moveTo(x, y);
x -= 100;
oddShape.lineTo(x, y);
y += 50;
oddShape.lineTo(x, y);
x += 100;
oddShape.lineTo(x, y);
x += 10;
y -= 10;
x1 = x - 20;
y1 = y - 20;
oddShape.curveTo(x, y, x1, y1, x2, y2);
return oddShape;
}
Obserwator
Obserwator (Observer) — nasłuchuje na zmiany w
innym obiekcie, implementuje interfejs Observer:
void update(Observable o, Object arg).
Obiekt obserwowany (Observable) —
powiadamiania inne obiekty o zmianie swojego
stanu, dziedziczy po klasie Observable:
setChanged() — informacja że nastąpiły zmiany,
notifyObservers() — informacja do obserwatorów,
notifyObservers(Object obj).
Oddzielenie logiki od wyświetlania, osobne
moduły do działania na danych i wyświetlania.
Dodatkowe klasy w AWT wspomagające grafikę to
BasicStroke oraz TexturePaint. Pierwsza
z
nich
umożliwia
stworzenie
właściwości
rysowanego obiektu takich jak np.: szerokość linii,
typ linii.
Przykładowo ustawienie szerokości linii na 12 punktów
odbywać się może poprzez zastosowanie następującego
kodu:
grubaLinia = new BasicStroke(12.0f);
g2.setStroke(grubaLinia);
Klasa TexturePaint umożliwia wypełnienie
danego kształtu (Shape) określoną teksturą.
//zastosowanie klasyTexturePaint
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
BufferedImage bi = new BufferedImage(5, 5,
BufferedImage.TYPE_INT_RGB);
Graphics2D big = bi.createGraphics();
big.setColor(Color.blue);
big.fillRect(0, 0, 5, 5);
big.setColor(Color.lightGray);
big.fillOval(0, 0, 5, 5);
Rectangle r =
new Rectangle(0, 0, 5, 5);
g2.setPaint(new TexturePaint(bi, r));
Rectangle rect = new Rectangle(5,5,200,200);
g2.fill(rect);
}
Kolory
Kolor którym będzie rysowana figura wyieramy za
pomocą
metody
setPaint
klasy
Graphics2D.
Agumentem metody setPaint są obiekty klasy
java.awt.Color:
Color.RED – predefiniowane stale klasy Color;
new Color(int r, int g, int b) – tworzenie
obiektu klasy Color (składowe koloru RGB);
W połączeniu z metodą setPaint:
setPaint(Color.RED);
setPaint(new Color(255,255,0));
Obrazy
Klasy obsługujące obrazki:
Image — abstrakcyjna klasa nadrzędna
przedstawiająca obraz jako tablicę pikseli,
BufferedImage — klasa pozwalająca na operacje na
obrazku, można tworzyć instancje.
ImageIO — wczytywanie i zapisywanie obrazów:
wsparcie dla: GIF, PNG, JPEG, BMP, WBMP,
rozszerzalność o inne formaty (dostępne pluginy dla
TIFF i JPEG 2000),
BufferedImage read(File file),
boolean write(RenderedImage img, String format, File
output).
Image
W początkowych wersjach bibliotek graficznych
Javy podstawą pracy z obrazami była klasa
Java.awt.Image. Obiekty tej abstrakcyjnej
klasy nadrzędnej uzyskiwane są w sposób
zależny od urządzeń.
Podstawowa metoda zwracająca obiekt typu
Image (klasa Image jest abstrakcyjna), często
wykorzystywana w programach tworzonych w
Javie to getImage(). Metoda ta dla aplikacji
jest związana z klasą Toolkit, natomiast dla
appletówz klasą Applet.
Wywołanie metody getImage() polega albo na
podaniu ścieżki dostępu (jako String) lub
lokalizatora URL do obrazu przechowywanego
w formacie GIF lub JPEG. Przykładowo:
Image obraz = Toolkit.getDefaultToolkit.getImage("pic.gif");
-
zwraca
obiekt
obraz
na
podstawie
obrazu
przechowywanego w pliku pic.gif w bieżącej ścieżce
dostępu;
Image obraz = Toolkit.getDefaultToolkit.getImage(new
URL("http://.../pic.gif");
-
zwraca
obiekt
obraz
na
podstawie
obrazu
przechowywanego w pliku pic.gif na serwerze podanym
w URL.
Mając obiekt typu Image można obraz z nim
związany wyświetlić (narysować). W tym celu
należy wykorzystać jedną z metod drawImage().
W najprostszej metodzie drawImage() podając
jako argument obiekt typu Image, współrzędne
x,y oraz obserwatora (ImageObserver, często w
ciele
klasy
komponentu,
w którym się rysuje odwołanie do obserwatora
jest wskazaniem aktualnego obiektu komponentu
- this) możemy wyświetlić obrazu w dozwolonym
do tego elemencie. Inna wersja metody
drawImage()
umożliwia
skalowanie
wyświetlanego
obrazu
poprzez
podanie
dodatkowych argumentów: szerokość (width)
i wysokość (height).
public void paintComponent(Graphics g){
super.paintComponent(g);
Image img =
Toolkit.getDefaultToolkit().createImage(„image.png");
g.drawImage(img, 0,0, this);
}
Oprócz poznanych do tej pory operacji związanych
z obrazami (stworzenie obiektu Image, filtracja
danych,
wyświetlenie
i
skalowanie)
często
wykorzystuje się dwie z kilku istniejących metod
klasy Image, a mianowicie Image.getWidth() oraz
Image.getHeight().
Metody
te
umożliwiają
poznanie wymiarów obrazu, co jest często niezwykle
istotne z punktu widzenia ich wyświetlania
i przetwarzania.
BufferedImage
Obiekt
BufferedImage
może
być
stworzony
bezpośrednio w pamięci i użyty do przechowywania
i przetwarzania danych obrazu uzyskanego z pliku lub
poprzez URL. Obraz BufferedImage może być
wyświetlony
poprzez
użycie
obiektów
klasy
Graphics2D. Obiekt BufferedImage zawiera dwa istotne
obiekty: obiekt danych - Raster oraz model kolorów
ColorModel. Klasa Raster umożliwia zarządzanie
danymi obrazu. Na obiekt tej klasy składają się obiekty
DataBuffer oraz SampleModel. DataBuffer stanowi
macierz
wartości
próbek
obrazu,
natomiast
SampleModel określa sposób interpretacji tych próbek.
Przykładowo dla danego piksela próbki (RGB) mogą
być przechowywane w trzech różnych macierzach
(banded interleaved) lub w jednej macierzy w
formie przeplatanych próbek (pixel interleaved) dla
różnych komponentów (R1,G1,B1,R2,G2,B2,...).
Rolą SampleModel jest określenie jakiej formy użyto
do zapisu danych w macierzach. Najczęściej nie
tworzy się bezpośrednio obiektu Raster lecz
wykorzystuje
się
efekt
działania
obiektu
BufferedImage, który rozbija Image na Raster oraz
ColorModel. Niemniej istnieje możliwość stworzenia
obiektu
Raster
poprzez
stworzenie
obiektu
WritableRaster i podaniu go jako argumentu w
jednym z konstruktorów klasy BufferedImage.
public File img = new File("image.png");
public BufferedImage buffImg = new
BufferedImage(240, 240,
BufferedImage.TYPE_INT_ARGB);
buffImg = ImageIO.read(img);
Graphics2D g = newImage.createGraphics();
g.drawImage(in, 0, 0, null);
DZIĘKUJEMY ZA
UWAGĘ