我已经研究了几个小时如何做到这一点,但遇到了砖墙。我有一个PDF文件,其中一个对象是一个北箭头。它是一个简单的线条图形(我相信它们在Acrobat中被称为图形标记),将指示哪种方式是“向上”。我想读一下那条线图形,确定它的旋转。我采取的第一步是看看是否可以用以下代码枚举PDF的内容:
Imports it = iTextSharp.text
Imports ip = iTextSharp.text.pdf
Dim pdfRdr As New ip.PdfReader("C:\city.pdf")
Dim page As ip.PdfDictionary = pdfRdr.GetPageN(1)
Dim objectReference As ip.PdfIndirectReference = CType(page.Get(ip.PdfName.CONTENTS), ip.PdfIndirectReference)
Dim stream As ip.PRStream = CType(ip.PdfReader.GetPdfObject(objectReference), ip.PRStream)
Dim streamBytes() As Byte = ip.PdfReader.GetStreamBytes(stream)
Dim tokenizer As New ip.PRTokeniser(New ip.RandomAccessFileOrArray(streamBytes))
'Loop through each PDf token
While tokenizer.NextToken
Debug.Print("token of type={0} and value={1}", tokenizer.TokenType.ToString, tokenizer.StringValue)
End While
token of type=OTHER and value=q
token of type=NUMBER and value=0.86275
token of type=NUMBER and value=0
token of type=NUMBER and value=0
token of type=NUMBER and value=0.86275
token of type=NUMBER and value=54
token of type=NUMBER and value=30
token of type=OTHER and value=cm
token of type=NAME and value=Fm0
token of type=OTHER and value=Do
token of type=OTHER and value=Q
token of type=OTHER and value=q
token of type=NUMBER and value=1
token of type=NUMBER and value=0
token of type=NUMBER and value=0
token of type=NUMBER and value=1
token of type=NUMBER and value=54
token of type=NUMBER and value=18
token of type=OTHER and value=cm
token of type=NAME and value=Fm1
token of type=OTHER and value=Do
token of type=OTHER and value=Q
我是在走正确的道路,还是有不同的方法来获取对图形标记的引用?
与最初的印象相反,北箭头不在PDF的注释中,而是常规页面内容的一部分。(@乔恩在最初的印象下创造了他的答案。)
在OP共享的PDF中,箭头是直接页面内容的一部分。另一方面,在OP共享的Adobe Acrobat屏幕截图中,箭头似乎是在表单XObject中(该表单将从直接的页面内容中引用)。
下面的方法应该检索这两种情况下的矢量图形指令。
Public Class VectorParser
Implements IExtRenderListener
Public Sub ModifyPath(renderInfo As PathConstructionRenderInfo) Implements IExtRenderListener.ModifyPath
pathInfos.Add(renderInfo)
End Sub
Public Function RenderPath(renderInfo As PathPaintingRenderInfo) As parser.Path Implements IExtRenderListener.RenderPath
Dim GraphicsState As GraphicsState = getGraphicsState(renderInfo)
Dim ctm As Matrix = GraphicsState.GetCtm()
If (Not (renderInfo.Operation And PathPaintingRenderInfo.FILL) = 0) Then
Console.Write("FILL ({0}) ", ToString(GraphicsState.FillColor))
If (Not (renderInfo.Operation And PathPaintingRenderInfo.STROKE) = 0) Then
Console.Write("and ")
End If
End If
If (Not (renderInfo.Operation And PathPaintingRenderInfo.STROKE) = 0) Then
Console.Write("STROKE ({0}) ", ToString(GraphicsState.StrokeColor))
End If
Console.Write("the path ")
For Each pathConstructionRenderInfo In pathInfos
Select Case pathConstructionRenderInfo.Operation
Case PathConstructionRenderInfo.MOVETO
Console.Write("move to {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.CLOSE
Console.Write("close {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.CURVE_123
Console.Write("curve123 {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.CURVE_13
Console.Write("curve13 {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.CURVE_23
Console.Write("curve23 {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.LINETO
Console.Write("line to {0} ", ToString(transform(ctm, pathConstructionRenderInfo.SegmentData)))
Case PathConstructionRenderInfo.RECT
Console.Write("rectangle {0} ", ToString(transform(ctm, expandRectangleCoordinates(pathConstructionRenderInfo.SegmentData))))
End Select
Next
Console.WriteLine()
pathInfos.Clear()
Return Nothing
End Function
Public Sub ClipPath(rule As Integer) Implements IExtRenderListener.ClipPath
End Sub
Public Sub BeginTextBlock() Implements IRenderListener.BeginTextBlock
End Sub
Public Sub RenderText(renderInfo As TextRenderInfo) Implements IRenderListener.RenderText
End Sub
Public Sub EndTextBlock() Implements IRenderListener.EndTextBlock
End Sub
Public Sub RenderImage(renderInfo As ImageRenderInfo) Implements IRenderListener.RenderImage
End Sub
Function expandRectangleCoordinates(rectangle As IList(Of Single)) As List(Of Single)
If rectangle.Count < 4 Then
Return New List(Of Single)
End If
Return New List(Of Single)() From
{
rectangle(0), rectangle(1),
rectangle(0) + rectangle(2), rectangle(1),
rectangle(0) + rectangle(2), rectangle(1) + rectangle(3),
rectangle(0), rectangle(1) + rectangle(3)
}
End Function
Function transform(ctm As Matrix, coordinates As IList(Of Single)) As List(Of Single)
Dim result As List(Of Single) = New List(Of Single)
If Not coordinates Is Nothing Then
For i = 0 To coordinates.Count - 1 Step 2
Dim vector As Vector = New Vector(coordinates(i), coordinates(i + 1), 1)
vector = vector.Cross(ctm)
result.Add(vector(Vector.I1))
result.Add(vector(Vector.I2))
Next
End If
Return result
End Function
Public Function ToString(coordinates As IList(Of Single)) As String
Dim result As StringBuilder = New StringBuilder()
result.Append("[ ")
For i = 0 To coordinates.Count - 1
result.Append(coordinates(i))
result.Append(" ")
Next
result.Append("]")
Return result.ToString()
End Function
Public Function ToString(baseColor As BaseColor) As String
If (baseColor Is Nothing) Then
Return "DEFAULT"
End If
Return String.Format("{0},{1},{2}", baseColor.R, baseColor.G, baseColor.B)
End Function
Function getGraphicsState(renderInfo As PathPaintingRenderInfo) As GraphicsState
Dim gsField As Reflection.FieldInfo = GetType(PathPaintingRenderInfo).GetField("gs", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
Return CType(gsField.GetValue(renderInfo), GraphicsState)
End Function
Dim pathInfos As List(Of PathConstructionRenderInfo) = New List(Of PathConstructionRenderInfo)
End Class
Using pdfReader As New PdfReader("test.pdf")
Dim extRenderListener As IExtRenderListener = New VectorParser
For page = 1 To pdfReader.NumberOfPages
Console.Write(vbCrLf + "Page {0}" + vbCrLf + "====" + vbCrLf, page)
Dim parser As PdfReaderContentParser = New PdfReaderContentParser(pdfReader)
parser.ProcessContent(page, extRenderListener)
Next
End Using
Page 1
====
STROKE (0,0,255) the path move to [ 277,359 434,2797 ] line to [ 311,5242 434,2797 ]
STROKE (0,0,255) the path move to [ 277,3591 434,2797 ] line to [ 315,0443 424,1336 ]
STROKE (0,0,255) the path move to [ 304,2772 425,376 ] line to [ 304,4842 426,6183 ]
STROKE (0,0,255) the path move to [ 304,6913 426,2042 ] line to [ 310,075 425,376 ]
STROKE (0,0,255) the path move to [ 304,6913 426,8254 ] line to [ 307,5902 425,9972 ]
FILL (0,0,255) the path move to [ 303,656 425,3759 ] line to [ 303,656 425,3759 ] line to [ 306,1407 425,1689 ] line to [ 306,1407 425,1689 ]
STROKE (0,0,255) the path move to [ 303,656 425,376 ] line to [ 303,656 425,376 ] line to [ 306,1407 425,1689 ] line to [ 306,1407 425,1689 ] close [ ]
FILL (0,0,255) the path move to [ 306,969 424,9618 ] line to [ 306,969 424,9618 ] line to [ 309,4538 424,7548 ] line to [ 309,4538 424,7548 ]
STROKE (0,0,255) the path move to [ 306,969 424,9619 ] line to [ 306,969 424,9619 ] line to [ 309,4538 424,7548 ] line to [ 309,4538 424,7548 ] close [ ]
FILL (0,0,255) the path move to [ 309,8679 424,9618 ] line to [ 309,8679 424,9618 ] line to [ 312,3527 424,5477 ] line to [ 312,3527 424,5477 ]
STROKE (0,0,255) the path move to [ 309,868 424,9619 ] line to [ 309,868 424,9619 ] line to [ 312,3527 424,5477 ] line to [ 312,3527 424,5477 ] close [ ]
STROKE (0,0,255) the path move to [ 313,1809 424,3407 ] line to [ 314,8374 424,1336 ]
STROKE (0,0,255) the path move to [ 304,2772 425,7901 ] line to [ 309,8679 424,9619 ] line to [ 312,9738 424,7548 ]
STROKE (0,0,255) the path move to [ 304,2772 425,9972 ] line to [ 309,8679 425,1689 ] line to [ 311,5244 424,9619 ]
STROKE (0,0,255) the path move to [ 304,6914 426,8254 ] line to [ 315,0445 424,1336 ]
STROKE (0,0,255) the path move to [ 311,7315 435,7292 ] line to [ 311,7315 432,8303 ]
STROKE (0,0,255) the path move to [ 321,2564 434,2797 ] line to [ 315,4587 434,2797 ]
STROKE (0,0,255) the path move to [ 315,4586 434,2797 ] line to [ 311,7315 434,2797 ]
STROKE (0,0,255) the path move to [ 311,7315 434,6938 ] line to [ 317,7363 434,0727 ] line to [ 311,7315 433,6585 ]
STROKE (0,0,255) the path move to [ 311,7315 434,4868 ] line to [ 314,8374 434,2797 ] line to [ 311,7315 434,2797 ]
STROKE (0,0,255) the path move to [ 310,6963 436,1433 ] line to [ 317,3222 434,9009 ] line to [ 322,2917 434,2797 ] line to [ 317,3222 433,6585 ] line to [ 310,6963 432,6232 ]
STROKE (0,0,255) the path move to [ 311,7315 435,5221 ] line to [ 317,3222 434,6938 ] line to [ 321,0493 434,2797 ] line to [ 317,3222 433,8656 ] line to [ 311,7315 433,0374 ]
STROKE (0,0,255) the path move to [ 311,7315 435,108 ] line to [ 317,3222 434,4868 ] line to [ 319,3928 434,2797 ] line to [ 317,3222 434,2797 ] line to [ 311,7315 433,4515 ]
使用iText7实现这一点同样简单。
顺便说一句:不幸的是,画箭头的指示没有特别标记;如果在同一页面上有其他矢量图形,则必须根据某些特定的标准过滤解析器返回的结果,例如颜色(在本例中为纯RGB蓝色)或近似的坐标范围(例如仅在给定的x和y坐标范围内)。
我知道周围也有类似的问题,但我无法找到一个可靠的答案,这是我的问题:有没有什么方法可以在没有谷歌地图引用的情况下将标记存储在ArrayList(或任何其他存储)中,然后简单地将它们添加到我的地图中? 背景:我有一个应用程序,目前有大约3500个标记。每个标记还有一个与之相关联的数据(布尔数组存储每个标记的数据,用于根据用户交互使它们可见/不可见)。目前,我使用扩展AsyncTask的类来获取这些标
我是一个新的传单,并试图实现不同CSS样式的一组标记。 因此,我意识到,在向映射添加标记后,我可以通过调用标记上的getElement()来访问不同的CSS属性,例如:
我正在尝试使用Microsoft Graph API访问用户所在的组。我面临一个问题,因为我认为我的权限设置正确,然而,当我登录到应用程序时,我得到的信息是: 有人遇到过这个问题吗? 知道我该怎么纠正吗?
我试图显示带有旋转x轴标签的图表,但该图表未显示。 此时,我可以看到图像,但在设置xticklabel后,我不再看到图像,只看到对象引用。(我会发布图片,但我没有足够的声誉:() 这里发布了一个类似的问题:在seaborn FactoryPlot中旋转标签文本,但解决方案不起作用。
我正在尝试实现chartJS条形图,并使用图例过滤条形图。我想将标签列表设置为空,因为这样可以清楚地删除条。我正在寻找一种在X轴上设置标记的方法,因为现在文本中的标记为空。 JSIDLE: https://jsfiddle.net/m1eorjwv/1/ 非常感谢,阿龙
我去一个标签名