title: Using Cocoa, NSPrintOperation, How Do I correctly Create a PDF file from text in an NSView?
body: <p>Using NSPrintOperation, How Do I correctly Create a PDF file from text in an NSView?</p>
  
  <hr>
  
  <p>*
  * NOTICE I FOUND A WORKAROUND, WHICH IS SHOWN AT THE BOTTOM
  *</p>
  
  <hr>
  
  <p>What I have done: 
  1. Put text into an NSTextView. </p>
  
  <pre><code>- (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
  </code></pre>
  
  <p>2.Try to Create a PDF file from the TextView's Text using the method below:</p>
  
  <pre><code>- (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;
  }
  </code></pre>
  
  <ol start="3">
  <li><p>Run the following code :</p>
  
  <pre><code>[self tempDirectoryURL];// invoke getter
  NSLog(@"_tempDirectoryURL=%@",_tempDirectoryURL);
  
  _tempDirectoryURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/ 
  </code></pre></li>
  </ol>
  
  <p>The Getter follows:</p>
  
  <pre><code>- (NSURL *)tempDirectoryURL { //getter
      NSURL *tempURL;
      if(!_tempDirectoryURL){
          tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]] isDirectory:YES];
          _tempDirectoryURL = tempURL;
      }
      return _tempDirectoryURL;
  }   
  </code></pre>
  
  <ol start="4">
  <li><p>After running this code:</p>
  
  <p>BOOL didRunOK = [printOp runOperation];//7</p>
  
  <p>BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[poTempfileURL path]];
   DLog(@"didRunOK=%lu\nfileExists=%lu",didRunOK,exists);
   DLog(@"poTempfileURL=%@",poTempfileURL);</p></li>
  </ol>
  
  <p>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</p>
  
  <p>console shows:</p>
  
  <pre><code> didRunOK=1
   fileExists=1
  </code></pre>
  
  <ol start="5">
  <li><p>When the following line of code runs:</p>
  
  <p>BOOL didRunOK = [printOp runOperation];//7</p></li>
  </ol>
  
  <p>The contents of printInfo for the printOp are:</p>
  
  <pre><code>{
      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;
  }
  </code></pre>
  
  <p>In Xcode : po [[textView textStorage] string] produces the text below labeled : </p>
  
  <pre><code> /// BEGIN NSTextView TEXT ///
  </code></pre>
  
  <p>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.</p>
  
  <p>When I open this same "PDF" file in TextEdit, the file contains the 
     content below which is labelled :  /// BEGIN TEXT PDF Tempfile ///</p>
  
  <p>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.</p>
  
  <p>po [doc pageCount] shows "4"</p>
  
  <p>/// BEGIN NSTextView TEXT ///  - po [[textView textStorage] string]</p>
  
  <pre><code>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.
  </code></pre>
  
  <p>/// END  NSTextView TEXT ///</p>
  
  <p>/// BEGIN TEXT PDF Tempfile ///</p>
  
  <pre><code>%PDF-1.3
  %ƒÂÚÂÎßÛ†–ƒ∆
  4 0 obj
  &lt;&lt; /Length 5 0 R /Filter /FlateDecode &gt;&gt;
  stream
  x+T�Á�„
  endstream
  endobj
  5 0 obj
  11
  endobj
  2 0 obj
  &lt;&lt; /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792]
  &gt;&gt;
  endobj
  6 0 obj
  &lt;&lt; /ProcSet [ /PDF ] &gt;&gt;
  endobj
  8 0 obj
  &lt;&lt; /Length 9 0 R /Filter /FlateDecode &gt;&gt;
  stream
  x+T�Á�„
  endstream
  endobj
  9 0 obj
  11
  endobj
  7 0 obj
  &lt;&lt; /Type /Page /Parent 3 0 R /Resources 10 0 R /Contents 8 0 R /MediaBox [0 0 612 792]
  &gt;&gt;
  endobj
  10 0 obj
  &lt;&lt; /ProcSet [ /PDF ] &gt;&gt;
  endobj
  12 0 obj
  &lt;&lt; /Length 13 0 R /Filter /FlateDecode &gt;&gt;
  stream
  x+T�Á�„
  endstream
  endobj
  13 0 obj
  11
  endobj
  11 0 obj
  &lt;&lt; /Type /Page /Parent 3 0 R /Resources 14 0 R /Contents 12 0 R /MediaBox
  [0 0 612 792] &gt;&gt;
  endobj
  14 0 obj
  &lt;&lt; /ProcSet [ /PDF ] &gt;&gt;
  endobj
  16 0 obj
  &lt;&lt; /Length 17 0 R /Filter /FlateDecode &gt;&gt;
  stream
  x+T�Á�„
  endstream
  endobj
  17 0 obj
  11
  endobj
  15 0 obj
  &lt;&lt; /Type /Page /Parent 3 0 R /Resources 18 0 R /Contents 16 0 R /MediaBox
  [0 0 612 792] &gt;&gt;
  endobj
  18 0 obj
  &lt;&lt; /ProcSet [ /PDF ] &gt;&gt;
  endobj
  3 0 obj
  &lt;&lt; /Type /Pages /MediaBox [0 0 612 792] /Count 4 /Kids [ 2 0 R 7 0 R 11 0 R
  15 0 R ] &gt;&gt;
  endobj
  19 0 obj
  &lt;&lt; /Type /Catalog /Pages 3 0 R &gt;&gt;
  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
  &lt;&lt; /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 &gt;&gt;
  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
  &lt;&lt; /Size 26 /Root 19 0 R /Info 1 0 R /ID [ &lt;1abd1092f1d909274c086bf0f90d6200&gt;
  &lt;1abd1092f1d909274c086bf0f90d6200&gt; ] &gt;&gt;
  startxref
  1507
  %%EOF
  </code></pre>
  
  <p>/// END  TEXT PDF Tempfile</p>
  
  <p>If I redo the method exportPDFfromView: fileNumber: this way,</p>
  
  <pre><code>- (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;
  }
  </code></pre>
  
  <p>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.</p>
  
  <pre><code>%PDF-1.3
  %ƒÂÚÂÎßÛ†–ƒ∆
  4 0 obj
  &lt;&lt; /Length 5 0 R /Filter /FlateDecode &gt;&gt;
  stream
  x+TÁ„
  endstream
  endobj
  5 0 obj
  11
  endobj
  2 0 obj
  &lt;&lt; /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 576 734]
  &gt;&gt;
  endobj
  6 0 obj
  &lt;&lt; /ProcSet [ /PDF ] &gt;&gt;
  endobj
  3 0 obj
  &lt;&lt; /Type /Pages /MediaBox [0 0 576 734] /Count 1 /Kids [ 2 0 R ] &gt;&gt;
  endobj
  7 0 obj
  &lt;&lt; /Type /Catalog /Pages 3 0 R &gt;&gt;
  endobj
  8 0 obj
  (Mac OS X 10.10.3 Quartz PDFContext)
  endobj
  9 0 obj
  (D:20150517134359Z00'00')
  endobj
  1 0 obj
  &lt;&lt; /Producer 8 0 R /CreationDate 9 0 R /ModDate 9 0 R &gt;&gt;
  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
  &lt;&lt; /Size 10 /Root 7 0 R /Info 1 0 R /ID [ &lt;d86abf98c49359ba2092ad602722f659&gt;
  &lt;d86abf98c49359ba2092ad602722f659&gt; ] &gt;&gt;
  startxref
  565
  %%EOF
  </code></pre>
  
  <p>! ! ! !</p>
  
  <p>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</p>
  
  <pre><code>    + (NSPrintOperation *)printOperationWithView:(NSView *)aView
                                 printInfo:(NSPrintInfo *)aPrintInfo
  </code></pre>
  
  <p>fail. </p>
  
  <p>The workaround produces multipage PDF files that can be viewed in Preview.</p>
  
  <p>I do hope this is useful to others.</p>
  
  <pre><code>- (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, &amp;pageRect, NULL);
  
  
     if (CGPDFDocumentGetNumberOfPages(document) &gt; 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;
  }
  </code></pre>
  
  <p>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.</p>
  
  <pre><code>    NSUInteger pageCountDocZero = [[inputDocuments objectAtIndex:0] pageCount];
      NSUInteger pageIndex = pageCountDocZero;
      for (PDFDocument *document in inputDocuments) {
          for (NSUInteger j = 0; j &lt; [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++];
          }
      }
  </code></pre>