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

Шевелев Георгий #206

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
14 changes: 14 additions & 0 deletions TagCloudDi/Applications/ConsoleApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using TagCloudDi.Drawer;

namespace TagCloudDi.Applications
{
public class ConsoleApplication(IDrawer drawer, Settings settings) : IApplication
{
public void Run()
{
var image = drawer.GetImage();
image.Save(settings.SavePath + '.' + settings.ImageFormat.ToLower(), settings.GetFormat());

Choose a reason for hiding this comment

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

Может лучше интерполяцию строк?

Console.WriteLine($"Saved to {settings.SavePath + '.' + settings.ImageFormat.ToLower()}");
}
}
}
7 changes: 7 additions & 0 deletions TagCloudDi/Applications/IApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudDi.Applications
{
public interface IApplication
{
void Run();
}
}
33 changes: 33 additions & 0 deletions TagCloudDi/Container.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Drawing;
using Autofac;
using TagCloudDi.Applications;
using TagCloudDi.Drawer;
using TagCloudDi.Layouter;
using TagCloudDi.TextProcessing;
using IContainer = Autofac.IContainer;

namespace TagCloudDi
{
public static class Container
{
public static IContainer SetupContainer(Settings settings)
{
var builder = new ContainerBuilder();
builder.Register(c => settings);
builder.Register(c =>
new ArchimedeanSpiral(new Point(
c.Resolve<Settings>().ImageWidth / 2,
c.Resolve<Settings>().ImageHeight / 2),
c.Resolve<Settings>()))
.As<IPointGenerator>();
builder.RegisterType<CircularCloudLayouter>().As<ILayouter>();
builder.RegisterType<FileTextReader>().As<ITextReader>();
builder.RegisterType<TextProcessor>().As<ITextProcessor>();
builder.RegisterType<RectanglesGenerator>().As<IRectanglesGenerator>();
builder.RegisterType<Drawer.Drawer>().As<IDrawer>();
builder.RegisterType<ConsoleApplication>().As<IApplication>();

return builder.Build();
}
}
}
23 changes: 23 additions & 0 deletions TagCloudDi/Drawer/Drawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Drawing;
using TagCloudDi.Layouter;

namespace TagCloudDi.Drawer
{
public class Drawer(Settings settings, IRectanglesGenerator rectanglesGenerator) : IDrawer
{
public Image GetImage()
{
var image = new Bitmap(settings.ImageWidth, settings.ImageHeight);
using var gr = Graphics.FromImage(image);
gr.Clear(Color.FromName(settings.BackColor));
foreach (var rectangleData in rectanglesGenerator.GetRectanglesData())
using (var font = new Font(settings.FontName, rectangleData.fontSize, FontStyle.Regular))
gr.DrawString(
rectangleData.word, font, new SolidBrush(Color.FromName(settings.TextColor)),

Choose a reason for hiding this comment

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

А зачем создавать кисточку каждый раз? Кажется ее можно создать до цикла и вызывать просто здесь.
Это во-первых не будет создавать нагрузку на сборщик мусора
Во-вторых, позволит написать вызов метода в одну строчку

rectangleData.rectangle
);

return image;
}
}
}
9 changes: 9 additions & 0 deletions TagCloudDi/Drawer/IDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagCloudDi.Drawer
{
public interface IDrawer
{
public Image GetImage();
}
}
Binary file added TagCloudDi/Examples/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TagCloudDi/Examples/Custom_Image_Size.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TagCloudDi/Examples/DifferentColors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TagCloudDi/Examples/DifferentFormat.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TagCloudDi/Examples/Different_Font.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TagCloudDi/Examples/Reversed_Spiral_Scale.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions TagCloudDi/Layouter/ArchimedeanSpiral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Drawing;

namespace TagCloudDi.Layouter
{
public class ArchimedeanSpiral(Point centerPoint, Settings settings) : IPointGenerator
{
private double angle { get; set; }
private const double DeltaAngle = Math.PI / 180;
private readonly int scale = settings.SpiralScale;
public Point CenterPoint => centerPoint;

public Point GetNextPoint()
{
var newX = (int)(centerPoint.X + scale * angle * Math.Cos(angle));
var newY = (int)(centerPoint.Y + scale * angle * Math.Sin(angle));
angle += DeltaAngle;

return new Point(newX, newY);
}
}
}
81 changes: 81 additions & 0 deletions TagCloudDi/Layouter/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Drawing;

namespace TagCloudDi.Layouter
{
public class CircularCloudLayouter : ILayouter
{
private readonly IPointGenerator pointGenerator;
public readonly List<Rectangle> Rectangles = [];

public CircularCloudLayouter(IPointGenerator pointGenerator)
{
this.pointGenerator = pointGenerator;
}

public Rectangle PutNextRectangle(Size rectangleSize)
{
if (rectangleSize.Height <= 0 || rectangleSize.Width <= 0)
throw new ArgumentException(
$"rectangleSize with zero or negative height or width is prohibited!",
nameof(rectangleSize)
);
while (true)
{
var nextPoint = pointGenerator.GetNextPoint();
var newPoint = new Point(nextPoint.X - rectangleSize.Width / 2, nextPoint.Y - rectangleSize.Height / 2);
var rectangle = new Rectangle(newPoint, rectangleSize);
if (IsIntersectsWithOthers(rectangle)) continue;
rectangle = GetCloserToCenterRectangle(rectangle);
Rectangles.Add(rectangle);
break;
}

return Rectangles[^1];
}

private bool IsIntersectsWithOthers(Rectangle rectangle) =>
Rectangles.Any(x => x.IntersectsWith(rectangle));

private Rectangle GetCloserToCenterRectangle(Rectangle rectangle)
{
var directions = GetDirection(rectangle);
foreach (var direction in directions)
{
var newRectangle = GetMovedRectangle(rectangle, direction.X, direction.Y);
while (!IsIntersectsWithOthers(newRectangle))
{
if (pointGenerator.CenterPoint.X - newRectangle.Size.Width / 2 == newRectangle.X
|| pointGenerator.CenterPoint.Y - newRectangle.Size.Height / 2 == newRectangle.Y)
break;
rectangle = newRectangle;
newRectangle = GetMovedRectangle(rectangle, direction.X, direction.Y);
}
}

return rectangle;
}

private List<(int X, int Y)> GetDirection(Rectangle rectangle)
{
var horizontalDiffer = pointGenerator.CenterPoint.X - rectangle.Size.Width / 2 - rectangle.X;
var verticalDiffer = pointGenerator.CenterPoint.Y - rectangle.Size.Height / 2 - rectangle.Y;
var directions = new List<(int X, int Y)>();
if (horizontalDiffer != 0 && verticalDiffer != 0)
directions.Add((horizontalDiffer > 0 ? 1 : -1, verticalDiffer > 0 ? 1 : -1));
if (horizontalDiffer != 0)
directions.Add((horizontalDiffer > 0 ? 1 : -1, 0));
if (verticalDiffer != 0)
directions.Add((0, verticalDiffer > 0 ? 1 : -1));
return directions;
}

private static Rectangle GetMovedRectangle(Rectangle rectangle, int xDelta, int yDelta) =>
new(
new Point(
rectangle.X + xDelta,
rectangle.Y + yDelta
),
rectangle.Size
);
}
}
9 changes: 9 additions & 0 deletions TagCloudDi/Layouter/ILayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagCloudDi.Layouter
{
public interface ILayouter
{
public Rectangle PutNextRectangle(Size rectangleSize);
}
}
10 changes: 10 additions & 0 deletions TagCloudDi/Layouter/IPointGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagCloudDi.Layouter
{
public interface IPointGenerator
{
public Point GetNextPoint();
public Point CenterPoint { get; }
}
}
7 changes: 7 additions & 0 deletions TagCloudDi/Layouter/IRectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudDi.Layouter
{
public interface IRectanglesGenerator
{
public IEnumerable<RectangleData> GetRectanglesData();
}
}
18 changes: 18 additions & 0 deletions TagCloudDi/Layouter/RectangleData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Drawing;

namespace TagCloudDi.Layouter
{
public class RectangleData
{
public readonly Rectangle rectangle;
public readonly string word;
public readonly float fontSize;

public RectangleData(Rectangle rectangle, string word, float fontSize)
{
this.fontSize = fontSize;
this.word = word;
this.rectangle = rectangle;
}
}
}
30 changes: 30 additions & 0 deletions TagCloudDi/Layouter/RectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Drawing;
using TagCloudDi.TextProcessing;

namespace TagCloudDi.Layouter
{
public class RectanglesGenerator(ITextProcessor textProcessor, Settings settings, ILayouter layouter) : IRectanglesGenerator
{
public IEnumerable<RectangleData> GetRectanglesData()
{
var frequencies = textProcessor.GetWordsFrequency();
var totalAmount = frequencies.Sum(x => x.Value);
return frequencies
.OrderByDescending(x => x.Value)
.Select(x =>
{
using var font = new Font(settings.FontName, settings.FontSize * (
x.Value * 100 / totalAmount), FontStyle.Regular);
return new RectangleData(layouter.PutNextRectangle(GetTextSize(x.Key, font)), x.Key, font.Size);
})
.ToList();
}

private Size GetTextSize(string text, Font font)
{
using var temporaryBitmap = new Bitmap(1, 1);
using var temporaryGraphics = Graphics.FromImage(temporaryBitmap);
return Size.Ceiling(temporaryGraphics.MeasureString(text, font));
}
}
}
17 changes: 17 additions & 0 deletions TagCloudDi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Autofac;
using CommandLine;
using TagCloudDi.Applications;

namespace TagCloudDi
{
abstract class MainClass
{
public static void Main(string[] args)
{
var settings = Parser.Default.ParseArguments<Settings>(args).Value;
var container = Container.SetupContainer(settings);
var app = container.Resolve<IApplication>();
app.Run();
}
}
}
52 changes: 52 additions & 0 deletions TagCloudDi/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Drawing.Imaging;
using CommandLine;

namespace TagCloudDi
{
public class Settings
{
[Option('f', "FontName", Required = false, Default = "Arial")]
public string FontName { get; set; }

[Option('z', "FontSize", Required = false, Default = 5)]
public int FontSize { get; set; }

[Option('t', "TextPath", Required = true)]
public string TextPath { get; set; }

[Option('e', "ExcludedWordsPath", Required = true)]
public string ExcludedWordsPath { get; set; }

[Option('p', "SpiralScale", Required = false, Default = 1)]
public int SpiralScale { get; set; }

[Option('y', "ImageHeight", Required = false, Default = 1080)]
public int ImageHeight { get; set; }

[Option('x', "ImageWidth", Required = false, Default = 1920)]
public int ImageWidth { get; set; }

[Option('s', "SavePathWithName", Required = true)]
public string SavePath { get; set; }

[Option('c', "TextColor", Required = false, Default = "White")]
public string TextColor { get; set; }

[Option('b', "BackgroundColor", Required = false, Default = "Black")]
public string BackColor { get; set; }

[Option('i', "ImageFormat", Required = false, Default = "png")]
public string ImageFormat { get; set; }

public ImageFormat GetFormat() => ImageFormat.ToLower() switch
{
"bmp" => System.Drawing.Imaging.ImageFormat.Bmp,
"gif" => System.Drawing.Imaging.ImageFormat.Gif,
"png" => System.Drawing.Imaging.ImageFormat.Png,
"tiff" => System.Drawing.Imaging.ImageFormat.Tiff,
"jpeg" => System.Drawing.Imaging.ImageFormat.Jpeg,
_ => throw new NotImplementedException()
};

}
}
17 changes: 17 additions & 0 deletions TagCloudDi/TagCloudDi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="8.0.0" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="System.Drawing.Common" Version="8.0.1" />
</ItemGroup>

</Project>
19 changes: 19 additions & 0 deletions TagCloudDi/TextProcessing/FileTextReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace TagCloudDi.TextProcessing
{
public class FileTextReader : ITextReader
{
public IEnumerable<string> GetWordsFrom(string filePath)
{
var words = new List<string>();
using var sr = new StreamReader(filePath);
var line = sr.ReadLine();
while (line != null)
{
words.Add(line!.ToLower());
line = sr.ReadLine();
}

return words;
}
}
}
7 changes: 7 additions & 0 deletions TagCloudDi/TextProcessing/ITextProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudDi.TextProcessing
{
public interface ITextProcessor
{
public Dictionary<string, int> GetWordsFrequency();
}
}
7 changes: 7 additions & 0 deletions TagCloudDi/TextProcessing/ITextReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudDi.TextProcessing
{
public interface ITextReader
{
IEnumerable<string> GetWordsFrom(string resource);
}
}
Loading