iOS打印界面导致自定义视图出现转换问题
我现在在iOS的打印界面上挣扎了很长时间。 我拥有的是一个具有自定义UIView的视图控制器,它在drawRect中执行绘图:
一个例子是如何在iPad上绘图(包括一些彩色测试线):
我已经设置了一个UIPrintRenderer子类,它打印页眉和页脚,并提供内容rect drawContentForPageAtIndex:inRect:用于自定义UIView的drawRect:方法。 调试器告诉我,drawRect:总是被调用 - 在渲染器类中是否存在rect drawContentForPageAtIndex:inRect:并不重要。 所以我不会在rect drawContentForPageAtIndex:inRect中绘制图形,而我使用drawRect:。
当打印机模拟器提供A4纸张格式时,我得到[0,0,841.89,595.276]的纸张矩形,[11.9905,11.9906,817.909,571.294]的可打印矩形和内容矩形[11.9905,33.9906,817.909,530.294 ]。 我真的不明白的是,drawRect:从打印界面得到[0,0,695,530.294]的矩形。 这是内容矩形的高度,但宽度是从矩形的宽度,当绘图正常完成w / out打印时:[0,0,695,648]。 它在模拟器输出页面中看起来像这样(当然也添加了一些测试框架,线条和圆圈):
这里有一些代码,首先是视图控制器中设置打印的部分:
- (IBAction)pressedPrint:(id)sender
{
UIPrintInteractionController* printCtrl = [UIPrintInteractionController sharedPrintController];
UIPrintInfo* printInfo = [UIPrintInfo printInfo];
NSLog(@"%s prepare printing parameters etc.", __func__);
printCtrl.delegate = self;
printInfo.outputType = UIPrintInfoOutputPhoto;
printInfo.orientation = UIPrintInfoOrientationLandscape;
printInfo.jobName = [NSString stringWithFormat:@"%@ - %@", NSLocalizedString(@"NavTitleMain", @""), self.title];
printInfo.duplex = UIPrintInfoDuplexNone;
printCtrl.printInfo = printInfo;
printCtrl.showsPageRange = NO;
// This code uses a custom UIPrintPageRenderer so that it can draw a header and footer.
DVPrintPageRenderer* myRenderer = [[DVPrintPageRenderer alloc] init];
// The DVPrintPageRenderer class provides a jobtitle that it will label each page with.
myRenderer.jobTitle = printInfo.jobName;
myRenderer.isTwoPageView = NO;
myRenderer.footerText = [centralDocument sharedInstance].docTitle;
myRenderer.drawView = self.drawArea;
// To draw the content of each page, a UIViewPrintFormatter is used.
UIViewPrintFormatter* viewFormatter = [self.drawArea viewPrintFormatter];
UIFont* titleFont = [UIFont fontWithName:@"Helvetica" size:HEADER_TEXT_HEIGHT];
CGSize titleSize = [myRenderer.jobTitle getSizeWithFont:titleFont];
UIFont* footerFont = [UIFont fontWithName:@"Helvetica" size:FOOTER_TEXT_HEIGHT];
CGSize footerSize = [myRenderer.footerText getSizeWithFont:footerFont];
viewFormatter.startPage = 0;
myRenderer.headerHeight = titleSize.height + HEADER_FOOTER_MARGIN_PADDING;
myRenderer.footerHeight = footerSize.height + HEADER_FOOTER_MARGIN_PADDING;
[myRenderer addPrintFormatter:viewFormatter startingAtPageAtIndex:0];
// Set our custom renderer as the printPageRenderer for the print job.
printCtrl.printPageRenderer = myRenderer;
drawArea.isPrinting = YES;
drawArea.printRenderer = myRenderer;
NSLog(@"%s before presenting the printer dialog", __func__);
void (^completionHandler)(UIPrintInteractionController*, BOOL, NSError*) =
^(UIPrintInteractionController* printController, BOOL completed, NSError* error)
{
drawArea.isPrinting = NO;
drawArea.printRenderer = nil;
if (!completed && error)
{
NSLog(@"Printing could not complete because of error: %@", error);
}
};
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[printCtrl presentFromBarButtonItem:sender animated:YES completionHandler:completionHandler];
}
else
{
[printCtrl presentAnimated:YES completionHandler:completionHandler];
}
}
drawRect的第一个代码部分:在这里也可能是相关的:
- (void)drawRect: (CGRect)rect
{
// Drawing code.
NSLog(@"%s entered for %@", __func__, (isPrinting ? @"printing" : @"screen drawing"));
NSInteger colorCount = (colorArray == nil) ? -1 : [colorArray count];
NSInteger graphCount = (graphPoints == nil) ? -1 : [graphPoints count];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
if (isPrinting)
{
// make sure that we'll print the frame rectangle
CGRect newRect = CGRectInset(printRenderer.rectContent, 2.0, 2.0);
saveGraphRect = drawGraphRect;
saveBackColor = viewBackColor;
saveTextColor = viewBackColor;
CGContextTranslateCTM(context, printRenderer.rectContent.origin.x, -printRenderer.rectContent.origin.y);
NSLog(@"%s content = [%g, %g, %g, %g]", __func__,
printRenderer.rectContent.origin.x, printRenderer.rectContent.origin.y,
printRenderer.rectContent.size.width, printRenderer.rectContent.size.height);
NSLog(@"%s rect(1) = [%g, %g, %g, %g]", __func__,
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
rect = CGRectMake(ceilf(newRect.origin.x), ceilf(newRect.origin.y),
floorf(newRect.size.width), floorf(newRect.size.height));
CGContextTranslateCTM(context, rect.origin.x, rect.origin.y);
rect.origin = CGPointMake(0.0, 0.0);
usedBounds = rect;
drawGraphRect = [self makeInsetDrawRectFrom:rect];
viewBackColor = [UIColor whiteColor];
axisTextColor = [UIColor blackColor];
NSLog(@"%s prepared for printing", __func__);
NSLog(@"%s bounds = [%g, %g, %g, %g]", __func__,
self.bounds.origin.x, self.bounds.origin.y,
self.bounds.size.width, self.bounds.size.height);
NSLog(@"%s paper = [%g, %g, %g, %g]", __func__,
printRenderer.paperRect.origin.x, printRenderer.paperRect.origin.y,
printRenderer.paperRect.size.width, printRenderer.paperRect.size.height);
NSLog(@"%s rect(2) = [%g, %g, %g, %g]", __func__,
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
NSLog(@"%s draw = [%g, %g, %g, %g]", __func__,
drawGraphRect.origin.x, drawGraphRect.origin.y, drawGraphRect.size.width, drawGraphRect.size.height);
}
else
{
usedBounds = self.bounds;
...
drawRect中rect的NSLog输出也是相关的:
2014-01-21 17:15:39.906 iELANA[19015:a0b] -[DrawView drawRect:] entered for screen drawing
2014-01-21 17:15:39.906 iELANA[19015:a0b] -[DrawView drawRect:] bounds = [0, 0, 695, 648]
2014-01-21 17:15:39.906 iELANA[19015:a0b] -[DrawView drawRect:] rect = [0, 0, 695, 648]
2014-01-21 17:15:39.906 iELANA[19015:a0b] -[DrawView drawRect:] draw = [62, 2, 631, 584]
2014-01-21 17:15:40.645 iELANA[19015:a0b] -[viewDiagram pressedPrint:] prepare printing parameters etc.
2014-01-21 17:15:40.645 iELANA[19015:a0b] -[viewDiagram pressedPrint:] before presenting the printer dialog
2014-01-21 17:15:46.131 iELANA[19015:a0b] printableRect = [11.9905, 11.9906, 817.909, 571.294]
2014-01-21 17:15:46.131 iELANA[19015:a0b] headerRect = [11.9905, 11.9906, 817.909, 22]
2014-01-21 17:15:46.131 iELANA[19015:a0b] header text size = [297, 17]
2014-01-21 17:15:46.133 iELANA[19015:a0b] -[DVPrintPageRenderer drawContentForPageAtIndex:inRect:] page = 0, rect [11.9905, 33.9906, 817.909, 530.294]
2014-01-21 17:15:46.133 iELANA[19015:a0b] paper rect = [0, 0, 841.89, 595.276]
2014-01-21 17:15:46.133 iELANA[19015:a0b] printable rect = [11.9905, 11.9906, 817.909, 571.294]
2014-01-21 17:15:46.133 iELANA[19015:a0b] -[DrawView drawRect:] entered for printing
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] content = [11.9905, 33.9906, 817.909, 530.294]
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] rect(1) = [0, 0, 695, 530.294]
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] prepared for printing
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] bounds = [0, 0, 695, 648]
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] paper = [0, 0, 841.89, 595.276]
2014-01-21 17:15:46.134 iELANA[19015:a0b] -[DrawView drawRect:] rect(2) = [0, 0, 813, 526]
2014-01-21 17:15:46.135 iELANA[19015:a0b] -[DrawView drawRect:] draw = [62, 2, 749, 462]
2014-01-21 17:15:46.140 iELANA[19015:a0b] printableRect = [11.9905, 11.9906, 817.909, 571.294]
2014-01-21 17:15:46.140 iELANA[19015:a0b] footerRect = [11.9905, 564.285, 817.909, 19]
2014-01-21 17:15:46.140 iELANA[19015:a0b] footer text size = [296, 14]
绘图代码使用Core Graphics和UIKit来处理框架,线条等等。 文本输出使用核心文本。 因此,应用正确的CTM转换仍然有一些工作。 但主要的第一个问题是:
为什么drawRect:从打印界面得到一个奇怪的矩形而不是内容矩形? 如果我无法打破这一规则,iPhone的印刷代替了iPad,情况就会变得非常糟糕 - 在目前的编码下,iPhone看起来更糟糕。
我应该在打印渲染器的drawContentForPageAtIndex:inRect:中更好地执行打印绘图代码吗?
你的帮助非常感谢:-)
Konran
添加:
看起来的确如此,传递给drawRect的图形上下文对于打印的需求是不可用的。 当我直接从drawRect返回时:在打印的情况下,将打印代码添加到drawContentForPageAtIndex:inRect :,我得到了一个更好的(测试)输出:
但是我不明白的以及我仍然需要你的帮助的是轴文本的定位代码,它们是用Core Text绘制的。 我尝试过非常不同的CTM转换组合......但是我使用的任何转换组合都会导致文本错位。 这就是我为x轴上的文本输出所做的:
- (void)drawAxisValueXin: (CGContextRef)context withText: (NSString*)axisValueX dockToPoint: (CGPoint)dockPoint
{
BOOL isRetina = (!isPrinting && AfxGetApp().isRetina);
CGFloat rMul = (isRetina) ? 2.0 : 1.0;
CGFloat fontSize = 10.0;
CTFontRef helvetica = CTFontCreateWithName(CFSTR("Helvetica"), fontSize, NULL);
if (isRetina)
{
dockPoint.x *= 2.0;
dockPoint.y *= 2.0;
}
// flip the coordinate system
CGContextSaveGState(context);
if (isPrinting)
{
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0.0f, CGRectGetHeight(printRenderer.paperRect));
CGContextScaleCTM(context, 1.0f, -1.0f);
}
else
{
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0.0f, CGRectGetHeight(usedBounds) * rMul);
CGContextScaleCTM(context, 1.0f, -1.0f);
}
// make the attributed string
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:axisValueX];
NSRange strRange = NSMakeRange(0, [attrString length]);
[attrString addAttribute: (id)kCTFontAttributeName
value: (__bridge id)helvetica
range: strRange];
[attrString addAttribute: (id)kCTForegroundColorAttributeName
value: (id)axisTextColor.CGColor
range: strRange];
// draw the text
CTLineRef ctLine = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CGFloat ascent;
CGFloat descent;
CGFloat width = ceilf(CTLineGetTypographicBounds(ctLine, &ascent, &descent, NULL));
CGFloat height = ceilf(ascent + descent);
CGSize textSize = CGSizeMake(width, height);
CGPoint atPoint = CGPointMake(dockPoint.x + (1.0 - textSize.width) * rMul,
dockPoint.y + (10.0 - 2.0) * rMul); // x = text right edge, y = text mid
CGPoint userPoint = CGContextConvertPointToUserSpace(context, atPoint);
if (fabsf(tiltLeftAxisX) > 1.0e-8)
{
CGContextRotateCTM(context, -tiltLeftAxisX);
dockPoint.y += 2.0 * rMul; // offset y 2 points down
dockPoint = CGContextConvertPointToUserSpace(context, dockPoint);
dockPoint.x = nearbyintf(dockPoint.x);
dockPoint.y = nearbyintf(dockPoint.y);
userPoint = CGPointMake(dockPoint.x - width,
dockPoint.y - height / 2.0);
}
CGContextSetTextPosition(context, userPoint.x, userPoint.y);
CTLineDraw(ctLine, context);
CGRect rectTempl = CGRectMake(-5.0, -5.0, 10.0, 10.0);
CGRect rectDot = CGRectOffset(rectTempl, userPoint.x, userPoint.y);
[[UIColor redColor] set];
CGContextFillEllipseInRect(context, rectDot);
rectDot = CGRectOffset(rectTempl, atPoint.x, atPoint.y);
[[UIColor greenColor] set];
CGContextFillEllipseInRect(context, rectDot);
// clean up
CFRelease(ctLine);
CFRelease(helvetica);
CGContextRestoreGState(context);
}
打印上下文与绘图上下文非常不同。 因此,上述方法的结论终于有效,就像这样:
- (void)drawAxisValueXin: (CGContextRef)context withText: (NSString*)axisValueX dockToPoint: (CGPoint)dockPoint
{
BOOL isRetina = (!isPrinting && AfxGetApp().isRetina);
CGFloat rMul = (isRetina) ? 2.0 : 1.0;
CGFloat fontSize = 10.0;
CTFontRef helvetica = CTFontCreateWithName(CFSTR("Helvetica"), fontSize, NULL);
if (isRetina)
{
dockPoint.x *= 2.0;
dockPoint.y *= 2.0;
}
else if (isPrinting)
{
dockPoint.y += 2.0;
}
// flip the coordinate system
CGContextSaveGState(context);
if (isPrinting)
{
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, -1.0));
}
else
{
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0.0f, CGRectGetHeight(usedBounds) * rMul);
CGContextScaleCTM(context, 1.0f, -1.0f);
}
// make the attributed string
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:axisValueX];
NSRange strRange = NSMakeRange(0, [attrString length]);
[attrString addAttribute: (id)kCTFontAttributeName
value: (__bridge id)helvetica
range: strRange];
[attrString addAttribute: (id)kCTForegroundColorAttributeName
value: (id)axisTextColor.CGColor
range: strRange];
// draw the text
CTLineRef ctLine = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CGFloat ascent;
CGFloat descent;
CGFloat width = ceilf(CTLineGetTypographicBounds(ctLine, &ascent, &descent, NULL));
CGFloat height = ceilf(ascent + descent);
CGSize textSize = CGSizeMake(width, height);
CGPoint atPoint = CGPointMake(dockPoint.x + (1.0 - textSize.width) * rMul,
dockPoint.y + (10.0 - 2.0) * rMul); // x = text right edge, y = text mid
CGPoint userPoint = (isPrinting) ? atPoint : CGContextConvertPointToUserSpace(context, atPoint);
if (fabsf(tiltLeftAxisX) > 1.0e-8)
{
if (isPrinting)
{
CGFloat xMove = textSize.height * sin(tiltLeftAxisX);
CGFloat yMove = textSize.width * sin(tiltLeftAxisX);
userPoint.x -= xMove;
userPoint.y -= yMove;
userPoint = CGContextConvertPointToDeviceSpace(context, userPoint);
CGContextRotateCTM(context, tiltLeftAxisX);
userPoint = CGContextConvertPointToUserSpace(context, userPoint);
}
else
{
CGContextRotateCTM(context, -tiltLeftAxisX);
dockPoint.y += 2.0 * rMul; // offset y 2 points down
dockPoint = CGContextConvertPointToUserSpace(context, dockPoint);
dockPoint.x = nearbyintf(dockPoint.x);
dockPoint.y = nearbyintf(dockPoint.y);
userPoint = CGPointMake(dockPoint.x - width,
dockPoint.y - height / 2.0);
}
}
CGContextSetTextPosition(context, userPoint.x, userPoint.y);
CTLineDraw(ctLine, context);
// clean up
CFRelease(ctLine);
CFRelease(helvetica);
CGContextRestoreGState(context);
}
链接地址: http://www.djcxy.com/p/81925.html
上一篇: iOS printing interface causes transformation problems with a custom view
下一篇: Height of glyph