Index


RISC World

Creating PDF files with Scribble 0.1

Gavin Wraith introduces the Scribble application

Why PDF

I expect most readers know that HTML was invented by Tim Berners-Lee as a device for separating content from appearance. The writer of a web page determines its content; the reader decides its appearance (by choice of browser settings). If you are sending information to another computer, how do you know what kind of graphics it supports? The original plan for the WWW intended that even a blind person should be able to read, that is hear, a web page. It follows that all those HTML tags for changing font, or background colours, or some other visual aspect, are not really part of the original plan. They were added later, often the result of commercial considerations - browser wars in which each side exploited the ignorance of a public to whom the idea of separating content from appearance was too abstract to be entertained. If you paint a picture or print out a photograph and show it to different people (sighted, of course) will they not see the same thing? Metaphysics and physiology to one side, the answer is yes, they will. But if the picture has to be transmitted digitally, to those people's various computers, what then?

When the unsuitability of web pages for transmitting visual appearances had sunk in, Adobe, famed for its page-description language, PostScript, came up with PDF. This is a file format that blends some of the ideas of HTML, such as links, with those of desktop publishing, where you want to ensure that when you print out hardcopy you will always get the same result, at least if the printers are of adequate capability. So if you want to send somebody a document where the visual aspect must be preserved precisely, do not use HTML, use PDF.

Why Scribble

Unfortunately, Adobe's software for viewing PDF files, Acrobat Reader, has never been implemented for Risc OS. Instead, for Risc OS we have:

  • !RiScript, from Cerilica (http://www.cerilica.com)

  • !PDF (free) maintained by Colin Granville (http://www.pdf.iconbar.com/)

Up till now the only ways to create a PDF file on a RISC OS machine have been:

  • Convert a PostScript file using !ps2pdf with !Ghostscript
  • Use the shareware Perl program, txt2pdf, from SANFACE software (http://www.sanface.com). You need Perl for this, of course, which has been ported to RISC OS by Nicholas Clark (http://plum.flirble.org/~nick/). There is a wimp frontend, !txt2pdf, by Joern-Erik LEO Burkert, which requires Justin Fletcher's JFShared library.

But now you can use !Scribble, provided on this CD, which I wrote earlier this year. This application is entirely straightforward to use. Once the filing system has seen !Scribble (or !Scribble has been filer_booted), the filetype Scrib

is defined (&1ac). To create a PDF file you must first describe it in a text file, using an editor. The description is in a simple language that I propose to call Scribble, which we will discuss below. Save the description, giving it filetype Scrib, and then double click the saved file's icon. The PDF file(s) will be created. Their filenames are determined by their descriptions. You can create lots of PDF files at once, possibly linked to each other, with a single Scrib file.

To view the results you need !RiScript or !PDF. !RiScript, rather than loading a file into memory and discarding it when the viewer window is closed, keeps the file open until you quit !RiScript. For this reason, if you are using !RiScript to debug a Scrib file, you should click the square button on !RiScript's toolbar to clear the display before double clicking on the updated Scrib file.

The Scribble language

Hello World example

Let us have a look at a very simple Scribble file, that bears the hoary message Hello World.

-- world a simple example

mydoc = BEGIN (arg[1].."/pdf")

mydoc:begin_page (A6.width,A6.height)

times_roman = mydoc:findfont ("Times-Roman", "host", 0)

mydoc:setfont(times_roman, 18)

mydoc:set_text_pos (A6.width/3,A6.height/1.5)

mydoc:show "Hello World"

mydoc:END ()

We have used blue to indicate those words which are not part of the Scribble language but can be chosen by you. The first line is a comment. It has no effect on the output PDF file. A comment starts with two consecutive minus signs (--) and continues to the end of the line. The next line creates an embryo PDF document, which we have chosen to call mydoc. The argument to BEGIN determines the filename that mydoc is eventually to be saved to. In this case we have decided to call it the same name as that of the Scribble file containing the description, but with /pdf appended on the end. In this case the leafname of the file is world, so the output will be saved to world/pdf in the same directory. The expression arg[1] denotes the full filename of the current Scribble file and the two full stops (..) denote the operator for concatenating strings.

Observe that subsequent instances of mydoc occur followed immediately by a colon (:) followed immediately by another word. These words are the names of functions called document-methods. In this case we have methods begin_page, findfont, setfont, set_text_pos, show, END. The arguments to a method are enclosed in parentheses, but these may be omitted if there is a single argument which is a literal string, as in the penultimate line. Learning to describe a PDF file with Scribble comes down to understanding a list of 78 methods and what their arguments can be. The arguments to begin_page determine the size of the page, measured in DTP points, i.e. 1/72 inches. Certain sizes are predefined, namely A0, A1, A2, A3, A4, A5, A6, B5, Letter, Legal, Ledger. The findfont method returns a font-handle, which we have called times_roman, for use in other methods such as setfont. The arguments to findfont are a font name, an encoding and an embedding flag. Because of the varieties of different sorts of font to be found, these arguments can be complicated, but for Risc OS users it is best to vary only the first argument, from among the following standard fonts.

  • Courier
  • Courier-Bold
  • Courier-Oblique
  • Courier-BoldOblique
  • Helvetica
  • Helvetica-Bold
  • Helvetica-Oblique
  • Helvetica-BoldOblique
  • Times-Roman
  • Times-Bold
  • Times-Italic
  • Times-BoldItalic
  • Symbol
  • ZapfDingbats

The setfont method takes a font-handle and a font-size in points. The set_text_pos takes two coordinates as arguments. The origin is at the bottom left of the page, but the coordinate system can be transformed in various ways. The show method takes a string as an argument. Finally the END method takes no arguments. It closes the page and saves the document as a PDF file.

Two page example

You can define various documents simultaneously, interweaving the methods for each. Here is a scribble program, page, that creates two PDF files, page1 and page2, with a link (a red star in a box) in page1 that launches page2.

x,y = BEGIN (arg[1].."1"), BEGIN (arg[1].."2")

x:begin_page(A5.width,A5.height)

y:begin_page(A5.width,A5.height)

x.font = x:findfont("Courier","host",0)

y.font = y:findfont("Courier","host",0)

x:setfont(x.font,20)

y:setfont(y.font,20)

x:show_xy("This is page1.",10,A5.height*0.9)

y:show_xy("This is page2.",10,A5.height*0.9)

x:continue_text("Click red * below")

y:END()

x:continue_text("to go to page2.")

x:setcolor("both","rgb",1,0,0,0) -- red

x:show_boxed("*",10,A5.height*0.7,30,20,"center","")

x:add_launchlink(10,A5.height*0.7,40,A5.height*0.8,"page2")

x:END ()

The first line may be a surprise to those not used to multiple assignment languages. We define two documents x and y in the same line. Of course, we could have used two separate lines. In the 4-th and 5-th lines we defined x.font and y.font to be font handles for x and y. The interweaving of the method calls for x and y is entirely arbitrary, chosen only to make the point. It would have been better style to keep them separate.

Chequerboard inverted in a circle

The inverse of a point P in a circle of radius and centre O is the point Q on the line OP for which OP.OQ is . The inverse of a figure is got by inverting each point of it. Inverses of circles and lines (circles of infinite radius) are circles and lines. Inversion leaves angles of intersection unchanged. The picture above shows the inversion of a chequerboard.

Here is a short Scribble program that produces this beautiful graphical result.

RESOLUTION, N = 512, 8

z = BEGIN (arg[1].."/pdf")

z:begin_page(RESOLUTION, RESOLUTION)

z:translate(RESOLUTION/2, RESOLUTION/2)

z:scale(RESOLUTION/8,RESOLUTION/8)

z:setcolor("fill","rgb",0,0.5,0.5,0)

z:set_parameter("fillrule","evenodd")

x = N

while x >= -N do

if x ~= 0 then

z:circle(2/x,0,2/abs(x))

z:circle(0,2/x,2/abs(x))

end -- if

x = x - 1

end -- while

z:fill()

z:END ()

King Arthur

A colourful nursery rhyme for our last example - here is a Scribble description.

verse1 = {

"When good king Arthur ruled the land",

"he was a goodly king.",

"He stole three pecks of barley rye",

"to make a bag pudding."

}

verse2 = {

"A bag pudding the king did make",

"and stuffed it full of plums,",

"and in it put great lumps of fat",

"as big as my two thumbs."

}

verse3 = {

"The king and queen did eat thereof",

"and noblemen beside,",

"and what they could not eat that night",

"the queen next morning fried."

}

x = BEGIN(arg[1].."/pdf")

x.red = function (self)

return self:setcolor("both","rgb",1,0,0,0)

end -- function

x.green = function (self)

return self:setcolor("both","rgb",0,1,0,0)

end -- function

x.blue = function (self)

return self:setcolor("both","rgb",0,0,1,0)

end -- function

x.showlines = function (self,t)

self:show("")

for i = 1,getn(t) do

self:continue_text(t[i])

end -- for

end -- function

x:begin_page(A4.width,A4.height)

icon = x:open_image_file("png",arg[1].."/png","",0)

x:place_image(icon,30,350,1)

x:close_image(icon)

font = x:findfont("Times-Roman", "host", 0)

x:setfont(font, 14)

x:set_text_pos(300, 700)

x:red()

x:showlines(verse1)

x:green()

x:continue_text(" ")

x:showlines(verse2)

x:blue()

x:continue_text(" ")

x:showlines(verse3)

x:END()

You may have noticed that the last two examples had rather more in them than just method-calls. The chessboard example had while ... do ... end and if ... then ... end constructs. The King Arthur example had user-defined methods, red, green, blue, showlines. The definition of the showlines method used a for ... do ... end construct. It also used tables for the separate verses. What is going on? Time to come clean.

Under the bonnet

!Scribble uses PDFLIB 4.0.3 (http://www.pdflib.com/) which is available under the Aladdin Free Public License (version 8, Nov. 18, 1999). This a library of C functions for making PDF files. It comes with bindings for Java, Perl, PHP, Python and Tcl; that is to say, if you are compiling these languages from C, then you can include the functions defined in PDFLIB as well and the relevant binding code lets you define new built in functions to create PDF files. Luiz Henrique de Figueiredo, one of the authors of Lua, which is free and copyright of TeCGraf, PUC-Rio, (http://www.lua.org/)

wrote a binding for Lua 4.0 and this is what I have used to create !Scribble. What this means is that Scribble is actually a small fragment of Lua with extra PDF-specific functions, namely BEGIN and the document methods, built-in. So to create PDF files with !Scribble you can use the full power of Lua as a programming language. I tried to persuade you in the first two examples that all you needed to know were those 78 document methods (only a few of them will get you quite far). Strictly speaking that is correct. But I hope that the last two examples demonstrate how Lua lets you extend the built-in core of Scribble further. In effect you can tailor the language to suit the kind of documents that you want to construct. Furthermore Scribble is not restricted to the double clicking way of creating PDF files that I have described above. For example, it could also be used to create PDF files from a database of text and pictures, using templates, in response to user queries.

The reference manual for PDFLIB is a PDF file over a megabyte in size. The Scribble document-methods correspond in a fairly obvious way to the C functions described in it. Scribble's documentation is fairly perfunctory at the moment, and I hope to improve it gradually, at the same time testing out which features do or do not work under Risc OS. The absence of definitive PDF display software, like Acrobat Reader, makes this task more difficult. PDF has been defined round the standards for most of the common platforms, but not RISC OS, so certain sections of the PDFLIB manual can be ignored.

Graphics come down in the end to MOVE and DRAW commands, as in BBC Basic. So it is no surprise to find similarities between the Drawfile format and parts of the PDF format. It should be possible to write a decompiler that translates a Drawfile into a Scribble file. Draw's notion of grouping objects could be translated into what PDFLIB calls templates - in effect, graphical subroutines. This would provide an avenue for creating graphics in PDF files by hand, avoiding the hassles of coordinate geometry that explicit coding brings.

Scribble is by no means a polished or completed artefact. I am not an expert with PDF. However, I hope that what is provided here is sufficient for others to use and develop.

Gavin Wraith

 Index