2

使用 NSPrintOperation,如何正确地从 NSView 中的文本创建 PDF 文件?


* * 通知我找到了一种解决方法,显示在底部 *


我所做的: 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.尝试使用以下方法从TextView的文本创建一个PDF文件:

- (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=%lu\nfileExists=%lu",didRunOK,exists); DLog(@"poTempfileURL=%@",poTempfileURL);

我希望在以下位置创建一个 PDF:poTempfileURL,其值为:poTempfileURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/884B9B4C-907B-489E-869B-B5EFE7A11B47-1821- 000016435C134E56/7A196040-0D81-496D-B9F3-BF0B855F6BBC-1821-0000164A9446040F_file_0.pdf

控制台显示:

 didRunOK=1
 fileExists=1
  1. 当以下代码行运行时:

    BOOL didRunOK = [printOp runOperation];//7

printOp 的 printInfo 的内容是:

{
    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 文件。

当我在 TextEdit 中打开同一个“PDF”文件时,该文件包含以下标记的内容:/// BEGIN TEXT PDF Tempfile ///

我需要做什么才能生成“正确”的 PDF 文件?我无法获得可以在预览中打开和阅读的 PDF。

po [doc pageCount] 显示“4”

/// BEGIN 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 文本 ///

/// 开始文本 PDF 临时文件 ///

%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 临时文件

如果我重做方法 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;
}

当我在 URL poTempfileURL 查看生成的 PDF 文件时,它只有一页,这是正确的。但是 PDF 再次在预览中显示没有文本。如果我用 TextEdit 查看这个“PDF”,内容如下。

%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++];
        }
    }
4

0 回答 0