1

Я довольно долго борюсь с интерфейсом печати iOS. Что у меня есть один контроллер с пользовательской UIView, что делает его рисунок в DrawRect вид:Интерфейс печати iOS вызывает проблемы с преобразованием с настраиваемым представлением

Пример как рисунок выглядит на IPad здесь (в том числе и некоторых цветных испытательных линий):

enter image description here

Я установил подкласс UIPrintRenderer, который печатает верхний и нижний колонтитулы и поставляет содержимое rect drawContentForPageAtIndex: inRect: для метода drawRect: пользовательского UIView. Отладчик говорит мне, что drawRect: вызывается всегда - не имеет значения, если rect drawContentForPageAtIndex: inRect: существует в классе визуализации или нет. Поэтому я не делаю рисунок в rect drawContentForPageAtIndex: inRect: и я использую drawRect: для этого.

Когда симулятор принтера поставляет формат бумаги формата А4, я получаю бумажный прямоугольник [0, 0, 841.89, 595.276], печатный прямоугольник [11,9905, 11,9906, 817,909, 571,294] и содержимое rect [11,9905, 33,9906] , 817,909, 530,294]. Я действительно не понимаю, что drawRect: получает прямой от [0, 0, 695, 530.294] от интерфейса печати. Это высота прямоугольника содержимого, но ширина такова, что из прямоугольника, когда чертеж выполняется обычно без печати: [0, 0, 695, 648]. Похоже, что это в выходной Тренажер страницы (там также добавлены несколько тестовых кадров, линии и круги, конечно):

enter image description here

Некоторые код здесь следует, первую часть в контроллере представления, который устанавливает печать :

- (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; 
     ... 

Выхода NSLog для прямоугольников в дра wRect: также актуальны:

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 для фреймов, линий и т. д. Текстовый вывод использует Core Text. Таким образом, есть еще некоторая работа, применяющая правильные трансформации CTM. Но главный первый вопрос:

Почему drawRect: получить прямолинейный прямоугольник вместо содержимого прямо из интерфейса печати? Если я не могу нарушить это правило, все будет очень плохо для печати iPhone вместо iPad - на iPhone с нынешним кодированием он выглядит намного хуже.

Должен ли я сделать код чертежа еще лучше в чертеже рендеринга рендерингаContentForPageAtIndex: inRect :?

Ваша помощь очень ценится :-)

Konran

Добавлено:

Кажется, на самом деле так, что графический контекст передается DrawRect: не может использоваться для требований печати ,Когда я вернусь непосредственно из DrawRect: в случае печати и добавить код для печати на drawContentForPageAtIndex: inRect :, я получаю гораздо лучше (тест) вывод:

enter image description here

Но то, что я не понимаю, и где Мне по-прежнему нужна ваша помощь, это код позиционирования для текстов оси, которые рисуются с помощью 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); 
} 

ответ

0

Контекст печати действительно сильно отличается от контекста рисования. Таким образом, заключение для вышеописанного метода выглядит следующим образом:

- (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); 
} 
Смежные вопросы