У меня есть пробный PDF на 140 страниц (полная спецификация Adobe PDF, http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000.pdf), и я открываю его в iBooks. Затем переключаюсь в режим просмотра в виде индекса (миниатюры). Если я прокручиваю до конца достаточно быстро, я вижу, что Я могу прокручивать быстрее, чем iBooks отображает страницы, но на iPad 2 довольно быстро догоняет.
Из этого я узнаю две вещи:
- Сначала iBooks показывает 140 пустых квадратов правильного размера, а затем заполняет предварительный просмотр.
- iBooks действительно отображает все предварительные просмотры и сохраняет их в памяти (если я прокручиваю, я не могу обнаружить повторный рендеринг)
- Я также протестировал другую спецификацию Adobe, которая имеет более 700 страниц: точно такое же поведение! Захватывающий!
Вопрос в том, как они это делают? Я написал код, который получает каждую страницу PDF в виде изображения, добавляет его в UIImageView и добавляет его в представление прокрутки.
Я использую ту же технику и макет, что и iBooks. Он рендерит так же быстро, как iBooks, но потребление памяти безумно, особенно когда прокрутка приложения полностью застревает через некоторое время. Кто-нибудь может указать мне правильное направление? Я уже удалил рендеринг PDF для тестирования, и он действительно быстрый, поэтому я могу связать его с созданием миниатюр.
EDIT:
Если из приведенного ниже кода генерация PDF удалена и вместо нее возвращается пустой UIImageView
, производительность все равно остается крайне низкой. Поэтому я предполагаю, что UIImageView вызывает проблему. Как я могу нарисовать большие пальцы PDF на моем UIScrollView
без требования 140 UIImageViews
?
Для тех фирм в Monotouch, вот код, который я использую для отрисовки больших пальцев, возможно, он демонстрирует очевидную слабость:
/// <summary>
/// Gets the low res page preview of a PDF page. Does a quick image render of the page.
/// </summary>
/// <param name="iPage">the number of the page to render</param>
/// <param name="oTergetRect">the target rect to fit the PDF page into</param>
/// <returns>
/// The low res page image view.
/// </returns>
public static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
{
RectangleF oOriginalPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
RectangleF oPdfPageRect = PdfViewerHelpers.RotateRectangle( oPdfPage.GetBoxRect (CGPDFBox.Media), oPdfPage.RotationAngle);
// If preview is requested for the PDF index view, render a smaller version.
if (!oTargetRect.IsEmpty)
{
// Resize the PDF page so that it fits the target rectangle.
oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size));
}
// Create a low res image representation of the PDF page to display before the TiledPDFView
// renders its content.
int iWidth = Convert.ToInt32 ( oPdfPageRect.Size.Width );
int iHeight = Convert.ToInt32 ( oPdfPageRect.Size.Height );
CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB();
CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast);
// First fill the background with white.
oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
oContext.FillRect (oOriginalPdfPageRect);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
oContext.ConcatCTM ( oPdfPage.GetDrawingTransform ( CGPDFBox.Media, oPdfPageRect, 0, true ) );
oContext.DrawPDFPage (oPdfPage);
CGImage oImage = oContext.ToImage();
UIImage oBackgroundImage = UIImage.FromImage( oImage );
oContext.Dispose();
oImage.Dispose ();
oColorSpace.Dispose ();
UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
oBackgroundImageView.UserInteractionEnabled = false;
oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
return oBackgroundImageView;
}
internal static RectangleF RotateRectangle ( RectangleF oRect, int iRotationAngle )
{
if ( iRotationAngle == 90 || iRotationAngle == 270 )
{
return new RectangleF (oRect.X, oRect.Y, oRect.Height, oRect.Width);
}
return oRect;
}