0

I'm working on a graphics app for Mac OS in Swift and want to have a professional WYSIWYG layout features for printing.

I've isolated a weird behavior of the Cocoa printing system and just wondered if anyone knows of a setup step I'm missing or a workaround. The issue is that the "Any" printer has irregular, non-centered margins even when horizontal+vertical centering is requested. In particular, the left margin of my landscape letter-size docuemnt is 18pt and the right margin is 40pt - bigger than 1/2", which I feel is an unacceptable contraint, not to mention the annoyance of not being able to rely on the requested centering.

My app is NSDocument-based and I set printInfo margins to 0, centered fields to true, and orientation to .landscape.

self.printInfo.topMargin = 0.0
self.printInfo.rightMargin = 0.0
self.printInfo.leftMargin = 0.0
self.printInfo.bottomMargin = 0.0
self.printInfo.isHorizontallyCentered = true
self.printInfo.isVerticallyCentered = true
self.printInfo.orientation = .landscape

let newPrintOp = NSPrintOperation(view: self.printView!, printInfo: self.printInfo)
newPrintOp.showsPrintPanel = true        
return newPrintOp

I am using Page Setup in this test. I have an EPSON printer that gives me the choice of regular or borderless printing, and with either option, selecting US Letter landscape, I get reasonable imageablePageBounds reported to draw into.

With the borderless page setup, I get

... imageablePageBounds: (0.0, 0.0, 792.0, 612.0)

and with 'regular' letter/landscape I get

... imageablePageBounds: (8.4000244140625, 8.399999618530273, 775.199951171875, 595.1999759674072)

The latter is setting to some driver minimum, but if you double the 8.4 point offsets and add to height and width you still get 792x612 == 11in x 8.5in

If instead I select "Any" printer in Page Setup and select US Letter, landscape, imageablePageBounds is reported (and enforced, even when printing to PDF) as: ... imageablePageBounds: (18.0, 18.0, 734.0, 576.0)

This gives 1/4" (18-pt) margins left, bottom, and top, but forces a 40-pt margin to the right (since width is only 734 - it should be 756 for a 10.5" drawing area). And indeed, if I try to draw an 10-inch image centered with 36pt margins, the right edge very annoyingly gets clipped unless I scale or shift it. It even gets clipped off with PDF output with this setup. Here's an image in the print panel that shows this clipping - the outer black line is the imageable view bounds given by the printing system, the blue line (right edge cut off) is a centered 10 x 7.5 image.

Screenshot of printing panel with issue

Does anyone know if there's a fix for this weird behavior? The ideal fix would be to get a reasonable 1/4" border as a default for anything I'm trying to print, but even if I can't get the max default width above 734pt I still want it to be centered so that I can at least work within 1/2" margins without any clipping.

Corbell
  • 1,283
  • 8
  • 15
  • A printer can have different top and bottom margins due to mechanical limitations. Any printer means every possible printer, including outdated printers with big margins. Fix: don't use (the margins of) Any Printer. – Willeke Jan 13 '20 at 08:50
  • I'm not sure this comment offers any insight - my code requesting 0 margins (and doing my own margin calculations) but the issue is that the system returns a printer-controlled page bounds with margins anyway. So your coordinate drawing automatically starts with the origin offset by the system's reported printer margins, and is clipped to them. Do you have an actual way to 'not use' the margins enforced by the Cocoa printing system, which clip your printing view's drawing even when printing to PDF in this case? – Corbell Jan 14 '20 at 08:24
  • Apparently I didn't understand the question. Is the question How to print in the margins, even if the printer can't do it? – Willeke Jan 14 '20 at 09:30
  • 1
    The question is why this particular setup with Cocoa printing, requesting 0 margins and a centered document, returns non-centered margins with one margin over 1/2", and whether there is any workaround. Note that the "Any" printer configuration is provided by the OS, can be selected by the user in Page Setup, and there is at least one perfectly valid use case for supporting it (permitting a machine with no attached printer to print output to PDF). – Corbell Jan 14 '20 at 17:14
  • Addendum, one can of course simply scale content to fit in the irregular margins, but that's accepting the problem and producing output the user almost certainly doesn't want (they will want WYSIWYG), rather than finding a workaround e.g. a way to get uniform centered margins (18pt or whatever is a reasonable default) from the "Any" printer configuration. – Corbell Jan 14 '20 at 17:18

3 Answers3

0

While the original behavior does seem like a bug, it appears that setting printInfo.paperSize field may provide a partial workaround, as long as the Mac has an installed printer available.

In addition to my other setup, if I add the line

self.printInfo.paperSize = CGSize(width: 792.0, height: 612.0)

for my US-Letter landscape document, and still use Page Setup to set printer "Any" and letter/landscape, when the print job actually runs it now shows up having selected the driver from the EPSON driver rather than leaving the buggy "Any" driver's margins - the result is nicely centered with minimal margins as desired.

enter image description here

I tested on a MacBook Pro with no printer set up, and this workaround did not correct the issue - it still shows up with off-center margin and clips the drawing. So the workaround requires some actual printer to be installed.

I've filed a bug via Apple's feedback assistant, will post an update if anything more is discovered or resolved.

Corbell
  • 1,283
  • 8
  • 15
0

Here's my test app, it prints the view on one page without margins, maybe it helps:

Document.swift

override func windowControllerDidLoadNib(_ windowController: NSWindowController) {
    let newPrintInfo = NSPrintInfo()
    newPrintInfo.leftMargin = 0.0
    newPrintInfo.bottomMargin = 0.0
    newPrintInfo.rightMargin = 0.0
    newPrintInfo.topMargin = 0.0
    newPrintInfo.horizontalPagination = .clip
    newPrintInfo.verticalPagination = .clip
    self.printInfo = newPrintInfo
}

override var printInfo: NSPrintInfo {
    didSet {
        view.printInfoChanged(printInfo)
    }
}

override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation {
    return NSPrintOperation(view: view, printInfo: printInfo)
}

MyView.swift

func printInfoChanged(_ newPrintInfo: NSPrintInfo) {
    setFrameSize(newPrintInfo.paperSize)
}

override func locationOfPrintRect(_ rect: NSRect) -> NSPoint {
    return NSZeroPoint
}

override func knowsPageRange(_ range: NSRangePointer) -> Bool {
    range.pointee.location = 1
    range.pointee.length = 1
    return true
}

override func rectForPage(_ page: Int) -> NSRect {
    return bounds
}

override func draw(_ dirtyRect: NSRect) {
    super.draw(dirtyRect)
    NSColor.green.set()
    NSBezierPath(rect:bounds).stroke()
    NSColor.red.set()
    NSBezierPath(ovalIn:bounds).stroke()
}
Willeke
  • 14,578
  • 4
  • 19
  • 47
  • I don't see any actual drawing code here in MyView so it's impossible to verify whether or not this ends up getting clipped to a 40pt left margin per the original bug. Is your test app actually drawing anything to verify the bug doesn't happen with the 'Any' printer selected, when no specific printer is installed on the host system? – Corbell Jan 24 '20 at 21:09
0

We have worked on this problem for days and weeks with no good answer. We finally filed a DTS report with Apple and sent a simple app that clearly demonstrates the problem with margins. After a week of back and forth Apple's official response was "Sorry, that's just the way it is" and something about how they needed to get back to making emojis and don't have time for any of this printer stuff. Making matters more convoluted, this margin problem only happens on some sizes of paper. To get around this we added instructions to the apps documentation:

Press the (App Name) dropdown button on the print panel and then select "Page Attributes". This will pop up a listing of paper size choices with your paper choice selected with a checkmark. Hold the mouse down on the selected printer size and in a second or so a new menu will pop up and let you select borderless.

Chris Walken
  • 378
  • 1
  • 9