Подтвердить что ты не робот

Предоставление UIView в PDF как векторы на iPad - Иногда отображается как растровое изображение, иногда как векторы

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

Код действительно прост:

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

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

Это похоже на то, как действие визуализации на экран устанавливает представление, которое будет отображаться в виде векторов, когда я впоследствии передам его в pdf-контекст.

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

Это как-то связано с UIViewPrintFormatter?

4b9b3361

Ответ 1

Единственный способ сделать так, чтобы метки визуализировались векторизованно, это использовать подкласс 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 и ведут себя нормально при отображении на экране.

Ответ 2

Как насчет того, если вы добавите представление на экран, но в заставку координат. Это похоже на хак, но это может сработать.

Ответ 3

Я хочу предложить альтернативу 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];
    }
}

Ответ 4

Используйте drawInContext, а не renderInContext.

Ответ 5

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

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

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

CALayer* formattedLayer = [view viewPrintFormatter].view.layer;
[formattedLayer renderInContext:pdfContext];