public static WatermarkSettings FromConfig(WatermarkConfiguration config) { var settings = new WatermarkSettings { Position = config.Position ?? WatermarkPosition.BottomRight, Text = config.Text }; if (config.Colors is null || config.Colors.Count() == 0) { settings.Colors = new[] { SKColors.Red, SKColors.Purple }; }
public static IImageProcessingContext ApplyWatermark(this IImageProcessingContext processingContext, WatermarkConfiguration config) { if (config is null) { return(processingContext); } else if (!string.IsNullOrEmpty(config.SourceFile)) { return(processingContext.ApplyWatermark(config.SourceFile, config.Opacity)); } var settings = WatermarkSettings.FromConfig(config); var size = processingContext.GetCurrentSize(); // Create a new image for the watermark layer. using var watermark = new Image <Rgba32>(size.Width, size.Height); var xOffeset = 0; var yOffeset = 0; watermark.Mutate(ctx => { // Draw the watermark. ctx.DrawWatermark(settings); var angle = 0.0f; if ((settings.Position == WatermarkPosition.BottomLeft) || (settings.Position == WatermarkPosition.TopRight)) { angle = 45.0f; // Calculate the x/y offsets for later when we draw the watermark on top of the source image. xOffeset = -(int)((Math.Sin(angle) * (size.Width / 2)) / 2); yOffeset = -(int)((Math.Sin(angle) * (size.Height / 2)) / 2); } else if ((settings.Position == WatermarkPosition.BottomRight) || (settings.Position == WatermarkPosition.TopLeft)) { angle = -45.0f; // Calculate the x/y offsets for later when we draw the watermark on top of the source image. xOffeset = (int)((Math.Sin(angle) * (size.Width / 2)) / 2); yOffeset = (int)((Math.Sin(angle) * (size.Height / 2)) / 2); } if (angle != 0) { ctx.Rotate(angle); } }); // Draw the watermark layer on top of the source image. processingContext.DrawImage(watermark, new Point(xOffeset, yOffeset), 1); return(processingContext); }
private void DrawTextBanner(SKCanvas canvas, Context context) { // Undo the original scaling factor to simplify the rendering. canvas.Scale(originalScale.X, originalScale.Y); var settings = WatermarkSettings.FromConfig(configuration); var bannerHeight = (float)(context.Size.Width / 4.5); var(start, end) = GetBannerLocations(settings.Position, context.Size, (float)bannerHeight); var shader = SKShader.CreateLinearGradient( start, end, settings.Colors.Select(c => c.WithAlpha((byte)(0xFF * context.Opacity))).ToArray(), null, SKShaderTileMode.Clamp); using var linePaint = new SKPaint { Shader = shader, IsStroke = true, StrokeWidth = bannerHeight, Style = SKPaintStyle.Stroke }; var path = new SKPath(); path.MoveTo(start); path.LineTo(end); canvas.DrawPath(path, linePaint); using var textPaint = new SKPaint { Color = settings.TextColor.WithAlpha((byte)(0xFF * context.Opacity)), TextAlign = SKTextAlign.Center, Typeface = settings.Typeface }; // Adjust TextSize property so text is 45% of the resulting image size. var textWidth = textPaint.MeasureText(settings.Text); textPaint.TextSize = 0.45f * context.Size.Width * textPaint.TextSize / textWidth; // Find the text bounds var textBounds = new SKRect(); // It may well be a Skia bug but it appears the measuring doesn't include the height of the descender characters in the measured height. textPaint.MeasureText(StripDescenders(settings.Text), ref textBounds); // Text drawn on the centre of the line so we need to bump it down to align the centre of the text. canvas.DrawTextOnPath(settings.Text, path, 0, textBounds.Height / 2, textPaint); }
// Colors: Red,Blue,Purple,#006666 private static IImageProcessingContext DrawWatermark(this IImageProcessingContext context, WatermarkSettings settings) { var imgSize = context.GetCurrentSize(); // measure the text size var size = TextMeasurer.Measure(settings.Text, new RendererOptions(settings.TextFont)); //find out how much we need to scale the text to fill the space (up or down) var scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height) / 3; //create a new settings.TextFont var scaledFont = new Font(settings.TextFont, scalingFactor * settings.TextFont.Size); var center = settings.Position switch { WatermarkPosition.Top => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), WatermarkPosition.TopLeft => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), WatermarkPosition.TopRight => new PointF(imgSize.Width / 2, (imgSize.Height / 9)), _ => new PointF(imgSize.Width / 2, imgSize.Height - (imgSize.Height / 9)), }; var textGraphicOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, }; // Apply Banner context.DrawBanner(settings) .DrawText(textGraphicOptions, settings.Text, scaledFont, settings.TextColor, center); return(context); }
private static IImageProcessingContext DrawBanner(this IImageProcessingContext context, WatermarkSettings settings) { var imgSize = context.GetCurrentSize(); var options = new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver, 1); var points = new[] { new PointF(0, imgSize.Height), new PointF(imgSize.Width, imgSize.Height) }; var stop = 0; IBrush brush = new LinearGradientBrush( points[0], points[1], GradientRepetitionMode.Repeat, settings.Colors.Select(x => new ColorStop(stop++, x)).ToArray()); var thickness = imgSize.Height / 4.5; var center = imgSize.Height - thickness; if ((settings.Position == WatermarkPosition.Top) || (settings.Position == WatermarkPosition.TopLeft) || (settings.Position == WatermarkPosition.TopRight)) { points = new[] { new PointF(0, 0), new PointF(imgSize.Width, 0) }; } var fullThickness = (float)(thickness * 2); var pen = new Pen(brush, fullThickness); var polygon = new Polygon(new LinearLineSegment(points)); return(context.Draw(options, pen, polygon)); }