Предоставление 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?
Ответы
Ответ 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];