Rendering a Uiview into a PDF as Vectors on an iPad - Sometimes Renders as Bitmap, Sometimes as Vectors

Rendering a UIView into a PDF as vectors on an iPad - Sometimes renders as bitmap, sometimes as vectors

The only way I found to make it so labels are rendered vectorized is to use a subclass of UILabel with the following method:

/** Overriding this CALayer delegate method is the magic that allows us to draw a vector version of the label into the layer instead of the default unscalable ugly bitmap */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());
if (!layer.shouldRasterize && isPDF)
[self drawRect:self.bounds]; // draw unrasterized
else
[super drawLayer:layer inContext:ctx];
}

Swift 5.x:

override func draw(_ layer: CALayer, in ctx: CGContext) {
let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty

if !self.layer.shouldRasterize && isPDF {
self.draw(self.bounds)
} else {
super.draw(layer, in: ctx)
}
}

That does the trick for me: labels are unrasterized and selectable in the resulting PDF view, and behave normally when rendered to the screen.

iOS - How to add text on top of PDF Document?

There are two possible scenarios here:

Editing existing PDF text is very difficult, even with something like PSPDFKit. It is no accident that there are no PDF-based word processors.

Annotating PDF content is more straightforward:

Add any additional content as subviews to the UIView that contains the PDF document. Additional content can be in the form of text, vectors or images - anything that can be added to a UIView. At this point you do not need to worry whether the added content is "part of" the PDF.

When you want to render the added content to the PDF, simply render the container view (which contains both the original document and annotations) to a PDF Context using UIGraphicsBeginPDFContextToFile and UIGraphicsBeginPDFPage.

Check this question and answer for a simple example and a method for ensuring that the PDF is rendered as vectors, not as a bitmap: Rendering a UIView into a PDF as vectors on an iPad - Sometimes renders as bitmap, sometimes as vectors

How can I avoid using CATiledLayer when rendering a PDF?

CATiledLayer is necessary either by itself or as a backing layer for a UIView when you are attempting to display a view or layer that exceeds the maximum texture size supported by the GPU. Apple lists this as 1024x1024 for the iPhone, but in my experience I've been able to go up to 2048x2048 on even the first-generation iPhone.

If you are able to render to a view or layer that is smaller in both width and height than those dimensions, you don't need to use a CATiledLayer and can get away with a standard layer. The tiling process does slow rendering a bit as it brings in the appropriate tiles, so you could gain some performance that way.

For a discussion on general PDF rendering performance, I direct you to this question:

Fast and Lean PDF Viewer for iPhone / iPad / iOs - tips and hints?

iOS - Creating multi page PDF from HTML content

I created a class based on every good advice I found around. I've been digging a lot and I hope my class will offer some good start for anyone trying to create multi-page PDF directly out of some HTML source.

You'll find the whole code here with some basic sample code : https://github.com/iclems/iOS-htmltopdf

I had just the same issue as you and my requirements were:
- full PDF (real text, no bitmap)
- smart multi-pages (compared to cutting a full height webview every X pixels...)

Thus, the solution I use is pretty nice as it resorts to the same tools iOS uses to split pages for print.

Let me explain, I setup a UIPrintPageRenderer based on the web view print formatter (first tip) :

UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];

[render addPrintFormatter:webView.viewPrintFormatter startingAtPageAtIndex:0];

CGRect printableRect = CGRectMake(self.pageMargins.left,
self.pageMargins.top,
self.pageSize.width - self.pageMargins.left - self.pageMargins.right,
self.pageSize.height - self.pageMargins.top - self.pageMargins.bottom);

CGRect paperRect = CGRectMake(0, 0, self.pageSize.width, self.pageSize.height);

[render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];

NSData *pdfData = [render printToPDF];

[pdfData writeToFile: self.PDFpath atomically: YES];

In the meantime, I have created a category on UIPrintPageRenderer to support:

-(NSData*) printToPDF
{
[self doNotRasterizeSubviews:self.view];

NSMutableData *pdfData = [NSMutableData data];

UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );

[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];

CGRect bounds = UIGraphicsGetPDFContextBounds();

for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();

[self drawPageAtIndex: i inRect: bounds];
}

UIGraphicsEndPDFContext();

return pdfData;
}


Related Topics



Leave a reply



Submit