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

Зубков Андрей #164

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions TagCloud/AppSettings/IAppSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace TagCloud.AppSettings;

public interface IAppSettings
{
public string InputPath { get; }
public string OutputPath { get; }
public string ImageExtension { get; }
public string FontType { get; }
public int CloudWidth { get; }
public int CloudHeight { get; }
public string LayouterType { get; }
public int CloudDensity { get; }
public string ImagePalette { get; }
public string BackgroundColor { get; }
public string ForegroundColor { get; }
}
39 changes: 39 additions & 0 deletions TagCloud/AppSettings/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using CommandLine;

namespace TagCloud.AppSettings;

public class Settings : IAppSettings
{
[Option('s', "sourceFile", Default = "text.txt", HelpText = "Path to file with words to visualize")]
public string InputPath { get; set; }

[Option('o', "outputPath", Default = "result", HelpText = "Path to output image file")]
public string OutputPath { get; set; }

[Option('e', "extensionImage", Default = "png", HelpText = "Output image file format")]
public string ImageExtension { get; set; }

[Option('f', "fontType", Default = "Arial", HelpText = "Font type of words")]
public string FontType { get; set; }

[Option('W', "width", Default = 1920, HelpText = "Width of cloud in pixels")]
public int CloudWidth { get; set; }

[Option('H', "height", Default = 1080, HelpText = "Height of cloud in pixels")]
public int CloudHeight { get; set; }

[Option('l', "layouter", Default = "Spiral", HelpText = "Cloud layouter algorithm")]
public string LayouterType { get; set; }

[Option('d', "density", Default = 1, HelpText = "Density of cloud, integer")]
public int CloudDensity { get; set; }

[Option('p', "imagePalette", Default = "Random", HelpText = "Image coloring method")]
public string ImagePalette { get; set; }

[Option("background", Default = "White", HelpText = "Bckground color name")]
public string BackgroundColor { get; set; }

[Option("foreground", Default = "Black", HelpText = "Foreground color name")]
public string ForegroundColor { get; set; }
}
64 changes: 64 additions & 0 deletions TagCloud/Configurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Autofac;
using CommandLine;
using ResultOf;
using TagCloud.AppSettings;
using TagCloud.Drawer;
using TagCloud.FileReader;
using TagCloud.FileSaver;
using TagCloud.Filter;
using TagCloud.PointGenerator;
using TagCloud.UserInterface;
using TagCloud.WordRanker;
using TagCloud.WordsPreprocessor;

namespace TagCloud;

public class Configurator
{
public static IAppSettings Parse(string[] args)
{
var settings = Parser.Default.ParseArguments<Settings>(args);

if (settings as Parsed<Settings> == null)
Environment.Exit(-1);

SettingsValidator.SizeIsValid(settings.Value)
.Then(SettingsValidator.FontIsInstalled)
.OnFail(e =>
{
Console.WriteLine(e);
Environment.Exit(-1);
});

return settings.Value;
}

public static ContainerBuilder ConfigureBuilder(IAppSettings settings)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сейчас все сервисы регистрируются по умолчанию в скоупе InstancePerDependency, это значит что при каждом запросе сервиса будет создаваться его экземпляр, даже если у него нет состояния. С таким подходом и увеличением количества сервисов можем начать проигрывать в памяти и скорости выполнения запросов, так как перед выполнением запроса нужно будет создать все зависимости заново.

Предлагаю чуть пооптимизировать и попробовать некоторые зависимости перевести в другие скоупы, в том числе синглтон

{
var builder = new ContainerBuilder();

builder.RegisterType<TxtReader>().As<IFileReader>().SingleInstance();
builder.RegisterType<DocReader>().As<IFileReader>().SingleInstance();
builder.RegisterType<ImageSaver>().As<ISaver>().SingleInstance();
builder.RegisterType<CloudDrawer>().As<IDrawer>().SingleInstance();
builder.RegisterType<WordRankerByFrequency>().As<IWordRanker>().SingleInstance();
builder.RegisterType<DefaultPreprocessor>().As<IPreprocessor>().SingleInstance();
builder.RegisterType<SpiralGenerator>().As<IPointGenerator>();
builder.RegisterType<CirclesGenerator>().As<IPointGenerator>();
builder.RegisterType<RandomPalette>().As<IPalette>();
builder.RegisterType<CustomPalette>().As<IPalette>();

builder.RegisterType<ConsoleUI>().As<IUserInterface>();

builder.Register(c => new WordFilter().UsingFilter((word) => word.Length > 3)).As<IFilter>().SingleInstance();
builder.Register(c => new FileReaderProvider(c.Resolve<IEnumerable<IFileReader>>())).As<IFileReaderProvider>()
.SingleInstance();
builder.Register(c => new PointGeneratorProvider(c.Resolve<IEnumerable<IPointGenerator>>()))
.As<IPointGeneratorProvider>();
builder.Register(c => new PaletteProvider(c.Resolve<IEnumerable<IPalette>>())).As<IPaletteProvider>();

builder.Register(c => settings).As<IAppSettings>().SingleInstance();

return builder;
}
}
114 changes: 114 additions & 0 deletions TagCloud/Drawer/CloudDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System.Drawing;
using System.Drawing.Text;
using ResultOf;
using TagCloud.AppSettings;
using TagCloud.Layouter;
using TagCloud.PointGenerator;

namespace TagCloud.Drawer;

public class CloudDrawer : IDrawer
{
private readonly IPointGeneratorProvider pointGeneratorProvider;
private readonly IPaletteProvider paletteProvider;
private readonly IAppSettings appSettings;
private int minimalRank;
private int maximalRank;
private const int MaximalFontSize = 50;
private const int LengthSizeMultiplier = 35;

public CloudDrawer(IPointGeneratorProvider pointGeneratorProvider, IPaletteProvider paletteProvider,
IAppSettings appSettings)
{
this.pointGeneratorProvider = pointGeneratorProvider;
this.paletteProvider = paletteProvider;
this.appSettings = appSettings;
}

public Result<Bitmap> DrawTagCloud(IEnumerable<(string word, int rank)> words)
{
var pointGenerator = pointGeneratorProvider.CreateGenerator(appSettings.LayouterType);

if (!pointGenerator.IsSuccess)
return Result.Fail<Bitmap>(pointGenerator.Error);

var palette = paletteProvider.CreatePalette(appSettings.ImagePalette);

if (!palette.IsSuccess)
return Result.Fail<Bitmap>(palette.Error);

var layouter = new CloudLayouter(pointGenerator.Value);
var tags = PlaceWords(words, layouter);

var cloudSize = CalculateCloudSize(tags);

return !ValidateCloudSize(cloudSize)
? Result.Fail<Bitmap>(
$"Tags image with size of {cloudSize.Width}x{cloudSize.Height} don't fit to given size of {appSettings.CloudWidth}x{appSettings.CloudHeight}")
: Result.Ok(DrawTags(tags, palette.Value));
}

private Bitmap DrawTags(IEnumerable<Tag> tags, IPalette palette)
{
var imageSize = new Size(appSettings.CloudWidth, appSettings.CloudHeight);
var image = new Bitmap(imageSize.Width, imageSize.Height);
using var graphics = Graphics.FromImage(image);
using var background = new SolidBrush(palette.BackgroundColor);
graphics.FillRectangle(background, 0, 0, imageSize.Width, imageSize.Height);
foreach (var tag in tags)
{
var pointFCoordinates = new PointF(tag.Position.X, tag.Position.Y);
using var brush = new SolidBrush(palette.ForegroundColor);
graphics.DrawString(tag.Value, new Font(appSettings.FontType, tag.FontSize), brush, pointFCoordinates);
}

return image;
}

private IEnumerable<Tag> PlaceWords(IEnumerable<(string word, int rank)> words, ILayouter layouter)
{
maximalRank = words.First().rank;
minimalRank = words.Last().rank - 1;

var tags = new List<Tag>();

foreach (var pair in words)
{
var fontSize = CalculateFontSize(pair.rank);
var boxLength = CalculateWordBoxLength(pair.word.Length, fontSize);
var rectangle = layouter.PutNextRectangle(new Size(boxLength, fontSize));
tags.Add(new Tag(pair.word, rectangle, fontSize));
}

return tags;
}

private int CalculateFontSize(int rank)
{
return (MaximalFontSize * (rank - minimalRank)) / (maximalRank - minimalRank);
}

private int CalculateWordBoxLength(int length, int fontSize)
{
return (int)Math.Round(length * LengthSizeMultiplier * ((double)fontSize / MaximalFontSize));
}

private Size CalculateCloudSize(IEnumerable<Tag> tags)
{
var tagsPositions = tags.Select(t => t.Position);
var minX = tagsPositions.Min(p => p.Left);
var maxX = tagsPositions.Max(p => p.Right);
var minY = tagsPositions.Min(p => p.Top);
var maxY = tagsPositions.Max(p => p.Bottom);

var width = maxX - minX;
var height = maxY - minY;

return new Size(width, height);
}

private bool ValidateCloudSize(Size size)
{
return size.Width <= appSettings.CloudWidth && size.Height <= appSettings.CloudHeight;
}
}
18 changes: 18 additions & 0 deletions TagCloud/Drawer/CustomPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Drawing;
using TagCloud.AppSettings;

namespace TagCloud.Drawer;

public class CustomPalette : IPalette
{
public string Name => "Custom";

public Color ForegroundColor { get; }
public Color BackgroundColor { get; }

public CustomPalette(IAppSettings settings)
{
ForegroundColor = Color.FromName(settings.ForegroundColor);
BackgroundColor = Color.FromName(settings.BackgroundColor);
}
}
9 changes: 9 additions & 0 deletions TagCloud/Drawer/IDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;
using ResultOf;

namespace TagCloud.Drawer;

public interface IDrawer
{
Result<Bitmap> DrawTagCloud(IEnumerable<(string word, int rank)> words);
}
10 changes: 10 additions & 0 deletions TagCloud/Drawer/IPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagCloud.Drawer;

public interface IPalette
{
string Name { get; }
Color ForegroundColor { get; }
Color BackgroundColor { get; }
}
8 changes: 8 additions & 0 deletions TagCloud/Drawer/IPaletteProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ResultOf;

namespace TagCloud.Drawer;

public interface IPaletteProvider
{
Result<IPalette> CreatePalette(string paletteName);
}
33 changes: 33 additions & 0 deletions TagCloud/Drawer/PaletteProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using ResultOf;

namespace TagCloud.Drawer;

public class PaletteProvider : IPaletteProvider
{
private Dictionary<string, IPalette> palettes;

public PaletteProvider(IEnumerable<IPalette> palettes)
{
this.palettes = ArrangePalettes(palettes);
}

public Result<IPalette> CreatePalette(string paletteName)
{
var availablePalettes = string.Join("", palettes.Select(pair => pair.Value.Name));

return palettes.ContainsKey(paletteName)
? Result.Ok(palettes[paletteName])
: Result.Fail<IPalette>($"Palette with name {paletteName} doesn't exist. Available palettes are: {availablePalettes}");
}

private Dictionary<string, IPalette> ArrangePalettes(IEnumerable<IPalette> palettes)
{
var palettesDictionary = new Dictionary<string, IPalette>();
foreach (var palette in palettes)
{
palettesDictionary[palette.Name] = palette;
}

return palettesDictionary;
}
}
12 changes: 12 additions & 0 deletions TagCloud/Drawer/RandomPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Drawing;

namespace TagCloud.Drawer;

public class RandomPalette : IPalette
{
public string Name => "Random";
private Random random = new();

public Color ForegroundColor => Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
public Color BackgroundColor => Color.White;
}
17 changes: 17 additions & 0 deletions TagCloud/Drawer/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Drawing;

namespace TagCloud.Drawer;

public class Tag
{
public readonly string Value;
public Rectangle Position;
public readonly int FontSize;

public Tag(string value, Rectangle position, int fontSize)
{
Value = value;
Position = position;
FontSize = fontSize;
}
}
Loading