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

Савенко Дмитрий #25

Open
wants to merge 7 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
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
31 changes: 31 additions & 0 deletions TagsCloudContainer/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Drawing;
using TagsCloudContainer.Interfaces;

namespace TagsCloudContainer;

public class CircularCloudLayouter(IPointGenerator pointGenerator): ITagCloudLayouter
{
private readonly List<Rectangle> _rectangles = new();
private readonly Grid _grid = new();
public Rectangle PutNextRectangle(Size rectangleSize)
{
if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0)
throw new ArgumentException("Размеры прямоугольника должны быть положительными.");

Rectangle newRectangle;
do
{
var point = pointGenerator.GetNextPoint();
var location = new Point(
point.X - rectangleSize.Width / 2,
point.Y - rectangleSize.Height / 2);
newRectangle = new Rectangle(location, rectangleSize);
} while (_grid.IsIntersecting(newRectangle));

_grid.AddRectangle(newRectangle);
_rectangles.Add(newRectangle);
return newRectangle;
}

public IEnumerable<Rectangle> GetRectangles() => _rectangles;
}
45 changes: 45 additions & 0 deletions TagsCloudContainer/CloudImageRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Drawing;
using System.Drawing.Imaging;
using TagsCloudContainer.Interfaces;
using TagsCloudContainer.Options;

namespace TagsCloudContainer;

public class CloudImageRenderer : ITagCloudRenderer
{
private readonly Random random = new();
private const float MinFontSize = 12f;
private const float MaxFontSize = 72f;
private const float FrequencyMultiplier = 2f;

public void Render(IEnumerable<Tag> tags, string outputFilePath, RenderingOptions options)
{
using var bitmap = new Bitmap(options.ImageSize.Width, options.ImageSize.Height);
using var graphics = Graphics.FromImage(bitmap);


graphics.Clear(options.BackgroundColor);


graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

foreach (var tag in tags)
{
var fontSize = Math.Max(MinFontSize, Math.Min(MaxFontSize, tag.Frequency * FrequencyMultiplier));

using var font = new Font(options.Font, fontSize, FontStyle.Bold);

var color = options.WordColors[random.Next(options.WordColors.Length)];
using var brush = new SolidBrush(color);

graphics.DrawString(
tag.Word,
font,
brush,
tag.Rectangle.Location
);
}

bitmap.Save(outputFilePath, ImageFormat.Png);
}
}
76 changes: 76 additions & 0 deletions TagsCloudContainer/DependencyInjectionConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Drawing;
using Autofac;
using TagsCloudContainer.DocumentReaders;
using TagsCloudContainer.Interfaces;
using TagsCloudContainer.Options;
using TagsCloudContainer.PointGenerators;

namespace TagsCloudContainer;

public static class DependencyInjectionConfig
{
public static IContainer BuildContainer(Options.Options? options = null)
{
var builder = new ContainerBuilder();

builder.Register(c => new RenderingOptions())
.AsSelf()
.SingleInstance();

var boringWords = "";
if (options is not null)
{
boringWords = options.BoringWordsFilePath;
}

builder.RegisterType<WordProcessor>()
.As<IWordProcessor>()
.SingleInstance()
.WithParameter("filepath",
boringWords);

builder.RegisterType<WordDocumentReader>().As<IDocumentReader>().SingleInstance();
builder.RegisterType<TxtReader>().As<IDocumentReader>().SingleInstance();

builder.RegisterType<DocumentReader>().AsSelf().SingleInstance();

builder.RegisterType<LogarithmicScaling>().As<ITextSizeCalculator>().SingleInstance();

builder.RegisterType<WordFrequencyAnalyzer>()
.As<IWordFrequencyAnalyzer>()
.SingleInstance();

builder.RegisterType<CircularCloudLayouter>()
.As<ITagCloudLayouter>()
.SingleInstance();

builder.RegisterType<SpiralGenerator>()
.As<IPointGenerator>()
.SingleInstance()
.WithParameter("center", new Point(500, 500));

builder.RegisterType<LinearSpiral>()
.Named<IPointGenerator>("linear");

builder.RegisterType<CloudImageRenderer>()
.As<ITagCloudRenderer>()
.SingleInstance();

builder.RegisterType<TagCloudGenerator>()
.As<ITagCloudGenerator>()
.SingleInstance();

builder.Register<ITagCloudGenerator>(c =>
new TagCloudGenerator(
c.Resolve<IWordProcessor>(),
c.Resolve<ITagCloudLayouter>(),
c.Resolve<ITagCloudRenderer>(),
c.Resolve<DocumentReader>(),
c.Resolve<IWordFrequencyAnalyzer>(),
c.Resolve<ITextSizeCalculator>()
))
.SingleInstance();

return builder.Build();
}
}
21 changes: 21 additions & 0 deletions TagsCloudContainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
USER $APP_UID
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["TagsCloudContainer/TagsCloudContainer.csproj", "TagsCloudContainer/"]
RUN dotnet restore "TagsCloudContainer/TagsCloudContainer.csproj"
COPY . .
WORKDIR "/src/TagsCloudContainer"
RUN dotnet build "TagsCloudContainer.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "TagsCloudContainer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TagsCloudContainer.dll"]
23 changes: 23 additions & 0 deletions TagsCloudContainer/DocumentReaders/DocumentReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using TagsCloudContainer.Interfaces;

namespace TagsCloudContainer.DocumentReaders;

public class DocumentReader: IDocumentReader
{
private readonly Dictionary<string, IDocumentReader> _readers;
public string[] SupportedDocumentExtensions => _readers.Keys.ToArray();
public DocumentReader(IEnumerable<IDocumentReader> readers)
{
_readers = readers
.SelectMany(reader => reader.SupportedDocumentExtensions.Select(ext => new { ext, reader }))
.ToDictionary(x => x.ext, x => x.reader);
}
public string[] ReadDocument(string filePath)
{
var extension = Path.GetExtension(filePath).ToLower();
if (!_readers.TryGetValue(extension, out var reader))
throw new NotSupportedException($"Format {extension} is not supported");

return reader.ReadDocument(filePath);
}
}
13 changes: 13 additions & 0 deletions TagsCloudContainer/DocumentReaders/TxtReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using TagsCloudContainer.Interfaces;

namespace TagsCloudContainer.DocumentReaders;

public class TxtReader : IDocumentReader
{
public string[] SupportedDocumentExtensions => [".txt"];

public string[] ReadDocument(string filePath)
{
return File.ReadAllLines(filePath);
}
}
19 changes: 19 additions & 0 deletions TagsCloudContainer/DocumentReaders/WordDocumentReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using DocumentFormat.OpenXml.Packaging;
using TagsCloudContainer.Interfaces;

namespace TagsCloudContainer.DocumentReaders;

public class WordDocumentReader : IDocumentReader
{
public string[] SupportedDocumentExtensions => [".doc", ".docx"];

public string[] ReadDocument(string filePath)
{
using var doc = WordprocessingDocument.Open(filePath, false);
var body = doc.MainDocumentPart?.Document.Body;
if (body == null) return Array.Empty<string>();

var text = body.InnerText;
return text.Split(new[] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
}
}
13 changes: 13 additions & 0 deletions TagsCloudContainer/Extensions/PointExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Drawing;

namespace TagsCloudContainer.Extensions;

public static class PointExtensions
{
public static double DistanceFromCenter(this Point point, Point center)
{
var dx = point.X - center.X;
var dy = point.Y - center.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
}
64 changes: 64 additions & 0 deletions TagsCloudContainer/Grid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Drawing;

namespace TagsCloudContainer;

public class Grid
{
private readonly int cellSize;
private readonly Dictionary<Point, List<Rectangle>> cells = new();

public Grid(int cellSize = 50)
{
this.cellSize = cellSize;
}
public void AddRectangle(Rectangle rectangle)
{
var cellsToUpdate = GetCellsCoveredByRectangle(rectangle);

foreach (var cell in cellsToUpdate)
{
if (!cells.ContainsKey(cell))
{
cells[cell] = new List<Rectangle>();
}

cells[cell].Add(rectangle);
}
}

public bool IsIntersecting(Rectangle rectangle)
{
var cellsToCheck = GetCellsCoveredByRectangle(rectangle);

foreach (var cell in cellsToCheck)
{
if (!cells.TryGetValue(cell, out var rectanglesInCell))
{
continue;
}

if (rectanglesInCell.Any(r => r.IntersectsWith(rectangle)))
{
return true;
}
}

return false;
}

private IEnumerable<Point> GetCellsCoveredByRectangle(Rectangle rectangle)
{
var startX = rectangle.Left / cellSize;
var endX = rectangle.Right / cellSize;
var startY = rectangle.Top / cellSize;
var endY = rectangle.Bottom / cellSize;

for (var x = startX; x <= endX; x++)
{
for (var y = startY; y <= endY; y++)
{
yield return new Point(x, y);
}
}
}
}
7 changes: 7 additions & 0 deletions TagsCloudContainer/Interfaces/IDocumentReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagsCloudContainer.Interfaces;

public interface IDocumentReader
{
string[] SupportedDocumentExtensions { get; }
string[] ReadDocument(string filePath);
}
8 changes: 8 additions & 0 deletions TagsCloudContainer/Interfaces/IPointGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagsCloudContainer.Interfaces;

public interface IPointGenerator
{
Point GetNextPoint();
}
8 changes: 8 additions & 0 deletions TagsCloudContainer/Interfaces/ITagCloudGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TagsCloudContainer.Options;

namespace TagsCloudContainer.Interfaces;

public interface ITagCloudGenerator
{
void GenerateCloud(string inputFilePath, string outputFilePath, RenderingOptions options);
}
9 changes: 9 additions & 0 deletions TagsCloudContainer/Interfaces/ITagCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagsCloudContainer.Interfaces;

public interface ITagCloudLayouter
{
Rectangle PutNextRectangle(Size rectangleSize);
IEnumerable<Rectangle> GetRectangles();
}
8 changes: 8 additions & 0 deletions TagsCloudContainer/Interfaces/ITagCloudRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TagsCloudContainer.Options;

namespace TagsCloudContainer.Interfaces;

public interface ITagCloudRenderer
{
void Render(IEnumerable<Tag> tags, string outputFilePath, RenderingOptions options);
}
Loading