private PdfSourceRect GetSourceRect(PdfSourceRect rectOnPage, PdfSourceRect pageRect, PdfViewerController.Viewport viewport) { PdfSourceRect pageSubRect; if (rectOnPage == null) { pageSubRect = pageRect; } else { pageSubRect = rectOnPage.Clone(); pageSubRect.Offset(pageRect.dX, pageRect .dY); //yes we have to translate forth and back to ensure that viewport clipping is always done in the exact same manner (rounding errors!) } PdfSourceRect sourceRect = pageSubRect.intersectDouble(viewport.Rectangle.GetSourceRect(viewport.ZoomFactor)); // translate sourcePdfRect, to be relative to page instead of relative to the canvas sourceRect.Offset(-pageRect.dX, -pageRect.dY); // translate origin from top/left to bottom/left sourceRect.dY = pageRect.dHeight - sourceRect.dBottom; return(sourceRect); }
private PdfSourceRect GetSourceFromTargetRect(PdfTargetRect targetRect, PdfSourceRect pageRect, PdfViewerController.Viewport viewport) { PdfTargetRect targetClone = targetRect.Clone(); targetClone.Offset(viewport.Rectangle.iX, viewport.Rectangle.iY); PdfSourceRect sourceRect = targetClone.GetSourceRect(viewport.ZoomFactor); sourceRect.Offset(-pageRect.dX, -pageRect.dY); sourceRect.dY = pageRect.dHeight - sourceRect.dBottom; return(sourceRect); }
// source and targetrects may be empty! (due to crops with pages etc.) public void Draw(WriteableBitmap bitmap, int rotation, IList <KeyValuePair <int, PdfSourceRect> > pageRectsDict, PdfViewerController.Viewport viewport) { Logger.LogInfo("Drawing bitmap"); if (!isOpen) { throw new PdfNoFileOpenedException(); } IList <PdfSourceRect> sourceRects = new List <PdfSourceRect>(); IList <PdfTargetRect> targetRects = new List <PdfTargetRect>(); IList <int> visiblePages = new List <int>(); IList <int> pages = new List <int>(); //The list of pagenumbers for each s/t rect that needs to be drawn IList <int> newPages = new List <int>(); //pages that are completely new drawn and nothing is reused IList <PdfSourceRect> pageRects = new List <PdfSourceRect>(); IList <PdfSourceRect> visibleRectOnPages = new List <PdfSourceRect>(); reusedTargetRects = new List <PdfTargetRect>(); foreach (KeyValuePair <int, PdfSourceRect> keyValuePair in pageRectsDict) { PdfSourceRect pageRect = keyValuePair.Value; int page = keyValuePair.Key; if (!visiblePages.Contains(page)) { visiblePages.Add(page); } // crop the page with viewport //Note that the size of the resulting rectangle may vary depending on viewport/pageRect offsets, due to rounding issues //PdfSourceRect visibleRectOnPage = pageRect.intersectDouble(viewport.Rectangle.GetSourceRect(viewport.ZoomFactor)); PdfTargetRect visibleTargetRect = pageRect.GetTargetRect(viewport.ZoomFactor) .intersectInt(viewport.Rectangle); PdfSourceRect visibleRectOnPage = visibleTargetRect.GetSourceRect(viewport.ZoomFactor); visibleRectOnPage.Offset(-pageRect.dX, -pageRect.dY); bool insertedRectanglesToDraw = false; if (lastBitmap != null && lastRotation == rotation && Math.Abs(lastViewport.ZoomFactor / viewport.ZoomFactor - 1.0) < 0.01) { insertedRectanglesToDraw = CalculateSourceTargetRects(bitmap, rotation, page, pageRect, pages, sourceRects, targetRects, visibleRectOnPage, viewport); } if (!insertedRectanglesToDraw) { //i just have to do the same thing in here as calculateSourceTargetRects would do PdfTargetRect targetRect = GetTargetRect(visibleRectOnPage, pageRect, viewport); sourceRects.Add(GetSourceFromTargetRect(targetRect, pageRect, viewport)); targetRects.Add(targetRect); pages.Add(page); newPages.Add(page); } pageRects.Add(pageRect); visibleRectOnPages.Add(visibleRectOnPage); } int drewThisManyTimes = 0; //DebugLogger.Log("Started drawing of pages " + string.Join(",", pages.Select(i => i.ToString()).ToArray())); for (int i = 0; i < pages.Count; i++) { int p = pages[i]; PdfSourceRect s = sourceRects[i]; PdfTargetRect t = targetRects[i]; //The target may be so small, that we cant see it or it can be horizontally shifted out of the viewport if (t.IsEmpty) { continue; } //draw the content of the sourcerectangle in the pdf to the targetRectangle on the viewer bitmap bitmap.Lock(); Logger.LogInfo("Drawing page " + p + " targetRect=" + t.ToString()); PdfViewerDraw(documentHandle, p, bitmap.PixelWidth, bitmap.PixelHeight, bitmap.BackBuffer, rotation, t.iX, t.iY, t.iWidth, t.iHeight, s.dX, s.dY, s.dWidth, s.dHeight, TPdfViewerModelPixelOrder.ePdfViewerModelPixelOrderBGRA); drewThisManyTimes++; Logger.LogInfo("Finished drawing page " + p); bitmap.AddDirtyRect(t.GetInt32Rect()); bitmap.Unlock(); } lastBitmap = bitmap; lastVisiblePages = visiblePages; lastPageRects = pageRects; lastRotation = rotation; lastViewport = viewport; lastVisibleRectOnPages = visibleRectOnPages; //DebugLogger.Log("Finished drawing of pages " + string.Join(",", pages.Select(i => i.ToString()).ToArray())); //visualizeDraw(bitmap.Clone(), rotation, pages, sourceRects, targetRects, newPages); Logger.LogInfo("Drew bitmap using " + drewThisManyTimes + " native calls"); }
private void CalculateCanvas() { if (canvasDirty == TCanvasDirtyness.Clean) { return; } int start = 1, end = PageCount; //If we are in a mode which doesnt show all pages, we only need to go through the shown ones if (!PdfUtils.PageLayoutScrollingEnabled(PageLayoutMode)) { switch (PdfUtils.HorizontalPagePosition(PageLayoutMode, PageNo)) { case -1: { start = PageNo; end = Math.Min(PageNo + 1, end); //because PageNo + 1 doesn't necessarily exist in this case break; } case 0: { start = PageNo; end = PageNo; break; } case 1: { start = PageNo - 1; //pageNo-1 always exists in this case end = PageNo; break; } } } int changedPage = int.MaxValue; PdfSourceRect oldCanvasRect = _canvasRect.Clone(); bool entireCanvasDirty = (canvasDirty == TCanvasDirtyness.CanvasDirty); canvasDirty = TCanvasDirtyness.Clean; if (entireCanvasDirty) { _canvasRect.dWidth = 0.0; _canvasRect.dX = 0.0; } double offset = 0.0; int page = entireCanvasDirty ? start : Math.Max(start, GetNextRelevantPage(start, end)); for (; page <= end; page++) { PdfSourceRect rect = null; if (pagesToLoadExactly.Remove(page)) { Logger.LogInfo("page " + page + " was loaded exactly"); //load page exactly rect = documentManager.GetPageRect(page); } else { rect = documentManager.GetPageRectGuess(page); } int nPage; lock (newlyLoadedPagesLock) { nPage = newlyLoadedPages.FirstOrDefault(number => number >= start && number <= end); } if (!entireCanvasDirty && nPage > 1 && nPage < page) { //maybe the getting of pages has getted a page before this one (due to predictionAlgorithm). In this case, consider this page first page = nPage; rect = documentManager.GetPageRectGuess(page); } bool removed = false; lock (newlyLoadedPagesLock) { removed = newlyLoadedPages.Remove(page); } if (removed || entireCanvasDirty)//If the page is newly loaded, calculate its position exactly. Also if the entire canvas is dirty, calculate always { changedPage = Math.Min(changedPage, page); //position the page newly, knowing that its the first time we know its exact size switch (PdfUtils.HorizontalPagePosition(PageLayoutMode, page)) { case 0: { //place 1 page rect.dCenterX = 0.0; rect.dY = GetPreviousBottom(page, start, end) + _borderSize; if (rect.dX - _borderSize < _canvasRect.dX) { _canvasRect.dWidth += _canvasRect.dX - (rect.dX - _borderSize); _canvasRect.dX = rect.dX - _borderSize; } if (rect.dRight + _borderSize > _canvasRect.dRight) { _canvasRect.dWidth += rect.dRight + _borderSize - _canvasRect.dRight; } offset = rect.dBottom + _borderSize - GetNextTop(page, start, end); break; } case -1: { //place left page rect.dRight = 0.0 - _borderSize / 2.0; rect.dY = Math.Max(GetPreviousBottom(page, start, end), GetPreviousBottom(page - 1, start, end)) + _borderSize; if (rect.dX - _borderSize < _canvasRect.dX) { _canvasRect.dWidth += _canvasRect.dX - (rect.dX - _borderSize); _canvasRect.dX = rect.dX - _borderSize; } offset = rect.dY - GetNextTop(page, start, end); break; } default: { //place right page rect.dX = 0.0 + _borderSize / 2.0; rect.dY = documentManager.GetPageRectGuess(page - 1).dY; if (rect.dRight + _borderSize > _canvasRect.dRight) { _canvasRect.dWidth += rect.dRight + _borderSize - _canvasRect.dRight; } offset = Math.Max(GetPreviousBottom(page, start, end), rect.dBottom) + _borderSize - GetNextTop(page, start, end); break; } } } else { //Only pages that are not newly loaded make it here. Adjust their offset if (offset == 0.0) { //if there is no offset, we dont need to do anything until we hit a page that needs to be loaded anew page = GetNextRelevantPage(start, end); if (page == int.MaxValue) { break;//there is no more page to load -> stop iterating through pages } page--; continue; } rect.Offset(0.0, offset); } }//end for-loop //we have loaded and positioned all pages, now we only need to resize the canvas lock (newlyLoadedPagesLock) { if (newlyLoadedPages.Count == 0 && pagesToLoadExactly.Count == 0) { canvasDirty = TCanvasDirtyness.Clean; } } if (PdfUtils.HorizontalPagePosition(PageLayoutMode, end) == -1) { offset = documentManager.GetPageRectGuess(end).dBottom + _borderSize - _canvasRect.dBottom; } if (offset != 0.0) { _canvasRect.dHeight += offset; CanvasRectChanged(oldCanvasRect, _canvasRect, changedPage); } return; }