Swing是一个为Java程序提供GUI的API。它由不同的GUI组件和一系列图形类组成,包括一个名为Graphics2D的抽象类。 PdfContentByte有一系列createGraphics()方法,允许您创建一个名为PdfGraphics2D的类的特殊实现。该子类覆盖所有Graphics2D方法,将它们转换为前面部分中描述的PdfContentByte调用。
使用Swing 对象绘制图形
Java API表示java.awt.Graphics是“所有图形控制文件的抽象基类,允许应用程序绘制到在各种设备上实现的组件,以及屏幕外图像。”抽象类java.awt.Graphics2D扩展了Graphics类“以提供对几何,坐标转换,颜色管理和文本布局的更复杂的控制。这是在Java平台上渲染二维形状,文本和图像的基础类。“
Oracle的Sun Developer Network(SDN),提供了一个教程:“从几何图元中构造复杂的形状。”在此教程中有一个名为Pear.java的例子,用于绘制一个如图14.7所示的形状。
图14.7右侧的窗口是一个包含JPanel的JFrame。使用下一段代码构建和绘制JPanel。此代码段几乎与可在SDN上找到的示例相同。
Listing 14.11 PearExample.java
public class PearExample extends JPanel {
Ellipse2D.Double circle, oval, leaf, stem;
Area circ, ov, leaf1, leaf2, st1, st2;
public PearExample() {
circle = new Ellipse2D.Double();
oval = new Ellipse2D.Double();
leaf = new Ellipse2D.Double();
stem = new Ellipse2D.Double();
circ = new Area(circle);
ov = new Area(oval);
leaf1 = new Area(leaf);
leaf2 = new Area(leaf);
st1 = new Area(stem);
st2 = new Area(stem);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
double ew = 75; double eh = 75;
g2.setColor(Color.GREEN);
leaf.setFrame(ew - 16, eh - 29, 15.0, 15.0);
leaf1 = new Area(leaf);
leaf.setFrame(ew - 14, eh - 47, 30.0, 30.0);
leaf2 = new Area(leaf);
leaf1.intersect(leaf2);
g2.fill(leaf1);
leaf.setFrame(ew + 1, eh - 29, 15.0, 15.0);
leaf1 = new Area(leaf);
leaf2.intersect(leaf1);
g2.fill(leaf2);
g2.setColor(Color.BLACK);
stem.setFrame(ew, eh - 42, 40.0, 40.0);
st1 = new Area(stem);
stem.setFrame(ew + 3, eh - 47, 50.0, 50.0);
st2 = new Area(stem);
st1.subtract(st2);
g2.fill(st1);
g2.setColor(Color.YELLOW);
circle.setFrame(ew - 25, eh, 50.0, 50.0);
oval.setFrame(ew - 19, eh - 20, 40.0, 70.0);
circ = new Area(circle);
ov = new Area(oval);
circ.add(ov);
g2.fill(circ);
}
}
这是一本关于PDF的书,不是关于Java的书,所以我们不会详细讨论不同的几何原语以及如何使用它们。 这一切都在SDN上进行了解释。 相反,我们将尝试将这个复杂的形状绘制为PDF,如窗口所示
在图14.7中。
使用PDFGRAPHICS2D 绘制图形
在清单14.12中,您将重用清单14.11中的代码。 您将构建一个JPanel,更具体地说是PearExample对象,创建一个PdfGraphics2D实例,并使用paint()方法将JPanel绘制到PdfGraphics2D。 不要忘记使用dispose()方法B,否则最终会在生成的PDF文件中出现不可预测的错误。
Listing 14.12 PearToPdf.java
Document document = new Document(new Rectangle(150, 150));
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(filename));
document.open();
PdfContentByte canvas = writer.getDirectContent();
PearExample pear = new PearExample();
Graphics2D g2 = canvas. createGraphics(150, 150);
pear.paint(g2);
g2.dispose();
document.close();
可以看到PearExample构造函数中没有一行引用iText,也没有引用paint()方法。 这是一个非常强大的功能。 如果你有一个使用Graphics2D对象绘制形状到的现有应用程序,则可以使用此代码段将这些形状添加到PDF文件中。 图14.8显示了如何通过PdfGraphics2D机制将使用JFreeChart库生成的图表集成到PDF文件中。
图14.8中的饼图是使用下一个代码片段创建的。 它绘制了数据库查询的结果,该数据库查询选择了九个导演以及这些导演在电影数据库中的电影数量。
Listing 14.13 DirectorCharts.java
public static JFreeChart getPieChart()
throws SQLException, IOException {
DatabaseConnection connection
= new HsqldbConnection("filmfestival");
Statement stm = connection.createStatement();
ResultSet rs = stm.executeQuery(QUERY1);
DefaultPieDataset dataset = new DefaultPieDataset();
Director director;
while (rs.next()) {
director = PojoFactory.getDirector(rs);
dataset.setValue(String.format("%s, %s",
director.getName(), director.getGivenName()),
rs.getInt("c"));
}
connection.close();
return ChartFactory.createPieChart(
"Movies / directors", dataset, true, true, false);
}
同样,这个方法也不用使用iText改写。 iText魔术发生在这里:
Listing 14.14 DirectorCharts.java (continued)
PdfContentByte cb = writer.getDirectContent();
float width = PageSize.A4.getWidth();
float height = PageSize.A4.getHeight() / 2;
PdfTemplate pie = cb.createTemplate(width, height);
Graphics2D g2d1 = pie.createGraphics(
width, height, new DefaultFontMapper());
Rectangle2D r2d1
= new Rectangle2D.Double(0, 0, width, height);
getPieChart().draw(g2d1, r2d1);
g2d1.dispose();
cb.addTemplate(pie, 0, height);
这个代码段使用PdfTemplate获取PdfGraphics2D对象。 用这个PdfGraphics2D对象轻松绘制图表。
PDFGRAPHICS2D应用故障排除
到目前为止,与本章前面的示例相比,Graphics2D示例非常简单。 如果跑起来没有任何问题,那你真是牛逼大发了。 许多开发人员在此过程中碰到的问题,可以通过遵循以下指引来避免:
■ 完成绘制到PdfGraphics2D对象后,不要忘记调用dispose()方法(清单14.12中的g2.dispose(); )。
■ Java的Graphics2D中的坐标系与PDF的图形中的默认坐标系不同。 Java Graphics中的原点是绘图区域的左上角。 X坐标向右增加; Y坐标向下增加。
■ Java使用标准的Red-Green-Blue(sRGB)中作为内部的默认颜色空间,但是颜色需要转换。 注意,具有四种颜色值的任何内容都被假定为ARGB,即使它可能是CMYK。 (ARGB包括RGB组件加上alpha透明度因子,用于指定将一种颜色绘制在另一种颜色上时会发生什么。)
■ 注意使用字体时。 java.awt.Font和com.itextpdf.text.Font字体类之间存在很大差异。 我们将在第14.5.2节讨论这个问题。
在下一节中,我们将介绍如何使用Graphics2D渲染文本。