PurePDF library 1.0 BETA

Developed or developing a new product in PureBasic? Tell the world about it.
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

Problem Solved!!! 8)

Just tested it by creating a 300 pages report.... and only 4mb of page file was consumed that was freed right after the end of the procedure!!!

Btw CPU usage has also improved, instead of 80% it dropped to 1% !!!

Hurray!

Excelent work Lucky !

:mrgreen:
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

some Bugfixes from me :twisted:

Code: Select all

Procedure pdf_MultiCellBasic(w.f,h.f,txt.s,border.f,align.s,fill.f, indent.w)
  Protected wMax.f, wMaxOther.f, wFirst.f, wOther.f, wMaxFirst.f
  Protected s.s
  Protected nb.l
  Protected first.b
  Protected savex.f
  ;Output text with automatic Or explicit line breaks
  If(w=0)
    w=pdf()\w - pdf()\fRightMargin - pdf()\x
  EndIf
  wFirst = w - indent
  wOther = w
  wmaxFirst = (wFirst-2*pdf()\fCellMargin)*1000/pdf()\fFontSize
  wmaxOther = (wOther-2*pdf()\fCellMargin)*1000/pdf()\fFontSize
  
  s = ReplaceString(txt, "\r","")
  nb  = Len(s)
  If(nb>0 And Right(s,1) = Chr(13))
    nb = nb - 1
  EndIf
  b = 0
  If border <> 0
    If(border=1)
      border= #borderl + #borderr + #bordert + #borderb
      b= #borderl + #borderr + #bordert
      b2=#borderl + #borderr
    Else
      b2=0
      If FindString("-1-4-6-9-11-14-16-19", Str(border),1) > 0
        b2=b2+#borderl
      EndIf
      If FindString("-3-4-8-9-13-14-18-19", Str(border),1) > 0
        b2=b2+#borderr
      EndIf
      If FindString("-5-6-8-9-15-16-18-19", Str(border),1) > 0
        b2=b2+#bordert
      EndIf
      b=b2
    EndIf  
  EndIf
  sep=-1
  i=1
  j=0
  l=0
  ns=0
  nl=1
  c.s
  first=#TRUE
  While(i<nb)
    ;Get Next character
    c = Mid(s,i,1)    
    If c = Chr(10)
            
      ;Explicit line Break
      If(pdf()\ws>0)     
        pdf()\ws=0
        _outstring("0 Tw")
      EndIf
      pdf_Cell7(w,h,Mid(s,j,i-j),b,2,align,fill)
      i = i + 1
      sep = -1
      j=i  
      l=0
      ns=0
      nl= nl +1
      If nl=2 And border <>0
        b=b2
      EndIf  
      Continue
    EndIf
    If(c=" ")
      sep = i
      ls = l
      ns=ns+1    
    EndIf
    l=l+fonts()\wCharWidth[Asc(c)]
   
    If first = #TRUE
      wmax = wmaxFirst
      w = wFirst
    Else
      wmax = wmaxother
      w = wother
    
    EndIf    
   
    If l>wmax
      ;Automatic line Break
      If(sep=-1)
        If(i=j)
          i = i +1
        EndIf  
        If(pdf()\ws>0)
          pdf()\ws=0
          _outstring("0 Tw")
        EndIf  
        savex = pdf()\x
        If (first = #TRUE And indent >0)
          pdf_SetX(pdf()\x + indent)
          first = #FALSE
        EndIf        
        pdf_Cell7(w,h,Mid(s,j,i-j),b,2,align,fill)      
        If (first = #FALSE)
          pdf_SetX(savex)
        EndIf
      Else
        If(align="J")
          If (ns>1)
 
             pdf()\ws = (wmax-ls)/1000*pdf()\ffontsize/(ns-1)
          Else
             pdf()\ws = 0
          EndIf
    
          _outstring(StrF(pdf()\ws*pdf()\k,3) + " Tw")
        EndIf  
        savex = pdf()\x
        If (first=#TRUE And indent > 0)
          pdf_SetX(pdf()\x + indent)
          first = #FALSE
        EndIf
        pdf_Cell7(w,h,Mid(s,j,sep-j),b,2,align,fill)
        If (first = #FALSE)
          pdf_SetX(savex)
        EndIf
        i=sep +1
      EndIf
      sep=-1;
      j=i;
      l=0;
      ns=0;
      nl = nl +1
      If(border <> 0 And nl=2)
        b=b2;
      EndIf  
    Else
      i=i+1
    EndIf
  Wend  
  ;Last chunk
   If(pdf()\ws>0)
     pdf()\ws=0
     _outstring("0 Tw");
   EndIf
   If FindString("-10-11-13-14-15-16-18-19", Str(border),1) > 0 And border <> 0
     b=b+#borderb
   EndIf
   pdf_Cell7(w,h,Mid(s,j,i-j + 1),b,2,align,fill)
   pdf()\x=pdf()\fLeftMargin;
EndProcedure
Especialy the part with the "If (first = #FALSE)" and so on ...
I wonder that this works theres no call to pdf_init() and pdf_end() 8O

has someone a working userlibrary "zlib" for PB3.91 ?
My is reporting "POLINK: error: Unresolved external symbol '_errno'."

Thanks and keep on making this good libs :idea:
schic
User
User
Posts: 34
Joined: Fri Sep 12, 2003 10:17 am

Post by schic »

added 40 bit encryption, converting the php code from
Klemen Vodopivec to PB (http://www.fpdf.org/en/script/script37.php)
Here are the Globals to add:

Code: Select all

Global encrypted.b
Global *padding.l
Global Ovalue$
Global Uvalue$
Global Pvalue.b
Global enc_obj_id.l
Global encryption_key$

Global pCompress.l
and procedures to complement:

Code: Select all

Procedure _PutTrailer()
  _outstring("/Size " + Str(pdf()\wObjNum + 1))
  _outstring("/Root " + Str(pdf()\wObjNum) + " 0 R")  
  _outstring("/Info " + Str(pdf()\wObjNum - 1) + " 0 R")  
  If encrypted
    ;$this->_out('/Encrypt '.$this->enc_obj_id.' 0 R');
    _outstring("/Encrypt " + Str(enc_obj_id) + " 0 R")
    ;$this->_out('/ID [()()]');
    _outstring("/ID [()()]")
  EndIf
EndProcedure

Procedure _PutStream(*aData.strData)
  
  tmpSize=*aData\lCurSize
  If encrypted
    _RC4(*aData\pData, tmpSize, _objectkey(pdf()\wObjNum))
  EndIf
  
  _outstring("stream")
  _OutStream(*aData)
  _outstring("endstream")
EndProcedure

Procedure.s _TextString(as.s)
  Protected lsResult.s
  If encrypted
    _RC4(@as,Len(as),_objectkey(pdf()\wObjNum))
  EndIf
  ; Format a text string
  lsResult = "(" + _escape(as) + ")"
  ProcedureReturn lsResult
EndProcedure

Procedure _PutResources()
  _PutFonts()
  _PutImages()
  ;Resource dictionary
  SelectElement(Offsets(),1)
  Offsets() = sBuffer\lCurSize
  _outstring("2 0 obj")
  _outstring("<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")
  _outstring("/Font <<")
  ForEach Fonts()
    _outstring("/F" + Str(Fonts()\bFontNum) + " " + Str(Fonts()\wObjNum) + " 0 R")
  Next
  _outstring(">>")
  If (CountList(Images()) > 0)
    _outstring("/XObject <<")
    ForEach Images()
      _outstring("/I" + Str(Images()\bImageNum) + " " + Str(Images()\wObjNum) + " 0 R")
      _outstring(">>")
    Next
  EndIf  
  _outstring(">>")
  _outstring("endobj") 
  _putBookMarks() 
  If pdf()\sJavaScript <> ""
    _PutJavascript()
  EndIf
  
  If encrypted
    _NewObj()
    enc_obj_id = pdf()\wObjNum
    _outstring("<<")
    _putencryption()
    ;_outstring(">>")
  EndIf
  
EndProcedure
and some to add:

Code: Select all

Procedure _putencryption()
  _outstring("/Filter /Standard")
  _outstring("/V 1");
  _outstring("/Length 40");
  _outstring("/R 2");
  _outstring("/O (" + _escape(Ovalue$) + ")")
  _outstring("/U (" + _escape(Uvalue$) + ")")
  _outstring("/P " + Str(Pvalue))
  _outstring(">>")
  _outstring("endobj")
  EndProcedure

Procedure.l _RC4(Mem.l, memLen.l, key.s) 
  ;RC4Mem(*MemoryBuffer.l, MomeryLength.l, Key.s) 
  Dim S.l(255) 
  Dim K.l(255)  
  
  i.l=0: j.l=0: t.l=0: x.l=0 
  temp.l=0: y.l=0 
  
  j = 1 
  l.l           =Len(key) 
  *Sp.LONG      = @S() 
  *keyP.BYTE    = @key 
  For i = 0 To 255 
    *Sp\l = i          
    *Sp + 4          
    If *keyP\b = 0 
      *keyP = @key 
    EndIf 
    K(i) = *keyP\b 
    *keyP+1 
  Next i 
  
  j = 0 
  For i = 0 To 255 
    j = (j + S(i) + K(i)) & 255 
    temp = S(i) 
    S(i) = S(j) 
    S(j) = temp 
  Next i 
  
  i = 0 
  j = 0 
  *Memm.BYTE = Mem 
  For x = 0 To memLen-1 
    i = (i+1) & 255 
    j = (j + S(i)) & 255 
    temp = S(i) 
    S(i) = S(j) 
    S(j) = temp 
    t = (S(i) + (S(j) & 255)) & 255 
    y = S(t) 
    *Memm\b ! y 
    *Memm + 1  
  Next 
  
  ProcedureReturn Mem 
EndProcedure 

Procedure.l hexdec(h$)
  ; h$ can be 0-FFFFFFF.
  ;chars=Len(h$)
  h$=UCase(h$)
  For r=1 To 2;chars
    d<<4 : a$=Mid(h$,r,1)
    If Asc(a$)>60
      d+Asc(a$)-55
    Else
      d+Asc(a$)-48
    EndIf
  Next
  ProcedureReturn d
EndProcedure

Procedure.s _md5_16(*txt,txt_len)
  Shared ret$
  tmp$ = MD5Fingerprint(*txt,txt_len)
  ret$=""
  For i = 1 To 32 Step 2
    ;$out.=chr(hexdec(substr($tmp,$i,2)))
    ret$ + Chr(hexdec(Mid(tmp$,i,2)))
  Next
  ProcedureReturn ret$
EndProcedure

Procedure.s _OValue(*U, *O)
  *tmpU=AllocateMemory(32)
  CopyMemory(*U,*tmpU,32)
  tmp$ = _md5_16(*O, 32)
  owner_RC4_key$ = Mid(tmp$,1,5)
  ProcedureReturn PeekS(_RC4(*tmpU, 32, owner_RC4_key$),32)
EndProcedure

Procedure _generateencryptionkey(user_pass$, owner_pass$, protection)
  
  *UPass.l = AllocateMemory(33)
  *OPass.l = AllocateMemory(33)
  
  LenUPass= Len(user_pass$)
  If LenUPass < 32
    CopyMemory(@user_pass$,*UPass,LenUPass)
    CopyMemory(*padding,*UPass+LenUPass,32-LenUPass)
  Else
    CopyMemory(@user_pass$,*UPass,32)
  EndIf
  
  LenOPass= Len(owner_pass$)
  If LenOPass < 32
    CopyMemory(@owner_pass$,*OPass,LenOPass)
    CopyMemory(*padding,*OPass+LenOPass,32-LenOPass)
  Else
    CopyMemory(@owner_pass$,*OPass,32)
  EndIf
  
  ; Compute O value
  Ovalue$ = _OValue(*UPass, *OPass)
  *tmp = AllocateMemory(32+32+4+1)
  tmp$ = Chr(protection) + Chr(255) + Chr(255) + Chr(255)
  CopyMemory(*UPass,*tmp,32):CopyMemory(@Ovalue$,*tmp+32,32):PokeS(*tmp+64,tmp$,Len(tmp$)) 
  tmp$ = _md5_16(*tmp,68)
  encryption_key$ = Mid(tmp$,1,5)
  
  ; Compute U value
  Uvalue$ = Space(32)
  tmpmem = AllocateMemory(32)
  CopyMemory(*padding, tmpmem, 32)
  tmpmem = _RC4(tmpmem, 32, encryption_key$)
  CopyMemory(tmpmem, @Uvalue$, 32)
  
  Pvalue = protection ; -((protection ! 255)+1)
EndProcedure



Procedure  _SetProtection(permission, user_pass$ ,owner_pass$);$permissions=array(),
  
  ; Procedure to set permissions as well as user and owner passwords
  ;
  ; - permissions is an array with values taken from the following list:
  ;   copy, print, modify, annot-forms
  ;   If a value is present it means that the permission is granted
  ; - If a user password is set, user will be prompted before document is opened
  ; - If an owner password is set, document can be opened in privilege mode with no
  ;   restriction if that password is entered
  ;$options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32 );
  
  protection.l = permission
  encrypted = #True
  _generateencryptionkey(user_pass$, owner_pass$, protection)
  
EndProcedure

Procedure.s _objectkey(n)
  encKeyLen=Len(encryption_key$)
  Debug "encKeyLen= " + Str(encKeyLen)
  *tmp=AllocateMemory(encKeyLen+5)
  CopyMemory(@encryption_key$,*tmp,encKeyLen)
  PokeL(*tmp+encKeyLen,n)
  PokeW(*tmp+encKeyLen+3,0)
  ProcedureReturn Mid(_md5_16(*tmp,encKeyLen+5),1,10)
EndProcedure

Procedure pdf_Protection()
  
  encrypted=#False;
  last_rc4_key$="";
  *padding = ?PaddingString
  
EndProcedure
more data for the data section:

Code: Select all

DataSection
PaddingString:
Data.b 40, 191,	78,	 94,	78,	117, 138,  65, 100,	  0,	78,	 86, 255, 250,	 1,	 8
Data.b 46,	46,	 0, 182, 208,	104,	62, 128,	47,  12, 169, 254, 100,	 83, 105,122
And an example how to use it:

Code: Select all

;#########################################
;Example with compression and protection #
;#########################################

txt$="01234456789 01234456789 01234456789 01234456789 01234456789 01234456789 01234456789 "
pdf_Init()
pdf_Protection()

  ; Info from PDFReference for permissions bit setting
  ;	1–2 Reserved; must be 0.
  ;	3 (Revision 2) Print the document.
  ;	  (Revision 3) Print the document (possibly not at the highest quality
  ;	  level, depending on whether bit 12 is also set).
  ;	4 Modify the contents of the document by operations other than
  ;	  those controlled by bits 6, 9, and 11.
  ;	5 (Revision 2) Copy or otherwise extract text and graphics from the
  ;	  document, including extracting text and graphics (in support of accessibility
  ;	  to disabled users or for other purposes).
  ;	  (Revision 3) Copy or otherwise extract text and graphics from the
  ;	  document by operations other than that controlled by bit 10.
  ;	6 Add or modify text annotations, fill in interactive form fields, and,
  ;	  if bit 4 is also set, create or modify interactive form fields (including
  ;	  signature fields).
  ;	7–8 Reserved; must be 1.
  ;	9 (Revision 3 only) Fill in existing interactive form fields (including
  ;	  signature fields), even if bit 6 is clear.
  ;	10 (Revision 3 only) Extract text and graphics (in support of accessibility
  ;	  to disabled users or for other purposes).
  ;	11 (Revision 3 only) Assemble the document (insert, rotate, or delete
  ;	  pages and create bookmarks or thumbnail images), even if bit 4 is
  ;	  clear.
  ;	12 (Revision 3 only) Print the document to a representation from
  ;	  which a faithful digital copy of the PDF content could be generated.
  ;	  When this bit is clear (and bit 3 is set), printing is limited to a lowlevel
  ;	  representation of the appearance, possibly of degraded quality.
  ;	  (See implementation note 20 in Appendix H.)
  ;	13–32 (Revision 3 only) Reserved; must be 1.
  
  ;Bit No     21 987654321 987654321 987654321 
permission.l=%11111111111111111111000011000000

_SetProtection(permission,"","xyz0815")
pdf_OpenBasic("P","mm","a4")
_ZlibInit()
pdf_SetCompression(@_GzCompress())

pdf_AddPage()
pdf_SetFont3("Arial","",12)
  For i = 1 To 8000
    pdf_Cell3(40,10,txt$)
    pdf_Ln()
  Next
pdf_Close()
pdf_Save("c:\test\Tutorial1.pdf")
Hope I didn´t forget something.
Thanks LuckyLuke for your excellent work wich enabled this.
________________
schic
schic
User
User
Posts: 34
Joined: Fri Sep 12, 2003 10:17 am

Post by schic »

[quote="ABBKlaus"]

has someone a working userlibrary "zlib" for PB3.91 ?
My is reporting "POLINK: error: Unresolved external symbol '_errno'."
quote]

I am working on it but yet couldn´t find the mistake. It depends on
the changed linker from PB3.91 I think :?:

But - instead of this Lib you can use the dll from http://www.winimage.com/zLibDll/ using CallCFunction()
use the same calls without the Z infront (compress2 instead of Zcompress2), should work well.

_______________
schic
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

thanks chic :D
I already have done this with the zlib.dll
Works great :wink:
LuckyLuke
Enthusiast
Enthusiast
Posts: 181
Joined: Fri Jun 06, 2003 2:41 pm
Location: Belgium

Post by LuckyLuke »

@ABBKlaus :
From the Tailbite help file :
If you need to do initialization operations at program start whenever your library is used, or clean/shutdown operations, you must use two special prefixes in two functions: _Init and _End. These functions can take no arguments, nor can they any values. Use only one _Init function and/or one _End function per library.
New version of PurePDF available.
Version 1.10 :
- Added pdf_SetProtection by schic
- Added pdf_Protection by schic
- Added pdf_SetDisplayMode
- Added pdf_DisplayPreferences
- Added tutorial18 & 19
- Bugfix _DataAddString
- BugFix pdf_MultiCellBasic by ABBKlaus
http://smollies.fateback.com/purePDF.zip

PureBasic User-Lib from zlib for PureBasic version 3.91. NOT all funcions are included.
http://smollies.fateback.com/zlib.zip
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

wow this libs rock :P
Tested them and worked fine for me (XP SP2 + PB3.91)

Hope you send them to Andre :!: To archive them on http://www.purearea.net
El_Choni
TailBite Expert
TailBite Expert
Posts: 1007
Joined: Fri Apr 25, 2003 6:09 pm
Location: Spain

Post by El_Choni »

From the Tailbite help file :
Quote:
If you need to do initialization operations at program start whenever your library is used, or clean/shutdown operations, you must use two special prefixes in two functions: _Init and _End. These functions can take no arguments, nor can they any values. Use only one _Init function and/or one _End function per library.
Sorry, should be "suffixes", not "prefixes", of course. Changed.

Regards,
El_Choni
schic
User
User
Posts: 34
Joined: Fri Sep 12, 2003 10:17 am

Post by schic »

has someone a working userlibrary "zlib" for PB3.91 ?
My is reporting "POLINK: error: Unresolved external symbol '_errno'."
Fixed the problem with the Polink error.
You can download the update at http://people.freenet.de/zlibforpb/ZuserLIB.zip

_____________
schic
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

HURRAY!!!!!
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

good. needs a help file though..
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

Very nice! I agree on the help file.. for idiots like me .. ;)

- np
schic
User
User
Posts: 34
Joined: Fri Sep 12, 2003 10:17 am

Post by schic »

My english is not to write a help which really helps :oops: (and drinking some beer in a beer-garden
turns me on much more :D ) but I have coded some examples. Have a look at
http://people.freenet.de/zlibforpb/.

This may show more than many (bad) explanations. There are also some usefull links.

Hope this helps
____________
schic
schic
User
User
Posts: 34
Joined: Fri Sep 12, 2003 10:17 am

Post by schic »

to avoid a crash with zlib compression and more than 400 pages, leave the FreeMemory(SourceMem) away. And - the function _ZlibInit() and structure z_stream are not needed for Zcompress2. In this case the lib does the initialisation for you:

Code: Select all

Procedure.b _GzCompress(*aData.strData)
  Protected zerr.b
  Protected CompMem.l
  Protected SourceLen.l
  Protected SourceMem.l
  Protected CompLen.l
  Protected lbError.b
  
  lbError = #False
  SourceLen = *aData\lCurSize
  SourceMem = *aData\pData 
  CompLen.l = SourceLen + SourceLen/1000 + 16 
  CompMem=AllocateMemory(CompLen)
  If CompMem
    zerr=Zcompress2(CompMem, @CompLen, SourceMem, SourceLen,#Z_DEFAULT_COMPRESSION)
    If zerr = #Z_OK
      *aData\pData = CompMem
      *aData\lMaxSize = CompLen
      *aData\lCurSize = CompLen
      ;FreeMemory(SourceMem)
      lbError = #True  
    EndIf
  EndIf
  ProcedureReturn lbError  
EndProcedure
Remark: using #Z_DEFAULT_COMPRESSION is much faster than #Z_BEST_COMPRESSION
and compression is not much different.
____________
schic
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

@Scik, you lib is working very good. If you make a helpfile for it, post
it as a topic of its own it Announcement section! I played with it last night, and its working all fine.
Post Reply