Используя Какао, NSPrintOperation, Как правильно создать PDF-файл из текста в NSView?

Используя NSPrintOperation, Как правильно создать PDF-файл из текста в NSView?


* * ОБРАТИТЕ ВНИМАНИЕ, Я НАШЕЛ ВРЕМЕННОЕ РЕШЕНИЕ, КОТОРОЕ ПОКАЗАНО НА НИЖЕ


Что я сделал: 1. Поместил текст в NSTextView.

- (NSTextView *)printableViewWithRecipe:(Recipe *)recipe
{

[_printView setString:@""];
[_printView setTextColor:[NSColor textColor]];
[_printView setFont:[NSFont userFontOfSize:0]];
NSDictionary    *titleAttr;
_printView = [[NSTextView alloc] initWithFrame:[[self printInfo] imageablePageBounds]];
[_printView setVerticallyResizable:YES];
[_printView setHorizontallyResizable:NO];

// Begin to ADD THE TEXT
[[_printView textStorage] beginEditing];

// Set the attributes for the title
[[_printView textStorage] beginEditing];
titleAttr =
[NSDictionary dictionaryWithObject:[(AppDelegate*)[[NSApplication sharedApplication] delegate] tableFont] forKey:NSFontAttributeName];

// Add the title
[
 [_printView textStorage] appendAttributedString:
 [[NSAttributedString alloc] initWithString:[recipe name]  attributes:titleAttr ]
];

// Create a couple returns between the title and the body
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];

// Add the body text
if([[recipe ingredients] length] )
    [[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
                                                      initWithString:[recipe ingredients] attributes:titleAttr]];
// Create a couple returns between the ingredients and the directions
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
if([[recipe directions] length] )
    [[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
                                                      initWithString:[recipe directions] attributes:titleAttr]];
// Create a couple returns between the directions and the comments
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
if([[recipe comments] length] )
    [[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
                                                      initWithString:[recipe comments] attributes:titleAttr]];
// Center the title
[_printView setAlignment:NSCenterTextAlignment range:NSMakeRange(0, [[recipe name] length])];

[[_printView textStorage] endEditing];

return _printView;

} // end printableViewForRecipe

2. Попробуйте создать файл PDF из текста TextView, используя метод ниже:

- (PDFDocument *)exportPDFfromView:(NSTextView*)textView  fileNumber:(NSUInteger)fileNumber
{ 
    NSPrintInfo *printInfo;
    NSPrintInfo *sharedInfo;
    NSPrintOperation *printOp;
    NSMutableDictionary *printInfoDict;
    NSMutableDictionary *sharedDict;
    sharedInfo = [NSPrintInfo sharedPrintInfo];
    sharedDict = [sharedInfo dictionary];
    printInfoDict = [NSMutableDictionary dictionaryWithDictionary: sharedDict];
    [printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
    NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
    NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
    [printInfoDict setObject:poTempfileURL forKey:NSPrintJobSavingURL];
    printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];//1
    [printInfo setHorizontalPagination: NSAutoPagination];//2
    [printInfo setVerticalPagination: NSAutoPagination];//3
    [printInfo setVerticallyCentered:NO];//4

    printOp = [NSPrintOperation printOperationWithView:textView printInfo:printInfo];//5
    [printOp setShowsPrintPanel:NO];
    [printOp setShowsProgressPanel:NO];//6
    DLog(@"poTempfileURL=%@",poTempfileURL);

    BOOL didRunOK = [printOp runOperation];//7
    BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[poTempfileURL path]];
    DLog(@"poTempfileURL=%@",poTempfileURL);
    DLog(@"didRunOK=%lu\nfileExists=%lu",didRunOK,exists);
    PDFDocument *doc = [[PDFDocument alloc] initWithURL:poTempfileURL];

    return doc;
}
  1. Запустите следующий код:

    [self tempDirectoryURL];// invoke getter
    NSLog(@"_tempDirectoryURL=%@",_tempDirectoryURL);
    
    _tempDirectoryURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/ 
    

Геттер следует:

- (NSURL *)tempDirectoryURL { //getter
    NSURL *tempURL;
    if(!_tempDirectoryURL){
        tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]] isDirectory:YES];
        _tempDirectoryURL = tempURL;
    }
    return _tempDirectoryURL;
}   
  1. После запуска этого кода:

    BOOL didRunOK = [printOp runOperation]; // 7

    BOOL существует = [[NSFileManager defaultManager] fileExistsAtPath:[путь poTempfileURL]]; DLOG (@"didRunOK=% лу \nfileExists=% лу",didRunOK, существует); DLoG (@"poTempfileURL=%@",poTempfileURL);

Я ожидаю, что файл PDF будет создан по адресу: poTempfileURL, где его значение будет следующим: poTempfileURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/884B9B4C-907B-489E21F9A1B9A10009 000016435C134E56/7A196040-0D81-496D-B9F3-BF0B855F6BBC-1821-0000164A9446040F_file_0.pdf

консоль показывает:

 didRunOK=1
 fileExists=1
  1. Когда выполняется следующая строка кода:

    BOOL didRunOK = [printOp runOperation]; // 7

Содержимое printInfo для printOp:

{
    NSBottomMargin = 90;
    NSCopies = 1;
    NSDestinationFormat = "application/pdf";
    NSDetailedErrorReporting = 0;
    NSFaxNumber = "";
    NSFirstPage = 1;
    NSHorizonalPagination = 0;
    NSHorizontallyCentered = 0;
    NSJobDisposition = NSPrintSaveJob;
    NSJobSavingFileNameExtensionHidden = 0;
    NSJobSavingURL = "file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/2687B4CD-6ABF-4826-B8F8-3D536FFACA66-1362-00001DEFA0B13D70/1F0483BF-00B4-4F65-A3C7-C4824F53C03E-1362-00001DF033AAD968_file_0.pdf";
    NSLastPage = 2147483647;
    NSLeftMargin = 72;
    NSMustCollate = 1;
    NSOrientation = 0;
    NSPagesAcross = 1;
    NSPagesDown = 1;
    NSPaperName = "na-letter";
    NSPaperSize = "NSSize: {612, 792}";
    NSPrintAllPages = 1;
    NSPrintProtected = 0;
    NSPrintSelectionOnly = 0;
    NSPrintTime = "0000-12-30 00:00:00 +0000";
    NSPrinter = "{\n    \"Device Description\" =     {\n        NSDeviceIsPrinter = YES;\n    };\n    \"Language Level\" = 3;\n    Name = \"HP DESKJET 840C @ Mark\\U2019s Mac Pro\";\n    Type = \"Generic PCL Laser Printer\";\n}";
    NSPrinterName = "HP DESKJET 840C @ Mark\U2019s Mac Pro";
    NSRightMargin = 72;
    NSSavePath = "/var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/2687B4CD-6ABF-4826-B8F8-3D536FFACA66-1362-00001DEFA0B13D70/1F0483BF-00B4-4F65-A3C7-C4824F53C03E-1362-00001DF033AAD968_file_0.pdf";
    NSScalingFactor = 1;
    NSTopMargin = 90;
    NSVerticalPagination = 0;
    NSVerticallyCentered = 0;
}

В Xcode: po [[textView textStorage] string] производит текст ниже с пометкой:

 /// BEGIN NSTextView TEXT ///

В Finder, когда я открываю файл, расположенный в poTempFileURL, в окне предварительного просмотра этот файл состоит из четырех страниц (он должен иметь только одну страницу) и представляется в виде предварительного просмотра пустым файлом PDF.

Когда я открываю тот же самый файл "PDF" в TextEdit, этот файл содержит содержимое ниже, которое помечено: /// BEGIN TEXT PDF Tempfile ///

Что мне нужно сделать, чтобы создать "правильный" PDF-файл? Я не могу получить PDF, который я могу открыть и прочитать в Preview.

po [doc pageCount] показывает "4"

/// НАЧАТЬ NSTextView TEXT /// - po [[textView textStorage] string]

French Toast

[French Toast]
preptime 0:03 cooktime 0:08 serves:1-2

egg   1     
milk   3/4  cup 
ground cinnamon   1/8  tsp  (optional)
best bread   2  slices  
butter   4  tsp (two per side)
maple syrup     (to taste)


[French Toast]

1. Add egg to a bowl and beat with a fork. 

2. Add milk and cinnamon to egg and beat briefly.

3. Heat heavy skillet to medium high. Add 2 tsp butter. 

4. Dip bread slice halves in batter and brown in skillet. Flip and add additional butter. Brown and serve with syrup.

Serve with pork sausage, chorizo or bacon.

/// КОНЕЦ NSTextView TEXT ///

/// НАЧАТЬ ТЕКСТ PDF Tempfile ///

%PDF-1.3
%ƒÂÚÂÎßÛ†–ƒ∆
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
5 0 obj
11
endobj
2 0 obj
<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792]
>>
endobj
6 0 obj
<< /ProcSet [ /PDF ] >>
endobj
8 0 obj
<< /Length 9 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
9 0 obj
11
endobj
7 0 obj
<< /Type /Page /Parent 3 0 R /Resources 10 0 R /Contents 8 0 R /MediaBox [0 0 612 792]
>>
endobj
10 0 obj
<< /ProcSet [ /PDF ] >>
endobj
12 0 obj
<< /Length 13 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
13 0 obj
11
endobj
11 0 obj
<< /Type /Page /Parent 3 0 R /Resources 14 0 R /Contents 12 0 R /MediaBox
[0 0 612 792] >>
endobj
14 0 obj
<< /ProcSet [ /PDF ] >>
endobj
16 0 obj
<< /Length 17 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
17 0 obj
11
endobj
15 0 obj
<< /Type /Page /Parent 3 0 R /Resources 18 0 R /Contents 16 0 R /MediaBox
[0 0 612 792] >>
endobj
18 0 obj
<< /ProcSet [ /PDF ] >>
endobj
3 0 obj
<< /Type /Pages /MediaBox [0 0 612 792] /Count 4 /Kids [ 2 0 R 7 0 R 11 0 R
15 0 R ] >>
endobj
19 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
20 0 obj
(Untitled)
endobj
21 0 obj
(Mac OS X 10.10.3 Quartz PDFContext)
endobj
22 0 obj
(HungryMe)
endobj
23 0 obj
(D:20150513191029Z00'00')
endobj
24 0 obj
()
endobj
25 0 obj
[ ]
endobj
1 0 obj
<< /Title 20 0 R /Producer 21 0 R /Creator 22 0 R /CreationDate 23 0 R /ModDate
23 0 R /Keywords 24 0 R /AAPL:Keywords 25 0 R >>
endobj
xref
0 26
0000000000 65535 f 
0000001363 00000 n 
0000000125 00000 n 
0000001022 00000 n 
0000000022 00000 n 
0000000107 00000 n 
0000000229 00000 n 
0000000371 00000 n 
0000000268 00000 n 
0000000353 00000 n 
0000000476 00000 n 
0000000622 00000 n 
0000000516 00000 n 
0000000603 00000 n 
0000000729 00000 n 
0000000875 00000 n 
0000000769 00000 n 
0000000856 00000 n 
0000000982 00000 n 
0000001125 00000 n 
0000001175 00000 n 
0000001202 00000 n 
0000001255 00000 n 
0000001282 00000 n 
0000001324 00000 n 
0000001343 00000 n 
trailer
<< /Size 26 /Root 19 0 R /Info 1 0 R /ID [ <1abd1092f1d909274c086bf0f90d6200>
<1abd1092f1d909274c086bf0f90d6200> ] >>
startxref
1507
%%EOF

/// КОНЕЦ ТЕКСТА PDF Tempfile

Если я переделываю метод exportPDFfromView: fileNumber: таким образом,

- (PDFDocument *)exportPDFfromView:(NSTextView*)textView  fileNumber:(NSUInteger)fileNumber
{
    NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
    NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
    DLog(@"poTempfileURL=%@",poTempfileURL);

    NSRect r = [textView bounds];
    NSData *data = [textView dataWithPDFInsideRect:r];
    [data writeToFile:poTempfileURL.path atomically:YES];
    PDFDocument *doc2 = [[PDFDocument alloc] initWithURL:poTempfileURL];
    DLog(@"doc2.pageCount=%lu",doc2.pageCount);

    ...

    return doc2;
}

когда я просматриваю результирующий PDF-файл по URL poTempfileURL, он имеет одну страницу, и это правильно. Но опять же, PDF не показывает текст в Preview. Если я просматриваю этот "PDF" с TextEdit, содержание ниже.

%PDF-1.3
%ƒÂÚÂÎßÛ†–ƒ∆
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
x+TÁ„
endstream
endobj
5 0 obj
11
endobj
2 0 obj
<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 576 734]
>>
endobj
6 0 obj
<< /ProcSet [ /PDF ] >>
endobj
3 0 obj
<< /Type /Pages /MediaBox [0 0 576 734] /Count 1 /Kids [ 2 0 R ] >>
endobj
7 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
8 0 obj
(Mac OS X 10.10.3 Quartz PDFContext)
endobj
9 0 obj
(D:20150517134359Z00'00')
endobj
1 0 obj
<< /Producer 8 0 R /CreationDate 9 0 R /ModDate 9 0 R >>
endobj
xref
0 10
0000000000 65535 f 
0000000493 00000 n 
0000000125 00000 n 
0000000268 00000 n 
0000000022 00000 n 
0000000107 00000 n 
0000000229 00000 n 
0000000351 00000 n 
0000000400 00000 n 
0000000452 00000 n 
trailer
<< /Size 10 /Root 7 0 R /Info 1 0 R /ID [ <d86abf98c49359ba2092ad602722f659>
<d86abf98c49359ba2092ad602722f659> ] >>
startxref
565
%%EOF

!!!!

Я нашел обходной путь, который приведет меня туда, куда я хочу пойти. Это все еще не объясняет мне, почему все мои, казалось бы, бесконечные попытки использовать

    + (NSPrintOperation *)printOperationWithView:(NSView *)aView
                               printInfo:(NSPrintInfo *)aPrintInfo

потерпеть поражение.

Обходной путь создает многостраничные файлы PDF, которые можно просматривать в режиме предварительного просмотра.

Я надеюсь, что это полезно для других.

- (void)testQuartz:(NSData *)pdfDocumentData savePath:(NSString*)savePath
{
   //Create the pdf document reference
   CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)pdfDocumentData);
   CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(dataProvider);

   //Create the pdf context
   CGPDFPageRef page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1
   CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
   CFMutableDataRef mutableData = CFDataCreateMutable(NULL, 0);

   //NSLog(@"w:%2.2f, h:%2.2f",pageRect.size.width, pageRect.size.height);
   CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData(mutableData);
   CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, NULL);


   if (CGPDFDocumentGetNumberOfPages(document) > 0)
   {
      //Draw the page onto the new context
      //page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1

      CGPDFContextBeginPage(pdfContext, NULL);
      CGContextDrawPDFPage(pdfContext, page);
      CGPDFContextEndPage(pdfContext);
   }
   else
   {
      NSLog(@"Failed to create the document");
   }

   CGContextRelease(pdfContext); //Release before writing data to disk.

   //Write to disk
   [(__bridge NSData *)mutableData writeToFile:savePath atomically:YES];

   //Clean up
   CGDataProviderRelease(dataProvider); //Release the data provider
   CGDataConsumerRelease(dataConsumer);
   CGPDFDocumentRelease(document);
   CFRelease(mutableData);
}


- (PDFDocument *)exportPDFfromView:(NSTextView*)textView  fileNumber:(NSUInteger)fileNumber
{
    NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
    NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
    DLog(@"poTempfileURL=%@",poTempfileURL);

    NSRect r = [textView bounds];
    NSData *data = [textView dataWithPDFInsideRect:r];

   [ self testQuartz:(NSData *)data savePath:poTempfileURL.path ];

    ...

    return aDoc;
}

Если вы похожи на меня и хотите опубликовать один PDF-файл, скажем, эссе, начинающийся с верхней части страницы в одном PDF-файле, вам, вероятно, понадобится что-то вроде следующего, чтобы вынуть страницы из временных входных документов и переместить их все в единый выходной PDF.

    NSUInteger pageCountDocZero = [[inputDocuments objectAtIndex:0] pageCount];
    NSUInteger pageIndex = pageCountDocZero;
    for (PDFDocument *document in inputDocuments) {
        for (NSUInteger j = 0; j < [document pageCount]; j++) {
            PDFPage *page = [document pageAtIndex:j];
            DLog(@"Inserting pageIndex:%lu i.e inputPage:%lu of %lu",pageIndex,j+1,[document pageCount]);
            [outputDocument insertPage:page atIndex:pageIndex++];
        }
    }

0 ответов

Другие вопросы по тегам