From 88837a20e3accdddf9b811cd2a68aae04183c012 Mon Sep 17 00:00:00 2001 From: Jon Sporring Date: Sun, 13 Aug 2023 16:38:36 +0200 Subject: [PATCH] Cleaned DrawingTextAlongAPath and added f# scripts --- .gitignore | 5 +- .../AvatarWithRoundedCorner/Program.fsx | 57 +++++++++ ImageSharp/DrawingTextAlongAPath/Program.cs | 119 +----------------- ImageSharp/DrawingTextAlongAPath/Program.fsx | 40 ++++++ 4 files changed, 103 insertions(+), 118 deletions(-) create mode 100644 ImageSharp/AvatarWithRoundedCorner/Program.fsx create mode 100644 ImageSharp/DrawingTextAlongAPath/Program.fsx diff --git a/.gitignore b/.gitignore index 3f3a6af..32e96d7 100644 --- a/.gitignore +++ b/.gitignore @@ -219,4 +219,7 @@ artifacts/ **/output/*.jpg **/output/*.jpeg **/output/*.bmp -**/output/*.gif \ No newline at end of file +**/output/*.gif +ImageSharp/AvatarWithRoundedCorner/fb.png +ImageSharp/AvatarWithRoundedCorner/fb-rounder.png +ImageSharp/AvatarWithRoundedCorner/fb-round.png diff --git a/ImageSharp/AvatarWithRoundedCorner/Program.fsx b/ImageSharp/AvatarWithRoundedCorner/Program.fsx new file mode 100644 index 0000000..54e2525 --- /dev/null +++ b/ImageSharp/AvatarWithRoundedCorner/Program.fsx @@ -0,0 +1,57 @@ +#r "nuget: SixLabors.ImageSharp" +#r "nuget: SixLabors.ImageSharp.Drawing, 1.0.0-beta15" + +open SixLabors.ImageSharp +open SixLabors.ImageSharp.PixelFormats +open SixLabors.ImageSharp.Processing +open SixLabors.ImageSharp.Drawing +open SixLabors.ImageSharp.Drawing.Processing + +let BuildCorners(imageWidth:float32, imageHeight:float32, cornerRadius:float32) = + // First create a square + let rect = new RectangularPolygon(-0.5f, -0.5f, cornerRadius, cornerRadius) + + // Then cut out of the square a circle so we are left with a corner + let cornerTopLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius)) + + // Corner is now a corner shape positions top left + // let's make 3 more positioned correctly, we can do that by translating the original around the center of the image. + let rightPos = imageWidth - cornerTopLeft.Bounds.Width + 1f + let bottomPos = imageHeight - cornerTopLeft.Bounds.Height + 1f + + // Move it across the width of the image - the width of the shape + let cornerTopRight = cornerTopLeft.RotateDegree(90f).Translate(rightPos, 0f) + let cornerBottomLeft = cornerTopLeft.RotateDegree(-90f).Translate(0f, bottomPos) + let cornerBottomRight = cornerTopLeft.RotateDegree(180f).Translate(rightPos, bottomPos) + + new PathCollection(cornerTopLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight) + +// This method can be seen as an inline implementation of an `IImageProcessor`: +// (The combination of `IImageOperations.Apply()` + this could be replaced with an `IImageProcessor`) +let ApplyRoundedCorners(context:IImageProcessingContext, cornerRadius: float32):IImageProcessingContext = + let size = context.GetCurrentSize() + let corners = BuildCorners(float32 size.Width, float32 size.Height, cornerRadius) + + context.SetGraphicsOptions(new GraphicsOptions( + Antialias = true, + // Enforces that any part of this shape that has color is punched out of the background + AlphaCompositionMode = PixelAlphaCompositionMode.DestOut + )) |> ignore + + // Mutating in here as we already have a cloned original + // use any color (not Transparent), so the corners will be clipped + for path in corners do + context.Fill(Color.Red, path)|>ignore + context + +// Implements a full image mutating pipeline operating on IImageProcessingContext +let ConvertToAvatar(context:IImageProcessingContext, size:Size, cornerRadius:float32):IImageProcessingContext = + ApplyRoundedCorners(context.Resize(ResizeOptions( + Size = size, + Mode = ResizeMode.Crop + )),cornerRadius) + +let img = Image.Load("fb.jpg") +img.Clone(fun x -> ConvertToAvatar(x,new Size(200, 200), 20f) |> ignore).Save("fb.png") +img.Clone(fun x -> ConvertToAvatar(x,new Size(200, 200), 100f) |> ignore).Save("fb-round.png") +img.Clone(fun x -> ConvertToAvatar(x,new Size(200, 200), 150f) |> ignore).Save("fb-rounder.png") diff --git a/ImageSharp/DrawingTextAlongAPath/Program.cs b/ImageSharp/DrawingTextAlongAPath/Program.cs index 81c72fb..714aed0 100644 --- a/ImageSharp/DrawingTextAlongAPath/Program.cs +++ b/ImageSharp/DrawingTextAlongAPath/Program.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -51,120 +51,5 @@ static void Main(string[] args) img.Save("output/wordart.png"); } } - - public static IImageProcessingContext ApplyScalingWaterMark(this IImageProcessingContext processingContext, - Font font, - string text, - Color color, - float padding, - bool wordwrap) - { - if (wordwrap) - { - // return processingContext.ApplyScalingWaterMarkWordWrap(font, text, color, padding); - } - //else - { - return processingContext.ApplyScalingWaterMarkSimple(font, text, color, padding); - } - } - - private static IImageProcessingContext ApplyScalingWaterMarkSimple( - this IImageProcessingContext processingContext, - Font font, - string text, - Color color, - float padding) - { - Size imgSize = processingContext.GetCurrentSize(); - - // Measure the text size - FontRectangle size = TextMeasurer.Measure(text, new TextOptions(font)); - - // Find out how much we need to scale the text to fill the space (up or down) - float scalingFactor = Math.Min(imgSize.Width - padding / size.Width, imgSize.Height - padding / size.Height); - - // Create a new font - Font scaledFont = new Font(font, scalingFactor * font.Size); - - var center = new PointF(imgSize.Width / 2, imgSize.Height / 2); - var textOptions = new TextOptions(scaledFont) - { - Origin = center, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - }; - return processingContext.DrawText(textOptions, text, color); - } - - //private static IImageProcessingContext ApplyScalingWaterMarkWordWrap( - // this IImageProcessingContext processingContext, - // Font font, - // string text, - // Color color, - // float padding) - //{ - // Size imgSize = processingContext.GetCurrentSize(); - // float targetWidth = imgSize.Width - (padding * 2); - // float targetHeight = imgSize.Height - (padding * 2); - - // float targetMinHeight = imgSize.Height - (padding * 3); // must be with in a margin width of the target height - - // // now we are working i 2 dimensions at once and can't just scale because it will cause the text to - // // reflow we need to just try multiple times - - // var scaledFont = font; - // FontRectangle s = new FontRectangle(0, 0, float.MaxValue, float.MaxValue); - - // float scaleFactor = (scaledFont.Size / 2);// everytime we change direction we half this size - // int trapCount = (int)scaledFont.Size * 2; - // if (trapCount < 10) - // { - // trapCount = 10; - // } - - // bool isTooSmall = false; - - // while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0) - // { - // if (s.Height > targetHeight) - // { - // if (isTooSmall) - // { - // scaleFactor = scaleFactor / 2; - // } - - // scaledFont = new Font(scaledFont, scaledFont.Size - scaleFactor); - // isTooSmall = false; - // } - - // if (s.Height < targetMinHeight) - // { - // if (!isTooSmall) - // { - // scaleFactor = scaleFactor / 2; - // } - // scaledFont = new Font(scaledFont, scaledFont.Size + scaleFactor); - // isTooSmall = true; - // } - // trapCount--; - - // s = TextMeasurer.Measure(text, new RendererOptions(scaledFont) - // { - // WrappingWidth = targetWidth - // }); - // } - - // var center = new PointF(padding, imgSize.Height / 2); - // var textGraphicsOptions = new TextGraphicsOptions() - // { - // TextOptions = { - // HorizontalAlignment = HorizontalAlignment.Left, - // VerticalAlignment = VerticalAlignment.Center, - // WrapTextWidth = targetWidth - // } - // }; - // return processingContext.DrawText(textGraphicsOptions, text, scaledFont, color, center); - //} } -} +} \ No newline at end of file diff --git a/ImageSharp/DrawingTextAlongAPath/Program.fsx b/ImageSharp/DrawingTextAlongAPath/Program.fsx new file mode 100644 index 0000000..de12ed8 --- /dev/null +++ b/ImageSharp/DrawingTextAlongAPath/Program.fsx @@ -0,0 +1,40 @@ +#r "nuget: SixLabors.ImageSharp" +#r "nuget: SixLabors.ImageSharp.Drawing, 1.0.0-beta15" + +open System +open SixLabors.Fonts +open SixLabors.ImageSharp +open SixLabors.ImageSharp.PixelFormats +open SixLabors.ImageSharp.Processing +open SixLabors.ImageSharp.Drawing +open SixLabors.ImageSharp.Drawing.Processing + +let img = new Image(1500, 500) +let pathBuilder = new PathBuilder() +pathBuilder.SetOrigin(new PointF(500f, 0f)) +pathBuilder.AddCubicBezier(new PointF(50f, 450f), new PointF(200f, 50f), new PointF(300f, 50f), new PointF(450f, 450f)) + +// Add more complex paths and shapes here. +let path = pathBuilder.Build() + +// For production application we would recomend you create a FontCollection +// singleton and manually install the ttf fonts yourself as using SystemFonts +// can be expensive and you risk font existing or not existing on a deployment +// by deployment basis. +let font = SystemFonts.CreateFont("Microsoft Sans Serif", 39f, FontStyle.Regular) +let text = "Hello World Hello World Hello World Hello World Hello World" + +// Draw the text along the path wrapping at the end of the line +let textOptions = new TextOptions(font) +textOptions.WrappingLength <- path.ComputeLength() +textOptions.VerticalAlignment <- VerticalAlignment.Bottom +textOptions.HorizontalAlignment <- HorizontalAlignment.Left + +// Let's generate the text as a set of vectors drawn along the path +let glyphs = TextBuilder.GenerateGlyphs(text, path, textOptions) + +img.Mutate(fun ctx -> ctx.Fill(Color.White) // white background image + .Draw(Color.Gray, 3f, path) // draw the path so we can see what the text is supposed to be following + .Fill(Color.Black, glyphs)|>ignore) + +img.Save("wordart.png")