3

I want to generate dynamically in UIKit a minimal PDF page,

so sending it straight to AirPrint (no file involved),

which contains only one line of text, for example,

Hello, world

as Helvetica Neue Light 180pt.

TBC it must be actually typeset in the PDF, not rendered as an image.

Note that the code to render a bitmap is trivial and widely available .. example https://stackoverflow.com/a/6566696/294884

I've read and tried until I'm blue in the face. Can anyone do this?

PS if you're reading this and you're a Postscript programmer, I'm specifically talking about the PDF generation systems in iPad, example: https://developer.apple.com/library/mac/documentation/graphicsimaging/conceptual/drawingwithquartz2d/dq_pdf/dq_pdf.html

(I'm totally unclear whether Quartz specifically is the best way to do this - it's a nightmare.)

By the way, here's the exact code to do this with a html approach...

This example sends some dynamic html direct to AirPrint, with no files involved.

PDF is trickier

-(NSString*)_sample
  {
  NSString *r = @"<table border=0 cellpadding=0 cellspacing=0 width=100%>"
        "<tr><td align=right>"
        "<font face=courier size=1>Almost a header!</font>"
        "</tr></td></table>"
        "<br><br><br><br>"

        "<font size=4 face=sans-serif>"
        "Hello"
        "<br><br><br><br>"
        "Some <i>italics</i>."
        "<br><br><br><br>"

        "<table border=1 cellpadding=10 cellspacing=1>"
        "<tr><td align=right>one</td><td>two</td><td>three</td></tr>"
        "</table>"

        "</font>";
  return r;
  }

-(IBAction)printRawHtml:(UIView *)sender
  {
  UIPrintInfo *pif = [UIPrintInfo printInfo];
  pif.outputType = UIPrintInfoOutputGeneral;
  pif.jobName = @"Test HTML-like Job";

  UIMarkupTextPrintFormatter *formatter = [[UIMarkupTextPrintFormatter alloc]
    initWithMarkupText:[self _sample]
    ];

  formatter.startPage = 0;
  formatter.contentInsets = UIEdgeInsetsMake(10, 72.0, 72.0, 72.0);
                               //top,left,bottom,right

  UIPrintInteractionController *pic =
      [UIPrintInteractionController sharedPrintController];
  pic.delegate = self;
  pic.printInfo = pif;
  pic.printFormatter = formatter;
  pic.showsPageRange = NO;
  pic.showsNumberOfCopies = NO;

  void (^cph)(UIPrintInteractionController *, BOOL, NSError *) =
    ^(UIPrintInteractionController
          *printController, BOOL completed, NSError *error)
      {
      if (!completed && error) NSLog(@"print error %@", error);
      };

  if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    [pic presentFromRect:sender.frame
       inView:self.view animated:YES completionHandler:cph];
  else
    [pic presentAnimated:YES completionHandler:cph];
  }
Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • Why the tag [ios]? Why [postscript]? (If you want "any" solution, I could golf it in raw PostScript!) – Jongware Jun 29 '14 at 22:02
  • PS whoever added the "too broad" flag here, is incoherent. You know of "TOO MANY WAYS" TO DO THIS?! Good grief. Please do, tell me one or two :) – Fattie Jun 29 '14 at 22:30
  • The link you have shows how to open a pdf as an output device. Just use the normal Quartz text facilities (which I know nothing about) and you should be good. Assuming everything in your linked document is true (which it probably is), if you've got the PDF graphics context created, then all your drawing (and text-setting) to that context will go into the pdf. I don't know enough about that software to guarantee that your text will remain as text and not be rasterized. But it probably will, since that is the whole point of pdf. – luser droog Jun 30 '14 at 15:16
  • You may also need to embed the font in the pdf (or a subset containing just the glyphs you use). – luser droog Jun 30 '14 at 17:19

2 Answers2

2

Code from Apple's developer website

- (IBAction)savePDFFile:(id)sender
{
    // Prepare the text using a Core Text Framesetter.
    CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (CFStringRef)textView.text, NULL);
    if (currentText) {
        CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
        if (framesetter) {

            NSString *pdfFileName = [self getPDFFileName];
            // Create the PDF context using the default page size of 612 x 792.
            UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);

            CFRange currentRange = CFRangeMake(0, 0);
            NSInteger currentPage = 0;
            BOOL done = NO;

            do {
                // Mark the beginning of a new page.
                UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);

                // Draw a page number at the bottom of each page.
                currentPage++;
                [self drawPageNumber:currentPage];

                // Render the current page and update the current range to
                // point to the beginning of the next page.
                currentRange = [self renderPageWithTextRange:currentRange andFramesetter:framesetter];

                // If we're at the end of the text, exit the loop.
                if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)currentText))
                    done = YES;
            } while (!done);

            // Close the PDF context and write the contents out.
            UIGraphicsEndPDFContext();

            // Release the framewetter.
            CFRelease(framesetter);

        } else {
            NSLog(@"Could not create the framesetter needed to lay out the atrributed string.");
        }
        // Release the attributed string.
        CFRelease(currentText);
    } else {
            NSLog(@"Could not create the attributed string for the framesetter");
    }
}

Here is official documentation from Apple

https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/GeneratingPDF/GeneratingPDF.html

l0gg3r
  • 8,864
  • 3
  • 26
  • 46
1

Like @luser droog mentioned, you can use Quartz2D to generate a PDF in iOS. I've never tried myself, but you can check out this tutorial by Ray Wenderlich. His tutorial specifically goes into detail on how to programmatically create a PDF to display a simple "Hello world" string.

c_rath
  • 3,618
  • 2
  • 22
  • 14
  • Hmm - great thinking! That's a great link. It focusses on writing to a file, but maybe that's the only way... – Fattie Jul 07 '14 at 20:42
  • I believe it also goes into displaying it as well... I'm not sure what you want to do with it in the long run, but you could always look into AirPrint as well once it's displayed if you needed to do anything else with it. Or just work with that little "share" button to add it as an attachment to emails, etc. – c_rath Jul 07 '14 at 22:37
  • For sure, the whole point was to AirPrint directly - I'll clarify in the question! Again great link thanks! I just didn't think to look there – Fattie Jul 08 '14 at 07:56