Слияние PDF-файлов на iOS - PullRequest
11 голосов
/ 02 июля 2011

Есть ли в iOS способ объединить PDF-файлы, то есть добавить страницы одной в конец другой и сохранить ее на диск?

Ответы [ 7 ]

23 голосов
/ 06 ноября 2011

Я сделал небольшой рефакторинг кода Джонатана, чтобы присоединиться к любому PDF-файлу любого размера:

+ (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;
}

Надеюсь, это поможет

21 голосов
/ 05 июля 2011

Я предложил это решение:

// 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);

Самая большая проблема здесь - это распределение памяти.Как вы можете видеть, в этом подходе вы должны прочитать оба PDF-файла, с которыми хотите объединиться, и одновременно сгенерировать вывод.Релизы происходят только в конце.Я попытался объединить PDF-файл с 500 страницами (~ 15 МБ) с другим, содержащим 100 страниц (~ 3 МБ), и он создал новый файл с 600 страницами (конечно!) Размером всего ~ 5 МБ (магия?).Выполнение заняло около 30 секунд (не так уж и плохо, учитывая iPad 1) и выделило 17 МБ (ой!).К счастью, приложение не рухнуло, но я думаю, что iOS очень хотелось бы убить приложение, потребляющее 17 МБ, как это.; Р

4 голосов
/ 18 июля 2017

Моя функция в Swift 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()
}
2 голосов
/ 27 января 2016

Я думал, что поделюсь ответом, используя Swift, так как я искал его в Swift и не мог найти его, и мне пришлось его перевести. Кроме того, мой ответ использует массив каждого из отдельных файлов pdf pdfPagesURLArray и перебирает их для создания полного файла pdf. Я новичок в этом, поэтому любые предложения приветствуются.

    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 {

Может сделать принудительное развертывание здесь вот так: 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)
2 голосов
/ 14 февраля 2013

Я продвигаю свою собственную библиотеку здесь ... но у меня есть бесплатная библиотека для чтения / записи PDF, которую я недавно показал, как использовать в контексте iOS.он идеально подходит для объединения PDF-файлов и манипулирования ими, и делает это с относительно небольшой сигнатурой памяти.Попробуйте использовать его, см. Здесь пример - ios с PDFHummus .Опять же, это я продвигаю свою собственную библиотеку, поэтому примите этот совет в правильном контексте.

1 голос
/ 01 ноября 2013

Я основал свое решение на решении, созданном @ 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);
}
0 голосов
/ 02 июля 2011

Я считаю, FastPdfKit это именно то, что вы ищете, и есть бесплатная версия!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...