我想打印一个由多个不同方向的页面组成的文档。假设每个奇数页都是纵向的,每个偶数页都是横向的。下面是我的
PrintView
类的代码:
// PrintView.h
@interface PrintView : NSView
{
NSPrintInfo* printInfo;
int nPages;
}
- (id)initWithParams:(CGRect)frame pages:(int)pagesCount;
- (void)setPrintInfo:(NSPrintInfo *)pi;
@end
// PrintView.m
#import "PrintView.h"
@implementation PrintView
- (id)initWithParams:(CGRect)frame pages:(int)pagesCount
{
self = [super initWithFrame:frame];
if (self)
{
nPages = pagesCount;
}
return self;
}
- (void)setPrintInfo:(NSPrintInfo *)pi
{
if (printInfo != pi)
{
printInfo = pi;
}
}
// print support
- (BOOL)knowsPageRange:(NSRangePointer)range
{
range->location = 1;
range->length = nPages;
return YES;
}
- (NSRect)rectForPage:(NSInteger)page
{
if (page % 2)
[printInfo setOrientation:NSPaperOrientationPortrait];
else
[printInfo setOrientation:NSPaperOrientationLandscape];
NSRect r = NSMakeRect(0, 0, printInfo.paperSize.width, printInfo.paperSize.height);
[self setFrame:r];
return r;
}
@end
此代码仅生成没有任何绘图的空白页面。页面方向应用于
rectForPage:
。
当我在内置预览中运行打印操作(更多详细信息请参阅下面的 MRE 中的
onBtnClick
功能)时,我看到所有页面都以纵向显示:
实际上第二页应该是横向的。此外,如果我将其打印为 PDF,我可以看到 PDF 中所有页面方向都是正确的:
所以我认为问题出在内置的 Cocoa 预览中。如果最后一页为横向,则预览中的所有页面也将以横向显示。似乎只有最后一页方向适用于预览。
是否有任何解决方法可以在默认的 Cocoa 打印预览中显示不同方向的页面?还是我做错了什么?
下面是简单应用程序的代码,只需一个标有“打印”的按钮。按下该按钮开始打印过程。您可以在 Xcode 中运行并编译它(我使用 Xcode 版本 15.2)。上面列出了文件
PrintView.m
和 PrintView.h
,所以这里是其余的:
// main.m
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
int main(int argc, const char *argv[])
{
@autoreleasepool
{
AppDelegate *delegate = [[AppDelegate alloc] init];
NSApplication *app = [NSApplication sharedApplication];
app.delegate = delegate;
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
NSApplicationMain(argc, argv);
}
return 0;
}
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "ViewController.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (nonatomic, strong) NSWindow* window;
@property (nonatomic, strong) NSViewController* controller;
@end
// AppDelegate.m
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
int mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:mask backing:2 defer:NO];
_controller = [[ViewController alloc] init];
[_window.contentView addSubview:_controller.view];
[_window makeKeyAndOrderFront:nil];
}
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
@end
// ViewController.h
#import <Cocoa/Cocoa.h>
@interface ViewController : NSViewController
@property (nonatomic, strong) NSButton* button;
-(void) onBtnClick;
@end
// ViewController.m
#import "ViewController.h"
#import "PrintView.h"
@implementation ViewController
- (void)loadView
{
self.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_button = [NSButton buttonWithTitle:@"Print" target:self action:@selector(onBtnClick)];
[_button setFrame:NSMakeRect(50, 50, 100, 100)];
[self.view addSubview:_button];
}
- (void)onBtnClick
{
int nPages = 3; // here you can change the number of page being printed
NSLog(@"printint %d pages...", nPages);
PrintView* pView = [[PrintView alloc] initWithParams:NSMakeRect(0, 0, 100, 100) pages:nPages];
NSPrintInfo* printInfo = [NSPrintInfo sharedPrintInfo];
NSPrintPanelOptions options = NSPrintPanelShowsCopies;
options |= NSPrintPanelShowsPageRange;
options |= NSPrintPanelShowsPaperSize;
options |= NSPrintPanelShowsPrintSelection;
options |= NSPrintPanelShowsPreview;
NSPrintOperation* pro;
if (printInfo)
pro = [NSPrintOperation printOperationWithView:pView printInfo:printInfo];
else
pro = [NSPrintOperation printOperationWithView:pView];
[pView setPrintInfo:[pro printInfo]];
[pro setShowsPrintPanel:YES];
[[pro printPanel] setOptions:options];
[pro runOperation];
}
@end
经过一些研究后,我发现实际上没有办法仅将横向方向应用于某些页面,而在默认打印预览中将其他页面保留为纵向。可以将横向或纵向应用于所有页面。
所以我通过旋转页面内的内容解决了我的问题。例如,这就是 Preview.app 的工作方式。
您可以使用
printInfo.jobDisposition
区分打印预览和打印到文件,打印到屏幕或实际打印机时为 NSPrintSpoolJob
,保存为 PDF 时为 NSPrintSaveJob
。这样您就可以在打印为 PDF 时保存实际的页面方向。
这里修改了
rectForPage:
功能:
- (NSRect)rectForPage:(NSInteger)page
{
currentPage = (int)page - 1;
if (printInfo.jobDisposition == NSPrintSaveJob)
{
// apply my page orientation only when saving to file
[printInfo setOrientation:[self getCurrentPageOrientation]];
}
NSRect r = NSMakeRect(0, 0, printInfo.paperSize.width, printInfo.paperSize.height);
[self setFrame:r];
return r;
}
函数
getCurrentPageOrientation
像以前一样简单地为奇数页返回 0,为偶数页返回 1。
这里是重写的
drawRect:
函数:
- (void)drawRect:(NSRect)dirtyRect
{
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
if (printInfo.jobDisposition == NSPrintSpoolJob && (int)printInfo.orientation != [self getCurrentPageOrientation])
{
// rotate content only when drawing on preview AND current page is in wrong orientation
CGAffineTransform transform = CGAffineTransformMake(0, -1, 1, 0, 0, dirtyRect.size.height);
CGContextConcatCTM(context, transform);
}
// rect sizes
int rectW = 200;
int rectH = 100;
// bottom left rectangle
CGRect rect1 = NSMakeRect(0, 0, rectW, rectH);
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, rect1);
}
我在每页的左下角绘制一个 100 x 200 的红色矩形。
自从我将
NSPrintPanelShowsOrientation
添加到 NSPrintPanelOptions
后,您甚至可以看到它在横向方向上的外观:
Apple 没有在默认打印预览中添加旋转某些页面的功能,这确实很奇怪且不直观。希望他们有一天会添加它。我也希望这个答案可以帮助那些面临类似问题的人。