Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout wrapping support #4

Closed
tocsoft opened this issue Feb 7, 2017 · 3 comments
Closed

layout wrapping support #4

tocsoft opened this issue Feb 7, 2017 · 3 comments

Comments

@tocsoft
Copy link
Member

tocsoft commented Feb 7, 2017

pass in a rectangle into the layout engine and it should auto wrap text at the provided width.

@dotnetnoobie
Copy link

I have made a basic version of this except is does both width and height which is used for the ImageSharp.Drawing to create images with text on the fly that will scale the text to fit in the rectangle which is generated from an AspNet Core 1.1 MVC Controller Action and returns the image as a file.

I am not saying this is how you should do it, I am just offering this as a quick and dirty hack/workaround for people until you have implemented the feature.

You need to set values for
text: the text you want drawn on the image
image: size width and height
margin: the margin from the edge of the image to the text

It starts with a font size of 100 and tries to build a list of stings that fit inside the size of the rec
if the height becomes to large, it lowers the font size by 1 and tries again and repeats until it has a font size that will fit the height

     var text = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born " +
                       "and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, " +
                       "the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, " +
                       "but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. " +
                       "Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, " +
                       "but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. " +
                       "To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? " +
                       "But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, " +
                       "or one who avoids a pain that produces no resultant pleasure? On the other hand, " +
                       "we denounce with righteous indignation and dislike men who are so beguiled and demoralized " +
                       "by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee";

            var img = new Image(800, 400);

            img.BackgroundColor(Color.Navy);

            var fontCollection = FontCollection.SystemFonts.Find("Segoe Print");

            // staring font size is set to 100 
            var font = new Font(fontCollection, 100, FontStyle.Regular);
            var dpi = 72;
            var margin = (float)10;

            var rec = new Rectangle(0, 0, (int)(img.Width - margin * 2), (int)(img.Height - margin * 2));

            var words = text.Split(' ');
            var lines = new List<string>();
            var line = "";
            float lineHeight = 0;

            for (var i = 0; i < words.Length; i++)
            {
                var temp = line + " " + words[i];
                var size = new TextMeasurer().MeasureText(temp.Trim(), font, dpi);

                if (size.Height > lineHeight)
                {
                    // keep track of the largest line height value to make all lines space evenly 
                    // and also calculate the total height of all lines 
                    lineHeight = size.Height;
                }

                if (size.Width < rec.Width)
                {
                    line += " " + words[i];
                }
                else
                {
                    lines.Add(line.Trim());
                    line = words[i];

                    var currentHeight = Math.Ceiling(lines.Count * lineHeight);

                    // remove 1 lineHeight from the rec.Height to account for the leftover line that may or maynot be added at the end of the loop
                    if (currentHeight > Math.Floor(rec.Height - lineHeight))
                    {
                        // to big, reset loop values with smaller font size and try again
                        // setting i = -1 makes the loop begin again and include the first word in the array of words
                        lines = new List<string>();
                        line = "";
                        i = -1;
                        lineHeight = 0;
                        font = new Font(font, font.Size - 1);
                    }
                }
            }
            lines.Add(line.Trim());

            var positionHeight = margin;

            // draw a line of text for each line we craeted in the list
            foreach (var lineText in lines)
            {
                img.DrawText(lineText, font, Brushes.Solid(Color.White), null, new Vector2(margin, (float)positionHeight), new TextGraphicsOptions(true));
                // add the lineHeight value to the positionHeight so the next line is below the previous line
                positionHeight += lineHeight;
            }

            var ms = new MemoryStream();

            img.Save(ms, new PngEncoder());

            return File(ms.ToArray(), "image/png");

@tocsoft
Copy link
Member Author

tocsoft commented Apr 12, 2017

@dotnetnoobie thanks for this, it gave me just the push I needed to get this feature landed.

You'll find if you update to the latest ImageSharp, ImageSharp.Drawing, and SixLabors.Fonts I've now added Word wrapping support.

I've also taken your use case and created a demo at https://github.com/SixLabors/Demos/blob/master/WaterMarkSample/Program.cs#L71 for a version that should have much better performance.

I'm not sure we'll ever add the option to auto scale the font size for you but this example should get you where you need to go in a much improved manor.

Note for future people: this landed in 0.1.0-alpha0005

@tocsoft tocsoft closed this as completed Apr 12, 2017
@dotnetnoobie
Copy link

@tocsoft very quick

If you look at the full framework .NET System.Drawing it does not "Auto Scale" the font size either, you have to do it manually

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants