Ejemplo n.º 1
0
        /// <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 fontStore))
            {
                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 fontProgram = fontStore.FontProgram;

            var fm = fontProgram.GetFontMatrix();

            var textMatrix = TransformationMatrix.FromValues(1, 0, 0, 1, position.X, position.Y);

            var letters = DrawLetters(text, fontProgram, fm, fontSize, textMatrix);

            CurrentStream.Add(BeginText.Value);
            CurrentStream.Add(new SetFontAndSize(font.Name, fontSize));
            CurrentStream.Add(new MoveToNextLineWithOffset((decimal)position.X, (decimal)position.Y));
            var bytesPerShow = new List <byte>();

            foreach (var letter in text)
            {
                if (char.IsWhiteSpace(letter))
                {
                    CurrentStream.Add(new ShowText(bytesPerShow.ToArray()));
                    bytesPerShow.Clear();
                }

                var b = fontProgram.GetValueForCharacter(letter);
                bytesPerShow.Add(b);
            }

            if (bytesPerShow.Count > 0)
            {
                CurrentStream.Add(new ShowText(bytesPerShow.ToArray()));
            }

            CurrentStream.Add(EndText.Value);

            return(letters);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds the JPEG image represented by the input stream at the specified location.
        /// </summary>
        public AddedImage AddJpeg(Stream fileStream, PdfRectangle placementRectangle)
        {
            var startFrom = fileStream.Position;
            var info      = JpegHandler.GetInformation(fileStream);

            byte[] data;
            using (var memory = new MemoryStream())
            {
                fileStream.Seek(startFrom, SeekOrigin.Begin);
                fileStream.CopyTo(memory);
                data = memory.ToArray();
            }

            var imgDictionary = new Dictionary <NameToken, IToken>
            {
                { NameToken.Type, NameToken.Xobject },
                { NameToken.Subtype, NameToken.Image },
                { NameToken.Width, new NumericToken(info.Width) },
                { NameToken.Height, new NumericToken(info.Height) },
                { NameToken.BitsPerComponent, new NumericToken(info.BitsPerComponent) },
                { NameToken.ColorSpace, NameToken.Devicergb },
                { NameToken.Filter, NameToken.DctDecode },
                { NameToken.Length, new NumericToken(data.Length) }
            };

            var reference = documentBuilder.AddImage(new DictionaryToken(imgDictionary), data);

            if (!resourcesDictionary.TryGetValue(NameToken.Xobject, out var xobjectsDict) ||
                !(xobjectsDict is DictionaryToken xobjects))
            {
                xobjects = new DictionaryToken(new Dictionary <NameToken, IToken>());
                resourcesDictionary[NameToken.Xobject] = xobjects;
            }

            var key = NameToken.Create($"I{imageKey++}");

            resourcesDictionary[NameToken.Xobject] = xobjects.With(key, new IndirectReferenceToken(reference));

            CurrentStream.Add(Push.Value);
            // This needs to be the placement rectangle.
            CurrentStream.Add(new ModifyCurrentTransformationMatrix(new []
            {
                (decimal)placementRectangle.Width, 0,
                0, (decimal)placementRectangle.Height,
                (decimal)placementRectangle.BottomLeft.X, (decimal)placementRectangle.BottomLeft.Y
            }));
            CurrentStream.Add(new InvokeNamedXObject(key));
            CurrentStream.Add(Pop.Value);

            return(new AddedImage(reference, info.Width, info.Height));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Draws a line on the current page between two points with the specified line width.
        /// </summary>
        /// <param name="from">The first point on the line.</param>
        /// <param name="to">The last point on the line.</param>
        /// <param name="lineWidth">The width of the line in user space units.</param>
        public void DrawLine(PdfPoint from, PdfPoint to, decimal lineWidth = 1)
        {
            if (lineWidth != 1)
            {
                CurrentStream.Add(new SetLineWidth(lineWidth));
            }

            CurrentStream.Add(new BeginNewSubpath((decimal)from.X, (decimal)from.Y));
            CurrentStream.Add(new AppendStraightLineSegment((decimal)to.X, (decimal)to.Y));
            CurrentStream.Add(StrokePath.Value);

            if (lineWidth != 1)
            {
                CurrentStream.Add(new SetLineWidth(1));
            }
        }
Ejemplo n.º 4
0
        /// <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));
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Adds the image previously added using <see cref="AddJpeg(byte[], PdfRectangle)"/>
        /// or <see cref="AddPng(byte[], PdfRectangle)"/> sharing the same image to prevent duplication.
        /// </summary>
        public void AddImage(AddedImage image, PdfRectangle placementRectangle)
        {
            if (!resourcesDictionary.TryGetValue(NameToken.Xobject, out var xobjectsDict) ||
                !(xobjectsDict is DictionaryToken xobjects))
            {
                xobjects = new DictionaryToken(new Dictionary <NameToken, IToken>());
                resourcesDictionary[NameToken.Xobject] = xobjects;
            }

            var key = NameToken.Create($"I{imageKey++}");

            resourcesDictionary[NameToken.Xobject] = xobjects.With(key, new IndirectReferenceToken(image.Reference));

            CurrentStream.Add(Push.Value);
            // This needs to be the placement rectangle.
            CurrentStream.Add(new ModifyCurrentTransformationMatrix(new[]
            {
                (decimal)placementRectangle.Width, 0,
                0, (decimal)placementRectangle.Height,
                (decimal)placementRectangle.BottomLeft.X, (decimal)placementRectangle.BottomLeft.Y
            }));
            CurrentStream.Add(new InvokeNamedXObject(key));
            CurrentStream.Add(Pop.Value);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Adds the PNG image represented by the input stream at the specified location.
        /// </summary>
        public AddedImage AddPng(Stream pngStream, PdfRectangle placementRectangle)
        {
            var png = Png.Open(pngStream);

            byte[] data;
            var    pixelBuffer = new byte[3];

            using (var memoryStream = new MemoryStream())
            {
                for (var rowIndex = 0; rowIndex < png.Height; rowIndex++)
                {
                    for (var colIndex = 0; colIndex < png.Width; colIndex++)
                    {
                        var pixel = png.GetPixel(colIndex, rowIndex);

                        pixelBuffer[0] = pixel.R;
                        pixelBuffer[1] = pixel.G;
                        pixelBuffer[2] = pixel.B;

                        memoryStream.Write(pixelBuffer, 0, pixelBuffer.Length);
                    }
                }

                data = memoryStream.ToArray();
            }

            var compressed = DataCompresser.CompressBytes(data);

            var imgDictionary = new Dictionary <NameToken, IToken>
            {
                { NameToken.Type, NameToken.Xobject },
                { NameToken.Subtype, NameToken.Image },
                { NameToken.Width, new NumericToken(png.Width) },
                { NameToken.Height, new NumericToken(png.Height) },
                { NameToken.BitsPerComponent, new NumericToken(png.Header.BitDepth) },
                { NameToken.ColorSpace, NameToken.Devicergb },
                { NameToken.Filter, NameToken.FlateDecode },
                { NameToken.Length, new NumericToken(compressed.Length) }
            };

            var reference = documentBuilder.AddImage(new DictionaryToken(imgDictionary), compressed);

            if (!resourcesDictionary.TryGetValue(NameToken.Xobject, out var xobjectsDict) ||
                !(xobjectsDict is DictionaryToken xobjects))
            {
                xobjects = new DictionaryToken(new Dictionary <NameToken, IToken>());
                resourcesDictionary[NameToken.Xobject] = xobjects;
            }

            var key = NameToken.Create($"I{imageKey++}");

            resourcesDictionary[NameToken.Xobject] = xobjects.With(key, new IndirectReferenceToken(reference));

            CurrentStream.Add(Push.Value);
            // This needs to be the placement rectangle.
            CurrentStream.Add(new ModifyCurrentTransformationMatrix(new[]
            {
                (decimal)placementRectangle.Width, 0,
                0, (decimal)placementRectangle.Height,
                (decimal)placementRectangle.BottomLeft.X, (decimal)placementRectangle.BottomLeft.Y
            }));
            CurrentStream.Add(new InvokeNamedXObject(key));
            CurrentStream.Add(Pop.Value);

            return(new AddedImage(reference, png.Width, png.Height));
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Restores the stroke, text and fill color to default (black).
 /// </summary>
 public void ResetColor()
 {
     CurrentStream.Add(Pop.Value);
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Sets the fill and text color for any following operations to the RGB value. Use <see cref="ResetColor"/> to reset.
 /// </summary>
 /// <param name="r">Red - 0 to 255</param>
 /// <param name="g">Green - 0 to 255</param>
 /// <param name="b">Blue - 0 to 255</param>
 public void SetTextAndFillColor(byte r, byte g, byte b)
 {
     CurrentStream.Add(Push.Value);
     CurrentStream.Add(new SetNonStrokeColorDeviceRgb(RgbToDecimal(r), RgbToDecimal(g), RgbToDecimal(b)));
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Sets the stroke color with the exact decimal value between 0 and 1 for any following operations to the RGB value. Use <see cref="ResetColor"/> to reset.
 /// </summary>
 /// <param name="r">Red - 0 to 1</param>
 /// <param name="g">Green - 0 to 1</param>
 /// <param name="b">Blue - 0 to 1</param>
 internal void SetStrokeColorExact(decimal r, decimal g, decimal b)
 {
     CurrentStream.Add(Push.Value);
     CurrentStream.Add(new SetStrokeColorDeviceRgb(CheckRgbDecimal(r, nameof(r)),
                                                   CheckRgbDecimal(g, nameof(g)), CheckRgbDecimal(b, nameof(b))));
 }