2011-07-01 20 views
9

क्या पीडीएफ फाइलों को मर्ज करने के लिए आईओएस में कोई तरीका है, यानी, दूसरे के अंत में एक के पेज संलग्न करें और इसे डिस्क पर सहेजें?आईओएस पर पीडीएफ फाइलों को मर्ज करें

+0

यह नहीं करने के लिए एक जवाब है यह, लेकिन अगर कोई [मौजूदा पीडीएफ फ़ाइल संलग्न करना चाहते हैं] (http://stackoverflow.com/a/15355168/1603234) – Hemang

उत्तर

21

मैं इस समाधान के साथ बाहर आया:

// Documents dir 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [paths objectAtIndex:0]; 

// File paths 
NSString *pdfPath1 = [documentsDirectory stringByAppendingPathComponent:@"1.pdf"]; 
NSString *pdfPath2 = [documentsDirectory stringByAppendingPathComponent:@"2.pdf"]; 
NSString *pdfPathOutput = [documentsDirectory stringByAppendingPathComponent:@"out.pdf"]; 

// File URLs 
CFURLRef pdfURL1 = (CFURLRef)[[NSURL alloc] initFileURLWithPath:pdfPath1]; 
CFURLRef pdfURL2 = (CFURLRef)[[NSURL alloc] initFileURLWithPath:pdfPath2]; 
CFURLRef pdfURLOutput = (CFURLRef)[[NSURL alloc] initFileURLWithPath:pdfPathOutput]; 

// File references 
CGPDFDocumentRef pdfRef1 = CGPDFDocumentCreateWithURL((CFURLRef) pdfURL1); 
CGPDFDocumentRef pdfRef2 = CGPDFDocumentCreateWithURL((CFURLRef) pdfURL2); 

// Number of pages 
NSInteger numberOfPages1 = CGPDFDocumentGetNumberOfPages(pdfRef1); 
NSInteger numberOfPages2 = CGPDFDocumentGetNumberOfPages(pdfRef2); 

// Create the output context 
CGContextRef writeContext = CGPDFContextCreateWithURL(pdfURLOutput, NULL, NULL); 

// Loop variables 
CGPDFPageRef page; 
CGRect mediaBox; 

// Read the first PDF and generate the output pages 
NSLog(@"GENERATING PAGES FROM PDF 1 (%i)...", numberOfPages1); 
for (int i=1; i<=numberOfPages1; i++) { 
    page = CGPDFDocumentGetPage(pdfRef1, i); 
    mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); 
    CGContextBeginPage(writeContext, &mediaBox); 
    CGContextDrawPDFPage(writeContext, page); 
    CGContextEndPage(writeContext); 
} 

// Read the second PDF and generate the output pages 
NSLog(@"GENERATING PAGES FROM PDF 2 (%i)...", numberOfPages2); 
for (int i=1; i<=numberOfPages2; i++) { 
    page = CGPDFDocumentGetPage(pdfRef2, i); 
    mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); 
    CGContextBeginPage(writeContext, &mediaBox); 
    CGContextDrawPDFPage(writeContext, page); 
    CGContextEndPage(writeContext);  
} 
NSLog(@"DONE!"); 

// Finalize the output file 
CGPDFContextClose(writeContext); 

// Release from memory 
CFRelease(pdfURL1); 
CFRelease(pdfURL2); 
CFRelease(pdfURLOutput); 
CGPDFDocumentRelease(pdfRef1); 
CGPDFDocumentRelease(pdfRef2); 
CGContextRelease(writeContext); 

यहां सबसे बड़ी समस्या स्मृति आवंटन है। जैसा कि आप देख सकते हैं, इस दृष्टिकोण में आपको उन दोनों पीडीएफ फाइलों को पढ़ना होगा जिन्हें आप विलय करना चाहते हैं और साथ ही आउटपुट उत्पन्न करते हैं। रिलीज केवल अंत में होते हैं। मैंने 500 पृष्ठों (~ 15 एमबी) के साथ एक पीडीएफ फ़ाइल को जोड़ने की कोशिश की जिसमें 100 पेज (~ 3 एमबी) शामिल हैं और इसने 600 पृष्ठों (बिल्कुल!) के साथ एक नया उत्पाद बनाया है जिसमें केवल ~ 5 एमबी आकार (जादू?) है। निष्पादन में लगभग 30 सेकंड लग गए (इतना बुरा नहीं, आईपैड 1 पर विचार करना) और 17 एमबी (आउच!) आवंटित किया गया। ऐप सौभाग्य से दुर्घटनाग्रस्त नहीं हुआ, लेकिन मुझे लगता है कि आईओएस इस तरह 17 एमबी उपभोग करने वाले ऐप को मारना पसंद करेगा। ; P

+0

कोड को संशोधित करना मुश्किल नहीं होना चाहिए ताकि यह प्रत्येक दस्तावेज़ (या यहां तक ​​कि प्रत्येक एक्स-पेज या तो) जारी करता हो, यदि आप एक समय में प्रत्येक पृष्ठ को डिस्क पर लिख रहे हैं ... हेक, आप कभी भी पढ़ सकते हैं और रिलीज़ कर सकते हैं एक समय में एक पेज! यह गति और स्मृति के बीच एक व्यापार है ... – FeifanZ

+0

यह काम करेगा! हालांकि मुझे इसे लागू करने का कोई तरीका नहीं मिला, फिर भी। 'CGPDFContextClose' का उपयोग करके किसी संदर्भ को बंद करने के बाद (फ़ाइल को डिस्क पर सहेजें), इसे फिर से खोलना संभव नहीं है और जहां से आपने रोका था, वहां से संपादन जारी रखना संभव है, जैसे कि पॉइंटर को फ़ाइल के अंत में ले जाना और नई सामग्री जोड़ें। – Jonatan

+0

हमम ... मैं वहां के कार्यों और विधियों से बहुत परिचित नहीं हूं, लेकिन कुछ प्रकार की फ़ाइल I/O स्ट्रीम क्लास हो सकती है जो आपको पॉइंटर को अग्रिम करने देगी। या बस एक समय में बिट्स की मेगाबाइट की तरह कुछ खींचें और इसे डिस्क पर लिखें (सुनिश्चित नहीं है कि यह कितना अच्छा काम करेगा) – FeifanZ

0

मेरा मानना ​​है कि FastPdfKit बिल्कुल वही है जो आप ढूंढ रहे हैं और यह मुफ़्त है!

+0

यह एक अच्छी लाइब्रेरी टी है ओ पीडीएफ प्रदर्शित करें, लेकिन यह AFAICT विलय का समर्थन नहीं करता है। – lkraider

23

मैं किसी भी आकार के किसी भी पीडीएफ फाइल में शामिल होने के जोनाथन के कोड पर एक छोटे से refactor कर दिया है:

+ (NSString *)joinPDF:(NSArray *)listOfPaths { 
    // File paths 
    NSString *fileName = @"ALL.pdf"; 
    NSString *pdfPathOutput = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fileName]; 

    CFURLRef pdfURLOutput = ( CFURLRef)CFBridgingRetain([NSURL fileURLWithPath:pdfPathOutput]); 

    NSInteger numberOfPages = 0; 
    // Create the output context 
    CGContextRef writeContext = CGPDFContextCreateWithURL(pdfURLOutput, NULL, NULL); 

    for (NSString *source in listOfPaths) { 
     CFURLRef pdfURL = ( CFURLRef)CFBridgingRetain([[NSURL alloc] initFileURLWithPath:source]); 

     //file ref 
     CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithURL((CFURLRef) pdfURL); 
     numberOfPages = CGPDFDocumentGetNumberOfPages(pdfRef); 

     // Loop variables 
     CGPDFPageRef page; 
     CGRect mediaBox; 

     // Read the first PDF and generate the output pages 
     DLog(@"GENERATING PAGES FROM PDF 1 (%@)...", source); 
     for (int i=1; i<=numberOfPages; i++) { 
      page = CGPDFDocumentGetPage(pdfRef, i); 
      mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); 
      CGContextBeginPage(writeContext, &mediaBox); 
      CGContextDrawPDFPage(writeContext, page); 
      CGContextEndPage(writeContext); 
     } 

     CGPDFDocumentRelease(pdfRef); 
     CFRelease(pdfURL); 
    } 
    CFRelease(pdfURLOutput); 

    // Finalize the output file 
    CGPDFContextClose(writeContext); 
    CGContextRelease(writeContext); 

    return pdfPathOutput; 
} 

आशा है कि

+2

सिर्फ एआरसी के लिए एक अद्यतन: ऐसा लगता है जब तक आप autoreleasing विधि fileURLWithPath का उपयोग करें कि यह एक अपवाद फेंक देगा: -> (__bridge CFURLRef) [NSURL fileURLWithPath: pdfPathOutput] के बजाय init विधि। – Bek

+0

मूल पीडीएफ आकार और अनुकूलता संस्करण के मामले में थोड़े अलग है, मर्ज करने के लिए केवल एक pdf फ़ाइल पर विचार मूल संस्करण 1.4 लेकिन 1.3 में उत्पन्न मर्ज किए गए एक में है। मैं संस्करण कैसे सेट कर सकता हूं? – Cam

3

में मदद करता है मैं अपने खुद के पुस्तकालय यहाँ को बढ़ावा देने के कर रहा हूँ ... लेकिन मेरे पास एक मुफ्त पीडीएफ पढ़ने/लेखन पुस्तकालय है, जिसे मैंने हाल ही में दिखाया है कि आईओएस संदर्भ में कैसे उपयोग किया जाए। यह पीडीएफ विलय करने और उन्हें छेड़छाड़ करने के लिए एकदम सही है, और अपेक्षाकृत छोटी स्मृति हस्ताक्षर के साथ ऐसा करता है। इसका उपयोग करने पर विचार करें, यहां एक उदाहरण देखें - ios with PDFHummus। दोबारा, यह मुझे अपनी पुस्तकालय का प्रचार कर रहा है, इसलिए सही सलाह में यह सलाह लें।

1

मैं @matsoftware द्वारा बनाए गए समाधान पर अपना समाधान आधारित करता हूं।

मैं अपने समाधान के लिए एक टुकड़ा बनाया: https://gist.github.com/jefferythomas/7265536

+ (void)combinePDFURLs:(NSArray *)PDFURLs writeToURL:(NSURL *)URL 
{ 
    CGContextRef context = CGPDFContextCreateWithURL((__bridge CFURLRef)URL, NULL, NULL); 

    for (NSURL *PDFURL in PDFURLs) { 
     CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((__bridge CFURLRef)PDFURL); 
     size_t numberOfPages = CGPDFDocumentGetNumberOfPages(document); 

     for (size_t pageNumber = 1; pageNumber <= numberOfPages; ++pageNumber) { 
      CGPDFPageRef page = CGPDFDocumentGetPage(document, pageNumber); 
      CGRect mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); 

      CGContextBeginPage(context, &mediaBox); 
      CGContextDrawPDFPage(context, page); 
      CGContextEndPage(context); 
     } 

     CGPDFDocumentRelease(document); 
    } 

    CGPDFContextClose(context); 
    CGContextRelease(context); 
} 
2

मैंने सोचा कि मैं स्विफ्ट का उपयोग कर के बाद से मैं स्विफ्ट में इसके लिए देख रहा था जवाब का हिस्सा था और यह नहीं मिल सकता है और यह अनुवाद करने के लिए किया था। साथ ही, मेरा उत्तर अलग-अलग पीडीएफ pdfPagesURLArray की सरणी का उपयोग करता है और पूर्ण पीडीएफ उत्पन्न करने के लिए लूप करता है। मैं इस पर बिल्कुल नया हूं इसलिए किसी भी सुझाव का स्वागत है।

let file = "fileName.pdf" 
    guard var documentPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first else { 
     NSLog("Doh - can't find that path") 
     return 
    } 
    documentPaths = documentPaths.stringByAppendingString(file) 
    print(documentPaths) 

    let fullPDFOutput: CFURLRef = NSURL(fileURLWithPath: documentPaths) 

    let writeContext = CGPDFContextCreateWithURL(fullPDFOutput, nil, nil) 

    for pdfURL in pdfPagesURLArray { 
     let pdfPath: CFURLRef = NSURL(fileURLWithPath: pdfURL) 
     let pdfReference = CGPDFDocumentCreateWithURL(pdfPath) 
     let numberOfPages = CGPDFDocumentGetNumberOfPages(pdfReference) 
     var page: CGPDFPageRef 
     var mediaBox: CGRect 

     for index in 1...numberOfPages { 

बल इस तरह यहाँ unwrapping कर सका: page = CGPDFDocumentGetPage(pdfReference, index)! लेकिन सबसे अच्छा अभ्यास के साथ जारी रखने के लिए:

 guard let getCGPDFPage = CGPDFDocumentGetPage(pdfReference, index) else { 
       NSLog("Error occurred in creating page") 
       return 
      } 
      page = getCGPDFPage 
      mediaBox = CGPDFPageGetBoxRect(page, .MediaBox) 
      CGContextBeginPage(writeContext, &mediaBox) 
      CGContextDrawPDFPage(writeContext, page) 
      CGContextEndPage(writeContext) 
     } 
    } 
    NSLog("DONE!") 

    CGPDFContextClose(writeContext); 

    NSLog(documentPaths) 
+0

धन्यवाद एक गुच्छा, मैं एचटीएमएल से पीडीएफ एक बहुत बनाने रहा हूँ और मैं पृष्ठ विराम की जरूरत है, जब से मैं किसी भी खोजने के लिए सक्षम नहीं था, इसलिए मैं कई एचटीएमएल के साथ कई पीडीएफ बनाया और फिर उन सभी गठबंधन करने के लिए उर कोड का इस्तेमाल किया, धन्यवाद :) – vinbhai4u

+1

@ vinbhai4u मैं तेजी से किसी भी समाधान नहीं मिला तो मैं होगा उम्मीद कर रही थी कि मैं क्या के साथ आया था दूसरों के लिए उपयोगी हो। खुशी है कि यह आपकी मदद की :) – FromTheStix

1

तेज 3 में मेरे समारोह:

// sourcePdfFiles is array of source file full paths, destPdfFile is dest file full path 
func mergePdfFiles(sourcePdfFiles:[String], destPdfFile:String) { 

    guard UIGraphicsBeginPDFContextToFile(destPdfFile, CGRect.zero, nil) else { 
     return 
    } 
    guard let destContext = UIGraphicsGetCurrentContext() else { 
     return 
    } 

    for index in 0 ..< sourcePdfFiles.count { 
     let pdfFile = sourcePdfFiles[index] 
     let pdfUrl = NSURL(fileURLWithPath: pdfFile) 
     guard let pdfRef = CGPDFDocument(pdfUrl) else { 
      continue 
     } 

     for i in 1 ... pdfRef.numberOfPages { 
      if let page = pdfRef.page(at: i) { 
       var mediaBox = page.getBoxRect(.mediaBox) 
       destContext.beginPage(mediaBox: &mediaBox) 
       destContext.drawPDFPage(page) 
       destContext.endPage() 
      } 
     } 
    } 

    destContext.closePDF() 
    UIGraphicsEndPDFContext() 
} 
+0

यह बहुत उपयोगी था। धन्यवाद! :) –

संबंधित मुद्दे