using ComPDFKit.Viewer.Layer; using ComPDFKitViewer.Helper; using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace ComPDFKit.Tool.DrawTool { internal class FrameSelectTool : CustomizeLayer { #region Attributes /// /// Indicates whether proportional scaling is required /// protected bool isProportionalScaling { get; set; } = false; /// /// Mouse start point /// protected Point mouseStartPoint { get; set; } /// /// Mouse end point /// protected Point mouseEndPoint { get; set; } /// /// Crop point /// protected Point cropPoint { get; set; } /// ///Is drawing annotation /// protected bool isFrameSelect { get; set; } /// /// Current zoom factor /// private double zoomFactor { get; set; } = 1; /// /// Draw rectangle /// protected Rect drawRect { get; set; } = new Rect(); /// /// The rectangle representing the maximum drawing area /// protected Rect maxRect { get; set; } /// /// The rectangle representing the original page range (calculated offset in continuous mode) /// protected Rect pageBound { get; set; } /// /// The rectangle at standard DPI (without subtracting half of the pen thickness) /// protected Rect DPIRect { get; set; } /// /// The offset value during movement /// protected Point moveOffset { get; set; } = new Point(0, 0); /// /// The offset value during movement /// protected int pageIndex { get; set; } = -1; protected DrawingContext drawDC { get; set; } /// /// The collection of points measured for annotation drawing /// protected PointCollection drawPoints { get; set; } = new PointCollection(); protected double textPadding { get; set; } = 10; protected Border lastTextBorder; #endregion public FrameSelectTool() { } public Point GetStartPoint() { return DpiHelper.StandardPointToPDFPoint(new Point((mouseStartPoint.X - pageBound.X + (cropPoint.X * zoomFactor)) / zoomFactor, (mouseStartPoint.Y - pageBound.Y + (cropPoint.Y * zoomFactor)) / zoomFactor)); } public Point GetEndPoint() { if (moveOffset == new Point()) { return new Point(-1, -1); } else { return DpiHelper.StandardPointToPDFPoint(new Point((mouseEndPoint.X - pageBound.X + (cropPoint.X * zoomFactor)) / zoomFactor, (mouseEndPoint.Y - pageBound.Y + (cropPoint.Y * zoomFactor)) / zoomFactor)); } } public double GetMoveLength() { if (mouseEndPoint == new Point()) { return 0; } Point checkPoint = mouseEndPoint; checkPoint.X = Math.Max(pageBound.Left, checkPoint.X); checkPoint.X = Math.Min(pageBound.Right, checkPoint.X); checkPoint.Y = Math.Max(pageBound.Top, checkPoint.Y); checkPoint.Y = Math.Min(pageBound.Bottom, checkPoint.Y); Vector moveOffset = checkPoint - mouseStartPoint; return moveOffset.Length; } public void SetIsProportionalScaling(bool isOpen) { isProportionalScaling = isOpen; } #region Draw public void StartDraw(Point downPoint, Rect maxRect, Rect pageBound, double zoom, int pageindex) { this.pageBound = pageBound; pageIndex = pageindex; isFrameSelect = true; drawRect = new Rect(); DPIRect = new Rect(); mouseStartPoint = downPoint; isFrameSelect = true; this.maxRect = maxRect; zoomFactor = zoom; moveOffset = new Point(); DPIRect = new Rect(); } bool noDraw=false; public void MoveDraw(Point downPoint, double zoom) { if (isFrameSelect) { noDraw = true; moveOffset = new Point( mouseEndPoint.X - downPoint.X, mouseEndPoint.Y - downPoint.Y ); mouseEndPoint = downPoint; zoomFactor = zoom; Draw(); } noDraw = false; } public Rect EndDraw(ref int index) { if (noDraw && isFrameSelect) { new Rect(); } if (!DPIRect.Equals(new Rect())) { Rect StandardRect = new Rect( (DPIRect.Left - pageBound.X + (cropPoint.X * zoomFactor)) / zoomFactor, (DPIRect.Top - pageBound.Y + (cropPoint.Y * zoomFactor)) / zoomFactor, DPIRect.Width / zoomFactor, DPIRect.Height / zoomFactor); isFrameSelect = false; noDraw = false; mouseStartPoint = new Point(); mouseEndPoint = new Point(); moveOffset = new Point(); pageBound = new Rect(); DPIRect = new Rect(); drawPoints.Clear(); ClearDraw(); index = pageIndex; return DpiHelper.StandardRectToPDFRect(StandardRect); } isFrameSelect = false; noDraw = false; return new Rect(); } public override void Draw() { if (noDraw&& isFrameSelect) { Dispatcher.Invoke(() => { drawDC = Open(); DrawSquare(drawDC); Present(); }); } } public virtual void ClearDraw() { Open(); Present(); } private void DrawSquare(DrawingContext drawingContext) { try { Pen DrawPen = new Pen(new SolidColorBrush(Color.FromRgb(71, 126, 222)), 2); SolidColorBrush FillBrush = new SolidColorBrush(Colors.Transparent); FillBrush = new SolidColorBrush(Color.FromArgb(0, 255, 255, 255)); if (isProportionalScaling) { Point mouseOffset = (Point)(mouseStartPoint - mouseEndPoint); if (mouseOffset.X < 0) { if (mouseOffset.Y > 0) { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseStartPoint.X - mouseEndPoint.X); } else { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseEndPoint.X - mouseStartPoint.X); } } else { if (mouseOffset.Y > 0) { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseEndPoint.X - mouseStartPoint.X); } else { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseStartPoint.X - mouseEndPoint.X); } } } Rect rect = new Rect(mouseStartPoint, mouseEndPoint); double mLeft = rect.Left; double mRight = rect.Right; double mUp = rect.Top; double mDown = rect.Bottom; if (rect.Left < maxRect.Left) { mLeft = maxRect.Left; } if (rect.Right > maxRect.Right) { mRight = maxRect.Right; } if (rect.Top < maxRect.Top) { mUp = maxRect.Top; } if (rect.Bottom > maxRect.Bottom) { mDown = maxRect.Bottom; } DPIRect = new Rect(mLeft, mUp, mRight - mLeft, mDown - mUp); int halfPenWidth = (int)Math.Ceiling(DrawPen.Thickness / 2); double drawWidth = DPIRect.Width - halfPenWidth * 2; double drawHeight = DPIRect.Height - halfPenWidth * 2; if (drawWidth > 0 && drawHeight > 0) { drawRect = new Rect( (int)DPIRect.Left + halfPenWidth, (int)DPIRect.Top + halfPenWidth, (int)DPIRect.Width - halfPenWidth * 2, (int)DPIRect.Height - halfPenWidth * 2); drawingContext?.DrawRectangle(null, DrawPen, drawRect); halfPenWidth = (int)Math.Floor(DrawPen.Thickness / 2); if (drawRect.Width - halfPenWidth * 2 > 0 && drawRect.Height - halfPenWidth * 2 > 0) { Rect innerRect = new Rect(drawRect.Left + halfPenWidth, drawRect.Top + halfPenWidth, drawRect.Width - 2 * halfPenWidth, drawRect.Height - 2 * halfPenWidth); drawingContext?.DrawRectangle(FillBrush, null, innerRect); } } else { drawRect = new Rect(); } } catch { } } public Rect GetMaxRect() { return maxRect; } /// /// Use to calculate the point drawn at a fixed angle /// /// /// Current point /// /// /// Start point /// /// /// Maximum drawing area /// /// /// Return the calculated point /// internal Point CalcAnglePoint(Point currentPoint, Point startPoint, Rect pageBound) { Vector angleVector = currentPoint - startPoint; Point originPoint = new Point(startPoint.X, startPoint.Y - angleVector.Length); Vector orignVector = originPoint - startPoint; Rect checkRect = pageBound; int angle = (int)Vector.AngleBetween(orignVector, angleVector); if (angle < 0) { angle += 360; } int mod = angle % 45; int quot = angle / 45; Point anglePoint = currentPoint; int rotateAngle = 0; if (mod < 22) { Matrix rotateMatrix = new Matrix(); rotateAngle = quot * 45; rotateMatrix.RotateAt(rotateAngle, startPoint.X, startPoint.Y); anglePoint = rotateMatrix.Transform(originPoint); anglePoint = new Point((int)anglePoint.X, (int)anglePoint.Y); } else { Matrix rotateMatrix = new Matrix(); rotateAngle = (quot + 1) * 45; rotateMatrix.RotateAt(rotateAngle, startPoint.X, startPoint.Y); anglePoint = rotateMatrix.Transform(originPoint); anglePoint = new Point((int)anglePoint.X, (int)anglePoint.Y); } if (checkRect.Contains(anglePoint) == false) { switch (rotateAngle) { case 0: { anglePoint.X = startPoint.X; anglePoint.Y = Math.Max(checkRect.Top, Math.Min(anglePoint.Y, startPoint.Y)); } break; case 45: { double addValue = Math.Min(anglePoint.X - startPoint.X, checkRect.Right - startPoint.X); addValue = Math.Min(addValue, startPoint.Y - checkRect.Top); anglePoint.X = startPoint.X + addValue; anglePoint.Y = startPoint.Y - addValue; } break; case 90: { anglePoint.X = startPoint.X + Math.Min(anglePoint.X - startPoint.X, checkRect.Right - startPoint.X); anglePoint.Y = startPoint.Y; } break; case 135: { double addValue = Math.Min(anglePoint.X - startPoint.X, checkRect.Right - startPoint.X); addValue = Math.Min(addValue, checkRect.Bottom - startPoint.Y); anglePoint.X = startPoint.X + addValue; anglePoint.Y = startPoint.Y + addValue; } break; case 180: { anglePoint.X = startPoint.X; anglePoint.Y = Math.Min(anglePoint.Y, checkRect.Bottom); } break; case 225: { double addValue = Math.Min(startPoint.X - anglePoint.X, startPoint.X - checkRect.Left); addValue = Math.Min(addValue, checkRect.Bottom - startPoint.Y); anglePoint.X = startPoint.X - addValue; anglePoint.Y = startPoint.Y + addValue; } break; case 270: { anglePoint.X = startPoint.X - Math.Min(startPoint.X - anglePoint.X, startPoint.X - checkRect.Left); anglePoint.Y = startPoint.Y; } break; case 315: { double addValue = Math.Min(startPoint.X - anglePoint.X, startPoint.X - checkRect.Left); addValue = Math.Min(addValue, startPoint.Y - checkRect.Top); anglePoint.X = startPoint.X - addValue; anglePoint.Y = startPoint.Y - addValue; } break; case 360: { anglePoint.X = startPoint.X; anglePoint.Y = Math.Max(checkRect.Top, Math.Min(anglePoint.Y, startPoint.Y)); } break; default: break; } } return anglePoint; } } #endregion }