2017-04-17 1 views
0
나는 애플의 프로그래밍 가이드 다음 PDF 문서의 내용을 구문 분석 스위프트를 사용하려고 해요

(모든 예제는 ObjC을하는을 ...)신속 CGPDFDocument 구문 분석

let filepath = "/Users/ben/Desktop/Test.pdf" 
let localUrl = filepath as CFString 
if let pdfURL = CFURLCreateWithFileSystemPath(nil, localUrl, CFURLPathStyle.cfurlposixPathStyle, false) { 
    if let pdf = CGPDFDocument(pdfURL) { 
     if let inf = pdf.info { 
      CGPDFDictionaryApplyFunction(inf, { (key, object, info) -> Void in 
       print("\(key), \(object), \(info)") 
      }, nil) 
     } 
     if let cat = pdf.catalog { 

      CGPDFDictionaryApplyFunction(cat, { (key, object, info) -> Void in 
       print("\(key), \(object), \(info)") 
      }, nil) 

     } 
} 
} 

이 일부를 생산하는 것 같지만 결과는 16 진수 문자열입니다.

0x00007ff29f43ce00, 0x00007ff29f492bd0, nil 
0x00007ff29f443b60, 0x00007ff29f492cd0, nil 
0x00007ff29f482590, 0x00007ff29f492dd0, nil 
0x00007ff29f482a40, 0x00007ff29f492ed0, nil 
0x00007ff29f482e30, 0x00007ff29f492fe0, nil 
0x00007ff29f47da20, 0x00007ff29f4930e0, nil 
0x00007ff29f474ac0, 0x00007ff29f842b50, nil 
0x00007ff29f43f5d0, 0x00007ff29f842bf0, nil 
0x00007ff29f485eb0, 0x00007ff29f842a60, nil 
0x00007ff29f482f70, 0x00007ff29f842ab0, nil 
0x00007ff29f48b1c0, 0x00007ff29f48f6d0, nil 

어떻게 실제 데이터를 얻을 수 있습니까? 이상적으로는 문서 메타 데이터와 포함 된 글꼴 같은 것을 얻으려고합니다.

답변

1

상위 수준 사전 및 정보 데이터를 검색하는 구문 분석은 정확하지만 유형 (정수, 문자열, 배열, 사전 등)에 따라 PDF 데이터의 값을 표시하려면 CGPDFDictionaryApplyFunction의 디코딩을 확장해야합니다. 당신이 호출하는 CGPDFDictionaryApplierFunction의 구문은 다음과 같습니다

typealias CGPDFDictionaryApplierFunction = (UnsafePointer<Int8>, COpaquePointer, UnsafeMutablePointer<()>) -> Void

데이터에 포인터를 표시하면 다음과 같이 자신의 유형에 따라 데이터 값에 액세스 할 수 귀하의 프로그램 (스위프트 2) :

let filepath = "/Users/ben/Desktop/Test.pdf" 
    let urlDocument = NSURL(fileURLWithPath: filepath) 
    let myDocument = CGPDFDocumentCreateWithURL(urlDocument) 
    if myDocument != nil { 
     let numPages = CGPDFDocumentGetNumberOfPages(myDocument) 
     print("Number of pages: \(numPages)") 
     // Get complete catalog 
     let myCatalog = CGPDFDocumentGetCatalog(myDocument) 
     CGPDFDictionaryApplyFunction(myCatalog, printPDFKeys, nil) 
     let myInfo = CGPDFDocumentGetInfo(myDocument) 
     CGPDFDictionaryApplyFunction(myInfo, printPDFKeys, nil) 
    } else { 
     print("Cannot open PDF document") 
    } 

CGPDFDictionaryApplyFunction에서 호출하려면 printPDFKeys를 전역 함수 (기본 클래스 외부)로 호출해야하며 위의 예 에서처럼 CGPDFDictionaryApplyFunction의 클로저에 코드를 삽입 할 수도 있습니다. 아래의 코드는 단축되어 오류 및 null 값에 대한 완전한 보호를 포함하지 않습니다.

func printPDFKeys(key: UnsafePointer<Int8>, object: COpaquePointer, info: UnsafeMutablePointer<()>) { 
    let contentDict: CGPDFDictionaryRef = CGPDFDictionaryRef(info) 
    let keyString = String(CString: UnsafePointer<CChar>(key), encoding: NSISOLatin1StringEncoding) 
    let objectType = CGPDFObjectGetType(object) 
    if keyString == nil { 
     return 
    } 
    print("key \(keyString!) is present in dictionary, type \(objectType.rawValue)") 
    var ptrObjectValue = UnsafePointer<Int8>() 
    switch objectType { 
    // ObjectType is enum of: 
    // Null 
    // Boolean 
    // Integer 
    // Real 
    // Name 
    // String 
    // Array 
    // Dictionary 
    // Stream 
    case .Boolean: 
     // Boolean 
     var objectBoolean = CGPDFBoolean() 
     if CGPDFObjectGetValue(object, objectType, &objectBoolean) { 
      let testbool = NSNumber(unsignedChar: objectBoolean) 
      print("Boolean value \(testbool)") 
     } 
    case .Integer: 
     // Integer 
     var objectInteger = CGPDFInteger() 
     if CGPDFObjectGetValue(object, objectType, &objectInteger) { 
      print("Integer value \(objectInteger)") 
     } 
    case .Real: 
     // Real 
     var objectReal = CGPDFReal() 
     if CGPDFObjectGetValue(object, objectType, &objectReal) { 
      print("Real value \(objectReal)") 
     } 
    case .Name: 
     // Name 
     if (CGPDFObjectGetValue(object, objectType, &ptrObjectValue)) { 
      let stringName = String(CString: UnsafePointer<CChar>(ptrObjectValue), encoding: NSISOLatin1StringEncoding) 
      print("Name value: \(stringName!)") 
     } 
    case .String: 
     // String 
     let valueFound = CGPDFObjectGetValue(object, objectType, &ptrObjectValue) 
     let stringValue = CGPDFStringCopyTextString(COpaquePointer(ptrObjectValue)) 
     print("String value: \(stringValue!)") 
    case .Array: 
     // Array 
     print("Array") 
     var objectArray = CGPDFArrayRef() 
     if (CGPDFObjectGetValue(object, objectType, &objectArray)) 
     { 
      print("array: \(arrayFromPDFArray(objectArray))") 
     } 
    case .Dictionary: 
     // Dictionary 
     var objectDictionary = CGPDFDictionaryRef() 
     if (CGPDFObjectGetValue(object, objectType, &objectDictionary)) { 
      let count = CGPDFDictionaryGetCount(objectDictionary) 
      print("Found dictionary with \(count) entries") 
      if !(keyString == "Parent") && !(keyString == "P") { 
       //catalogLevel = catalogLevel + 1 
       CGPDFDictionaryApplyFunction(objectDictionary, printPDFKeys, nil) 
       //catalogLevel = catalogLevel - 1 
      } 
     } 
case .Stream: 
    // Stream 
    print("Stream") 
    var objectStream = CGPDFStreamRef() 
    if (CGPDFObjectGetValue(object, objectType, &objectStream)) { 
     let dict: CGPDFDictionaryRef = CGPDFStreamGetDictionary(objectStream) 
     var fmt: CGPDFDataFormat = .Raw 
     let streamData: CFDataRef = CGPDFStreamCopyData(objectStream, &fmt)!; 
     let data = NSData(data: streamData) 
     let dataString = NSString(data: data, encoding: NSUTF8StringEncoding) 
     let dataLength: Int = CFDataGetLength(streamData) 
     print("data stream (length=\(dataLength)):") 
     if dataLength < 400 { 
      print(dataString) 
     } 
    } 
default: 
    print("Null") 
} 
} 

// convert a PDF array into an objC one 
func arrayFromPDFArray(pdfArray: CGPDFArrayRef) -> NSMutableArray { 
var i:Int = 0 
var tmpArray: NSMutableArray = NSMutableArray() 

let count = CGPDFArrayGetCount(pdfArray) 
for i in 0..<count { 
    var value = CGPDFObjectRef() 
    if (CGPDFArrayGetObject(pdfArray, i, &value)) { 
     if let object = objectForPDFObject(value) { 
      tmpArray.addObject(object) 
     } 
    } 
} 

return tmpArray 
} 

func objectForPDFObject(object: CGPDFObjectRef) -> AnyObject? { 
let objectType: CGPDFObjectType = CGPDFObjectGetType(object) 
var ptrObjectValue = UnsafePointer<Int8>() 
switch (objectType) { 
case .Boolean: 
    // Boolean 
    var objectBoolean = CGPDFBoolean() 
    if CGPDFObjectGetValue(object, objectType, &objectBoolean) { 
     let testbool = NSNumber(unsignedChar: objectBoolean) 
     return testbool 
    } 
case .Integer: 
    // Integer 
    var objectInteger = CGPDFInteger() 
    if CGPDFObjectGetValue(object, objectType, &objectInteger) { 
     return objectInteger 
    } 
case .Real: 
    // Real 
    var objectReal = CGPDFReal() 
    if CGPDFObjectGetValue(object, objectType, &objectReal) { 
     return objectReal 
    } 
case .String: 
    let valueFound = CGPDFObjectGetValue(object, objectType, &ptrObjectValue) 
    let stringValue = CGPDFStringCopyTextString(COpaquePointer(ptrObjectValue)) 
    return stringValue 
case .Dictionary: 
    // Dictionary 
    var objectDictionary = CGPDFDictionaryRef() 
    if (CGPDFObjectGetValue(object, objectType, &objectDictionary)) { 
     let count = CGPDFDictionaryGetCount(objectDictionary) 
     print("In array, found dictionary with \(count) entries") 
     CGPDFDictionaryApplyFunction(objectDictionary, printPDFKeys, nil) 
    } 
case .Stream: 
    // Stream 
    var objectStream = CGPDFStreamRef() 
    if (CGPDFObjectGetValue(object, objectType, &objectStream)) { 
     let dict: CGPDFDictionaryRef = CGPDFStreamGetDictionary(objectStream) 
     var fmt: CGPDFDataFormat = .Raw 
     let streamData: CFDataRef = CGPDFStreamCopyData(objectStream, &fmt)!; 
     let data = NSData(data: streamData) 
     let dataString = NSString(data: data, encoding: NSUTF8StringEncoding) 
     print("data stream (length=\(CFDataGetLength(streamData))):") 
     return dataString 
    } 
default: 
    return nil 
} 
return nil 
} 
+0

스위프트 3을 사용하고 있지만 멋진 것들입니다. 따라서 많은 오류가 발생했습니다. 특히,'var objectStream = CGPDFStreamRef()'와 같은 것들은 인수를 필요로합니다. – benwiggy

+0

시간을 내 주셔서 감사합니다. 애플은 "CGPDFJustGetAllTheData"와 같은 분명한 작업을 위해 고차원 API를 개발할 것이라고 생각한다. 또는 함수 라이브러리가 더 보편적입니다. – benwiggy

+0

대단히 환영합니다! 이것이 도움이 될 수있어서 기쁘다. 사실, 애플 API는 사용자 친화적이지 않다. PDF 디코딩 자체를 배우는 것은 꽤 시간이 많이 걸린다. –