1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
/*
* java-gnome, a UI library for writing GTK and GNOME programs from Java!
*
* Copyright © 2007-2010 Operational Dynamics Consulting, Pty Ltd and Others
* Copyright © 2008 Nathan Strum
*
* The code in this file, and the program it is a part of, is made available
* to you by its authors as open source software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License version
* 2 ("GPL") as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
*
* You should have received a copy of the GPL along with this program. If not,
* see http://www.gnu.org/licenses/. The authors of this program may be
* contacted through http://java-gnome.sourceforge.net/.
*/
package cairo;
/*
* The image sketch is included with java-gnome with permission of its author,
* Nathan Strum, for the express purpose of illustrating this example.
*/
import java.io.IOException;
import org.freedesktop.cairo.Context;
import org.freedesktop.cairo.PdfSurface;
import org.freedesktop.cairo.Surface;
import org.gnome.gdk.Pixbuf;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.PaperSize;
import org.gnome.gtk.Unit;
import org.gnome.pango.FontDescription;
import org.gnome.pango.Layout;
import org.gnome.pango.LayoutLine;
import org.gnome.pango.Rectangle;
import static java.lang.Math.PI;
import static textview.LoremIpsum.text;
/**
* Some poor kid sitting through latin class doodling on his lined paper.
*
* This is an example of using Pango to render text along side Cairo drawing
* primitives, and using Cairo's PdfSurface back end to produce a PDF that can
* subsequently be previewd or printed to paper.
*
* The blue lines actually represent the baseline of the font (the calls to
* Context's showLayout() draw LayoutLines with their baseline at the current
* Cairo point); if you go to a high level of zoom you'll see the overshoot
* that some glyphs are designed with. The red line is the left margin, and
* unlike the baseline (which is just an arbitrary point midway into the
* font's extents), nothing bleeds left past the margin line.
*
* @author Andrew Cowie
* @author Nathan Strum
*/
public class ExampleLinedPaper
{
public static void main(String[] args) throws IOException {
final Surface surface;
final Context cr;
final Layout layout;
final FontDescription desc;
final String[] paras;
final LayoutLine first;
final PaperSize paper;
final double pageWidth, pageHeight;
final double topMargin, leftMargin, rightMargin;
final Rectangle rect;
final double[] holes;
double y, v, b;
final Pixbuf pixbuf;
Gtk.init(args);
paper = PaperSize.getDefault();
pageWidth = paper.getWidth(Unit.POINTS);
pageHeight = paper.getHeight(Unit.POINTS);
topMargin = 25;
leftMargin = 45;
rightMargin = 20;
surface = new PdfSurface("doc/examples/cairo/ExampleLinedPaper.pdf", pageWidth, pageHeight);
cr = new Context(surface);
cr.moveTo(leftMargin, topMargin);
layout = new Layout(cr);
desc = new FontDescription("Liberation Serif, 12");
layout.setFontDescription(desc);
/*
* Before we start rendering, we need some information about the line
* height. Given that all lines are going to be rendered in the same
* font, we can get the metrics of a piece of arbitrary text and then
* use that height to do the line spacing for both the text and the
* lines.
*/
layout.setText("Lorem");
first = layout.getLineReadonly(0);
rect = first.getExtentsLogical();
v = rect.getHeight();
b = rect.getAscent();
/*
* Draw the horizontal rules in blue. These will cunningly be drawn on
* the font baseline, and given that the LayoutLines below will be
* drawn with reference to this latitude it will end up looking like
* the person writing is very good at staying between the lines.
*/
y = topMargin + b;
while (y < pageHeight) {
cr.moveTo(0, y);
cr.lineTo(pageWidth, y);
y += v;
}
cr.setSource(0, 0, 199.0 / 255.0);
cr.setLineWidth(0.1);
cr.stroke();
/*
* Draw a vertical red line as the left margin rule.
*/
cr.moveTo(leftMargin, 0);
cr.lineTo(leftMargin, pageHeight);
cr.setSource(255.0 / 255.0, 0.0, 0.0);
cr.stroke();
/*
* Now draw the "holes" making this three-hole punched lined paper.
* The holes array are fractions of the page height which is where we
* will draw the circles with arc(). We wil preserve the path so we
* can use it again to full with white, making it look like the paper
* was punched out.
*/
holes = new double[] {
1.0 / 7.0,
1.0 / 2.0,
6.0 / 7.0
};
cr.setLineWidth(1.0);
for (double hole : holes) {
cr.arc(leftMargin / 2.0, pageHeight * hole, leftMargin / 4.0, 0.0, 2 * PI);
cr.setSource(1.0, 1.0, 1.0);
cr.fillPreserve();
cr.setSource(0.5, 0.5, 0.5);
cr.stroke();
}
/*
* And finally we lay out the words. Given some source text, split it
* up into individual paragraphs. Pango's Layout is capable of doing
* multiple paragraphs at once, but this allows us to control the
* spacing between paragraphs.
*/
paras = text.split("\n");
/*
* Set a width for the Layouts. This will kick-off word wrapping. And
* reset the source colour so that the text will be black.
*/
layout.setWidth(pageWidth - (leftMargin + rightMargin));
cr.setSource(0.0, 0.0, 0.0);
/*
* We did the lines first so that the typeset text will be over the
* ruled lines. We go to the trouble of drawing the lines
* individually, making it easier to keep things aligned with the
* baselines of the rules that we've already drawn.
*/
y = topMargin + b;
for (String para : paras) {
layout.setText(para);
for (LayoutLine line : layout.getLinesReadonly()) {
y += v;
cr.moveTo(leftMargin, y);
cr.showLayout(line);
}
y += v; // blank line between paras
}
/*
* Of course, what student in latin class is paying attention? None in
* the history of western civilization, we're quite sure. So to
* complete our example we have a doodle at the bottom of the page.
*/
pixbuf = new Pixbuf("doc/examples/cairo/incoming-sketch.png");
cr.setSource(pixbuf, pageWidth - pixbuf.getWidth() - 10, pageHeight - pixbuf.getHeight() + 50);
cr.paint();
/*
* Finally, flush the drawing out to the Surface and through it on out
* to the PDF document. This is very important! If you don't reach
* this point the file on disk will be incomplete and won't render in
* a PDF viewer.
*/
surface.finish();
}
}
|