Skip to content

Commit 8cd8372

Browse files
authored
Merge pull request #48 from gpc/gdoc-to-asciidoctor-conversion
Convert Groovy Docs (.gdoc) to asciidoc (.adoc)
2 parents f329ad4 + 081b2c6 commit 8cd8372

12 files changed

+392
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
= Introduction
2+
3+
This plugin adds additional rendering capabilities to Grails applications via the https://xhtmlrenderer.dev.java.net/[XHTML Renderer] library.
4+
5+
Rendering is either done directly via `«format»RenderingService` services ...
6+
7+
[source,groovy]
8+
----
9+
ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/pdfs/report", model: [data: data])
10+
----
11+
12+
Or via the `render«format»()` methods added to controllers ...
13+
14+
[source,groovy]
15+
----
16+
renderPdf(template: "/pdfs/report", model: [report: reportObject], filename: reportObject.name)
17+
----
18+
19+
The plugin is released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache License 2.0] license and is produced under the http://gpc.github.com/[Grails Plugin Collective].
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
= GSP Considerations
2+
3+
There are a few things that you do need to be aware of when writing GSPs to be rendered via this plugin.
4+
5+
=== Link resources must be resolvable
6+
7+
All links to resources (e.g. images, css) must be _accessible by the application_. This is due to the linked resources being accessed by _application_ and not a browser. Depending on your network setup, ensure resources are available.
8+
9+
The rendering engine resolves all relative links relative to the `grails.serverURL` config property.
10+
11+
=== Must be well formed
12+
13+
The GSP must render to well formed, valid, XHTML. If it does not, a `grails.plugins.rendering.document.XmlParseException` will be thrown.
14+
15+
=== Must declare DOCTYPE
16+
17+
Without a doctype, you are likely to get parse failures due to unresolvable entity references (e.g. ` `). Be sure to declare the XHTML doctype at the start of your GSP like so:
18+
19+
[source,xml]
20+
----
21+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
22+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
23+
----

src/docs/guide/3. Rendering.adoc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
= Rendering
2+
3+
There are four services available for rendering:
4+
5+
* pdfRenderingService
6+
* gifRenderingService
7+
* pngRenderingService
8+
* jpegRenderingService
9+
10+
All services have the same method:
11+
12+
[source,java]
13+
----
14+
OutputStream render(Map args, OutputStream destination = new ByteArrayOutputStream())
15+
----
16+
17+
The `args` define the render operation, with the bytes written to the given output stream. The given output stream is returned from the method. If no `destination` is provided, the render will write to a new `ByteArrayOutputStream`.
18+
19+
Here are some examples:
20+
21+
[source,java]
22+
----
23+
// Get the bytes
24+
def bytes = gifRenderingService.render(template: '/images/coupon', model: [serial: 12345])
25+
26+
// Render to a file
27+
new File("coupon.jpg").withOutputStream { outputStream ->
28+
jpegRenderingService.render([template: '/images/coupon', model: [serial: 12345]], outputStream)
29+
}
30+
----
31+
32+
For information on rendering to the HTTP response, see <<guide:5. Rendering To The Response,Rendering To The Response>>.
33+
34+
=== Basic Render Arguments
35+
36+
All rendering methods take a `Map` argument that specifies which template to render and the model to use (in most cases).
37+
38+
The following map arguments are common to all rendering methods:
39+
40+
* `template` (required) - The template to render
41+
* `model` (optional) - The model to use
42+
* `plugin` (optional) - The plug-in containing the template
43+
* `controller` (optional) - The controller _instance_ or _name_ to resolve the template against (set automatically in provided `render«format»` methods on controllers).
44+
45+
=== Template Resolution
46+
47+
The plugin uses the same resolution strategy as the `render()` method in Grails controllers and taglibs.
48+
49+
That is,
50+
51+
* template files must start with an underscore (`_template.gsp`)
52+
* template paths starting with `/` are resolved relative to the `views` directory
53+
* template paths NOT starting with `/` are resolved relative to the `views/«controller»` directory
54+
55+
If the `template` argument does not start with a `/`, the `controller` argument must be provided. The methods added to controllers (e.g. `renderPdf()`) automatically pass the `controller` param for you.
56+
57+
=== Debugging
58+
59+
To get more visibility about what is going on inside, you can activate the logging within Flying Saucer by providing the system property `xr.util-logging.loggingEnabled` like so:
60+
61+
[source,shell]
62+
----
63+
grails -Dxr.util-logging.loggingEnabled=true run-app
64+
----

src/docs/guide/4. Sizing.adoc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
= Sizing
2+
3+
=== Documents
4+
5+
When rendering PDF documents, you can specify the page size via CSS:
6+
7+
[source,css]
8+
----
9+
<style type="text/css">
10+
@page {
11+
size: 210mm 297mm;
12+
}
13+
</style>
14+
----
15+
16+
=== Images
17+
18+
The image rendering methods take extra arguments to control the size of the rendered image. The extra arguments are maps containing `width` or `height` keys, or both.
19+
20+
==== render
21+
22+
The `render` argument is the size of the view port that the document is rendered into. This is equivalent to the dimensions of the browser window for html rendering.
23+
24+
The default value for `render` is `[width: 10, height: 10000]` (i.e. 10 pixels wide by 10000 pixels high).
25+
26+
==== autosize
27+
28+
The `autosize` argument specifies whether to adjust the size of the image to exactly be the rendered content.
29+
30+
The default value for `autosize` is `[width: true, height: true]`.
31+
32+
==== scale
33+
34+
The `scale` argument specifies the factor to scale the image by after initial rendering. For example, the value `[width: 0.5, height: 0.5]` produces an image half the size of the original render.
35+
36+
The default value for `scale` is `null`.
37+
38+
==== resize
39+
40+
The `resize` argument specifies the adjusted image after initial rendering. For example, the value `[width: 200, height: 400]` will resize the image to 200 pixels x 400 pixels regardless of the original size.
41+
42+
(note that `resize` & `scale` are mutually exclusive with `scale` taking precedence).
43+
44+
The default value for `resize` is `null`.
45+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
= Rendering To The Response
2+
3+
There are four methods added to all controllers for rendering:
4+
5+
* renderPdf(Map args)
6+
* renderGif(Map args)
7+
* renderPng(Map args)
8+
* renderJpeg(Map args)
9+
10+
Each of the methods is equivalent to:
11+
12+
[source,groovy]
13+
----
14+
«format»RenderingService.render(args + [controller: this], response)
15+
----
16+
17+
All methods take all of the arguments that their respective service's `render()` method take, plus some extras.
18+
19+
=== Extra Render Arguments
20+
21+
All rendering methods take a `Map` argument that specifies which template to render and the model to use (in most cases).
22+
23+
The following map arguments are common to all rendering methods:
24+
25+
* `filename` (optional) - sets the `Content-Disposition` header with `attachment; filename="$filename"` (asking the browser to download the file with the given filename)
26+
* `contentType` (optional) - the `Content-Type` header value (see Content Type Defaults below)
27+
28+
=== Default Content Types
29+
30+
The default content types are:
31+
32+
* application/pdf
33+
* image/gif
34+
* image/png
35+
* image/jpeg
36+
37+
=== Large Files/Renders
38+
39+
See the section on <<guide:6. Caching And Performance,caching and performance>> for some other arguments that can help with large renders.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
= Caching And Performance
2+
3+
=== Caching
4+
5+
Rendering can be an expensive operation so you may need to implement caching (using the excellent http://grails.org/plugin/springcache[spring-cache] plugin).
6+
7+
==== Document Caching
8+
9+
Rendering works internally by creating a `org.w3c.dom.Document` instance from the GSP page via the `xhtmlDocumentService`. If you plan to render the same GSP as different output formats, you may want to cache the created Document.
10+
11+
[source,groovy]
12+
----
13+
import grails.plugin.springcache.annotations.Cacheable
14+
15+
class CouponDocumentService {
16+
def xhmlDocumentService
17+
18+
@Cacheable('couponDocumentCache')
19+
class getDocument(serial) {
20+
xhmlDocumentService.createDocument(template: '/coupon', model: [serial: serial])
21+
}
22+
}
23+
----
24+
25+
All of the render methods can take a `document` parameter instead of the usual `template`/`model` properties.
26+
27+
[source,groovy]
28+
----
29+
class CouponController {
30+
31+
def couponDocumentService
32+
33+
def gif = {
34+
def serial = params.id
35+
def document = couponDocumentService.getDocument(serial)
36+
37+
renderGif(filename: "${serial}.gif", document)
38+
}
39+
}
40+
----
41+
42+
==== Byte Caching
43+
44+
You can take things further and actually cache the rendered bytes.
45+
46+
[source,groovy]
47+
----
48+
import grails.plugin.springcache.annotations.Cacheable
49+
50+
class CouponGifService {
51+
52+
def couponDocumentService
53+
def gifRenderingService
54+
55+
def getGif(serial) {
56+
def document = couponDocumentService.getDocument(serial)
57+
def byteArrayOutputStream = gifRenderingService.gif([:], document)
58+
byteArrayOutputStream.toByteArray()
59+
}
60+
}
61+
----
62+
63+
[source,groovy]
64+
----
65+
class CouponController {
66+
67+
def couponGifService
68+
69+
def gif = {
70+
def serial = params.id
71+
def bytes = couponGifService.getGif(serial)
72+
73+
renderGif(bytes: bytes, filename: "${serial}.gif")
74+
}
75+
}
76+
----
77+
78+
=== Avoiding Byte Copying
79+
80+
When rendering to the response, the content is first written to a temp buffer before being written to the response. This is so the number of bytes can be determined and the `Content-Length` header can be set.
81+
82+
This copy can be avoided and the render (or bytes) can be written directly to the response output stream. This means that the `Content-Length` header will not be set unless you manually specify the length.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
= Inline Images
2+
3+
This plugin adds support for inline images via http://en.wikipedia.org/wiki/Data_URI_scheme[data URIs]. This is useful for situations where the images you need to imbed in a rendered PDF or image are not accessible via a URL.
4+
5+
For example, your application may generate barcodes that you don't necessarily want to expose but want to include in your generated PDFs or images. Using inline images, you can include the image bytes directly in the output.
6+
7+
To make this easier, the plugin provides tags to render byte arrays as common image formats (i.e. gif, png and jpeg).
8+
9+
The tags are under the namespace `rendering` and are called `inlinePng`, `inlineGif` and `inlineJpeg`. They all take a single argument, `bytes`, which is a `byte[]` containing the raw bytes of the image.
10+
11+
Here is an example of how this could be used to include a local (i.e. from the filesystem) image in a generated pdf/image.
12+
13+
[source,groovy]
14+
----
15+
class SomeController {
16+
17+
def generate = {
18+
def file = new File("path/to/image.png")
19+
renderPng(template: "thing", model: [imageBytes: file.bytes])
20+
}
21+
22+
}
23+
----
24+
25+
In the view ...
26+
27+
[source,html]
28+
----
29+
<html>
30+
<head></head>
31+
<body>
32+
<p>Below is an inline image</p>
33+
<rendering:inlinePng bytes="${imageBytes}" class="some-class" />
34+
</body>
35+
</html>
36+
----
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
= Exotic Characters
2+
3+
In most cases, there are no issues with dealing with exotic Unicode characters. However, certain characters will not render in PDF documents without some extra work (the same problem does not exist with image rendering).
4+
5+
This http://www.mail-archive.com/[email protected]/msg48788.html[thread] explains the issue.
6+
7+
The solution is to register the font to use with a particular encoding. Because we are using XHTMLRenderer we can specify this in CSS as opposed to programatically registering.
8+
9+
[source,css]
10+
----
11+
@font-face {
12+
src: url(path/to/arial.ttf);
13+
-fs-pdf-font-embed: embed;
14+
-fs-pdf-font-encoding: cp1250;
15+
}
16+
body {
17+
font-family: "Arial Unicode MS", Arial, sans-serif;
18+
}
19+
----
20+
See http://pigeonholdings.com/projects/flyingsaucer/R8/doc/guide/users-guide-R8.html#xil_44[this page] for details on these CSS directives.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
= renderGif
2+
3+
== Purpose
4+
5+
== Examples
6+
7+
[source,java]
8+
----
9+
foo.renderGif(map)
10+
----
11+
12+
== Description
13+
14+
Arguments:
15+
16+
* `map`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
= renderJpeg
2+
3+
== Purpose
4+
5+
== Examples
6+
7+
[source,java]
8+
----
9+
foo.renderJpeg(map)
10+
----
11+
12+
== Description
13+
14+
Arguments:
15+
16+
* `map`

0 commit comments

Comments
 (0)