pdflib: BBCSDL hard copy output

Discussions related to the code libraries supplied with BB4W & BBCSDL
svein
Posts: 58
Joined: Tue 03 Apr 2018, 19:34

Re: pdflib: BBCSDL hard copy output

Post by svein »

No, russian is not included yet.
This library is currently hardcoded to WinAnsiEncoding.
From wikipedia:
Windows Code Page 1252, often called the “Windows ANSI” encoding.
This is the standard Windows encoding for Latin text in Western writing
systems.
These encodings were designed for representation of Italian, Spanish, Portuguese, French, German, Dutch, English, Danish, Swedish, Norwegian, and Icelandic, which use the Latin alphabet.
I have not yet figured out what to do with the rest of the languages.

Maybe there's an utf-8 routine in BBCbasic that can be of some help ?
Just to clarify, does the library now support both ANSI and UTF-8? If yes, does it automatically follow the BBC BASIC setting or is it necessary to configure it separately for the required encoding?
It's supposed to support both, yes.

Currently the text string is scanned for the presence of &C3 and if found the following byte is converted to "\xxx".

Code: Select all

	  REPEAT
            I%=INSTR(text$,CHR$195,I%+1)
            IF I% THEN
              A%=ASCMID$(text$,I%+1)+64
              a$="\"+CHR$((A%>>6)+48)+CHR$((A%>>3AND7)+48)+CHR$((A%AND7)+48)
              text$=LEFT$(text$,I%-1)+a$+MID$(text$,I%+2)
            ENDIF
          UNTIL I%=0
Working UTF-8 example:

Code: Select all

H=22 : Y-=H : PROC_PLfont("Times",H,0)
PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz åæø ÅÆØ")
This is going to need more work i guess, i'll keep digging.

Regards Svein
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

svein wrote: Thu 09 Apr 2020, 23:15 This library is currently hardcoded to WinAnsiEncoding.
So it's ANSI only and doesn't support Unicode at all?! :o
Currently the text string is scanned for the presence of &C3
&C3 has no special significance in Unicode. In UTF-8 all bytes &00-&7F are single-byte characters and all bytes &80-&FF begin, or are part of, multi-byte sequences. In ANSI &C3 is à (capital A with a tilde) so as far as I can see all that code achieves is to make your library incompatible with ANSI (because that character cannot be used) without making it any more compatible with Unicode. :cry:
Working UTF-8 example:
There's nothing 'Unicode' about that! All the characters in that string are ANSI characters; it so happens that they have the same code-points in both Unicode and ANSI (that's common, but not universal, with code points up to 255), but that is the only reason it is "working".

This post has been reported for violating the forum's guidelines.
Last edited by RichardRussell on Mon 13 Apr 2020, 00:00, edited 1 time in total.
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

Another question about PDFLIB if I may. The BB4W manual says "You can print more than one graphic on the same page by using *HARDCOPY multiple times with different offsets specified. Similarly you can combine graphics and text by using *HARDCOPY in conjunction with the VDU 2 and VDU 3 commands". But the description of PDFLIB implies that you can only do one hardcopy per page; if that's right can the restriction be removed?
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

I've made some progress hacking PDFLIB to accept Unicode, but the character spacing is wrong (might even be monospaced); I've no idea why. If anybody fancies looking at the PDF to see where the fault lies it's here.

pdf_rtr.gif
You do not have the required permissions to view the files attached to this post.
Last edited by RichardRussell on Sun 12 Apr 2020, 19:09, edited 1 time in total.
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

RichardRussell wrote: Sat 11 Apr 2020, 10:31(might even be monospaced)
Indeed it was monospaced. It turns out that, with Unicode, it is compulsory to include a table of glyph widths in the PDF file, and if you don't it defaults to a fixed width. This is rather silly because the widths can also be obtained from the TrueType font tables, but for some reason they aren't used. Since there may well be many thousands of glyphs the width table is quite large, but that's just how it is.

pdf_good.gif
You do not have the required permissions to view the files attached to this post.
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

RichardRussell wrote: Fri 10 Apr 2020, 08:56it so happens that they have the same code-points in both Unicode and ANSI (that's common, but not universal, with code points up to 255)
The Euro symbol is an example of a character which is in both ANSI and Unicode character sets, but with different codes. In ANSI it's &80 and in Unicode it's &20AC. There are at least 26 other characters that I know of which have the same property of being in both character sets but with different codes.
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

Summarising what my (limited) research has determined:
  • The built-in PDF fonts are ANSI only, there is no support for Unicode.
  • To support Unicode it is necessary to embed a TrueType font in the PDF file.
  • A glyph widths table is necessary, even though the information is in the font.
It makes sense that a TrueType (or OpenType) font must be embedded to support Unicode, because you can't expect every PDF reader to have the full set of characters (potentially more than 100,000) in each of the built-in fonts. By embedding a font you know exactly what characters are available and how they will be rendered. However it can make the PDF file very large (possibly several megabytes).

Here's an extract from the latest demo PDF (4 Mbytes) generated by Svein's PDFLIB library, as (slightly) modified by me. There are two embedded fonts, FreeSerif and DejaVuSans:

pdf_fonts.png
You do not have the required permissions to view the files attached to this post.
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

I have the feeling that I'm talking to myself, but just in case there is anybody interested here is a slightly modified demo program (it assumes the library will be in the same directory):

Code: Select all

      REM Demo of pdflib for bbcsdl, one page generated.
      REM Note: The screen output is not perfect WYSIWYG, but more like a draft of the generated pdf file.
      REM 1. The fonts are not the same. 2. The pdf grapich is antialiased.

      INSTALL @dir$ + "pdflib_rtr"

      REM default screen size = 596,842 = A4 paper size
      REM default graphics mode = pixels
      REM default pdf line style = LineCapButt and LineJoinMiter
      REM 1 pixel = 1 pdf unit = A4_paper_width/596 = 0.35278 mm

      REM PDF line styles
      LineCapRound  = &01000000
      LineCapSquare = &02000000
      LineJoinRound = &04000000
      LineJoinBevel = &08000000
      REM BBC graphic units
      GrUnits       = &10000000

      DIM r{x%,y%,w%,h%}
      SYS "SDL_GetDisplayBounds",0,r{}
      IF r.h%>899 THEN
        VDU 23,22,596;842;8,16,16,128+8 : REM 1192,1684   (A4 size)
      ELSE
        VDU 23,22,596;r.h%-60;8,16,16,128+8 : REM reduced height for small screens
        ORIGIN 0,(r.h%-842)*2
      ENDIF
      PROC_PLfont("Courier",12,0)

      REM line
      style = 0
      pencolour=0
      penwidth=2
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLline(100,30,400,35)
      PROC_PLprint(180,35,"Near horizontal line")

      REM outline rectangle
      pencolour=0
      penwidth=2
      fill=0
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLrectangle(100,440,350,100,fill)

      REM Filled rectangle
      pencolour=&AABBCC
      fill=1
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLrectangle(105,445,340,90,fill)
      PROC_PLprint(110,485,"Text is always printed on top of graphics.")
      PROC_PLprint(110,545,"Filled rectangle inside outline rectangle.")

      REM Cubic Bezier curve from four control points
      pencolour = &FF : REM blue
      penwidth = 5.5
      fill=0
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLbezier(10, 10, 100, 100, 200, 300, 400, 300, fill) : REM start,cp1,cp2,end,fill
      PROC_PLprint(405,296,"Cubic bezier line")

      REM Switching to BBC graphic units mode
      style=GrUnits

      REM Filled five-pointed star   (copy from aagfxdem.bbc)
      pencolour = &808080 : REM grey
      penwidth = 1.0
      fill=1
      DIM X(5), Y(5)
      X() = 1100,900,1060,1000,940,1100
      Y() = 430,430,320,500,320,430
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLpolyline(6, X(), Y(), fill)
      PROC_PLprint(870,500,"Polyline filled star")

      REM Angled solid ellipse    (copy from aagfxdem.bbc)
      REM degrees, 0 degree up, clockwise
      pencolour = &80A080
      angle=30
      fill=1
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLellipse(200, 450, 140, 50, angle, fill)
      PROC_PLprint(100,590,"Angled solid ellipse")

      REM Heart shape from polybezier   (copy from aagfxdem.bbc)
      x = 600 : y = 250
      DIM x(12), y(12)
      x() = x, x,    x-100, x-100, x-100, x,    x,     x,    x+100, x+100, x+100, x,    x
      y() = y, y+60, y+60,  y,     y-60,  y-70, y-110, y-70, y-60,  y,     y+60,  y+60, y
      pencolour = &400000
      penwidth = 1.0
      fill=1
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLpolybezier(13, x(), y(), fill)
      pencolour = &C0392B
      penwidth = 3.0
      fill=0
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLpolybezier(13, x(), y(), fill)
      PROC_PLprint(410,310,"Heart shape from polybezier")

      REM back to pixel mode
      style=0

      REM Circle
      pencolour = 0
      penwidth = 2.0
      fill=0
      PROC_PLcolour(pencolour,penwidth,style)
      PROC_PLcircle(450,375,50,fill)
      PROC_PLprint(430,372,"Circle")

      REM sector diagram, degrees, 0 degree up, clockwise
      x=250 : y=350 : radius=60 : fill=1
      PROC_PLcolour(&8040FF,penwidth,style)
      PROC_PLsector(x,y,radius,0,60,fill) : REM angle=0 extent=60
      PROC_PLcolour(&40FF80,penwidth,style)
      PROC_PLsector(x,y,radius,60,30,fill) : REM angle=60 extent=30
      PROC_PLcolour(&FF8040,penwidth,style)
      PROC_PLsector(x,y,radius,90,100,fill)
      PROC_PLcolour(&80A0C0,penwidth,style)
      PROC_PLsector(x,y,radius,190,150,fill)
      PROC_PLcolour(&BBFF00,penwidth,style)
      PROC_PLsector(x,y,radius,340,20,fill)
      PROC_PLprint(x-radius,y+radius+15,"Filled sector")
      PROC_PLprint(x-radius,y+radius+5,"diagram")

      REM text waterfall
      Y=700
      H=8 : Y-=H : PROC_PLfont("Helvetica",H,0) : REM colour=0=black
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=10 : Y-=H : PROC_PLfont("Helvetica",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=12 : Y-=H : PROC_PLfont("Helvetica",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=14 : Y-=H : PROC_PLfont("Helvetica",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=16 : Y-=H : PROC_PLfont(@lib$ + "DejaVuSans.ttf",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=18 : Y-=H : PROC_PLfont(@lib$ + "DejaVuSans.ttf",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=20 : Y-=H : PROC_PLfont(@lib$ + "DejaVuSans.ttf",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")
      H=22 : Y-=H : PROC_PLfont(@lib$ + "DejaVuSans.ttf",H,0)
      PROC_PLprint(60,Y,"abcdefghijklmnopqrstuvwxyz £€\1234567890 ")

      REM demo of fonts
      PROC_PLfont("Helvetica",14,0)
      PROC_PLprint(20,820,"Helvetica: ")
      PROC_PLfont("Helvetica",14,&FF) : REM colour=blue
      PROC_PLprint(0,0,"Normal text ") : REM 0,0 = continue print on line
      PROC_PLfont("HelveticaB",14,&8000) : REM colour=green
      PROC_PLprint(0,0,"Bold text ")
      PROC_PLfont("HelveticaO",14,&FF0000) : REM colour=red
      PROC_PLprint(0,0,"Oblique text")

      PROC_PLfont("Times",14,0)
      PROC_PLprint(20,800,"Times: ")
      PROC_PLfont("Times",14,&FF)
      PROC_PLprint(0,0,"Normal text ")
      PROC_PLfont("TimesB",14,&8000)
      PROC_PLprint(0,0,"Bold text ")
      PROC_PLfont("TimesI",14,&FF0000)
      PROC_PLprint(0,0,"Italic text")

      PROC_PLfont("Courier",14,0)
      PROC_PLprint(20,780,"Courier: ")
      PROC_PLfont("Courier",14,&FF)
      PROC_PLprint(0,0,"Normal text ")
      PROC_PLfont("CourierB",14,&8000)
      PROC_PLprint(0,0,"Bold text ")
      PROC_PLfont("CourierO",14,&FF0000)
      PROC_PLprint(0,0,"Oblique text")

      PROC_PLfont(@lib$ + "FreeSerif.ttf",14,0)
      PROC_PLprint(20,760,"FreeSerif: ")
      PROC_PLfont(@lib$ + "FreeSerif.ttf",14,&FF)
      PROC_PLprint(0,0,"Հայերեն տեքստ ")
      PROC_PLfont(@lib$ + "FreeSerif.ttf",14,&8000)
      PROC_PLprint(0,0,"Ελληνικό κείμενο ")
      PROC_PLfont(@lib$ + "FreeSerif.ttf",14,&FF0000)
      PROC_PLprint(0,0,"Русский текст")

      PROC_PLfont(@lib$ + "DejaVuSans.ttf",14,0)
      PROC_PLprint(20,738,"DejaVuSans: ")
      PROC_PLfont(@lib$ + "DejaVuSans.ttf",14,&FF)
      PROC_PLprint(0,0,"Հայերեն տեքստ ")
      PROC_PLfont(@lib$ + "DejaVuSans.ttf",14,&8000)
      PROC_PLprint(0,0,"Ελληνικό κείμενο ")
      PROC_PLfont(@lib$ + "DejaVuSans.ttf",14,&FF0000)
      PROC_PLprint(0,0,"Русский текст")

      PROC_PLfont("Symbol",14,0)
      PROC_PLprint(20,716,"Symbol: ")
      PROC_PLfont("Symbol",14,&FF)
      PROC_PLprint(0,0,"Normal text  ")

      PROC_PLfont("Zap",14,0)
      PROC_PLprint(0,0,"ZapfDingBats: ")
      PROC_PLfont("Zap",14,&FF)
      PROC_PLprint(0,0,"Normal text ")

      MOVE 120,40 : PRINT "Note: Open the PDF file to see the final result !"

      ON CLOSE RETURN
      IF FN_PLcreatepdf(@usr$+"demo_rtr.pdf")=0 THEN ERROR 0,"can't create pdf_file"
      IF FN_PLhardcopy(@usr$+"demo_hardcopy.pdf")=0 THEN ERROR 0,"can't create pdf_file"
      ON CLOSE OFF
      END
And here is the modified PDFLIB library; I have tried to keep the changes from Svein's original code to a minimum. The only new feature is that PROC_PLfont can take either a font alias, as before, or a full path to a TTF file. In the latter case the font is embedded in the PDF and Unicode is supported, otherwise only ANSI characters can be used (although the source text is assumed to be UTF-8). There is a maximum of four such TTF fonts, determined in part by not wanting to alter Svein's original PDF object numbers:

Code: Select all

      REM Pdflib Version 1.1, Dec.2019, Version 1.2 (RTR) Apr.2020
      REM (C) Svein Svensson (sveinioslo@gmail.com) & Richard Russell (www.rtrussell.co.uk)

      REM Library to create a PDF file for BBCSDL
      REM Hardcoded to one sheet of A4 paper size, or hardcopy of current screen.
      REM Modified by Richard Russell to support Unicode text (must have embedded font)

      REM aliases to be used in PROC_PLfont():
      REM Times,TimesB,TimesI,TimesBI,Helvetica,HelveticaB,HelveticaO,HelveticaBO
      REM Courier,CourierB,CourierO,CourierBO,Symbol,Zap
      REM Alternatively a path to a TrueType file for Unicode (maximum four such fonts)

      REM The PostScript names of 14 Type 1 fonts, known as the standard 14 fonts, are as follows: Times-Roman,
      REM Helvetica, Courier, Symbol, Times-Bold, Helvetica-Bold, Courier-Bold, ZapfDingbats, Times-Italic, Helvetica-
      REM Oblique, Courier-Oblique, Times-BoldItalic, Helvetica-BoldOblique, Courier-BoldOblique

      REM Note: The screen output is not perfect WYSIWYG, but more like a draft of the generated pdf file.
      REM 1. The fonts are not the same. 2. The pdf graphics are antialiased.

      REM default screen size = 596,842 = A4 paper size
      REM default graphics mode = pixels
      REM default pdf line style = LineCapButt and LineJoinMiter
      REM 1 pixel = 1 pdf unit = A4_paper_width/596 = 0.35278 mm

      REM REM PDF line styles
      REM LineCapRound  = &01000000
      REM LineCapSquare = &02000000
      REM LineJoinRound = &04000000
      REM LineJoinBevel = &08000000
      REM REM BBC graphic units
      REM GrUnits       = &10000000

      REM ...........................................................................

      REM This software is provided 'as-is', without any express or implied
      REM warranty. In no event will the authors be held liable for any damages
      REM arising from the use of this software.

      REM Permission is granted to anyone to use this software for any purpose,
      REM including commercial applications, and to alter it and redistribute it
      REM freely, subject to the following restrictions:

      REM 1. The origin of this software must not be misrepresented; you must not
      REM    claim that you wrote the original software. If you use this software
      REM    in a product, an acknowledgment in the product documentation would be
      REM    appreciated but is not required.
      REM 2. Altered source versions must be plainly marked as such, and must not be
      REM    misrepresented as being the original software.
      REM 3. This notice may not be removed or altered from any source distribution

      DEF PROC_PLline(x1,y1,x2,y2) : LOCAL M%,R%
      DEF PROC_PLrectangle(x1,y1,x2,y2,R%) : LOCAL M% : M%=1
      DEF PROC_PLbezier(x1,y1,x2,y2,x3,y3,x4,y4,R%) : LOCAL M% : M%=2
      DEF PROC_PLsector(x,y,r,m,d,R%) : LOCAL M% : M%=3
      DEF PROC_PLpolyline(N%,X(),Y(),R%) : LOCAL M% : M%=4
      DEF PROC_PLpolybezier(N%,X(),Y(),R%): LOCAL M% : M%=5
      DEF PROC_PLellipse(x,y,r1,r2,m,R%): LOCAL M% : M%=6
      DEF PROC_PLcircle(x,y,r,R%) : LOCAL M% : M%=7
      DEF PROC_PLcolour(C%,W,S%) : LOCAL M% : M%=10
      DEF PROC_PLprint(x,y,text$) : LOCAL M% : M%=11  : REM VDU 5 print, x=y=0 = continue print on line
      DEF PROC_PLfont(font$,S%,C%) : LOCAL M% : M%=12 : REM (font alias/TTF file,font size,font colour)
      DEF FN_PLcreatepdf(file$): LOCAL M% : M%=20 : REM returns zero if the file was not created, for whatever reason.
      DEF FN_PLhardcopy(file$) : LOCAL M% : M%=21 : REM same as above
      PRIVATE tstream$,gstream$,tf$,flag%,ttf%,ttf$() : DIM ttf$(3)
      LOCAL debug% : debug%=0
      LOCAL units% : units%=&10000000
      GCOL 11
      CASE M% OF
        WHEN 0 : REM line
          IF debug% THEN gstream$+="%line"+CHR$10
          IF flag%ANDunits% THEN x1/=2 : x2/=2 : y1/=2 : y2/=2
          LINE x1*2,y1*2,x2*2,y2*2
          gstream$+=STR$x1+" "+STR$y1+" m "+STR$x2+" "+STR$y2+" l"
        WHEN 1 : REM rectangle
          IF debug% THEN gstream$+="%rectangle"+CHR$10
          IF flag%ANDunits% THEN x1/=2 : x2/=2 : y1/=2 : y2/=2
          IF R% THEN RECTANGLE FILL x1*2,y1*2,x2*2,y2*2 ELSE RECTANGLE x1*2,y1*2,x2*2,y2*2
          gstream$+=STR$x1+" "+STR$y1+" "+STR$x2+" "+STR$y2+" re"
        WHEN 2 : REM cubic bezier, (start,cp1,cp2,end)
          IF debug% THEN gstream$+="%bezier"+CHR$10
          LOCAL x(),y()
          DIM x(3),y(3)
          x()=x1,x2,x3,x4
          y()=y1,y2,y3,y4
          IF flag%ANDunits% THEN x()/=2 : y()/=2
          PROC_PLdrawbez(x(),y())
          gstream$+=STR$x(0)+" "+STR$y(0)+" m "
          gstream$+=STR$x(1)+" "+STR$y(1)+" "+STR$x(2)+" "+STR$y(2)+" "+STR$x(3)+" "+STR$y(3)+" c"
        WHEN 3 : REM sector
          IF debug% THEN gstream$+="%sector"+CHR$10
          LOCAL a,G%,step%
          step%=10 : REM anglesteps when plotting circle
          G%=LEN(gstream$)
          IF flag%ANDunits% THEN x/=2 : y/=2 : r/=2
          MOVE x*2,y*2
          gstream$+=STR$x+" "+STR$y+" m"
          x1=x+SINRAD(m)*r
          y1=y+COSRAD(m)*r
          DRAW x1*2,y1*2
          gstream$+=" "+STR$x1+" "+STR$y1+" l"
          FOR a=m TO m+d STEP step%
            x1=x+SINRAD(a)*r
            y1=y+COSRAD(a)*r
            DRAW x1*2,y1*2
            gstream$+=" "+STR$x1+" "+STR$y1+" l"
            IF LEN(gstream$)-G%>100 THEN gstream$+=CHR$10 : G%=LEN(gstream$)
          NEXT
          DRAW x*2,y*2
          gstream$+=" "+STR$x+" "+STR$y+" l"
        WHEN 4 : REM polyline
          IF debug% THEN gstream$+="%polyline"+CHR$10
          LOCAL xx(),yy(),I%,G%
          G%=LEN(gstream$)
          DIM xx(N%-1),yy(N%-1)
          xx()=X() : yy()=Y()
          IF flag%ANDunits% THEN xx()/=2 : yy()/=2
          MOVE xx(0)*2,yy(0)*2
          gstream$+=STR$xx(0)+" "+STR$yy(0)+" m"
          FOR I%=1 TO N%-1
            DRAW xx(I%)*2,yy(I%)*2
            gstream$+=" "+STR$xx(I%)+" "+STR$yy(I%)+" l"
            IF LEN(gstream$)-G%>100 THEN gstream$+=CHR$10 : G%=LEN(gstream$)
          NEXT
        WHEN 5 : REM cubic polybezier, (start,cp1,cp2,end/start,cp1,cp2,end/start,.......,end)
          IF debug% THEN gstream$+="%polybezier"+CHR$10
          LOCAL x(),y(),xx(),yy(),I%,G%
          G%=LEN(gstream$)
          DIM x(3),y(3),xx(N%-1),yy(N%-1)
          xx()=X() : yy()=Y()
          IF flag%ANDunits% THEN xx()/=2 : yy()/=2
          gstream$+=STR$xx(0)+" "+STR$yy(0)+" m"
          FOR I%=0 TO N%-4 STEP 3
            x(0)=xx(I%) : x(1)=xx(I%+1) : x(2)=xx(I%+2) : x(3)=xx(I%+3)
            y(0)=yy(I%) : y(1)=yy(I%+1) : y(2)=yy(I%+2) : y(3)=yy(I%+3)
            PROC_PLdrawbez(x(),y())
            gstream$+=" "+STR$x(1)+" "+STR$y(1)+" "+STR$x(2)+" "+STR$y(2)+" "+STR$x(3)+" "+STR$y(3)+" c"
            IF LEN(gstream$)-G%>100 THEN gstream$+=CHR$10 : G%=LEN(gstream$)
          NEXT
          IF RIGHT$(gstream$)=CHR$10 THEN gstream$=LEFT$(gstream$)
        WHEN 6 : REM angled ellipse
          IF debug% THEN gstream$+="%ellipse"+CHR$10
          LOCAL x1,x2,x3,x4,y1,y2,y3,y4,x(),y()
          IF flag%ANDunits% THEN x/=2 : y/=2 : r1/=2 : r2/=2
          DIM x(3),y(3)
          m=RAD(m) : r2*=1.333333
          x1=x+SIN(m)*r1 : y1=y+COS(m)*r1
          x2=x-SIN(m)*r1 : y2=y-COS(m)*r1
          m+=PI/2
          x3=x1+SIN(m)*r2 : y3=y1+COS(m)*r2
          x4=x2+SIN(m)*r2 : y4=y2+COS(m)*r2
          x()=x1,x3,x4,x2 : y()=y1,y3,y4,y2
          PROC_PLdrawbez(x(),y())
          gstream$+=STR$x(0)+" "+STR$y(0)+" m"
          gstream$+=" "+STR$x(1)+" "+STR$y(1)+" "+STR$x(2)+" "+STR$y(2)+" "+STR$x(3)+" "+STR$y(3)+" c"
          x3=x1-SIN(m)*r2 : y3=y1-COS(m)*r2
          x4=x2-SIN(m)*r2 : y4=y2-COS(m)*r2
          x()=x2,x4,x3,x1 : y()=y2,y4,y3,y1
          PROC_PLdrawbez(x(),y())
          gstream$+=" "+STR$x(1)+" "+STR$y(1)+" "+STR$x(2)+" "+STR$y(2)+" "+STR$x(3)+" "+STR$y(3)+" c"
        WHEN 7 : REM circle
          IF debug% THEN gstream$+="%circle"+CHR$10
          LOCAL a,G%,step%
          step%=10 : REM anglesteps when plotting circle
          G%=LEN(gstream$)
          IF flag%ANDunits% THEN x/=2 : y/=2 : r/=2
          MOVE x*2,y*2+r*2
          gstream$+=" "+STR$x+" "+STR$(y+r)+" m"
          FOR a=0 TO 360 STEP step%
            x1=x+SINRAD(a)*r
            y1=y+COSRAD(a)*r
            DRAW x1*2,y1*2
            gstream$+=" "+STR$x1+" "+STR$y1+" l"
            IF LEN(gstream$)-G%>100 THEN gstream$+=CHR$10 : G%=LEN(gstream$)
          NEXT
        WHEN 10 : REM colour  xxRRGGBB
          IF debug% THEN gstream$+="%colour"+CHR$10
          LOCAL r&,g&,b&
          r&=C%>>16 : g&=C%>>8 : b&=C%
          gstream$+=STR$(r&/255)+" "+STR$(g&/255)+" "+STR$(b&/255)+" RG "
          gstream$+=STR$(r&/255)+" "+STR$(g&/255)+" "+STR$(b&/255)+" rg "
          gstream$+=STR$(S%>>24 AND 3)+" J "+STR$((S%>>24 AND &C)>>2)+" j "
          gstream$+=STR$W+" w "+CHR$10
          COLOUR 11,r&,g&,b&
          VDU 23,23,W|
          flag%=S%
          ENDPROC
        WHEN 11 : REM print UTF-8 text (x=y=0=continue on line)
          PRIVATE oldx,oldy
          VDU 5 : GCOL 10
          IF x=0 AND y=0 THEN
            PRINT text$; : tstream$+=tf$+FN_PLencode(tf$,text$)+" Tj"+CHR$10
          ELSE
            IF flag%ANDunits% THEN x/=2 : y/=2
            IF POS
            MOVE x*2,y*2+@vdu%!220*2 : PRINT text$;
            tstream$+=tf$+STR$(x-oldx)+" "+STR$(y-oldy)+" Td "+FN_PLencode(tf$,text$)+" Tj"+CHR$10
            oldx=x : oldy=y
          ENDIF
          tf$=""
          ENDPROC
        WHEN 12 : REM font   (alias or TTF file)
          IF debug% THEN tstream$+="%font"+CHR$10
          LOCAL I%,r&,g&,b&,a$,b$
          a$=RIGHT$(font$,2)
          IF ASC(a$)>96 THEN a$=RIGHT$(a$)
          CASE a$ OF
            WHEN "B"       : b$=",B"
            WHEN "I","O"   : b$=",I"
            WHEN "BI","BO" : b$=",BI"
          ENDCASE
          IF INSTR(font$, "/") OR INSTR(font$, "\") THEN
            a$="""" + font$ + ""","
            WHILE ttf$(I%) <> font$ AND ttf$(I%) <> "" : I% += 1 : ENDWHILE
            IF ttf% = I% ttf% += 1
            ttf$(I%) = font$
            font$ = "F" + STR$(I%+1)
          ELSE
            a$=""""+@lib$+"DejaVuSans.ttf"","
          ENDIF
          OSCLI "FONT "+a$+STR$(INT(S%/1.333+0.5))+b$
          r&=C%>>16 : g&=C%>>8 : b&=C%
          COLOUR 10,r&,g&,b&
          tf$=STR$(r&/255)+" "+STR$(g&/255)+" "+STR$(b&/255)+" rg "
          tf$+="/"+font$+" "+STR$S%+" Tf"+CHR$10
          ENDPROC
        WHEN 20,21 : REM createpdf + hardcopy
          LOCAL F%,I%,J%,xref%(),xc%,len1%,len2%,len3%,len4%,stream$,a$,b$
          LOCAL I%%,img%%,imgstart%%,imgw%,imgh%,xscreen%,yscreen%
          DIM xref%(99) : xc%=1
          F%=OPENOUT(file$)
          IF F%=0 THEN =0 : REM can't create file
          IF POS
          xscreen%=596
          yscreen%=842
          REM pre
          a$="%PDF-1.4"+CHR$10+"%"
          a$+=CHR$200 : a$+=CHR$201 : a$+=CHR$202 : a$+=CHR$203 : a$+=CHR$10
          xref%(xc%)=LEN(a$) : xc%+=1
          a$+="1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R >> endobj"+CHR$10
          xref%(xc%)=LEN(a$) : xc%+=1
          a$+="2 0 obj << /Type /Outlines /Count 0 >> endobj"+CHR$10
          xref%(xc%)=LEN(a$) : xc%+=1
          a$+="3 0 obj << /Type /Pages /Kids [4 0 R] /Count 1 >> endobj"+CHR$10
          xref%(xc%)=LEN(a$) : xc%+=1
          a$+="4 0 obj << /Type /Page /Parent 3 0 R /MediaBox [0 0 "+STR$xscreen%+" "+STR$yscreen%
          a$+="] /Contents " : IF M%=21 THEN a$+="7" ELSE a$+="5"
          a$+=" 0 R /Resources 6 0 R >> endobj"+CHR$10
          xref%(xc%)=LEN(a$) : xc%+=1
          IF M%=21 THEN
            b$=@tmp$+"hardcopy.bmp"
            ORIGIN 0,0
            OSCLI "SCREENSAVE "+b$
            I%=OPENIN b$
            DIM img%% EXT#I%
            CLOSE#I%
            OSCLI "LOAD "+b$+" "+STR$~img%%
            len2%=img%%!2-img%%!10
            imgstart%%=img%%+img%%!10
            imgw%=img%%!18
            imgh%=img%%!22
            a$+="5 0 obj << /Type /XObject /Subtype /Image "+CHR$10
            a$+="/Width "+STR$imgw%+" /Height "+STR$imgh%
            a$+=" /ColorSpace /DeviceRGB /BitsPerComponent 8 /Length "+STR$len2%+" >>"+CHR$10
            a$+="stream"+CHR$10
            len1%=LEN(a$)
            BPUT#F%,a$;
            FOR I%%=imgstart%%+len2%-1 TO imgstart%% STEP -1
              BPUT#F%,?I%%
            NEXT
            a$=CHR$10+"endstream endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="6 0 obj  << /ProcSet [/PDF /ImageC] /XObject << /Img1 5 0 R >> >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="7 0 obj << /Length >>"+CHR$10
            a$+="stream"+CHR$10
            b$="q"+CHR$10
            b$+="-"+STR$xscreen%+" 0 0 "+STR$yscreen%+" "+STR$xscreen%+" 0 cm"+CHR$10
            b$+="/Img1 Do"+CHR$10
            b$+="Q"+CHR$10
            J%=INSTR(a$,"/Length",0)
            a$=LEFT$(a$,J%+6)+" "+STR$LEN(b$)+MID$(a$,J%+7)
            a$+=b$+"endstream endobj"+CHR$10
            BPUT#F%,a$;
            len3%=LEN(a$)
          ELSE
            stream$=gstream$+"BT"+CHR$10+tstream$+"ET"+CHR$10
            len2%=LEN(stream$)
            a$+="5 0 obj << /Length "+STR$len2%+" >>"+CHR$10
            a$+="stream"+CHR$10
            BPUT#F%,a$; : BPUT#F%,stream$;
            len1%=LEN(a$)
            a$="endstream endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="6 0 obj  << /ProcSet [/PDF /Text]"+CHR$10
            a$+="/Font << /Times 11 0 R /TimesB 12 0 R /TimesI 13 0 R /TimesBI 14 0 R /Helvetica 15 0 R"+CHR$10
            a$+="/HelveticaB 16 0 R /HelveticaO 17 0 R /HelveticaBO 18 0 R /Courier 19 0 R /CourierB 20 0 R"+CHR$10
            a$+="/CourierO 21 0 R /CourierBO 22 0 R /Symbol 23 0 R /Zap 24 0 R"+CHR$10
            a$+="/F1 25 0 R /F2 26 0 R /F3 27 0 R /F4 28 0 R >> >> endobj"+CHR$10
            FOR I% = 0 TO DIM(ttf$(),1)
              xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
              IF ttf$(I%) <> "" THEN
                J% = OPENIN(ttf$(I%))
                IF J% = 0 ERROR 120, "Couldn't open file " + ttf$(I%)
                a$ += STR$(I%+7) + " 0 obj << /Length1 " + STR$EXT#J%
                a$ += " /Type /Stream /Length " + STR$EXT#J% + " >> stream" + CHR$10
                BPUT#F%,a$; : len1%+=LEN(a$)
                REPEAT a$ = GET$#J% BY &1000 : BPUT#F%,a$; : UNTIL LENa$ < &1000
                BPUT#F%,10  : len2%+=EXT#J% + 1
                CLOSE #J%
                a$="endstream endobj"+CHR$10
              ELSE
                a$ += STR$(I%+7) + " 0 obj null endobj"+CHR$10
              ENDIF
            NEXT
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="11 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="12 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-Bold /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="13 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-Italic /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="14 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-BoldItalic /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="15 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="16 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="17 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="18 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="19 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="20 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="21 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="22 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier-BoldOblique /Encoding /WinAnsiEncoding >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="23 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Symbol >> endobj"+CHR$10
            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="24 0 obj << /Type /Font /Subtype /Type1 /BaseFont /ZapfDingbats >> endobj"+CHR$10

            xref%(25)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="25 0 obj << /Type /Font /Subtype /Type0 /Encoding /Identity-H /DescendantFonts ["+CHR$10
            a$+="<< /CIDSystemInfo << /Ordering (Adobe) /Registry (Adobe) /Supplement 0 >>"+CHR$10
            a$+=FN_PLwidths(ttf$(0))
            a$+="/Subtype /CIDFontType2 /Type /Font /FontDescriptor << /StemV 777 /ItalicAngle 0 /Type /FontDescriptor"+CHR$10
            a$+="/FontName /CIDFont+F1 /Ascent 891 /FontFile2 7 0 R /Flags 4 /FontBBox [-777 -216 777 891]"+CHR$10
            a$+="/CapHeight 662 /Descent -216 >> /BaseFont /CIDFont+F1 >>] /BaseFont /CIDFont+F1 >> endobj"+CHR$10

            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="26 0 obj << /Type /Font /Subtype /Type0 /Encoding /Identity-H /DescendantFonts ["+CHR$10
            a$+="<< /CIDSystemInfo << /Ordering (Adobe) /Registry (Adobe) /Supplement 0 >>"+CHR$10
            a$+=FN_PLwidths(ttf$(1))
            a$+="/Subtype /CIDFontType2 /Type /Font /FontDescriptor << /StemV 777 /ItalicAngle 0 /Type /FontDescriptor"+CHR$10
            a$+="/FontName /CIDFont+F2 /Ascent 891 /FontFile2 8 0 R /Flags 4 /FontBBox [-777 -216 777 891]"+CHR$10
            a$+="/CapHeight 662 /Descent -216 >> /BaseFont /CIDFont+F2 >>] /BaseFont /CIDFont+F2 >> endobj"+CHR$10

            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="27 0 obj << /Type /Font /Subtype /Type0 /Encoding /Identity-H /DescendantFonts ["+CHR$10
            a$+="<< /CIDSystemInfo << /Ordering (Adobe) /Registry (Adobe) /Supplement 0 >>"+CHR$10
            a$+=FN_PLwidths(ttf$(2))
            a$+="/Subtype /CIDFontType2 /Type /Font /FontDescriptor << /StemV 777 /ItalicAngle 0 /Type /FontDescriptor"+CHR$10
            a$+="/FontName /CIDFont+F3 /Ascent 891 /FontFile2 9 0 R /Flags 4 /FontBBox [-777 -216 777 891]"+CHR$10
            a$+="/CapHeight 662 /Descent -216 >> /BaseFont /CIDFont+F3 >>] /BaseFont /CIDFont+F3 >> endobj"+CHR$10

            xref%(xc%)=len1%+len2%+LEN(a$) : xc%+=1
            a$+="28 0 obj << /Type /Font /Subtype /Type0 /Encoding /Identity-H /DescendantFonts ["+CHR$10
            a$+="<< /CIDSystemInfo << /Ordering (Adobe) /Registry (Adobe) /Supplement 0 >>"+CHR$10
            a$+=FN_PLwidths(ttf$(3))
            a$+="/Subtype /CIDFontType2 /Type /Font /FontDescriptor << /StemV 777 /ItalicAngle 0 /Type /FontDescriptor"+CHR$10
            a$+="/FontName /CIDFont+F4 /Ascent 891 /FontFile2 10 0 R /Flags 4 /FontBBox [-777 -216 777 891]"+CHR$10
            a$+="/CapHeight 662 /Descent -216 >> /BaseFont /CIDFont+F4 >>] /BaseFont /CIDFont+F4 >> endobj"+CHR$10

            BPUT#F%,a$;
            len4%=LEN(a$)
          ENDIF
          REM post
          a$="xref"+CHR$10
          a$+="0 "+STR$xc%+CHR$10
          a$+="0000000000 65535 f"+CHR$10
          FOR I%=1 TO xc%-1
            a$+=RIGHT$("0000000000"+STR$(xref%(I%)),10)+" 00000 n"+CHR$10
          NEXT
          a$+="trailer"+CHR$10
          a$+="<< /Size "+STR$xc%+" /Root 1 0 R >>"+CHR$10
          a$+="startxref"+CHR$10
          a$+=STR$(len1%+len2%+len3%+len4%)+CHR$10+"%%EOF"
          BPUT#F%,a$
          CLOSE#F%
          tstream$ = "" : gstream$ = "" : ttf$() = "" : ttf% = 0
          =1 : REM file created ok
      ENDCASE
      IF R% THEN gstream$+=" f"+CHR$10 ELSE gstream$+=" S"+CHR$10
      ENDPROC

      REM for internal use only
      DEF PROC_PLdrawbez(bx(),by()) : bx()*=2 : by()*=2
      LOCAL P,ps,x1,x2,x3,x4,x5,y1,y2,y3,y4,y5,a
      ps=40 : MOVE bx(0),by(0)
      FOR P=1 TO ps
        a=P/ps
        x1=bx(0)+(bx(1)-bx(0))*a : y1=by(0)+(by(1)-by(0))*a
        x2=bx(1)+(bx(2)-bx(1))*a : y2=by(1)+(by(2)-by(1))*a
        x3=bx(2)+(bx(3)-bx(2))*a : y3=by(2)+(by(3)-by(2))*a
        x4=x1+(x2-x1)*a : y4=y1+(y2-y1)*a
        x5=x2+(x3-x2)*a : y5=y2+(y3-y2)*a
        DRAW x4+(x5-x4)*a,y4+(y5-y4)*a
      NEXT
      bx()/=2 : by()/=2
      ENDPROC

      REM Encode UTF-8 text as ANSI (for built-in fonts) or UCS-2 (for TTF fonts)
      DEF FN_PLencode(f$,t$)
      LOCAL C%, I%, f%%, u$
      IF POS REM SDL thread sync
      IF @platform% AND &40 f%% = ]@vdu.hf% ELSE f%% = !@vdu.hf%
      IF INSTR(f$, "/F") THEN
        u$ = "<"
        WHILE I% < LEN(t$)
          I% += 1
          C% = ASCMID$(t$,I%)
          IF C% >= &E0 THEN
            C% = (C% << 12) AND &F000
            C% OR= (ASCMID$(t$,I%+1) << 6) AND &0FC0
            C% OR= ASCMID$(t$,I%+2) AND &003F
            I% += 2
          ELSEIF C% >= &C0 THEN;
            C% = (C% << 6) AND &07C0
            C% OR= ASCMID$(t$,I%+1) AND &003F
            I% += 1
          ENDIF
          SYS "FT_Get_Char_Index", f%%, C% TO C%
          u$ += RIGHT$("000" + STR$~C%, 4)
        ENDWHILE
        u$ += ">"
      ELSE
        REPEAT
          I%=INSTR(t$,"\",I%+1)
          IF I% THEN t$=LEFT$(t$,I%)+"134"+MID$(t$,I%+1)
        UNTIL I%=0
        u$ = "("
        WHILE I% < LEN(t$)
          I% += 1
          C% = ASCMID$(t$,I%)
          IF C% >= &E0 THEN
            C% = (C% << 12) AND &F000
            C% OR= (ASCMID$(t$,I%+1) << 6) AND &0FC0
            C% OR= ASCMID$(t$,I%+2) AND &003F
            I% += 2
          ELSEIF C% >= &C0 THEN;
            C% = (C% << 6) AND &07C0
            C% OR= ASCMID$(t$,I%+1) AND &003F
            I% += 1
          ENDIF
          IF C% > &FF THEN
            CASE C% OF
              WHEN &20AC: C% = &80 : REM Euro
              WHEN &201A: C% = &82
              WHEN &0192: C% = &83
              WHEN &201E: C% = &84
              WHEN &2026: C% = &85
              WHEN &2020: C% = &86
              WHEN &2021: C% = &87
              WHEN &02C6: C% = &88
              WHEN &2030: C% = &89
              WHEN &0160: C% = &8A
              WHEN &2039: C% = &8B
              WHEN &0152: C% = &8C
              WHEN &017D: C% = &8E
              WHEN &2018: C% = &91
              WHEN &2019: C% = &92
              WHEN &201C: C% = &93
              WHEN &201D: C% = &94
              WHEN &2022: C% = &95
              WHEN &2013: C% = &96
              WHEN &2014: C% = &97
              WHEN &02DC: C% = &98
              WHEN &2122: C% = &99
              WHEN &0161: C% = &9A
              WHEN &203A: C% = &9B
              WHEN &0153: C% = &9C
              WHEN &017E: C% = &9E
              WHEN &0178: C% = &9F
            ENDCASE
          ENDIF
          u$ += CHR$C%
        ENDWHILE
        u$ += ")"
      ENDIF
      = u$

      REM Build table of glyph widths (this can be quite slow!)
      DEF FN_PLwidths(f$) : IF f$ = "" THEN = ""
      LOCAL G%, R%, f%%, a$ : a$ = "/W [ 1 ["
      OSCLI "font """ + f$ + """"
      IF @platform% AND &40 f%% = ]@vdu.hf% ELSE f%% = !@vdu.hf%
      REPEAT
        G% += 1
        SYS "FT_Load_Glyph", f%%, G%, 1 TO R%
        IF R% EXIT REPEAT
        IF @platform% AND &40 THEN
          a$ += STR$(1000 * !(](f%%+120) + 64) DIV (f%%!104 AND &FFFF)) + " "
        ELSE
          a$ += STR$(1000 * !(f%%!84 + 40) DIV (f%%!68 AND &FFFF)) + " "
        ENDIF
      UNTIL FALSE
      = LEFT$(a$) + "]]" + CHR$10
Further enhancements that I would like to see are support for multiple pages (so it could be used to implement File... Print in SDLIDE) and the ability to include multiple bitmap images on the same page (as the *HARDCOPY command in BB4W can). Perhaps Svein might consider adding them?
RichardRussell

Re: pdflib: BBCSDL hard copy output

Post by RichardRussell »

RichardRussell wrote: Mon 13 Apr 2020, 16:44 I have the feeling that I'm talking to myself
Evidently I was right. :( :cry: :( :cry: