RFR: 8295737: macOS: Print content cut off when width > height with portrait orientation

Alexander Scherbatiy alexsch at openjdk.org
Wed Nov 2 14:48:32 UTC 2022


On Fri, 21 Oct 2022 08:42:12 GMT, Alexander Scherbatiy <alexsch at openjdk.org> wrote:

> A printed content is truncated on macOS if the content paper size width larger than height with portrait orientation or width is less than height with landscape orientation.
> 
> To reproduce the issue run the [CutOffImage](https://bugs.openjdk.org/secure/attachment/101145/CutOffImage.java) sample on MacOS.
> 
> Four rectangles are printed:
> 1. size 300x100, portrait orientation
> 2. size 300x100, landscape orientation
> 3. size 100x300, portrait orientation
> 4. size 100x300, landscape orientation
> 
> The first and fourth rectangles are truncated: [cut off content](https://bugs.openjdk.org/secure/attachment/101153/before-fix-all.pdf)
> 
> The reason is that NSPrintInfo class does not allow to set paper size and orientation independently.
> Setting paper size width large than height changes NSPrintInfo orientation to landscape.
> Setting paper size width less than height changes NSPrintInfo orientation to portrait.
> Updating NSPrintInfo orientation from landscape to portrait or from portrait to landscape swaps NSPrintInfo paper width and height.
> 
> The Cocoa code that shows NSPrintInfo behavior:
> 
> #import <Cocoa/Cocoa.h>
> 
> int main()
> {
>     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
>     NSApp = [NSApplication sharedApplication];
> 
>     #ifdef __MAC_10_9 // code for SDK 10.9 or newer
>     #define NS_PORTRAIT NSPaperOrientationPortrait
>     #define NS_LANDSCAPE NSPaperOrientationLandscape
>     #else // code for SDK 10.8 or older
>     #define NS_PORTRAIT NSPortraitOrientation
>     #define NS_LANDSCAPE NSLandscapeOrientation
>     #endif
> 
>     printf("NS_PORTRAIT: %d\n", NS_PORTRAIT);
>     printf("NS_LANDSCAPE: %d\n", NS_LANDSCAPE);
> 
>     printf("create default print info\n");
>     NSPrintInfo* defaultPrintInfo = [[NSPrintInfo sharedPrintInfo] copy];
>     NSSize size = [defaultPrintInfo paperSize];
>     printf("orientation: %d, paper size: [%f, %f]\n", [defaultPrintInfo orientation], size.width, size.height);
> 
>     printf("call setUpPrintOperationDefaultValues\n");
>     [defaultPrintInfo setUpPrintOperationDefaultValues];
>     size = [defaultPrintInfo paperSize];
>     printf("orientation: %d, paper size: [%f, %f]\n", [defaultPrintInfo orientation], size.width, size.height);
> 
>     double w = 300.0;
>     double h = 100.0;
>     printf("set size: [%f, %f]\n", w, h);
>     [defaultPrintInfo setPaperSize:NSMakeSize(w, h)];
>     size = [defaultPrintInfo paperSize];
>     printf("orientation: %d, paper size: [%f, %f]\n", [defaultPrintInfo orientation], size.width, size.height);
> 
>     printf("Set NS_PORTRAIT orientation\n");
>     [defaultPrintInfo setOrientation: NS_PORTRAIT];
>     size = [defaultPrintInfo paperSize];
>     printf("orientation: %d, paper size: [%f, %f]\n", [defaultPrintInfo orientation], size.width, size.height);
> 
>     [NSApp run];
> 
>     [NSApp release];
>     [pool release];
>     return(EXIT_SUCCESS);
> } 
> 
> 
> On macOS Mojave 10.14.5 it prints:
> 
> 
> NS_PORTRAIT: 0
> NS_LANDSCAPE: 1
> create default print info
> orientation: 0, paper size: [612.000000, 792.000000]
> call setUpPrintOperationDefaultValues
> orientation: 0, paper size: [612.000000, 792.000000]
> set size: [300.000000, 100.000000]
> orientation: 1, paper size: [300.000000, 100.000000] // orientation flip
> Set NS_PORTRAIT orientation
> orientation: 0, paper size: [100.000000, 300.000000] // size flip
> ``` 
> 
> There are four possible cases for printing a rectangle with different size and orientation:
> 1. Input: paper size: (w > h), orientation portrait
>   [dstPrintInfo setPaperSize: NSMakeSize(w, h)]  // size: (w, h), orientation: landscape
>   [dstPrintInfo setOrientation: NS_PORTRAIT]     // size: (h, w), orientation: portrait
>   Note: width and height are swapped
> 2. Input: paper size: (w > h), orientation landscape
>   [dstPrintInfo setPaperSize: NSMakeSize(h, w)]  // size: (h, w), orientation: portrait
>   [dstPrintInfo setOrientation: NS_LANDSCAPE]  // size: (w, h), orientation: landscape
> 3. Input: paper size: (w < h), orientation portrait
>   [dstPrintInfo setPaperSize: NSMakeSize(w, h)]  // size: (w, h), orientation: portrait
>   [dstPrintInfo setOrientation: NS_PORTRAIT]     // size: (w, h), orientation: portrait
> 4. Input: paper size: (w < h), orientation landscape
>   [dstPrintInfo setPaperSize: NSMakeSize(h, w)]  // size: (h, w), orientation: landscape
>   [dstPrintInfo setOrientation: NS_LANDSCAPE]  // size: (h, w), orientation: landscape
>   Note: width and height are swapped
> 
> Only for cases 1 and 4 the final width and height are swapped.
> The proposed fix enlarges height for cases 1 and 4 to not cut the printed rectangle.
> 
> It is not full fix which draws rectangles for cases 1 and 4 in the requested size.
> Setting requested size leads that subsequent orientation flips width and height.
> The fix only enlarges the truncated area in height direction. The enlarged area in width is preserved as before the fix.
> 
> Printed rectangles before and after the fix:
> 1. size 300x100, portrait orientation: [before-fix-1.pdf](https://bugs.openjdk.org/secure/attachment/101157/before-fix-1.pdf),  [after-fix-1.pdf](https://bugs.openjdk.org/secure/attachment/101162/after-fix-1.pdf)
> 2. size 300x100, landscape orientation: [before-fix-2.pdf](https://bugs.openjdk.org/secure/attachment/101156/before-fix-2.pdf),  [after-fix-2.pdf](https://bugs.openjdk.org/secure/attachment/101161/after-fix-2.pdf)
> 3. size 100x300, portrait orientation: [before-fix-3.pdf](https://bugs.openjdk.org/secure/attachment/101155/before-fix-3.pdf),  [after-fix-3.pdf](https://bugs.openjdk.org/secure/attachment/101160/after-fix-3.pdf)
> 4. size 100x300, landscape orientation: [before-fix-4.pdf](https://bugs.openjdk.org/secure/attachment/101154/before-fix-4.pdf),  [after-fix-4.pdf](https://bugs.openjdk.org/secure/attachment/101159/after-fix-4.pdf)
> 
> All four rectangles: [before-fix-all.pdf](https://bugs.openjdk.org/secure/attachment/101153/before-fix-all.pdf),  [after-fix-all.pdf](https://bugs.openjdk.org/secure/attachment/101158/after-fix-all.pdf)

Suppose there is an [image](https://bugs.openjdk.org/secure/attachment/101295/image-PORTRAIT-600x200.png) with size 600x200. It is necessary to print only region [0, 0, 300, 100] of the image using page size 300x100 and portrait orientation (case 1).

The java code which prints only part of the image with the given page size and orientation could look like:

        PageFormat pageFormat = printerJob.getPageFormat(null);
        pageFormat.setOrientation(PageFormat.PORTRAIT);
        Paper paper = pageFormat.getPaper();
        paper.setSize(300, 100);
        paper.setImageableArea(0, 0, 300, 100);
        pageFormat.setPaper(paper);


First, I would check how the image can be printed with pure Cocoa code using NSImageView, NSPrintInfo, and NSPrintOperation classes and transformations.

The NSImageView rotation can be implemented as:

@interface SampleImageView : NSImageView
@end

@implementation SampleImageView
 - (void)drawRect:(NSRect)dirtyRect {
    NSAffineTransform *transform = [[NSAffineTransform alloc] init];
    [transform rotateByDegrees: 90.0];
    [transform concat]; 
    [super drawRect:dirtyRect];
}
@end


The Cocoa pseudo code which prints the image is:

NSImageView *nsImageView = // create NSImageView with the given image
// apply clip and transformations to the nsImageView
NSPrintInfo* printInfo = // create NSPrintInfo
// set printInfo page size
NSPrintOperation* loop = [NSPrintOperation printOperationWithView:nsImageView printInfo:printInfo];


The question which is not clear for me, which page size needs to be used for the code `// set printInfo page size`?

Should it be the requested size 300x100? Setting page size 300x100 to NSPrintInfo implies that it is applied to landscape orientation. The result page size is rotated by 90 degree comparing to the portrait orientation. May be there are transforms which can be applied to NSPrintInfo for page size rotation?

Should the default page size be used instead? So the NSImageView is translated, rotated, and clipped but it is printed to the page with default page size?

-------------

PR: https://git.openjdk.org/jdk/pull/10808



More information about the client-libs-dev mailing list