Jump to: navigation, search

Difference between revisions of "GEF/GEF4/Graphics"

< GEF‎ | GEF4
m
m
 
(42 intermediate revisions by 2 users not shown)
Line 7: Line 7:
 
The GEF4 Graphics component provides a level of abstraction over different drawing toolkits (natives). At the moment, SWT and AWT backends are in development. Its goal is to be as complete as possible, i.e. you should have access to all the functionality that you have access to when working directly with one of the natives (SWT or AWT). Of course, this is not always viable. But we aim to provide at least the greatest common divisor of the functionality that is offered by the individual natives and additionally, decent simulations for operations which are not offered by all natives.
 
The GEF4 Graphics component provides a level of abstraction over different drawing toolkits (natives). At the moment, SWT and AWT backends are in development. Its goal is to be as complete as possible, i.e. you should have access to all the functionality that you have access to when working directly with one of the natives (SWT or AWT). Of course, this is not always viable. But we aim to provide at least the greatest common divisor of the functionality that is offered by the individual natives and additionally, decent simulations for operations which are not offered by all natives.
  
== Features ==
+
{|border="0" style="border:1px black solid;border-collapse:collapse" cellpadding="5" cellspacing="0" size="10"
 +
!style="border:1px black solid; color: grey"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]org.eclipse.gef4.graphics
 +
!bgcolor="#fffdc8" style="border:1px black solid"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]color
 +
!style="border:1px black solid"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]font
 +
!colspan="2" bgcolor="#fffdc8" style="border:1px black solid"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]image
 +
!style="border:1px black solid" bgcolor="#fffdc8"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]awt
 +
!style="border:1px black solid"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]swt
 +
|-
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-int_obj.gif]][[GEF/GEF4/Graphics#IGraphics|IGraphics]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#Color|Color]]
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#Font|Font]]
 +
|style="border-right:1px black solid" bgcolor="#fffdc8"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#Image|Image]]
 +
!style="border-right:1px black solid; border-bottom:1px black solid"|[[Image:GEF4Geometry-jdt-icons-package_obj.gif]]operations
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#AwtGraphics|AwtGraphics]]
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#SwtGraphics|SwtGraphics]]
 +
|-
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-int_obj.gif]][[GEF/GEF4/Graphics#IImageGraphics|IImageGraphics]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-int_obj.gif]][[GEF/GEF4/Graphics#IImageOperation|IImageOperation]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|-
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#GraphicsState|GraphicsState]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#ImageOperation|ImageOperations]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|-
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#Pattern|Pattern]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|-
 +
|style="border-right:1px grey solid"|[[Image:GEF4Geometry-jdt-icons-class_obj.gif]][[GEF/GEF4/Graphics#Gradient|Gradient]]
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|style="border-right:1px grey solid" bgcolor="#fffdc8"|
 +
|style="border-right:1px grey solid"|
 +
|}
 +
 
 +
=== Features ===
 +
 
 +
In this section you can find our feature-matrix. It presents the functionality offered by the GEF4 Graphics component in comparison to GEF 3.x Draw2d Graphics, SWT GC, and AWT Graphics2D.
  
 
{|border="0" borderwidth="10"
 
{|border="0" borderwidth="10"
Line 27: Line 78:
 
|-
 
|-
 
|Resolution independent rendering
 
|Resolution independent rendering
|<div style="background-color:#a90; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+/-<sup><span style="position:absolute">&nbsp;&nbsp;<span style="border-bottom:1px dotted; cursor:help;" title="Font size inconsistencies.">2</span></span></sup></div>
+
|<div style="background-color:#a90; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+/-<sup><span style="position:absolute">&nbsp;&nbsp;<span style="border-bottom:1px dotted; cursor:help;" title="Some inconsistencies, working on it.">2</span></span></sup></div>
 
|<div style="background-color:darkred; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">-</div>
 
|<div style="background-color:darkred; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">-</div>
 
|<div style="background-color:darkred; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">-</div>
 
|<div style="background-color:darkred; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">-</div>
Line 48: Line 99:
 
|'''Drawing geometric primitives'''
 
|'''Drawing geometric primitives'''
 
|-
 
|-
|Lines, polylines, rectangles, polygons, arcs, rounded-rectangles, and ellipses
+
|Lines, polylines, rectangles, polygons, arcs, rounded-rectangles, ellipses
 
|<div style="background-color:darkgreen; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+</div>
 
|<div style="background-color:darkgreen; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+</div>
 
|<div style="background-color:darkgreen; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+</div>
 
|<div style="background-color:darkgreen; color:white; font-weight:bold; border-radius:8px; -moz-border-radius:8px; text-align:center;">+</div>
Line 162: Line 213:
 
'''Footnotes:'''
 
'''Footnotes:'''
 
#Missing transformation: shearing.
 
#Missing transformation: shearing.
#Under development.
+
#Some inconsistencies, working on it.
 
#Not supported when e.g. path clipping is used.
 
#Not supported when e.g. path clipping is used.
 
#Implemented for quadratic and cubic Bezier curves.
 
#Implemented for quadratic and cubic Bezier curves.
Line 170: Line 221:
 
== IGraphics ==
 
== IGraphics ==
  
The heart of the GEF4 Graphics component is the IGraphics interface. Normally, you will be handed over an IGraphics to accomplish your displaying tasks by a surrounding framework, but it can be used stand-alone, too. Thereto, you have to create a specific IGraphics implementation. Let us consider the following SWT example:
+
* ''package: org.eclipse.gef4.graphics''
 +
 
 +
[[Image:GEF4Graphics-IGraphics-overview.png|right|IGraphics]]
 +
 
 +
The heart of the GEF4 Graphics component is the IGraphics interface. Normally, you will be handed over an IGraphics to accomplish your displaying tasks by a surrounding framework:
 +
 
 +
<br />
 +
[[Image:GEF4Graphics-IGraphics-context.png|IGraphics context]]
 +
<br />
 +
 
 +
To use it stand-alone, you have to create a specific IGraphics implementation. Let us consider the following SWT example:
  
 
''[Example 001: Simple Graphics]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example001.java Example001.java]
 
''[Example 001: Simple Graphics]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example001.java Example001.java]
Line 269: Line 330:
 
# The GEF4 Geometry component is integrated into the IGraphics interface, so that we can easily display geometry objects. Notably, the power of the draw() and fill() operations is directly coupled with the power of the Geometry component. All drawing primitives, such as lines, rectangles, ellipses, and many more, are represented by corresponding Geometry objects.
 
# The GEF4 Geometry component is integrated into the IGraphics interface, so that we can easily display geometry objects. Notably, the power of the draw() and fill() operations is directly coupled with the power of the Geometry component. All drawing primitives, such as lines, rectangles, ellipses, and many more, are represented by corresponding Geometry objects.
 
# The drawing operations of the IGraphics are influenced by a set of attributes which are managed by the IGraphics (draw-color, fill-color, etc.). A full set of attributes is referred to as a GraphicsState.
 
# The drawing operations of the IGraphics are influenced by a set of attributes which are managed by the IGraphics (draw-color, fill-color, etc.). A full set of attributes is referred to as a GraphicsState.
 
<br />
 
[[Image:GEF4Graphics-IGraphics-context.png|IGraphics context]]
 
<br />
 
  
 
There are four different drawing operations available on an IGraphics: draw(), fill(), write(), and paint().
 
There are four different drawing operations available on an IGraphics: draw(), fill(), write(), and paint().
Line 278: Line 335:
 
* Using the IGraphics#draw(ICurve) and IGraphics#draw(Path) methods, you can display the (contour of the) passed-in geometry object.
 
* Using the IGraphics#draw(ICurve) and IGraphics#draw(Path) methods, you can display the (contour of the) passed-in geometry object.
 
** For a reference of all available geometry objects, take a look at the GEF4 Geometry component ([[GEF/GEF4/Geometry]]).
 
** For a reference of all available geometry objects, take a look at the GEF4 Geometry component ([[GEF/GEF4/Geometry]]).
** Specific attributes: draw-pattern (Color, Gradient, and Image), stroke (dash-array, dash-begin, line-cap, line-join, line-width, miter-limit)
 
 
* Analogical, the IGraphics#fill(IShape), IGraphics#fill(IMultiShape), and IGraphics#fill(Path) methods will fill the interior of the passed-in geometry object.
 
* Analogical, the IGraphics#fill(IShape), IGraphics#fill(IMultiShape), and IGraphics#fill(Path) methods will fill the interior of the passed-in geometry object.
** Specific attributes: fill-pattern (Color, Gradient, and Image)
 
 
* Using the IGraphics#paint(Image) method, you can display the passed-in Image object.
 
* Using the IGraphics#paint(Image) method, you can display the passed-in Image object.
 
* Using the IGraphics#write(String) method, you can display the passed-in String object.
 
* Using the IGraphics#write(String) method, you can display the passed-in String object.
** Specific attributes: font, write-pattern (Color, Gradient, and Image), background-color
 
  
=== GraphicsState ===
+
=== States Stack ===
 +
 
 +
The IGraphics interface provides a state-stack-mechanism which can be used to elegantly avoid setting some attributes manually. Moreover, this stack is qualified for the transformation matrix and the clipping area, because the corresponding objects are seldom set explicitly but rather modified based on their current values.
 +
 
 +
On the top of the stack is the currently in-use GraphicsState. This is the GraphicsState you are accessing when calling any of the IGraphics#get*(*), IGraphics#is*(*), or IGraphics#set*(*) methods. You can duplicate the currently in-use GraphicsState on the states stack by calling IGraphics#pushState(). If you wish to reactivate a previously stored GraphicsState, use the IGraphics#popState() method. It will remove the top stack element, leaving the previously pushed GraphicsState as the new top stack element. To reactivate a previously stored GraphicsState without taking it from the stack, you can use the IGraphics#restoreState() method.
 +
 
 +
<source lang="Java">
 +
// TODO: states tack example using push/pop/restore
 +
</source>
 +
 
 +
Additionally, you can query an IGraphics for the currently in-use GraphicsState using the IGraphics#getState() method. Analogously, you can set the currently in-use GraphicsState for an IGraphics using the IGraphics#setState(GraphicsState) method.
 +
 
 +
<source lang="Java">
 +
// TODO: getState()/setState() example
 +
</source>
 +
 
 +
== IImageGraphics ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics''
 +
 
 +
[[Image:GEF4Graphics-IImageGraphics-overview.png|right|IImageGraphics]]
 +
 
 +
The IImageGraphics interface extends the IGraphics interface. If you want to render into an Image you have to construct an IImageGraphics for that Image. You can easily create it using the IGraphics#createImageGraphics(Image) method.
 +
 
 +
When drawing into a destination Image using an IImageGraphics, the drawing operations may be deferred. You can force an update of the destination Image by calling IImageGraphics#updateImage() or when destructing the IImageGraphics using IImageGraphics#cleanUp().
 +
 
 +
''[OffScreenExample]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/OffScreenExample.java OffScreenExample.java]
 +
<source lang="Java">
 +
/*******************************************************************************
 +
* Copyright (c) 2013 itemis AG and others.
 +
*
 +
* All rights reserved. This program and the accompanying materials
 +
* are made available under the terms of the Eclipse Public License v1.0
 +
* which accompanies this distribution, and is available at
 +
* http://www.eclipse.org/legal/epl-v10.html
 +
*
 +
* Contributors:
 +
*    Matthias Wienand (itemis AG) - initial API and implementation
 +
*
 +
*******************************************************************************/
 +
package org.eclipse.gef4.graphics.examples;
 +
 
 +
import java.util.Random;
 +
 
 +
public class OffScreenExample implements IExample {
 +
 
 +
private static final int PAD = 30;
 +
private static final int IMG_HEIGHT = 300;
 +
private static final int IMG_WIDTH = 400;
 +
 
 +
private Image image;
 +
 
 +
@Override
 +
public int getHeight() {
 +
return IMG_HEIGHT + PAD + PAD;
 +
}
 +
 
 +
@Override
 +
public String getTitle() {
 +
return "GEF4 Graphics - Off Screen Example";
 +
}
 +
 
 +
@Override
 +
public int getWidth() {
 +
return IMG_WIDTH + PAD + PAD;
 +
}
 +
 
 +
private void initResource(IGraphics g) {
 +
if (image == null) {
 +
image = new Image(IMG_WIDTH, IMG_HEIGHT, new Color(255, 255, 255));
 +
 
 +
IImageGraphics ig = g.createImageGraphics(image);
 +
 
 +
ig.setFill(new Gradient.Linear(new Point(), new Point(400, 300))
 +
.addStop(0, new Color(255, 255, 0))
 +
.addStop(0.25, new Color(255, 128, 0))
 +
.addStop(0.75, new Color(255, 255, 0))
 +
.addStop(1, new Color(255, 0, 0)));
 +
 
 +
ig.fill(new Rectangle(0, 0, IMG_WIDTH, IMG_HEIGHT));
 +
 
 +
// draw bubbles
 +
Random rng = new Random(System.currentTimeMillis());
 +
for (int i = 0; i < 25; i++) {
 +
int side = rng.nextInt(35) + 15;
 +
Ellipse bubble = new Ellipse(0, 0, side, side);
 +
 
 +
ig.pushState().translate(rng.nextInt(IMG_WIDTH - 50),
 +
rng.nextInt(IMG_HEIGHT - 50));
 +
 
 +
ig.setFill(new Gradient.Radial(bubble).addStop(0,
 +
new Color(64, 255, 255)).addStop(1,
 +
new Color(64, 64, 255)));
 +
ig.fill(bubble);
 +
 
 +
ig.popState();
 +
}
 +
 
 +
ig.cleanUp();
 +
}
 +
}
 +
 
 +
@Override
 +
public void renderScene(IGraphics g) {
 +
initResource(g);
 +
g.translate(PAD, PAD);
 +
g.paint(image);
 +
}
 +
 
 +
}
 +
</source>
 +
[[Image:GEF4Graphics-OffScreenExample.png|Off Screen Example (AWT)]]
 +
 
 +
== GraphicsState ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics''
  
 
[[Image:GEF4Graphics-GraphicsState-overview.png|right|GraphicsState]]
 
[[Image:GEF4Graphics-GraphicsState-overview.png|right|GraphicsState]]
Line 311: Line 480:
 
* '''Font = Times New Roman, 16pt, normal'''<br />Specifies the font to use for write() operations.
 
* '''Font = Times New Roman, 16pt, normal'''<br />Specifies the font to use for write() operations.
  
Additional to these attributes, a GraphicsState consists of four general attributes, which will affect all drawing operations:
+
Additional to these attributes, a GraphicsState consists of several general attributes, which will affect all drawing operations:
  
 
* '''Device-DPI = ?'''<br />The dots per inch (DPI) of the current rendering device. The default value is queried by an IGraphics implementation from the corresponding native.
 
* '''Device-DPI = ?'''<br />The dots per inch (DPI) of the current rendering device. The default value is queried by an IGraphics implementation from the corresponding native.
Line 322: Line 491:
 
* '''Xor-Mode-Emulation = false'''<br />If enabled, xor-mode rendering is always emulated if the current native does not provide xor-mode rendering on all platforms. If disabled, xor-mode rendering may be emulated on some platforms but it is delegated to the current native when possible.
 
* '''Xor-Mode-Emulation = false'''<br />If enabled, xor-mode rendering is always emulated if the current native does not provide xor-mode rendering on all platforms. If disabled, xor-mode rendering may be emulated on some platforms but it is delegated to the current native when possible.
  
=== Font ===
+
=== Pattern ===
  
A Font object stores font family, size, and style.
+
[[Image:GEF4Graphics-Pattern-overview.png|right|Pattern]]
  
=== Color ===
+
The Pattern class maintains three objects which can serve as color sources for the IGraphics#draw(), IGraphics#fill(), and IGraphics#write() methods. Those three objects are a Color, a Gradient, and an Image. The Pattern's Mode - which is one of COLOR, GRADIENT, or IMAGE - specifies which of the three is currently active, i.e. to be used as a color source.
  
A Color object stores the red, green, blue, and alpha component of a color in the RGBA color space.
+
<!-- <source lang="Java">
 +
// TODO: image fill example
 +
</source> -->
  
=== Gradient ===
+
In the following example, an IGraphics' write-Pattern is set (using IGraphics#setWrite(Gradient)) to a linear Gradient. After that, letters of displayed text are filled with the specified color gradient.
 +
 
 +
''[WritePatternExample]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/WritePatternExample.java WritePatternExample.java]
 +
<source lang="Java">
 +
* Copyright (c) 2013 itemis AG and others.
 +
package org.eclipse.gef4.graphics.examples;
 +
 
 +
import org.eclipse.gef4.geometry.planar.Dimension;
 +
 
 +
public class WritePatternExample implements IExample {
 +
 
 +
@Override
 +
public int getHeight() {
 +
return 300;
 +
}
 +
 
 +
@Override
 +
public String getTitle() {
 +
return "Write Pattern Example";
 +
}
 +
 
 +
@Override
 +
public int getWidth() {
 +
return 600;
 +
}
 +
 
 +
@Override
 +
public void renderScene(IGraphics g) {
 +
Gradient.Linear gradient = new Gradient.Linear(new Point(), new Point(
 +
100, 0), CycleMode.REFLECT);
 +
gradient.addStop(0, new Color(255, 0, 0));
 +
gradient.addStop(1, new Color(255, 255, 0));
 +
g.setWrite(gradient);
 +
g.setFont(new Font("Courier New", 32, Font.STYLE_BOLD
 +
| Font.STYLE_UNDERLINED));
 +
 
 +
g.setDraw(new Color(0, 0, 255));
 +
g.draw(new Rectangle(0, 0, 100, 100).getOutline());
 +
 
 +
String text = getTitle();
 +
Dimension textSize = g.getTextDimension(text);
 +
g.write(text);
 +
g.translate(50, textSize.height);
 +
g.write(text);
 +
}
 +
}
 +
</source>
 +
[[Image:GEF4Graphics-WritePatternExample.png|Write Pattern Example (AWT)]]
 +
 
 +
== Font ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics.font''
 +
 
 +
[[Image:GEF4Graphics-Font-overview.png|right|Font]]
 +
 
 +
A Font object stores font family, size, and style. Text rendering is currently a less-marked feature of the component. Nonetheless, using these attributes you can apply simple styles to your texts. The size is interpreted in points; fractional sizes are allowed. The style is a bitwise-OR combination of the following constants:
 +
 
 +
* NORMAL<br />Text is displayed plain, i.e. normal font weight, roman type, not underlined.
 +
* BOLD<br />Text is displayed bold, i.e. with increased weight.
 +
* ITALIC<br />Text is displayed in italic type, i.e. slanted.
 +
* UNDERLINED<br />Text is displayed underlined.
 +
 
 +
The following example shows text rendering with font sizes from 3.5pt to 32.5pt:
 +
 
 +
''[FontSizeExample]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/FontSizeExample.java FontSizeExample.java]
 +
<source lang="Java">
 +
/*******************************************************************************
 +
* Copyright (c) 2013 itemis AG and others.
 +
*
 +
* All rights reserved. This program and the accompanying materials
 +
* are made available under the terms of the Eclipse Public License v1.0
 +
* which accompanies this distribution, and is available at
 +
* http://www.eclipse.org/legal/epl-v10.html
 +
*
 +
* Contributors:
 +
*    Matthias Wienand (itemis AG) - initial API and implementation
 +
*
 +
*******************************************************************************/
 +
package org.eclipse.gef4.graphics.examples;
 +
 
 +
import org.eclipse.gef4.geometry.planar.Dimension;
 +
import org.eclipse.gef4.graphics.IGraphics;
 +
 
 +
public class FontSizeExample implements IExample {
 +
 
 +
private static final int PAD = 10;
 +
 
 +
@Override
 +
public int getHeight() {
 +
return 600;
 +
}
 +
 
 +
@Override
 +
public String getTitle() {
 +
return "Font Size Example";
 +
}
 +
 
 +
@Override
 +
public int getWidth() {
 +
return 800;
 +
}
 +
 
 +
@Override
 +
public void renderScene(IGraphics g) {
 +
double y = PAD, x = PAD;
 +
g.translate(x, y);
 +
for (double size = 3.5; size < 33; size += 0.5) {
 +
String text = "Text in size " + size + "pt";
 +
g.setFontSize(size);
 +
Dimension dim = g.getTextDimension(text);
 +
y += dim.height;
 +
if (y > getHeight()) {
 +
g.translate(PAD + dim.width, PAD + dim.height - y);
 +
y = dim.height + PAD;
 +
}
 +
g.write(text);
 +
g.translate(0, dim.height);
 +
}
 +
}
 +
 
 +
}
 +
</source>
 +
[[Image:GEF4Graphics-FontSizeExample-SWT.png|Font Size Example (SWT)]]
 +
 
 +
== Color ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics.color''
 +
 
 +
[[Image:GEF4Graphics-Color-overview.png|right|Color]]
 +
 
 +
A Color object stores the red, green, blue, and alpha components of a color in the RGBA color space. The individual channel values are limited to the range [0;255]. An alpha channel value of 0 signifies a fully transparent and a value of 255 a fully opaque color.
 +
 
 +
You can blend two Colors using one of the Color#getBlended(Color, ...) methods. They are used internally to generate gradient colors.
 +
 
 +
''[ColorBlendExample]''
 +
<source lang="Java">
 +
Color white = new Color(255, 255, 255);
 +
Color red = new Color(255, 0, 0);
 +
Color whiteRed = white.getBlended(red, 0.5);
 +
 
 +
Color cyan = new Color(0, 255, 255);
 +
Color magenta = new Color(255, 0, 255);
 +
Color cyanMagenta = cyan.getBlended(magenta, 0.5, 2.2); // gamma correction x^(1 / 2.2)
 +
 
 +
//...
 +
</source>
 +
[[Image:GEF4Graphics-ColorBlendExample-SWT.png|Color Blend Example (SWT)]]
 +
 
 +
When working with image data the Color class provides utility methods to extract channel values of a pixel, to create a Color object from a pixel, and to get a pixel representation of a Color object.
 +
 
 +
== Gradient ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics''
 +
 
 +
[[Image:GEF4Graphics-Gradient-overview.png|right|Gradient]]
  
 
A Gradient object stores a linear or radial, cyclic or acyclic, multi-stop color gradient. Therefore it manages a list of gradient-stops which consist of a percentual distance from the gradient's start location and a Color object. The gradient-stops specify the colors of the gradient at the stops' distances. Note that no gamma-correction is applied to the gradients.
 
A Gradient object stores a linear or radial, cyclic or acyclic, multi-stop color gradient. Therefore it manages a list of gradient-stops which consist of a percentual distance from the gradient's start location and a Color object. The gradient-stops specify the colors of the gradient at the stops' distances. Note that no gamma-correction is applied to the gradients.
  
'''Gradient.Linear'''
+
=== Gradient.Linear ===
  
 
''[Example002: Gradient.Linear]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example002.java Example002.java]
 
''[Example002: Gradient.Linear]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example002.java Example002.java]
Line 351: Line 676:
 
A linear gradient is defined by a start and an end Point. In the example, the top-left and top-right corners of the Rectangle to fill are used. The three stops define color transitions from white to red and from red to black.
 
A linear gradient is defined by a start and an end Point. In the example, the top-left and top-right corners of the Rectangle to fill are used. The three stops define color transitions from white to red and from red to black.
  
'''Gradient.Radial'''
+
=== Gradient.Radial ===
  
 
''[Example003: Gradient.Radial]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example003.java Example003.java]
 
''[Example003: Gradient.Radial]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example003.java Example003.java]
Line 368: Line 693:
 
A radial gradient is defined by an Ellipse (border) and a focus Point. The focus Point determines where the gradient starts, i.e. the percentual distance at that Point is 0. The three stops define color transitions from white to red and from red to black.
 
A radial gradient is defined by an Ellipse (border) and a focus Point. The focus Point determines where the gradient starts, i.e. the percentual distance at that Point is 0. The three stops define color transitions from white to red and from red to black.
  
Another interesting feature of GEF4 Gradients is the '''CycleMode'''. It defines the colors of a gradient outside of the gradient area.
+
=== CycleMode ===
  
 
''[Example004: Gradients: CycleMode]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example004.java Example004.java]
 
''[Example004: Gradients: CycleMode]'' [http://git.eclipse.org/c/gef/org.eclipse.gef4.git/tree/org.eclipse.gef4.graphics.examples/src/org/eclipse/gef4/graphics/examples/doc/Example004.java Example004.java]
Line 384: Line 709:
 
[[Image:GEF4Graphics-Example004.png|Gradients: CycleMode example]]
 
[[Image:GEF4Graphics-Example004.png|Gradients: CycleMode example]]
  
=== Image ===
+
The CycleMode defines the colors of a gradient outside of the gradient area. For linear gradients, this is beyond their start and end points. For radial gradients, this is beyond their boundary (Ellipse). You can choose one of three CycleModes:
 +
 
 +
* ''NO_CYCLE''<br />The Color of the nearest gradient-stop is used outside of the gradient area.
 +
* ''REFLECT''<br />The gradient-stops are reflected outside of the gradient area.
 +
* ''REPEAT''<br />The gradient-stops are repeated outside of the gradient area.
 +
 
 +
== Image ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics.image''
 +
 
 +
[[Image:GEF4Graphics-Image-overview.png|right|Image]]
 +
 
 +
The Image class stores rectangular image data. Individual pixels are stored in the ARGB color space using ints (32bit): 0xAARRGGBB. At the time of writing, the API does not provide Image I/O.
 +
 
 +
Information on an Image:
 +
<source lang="Java">
 +
int width = image.getWidth();
 +
int height = image.getHeight();
 +
Rectangle bounds = image.getBounds();
 +
 
 +
int[] redHistogram = image.getRedHistogram();
 +
int[] greenHistogram = image.getGreenHistogram();
 +
int[] blueHistogram = image.getBlueHistogram();
 +
int[] alphaHistogram = image.getAlphaHistogram();
 +
 
 +
int pixel = image.getPixel(x, y);
 +
int[] row = image.getPixelRow(y);
 +
int[] data = image.getPixels();
 +
</source>
 +
 
 +
Image creation:
 +
<source lang="Java">
 +
Image new = new Image(); // 1x1, black
 +
Image new = new Image(400, 300); // 400x300, black
 +
Image new = new Image(400, 300, new Color(255, 0, 0)); // 400x300, red
 +
Image copy = image.getCopy();
 +
Image subImage = image.getSubImage(x, y, width, height);
 +
Image bigImage = image.getScaled(2);
 +
Image thumb = image.getThumbnail(maxWidth, maxHeight);
 +
Image operated = image.apply(imageOperation);
 +
</source>
 +
 
 +
Image manipulation:
 +
<source lang="Java">
 +
image.setPixel(x, y, color);
 +
image.setPixels(...);
 +
</source>
 +
 
 +
== IImageOperation ==
 +
 
 +
* ''package: org.eclipse.gef4.graphics.image.operations''
 +
 
 +
[[Image:GEF4Graphics-IImageOperation-overview.png|right|IImageOperation]]
 +
 
 +
The IImageOperation interface specifies one single method IImageOperation#apply(Image) which takes an Image argument and returns another Image representing the result of the particular operation. Some IImageOperation implementations, such as common arithmetic operations (addition, difference, multiplication, division), are provided by GEF4. Take a look at the ImageOperations class below for more information on those implementations.
 +
 
 +
Of course you can create your own IImageOperations. The following example implements channel-wise histogram equalization. The left halve of the image is displayed unmodified. The right halve of the image is displayed after applying histogram equalization to it:
 +
 
 +
''[ImageOperationExample]''
 +
<source lang="Java">
 +
/*******************************************************************************
 +
* Copyright (c) 2013 itemis AG and others.
 +
*
 +
* All rights reserved. This program and the accompanying materials
 +
* are made available under the terms of the Eclipse Public License v1.0
 +
* which accompanies this distribution, and is available at
 +
* http://www.eclipse.org/legal/epl-v10.html
 +
*
 +
* Contributors:
 +
*    Matthias Wienand (itemis AG) - initial API and implementation
 +
*
 +
*******************************************************************************/
 +
package org.eclipse.gef4.graphics.examples;
 +
 
 +
import java.io.IOException;
 +
 
 +
import javax.imageio.ImageIO;
 +
 
 +
import org.eclipse.gef4.geometry.planar.Rectangle;
 +
import org.eclipse.gef4.graphics.IGraphics;
 +
import org.eclipse.gef4.graphics.color.Color;
 +
import org.eclipse.gef4.graphics.image.Image;
 +
import org.eclipse.gef4.graphics.image.operations.IImageOperation;
 +
 
 +
public class ImageOperationExample implements IExample {
 +
 
 +
class HistogramEqualizer implements IImageOperation {
 +
 
 +
@Override
 +
public Image apply(Image image) {
 +
int[] equRed = genEqualizer(image, image.getRedHistogram());
 +
int[] equGreen = genEqualizer(image, image.getGreenHistogram());
 +
int[] equBlue = genEqualizer(image, image.getBlueHistogram());
 +
 
 +
Image result = image.getCopy();
 +
 
 +
for (int x = 0; x < image.getWidth(); x++) {
 +
for (int y = 0; y < image.getHeight(); y++) {
 +
int[] rgba = Color.getPixelRGBA(image.getPixel(x, y));
 +
int resPixel = Color.getPixel(equRed[rgba[0]],
 +
equGreen[rgba[1]], equBlue[rgba[2]], rgba[3]);
 +
result.setPixel(x, y, resPixel);
 +
}
 +
}
 +
 
 +
return result;
 +
}
 +
 
 +
private int[] genEqualizer(Image image, int[] hist) {
 +
int[] cdf = new int[256];
 +
int cdfMin = 0;
 +
boolean noHist = true;
 +
 
 +
cdf[0] = hist[0];
 +
 
 +
if (hist[0] > 0) {
 +
cdfMin = cdf[0];
 +
noHist = false;
 +
}
 +
 
 +
for (int i = 1; i < 256; i++) {
 +
cdf[i] = cdf[i - 1] + hist[i];
 +
if (noHist && hist[i] > 0) {
 +
cdfMin = hist[i];
 +
noHist = false;
 +
}
 +
}
 +
 
 +
int[] equalizer = new int[256];
 +
double s = 255d / (image.getWidth() * image.getHeight());
 +
for (int i = 0; i < 256; i++) {
 +
equalizer[i] = (int) ((cdf[i] - cdfMin) * s);
 +
}
 +
 
 +
return equalizer;
 +
}
 +
}
 +
 
 +
private static String IMAGE_FILE = "tour-eiffel_notre-dame.jpg";
 +
 
 +
private Image image;
 +
 
 +
@Override
 +
public int getHeight() {
 +
return 460;
 +
}
 +
 
 +
@Override
 +
public String getTitle() {
 +
return "Image Operation Example - Histogram Equalization";
 +
}
 +
 
 +
@Override
 +
public int getWidth() {
 +
return 680;
 +
}
 +
 
 +
private void loadImage() {
 +
if (image == null) {
 +
try {
 +
image = new Image(ImageIO.read(OverviewExample.class
 +
.getResource(IMAGE_FILE)));
 +
} catch (IOException x) {
 +
System.out.println("Cannot load image file '" + IMAGE_FILE
 +
+ "':");
 +
x.printStackTrace();
 +
}
 +
}
 +
}
 +
 
 +
@Override
 +
public void renderScene(IGraphics g) {
 +
loadImage();
 +
Rectangle halve = image.getBounds().getShrinked(0, 0,
 +
0.5 * image.getWidth(), 0);
 +
g.translate(10, 10).pushState().intersectClip(halve);
 +
g.paint(image);
 +
g.popState().intersectClip(halve.getTranslated(halve.getWidth(), 0));
 +
g.paint(new HistogramEqualizer().apply(image));
 +
}
 +
}
 +
</source>
 +
[[Image:GEF4Graphics-ImageOperationExample-AWT.png|Image Operation Example (AWT)]]
 +
 
 +
=== ImageOperations ===
 +
 
 +
[[Image:GEF4Graphics-ImageOperations-overview.png|ImageOperations]]
  
 
== How to ==
 
== How to ==
Line 465: Line 976:
  
 
=== How to do image arithmetic ===
 
=== How to do image arithmetic ===
 +
 +
== Native-specific ==
 +
 +
=== AwtGraphics ===
 +
 +
* ''package: org.eclipse.gef4.graphics.awt''
 +
 +
=== SwtGraphics ===
 +
 +
* ''package: org.eclipse.gef4.graphics.swt''
  
 
[[Category:GEF]]
 
[[Category:GEF]]

Latest revision as of 09:14, 28 March 2013

Note to non-wiki readers: This documentation is generated from the Eclipse wiki - if you have corrections or additions it would be awesome if you added them in the original wiki page.


Introduction

The GEF4 Graphics component provides a level of abstraction over different drawing toolkits (natives). At the moment, SWT and AWT backends are in development. Its goal is to be as complete as possible, i.e. you should have access to all the functionality that you have access to when working directly with one of the natives (SWT or AWT). Of course, this is not always viable. But we aim to provide at least the greatest common divisor of the functionality that is offered by the individual natives and additionally, decent simulations for operations which are not offered by all natives.

GEF4Geometry-jdt-icons-package obj.giforg.eclipse.gef4.graphics GEF4Geometry-jdt-icons-package obj.gifcolor GEF4Geometry-jdt-icons-package obj.giffont GEF4Geometry-jdt-icons-package obj.gifimage GEF4Geometry-jdt-icons-package obj.gifawt GEF4Geometry-jdt-icons-package obj.gifswt
GEF4Geometry-jdt-icons-int obj.gifIGraphics GEF4Geometry-jdt-icons-class obj.gifColor GEF4Geometry-jdt-icons-class obj.gifFont GEF4Geometry-jdt-icons-class obj.gifImage GEF4Geometry-jdt-icons-package obj.gifoperations GEF4Geometry-jdt-icons-class obj.gifAwtGraphics GEF4Geometry-jdt-icons-class obj.gifSwtGraphics
GEF4Geometry-jdt-icons-int obj.gifIImageGraphics GEF4Geometry-jdt-icons-int obj.gifIImageOperation
GEF4Geometry-jdt-icons-class obj.gifGraphicsState GEF4Geometry-jdt-icons-class obj.gifImageOperations
GEF4Geometry-jdt-icons-class obj.gifPattern
GEF4Geometry-jdt-icons-class obj.gifGradient

Features

In this section you can find our feature-matrix. It presents the functionality offered by the GEF4 Graphics component in comparison to GEF 3.x Draw2d Graphics, SWT GC, and AWT Graphics2D.

GEF4 Graphics GEF 3.x Draw2d SWT AWT
General
Affine coordinate transformations
+
+/-  1
+
+
how-to
Resolution independent rendering
+/-  2
-
-
-
State stack mechanism: push/pop/restore
+
+/-  3
-
-
how-to
Off-screen rendering support
+
?
+
+
how-to
Drawing geometric primitives
Lines, polylines, rectangles, polygons, arcs, rounded-rectangles, ellipses
+
+
+
+
how-to
Arbitrary Bezier curves, curved-polygons, and polybeziers
+
+/-  4
+/-  4
+/-  4
how-to
Arbitrary clipping area
+
+
+
+
how-to
Basic stroke: width, caps, joins, dashes
+
+
+
+
how-to
Multi-stop, cyclic/acyclic, linear gradients
+
+/-  5
+/-  5
+
how-to
Multi-stop, cyclic/acyclic, radial gradients
+
-
-
+
how-to
Image fill
+
+
+
+
how-to
Displaying text
Basic text drawing
+
+
+
+
how-to
Font styles: italic, bold, and underlined
+
+/-  6
+/-  6
+/-  6
how-to
Filling text with a gradient
+
-
-
+
how-to
Filling text with image data
+
-
-
+
how-to
Image operations
Basic image drawing
+
+
+
+
how-to
Image resizing
+
+
+
+
how-to
Image blurring
+
-
-
+
how-to
Combining images via standard arithmetic or logical operations
+
-
-
-
how-to


Footnotes:

  1. Missing transformation: shearing.
  2. Some inconsistencies, working on it.
  3. Not supported when e.g. path clipping is used.
  4. Implemented for quadratic and cubic Bezier curves.
  5. Only single-stop, acyclic, linear gradients supported.
  6. Missing font style: underlined.

IGraphics

  • package: org.eclipse.gef4.graphics
IGraphics

The heart of the GEF4 Graphics component is the IGraphics interface. Normally, you will be handed over an IGraphics to accomplish your displaying tasks by a surrounding framework:


IGraphics context

To use it stand-alone, you have to create a specific IGraphics implementation. Let us consider the following SWT example:

[Example 001: Simple Graphics] Example001.java

/*******************************************************************************
 * Copyright (c) 2012, 2013 itemis AG and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Matthias Wienand (itemis AG) - initial API and implementation
 *     
 *******************************************************************************/
package org.eclipse.gef4.graphics.examples.doc;
 
import org.eclipse.gef4.geometry.planar.Ellipse;
import org.eclipse.gef4.geometry.planar.Polygon;
import org.eclipse.gef4.geometry.planar.Rectangle;
import org.eclipse.gef4.graphics.IGraphics;
import org.eclipse.gef4.graphics.LineCap;
import org.eclipse.gef4.graphics.LineJoin;
import org.eclipse.gef4.graphics.color.Color;
import org.eclipse.gef4.graphics.swt.SwtGraphics;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
 
public class Example001 implements PaintListener {
 
	public static void main(String[] args) {
		new Example001("Simple Graphics");
	}
 
	public Example001(String title) {
		Display display = new Display();
 
		Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
		shell.setText(title);
		shell.setBounds(0, 0, 640, 480);
		shell.open();
 
		shell.addPaintListener(this);
		shell.redraw(); // platform independently triggers a PaintEvent
 
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}
 
	@Override
	public void paintControl(PaintEvent e) {
		SwtGraphics g = new SwtGraphics(e.gc);
		renderScene(g);
		g.cleanUp();
	}
 
	public void renderScene(IGraphics g) {
		// The rendering code goes here. It is independent of the actual
		// IGraphics implementation. Therefore, it is independent of the
		// underlying drawing toolkit, too.
 
		final Ellipse ellipse = new Ellipse(50, 50, 350, 200);
		final Rectangle rectangle = new Rectangle(100, 160, 125, 220);
		final Polygon triangle = new Polygon(260, 170, 190, 300, 330, 300);
 
		g.setFill(new Color(255, 0, 0)).setDraw(new Color(128, 0, 0))
				.setDashArray(25, 10).setLineWidth(3);
 
		g.fill(ellipse).draw(ellipse.getOutline());
 
		g.setFill(new Color(0, 0, 255)).setDraw(new Color())
				.setLineJoin(LineJoin.ROUND).setLineCap(LineCap.ROUND);
 
		g.fill(rectangle).draw(rectangle.getOutline());
 
		g.setFill(new Color(0, 255, 0)).setDraw(new Color(0, 128, 0))
				.setLineJoin(LineJoin.MITER);
 
		g.fill(triangle).draw(triangle.getOutline());
	}
 
}

Simple GEF4 Graphics example (SWT)

[Note: You can tryout the examples in your local GEF4 installation. Every example shown in this documentation exists in the org.eclipse.gef4.graphics.examples project under the org.eclipse.gef4.graphics.examples.doc package. The examples are easily found via their identification number which is written atop the source code.]

As you can see in this example, the SwtGraphics is an IGraphics implementation. It can be constructed via a SWT GC which is passed-in to the paintControl() event handler. The renderScene() method does not know anything about the actual IGraphics implemention that is used. That's why we would not need to adjust our rendering code when switching to AWT, for example. You may wonder why we have to call the cleanUp() method on the IGraphics. In the case of SWT, this is necessary to fully free the system resources that will be allocated during the rendering process.

When looking at the code, there are two important observations:

  1. The GEF4 Geometry component is integrated into the IGraphics interface, so that we can easily display geometry objects. Notably, the power of the draw() and fill() operations is directly coupled with the power of the Geometry component. All drawing primitives, such as lines, rectangles, ellipses, and many more, are represented by corresponding Geometry objects.
  2. The drawing operations of the IGraphics are influenced by a set of attributes which are managed by the IGraphics (draw-color, fill-color, etc.). A full set of attributes is referred to as a GraphicsState.

There are four different drawing operations available on an IGraphics: draw(), fill(), write(), and paint().

  • Using the IGraphics#draw(ICurve) and IGraphics#draw(Path) methods, you can display the (contour of the) passed-in geometry object.
    • For a reference of all available geometry objects, take a look at the GEF4 Geometry component (GEF/GEF4/Geometry).
  • Analogical, the IGraphics#fill(IShape), IGraphics#fill(IMultiShape), and IGraphics#fill(Path) methods will fill the interior of the passed-in geometry object.
  • Using the IGraphics#paint(Image) method, you can display the passed-in Image object.
  • Using the IGraphics#write(String) method, you can display the passed-in String object.

States Stack

The IGraphics interface provides a state-stack-mechanism which can be used to elegantly avoid setting some attributes manually. Moreover, this stack is qualified for the transformation matrix and the clipping area, because the corresponding objects are seldom set explicitly but rather modified based on their current values.

On the top of the stack is the currently in-use GraphicsState. This is the GraphicsState you are accessing when calling any of the IGraphics#get*(*), IGraphics#is*(*), or IGraphics#set*(*) methods. You can duplicate the currently in-use GraphicsState on the states stack by calling IGraphics#pushState(). If you wish to reactivate a previously stored GraphicsState, use the IGraphics#popState() method. It will remove the top stack element, leaving the previously pushed GraphicsState as the new top stack element. To reactivate a previously stored GraphicsState without taking it from the stack, you can use the IGraphics#restoreState() method.

// TODO: states tack example using push/pop/restore

Additionally, you can query an IGraphics for the currently in-use GraphicsState using the IGraphics#getState() method. Analogously, you can set the currently in-use GraphicsState for an IGraphics using the IGraphics#setState(GraphicsState) method.

// TODO: getState()/setState() example

IImageGraphics

  • package: org.eclipse.gef4.graphics
IImageGraphics

The IImageGraphics interface extends the IGraphics interface. If you want to render into an Image you have to construct an IImageGraphics for that Image. You can easily create it using the IGraphics#createImageGraphics(Image) method.

When drawing into a destination Image using an IImageGraphics, the drawing operations may be deferred. You can force an update of the destination Image by calling IImageGraphics#updateImage() or when destructing the IImageGraphics using IImageGraphics#cleanUp().

[OffScreenExample] OffScreenExample.java

/*******************************************************************************
 * Copyright (c) 2013 itemis AG and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Matthias Wienand (itemis AG) - initial API and implementation
 * 
 *******************************************************************************/
package org.eclipse.gef4.graphics.examples;
 
import java.util.Random;
 
public class OffScreenExample implements IExample {
 
	private static final int PAD = 30;
	private static final int IMG_HEIGHT = 300;
	private static final int IMG_WIDTH = 400;
 
	private Image image;
 
	@Override
	public int getHeight() {
		return IMG_HEIGHT + PAD + PAD;
	}
 
	@Override
	public String getTitle() {
		return "GEF4 Graphics - Off Screen Example";
	}
 
	@Override
	public int getWidth() {
		return IMG_WIDTH + PAD + PAD;
	}
 
	private void initResource(IGraphics g) {
		if (image == null) {
			image = new Image(IMG_WIDTH, IMG_HEIGHT, new Color(255, 255, 255));
 
			IImageGraphics ig = g.createImageGraphics(image);
 
			ig.setFill(new Gradient.Linear(new Point(), new Point(400, 300))
					.addStop(0, new Color(255, 255, 0))
					.addStop(0.25, new Color(255, 128, 0))
					.addStop(0.75, new Color(255, 255, 0))
					.addStop(1, new Color(255, 0, 0)));
 
			ig.fill(new Rectangle(0, 0, IMG_WIDTH, IMG_HEIGHT));
 
			// draw bubbles
			Random rng = new Random(System.currentTimeMillis());
			for (int i = 0; i < 25; i++) {
				int side = rng.nextInt(35) + 15;
				Ellipse bubble = new Ellipse(0, 0, side, side);
 
				ig.pushState().translate(rng.nextInt(IMG_WIDTH - 50),
						rng.nextInt(IMG_HEIGHT - 50));
 
				ig.setFill(new Gradient.Radial(bubble).addStop(0,
						new Color(64, 255, 255)).addStop(1,
						new Color(64, 64, 255)));
				ig.fill(bubble);
 
				ig.popState();
			}
 
			ig.cleanUp();
		}
	}
 
	@Override
	public void renderScene(IGraphics g) {
		initResource(g);
		g.translate(PAD, PAD);
		g.paint(image);
	}
 
}

Off Screen Example (AWT)

GraphicsState

  • package: org.eclipse.gef4.graphics
GraphicsState

A GraphicsState represents one set of IGraphics attributes. The following list presents all available attributes, default values, and a short description of the attributes.

Draw-specific attributes:

  • Draw-Pattern = black
    Specifies the draw-pattern which consists of a Color, a Gradient, an Image, and a Mode. The pattern's mode specifies which of the three values (Color, Gradient, and Image) is queried for the drawing color.
  • Dash-Array = {}
    Specifies a double[] consisting of distance values which alternatingly specify opaque and transparent sections.
  • Dash-Begin = 0
    Specifies the initially assumed covered distance when applying the DashArray.
  • LineCap = FLAT
    Specifies how to display unconnected end points of displayed lines. A FLAT LineCap will not extend a drawn line beyond its unconnected end points. A ROUND LineCap will draw a semi-circle at the unconnected end points of a displayed line. A SQUARE LineCap will extend a drawn line beyond its unconnected end points by half the line's width.
  • LineJoin = BEVEL
    Specifies how to display the connection point of two displayed lines. A BEVEL LineJoin fills the bent corner triangular. A MITER LineJoin fills the bent corner up to the intersection point of the two outermost lines if its distance to the middle intersection is less than or equal to the MiterLimit. In case of exceeding the MiterLimit, the BEVEL LineJoin is used.
  • Line-Width = 1
    Specifies the width of displayed lines.
  • Miter-Limit = 10
    Restricts the use of the MITER LineJoin, because for low intersection angles, the intersection point may lie far away from the original connection point. Its value is the maximal quotient of the distance between the intersection point and the connection point and the line width.

Fill-specific attributes:

  • Fill-Pattern = black
    Specifies the fill-pattern which consists of a Color, a Gradient, an Image, and a Mode. The pattern's mode specifies which of the three values (Color, Gradient, and Image) is queried for the filling color.

Write-specific attributes:

  • Write-Pattern = black
    Specifies the write-pattern which consists of a Color, a Gradient, an Image, and a Mode. The pattern's Mode specifies which of the three values (Color, Gradient, and Image) is queried for the color to write the text in.
  • Write-Background = transparent white
    Specifies the background color for write() operations.
  • Font = Times New Roman, 16pt, normal
    Specifies the font to use for write() operations.

Additional to these attributes, a GraphicsState consists of several general attributes, which will affect all drawing operations:

  • Device-DPI = ?
    The dots per inch (DPI) of the current rendering device. The default value is queried by an IGraphics implementation from the corresponding native.
  • Logical-DPI = 96
    The dots per inch (DPI) which is assumed by your application.
  • AffineTransform = identity transform
    Transforms the coordinate system before applying any drawing operations.
  • Clip = null
    Specifies a Path which serves as the clipping area for all subsequent drawing operations. Setting the clip to null disables clipping.
  • Antialiasing = true
    If enabled, anti-aliasing is used to smooth drawn edges.
  • InterpolationHint = QUALITY
    When displaying a transformed Image, the InterpolationHint specifies whether to apply a fast and low-quality (InterpolationHint#SPEED) interpolation, or to apply a slower but higher-quality (InterpolationHint#QUALITY) interpolation.
  • Xor-Mode = false
    If enabled, combines source and destination colors via binary exclusive-or when drawing.
  • Xor-Mode-Emulation = false
    If enabled, xor-mode rendering is always emulated if the current native does not provide xor-mode rendering on all platforms. If disabled, xor-mode rendering may be emulated on some platforms but it is delegated to the current native when possible.

Pattern

Pattern

The Pattern class maintains three objects which can serve as color sources for the IGraphics#draw(), IGraphics#fill(), and IGraphics#write() methods. Those three objects are a Color, a Gradient, and an Image. The Pattern's Mode - which is one of COLOR, GRADIENT, or IMAGE - specifies which of the three is currently active, i.e. to be used as a color source.


In the following example, an IGraphics' write-Pattern is set (using IGraphics#setWrite(Gradient)) to a linear Gradient. After that, letters of displayed text are filled with the specified color gradient.

[WritePatternExample] WritePatternExample.java

 * Copyright (c) 2013 itemis AG and others.
package org.eclipse.gef4.graphics.examples;
 
import org.eclipse.gef4.geometry.planar.Dimension;
 
public class WritePatternExample implements IExample {
 
	@Override
	public int getHeight() {
		return 300;
	}
 
	@Override
	public String getTitle() {
		return "Write Pattern Example";
	}
 
	@Override
	public int getWidth() {
		return 600;
	}
 
	@Override
	public void renderScene(IGraphics g) {
		Gradient.Linear gradient = new Gradient.Linear(new Point(), new Point(
				100, 0), CycleMode.REFLECT);
		gradient.addStop(0, new Color(255, 0, 0));
		gradient.addStop(1, new Color(255, 255, 0));
		g.setWrite(gradient);
		g.setFont(new Font("Courier New", 32, Font.STYLE_BOLD
				| Font.STYLE_UNDERLINED));
 
		g.setDraw(new Color(0, 0, 255));
		g.draw(new Rectangle(0, 0, 100, 100).getOutline());
 
		String text = getTitle();
		Dimension textSize = g.getTextDimension(text);
		g.write(text);
		g.translate(50, textSize.height);
		g.write(text);
	}
}

Write Pattern Example (AWT)

Font

  • package: org.eclipse.gef4.graphics.font
Font

A Font object stores font family, size, and style. Text rendering is currently a less-marked feature of the component. Nonetheless, using these attributes you can apply simple styles to your texts. The size is interpreted in points; fractional sizes are allowed. The style is a bitwise-OR combination of the following constants:

  • NORMAL
    Text is displayed plain, i.e. normal font weight, roman type, not underlined.
  • BOLD
    Text is displayed bold, i.e. with increased weight.
  • ITALIC
    Text is displayed in italic type, i.e. slanted.
  • UNDERLINED
    Text is displayed underlined.

The following example shows text rendering with font sizes from 3.5pt to 32.5pt:

[FontSizeExample] FontSizeExample.java

/*******************************************************************************
 * Copyright (c) 2013 itemis AG and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Matthias Wienand (itemis AG) - initial API and implementation
 * 
 *******************************************************************************/
package org.eclipse.gef4.graphics.examples;
 
import org.eclipse.gef4.geometry.planar.Dimension;
import org.eclipse.gef4.graphics.IGraphics;
 
public class FontSizeExample implements IExample {
 
	private static final int PAD = 10;
 
	@Override
	public int getHeight() {
		return 600;
	}
 
	@Override
	public String getTitle() {
		return "Font Size Example";
	}
 
	@Override
	public int getWidth() {
		return 800;
	}
 
	@Override
	public void renderScene(IGraphics g) {
		double y = PAD, x = PAD;
		g.translate(x, y);
		for (double size = 3.5; size < 33; size += 0.5) {
			String text = "Text in size " + size + "pt";
			g.setFontSize(size);
			Dimension dim = g.getTextDimension(text);
			y += dim.height;
			if (y > getHeight()) {
				g.translate(PAD + dim.width, PAD + dim.height - y);
				y = dim.height + PAD;
			}
			g.write(text);
			g.translate(0, dim.height);
		}
	}
 
}

Font Size Example (SWT)

Color

  • package: org.eclipse.gef4.graphics.color
Color

A Color object stores the red, green, blue, and alpha components of a color in the RGBA color space. The individual channel values are limited to the range [0;255]. An alpha channel value of 0 signifies a fully transparent and a value of 255 a fully opaque color.

You can blend two Colors using one of the Color#getBlended(Color, ...) methods. They are used internally to generate gradient colors.

[ColorBlendExample]

Color white = new Color(255, 255, 255);
Color red = new Color(255, 0, 0);
Color whiteRed = white.getBlended(red, 0.5);
 
Color cyan = new Color(0, 255, 255);
Color magenta = new Color(255, 0, 255);
Color cyanMagenta = cyan.getBlended(magenta, 0.5, 2.2); // gamma correction x^(1 / 2.2)
 
//...

Color Blend Example (SWT)

When working with image data the Color class provides utility methods to extract channel values of a pixel, to create a Color object from a pixel, and to get a pixel representation of a Color object.

Gradient

  • package: org.eclipse.gef4.graphics
Gradient

A Gradient object stores a linear or radial, cyclic or acyclic, multi-stop color gradient. Therefore it manages a list of gradient-stops which consist of a percentual distance from the gradient's start location and a Color object. The gradient-stops specify the colors of the gradient at the stops' distances. Note that no gamma-correction is applied to the gradients.

Gradient.Linear

[Example002: Gradient.Linear] Example002.java

Rectangle rect = new Rectangle(0, 0, 100, 100);
Gradient.Linear linearGradient = new Gradient.Linear(rect.getTopLeft(), rect.getTopRight())
    .addStop(0.0, new Color(255, 255, 255))
    .addStop(0.5, new Color(255,   0,   0))
    .addStop(1.0, new Color(  0,   0,   0));
graphics.setFill(linearGradient);
graphics.fill(rect);

Gradient.Linear example

A linear gradient is defined by a start and an end Point. In the example, the top-left and top-right corners of the Rectangle to fill are used. The three stops define color transitions from white to red and from red to black.

Gradient.Radial

[Example003: Gradient.Radial] Example003.java

Ellipse ellipse = new Ellipse(0, 0, 100, 100);
Gradient.Radial radialGradient = new Gradient.Radial(ellipse, ellipse.getCenter())
    .addStop(0.0, new Color(255, 255, 255))
    .addStop(0.5, new Color(255,   0,   0))
    .addStop(1.0, new Color(  0,   0,   0));
graphics.setFill(radialGradient);
graphics.fill(ellipse);

Gradient.Radial example

A radial gradient is defined by an Ellipse (border) and a focus Point. The focus Point determines where the gradient starts, i.e. the percentual distance at that Point is 0. The three stops define color transitions from white to red and from red to black.

CycleMode

[Example004: Gradients: CycleMode] Example004.java

Ellipse ellipse = new Ellipse(0, 0, 100, 100);
Gradient.Radial radialGradient = new Gradient.Radial(ellipse, ellipse
	.getCenter().translate(-10, -10), CycleMode.REFLECT)
	.addStop(0.0, new Color(255, 255, 255))
	.addStop(0.5, new Color(255, 0, 0))
	.addStop(1.0, new Color(0, 0, 0));
g.setFill(radialGradient);
g.fill(new Rectangle(0, 0, 200, 200));

Gradients: CycleMode example

The CycleMode defines the colors of a gradient outside of the gradient area. For linear gradients, this is beyond their start and end points. For radial gradients, this is beyond their boundary (Ellipse). You can choose one of three CycleModes:

  • NO_CYCLE
    The Color of the nearest gradient-stop is used outside of the gradient area.
  • REFLECT
    The gradient-stops are reflected outside of the gradient area.
  • REPEAT
    The gradient-stops are repeated outside of the gradient area.

Image

  • package: org.eclipse.gef4.graphics.image
Image

The Image class stores rectangular image data. Individual pixels are stored in the ARGB color space using ints (32bit): 0xAARRGGBB. At the time of writing, the API does not provide Image I/O.

Information on an Image:

int width = image.getWidth();
int height = image.getHeight();
Rectangle bounds = image.getBounds();
 
int[] redHistogram = image.getRedHistogram();
int[] greenHistogram = image.getGreenHistogram();
int[] blueHistogram = image.getBlueHistogram();
int[] alphaHistogram = image.getAlphaHistogram();
 
int pixel = image.getPixel(x, y);
int[] row = image.getPixelRow(y);
int[] data = image.getPixels();

Image creation:

Image new = new Image(); // 1x1, black
Image new = new Image(400, 300); // 400x300, black
Image new = new Image(400, 300, new Color(255, 0, 0)); // 400x300, red
Image copy = image.getCopy();
Image subImage = image.getSubImage(x, y, width, height);
Image bigImage = image.getScaled(2);
Image thumb = image.getThumbnail(maxWidth, maxHeight);
Image operated = image.apply(imageOperation);

Image manipulation:

image.setPixel(x, y, color);
image.setPixels(...);

IImageOperation

  • package: org.eclipse.gef4.graphics.image.operations
IImageOperation

The IImageOperation interface specifies one single method IImageOperation#apply(Image) which takes an Image argument and returns another Image representing the result of the particular operation. Some IImageOperation implementations, such as common arithmetic operations (addition, difference, multiplication, division), are provided by GEF4. Take a look at the ImageOperations class below for more information on those implementations.

Of course you can create your own IImageOperations. The following example implements channel-wise histogram equalization. The left halve of the image is displayed unmodified. The right halve of the image is displayed after applying histogram equalization to it:

[ImageOperationExample]

/*******************************************************************************
 * Copyright (c) 2013 itemis AG and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Matthias Wienand (itemis AG) - initial API and implementation
 * 
 *******************************************************************************/
package org.eclipse.gef4.graphics.examples;
 
import java.io.IOException;
 
import javax.imageio.ImageIO;
 
import org.eclipse.gef4.geometry.planar.Rectangle;
import org.eclipse.gef4.graphics.IGraphics;
import org.eclipse.gef4.graphics.color.Color;
import org.eclipse.gef4.graphics.image.Image;
import org.eclipse.gef4.graphics.image.operations.IImageOperation;
 
public class ImageOperationExample implements IExample {
 
	class HistogramEqualizer implements IImageOperation {
 
		@Override
		public Image apply(Image image) {
			int[] equRed = genEqualizer(image, image.getRedHistogram());
			int[] equGreen = genEqualizer(image, image.getGreenHistogram());
			int[] equBlue = genEqualizer(image, image.getBlueHistogram());
 
			Image result = image.getCopy();
 
			for (int x = 0; x < image.getWidth(); x++) {
				for (int y = 0; y < image.getHeight(); y++) {
					int[] rgba = Color.getPixelRGBA(image.getPixel(x, y));
					int resPixel = Color.getPixel(equRed[rgba[0]],
							equGreen[rgba[1]], equBlue[rgba[2]], rgba[3]);
					result.setPixel(x, y, resPixel);
				}
			}
 
			return result;
		}
 
		private int[] genEqualizer(Image image, int[] hist) {
			int[] cdf = new int[256];
			int cdfMin = 0;
			boolean noHist = true;
 
			cdf[0] = hist[0];
 
			if (hist[0] > 0) {
				cdfMin = cdf[0];
				noHist = false;
			}
 
			for (int i = 1; i < 256; i++) {
				cdf[i] = cdf[i - 1] + hist[i];
				if (noHist && hist[i] > 0) {
					cdfMin = hist[i];
					noHist = false;
				}
			}
 
			int[] equalizer = new int[256];
			double s = 255d / (image.getWidth() * image.getHeight());
			for (int i = 0; i < 256; i++) {
				equalizer[i] = (int) ((cdf[i] - cdfMin) * s);
			}
 
			return equalizer;
		}
	}
 
	private static String IMAGE_FILE = "tour-eiffel_notre-dame.jpg";
 
	private Image image;
 
	@Override
	public int getHeight() {
		return 460;
	}
 
	@Override
	public String getTitle() {
		return "Image Operation Example - Histogram Equalization";
	}
 
	@Override
	public int getWidth() {
		return 680;
	}
 
	private void loadImage() {
		if (image == null) {
			try {
				image = new Image(ImageIO.read(OverviewExample.class
						.getResource(IMAGE_FILE)));
			} catch (IOException x) {
				System.out.println("Cannot load image file '" + IMAGE_FILE
						+ "':");
				x.printStackTrace();
			}
		}
	}
 
	@Override
	public void renderScene(IGraphics g) {
		loadImage();
		Rectangle halve = image.getBounds().getShrinked(0, 0,
				0.5 * image.getWidth(), 0);
		g.translate(10, 10).pushState().intersectClip(halve);
		g.paint(image);
		g.popState().intersectClip(halve.getTranslated(halve.getWidth(), 0));
		g.paint(new HistogramEqualizer().apply(image));
	}
}

Image Operation Example (AWT)

ImageOperations

ImageOperations

How to

The "How to..." sections explain how to use specific functionality of the GEF4 Graphics component. You can try out the various presented code snippets using the HowToSnippets demo in the org.eclipse.gef4.graphics.examples project under the org.eclipse.gef4.graphics.examples.doc package.

How to transform the coordinate system

How to use the states stack

How to do off-screen rendering

The IGraphics interface facilitates the creation of an IImageGraphics for the currently used native. The IImageGraphics is associated with an Image to draw into.

How to draw geometric primitives

How-to snippet 001
How-to snippet 002

The GEF4 Geometry component provides many geometric abstractions. It is integrated into the GEF4 Graphics component. Therefore, the GEF4 Graphics component allows for rendering those geometric abstractions. You can use the draw() and fill() methods of the IGraphics in order to draw the contour of a geometric abstraction or fill it with a color, a gradient, or an image.

How-to snippet 001:

graphics.setDraw(new Color(0, 0, 0)).draw(new Line(10, 10, 90, 90));
graphics.setFill(new Color(255, 0, 0)).fill(new Ellipse(30, 5, 20, 20));
graphics.draw(new Rectangle(5, 50, 30, 10).getOutline());

The list of provided geometric primitives contains all of the standard geometric objects, such as arcs, lines, ellipses, paths, polygons, polylines, rectangles, and rounded rectangles. Complementary, additional abstractions for the use of Bezier curves are provided, namely curved-polygons and polybeziers where the edges are arbitrary Bezier curves.

How-to snippet 002:

// connection passes through the given points
PolyBezier connection = PolyBezier.interpolateCubic(
    new Point(10, 10), new Point(10, 90), new Point(180, 90), new Point(180, 200)
);
graphics.draw(connection);

How to draw arbitrary Bezier curves

How-to snippet 003

Bezier curves are used in the GEF4 Geometry component to represent edges of geometric objects. They can be visualized like any other of the geometric abstractions.

How-to snippet 003:

graphics.draw(new BezierCurve(new Point(300, 25), new Point(330, 165), new Point(110, 65),
	new Point(180, 240), new Point(160, 220), new Point(100, 165)));
graphics.draw(new BezierCurve(new Point(10, 150), new Point(86, 90), new Point(162, 25),
	new Point(238, 130), new Point(314, 200), new Point(380, 150)));

As you can see, a Bezier curve approaches the polyline of its control points. The first control point is called the start point, the last control point is called the end point, and the intermediate control points are called the handle points of the Bezier curve. The number of control points determines the curve's degree. A degree 0 (1 control point) Bezier curve represents a single point. A degree 1 curve represents a straight line segment. Higher degree Bezier curves generally proceed along a meandering path.

How to use the clipping area

How to change the stroke

How to use linear gradients

How to use radial gradients

How to do an image fill

How to draw text

How to change the font style

How to fill text with a gradient

How to fill text with image data

How to display images

How to resize images

How to blur images

How to do image arithmetic

Native-specific

AwtGraphics

  • package: org.eclipse.gef4.graphics.awt

SwtGraphics

  • package: org.eclipse.gef4.graphics.swt