2

Using NSPrintOperation, How Do I correctly Create a PDF file from text in an NSView?


* * NOTICE I FOUND A WORKAROUND, WHICH IS SHOWN AT THE BOTTOM *


What I have done: 1. Put text into an 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.Try to Create a PDF file from the TextView's Text using the method below:

- (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. Run the following code :

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

The Getter follows:

- (NSURL *)tempDirectoryURL { //getter
    NSURL *tempURL;
    if(!_tempDirectoryURL){
        tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]] isDirectory:YES];
        _tempDirectoryURL = tempURL;
    }
    return _tempDirectoryURL;
}   
  1. After running this code:

    BOOL didRunOK = [printOp runOperation];//7

    BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[poTempfileURL path]]; DLog(@"didRunOK=%lu\nfileExists=%lu",didRunOK,exists); DLog(@"poTempfileURL=%@",poTempfileURL);

I expect a PDF to be created at: poTempfileURL where it value is: 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

console shows:

 didRunOK=1
 fileExists=1
  1. When the following line of code runs:

    BOOL didRunOK = [printOp runOperation];//7

The contents of printInfo for the printOp are:

{
    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;
}

In Xcode : po [[textView textStorage] string] produces the text below labeled :

 /// BEGIN NSTextView TEXT ///

In Finder when I open the file located at poTempFileURL, in Preview, the file has four pages (it should have only one page), and appears to be an empty PDF file in Preview.

When I open this same "PDF" file in TextEdit, the file contains the content below which is labelled : /// BEGIN TEXT PDF Tempfile ///

What do I need to do to produce a "proper" PDF file? I can not get a PDF that I can open and read in Preview.

po [doc pageCount] shows "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.

/// END NSTextView TEXT ///

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

/// END TEXT PDF Tempfile

If I redo the method exportPDFfromView: fileNumber: this way,

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

when I view the resultant PDF file at URL poTempfileURL, it has one page, which is correct. But again the PDF shows no text in Preview. If I view this "PDF" with TextEdit, the contents are below.

%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

! ! ! !

I have found a workaround that will get me where I want to go. This still does not explain to me why all my seemingly endless attempts to use

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

fail.

The workaround produces multipage PDF files that can be viewed in Preview.

I do hope this is useful to others.

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

If you are like me and want to publish a single PDF, with say essays, all beginning at the top of a page in the single PDF, you will probably want something like the following to take pages out of temporary input documents and move them all into the single output 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++];
        }
    }
mbarron
  • 285
  • 4
  • 15

0 Answers0