iosprintingairprint

Unwanted extra blank space when printing onto continuous roll of paper using AirPrint


I'm working on code that prints receipts onto a continuous roll of paper using a receipt printer. The receipts are similar to what you get when you pay with your credit card in a store.

I'm using UIMarkupTextPrintFormatter as you can see below in my code.

But for some reason I keep getting blank space both in the middle and at the end of the printed text. (After printing the last line, the printer keeps rolling an extra few inches of blank paper!)

I inspected the pageCount property and it returns 2, so probably this is where the extra blank space is coming from.

I have also enabled the page range to show the number of pages (for debugging). I should not be getting a page range on the controller. But I am, and it is suggesting that my content goes over 2 pages.

Could you point out where my code falls short? what is the proper way to print my HTML content onto a continuous roll of paper?

My code works perfectly on the printer simulator. I get the exact output that I'm aiming for. No unexpected blank space. But it fails on a real AirPrint compatible receipt printer!

Any suggestion is much appreciated.

UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
if(!controller){
    DDLogInfo(@"Couldn't get shared UIPrintInteractionController!");
    return;
}

UIPrintInteractionCompletionHandler completionHandler = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
    if(!completed && error)
        DDLogInfo(@"FAILED! due to error in domain %@ with error code %ld", error.domain, (long)error.code);
};

controller.showsPageRange = YES;
controller.showsPaperSelectionForLoadedPapers = YES;

//  Since the we're using a formatter, explicitly set the other properties to nil
controller.printingItem = nil;
controller.printingItems = nil;
controller.printPageRenderer = nil;


UIMarkupTextPrintFormatter *formatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:[self htmlPrintContent]];
formatter.startPage = 0;
formatter.contentInsets = UIEdgeInsetsZero;
controller.printFormatter = formatter;

// Ask for a print job object and configure its settings to tailor the print request
UIPrintInfo *info = [UIPrintInfo printInfo];

// B&W or color, normal quality output for mixed text, graphics, and images
info.outputType = UIPrintInfoOutputGrayscale;

// Select the job named this in the printer queue to cancel our print request.
info.jobName = @"somejobname";

// Make sure we are printing in a portrait orientation.
info.orientation = UIPrintInfoOrientationPortrait;

// We don't need duplex printing so set it to none explicitly
info.duplex = UIPrintInfoDuplexNone;

// Instruct the printing concierge to use our custom print job settings.
controller.printInfo = info;


// Present the standard iOS Print Panel that allows you to pick the target Printer, number of pages, etc.
[controller presentFromRect:self.printButton.frame inView:self.view animated:YES completionHandler:completionHandler];

Solution

  • I ended up switching to UISimpleTextPrintFormatter instead of UIMarkupTextPrintFormatter.

    All formatting is done using NSAttributedString

    Also implemented

    - (CGFloat)printInteractionController:(UIPrintInteractionController *)printInteractionController cutLengthForPaper:(UIPrintPaper *)paper
    

    in order to determine the height required for my text.

    CGFloat printableWidth = paper.printableRect.size.width;
    
    CGRect attributedStringBoundingRect = [attributedPrintContent boundingRectWithSize:CGSizeMake(printableWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
    
    /* Calculate the margins of the roll */
    CGFloat lengthOfMargins = paper.paperSize.height - paper.printableRect.size.height;
    
    /* The cut length is the height of the text, plus margins, plus content insets */
    CGFloat cutLength = attributedStringBoundingRect.size.height + lengthOfMargins + formatter.contentInsets.bottom + formatter.contentInsets.top;
    

    Hope this helps...