!7 lib 1012002 // gtk-4.1.jar /* * ExampleLinedPaper.java * * Copyright (c) 2007-2009 Operational Dynamics Consulting Pty Ltd, and Others * * The code in this file, and the program it is a part of, are made available * to you by the authors under the terms of the "GNU General Public Licence, * version 2" See the LICENCE file for the terms governing usage and * redistribution. * * Copyright (c) 2008 Nathan Strum * * The image sketch is included with java-gnome with permission of its author * for the express purpose of illustrating this example. */ 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; sS text = "Lorem Ipsum"; /** * 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 */ p { 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; File pdfFile = programFile("rendered.pdf"); surface = new PdfSurface(f2s(pdfFile), 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 * Math.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(f2s(loadImageAsFile(#1009664))); 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(); print("Made: " + f2s(pdfFile)); }