/// <summary> /// Create a new letter to represent some text drawn by the Tj operator. /// </summary> public Letter(string value, PdfRectangle glyphRectangle, PdfPoint startBaseLine, PdfPoint endBaseLine, double width, double fontSize, FontDetails font, IColor color, double pointSize, int textSequence) { Value = value; GlyphRectangle = glyphRectangle; StartBaseLine = startBaseLine; EndBaseLine = endBaseLine; Width = width; FontSize = fontSize; Font = font; Color = color ?? GrayColor.Black; PointSize = pointSize; TextSequence = textSequence; TextOrientation = GetTextOrientation(); }
/// <summary> /// Create a new letter to represent some text drawn by the Tj operator. /// </summary> internal Letter(string value, PdfRectangle glyphRectangle, PdfPoint startBaseLine, PdfPoint endBaseLine, double width, double fontSize, string fontName, IColor color, double pointSize, int textSequence) { Value = value; GlyphRectangle = glyphRectangle; StartBaseLine = startBaseLine; EndBaseLine = endBaseLine; Width = width; FontSize = fontSize; FontName = fontName; Color = color ?? GrayColor.Black; PointSize = pointSize; TextSequence = textSequence; TextDirection = GetTextDirection(); }
public static void Main() { // NOTE: // When used in trial mode, the library imposes some restrictions. // Please visit http://bitmiracle.com/pdf-library/trial-restrictions.aspx // for more information. string pathToFile = "TextMarkupAnnotations.pdf"; using (PdfDocument pdf = new PdfDocument()) { PdfPage page = pdf.Pages[0]; PdfCanvas canvas = page.Canvas; // Draw text on the page const string Text = "Highlighted text"; PdfPoint textPosition = new PdfPoint(10, 50); canvas.FontSize = 30; canvas.DrawString(textPosition, Text); // Get size of the drawn text PdfSize size = canvas.MeasureText(Text); var bounds = new PdfRectangle(textPosition, size); // Highlight and annotate the text var color = new PdfRgbColor(0, 0, 255); const string AnnotationContents = "Lorem ipsum"; page.AddHighlightAnnotation(AnnotationContents, bounds, color); // Or call these method to strike out or underline the text: // page.AddStrikeoutAnnotation(AnnotationContents, bounds, color); // page.AddJaggedUnderlineAnnotation(AnnotationContents, bounds, color); // page.AddUnderlineAnnotation(AnnotationContents, bounds, color); pdf.Save(pathToFile); } Process.Start(pathToFile); }
internal void boxPrint(PdfPoint upperLeftCorner, PdfSize size, PrintBackground background) { if (_top != null) { background.DrawLineHorizontal(_top, upperLeftCorner + new PdfSize(0, -_top.LineWidth.pnts / 2), size.width); } if (_left != null) { background.DrawLineVertical(_left, upperLeftCorner + new PdfSize(_left.LineWidth.pnts / 2, 0), size.height); } if (_right != null) { background.DrawLineVertical(_right, upperLeftCorner + new PdfSize(size.width.pnts - _right.LineWidth.pnts / 2, 0), size.height); } if (_bottom != null) { background.DrawLineHorizontal(_bottom, upperLeftCorner + new PdfSize(0, size.height.pnts + _bottom.LineWidth.pnts / 2), size.width); } }
private static void sortWords(List <PdfTextData> words, PdfMatrix transformation) { // For some transformations we should invert X coordinates during sorting. PdfPoint xAxis = transformVector(transformation, 1, 0); PdfPoint yAxis = transformVector(transformation, 0, 1); int xDirection = 1; // Happens when space is rotated on 90 or 270 degrees if (Math.Abs(xAxis.X) < 0.0001) { // Happens when transformed coordinates fall to 2nd or 4th quarter. // y // ^ // 2nd | 1st // | // ------------------> x // | // 3rd | 4th // | // if (Math.Sign(xAxis.Y) != Math.Sign(yAxis.X)) { xDirection = -1; } } words.Sort((x, y) => { double yDiff = measureVerticalDistance(x.Position, y.Position, transformation); if (Math.Abs(yDiff) > 0.0001) { return(yDiff.CompareTo(0)); } double xDiff = measureHorizontalDistance(x.Position, y.Position, transformation); return((xDiff * xDirection).CompareTo(0)); }); }
private void ShowGlyph(IFont font, PdfRectangle glyphRectangle, PdfPoint startBaseLine, PdfPoint endBaseLine, decimal width, string unicode, decimal fontSize, IColor color, decimal pointSize, int textSequence) { var letter = new Letter(unicode, glyphRectangle, startBaseLine, endBaseLine, width, fontSize, font.Name.Data, color, pointSize, textSequence); letters.Add(letter); }
/// <summary> /// Douglases the peucker reduction. /// </summary> /// <param name="points">The points.</param> /// <param name="firstIndex">The first point index.</param> /// <param name="lastIndex">The last point index.</param> /// <param name="tolerance">The tolerance.</param> /// <param name="indexesToKeep">The points' index to keep.</param> private static void Reduce(PdfPoint[] points, int firstIndex, int lastIndex, double tolerance, ref List <int> indexesToKeep) { double maxDistance = 0; int indexFarthest = 0; unsafe { fixed(PdfPoint *samples = points) { PdfPoint point1 = *(samples + firstIndex); PdfPoint point2 = *(samples + lastIndex); double distXY = (double)point1.X * (double)point2.Y - (double)point2.X * (double)point1.Y; double distX = (double)point2.X - (double)point1.X; double distY = (double)point1.Y - (double)point2.Y; double bottom = distX * distX + distY * distY; for (int index = firstIndex; index < lastIndex; index++) { PdfPoint point = *(samples + index); double area = distXY + distX * (double)point.Y + distY * (double)point.X; double distance = (area / bottom) * area; if (distance > maxDistance) { maxDistance = distance; indexFarthest = index; } } } } if (maxDistance > tolerance && indexFarthest != 0) { //Add the largest point that exceeds the tolerance indexesToKeep.Add(indexFarthest); Reduce(points, firstIndex, indexFarthest, tolerance, ref indexesToKeep); Reduce(points, indexFarthest, lastIndex, tolerance, ref indexesToKeep); } }
public static void Run(string trueTypeFontPath, string jpgImagePath) { var builder = new PdfDocumentBuilder { ArchiveStandard = PdfAStandard.A2A }; var font = builder.AddTrueTypeFont(File.ReadAllBytes(trueTypeFontPath)); var page = builder.AddPage(PageSize.A4); var pageTop = new PdfPoint(0, page.PageSize.Top); var letters = page.AddText("This is some text added to the output file near the top of the page.", 12, pageTop.Translate(20, -25), font); var bottomOfText = letters.Min(x => x.GlyphRectangle.Bottom); var imagePlacement = new PdfRectangle(new PdfPoint(50, bottomOfText - 200), new PdfPoint(150, bottomOfText)); page.AddJpeg(File.ReadAllBytes(jpgImagePath), imagePlacement); var fileBytes = builder.Build(); try { var location = AppDomain.CurrentDomain.BaseDirectory; var output = Path.Combine(location, "outputOfPdfA2A.pdf"); File.WriteAllBytes(output, fileBytes); Console.WriteLine($"File output to: {output}"); } catch (Exception ex) { Console.WriteLine($"Failed to write output to file due to error: {ex}."); } }
private static void CreatePolygonAnnotations(PdfFixedDocument document, PdfFont font) { PdfBrush blackBrush = new PdfBrush(); PdfPage page = document.Pages.Add(); page.Graphics.DrawString("Polygon annotations", font, blackBrush, 50, 50); int[] vertices = new int[] { 3, 4, 5, 6 }; double centerY = 125, centerX = 150; double radius = 50; for (int i = 0; i < vertices.Length; i++) { PdfPoint[] points = new PdfPoint[vertices[i]]; double angle = 90; double rotation = 360 / vertices[i]; for (int j = 0; j < vertices[i]; j++) { points[j] = new PdfPoint(); points[j].X = centerX + radius * Math.Cos(Math.PI * angle / 180); points[j].Y = centerY - radius * Math.Sin(Math.PI * angle / 180); angle = angle + rotation; } PdfPolygonAnnotation polygon = new PdfPolygonAnnotation(); page.Annotations.Add(polygon); polygon.Author = "Xfinium.Pdf"; polygon.Contents = "Polygon annotation with " + vertices[i] + " vertices."; polygon.Points = points; polygon.LineColor = new PdfRgbColor(192, 0, 0); polygon.LineWidth = 3; polygon.InteriorColor = new PdfRgbColor(0, 0, 192); centerY = centerY + 150; } }
/// <summary> /// Draws a rectangle on the current page starting at the specified point with the given width, height and line width. /// </summary> /// <param name="position">The position of the rectangle, for positive width and height this is the bottom-left corner.</param> /// <param name="width">The width of the rectangle.</param> /// <param name="height">The height of the rectangle.</param> /// <param name="lineWidth">The width of the line border of the rectangle.</param> /// <param name="fill">Whether to fill with the color set by <see cref="SetTextAndFillColor"/>.</param> public void DrawRectangle(PdfPoint position, decimal width, decimal height, decimal lineWidth = 1, bool fill = false) { if (lineWidth != 1) { currentStream.Add(new SetLineWidth(lineWidth)); } currentStream.Add(new AppendRectangle((decimal)position.X, (decimal)position.Y, width, height)); if (fill) { currentStream.Add(FillPathEvenOddRuleAndStroke.Value); } else { currentStream.Add(StrokePath.Value); } if (lineWidth != 1) { currentStream.Add(new SetLineWidth(lineWidth)); } }
public void CanWriteTwoPageDocument() { var builder = new PdfDocumentBuilder(); var page1 = builder.AddPage(PageSize.A4); var page2 = builder.AddPage(PageSize.A4); var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf")); var topLine = new PdfPoint(30, page1.PageSize.Height - 60); var letters = page1.AddText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", 9, topLine, font); page1.AddText("incididunt ut labore et dolore magna aliqua.", 9, new PdfPoint(30, topLine.Y - letters.Max(x => x.GlyphRectangle.Height) - 5), font); var page2Letters = page2.AddText("The very hungry caterpillar ate all the apples in the garden.", 12, topLine, font); var left = (decimal)page2Letters[0].GlyphRectangle.Left; var bottom = (decimal)page2Letters.Min(x => x.GlyphRectangle.Bottom); var right = (decimal)page2Letters[page2Letters.Count - 1].GlyphRectangle.Right; var top = (decimal)page2Letters.Max(x => x.GlyphRectangle.Top); page2.SetStrokeColor(10, 250, 69); page2.DrawRectangle(new PdfPoint(left, bottom), right - left, top - bottom); var bytes = builder.Build(); WriteFile(nameof(CanWriteTwoPageDocument), bytes); using (var document = PdfDocument.Open(bytes)) { var page1Out = document.GetPage(1); Assert.StartsWith("Lorem ipsum dolor sit", page1Out.Text); var page2Out = document.GetPage(2); Assert.StartsWith("The very hungry caterpillar", page2Out.Text); } }
/// <summary> /// Draws the text in the provided font at the specified position and returns the letters which will be drawn. /// </summary> /// <param name="text">The text to draw to the page.</param> /// <param name="fontSize">The size of the font in user space units.</param> /// <param name="position">The position of the baseline (lower-left corner) to start drawing the text from.</param> /// <param name="font"> /// A font added to the document using <see cref="PdfDocumentBuilder.AddTrueTypeFont"/> /// or <see cref="PdfDocumentBuilder.AddStandard14Font"/> methods. /// </param> /// <returns>The letters from the input text with their corresponding size and position.</returns> public IReadOnlyList <Letter> AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font) { if (font == null) { throw new ArgumentNullException(nameof(font)); } if (text == null) { throw new ArgumentNullException(nameof(text)); } if (!documentBuilder.Fonts.TryGetValue(font.Id, out var fontProgram)) { throw new ArgumentException($"No font has been added to the PdfDocumentBuilder with Id: {font.Id}. " + $"Use {nameof(documentBuilder.AddTrueTypeFont)} to register a font.", nameof(font)); } if (fontSize <= 0) { throw new ArgumentOutOfRangeException(nameof(fontSize), "Font size must be greater than 0"); } var fm = fontProgram.GetFontMatrix(); var textMatrix = TransformationMatrix.FromValues(1, 0, 0, 1, position.X, position.Y); var letters = DrawLetters(text, fontProgram, fm, fontSize, textMatrix); operations.Add(BeginText.Value); operations.Add(new SetFontAndSize(font.Name, fontSize)); operations.Add(new MoveToNextLineWithOffset(position.X, position.Y)); operations.Add(new ShowText(text)); operations.Add(EndText.Value); return(letters); }
/// <summary> /// Create a new <see cref="PdfRectangle"/>. /// </summary> public PdfRectangle(decimal x1, decimal y1, decimal x2, decimal y2) { decimal bottom; decimal top; if (y1 <= y2) { bottom = y1; top = y2; } else { bottom = y2; top = y1; } decimal left; decimal right; if (x1 <= x2) { left = x1; right = x2; } else { left = x2; right = x1; } TopLeft = new PdfPoint(left, top); TopRight = new PdfPoint(right, top); BottomLeft = new PdfPoint(left, bottom); BottomRight = new PdfPoint(right, bottom); }
/// <summary> /// Create a new <see cref="PdfRectangle"/>. /// </summary> public PdfRectangle(double x1, double y1, double x2, double y2) { double bottom; double top; if (y1 <= y2) { bottom = y1; top = y2; } else { bottom = y2; top = y1; } double left; double right; if (x1 <= x2) { left = x1; right = x2; } else { left = x2; right = x1; } TopLeft = new PdfPoint(left, top); TopRight = new PdfPoint(right, top); BottomLeft = new PdfPoint(left, bottom); BottomRight = new PdfPoint(right, bottom); }
public void DrawLineHorizontal(PdfStyleLine lineStyle, PdfPoint begin, PdfDistance length) { if (lineStyle is null) { throw new ArgumentNullException(nameof(lineStyle)); } if (_horizontalLines == null) { _horizontalLines = new Lines(); } _horizontalLines.Add(lineStyle, begin, new PdfPoint(begin.x + length, begin.y)); }
public Line(PdfStyleLine lineStyle, PdfPoint begin, PdfPoint end) { this.LineStyle = lineStyle; this.Begin = begin; this.End = end; }
public void DrawLineDiagonal(PdfStyleLine lineStyle, PdfPoint begin, PdfSize size) { if (lineStyle is null) { throw new ArgumentNullException(nameof(lineStyle)); } if (_diagonalLines == null) { _diagonalLines = new Lines(); } _diagonalLines.Add(new Line(lineStyle, begin, begin + size)); }
/// <summary> /// Create a new <see cref="PdfLine"/>. /// </summary> /// <param name="point1">First point of the line.</param> /// <param name="point2">Second point of the line.</param> public PdfLine(PdfPoint point1, PdfPoint point2) { Point1 = point1; Point2 = point2; }
public AppendEndControlPointBezierCurve(decimal x1, decimal y1, decimal x3, decimal y3) { ControlPoint1 = new PdfPoint(x1, y1); End = new PdfPoint(x3, y3); }
public bool GetWordAtPosition(PdfPoint location, double xTolerance, double yTolerance, out PdfTextSpan span) { return(_document.GetWordAtPosition(location, xTolerance, yTolerance, out span)); }
/// <summary> /// The absolute distance between the X coordinates of two points. /// </summary> /// <param name="point1">The first point.</param> /// <param name="point2">The second point.</param> /// <returns></returns> public static double Horizontal(PdfPoint point1, PdfPoint point2) { return(Math.Abs((double)(point2.X - point1.X))); }
public void DisplayPaths() { if (PagePlotModel == null) { return; } foreach (var s in PagePlotModel.Series.Where(s => (string)s.Tag == "pdfpath").ToList()) { PagePlotModel.Series.Remove(s); } foreach (var path in _pdfPageModel.GetPdfPaths()) { foreach (var sp in path) { string title = ("path: " + (path.IsStroked ? "stroked " + (path.StrokeColor?.ToRGBValues()).ToString() : "") + (path.IsFilled ? "filled " + (path.FillColor?.ToRGBValues()).ToString() : "") + (path.IsClipping ? "clipping" : "") ).Trim(); var series1 = new LineSeries { Tag = "pdfpath", Title = title, LineStyle = LineStyle.Solid, Color = OxyColors.Yellow }; PdfPoint first = PdfPoint.Origin; foreach (var c in sp.Commands) { if (c is Move m) { first = m.Location; series1.Points.Add(PdfDocumentModel.ToDataPoint(first)); } else if (c is Line l) { series1.Points.Add(PdfDocumentModel.ToDataPoint(l.From)); series1.Points.Add(PdfDocumentModel.ToDataPoint(l.To)); } else if (c is BezierCurve bc) { var lines = bc.ToLines(10).ToList(); for (int i = 0; i < lines.Count; i++) { series1.Points.Add(PdfDocumentModel.ToDataPoint(lines[i].From)); series1.Points.Add(PdfDocumentModel.ToDataPoint(lines[i].To)); } } else if (c is Close) { series1.Points.Add(PdfDocumentModel.ToDataPoint(first)); } else { throw new ArgumentException(); } } PagePlotModel.Series.Add(series1); } } PagePlotModel.InvalidatePlot(true); }
/// <summary> /// The angle in degrees between the horizontal axis and the line between two points. /// </summary> /// <param name="point1">The first point.</param> /// <param name="point2">The second point.</param> /// <returns></returns> public static double Angle(PdfPoint point1, PdfPoint point2) { return(Math.Atan2((float)(point2.Y - point1.Y), (float)(point2.X - point1.X)) * 180.0 / Math.PI); }
public static DataPoint ToDataPoint(PdfPoint pdfPoint) { return(new DataPoint(pdfPoint.X, pdfPoint.Y)); }
public void AddFlexPoint(PdfPoint point) { }
public static void Main() { // NOTE: // When used in trial mode, the library imposes some restrictions. // Please visit http://bitmiracle.com/pdf-library/trial-restrictions.aspx // for more information. using (var pdf = new PdfDocument(@"..\Sample data\Freedman Scora.pdf")) { // This font is used to draw all recognized text chunks in PDF. // Make sure that the font defines all glyphs for the target language. PdfFont universalFont = pdf.AddFont("Arial"); var location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var tessData = Path.Combine(location, @"tessdata"); using (var engine = new TesseractEngine(tessData, "eng", EngineMode.LstmOnly)) { for (int i = 0; i < pdf.PageCount; ++i) { PdfPage page = pdf.Pages[i]; // Simple check if the page contains searchable text. // We do not need to do OCR in that case. if (!string.IsNullOrEmpty(page.GetText().Trim())) { continue; } var canvas = page.Canvas; canvas.Font = universalFont; // Produce invisible, but searchable text canvas.TextRenderingMode = PdfTextRenderingMode.NeitherFillNorStroke; const int Dpi = 200; const double ImageToPdfScaleFactor = 72.0 / Dpi; foreach (RecognizedTextChunk word in recognizeWords(page, engine, Dpi, $"page_{i}.png")) { if (word.Confidence < 80) { Console.WriteLine($"Possible recognition error: low confidence {word.Confidence} for word '{word.Text}'"); } Rect bounds = word.Bounds; PdfRectangle pdfBounds = new PdfRectangle( bounds.X1 * ImageToPdfScaleFactor, bounds.Y1 * ImageToPdfScaleFactor, bounds.Width * ImageToPdfScaleFactor, bounds.Height * ImageToPdfScaleFactor ); tuneFontSize(canvas, pdfBounds.Width, word.Text); double distanceToBaseLine = getDistanceToBaseline(canvas.Font, canvas.FontSize); var position = new PdfPoint(pdfBounds.Left, pdfBounds.Bottom - distanceToBaseLine); showTextAtRotatedPage(word.Text, position, page, page.MediaBox); } } } universalFont.RemoveUnusedGlyphs(); const string Result = "OcrAndMakeSearchable.pdf"; pdf.Save(Result); Console.WriteLine($"The output is located in {Environment.CurrentDirectory}"); } }
public void DrawLineVertical(PdfStyleLine lineStyle, PdfPoint begin, PdfDistance length) { if (lineStyle is null) { throw new ArgumentNullException(nameof(lineStyle)); } if (_verticalLines == null) { _verticalLines = new Lines(); } _verticalLines.Add(lineStyle, begin, new PdfPoint(begin.x, begin.y + length)); }
public int GetCharacterIndexAtPosition(PdfPoint location, double xTolerance, double yTolerance) { return(_document.GetCharacterIndexAtPosition(location, xTolerance, yTolerance)); }
private static void CreateInkAnnotations(PdfFixedDocument document, PdfFont font) { PdfBrush blackBrush = new PdfBrush(); Random rnd = new Random(); PdfPage page = document.Pages.Add(); page.Graphics.DrawString("Ink annotations", font, blackBrush, 50, 50); // The ink annotation will contain 3 lines, each one with 10 points. PdfPoint[][] points = new PdfPoint[3][]; for (int i = 0; i < points.Length; i++) { points[i] = new PdfPoint[10]; for (int j = 0; j < points[i].Length; j++) { points[i][j] = new PdfPoint(rnd.NextDouble() * page.Width, rnd.NextDouble() * page.Height); } } PdfInkAnnotation ia = new PdfInkAnnotation(); page.Annotations.Add(ia); ia.Contents = "I am an ink annotation."; ia.InkColor = new PdfRgbColor(255, 0, 255); ia.InkWidth = 5; ia.Points = points; }
/// <summary> /// The absolute distance between the Y coordinates of two points. /// </summary> /// <param name="point1">The first point.</param> /// <param name="point2">The second point.</param> /// <returns></returns> public static double Vertical(PdfPoint point1, PdfPoint point2) { return(Math.Abs((double)(point2.Y - point1.Y))); }
private bool PointBelongsToRay(PdfPoint rayOriginPoint, PdfPoint raySecondPoint, PdfPoint pointCheck) { // https://math.stackexchange.com/questions/1766357/check-if-a-given-coordinate-lies-in-path-of-a-ray-coordinate-geometry var tx = (pointCheck.X - rayOriginPoint.X) / (raySecondPoint.X - rayOriginPoint.X); if (tx < 0) { return(false); } var ty = (pointCheck.Y - rayOriginPoint.Y) / (raySecondPoint.Y - rayOriginPoint.Y); if (ty < 0) { return(false); } return(true); }
private static void CreatePolylineAnnotations(PdfFixedDocument document, PdfFont font) { PdfBrush blackBrush = new PdfBrush(); PdfPage page = document.Pages.Add(); page.Graphics.DrawString("Polyline annotations", font, blackBrush, 50, 50); int[] vertices = new int[] { 3, 4, 5, 6 }; double centerY = 125, centerX = 150; double radius = 50; for (int i = 0; i < vertices.Length; i++) { PdfPoint[] points = new PdfPoint[vertices[i]]; double angle = 90; double rotation = 360 / vertices[i]; for (int j = 0; j < vertices[i]; j++) { points[j] = new PdfPoint(); points[j].X = centerX + radius * Math.Cos(Math.PI * angle / 180); points[j].Y = centerY - radius * Math.Sin(Math.PI * angle / 180); angle = angle + rotation; } PdfPolylineAnnotation polyline = new PdfPolylineAnnotation(); page.Annotations.Add(polyline); polyline.Author = "Xfinium.Pdf"; polyline.Contents = "Polyline annotation with " + vertices[i] + " vertices."; polyline.Points = points; polyline.LineColor = new PdfRgbColor(192, 0, 0); polyline.LineWidth = 3; centerY = centerY + 150; } }