Platforms to show: All Mac Windows Linux Cross-Platform

/DynaPDF/Create PDF with Arabic


Required plugins for this example: MBS DynaPDF Plugin

You find this example project in your Plugins Download as a Xojo project file within the examples folder: /DynaPDF/Create PDF with Arabic

This example is the version from Sun, 23th Sep 2017.

Project "Create PDF with Arabic.xojo_binary_project"
FileTypes
Filetype text
End FileTypes
MenuBar MenuBar1
MenuItem UntitledMenu1 = ""
MenuItem FileMenu = "&File"
MenuItem FileQuit = "Quit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem UntitledMenu0 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "Clear"
End MenuBar
Class App Inherits Application
EventHandler Sub Open() dim pdf as new MyDynapdfMBS dim d as new date pdf.SetLicenseKey "Starter" // For this example you can use a Starter, Lite, Pro or Enterprise License dim f as FolderItem = SpecialFolder.Desktop.Child("Create PDF with Arabic.pdf") call pdf.CreateNewPDF f call pdf.SetDocInfo pdf.kdiSubject, "My first Xojo output" call pdf.SetDocInfo pdf.kdiProducer, "Xojo test application" call pdf.SetDocInfo pdf.kdiTitle, "My first Xojo output" // We want to use top-down coordinates call pdf.SetPageCoords pdf.kpcTopDown call pdf.Append dim text as string = "مرحبا العالم" // todo: convert from unicode text into right glyph dim glyphs() as integer glyphs.Append &hFEE3 glyphs.Append &hFEAE glyphs.Append &hFEA3 glyphs.Append &hFE92 glyphs.Append &hFE8E glyphs.Append 32 // space glyphs.Append &h0627 glyphs.Append &hFEDF glyphs.Append &hFECC glyphs.Append &hFE8E glyphs.Append &hFEDF glyphs.Append &hFEE2 dim Text3 as string = "" for each g as integer in glyphs text3 = text3 + encodings.UTF16.Chr(g) next ' '// reverse it ' 'dim text2 as string 'for i as integer = len(text) downto 1 'text2 = text2 + mid(text, i, 1) 'next // and put ob page call pdf.SetFont "Helvetica", pdf.kfsNone, 20.0, true, pdf.kcpUnicode call pdf.WriteFTextex 100, 350, 300, 300, pdf.ktaCenter, "Original Text" call pdf.SetFont "Baghdad", pdf.kfsNone, 40.0, true, pdf.kcpUnicode call pdf.WriteFTextex 100, 300, 300, 300, pdf.ktaCenter, text // this is convert method we tried // not 100% perfect yet dim textCorrected as string = ArabicConverterModule.Convert(text) call pdf.SetFont "Helvetica", pdf.kfsNone, 20.0, true, pdf.kcpUnicode call pdf.WriteFTextex 100, 250, 300, 300, pdf.ktaCenter, "Converted Text" call pdf.SetFont "Baghdad", pdf.kfsNone, 40.0, true, pdf.kcpUnicode call pdf.WriteFTextEx 100, 200, 300, 300, pdf.ktaCenter, textCorrected // reverse it for i as integer = 1 to len(textCorrected) System.DebugLog str(asc(mid(textCorrected, i, 1))) next dim text2 as string for i as integer = len(textCorrected) downto 1 text2 = text2 + mid(textCorrected, i, 1) next call pdf.SetFont "Helvetica", pdf.kfsNone, 20.0, true, pdf.kcpUnicode call pdf.WriteFTextex 100, 150, 300, 300, pdf.ktaCenter, "Convert & Reverse Text" call pdf.SetFont "Baghdad", pdf.kfsNone, 40.0, true, pdf.kcpUnicode call pdf.WriteFTextEx 100, 100, 300, 300, pdf.ktaCenter, text2 call pdf.SetFont "Helvetica", pdf.kfsNone, 20.0, true, pdf.kcpUnicode call pdf.WriteFTextex 100, 450, 300, 300, pdf.ktaCenter, "Text with Glypths" call pdf.SetFont "Baghdad", pdf.kfsNone, 40.0, true, pdf.kcpUnicode call pdf.WriteFTextEx 100, 400, 300, 300, pdf.ktaCenter, text3 call pdf.EndPage call pdf.CloseFile f.Launch quit End EventHandler
End Class
Class MyDynaPDFMBS Inherits DynaPDFMBS
EventHandler Function Error(ErrorCode as integer, ErrorMessage as string, ErrorType as integer) As integer // output all messages on the console: System.DebugLog str(ErrorCode)+": "+ErrorMessage // and display dialog: Dim d as New MessageDialog //declare the MessageDialog object Dim b as MessageDialogButton //for handling the result d.icon=MessageDialog.GraphicCaution //display warning icon d.ActionButton.Caption="Continue" d.CancelButton.Visible=True //show the Cancel button // a warning or an error? if BitAnd(ErrorType, me.kE_WARNING) = me.kE_WARNING then // if user decided to ignore, we'll ignore if IgnoreWarnings then Return 0 d.Message="A warning occurred while processing your PDF code." // we add a third button to display all warnings d.AlternateActionButton.Caption = "Ignore warnings" d.AlternateActionButton.Visible = true else d.Message="An error occurred while processing your PDF code." end if d.Explanation = str(ErrorCode)+": "+ErrorMessage b=d.ShowModal //display the dialog Select Case b //determine which button was pressed. Case d.ActionButton Return 0 // ignore Case d.AlternateActionButton IgnoreWarnings = true Return 0 // ignore Case d.CancelButton Return -1 // stop End select End EventHandler
Property IgnoreWarnings As Boolean
End Class
Module ArabicConverterModule
Private Function CharacterMapContains(c as integer) As Boolean for each ch as charRep in charsMap if ch.code = c then Return true end if next End Function
Function Convert(s as string) As string Init dim result as string dim normal as string = ConvertEncoding(s, encodings.UTF16) dim len as integer = len(normal) for i as integer = 1 to len dim current as integer = asc(mid(normal, i, 1)) if CharacterMapContains(current) then dim prevChar, nextChar as integer dim prevID as integer = i - 1 dim nextID as integer = i + 1 dim crep as CharRep // Transparent characters have no effect in the shaping process. // So, ignore all the transparent characters that are BEFORE the // current character. while (prevID >= 1) dim c as integer = asc(mid(normal, prevID, 1)) if not IsTransparent(c) then exit end if prevID = prevID - 1 wend prevChar = asc(mid(normal, prevID, 1)) crep = GetCharRep(prevChar) if ((prevID < 1) or (not CharacterMapContains(prevChar)) or (not (crep.Initial <> 0) and not (crep.Medial <> 0))) then prevChar = 0 end if // Transparent characters have no effect in the shaping process. // So, ignore all the transparent characters that are AFTER the // current character. while nextID <= len dim c as integer = asc(mid(normal, nextID, 1)) if not IsTransparent(c) then exit end if nextID = nextID + 1 wend nextChar = asc(mid(normal, nextID, 1)) crep = GetCharRep(nextChar) if ((nextID > len) or not CharacterMapContains(nextChar) or (not (crep.Medial <> 0) and not (crep.Final <> 0) and (nextChar <> &h0640))) then nextChar = 0 end if // Combinations if (current = &h0644 and nextChar <> 0 and (nextChar = &h0622 or nextChar = &h0623 or nextChar = &h0625 or nextChar = &h0627)) then dim combcrep as CombCharRep = GetCombCharRep(current, nextChar) if prevChar <> 0 then result = result + encodings.UTF16.chr(combcrep.Final) else result = result + encodings.UTF16.chr(combcrep.Isolated) end if i = i + 1 continue end if crep = GetCharRep(current) // Medial if (prevChar <> 0 and nextChar <> 0 and crep.Medial <> 0) then result = result + encodings.UTF16.chr( crep.Medial) continue // Final elseif (prevChar <> 0 and crep.Final <> 0) then result = result + encodings.UTF16.chr( crep.Final) continue // Initial elseif (nextChar <> 0 and crep.Initial <> 0) then result = result + encodings.UTF16.chr( crep.Initial) continue end if // Isolated result = result + encodings.UTF16.chr( crep.Isolated) else result = result + encodings.UTF16.chr(current) end if next Return result End Function
Private Function GetCharRep(c as integer) As charRep for each ch as CharRep in charsMap if ch.Code = c then Return ch end if next // return dummy one static n as new CharRep Return n End Function
Private Function GetCombCharRep(c0 as integer, c1 as integer) As CombCharRep for each ch as CombCharRep in combCharsMap if ch.Code0 = c0 and ch.Code1 = C1 then Return ch end if next // return dummy static n as new CombCharRep Return n End Function
Private Sub Init() if inited then Return inited = true charsMap.Append new CharRep( &h0621, &hFE80, 0, 0, 0 ) // HAMZA charsMap.Append new CharRep( &h0622, &hFE81, 0, 0, &hFE82 ) // ALEF_MADDA charsMap.Append new CharRep( &h0623, &hFE83, 0, 0, &hFE84 ) // ALEF_HAMZA_ABOVE charsMap.Append new CharRep( &h0624, &hFE85, 0, 0, &hFE86 ) // WAW_HAMZA charsMap.Append new CharRep( &h0625, &hFE87, 0, 0, &hFE88 ) // ALEF_HAMZA_BELOW charsMap.Append new CharRep( &h0626, &hFE89, &hFE8B, &hFE8C, &hFE8A ) // YEH_HAMZA charsMap.Append new CharRep( &h0627, &hFE8D, 0, 0, &hFE8E ) // ALEF charsMap.Append new CharRep( &h0628, &hFE8F, &hFE91, &hFE92, &hFE90 ) // BEH charsMap.Append new CharRep( &h0629, &hFE93, 0, 0, &hFE94 ) // TEH_MARBUTA charsMap.Append new CharRep( &h062A, &hFE95, &hFE97, &hFE98, &hFE96 ) // TEH charsMap.Append new CharRep( &h062B, &hFE99, &hFE9B, &hFE9C, &hFE9A ) // THEH charsMap.Append new CharRep( &h062C, &hFE9D, &hFE9F, &hFEA0, &hFE9E ) // JEEM charsMap.Append new CharRep( &h062D, &hFEA1, &hFEA3, &hFEA4, &hFEA2 ) // HAH charsMap.Append new CharRep( &h062E, &hFEA5, &hFEA7, &hFEA8, &hFEA6 ) // KHAH charsMap.Append new CharRep( &h062F, &hFEA9, 0, 0, &hFEAA ) // DAL charsMap.Append new CharRep( &h0630, &hFEAB, 0, 0, &hFEAC ) // THAL charsMap.Append new CharRep( &h0631, &hFEAD, 0, 0, &hFEAE ) // REH charsMap.Append new CharRep( &h0632, &hFEAF, 0, 0, &hFEB0 ) // ZAIN charsMap.Append new CharRep( &h0633, &hFEB1, &hFEB3, &hFEB4, &hFEB2 ) // SEEN charsMap.Append new CharRep( &h0634, &hFEB5, &hFEB7, &hFEB8, &hFEB6 ) // SHEEN charsMap.Append new CharRep( &h0635, &hFEB9, &hFEBB, &hFEBC, &hFEBA ) // SAD charsMap.Append new CharRep( &h0636, &hFEBD, &hFEBF, &hFEC0, &hFEBE ) // DAD charsMap.Append new CharRep( &h0637, &hFEC1, &hFEC3, &hFEC4, &hFEC2 ) // TAH charsMap.Append new CharRep( &h0638, &hFEC5, &hFEC7, &hFEC8, &hFEC6 ) // ZAH charsMap.Append new CharRep( &h0639, &hFEC9, &hFECB, &hFECC, &hFECA ) // AIN charsMap.Append new CharRep( &h063A, &hFECD, &hFECF, &hFED0, &hFECE ) // GHAIN charsMap.Append new CharRep( &h0640, &h0640, 0, 0, 0 ) // TATWEEL charsMap.Append new CharRep( &h0641, &hFED1, &hFED3, &hFED4, &hFED2 ) // FEH charsMap.Append new CharRep( &h0642, &hFED5, &hFED7, &hFED8, &hFED6 ) // QAF charsMap.Append new CharRep( &h0643, &hFED9, &hFEDB, &hFEDC, &hFEDA ) // KAF charsMap.Append new CharRep( &h0644, &hFEDD, &hFEDF, &hFEE0, &hFEDE ) // LAM charsMap.Append new CharRep( &h0645, &hFEE1, &hFEE3, &hFEE4, &hFEE2 ) // MEEM charsMap.Append new CharRep( &h0646, &hFEE5, &hFEE7, &hFEE8, &hFEE6 ) // NOON charsMap.Append new CharRep( &h0647, &hFEE9, &hFEEB, &hFEEC, &hFEEA ) // HEH charsMap.Append new CharRep( &h0648, &hFEED, 0, 0, &hFEEE ) // WAW //charsMap.Append new CharRep( &h0649, &hFEEF, &hFBE8, &hFBE9, &hFEF0 ) // ALEF_MAKSURA charsMap.Append new CharRep( &h0649, &hFEEF, 0, 0, &hFEF0 ) // ALEF_MAKSURA charsMap.Append new CharRep( &h064A, &hFEF1, &hFEF3, &hFEF4, &hFEF2 ) // YEH combCharsMap.Append new CombCharRep( &h0644, &h0622, &hFEF5, 0, 0, &hFEF6 ) // LAM_ALEF_MADDA combCharsMap.Append new CombCharRep( &h0644, &h0623, &hFEF7, 0, 0, &hFEF8 ) // LAM_ALEF_HAMZA_ABOVE combCharsMap.Append new CombCharRep( &h0644, &h0625, &hFEF9, 0, 0, &hFEFA ) // LAM_ALEF_HAMZA_BELOW combCharsMap.Append new CombCharRep( &h0644, &h0627, &hFEFB, 0, 0, &hFEFC ) // LAM_ALEF transChars = new Dictionary transChars.value(&h0610) = nil // ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM transChars.value(&h0612) = nil // ARABIC SIGN ALAYHE ASSALLAM transChars.value(&h0613) = nil // ARABIC SIGN RADI ALLAHOU ANHU transChars.value(&h0614) = nil // ARABIC SIGN TAKHALLUS transChars.value(&h0615) = nil // ARABIC SMALL HIGH TAH transChars.value(&h064B) = nil // ARABIC FATHATAN transChars.value(&h064C) = nil // ARABIC DAMMATAN transChars.value(&h064D) = nil // ARABIC KASRATAN transChars.value(&h064E) = nil // ARABIC FATHA transChars.value(&h064F) = nil // ARABIC DAMMA transChars.value(&h0650) = nil // ARABIC KASRA transChars.value(&h0651) = nil // ARABIC SHADDA transChars.value(&h0652) = nil // ARABIC SUKUN transChars.value(&h0653) = nil // ARABIC MADDAH ABOVE transChars.value(&h0654) = nil // ARABIC HAMZA ABOVE transChars.value(&h0655) = nil // ARABIC HAMZA BELOW transChars.value(&h0656) = nil // ARABIC SUBSCRIPT ALEF transChars.value(&h0657) = nil // ARABIC INVERTED DAMMA transChars.value(&h0658) = nil // ARABIC MARK NOON GHUNNA transChars.value(&h0670) = nil // ARABIC LETTER SUPERSCRIPT ALEF transChars.value(&h06D6) = nil // ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA transChars.value(&h06D7) = nil // ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA transChars.value(&h06D8) = nil // ARABIC SMALL HIGH MEEM INITIAL FORM transChars.value(&h06D9) = nil // ARABIC SMALL HIGH LAM ALEF transChars.value(&h06DA) = nil // ARABIC SMALL HIGH JEEM transChars.value(&h06DB) = nil // ARABIC SMALL HIGH THREE DOTS transChars.value(&h06DC) = nil // ARABIC SMALL HIGH SEEN transChars.value(&h06DF) = nil // ARABIC SMALL HIGH ROUNDED ZERO transChars.value(&h06E0) = nil // ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO transChars.value(&h06E1) = nil // ARABIC SMALL HIGH DOTLESS HEAD OF KHAH transChars.value(&h06E2) = nil // ARABIC SMALL HIGH MEEM ISOLATED FORM transChars.value(&h06E3) = nil // ARABIC SMALL LOW SEEN transChars.value(&h06E4) = nil // ARABIC SMALL HIGH MADDA transChars.value(&h06E7) = nil // ARABIC SMALL HIGH YEH transChars.value(&h06E8) = nil // ARABIC SMALL HIGH NOON transChars.value(&h06EA) = nil // ARABIC EMPTY CENTRE LOW STOP transChars.value(&h06EB) = nil // ARABIC EMPTY CENTRE HIGH STOP transChars.value(&h06EC) = nil // ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE transChars.value(&h06ED) = nil // ARABIC SMALL LOW MEEM End Sub
Private Function IsTransparent(c as integer) As Boolean Return transChars.HasKey(c) End Function
Note "Note"
based on https://github.com/Accorpa/Arabic-Converter-From-and-To-Arabic-Presentation-Forms-B but we give you this code with BSD license.
Property Private Inited As Boolean
Property Private charsMap() As CharRep
Property Private combCharsMap() As CombCharRep
Property Private transChars As Dictionary
End Module
Class CombCharRep
Sub Constructor() End Sub
Sub Constructor(c0 as integer, c1 as integer, iso as integer, ini as integer, med as integer, fin as integer) code0 = c0 code1 = c1 Isolated = iso Initial = ini Medial = med final = fin End Sub
Property Code0 As Integer
Property Code1 As Integer
Property Final As Integer
Property Initial As Integer
Property Isolated As Integer
Property Medial As Integer
End Class
Class CharRep
Sub Constructor() End Sub
Sub Constructor(cod as integer, iso as integer, ini as integer, med as integer, fin as integer) code = cod Isolated = iso Initial = ini Medial = med final = fin End Sub
Property Code As Integer
Property Final As Integer
Property Initial As Integer
Property Isolated As Integer
Property Medial As Integer
End Class
End Project

See also:

The items on this page are in the following plugins: MBS DynaPDF Plugin.


The biggest plugin in space...