Не секрет, что PDF документ в приложении можно показать в UIWebView. Но, что делать, если вас не устраивает то, как UIWebView отображает документ? Может быть вы хотите сделать свой механизм перехода по страницам?

В iOS PDF можно отобразить через CoreGraphics. При использовании этого подхода каждая страница рисуется отдельно. Т.е. если нужно сделать переход по страницам в документе — нужно будет все делать вручную.

Итак, предположим, что у нас в Bundle приложения лежит PDF-файл idevby.pdf. Как его отобразить? Создадим класс PDFView, который будет это отображать:

@interface PDFView : UIView
@end

В классе перекроем метод drawRect::

- (void)drawRect:(CGRect)rect
{
    // путь до документа
    CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"idevby" ofType:@"pdf"]];

// открываем документ CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url);

// если в документе нет страниц - ничего отображать не нужно if ( CGPDFDocumentGetNumberOfPages(pdfDocument) > 0 ) { // получим первую страницу (страницы нумеруются с первой) CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1);

// получим необходимое преобразование CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSaveGState(context);

// применим преобразование CGContextTranslateCTM(context, 0, self.bounds.size.height); CGContextScaleCTM(context, 1, -1); CGContextConcatCTM(context, t);

// отрисуем страницу CGContextDrawPDFPage(context, pdfPage);

CGContextRestoreGState(context); }

// закроем документ CGPDFDocumentRelease(pdfDocument); }

Рассмотрим основные моменты.

При отрисовке PDF-страницы мы сохраняем состояние контекста, а затем восстанавливаем его:

CGContextSaveGState(context);
...
CGContextRestoreGState(context);

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

Нам необходимо отразить контекст по вертикали, иначе документ будет показан «вверх ногами». Это связано с тем, что в данном случае ось Y направлена снизу вверх.

CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);

Ну и самое интересное:

CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);
...
CGContextConcatCTM(context, t);

CGContextDrawPDFPage(context, pdfPage);

Функция CGPDFPageGetDrawingTransform возвращает трансформацию для контекста, которую нужно применить, чтобы целиком отобразить заданную область страницы в заданной области view. Трансформацию применяет функция CGContextConcatCTM. Первым аргументом функции CGPDFPageGetDrawingTransform является страница, которую хотим отобразить. Второй аргумент — область документа для отображения. Области определены так:

enum CGPDFBox {
kCGPDFMediaBox = 0,
kCGPDFCropBox = 1,
kCGPDFBleedBox = 2,
kCGPDFTrimBox = 3,
kCGPDFArtBox = 4
};

Третий аргумент — область на view, где будет отображена страница, в данном случае мы используем всю область. Четвертый аргумент — угол вращения в градусах, должен быть обязательно кратным 90. Пятый аргумент — сохранять ли пропорции сторон при отрисовке.

Конечно-же, этот способ более трудоемкий, чем способ с использованием UIWebView. Но, используя такой подход, мы можем получить больше возможностей для кастомизации отображения PDF. Есть и минус данного подхода — если в документе есть ссылки — они не будут активными и необходимо будет применять дополнительные средства.

На этом все, спасибо за внимание. Загрузить исходный код можно отсюда.

Напоследок несколько примеров:

PDF

CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1)

PDF

CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 90, 1)

PDF

CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 90, 0)

PDF

CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, CGRectInset(self.bounds, 50, 100), 0, 1)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *