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

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
17 changes: 17 additions & 0 deletions TagCloud/AppSettings/IAppSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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 bool UseRandomPalette { get; }
public string BackgroundColor { get; }
public string ForegroundColor { get; }
public string BoringWordsFile { get; }
}
42 changes: 42 additions & 0 deletions TagCloud/AppSettings/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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 = "SansSerif", HelpText = "Font type of words")]
public string FontType { get; set; }

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

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

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

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

[Option('r', "randomPalette", Default = true, HelpText = "Use random colors")]
public bool UseRandomPalette { get; set; }

[Option("background", Default = "White", HelpText = "Cloud layouter algorithm")]
public string BackgroundColor { get; set; }

[Option("foreground", Default = "Black", HelpText = "Cloud layouter algorithm")]
public string ForegroundColor { get; set; }

[Option("boringWordsFile", Default = null, HelpText = "Cloud layouter algorithm")]
public string BoringWordsFile { get; set; }
}
34 changes: 34 additions & 0 deletions TagCloud/Configurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Drawing;
using Autofac;
using CommandLine;
using TagCloud.AppSettings;
using TagCloud.Drawer;
using TagCloud.FileReader;
using TagCloud.Filter;

namespace TagCloud;

public class Configurator
{
public static IAppSettings Parse(string[] args, ContainerBuilder builder)
{
var settings = Parser.Default.ParseArguments<Settings>(args).WithParsed(o =>
{
if (o.UseRandomPalette)
builder.RegisterType<RandomPalette>().As<IPalette>();
else
builder.Register(p =>
new CustomPalette(Color.FromName(o.ForegroundColor), Color.FromName(o.BackgroundColor)));
var filter = new WordFilter().UsingFilter((word) => word.Length > 3);
if (string.IsNullOrEmpty(o.BoringWordsFile))
builder.Register(c => filter).As<IFilter>();
else
{
var boringWords = new TxtReader().ReadLines(o.BoringWordsFile);
builder.Register(c => filter.UsingFilter((word) => !boringWords.Contains(word)));
}
});

return settings.Value;
}
}
78 changes: 78 additions & 0 deletions TagCloud/Drawer/CloudDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Drawing;
using TagCloud.AppSettings;
using TagCloud.Layouter;

namespace TagCloud.Drawer;

public class CloudDrawer : IDrawer
{
private readonly ILayouter layouter;
private readonly IPalette palette;
private readonly IAppSettings appSettings;
private int minimalRank;
private int maximalRank;
private const int MaximalFontSize = 50;
private const int LengthSizeMultiplier = 35;

public CloudDrawer(ILayouter layouter, IPalette palette, IAppSettings appSettings)
{
this.layouter = layouter;
this.palette = palette;
this.appSettings = appSettings;
}

public Bitmap DrawTagCloud(IEnumerable<(string word, int rank)> words)
{
var tags = PlaceWords(words);
var imageSize = new Size(appSettings.CloudWidth, appSettings.CloudHeight);
var shift = GetImageShift(layouter.Rectangles);
var image = new Bitmap(imageSize.Width, imageSize.Height);
using var graphics = Graphics.FromImage(image);
using var background = new SolidBrush(palette.BackgroudColor);
graphics.FillRectangle(background, 0, 0, imageSize.Width, imageSize.Height);
foreach (var tag in tags)
{
var shiftedCoordinates = new PointF(tag.Position.X - shift.Width, tag.Position.Y - shift.Height);
using var brush = new SolidBrush(palette.ForegroundColor);
graphics.DrawString(tag.Value, new Font(appSettings.FontType, tag.FontSize), brush, shiftedCoordinates);
}

return image;
}

private IList<Tag> PlaceWords(IEnumerable<(string word, int rank)> words)
{
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 static Size GetImageShift(IList<Rectangle> rectangles)
{
var minX = rectangles.Min(rectangle => rectangle.Left);
var minY = rectangles.Min(rectangle => rectangle.Top);

return new Size(minX, minY);
}
}
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;

namespace TagCloud.Drawer;

public class CustomPalette : IPalette
{
private Color foregroundColor;
private Color backgroundColor;

public CustomPalette(Color foregroundColor, Color backgroundColor)
{
this.foregroundColor = foregroundColor;
this.backgroundColor = backgroundColor;
}

public Color ForegroundColor => foregroundColor;
public Color BackgroudColor => backgroundColor;
}
8 changes: 8 additions & 0 deletions TagCloud/Drawer/IDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud.Drawer;

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

namespace TagCloud.Drawer;

public interface IPalette
{
Color ForegroundColor { get; }
Color BackgroudColor { get; }
}
11 changes: 11 additions & 0 deletions TagCloud/Drawer/RandomPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Drawing;

namespace TagCloud.Drawer;

public class RandomPalette : IPalette
{
private Random random = new();

public Color ForegroundColor => Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
public Color BackgroudColor => 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 string Value;
public Rectangle Position;
public int FontSize;

public Tag(string value, Rectangle position, int fontSize)
{
Value = value;
Position = position;
FontSize = fontSize;
}
}
33 changes: 33 additions & 0 deletions TagCloud/FileReader/FileReaderProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace TagCloud.FileReader;

public class FileReaderProvider : IFileReaderProvider
{
private Dictionary<string, IFileReader> readers;

public FileReaderProvider(IEnumerable<IFileReader> readers)
{
this.readers = ArrangeReaders(readers);
}

public IFileReader CreateReader(string inputPath)
{
var extension = inputPath.Split(".").Last();
if (readers.ContainsKey(extension))
return readers[extension];
throw new ArgumentException($"{extension} file type is not supported");
}

private Dictionary<string, IFileReader> ArrangeReaders(IEnumerable<IFileReader> readers)
{
var readersDictionary = new Dictionary<string, IFileReader>();
foreach (var reader in readers)
{
foreach (var extension in reader.GetAviableExtensions())
{

Choose a reason for hiding this comment

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

Available

readersDictionary[extension] = reader;
}
}

return readersDictionary;
}
}
8 changes: 8 additions & 0 deletions TagCloud/FileReader/IFileReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TagCloud.FileReader;

public interface IFileReader
{
IEnumerable<string> ReadLines(string inputPath);

IList<string> GetAviableExtensions();
}
6 changes: 6 additions & 0 deletions TagCloud/FileReader/IFileReaderProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagCloud.FileReader;

public interface IFileReaderProvider
{
IFileReader CreateReader(string inputPath);
}
21 changes: 21 additions & 0 deletions TagCloud/FileReader/TxtReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Xml.XPath;

namespace TagCloud.FileReader;

public class TxtReader : IFileReader
{
private List<string> extensions = new() { "txt" };

public IEnumerable<string> ReadLines(string InputPath)
{
if (!File.Exists(InputPath))
throw new ArgumentException("Source file doesn't exist");

return File.ReadLines(InputPath);
}

public IList<string> GetAviableExtensions()
{
return extensions;
}
}
8 changes: 8 additions & 0 deletions TagCloud/FileSaver/ISaver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud.FileSaver;

public interface ISaver
{
void Save(Bitmap bitmap, string OutputPath, string imageFormat);
}

Choose a reason for hiding this comment

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

с маленькой буквы

18 changes: 18 additions & 0 deletions TagCloud/FileSaver/ImageSaver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Drawing;

namespace TagCloud.FileSaver;

public class ImageSaver : ISaver
{
private List<string> supportedFormats = new() { "png", "jpg", "jpeg", "bmp", "gif" };

public void Save(Bitmap bitmap, string outputPath, string imageFormat)
{
if (!supportedFormats.Contains(imageFormat))
throw new ArgumentException($"{imageFormat} format is not supported");
using (bitmap)
{
bitmap.Save($"{outputPath}.{imageFormat}");
}
}
}
8 changes: 8 additions & 0 deletions TagCloud/Filter/IFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TagCloud.Filter;

public interface IFilter
{
IEnumerable<string> FilterWords(IEnumerable<string> words);

IFilter UsingFilter(Func<string, bool> filter);
}
18 changes: 18 additions & 0 deletions TagCloud/Filter/WordFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace TagCloud.Filter;

public class WordFilter : IFilter
{
private readonly List<Func<string, bool>> filters = [];

public IEnumerable<string> FilterWords(IEnumerable<string> words)
{
return words.Where(word => filters.All(f => f(word)));
}

public IFilter UsingFilter(Func<string, bool> filter)
{
filters.Add(filter);

return this;
}
}
Loading