Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

A solution to printing in REBOL

 [1/13] from: g::santilli::tiscalinet::it at: 16-Jun-2001 19:59


Hi all! I see there has been some discussion on the list lately about the need of a (possibly multiplatform) solution to the problem of printing. One of the possible solution, useful when one has a relatively simple text document and does not need precise positioning of text in the page, is using HTML files. But if I need to print a report on a given template with precise text positioning? A better control on the page layout and size? In this case, a useful solution would be to create a PDF file. I see this solution has been proposed on the list, but I didn't see (maybe I missed them?) any taker wrt writing a dialect to generate PDF files. So I decided to write it myself. I downloaded the specification from www.adobe.com yesterday afternoon, and I was able to write a PDF generator in REBOL in about a day of work. WARNING! This is ALPHA unfinished buggy code! WARNING! I thought that this script might be useful. Creating a PDF file is as easy as writing: write/binary %pdf-file.pdf layout-pdf [ [ textbox [ "Hello world! This is a simple PDF file." ] ] ] Please run the provided pdf-maker-doc.r script to create the documentation, in PDF format of course. :-) I'm looking forward to get comments, and possibly help. Have fun! Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/ -- Attached file included as plaintext by Listar -- -- File: pdf-maker-doc.r REBOL [] do %pdf-maker.r write/binary %pdf-maker-doc.pdf layout-pdf [ [ ; page 1 textbox [ font Helvetica-Bold 36 offset 50 0 "PDF-Maker!" font Helvetica 12 offset 78 0 "(first alpha release)" offset -123 -20 {Welcome to pdf-maker.r preliminary documentation. This is my first attempt at a PDF generator as} newline offset -5 0 {a multiplatform solution to printing in } font Helvetica-Bold 12 {REBOL} font Helvetica 12 {. As you can see, it is pretty limited currently. Anyway, it should work, and can surely be improved in the future. Current limitations are:} newline offset 20 -5 "^(97) Text only, no graphics at the moment." newline "^(97) No colors, etc. You have to cope with just black text." newline "^(97) Only the 14 PostScript standard fonts are supported." newline "^(97) No justification, right alignement, etc." newline offset -20 -5 {Graphics would not be very difficult to add, so would colors. Custom fonts would definitely require work, and justification and right alignement would require A LOT of work, because you'd have to process font metrics and so on. These two are not likely to be added by me soon.} newline offset 0 -5 {Anyway, let's go on explaining how to create a PDF file. You'll need just one function, } font Courier 12 "layout-pdf" font Helvetica 12 {, which in turn just needs an argument of type } font Courier 12 "block!" font Helvetica 12 {:} newline offset 20 -5 font Courier 12 {layout-pdf [ ; page definitions here ]} newline offset -20 -5 font Helvetica 12 {This block contains a block for each page in the document, so that a document with two pages will look like:} newline offset 20 -5 font Courier 12 {layout-pdf [ [ ; first page ; ... ] [ ; second page ; ... ] ]} newline offset -20 -5 font Helvetica 12 {Each page definition might include and optional page size and rotation specification; the page size is expressed in millimeters (as any other position or size in the dialect). For example, to create a page 150 millimeters wide and 140 high, you can write:} newline offset 20 -5 font Courier 12 {[ page size 150 140 ; ... ]} newline offset -20 -5 font Helvetica 12 {while to create a page of default size (ISO A4, 211x297 millimeters) but rotated 270 degrees clockwise:} newline offset 20 -5 font Courier 12 {[ page rotation 270 ; has to be multiple of 90 ; ... ]} ] ] [ ; page 2 textbox [ {Of course the two can be specified together, in any order:} newline offset 20 -5 font Courier 12 {[ page rotation 90 size 180.5 280 ; ... ]} newline offset -20 -5 font Helvetica 12 {A page can contain any number of } font Times-Italic 12 "text boxes" font Helvetica 12 {; a text box is used to render text inside a rectangular area of the page with proper clipping. A text box can be created with:} newline offset 20 -5 font Courier 12 {[ textbox 10 17 191 263 [ ; text... ] ]} newline offset -20 -5 font Helvetica 12 {The numbers after } font Courier 12 "textbox" font Helvetica 12 { are x position, y position, width and height (the numbers shown above are a reasonable default for A4 pages used if you don't specify any). The position is referred to the LOWER LEFT corner of the box; also notice that the y axis is swapped if you compare it to REBOL/View's faces y axis.} newline offset 0 -5 {A simple text box can just contain a string of text. The lines of text will simply be rendered left justified inside the text box with the default font (Helvetica 12pt). However, it can also contain some commands to specify the font to use, where to position the text, and so on. The currently available commands are:} newline offset 20 -5 font Courier 10 {font <font-name> <font-size> ; font-size is in points offset <x-offset> <y-offset> ; in millimeters, relative to start of line newline ; just begins a new line line height <line-height> ; sets the line height} newline offset -20 -5 font Helvetica 12 {To see an example of these commands, look at the REBOL script that created this PDF file. Notice that the font name should be one of:} newline offset 20 -5 font Courier 10 {Helvetica Courier Times-Roman Symbol Helvetica-Bold Courier-Bold Times-Bold ZapfDingbats Helvetica-Oblique Courier-Oblique Times-Italic Helvetica-BoldOblique Courier-BoldOblique Times-BoldItalic} newline offset -20 -5 font Helvetica 12 "Enjoy!" newline offset 10 0 font Times-Italic 12 "Gabriele." ] ] ] -- Attached file included as plaintext by Listar -- -- File: pdf-maker.r REBOL [] context [ pdf-start: "%PDF-1.3^/" pdf-end: "%%EOF" pdf-string-valid: complement charset "()\" pdf-form: func ["REBOL to PDF" value /only /local result mrk1 mrk2] [ result: make string! 256 if block? :value [ if only [insert result "["] foreach element value [ insert insert tail result pdf-form/only element #" " ] either only [change back tail result "]"] [remove back tail result] return result ] if char? :value [ return head insert result reduce [ #"(" either find pdf-string-valid value [""] [#"\"] value #")" ] ] if string? :value [ insert result "(" parse/all value [ some [ mrk1: some pdf-string-valid mrk2: ( insert/part tail result mrk1 mrk2 ) | mrk1: skip ( insert insert tail result #"\" mrk1/1 ) ] ] insert tail result ")" return result ] if issue? :value [return form value] mold :value ] xref: [] contents: #{} pdf-words: context [ obj: func [id data] [ insert tail xref reduce [id index? tail contents] insert tail contents reduce [ id " 0 obj^/" pdf-form data "^/endobj^/" ] ] stream: func [id data] [ insert tail xref reduce [id index? tail contents] if block? data [data: pdf-form data] insert tail contents reduce [ id " 0 obj^/" pdf-form compose [ #<< /Length (length? data) #>> ] "^/stream^/" data "^/endstream^/endobj^/" ] ] ] zero-padded: func [val n] [ val: form val head insert insert/dup make string! n #"0" n - length? val val ] make-xref: has [pos] [ pos: tail contents insert pos "xref^/0 1^/0000000000 65535 f ^/" foreach [id ofs] xref [ insert tail pos reduce [ id " 1^/" zero-padded ofs 10 " 00000 n ^/" ] ] insert tail pos reduce [ newline "trailer^/" pdf-form compose [ #<< /Size (1 + divide length? xref 2) /Root 1 0 R ; this assumes root will always be 1 #>> ] "^/startxref^/" index? pos newline ] ] set 'make-pdf func [spec [block!]] [ clear xref clear contents insert contents pdf-start do bind spec in pdf-words 'self make-xref copy head insert tail contents pdf-end ] pages: [] used-fonts: [] font-resources: [] pdf-spec: [] default-page: context [ size: [211 297] ; mm. (ISO A4) rotation: 0 contents: [] ] default-textbox: context [ bbox: [10 17 191 263] text: [] ] make-docroot: does [ insert tail pdf-spec [ obj 1 [ #<< /Type /Catalog /Outlines 2 0 R /Pages 100 0 R #>> ] obj 2 [ #<< /Type /Outlines /Count 0 #>> ] obj 3 [ ; ProcSet to use in pages [/PDF /Text] ] ] ] new: val1: val2: bb: txtb: none txtb-emit: func [data] [ insert tail txtb/text reduce data ] use-font: func [name size] [ used-fonts: union used-fonts reduce [name] txtb-emit [to-refinement name size 'Tf size / 10 + size 'TL] ] font-def: ['font set val1 word! set val2 number! (use-font val1 val2)] offset-text: ['offset set val1 number! set val2 number! (txtb-emit [mm2pt val1 mm2pt val2 'Td])] set-lead: ['line 'height set val1 number! (txtb-emit [val1 'TL])] process-text: func [text] [ text: parse/all text "^/" if pick text 1 [txtb-emit [pick text 1 'Tj]] foreach line next text [ txtb-emit ['T* line 'Tj] ] ] draw-text: [set val1 string! (process-text val1)] textbox-rule: [ [font-def | none (use-font 'Helvetica 12)] (txtb-emit [mm2pt txtb/bbox/1 mm2pt txtb/bbox/2 + txtb/bbox/4 'Td 'T*]) some [ font-def | offset-text | 'newline (insert tail txtb/text 'T*) | set-lead | draw-text ] ] page-rule: [ (insert tail pages new: make default-page []) opt ['page any [ 'size set val1 number! set val2 number! (new/size: reduce [val1 val2]) | 'rotation set val1 integer! (new/rotation: val1) ]] any [ 'textbox (insert tail new/contents txtb: make default-textbox []) opt [(bb: clear []) 4 [set val1 number! (append bb val1)] (change txtb/bbox bb)] into textbox-rule ] ] parse-spec: func [spec] [ parse spec [some [into page-rule]] ] make-fonts: has [i] [ i: 4 clear font-resources foreach font used-fonts [ insert tail font-resources reduce [to-refinement font i 0 'R] insert tail pdf-spec compose/deep [ obj (i) [ #<< /Type /Font /Subtype /Type1 /BaseFont (to-refinement font) /Encoding /WinAnsiEncoding #>> ] ] i: i + 1 ] ] mm2pt: func [mm] [mm * 72 / 25.4] make-pages: has [i kids mediabox stream] [ i: 101 kids: clear [] foreach page pages [ insert tail kids reduce [i 0 'R] mediabox: reduce [0 0 mm2pt page/size/1 mm2pt page/size/2] stream: clear [] foreach textbox page/contents [ insert tail stream compose [ q (mm2pt textbox/bbox/1) (mm2pt textbox/bbox/2) (mm2pt textbox/bbox/3) (mm2pt textbox/bbox/4) re W n BT (textbox/text) ET Q ] ] insert tail pdf-spec compose/deep [ obj (i) [ #<< /Type /Page /Parent 100 0 R /MediaBox [(mediabox)] /Rotate (page/rotation) /Contents (i + 1) 0 R /Resources #<< /ProcSet 3 0 R /Font #<< (font-resources) #>> #>> #>> ] stream (i + 1) [ (stream) ] ] i: i + 2 ] insert tail pdf-spec compose/deep [ obj 100 [ #<< /Type /Pages /Kids [(kids)] /Count (length? pages) #>> ] ] ] set 'layout-pdf func [spec [block!]] [ clear pages clear used-fonts make-docroot parse-spec spec make-fonts make-pages make-pdf pdf-spec ] ]

 [2/13] from: robert:muench:robertmuench at: 21-Jun-2001 14:48


> -----Original Message----- > From: [rebol-bounce--rebol--com] [mailto:[rebol-bounce--rebol--com]]On Behalf Of
<<quoted lines omitted: 6>>
> PDF generator in REBOL in about a day of work. > WARNING! This is ALPHA unfinished buggy code! WARNING!
Hi, I tried it but it crashes on my system with a "should not happen" message. Is this only my problem? Anyway, I think this is a nice start and maybe we can expand "makedoc" with a PDF emitter. Robert

 [3/13] from: al:bri:xtra at: 23-Jun-2001 10:14


I, too, would be highly interested. Andrew Martin ICQ: 26227169 http://zen.scripterz.org

 [4/13] from: g:santilli:tiscalinet:it at: 22-Jun-2001 23:56


Hello Ladislav! On 22-Giu-01, you wrote: LM> Hi Gabriele, LM> I, for one, would like to have one. Maybe you missed the message from the list? I'm resending pdf-maker.r to you directly. Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [5/13] from: louisaturk:eudoramail at: 22-Jun-2001 18:17


Hi Gabriele, Would you please send it to me also please? Thanks, Louis At 11:56 PM 6/22/2001 +0200, you wrote:

 [6/13] from: depotcity:telus at: 22-Jun-2001 15:46


here's a link to the old message http://www.escribe.com/internet/rebol/m10731.html

 [7/13] from: larry:ecotope at: 22-Jun-2001 15:45


Hi Gabriele, Sorry for my belated reply. I downloaded your pdf-maker scripts the day you posted them. With Core 2.5 on Win98, they worked flawlessly to produce the documentation in PDF form. It displayed without problems in Acrobat reader v4 both directly and through the browser. I think you might have gotten a larger response on the mail-list if PDF had appeared in the subject line. The pdf-maker script is a very nice piece of work that well illustrates the power of REBOL. Hats off to you. Would it be possible for you to post the scripts to a website, the View lib, or someones' rebsite (I volunteer mine if you are interested). It would be better to have them as two separate scripts. That might have thrown a few folks trying to DO the email. Please don't abandon work on the pdf-maker, at least until you have added images and colors ;-) -Larry

 [8/13] from: lmecir:mbox:vol:cz at: 22-Jun-2001 21:44


Hi Gabriele, I, for one, would like to have one. L ...snip...

 [9/13] from: giesse:writeme at: 22-Jun-2001 14:22


Robert M. Muench wrote:
> Hi, I tried it but it crashes on my system with a "should not happen" message.
Maybe it's an email formatting problem?
> Is this only my problem? Anyway, I think this is a nice start and maybe we can > expand "makedoc" with a PDF emitter. Robert
I'll surely do that as soon as I have some free time. Anyway, it seems like there is not much interest in a PDF generator... Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [10/13] from: m:converso:bitinia at: 23-Jun-2001 8:07


Hi Gabriele me too: as you know very well best Maurizio Ladislav Mecir wrote:

 [11/13] from: ljurado:bariloche:ar at: 23-Jun-2001 13:04


Gabriele : do %pdf-maker.r write/binary %example.pdf layout-pdf [ [textbox ["Hello World !"] ] ] This is working OK, but, how can get the message in an 100 x 100 page ? Regards, Luis

 [12/13] from: g:santilli:tiscalinet:it at: 24-Jun-2001 12:26


Hello Luis! On 23-Giu-01, you wrote: LD> do %pdf-maker.r LD> write/binary %example.pdf layout-pdf [ [textbox ["Hello World LD> !"] ] ] LD> This is working OK, but, how can get the message in an 100 x LD> 100 page ? For a 100x100 millimeters page: layout-pdf [ [ page size 100 100 textbox 10 10 80 80 ["Hello World!"] ] ] You can read the documentation for the details. Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [13/13] from: robert:muench:robertmuench at: 24-Jun-2001 17:42


> -----Original Message----- > From: [giesse--sunti3--ing--univaq--it] [mailto:[giesse--sunti3--ing--univaq--it]]On
<<quoted lines omitted: 3>>
> Subject: [REBOL] Re: A solution to printing in REBOL > Maybe it's an email formatting problem?
Hi, hmm... you sent it in plain text and I just copied it into a text-editor. Anyway, I check it out.
> I'll surely do that as soon as I have some free time. Anyway, it > seems like there is not much interest in a PDF generator...
Well, there now has been generated some interest :-)). A simple makedoc emitter would be a nice place to start, there are a lot of input files available to test it. Robert

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted