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); }
public PdfSourceRect RectOnCanvas(PdfSourceRect pageRect, PdfViewerController.Viewport viewport) { PdfSourceRect rect = viewport.Rectangle.GetSourceRect(viewport.ZoomFactor); double left = Double.IsNaN(this.left) ? rect.dX : (this.left + pageRect.dX); double top = (Double.IsNaN(this.top) || this.top == -32768) ? pageRect.dY : (pageRect.dBottom - this.top); double width = Double.IsNaN(this.right) ? rect.dRight - left : this.right - left; double height = Double.IsNaN(this.bottom) ? (rect.dBottom - top) : (this.bottom - top); return(new PdfSourceRect(left, top, Math.Max(width, 0.0), Math.Max(height, 0.0))); }
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); }
//we ought to ensure, that the size of the resulting target rect is independent of the viewport offset //the problem is, that sometimes the rectOnPage is not entirely within the viewport and it thus gets cropped a bit by one of the viewports, yielding inconsistent size private PdfTargetRect GetTargetRect(PdfSourceRect rectOnPage, PdfSourceRect pageRect, PdfViewerController.Viewport viewport) { PdfSourceRect pageSubRect; if (rectOnPage == null) { pageSubRect = pageRect; } else { pageSubRect = rectOnPage.Clone(); pageSubRect.Offset(pageRect.dX, pageRect.dY); } PdfTargetRect targetRect = pageSubRect.GetTargetRect(viewport.ZoomFactor); targetRect = targetRect.intersectInt(viewport.Rectangle); targetRect.Offset(-viewport.Rectangle.iX, -viewport.Rectangle.iY); //Subtract the offset of the viewportPdfRectangle on the Canvas. This way we get coordinats in relation to the viewport return(targetRect); }
// 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 PdfTargetRect GetTargetRect(PdfSourceRect pageRect, PdfViewerController.Viewport viewport) { return(GetTargetRect(null, pageRect, viewport)); }
/// <returns>Whether the page has been drawn or queued to lists for drawing. Returns false if no valid information about previous drawRequest</returns> private bool CalculateSourceTargetRects(WriteableBitmap bitmap, int rotation, int page, PdfSourceRect pageRect, IList <int> pages, IList <PdfSourceRect> sourceRects, IList <PdfTargetRect> targetRects, PdfSourceRect visibleRectOnPage, PdfViewerController.Viewport viewport) { if (!lastVisiblePages.Contains(page) || visibleRectOnPage.IsEmpty) { return(false); } int lastIndex = lastVisiblePages.IndexOf(page); PdfSourceRect reusableRectOnPage = lastVisibleRectOnPages[lastIndex].intersectDouble(visibleRectOnPage); PdfTargetRect reusableTargetRect, reusableTargetRectOnLastBitmap; while (true) { reusableTargetRect = GetTargetRect(reusableRectOnPage, pageRect, viewport); reusableTargetRectOnLastBitmap = GetTargetRect(reusableRectOnPage, lastPageRects[lastIndex], lastViewport); if (reusableTargetRectOnLastBitmap.IsEmpty) { return(false); //if we cant reuse anything, there is nothing to do } if (reusableTargetRect.iWidth != reusableTargetRectOnLastBitmap.iWidth || reusableTargetRect.iHeight != reusableTargetRectOnLastBitmap.iHeight) { //Console.WriteLine("Inconsistent reusableTargetRect sizes: {0} vs. {1} and {2} vs. {3}", reusableTargetRect.iWidth, reusableTargetRectOnLastBitmap.iWidth, reusableTargetRect.iHeight, reusableTargetRectOnLastBitmap.iHeight); reusableRectOnPage.Shrink(0.99); } else { break; } } reusedTargetRects.Add(reusableTargetRect); //calculate the area to copy int bytesPerPixel = (lastBitmap.Format.BitsPerPixel + 7) / 8; int stride = reusableTargetRectOnLastBitmap.iWidth * bytesPerPixel; byte[] pixels = new byte[reusableTargetRectOnLastBitmap.iWidth * reusableTargetRectOnLastBitmap.iHeight * bytesPerPixel]; //read from last bitmap lastBitmap.CopyPixels(reusableTargetRectOnLastBitmap.GetInt32Rect(), pixels, stride, 0); //(lastBitmap.PixelWidth * (reusableTargetRectOnLastBitmap.iY - 1) + reusableTargetRectOnLastBitmap.iX - 1) * bytesPerPixel); //write to new bitmap bitmap.Lock(); bitmap.WritePixels(reusableTargetRect.GetInt32Rect(), pixels, stride, 0); bitmap.AddDirtyRect(reusableTargetRect.GetInt32Rect()); bitmap.Unlock(); //calculate rects that need to be drawn newly IList <PdfTargetRect> targetDifs = GetTargetRect(pageRect, viewport).subtractRect(reusableTargetRect); for (int i = 0; i < 4; i++) { PdfTargetRect targetRect = targetDifs[i]; if (targetRect.IsEmpty) { continue; } PdfSourceRect sourceRect = GetSourceFromTargetRect(targetRect, pageRect, viewport); targetRects.Add(targetRect); sourceRects.Add(sourceRect); pages.Add(page); } return(true); }
// source and targetrects may be empty! (due to crops with pages etc.) public PdfDrawRequest Draw(int width, int height, Resolution resolution, int rotation, IDictionary <int, PdfSourceRect> pageRects, PdfViewerController.Viewport viewport) { IList <KeyValuePair <int, PdfSourceRect> > newPageRects = new List <KeyValuePair <int, PdfSourceRect> >(); foreach (int key in pageRects.Keys) { int newKey; if (key - 1 < _pageOrder.Count) { newKey = _pageOrder[key - 1]; } else { continue; } if (newKey > document.PageCount) { continue; } newPageRects.Add(new KeyValuePair <int, PdfSourceRect>(newKey, pageRects[key])); } PdfDrawRequest request = new PdfDrawRequest(new DrawArgs(width, height, resolution, rotation, newPageRects, viewport)); if (lastDrawRequest == null) { requestQueue.Add(request); } else { requestQueue.Replace(lastDrawRequest, request); } lastDrawRequest = request; //add new draw request return(request); }
public DrawArgs(int bitmapWidth, int bitmapHeight, Resolution resolution, int rotation, IList <KeyValuePair <int, PdfSourceRect> > pageRects, PdfViewerController.Viewport viewport) { this.bitmapWidth = bitmapWidth; this.bitmapHeight = bitmapHeight; this.resolution = resolution; this.rotation = rotation; this.pageRects = pageRects; this.viewport = viewport; }