Рендеринг UIView в PDF как векторы на iPad - иногда рендеринг как растровое изображение, иногда как вектор - PullRequest
27 голосов
/ 21 июня 2011

У меня есть приложение для iPad, и я пытаюсь сгенерировать PDF из UIView, и оно почти отлично работает.

Код действительно прост, как показано ниже:

UIGraphicsBeginPDFContextToFile( filename, bounds, nil );
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[view.layer renderInContext:pdfContext];
UIGraphicsEndPDFContext();

Это работает очень хорошо с одним странным исключением.Если представление было на экране до его визуализации в PDF, тогда UILabels на представлении будет отображаться в PDF как замечательные векторы.Если представление еще не было на экране (т.е. контроллером был initWithNib и т. Д., Но не было помещено в контроллер навигации или что-либо еще), то текст отображается как растровое изображение с разрешением ipad.

Это похоже на то, как процесс рендеринга на экран настраивает вид для рендеринга в виде векторов, когда я впоследствии отрисовываю его в контексте PDF.

Есть ли какой-нибудь метод, который я могу вызвать или свойство, которое я могу установить в представлении, слое или в другом месте, чтобы имитировать это поведение, не отображая вид на экране?

Это что-то делатьс UIViewPrintFormatter?

Ответы [ 5 ]

23 голосов
/ 30 января 2012

Единственный способ сделать так, чтобы метки были векторизованы, - это использовать подкласс UILabel следующим методом:

/** Overriding this CALayer delegate method is the magic that allows us to draw a vector version of the label into the layer instead of the default unscalable ugly bitmap */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
    BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());
    if (!layer.shouldRasterize && isPDF)
        [self drawRect:self.bounds]; // draw unrasterized
    else
        [super drawLayer:layer inContext:ctx];
}

Swift 5.x:

override func draw(_ layer: CALayer, in ctx: CGContext) {
    let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty

    if !self.layer.shouldRasterize && isPDF {
        self.draw(self.bounds)
    } else {
        super.draw(layer, in: ctx)
    }
}

Это делает мой трюк: метки не являются рестеризированными и выбираются в получающемся представлении PDF и ведут себя нормально при отображении на экране.

1 голос
/ 15 апреля 2013

Я хочу предложить альтернативу отличному решению mprudhom: Используя расширения UIString, вы также можете сделать так, чтобы текст в UILabel отображался как шрифт (с поддержкой select'n'copy и т. Д.) Таким образом, символы шрифта будут правильно вставлены в PDF.

Чтобы поддерживать выравнивание текста по правому и по центру, а также выравнивание по центру по умолчанию по умолчанию, мне пришлось рассчитать ограничивающую рамку для метода drawInRect.

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());

    if (!layer.shouldRasterize && isPDF) {
        // [self drawRect:self.bounds];

        CGSize fitSize = [self sizeThatFits:self.bounds.size];
        float x = self.bounds.origin.x;
        float y = self.bounds.origin.y;

        if (self.textAlignment == NSTextAlignmentCenter) {
            x += (self.bounds.size.width  - fitSize.width)  / 2.0f;
            y += (self.bounds.size.height - fitSize.height) / 2.0f;
        } else if (self.textAlignment == NSTextAlignmentRight) {
            x += self.bounds.size.width  - fitSize.width;
            y += self.bounds.size.height - fitSize.height;
        }
        [self.textColor set];
        [self.text drawInRect:CGRectMake(x, y, fitSize.width, fitSize.height) withFont:self.font lineBreakMode:NSLineBreakByWordWrapping alignment:self.textAlignment];
    } else {
        [super drawLayer:layer inContext:ctx];
    }
}
1 голос
/ 20 ноября 2011

Что делать, если вы добавляете вид на экран, но в закадровых координатах.Это больше похоже на взлом, но это может сработать.

0 голосов
/ 19 августа 2011

Используйте drawInContext вместо renderInContext.

0 голосов
/ 19 августа 2011

Попытка использовать представление viewPrintFormatter.

Вместо [view.layer renderInContext:pdfContext];

попробуйте это

CALayer* formattedLayer = [view viewPrintFormatter].view.layer;
[formattedLayer renderInContext:pdfContext];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...