Platforms to show: All Mac Windows Linux Cross-Platform
/DynaPDF/Text Positions
Function:
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /DynaPDF/Text Positions
This example is the version from Wed, 20th Feb 2018.
Function:
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /DynaPDF/Text Positions
This example is the version from Wed, 20th Feb 2018.
Project "Text Positions.rbp"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
End Class
Class MainWindow Inherits Window
Control CheckSplit Inherits CheckBox
ControlInstance CheckSplit Inherits CheckBox
EventHandler Sub Action()
split = me.Value
canvas1.Invalidate
End EventHandler
End Control
Control Canvas1 Inherits Canvas
ControlInstance Canvas1 Inherits Canvas
EventHandler Sub Paint(g As Graphics, areas() As REALbasic.Rect)
const factor = 2.0
dim lines() as string
dim Page as DynaPDFPageMBS = pdf.GetPage(1)
dim bbox as DynaPDFRectMBS = page.BBox(page.kpbMediaBox)
dim PageWidth as integer = bbox.Width
dim PageHeight as integer = abs(bbox.Bottom - bbox.top)
if ShowPDF then
// we draw pdf as background
dim pic as Picture = pdf.RenderPagePicture(1, PageWidth*factor, PageHeight*factor, 2, nil)
g.DrawPicture pic, 0, 0
end if
// now draw text blocks
for each t as PDFText in texts
dim m as DynaPDFMatrixMBS = t.EffectiveMatrix
//XY Axis
dim xAxis As Double = GetScaleX(m)
dim yAxis As Double = GetScaleY(m)
//font infomation
dim fontinfo As DynaPDFFontInfoMBS = t.State.FontInfo
dim ascent As Single = fontinfo.Ascent
dim descent As Single = abs(fontinfo.Descent)
//font size
dim fontSize as Double = t.State.FontSize * yAxis
dim x1 as Double = 0
dim y1 as Double = 0
dim x2 as Double = 0
dim y2 as Double = t.State.FontSize
dim fx as Double = 0
dim fy as Double = t.State.FontSize
'dim MM as DynaPDFMatrixMBS = t.Matrix * t.State.matrix
'dim ffx as Double = fx * M.b + fy * M.d '+ M.y
dim ffy as Double = fx * M.b + fy * M.d '+ M.y
g.TextSize = ffy * factor
dim xx1,yy1,xx2,yy2 as Double
if t.KerningA <> nil then
for each k as DynaPDFTextRecordAMBS in t.KerningA
// translate native encoding to Unicode
dim decoded as Boolean
dim ktext as string = k.Text
x1 = x1 - k.Advance
x2 = x2 - k.Advance
xx1 = x1 * M.a + y1 * M.c + M.x
yy1 = x1 * M.b + y1 * M.d + M.y
xx2 = x2 * M.a + y2 * M.c + M.x
yy2 = x2 * M.b + y2 * M.d + M.y
// swap coordinates from bottom-up in PDF to top-down in Xojo
yy1 = PageHeight - yy1
yy2 = PageHeight - yy2
// safe position
dim xxx1 as Double = xx1
dim i as integer = 0
dim l as integer = ktext.lenb
dim width as Double = 0
while i < l
width = 0
dim ProcessedBytes as integer = 0
dim OneText as string = DynaPDFMBS.TranslateRawCode(t.state.FontHandle, kText, i, width, decoded, t.state.CharSpacing, t.state.WordSpacing, t.State.TextScale, ProcessedBytes)
lines.append OneText+": "+str(width)
if width <= 0.0 then
Break // something broken?
end if
if ProcessedBytes <= 0 then
break // should not happen
ProcessedBytes = 1
end if
// drawing here will not match what DynaPDF draws as we do not take style and spacing in account
g.ForeColor = &c0000FF
g.DrawString OneText, xx1*factor, (yy1)*factor
if split then
g.ForeColor = &c00FF00
g.PenWidth=1
g.DrawRect xx1*factor,yy2*factor,(width*xAxis)*factor,abs(yy2-yy1)*factor
end if
// advance position
xx1 = (xx1 + width*xAxis)
x1 = (x1 + width)
// next
i = i + ProcessedBytes
wend
if not split then
// box around
g.PenWidth = 1
g.ForeColor = &cFF0000
g.DrawRect xxx1*factor,yy2*factor,abs(xx1-xxx1)*factor,abs(yy2-yy1)*factor
end if
next
end if
next
call pdf.EndPage
End EventHandler
End Control
Control CheckShowPDF Inherits CheckBox
ControlInstance CheckShowPDF Inherits CheckBox
EventHandler Sub Action()
ShowPDF = me.Value
canvas1.Invalidate
End EventHandler
End Control
EventHandler Sub Open()
dim f as FolderItem = FindFile("license.pdf")
if f=nil or not f.Exists then
Return
end if
dim p as new MyDynapdfMBS
p.SetLicenseKey "Pro" // For this example you can use a Pro or Enterprise License
call p.CreateNewPDF(Nil)
// Skip anything that is not required
call p.SetImportFlags p.kifImportAll+p.kifImportAsPage
// From which PDF file do you want to extract the images?
call p.OpenImportFile(f, p.kptOpen, "")
// Comment this out if you want to extract the images from specific pages only
call p.ImportPDFFile(1, 1.0, 1.0)
call p.CloseImportFile
dim parser as new MyDynaPDFParseInterfaceMBS(p)
'If you want to create a multipage TIFF then create the output image here
'and call AddImage() only in the callback function. After the loop
'returns call CloseImage() to close the image file.
call p.EditPage 1
call p.ParseContent(parser, p.kpfNone)
call p.EndPage
self.texts = parser.Texts
self.pdf = p
End EventHandler
Private Function CalcDistance(x1 as double, y1 as Double, x2 as Double, y2 as Double) As Double
// Distance between two points
dim dx as double = x2-x1
dim dy as double = y2-y1
return sqrt(dx*dx + dy*dy)
End Function
Private Function GetScaleX(m As DynapdfMatrixMBS) As Double
Dim x1 As double= 0.0
Dim y1 As double= 0.0
Dim x2 As double= 1.0
Dim y2 As double= 0.0
Transform(m, x1, y1)
Transform(m, x2, y2)
if (y1 > y2) then
return -CalcDistance(x1, y1, x2, y2)
else
return CalcDistance(x1, y1, x2, y2)
end if
End Function
Private Function GetScaleY(m As DynapdfMatrixMBS) As Double
Dim x1 As double= 0.0
Dim y1 As double= 0.0
Dim x2 As double= 0.0
Dim y2 As double= 1.0
Transform(m, x1, y1)
Transform(m, x2, y2)
if (y1 > y2) then
return -CalcDistance(x1, y1, x2, y2)
else
return CalcDistance(x1, y1, x2, y2)
end if
End Function
Property ShowPDF As Boolean = true
Property pdf As MyDynaPDFMBS
Property split As Boolean
Property texts() As PDFText
End Class
MenuBar MainMenuBar
MenuItem FileMenu = "&File"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem EditSeparator1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem EditSeparator2 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
Class PDFState
Sub Constructor(other as PDFState)
self.CharSpacing = other.CharSpacing
self.ExtGState = other.ExtGState
self.FontHandle = other.FontHandle
self.FontInfo = other.FontInfo
self.FontName = other.FontName
self.FontSize = other.FontSize
self.FontStyle = other.FontStyle
self.MiterLimit = other.MiterLimit
self.textDrawMode = other.textDrawMode
self.TextScale = other.TextScale
self.WordSpacing = other.WordSpacing
self.matrix = new DynaPDFMatrixMBS(other.matrix) // copy
End Sub
Sub constructor()
matrix = new DynaPDFMatrixMBS // makes new identity matrix
FontSize = 1.0
CharSpacing = 0.0
TextDrawMode = DynaPDFMBS.kdmNormal
TextScale = 100.0
WordSpacing = 0.0
End Sub
Property CharSpacing As Double
Property ExtGState As DynaPDFExtGState2MBS
Property FontHandle As Integer
Property FontInfo As DynaPDFFontInfoMBS
Property FontName As String
Property FontSize As double
Property FontStyle As Integer
Property Leading As Double
Property MiterLimit As double
Property TextScale As Double
Property WordSpacing As Double
Property matrix As DynaPDFMatrixMBS
Property textDrawMode As Integer
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
Class MyDynaPDFParseInterfaceMBS Inherits DynaPDFParseInterfaceMBS
EventHandler Function BeginTemplate(ObjectPtr as integer, Handle as integer, BBox as DynaPDFRectMBS, Matrix as DynaPDFMatrixMBS) As integer
current.matrix = current.matrix * matrix
End EventHandler
EventHandler Sub MulMatrix(ObjectPtr as integer, matrix as DynaPDFMatrixMBS)
current.matrix = current.matrix * matrix
End EventHandler
EventHandler Function RestoreGraphicState() As integer
current = states.pop
End EventHandler
EventHandler Function SaveGraphicState() As integer
states.Append current
current = new PDFState(Current)
End EventHandler
EventHandler Sub SetCharSpacing(ObjectPtr as integer, Value as double)
current.CharSpacing = value
End EventHandler
EventHandler Sub SetExtGState(ObjectPtr as integer, GS as DynaPDFExtGState2MBS)
current.ExtGState = gs
End EventHandler
EventHandler Sub SetFont(ObjectPtr as integer, fontType as integer, Embedded as boolean, FontName as string, Style as integer, FontSize as double, FontHandle as integer, FontInfo as DynaPDFFontInfoMBS)
current.FontName = FontName
current.FontStyle = Style
current.FontSize = FontSize
current.FontInfo = FontInfo
current.FontHandle = FontHandle
End EventHandler
EventHandler Sub SetLeading(ObjectPtr as integer, Value as double)
current.Leading = value
End EventHandler
EventHandler Sub SetMiterLimit(ObjectPtr as integer, Value as double)
current.MiterLimit = value
End EventHandler
EventHandler Sub SetTextDrawMode(ObjectPtr as integer, Mode as integer)
current.textDrawMode = mode
End EventHandler
EventHandler Sub SetTextScale(ObjectPtr as integer, Value as double)
current.TextScale = value
End EventHandler
EventHandler Sub SetWordSpacing(ObjectPtr as integer, Value as double)
current.WordSpacing = value
End EventHandler
EventHandler Function ShowTextArrayA(ObjectPtr as integer, Matrix as DynaPDFMatrixMBS, Kerning() as DynaPDFTextRecordAMBS, Count as integer, Width as double) As integer
dim t as new PDFText
t.State = new PDFState(current)
t.Count = Count
t.Width = Width
t.KerningA = Kerning
t.Matrix = matrix
texts.Append t
End EventHandler
Sub Constructor(p as MyDynaPDFMBS)
self.current = new PDFState
self.pdf = p
End Sub
Property States() As PDFState
Property Texts() As PDFText
Property current As PDFState
Property pdf As dynaPDFmbs
End Class
Module UtilModule
Function FindFile(name as string) As FolderItem
// Look for file in parent folders from executable on
dim parent as FolderItem = app.ExecutableFile.Parent
while parent<>Nil
dim file as FolderItem = parent.Child(name)
if file<>Nil and file.Exists then
Return file
end if
parent = parent.Parent
wend
End Function
Sub Transform(m as DynaPDFMatrixMBS, byref x as Double, byref y as double)
dim tx as double = x
x = tx * M.a + y * M.c + M.x
y = tx * M.b + y * M.d + M.y
End Sub
End Module
Class PDFText
Function EffectiveMatrix() As DynaPDFMatrixMBS
return matrix * state.matrix
End Function
Property Count As Integer
Property Decoded As boolean
Property KerningA() As DynapdfTextRecordAMBS
Property Matrix As DynapdfMatrixMBS
Property Source() As DynapdfTextRecordAMBS
Property State As PDFState
Property Width As Double
End Class
End Project
See also:
The items on this page are in the following plugins: MBS DynaPDF Plugin.
Links
MBS Xojo Chart Plugins