Programmatically Generate PDF from HTML on iPhone - iphone

I am looking for a way to programmatically (in obj-c) generate a PDF file from a local html file. I am dynamically generating the html from user inputs, I need to create the PDF and send it to the user (via email). I am having difficulty with the PDF generation portion.
I have the code to create a PDF using CGPDFContextCreateWithURL but I am struggling with drawing the page using quartz.
I have searched extensively on SO as well as the internet to no avail.
Any help is much appreciated!

To generate a pdf from an HTML, you need to render the html into a web view, and take snapshots of the web view, and render them into an image context.
The tutorial might be helpful:
http://www.ioslearner.com/convert-html-uiwebview-pdf-iphone-ipad/

I've written a little piece of code that takes an NSAttributedString from DTCoreText, and renders it into a paged PDF file. You can find it on my GitHub Repository. It won't render images or complex html, but it should serve for most uses. Plus, if you're familiar with CoreText, you can extend my PDF frame setter to generate these items.
So what it does now: Give it an HTML string, and it will use DTCoreText to generate an NSAttributedString, then render that into a PDF. It hands back the location that it saved the PDF file in the app's Documents folder.

Why not use a WebService, send the HTML page to this and retrieve the PDF-file ?
That way you can use iTextSharp and C#, and you're done in about 2 minutes.
Plus (if you're evil) you can store and see all the data on your server.

I haven't tried this myself so i have nothing to offer concrete but I'd have to imagine there has to be an easy way to do this on iPhone due to the imaging model. I'd look deeper into the documentation.
As to pushing back with the client that is up to you but there are probably multiple reasons for wanting to keep everything local. Frankly I would not be pleased at all to here from somebody I hired that he couldn't manage this particular task. So think long and hard about this push back. Oh even if you do push back a webserver is a poor choice. I'd go back a step further and investgate why you need something in HTML in the first place.

I've never tried this so I have no idea if it'll work, but how about loading the HTML into a UIWebView, and then make the view draw itself into a PDF context? E.g.
UIWebView *webview = [[UIWebView alloc] initWithFrame:CGRectMake(...)];
[webview loadHTMLString:html baseURL:...];
Then:
- (void)webViewDidFinishLoad:(UIWebView *)webview {
CGPDFContextRef pdfContext = CGPDFContextCreateWithURL(...);
[webview.layer drawInContext:pdfContext];
...
}

I made it by following this SO: https://stackoverflow.com/a/13342906/448717
In order to maintain the same content's proportions I had to multiply the size of the WKWebView 1.25 times the printableRect's size set for the UIPrinterRenderer, as the screen points differs from the PostScript's... I guess.

Related

Rendering Images inside PDF, images not being rendered in PDF Viewer 0.1.8

Please check updates as they have additional informations... Apparently located the problem in a specific pdf client but cannot close the issue with an open bounty...
I am generating a pdf using grails rendering plugin. The PDF has a couple of images inside and "some" of them are not being outputted!
I am rendering the images inline via data uris as required by the plugin. That means that all my images are something like:
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQECWAJYAAD...">
If I render them in a normal html view, I can see the images just fine!
If I render the template to a JPG/PNG with the same plugin, again the images render all fine.
If I render to PDF the images which are being retrieved by an octed-stream are broken!
Something like:
Looks like the image started to render and then something happened...
It is happening on the big-sized images, but also on the thumbnail version of same image.
Any one has some hints as why this might occur?
UPDATE
The file which does not show up is a file with mime application/octet-stream
So apparently I can retrieve the bytes from the file, but when they transmitted for PDF Rendering, the image does not appear...
Yet another update
The issue seems to be related with the PDF Viewer. Was using a Linux based PDF Viewer (PDF Viewer 0.1.8) and specific images are broken. In all other PDF Viewers I could test everything works fine.
Cannot close the issue as there is a bounty open :( Sorry that the bounty and question seems meaningless now, but you never know, someone might have an idea how to solve this even for PDF Viewer 0.1.8.
<img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQECWAJYAAD...">
works fine for me. Note the missing "e".
You can use rendering tag:
<rendering:inlineJpeg bytes="${your-image}" />
Make sure you decodeBase64() your image.

How to parse HTML to PlainText while maintaining paragraph formatting

I have an iOS app that is pulling data from a Restful web service. A portion of the content I am receiving is being loaded into a UITextView. The portion that will be going into the text view is coming in as HTML format. I need to convert it from HTML to plain text while using the paragraph tags to format the text view properly.
Here is what the HTML format looks like
<p data-seq="1"><span class="paragraph">Content of paragraph 1</span></p><p data-seq="2"><span class="paragraph">Content of paragraph 2</span></p>
You can see that <p data-seq="2"><span class="paragraph">....</span></p> designates the start and end of the paragraph.
I initially tried using NSScanner from this example, How to convert NSString HTML markup to plain text NSString?. This was quick to implement but it strips all tags and and parses the text as one long paragraph.
I have added libXml2 to my code. I started following this tutorial for implementation but after I started working through it I wasn't sure how to format the output into paragraphs.
I have also seen recommendations for the DTCoreText library but I didn't see a lot of info on it.
Could someone possibly throw up a snippet using any of the above three options or one of their own on how to parse html into plain text while maintaining the paragraphs?
SOLUTION
Per lxt's recommendation I investigated DTCoreText. Once I managed to get it installed in my app (definitely recommend cocoa pods for that). It was easy as #import "DTCoreText.h" in my detailViewController and then the lines below to add it to the UITextView.
NSDictionary *options = #{DTUseiOS6Attributes: [NSNumber numberWithBool:YES]};
NSData *htmlData = [self.htmlString dataUsingEncoding:NSUTF8StringEncoding];
NSAttributedString *stringArticle = [[NSAttributedString alloc] initWithHTMLData:htmlData options:options documentAttributes:NULL];
self.newsDetailText.attributedText = stringArticle;
The first build failed because I didn't include the DTUseiOS6Attributes line. The second build succeeded and the detail view was perfectly formatted. It was a fist pump moment! Thanks again for the recommendation lxt!
I would honestly recommend using DTCoreText rather than writing your own parser. There's no real benefit reinventing the wheel, and it's also a widely used library with a large user base.
I am surprised you had trouble finding info about it, the library has very good documentation available, and the author is also pretty active on Twitter (#cocoanetics).
You can use the nifty DTAttributedTextView class provided in place of your UITextView. The library also provides a category that extends NSAttributedString with a initWithHTMLData:documentAttributes: method. This will let you create your attributed string and plug it into your view. It's really no more than a couple of lines of code.

UIView to Editable PDF. Possible?

I am trying to convert a UIView to pdf (iOS). I managed to do it by using renderInContext. However, it captures the whole UIView as an "image" which is not really what I want. The questions and answers I found on stackoverflow gives me the same result of using the renderInContext.
I want to convert the whole UIView (with my textfields etc.) to editable pdf. Which means the pdf file after converting still enables the user to edit what was already written in the textfields in the pdf (the pdf file will be sent to email and edited in the computer).
Is this possible? If so, how can I go about doing this?

text and image as one scrollable entity

I need an undefined amount of text and one or more pictures to be scrollable as one entity. I'm quite surprised that this doesn't seem to be provided by default, I thought I've seen that several times before... I tried to google, but all I find doesn't fit. The images won't be wider than the screen, but in between lines of text.
I need something that let's me do something like:
image
textA
textA goes on
__ screen ends here, content goes on
textA goes on
textA goes on
image
image
textB
textB goes on
image
textC
The content for the text would come out of a plist, but I THINK I can predict it will be REALLY static, so I could just set the Text in IB and create a view for every content -.-.
I've read about Web View, but as far as I got it, you'd need internet connection to make that work, and the app should work without any internet connection at all.
Any suggestions or experiences concerning that?
Thanks a lot!
There different way to get things done:
If you have static content and want a complicated layout and know how to do it in html you should go with UIWebview and a bundled html file and images and load it with something like:[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"MyStuff" ofType:#"html"]]]];
You can also do a layout with UILabels and UIImageviews and arrange all of this onto one UIScrollview
If it's more dynamic you should go with the latter, but you need to program sort of layout algorithms that handle different number/sizes of images, number/length of test paragraphs and so on.
One option, as you mention, is UIWebView.
It does not require a connection, since you can load a static HTML into it executing:
– loadHTMLString:baseURL:
By specifying a baseURL that "points" to your bundle, you can also include images as resources in your Xcode project and have them displayed (by using <img src=... /img in your HTML):
NSString* basePath = [[NSBundle mainBundle] bundlePath];
[_label loadHTMLString:text baseURL:[NSURL fileURLWithPath:basePath]];
You don't need an internet connection to make a web view work. Look at this method on UIWebView:
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL

How to get rid from question mark in a blue square in UIWebView?

In my iPhone application I'm parsing RSS feed to get html and keep it. Afterwards I display this html in UIWebView. The problem is that html contains urls of images, if there is network connection everything is ok, UIWebView loads and displays these images, but if there is no connection it shows text but in place of images shows frame with blue square inside
How can I get rid of it?
Thank you
Check programmatically to make sure that you have an internet connection.
See this question and its accepted answer on how to do that.
If you don't have an internet connection, then you have a couple of options. You can either:
Parse through your html, replace the <img> tags with blanks (this will completely get rid of the images and their associated blue question mark boxes.
Parse through your html, replace the src part of <img src="somewebsite"> with a reference to an image placeholder in the project bundle.
XPath is your friend when it comes to parsing html. Although if you wanted to, you could do all of this with NSSTring.