Reputation: 3873
TLDR: If you print UIWebView
which contains HTML
content consisting of elements with text aligned right
/ center
, resulting document will have pages with unexpectedly large bottom margins.
I came across this issue, and was quite surprised when I could not google anyone with similar problem. I have filed a radar with apple (#20760071) and also created an issue on ResearchKit
's GitHub repo, as this affects their ORKHTMLPDFWriter
.
AFAIK this also affects all libraries that use UIWebView
for converting HTML
to PDF
, I have tested:
I am wondering if anyone can come up with some workaround.
How to reproduce:
NSMutableString* html = [NSMutableString string];
[html appendString:@"<html><body>"];
for (int i=0; i<200; i++) {
[html appendString:@"<div align=\"right\">line</div>"];
}
[html appendString:@"</body></html>"];
UIPrintInteractionController* pc = [UIPrintInteractionController sharedPrintController];
UIPrintInfo* printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGrayscale;
pc.printInfo = printInfo;
pc.showsPaperSelectionForLoadedPapers = YES;
UIWebView* web = [UIWebView new];
[web loadHTMLString:html baseURL:nil];
pc.printFormatter = web.viewPrintFormatter;
[pc presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
NSLog(@"%d -- %@",completed, error);
}];
You can also clone the project demonstrating this issue in ResearchKit
.
Knowing specific width of the content (e.g. images), one can align it without specifying text alignment, e.g:
Using automatic margins:
<div>
<div style="width:200px; margin-left:auto; margin-right:0px;">
content
</div>
</div>
Floating columns:
<div>
<div style="width:200px; float:right;">
content
</div>
</div>
However, none of the above works for aligning variable length text, which is the main use case I am concerned with.
Upvotes: 14
Views: 1661
Reputation: 16
My solution to text-align:right
<header>
<style type="text/css">
.default-text-align-right {
text-align: right;
}
.alternative-text-align-right {
position: absolute;
right: 10px;
}
</style>
</header>
<body>
<div>
<div class="default-text-align-right">
Default Text Align Left
</div>
<div>
<div class="alternative-text-align-right">Alternative Text Align Right</div>
<div> </div>
</div>
<div class="default-text-align-right">
Default Text Align Left
</div>
</div>
</body>
Upvotes: 0
Reputation: 56
Vano,
The solution that I came up with after some testing is adding the following css rules with the text align.
display: -webkit-box;
display: -webkit-flex;
display: flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
text-align:right;
Upvotes: 4
Reputation: 1443
I imagine that wouldn't work with aligning variable length text, because the length of the text, obviously, is constantly changing, where your workaround's div
attribute has a static width
attribute.
This is a job for a string replacement, replacing the divider's width
with the paper's size (to allow the margins to fill with text). To get this width, call this:
pc.printPaper.printRect.size.width;
But, in order to replace it, you need to have a delegate there to fix up the HTML code right before the job starts.
Have your delegate be a new class object from type NSObject
as a subclass in Xcode's File Creator, and then have your function to fire the printer and render the content be similar to this in your view:
NSMutableString* html = [NSMutableString string];
[html appendString:@"<html><body>"];
for (int i=0; i<200; i++) {
[html appendString:@"temporary content... "];
}
[html appendString:@"</body></html>"];
UIWebView* web = [UIWebView new];
[web loadHTMLString:html baseURL:nil];
UIPrintInteractionController* pc = [UIPrintInteractionController sharedPrintController];
pc.printFormatter = web.viewPrintFormatter;
UIPrintInfo* printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGrayscale;
printerDelegate* pd = [printerDelegate new];
pc.printInfo = printInfo;
pc.showsPaperSelectionForLoadedPapers = YES;
pc.delegate = pd;
[pc presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
NSLog(@"%d -- %@",completed, error);
}];
(Note: I made temporary content in the HTML file for a reason. I'm not done yet!)
In the delegate class I asked you to make before, make this the .h
file:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface printerDelegate : NSObject <UIPrintInteractionControllerDelegate>
@end
Then, in it's .m
file, I have this...
#import "printerDelegate.h"
#import <UIKit/UIKit.h>
@implementation printerDelegate
-(void)printInteractionControllerWillDismissPrinterOptions:(UIPrintInteractionController *)printInteractionController {
@try {
NSMutableString* html = [NSMutableString string];
[html appendString:@"<html><body>"];
for (int i=0; i<200; i++) {
[html appendString:[NSString stringWithFormat:@"<div><div style=""width:%fpx; margin-left:auto; margin-right:0px;"">content</div></div>", printInteractionController.printPaper.printRect.size.width]];
}
[html appendString:@"</body></html>"];
UIWebView* web = [UIWebView new];
[web loadHTMLString:html baseURL:nil];
printInteractionController.printFormatter = web.viewPrintFormatter;
}
@catch (NSException *exception) {
NSLog(@"%@", exception.debugDescription);
}
@finally {
}
}
@end
It returns a bad access exception, but you get the gist: after the user selects their type of paper, set the divider's width
to be the width of the printing area. The only other option would be to either have a specified width (like you suggested in your edit) or have one specific type paper the user can print from.
The reason why this happens is because of a bug in printing the HTML of a UIWebView
, not because of coding. Hopefully Apple fixes this in a later update.
Upvotes: -1