diff --git a/Domain/BigFrameLayerRenderResult.cs b/Domain/BigFrameLayerRenderResult.cs index 49817a1..612b1cd 100644 --- a/Domain/BigFrameLayerRenderResult.cs +++ b/Domain/BigFrameLayerRenderResult.cs @@ -1,4 +1,6 @@ -using SkiaSharp; +using Domain.Interfaces; +using Make3.CommonTypes.Interfaces; +using Make3.CommonTypes.Interfaces.Matrices; namespace Domain; @@ -10,6 +12,10 @@ public class BigFrameLayerRenderResult public uint FrameSizeY { get; set; } // или пиксели? - public SKBitmap Frame { get; set; } //типа автомаска + public required IBinaryMask Automask { get; set; } //типа автомаска + public double[,] Table1 { get; set; } + public double[,] Table2 { get; set; } + public double[,] Table3 { get; set; } + public double[,] Table4 { get; set; } public List FrameInfos { get; set; } = []; } \ No newline at end of file diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj index 17118bb..701d2a2 100644 --- a/Domain/Domain.csproj +++ b/Domain/Domain.csproj @@ -8,7 +8,8 @@ - + + diff --git a/Domain/Entities/BinaryMask2.cs b/Domain/Entities/BinaryMask2.cs new file mode 100644 index 0000000..d96dbc4 --- /dev/null +++ b/Domain/Entities/BinaryMask2.cs @@ -0,0 +1,28 @@ +namespace Domain.Entities; + +public class BinaryMask2(uint width, uint height) +{ + public uint Width { get; init; } = width; + public uint Height { get; init; } = height; + + private readonly bool[] _data = new bool[width * height]; + + public void MakeOpaque(uint x, uint y) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(x, Width); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(y, Height); + _data[y * Width + x] = true; + } + + public bool IsOpaque(uint x, uint y) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(x, Width); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(y, Height); + return _data[y * Width + x]; + } + + public bool IsTransparent(uint x, uint y) + { + return !IsOpaque(x, y); + } +} \ No newline at end of file diff --git a/Domain/Entities/IntermediateRenderResult.cs b/Domain/Entities/IntermediateRenderResult.cs new file mode 100644 index 0000000..768743b --- /dev/null +++ b/Domain/Entities/IntermediateRenderResult.cs @@ -0,0 +1,12 @@ +using Make3.CommonTypes.Interfaces; + +namespace Domain.Entities; + +public class IntermediateRenderResult +{ + public required IBinaryMask Automask { get; set; } //типа автомаска + public double[,] Table1 { get; set; } + public double[,] Table2 { get; set; } + public double[,] Table3 { get; set; } + public double[,] Table4 { get; set; } +} \ No newline at end of file diff --git a/Domain/Interfaces/ILayer.cs b/Domain/Interfaces/ILayer.cs index aa4b217..556722b 100644 --- a/Domain/Interfaces/ILayer.cs +++ b/Domain/Interfaces/ILayer.cs @@ -1,13 +1,17 @@ -using SkiaSharp; +using Domain.Entities; +using ImageMagick; +using Make3.CommonTypes.Interfaces; + namespace Domain.Interfaces; public interface ILayer { public uint Order { get; } public OpticalSchema OpticalSchema { get; } - public SKBitmap Image { get; } - public SKBitmap? Mask { get; } + public MagickImage Image { get; } + public IBinaryMask? Mask { get; } public bool InvertMask { get; } public Task Prerender(); - public Task Render(uint x, uint y, uint frameWidth, uint frameHeight, SKBitmap automask); + // public Task Render(uint x, uint y, uint frameWidth, uint frameHeight, MagickImage automask); + public Task Render(uint x, uint y, uint frameWidth, uint frameHeight, IBinaryMask automask); } diff --git a/Domain/Interfaces/IRenderManager.cs b/Domain/Interfaces/IRenderManager.cs index 8a9c26c..3eb0af6 100644 --- a/Domain/Interfaces/IRenderManager.cs +++ b/Domain/Interfaces/IRenderManager.cs @@ -2,7 +2,7 @@ namespace Domain.Interfaces; public interface IRenderManager { - public Task StartRender(Project project); + public Task StartRender(Project.Project project); public Task StopRender(Guid renderId); IEnumerable GetActiveRenders(); } \ No newline at end of file diff --git a/Domain/Project/HardwareSettings.cs b/Domain/Project/HardwareSettings.cs new file mode 100644 index 0000000..1324e3b --- /dev/null +++ b/Domain/Project/HardwareSettings.cs @@ -0,0 +1,11 @@ +namespace Domain.Project; + +public class HardwareSettings +{ + public double Ppu { get; set; } + public double UnitSize { get; set; } + public required IlluminationLevels IlluminationLevels { get; set; } + public required Resolution MatrixResolution { get; set; } + public required Resolution FrameResolution { get; set; } + public required Size FrameSize { get; set; } +} diff --git a/Domain/Project/IlluminationLevels.cs b/Domain/Project/IlluminationLevels.cs new file mode 100644 index 0000000..e66b982 --- /dev/null +++ b/Domain/Project/IlluminationLevels.cs @@ -0,0 +1,3 @@ +namespace Domain.Project; + +public record IlluminationLevels(byte Zero, byte LinearLow, byte LinearHigh); \ No newline at end of file diff --git a/Domain/Project.cs b/Domain/Project/Project.cs similarity index 69% rename from Domain/Project.cs rename to Domain/Project/Project.cs index 5d86834..94af3f4 100644 --- a/Domain/Project.cs +++ b/Domain/Project/Project.cs @@ -1,10 +1,11 @@ using Domain.Interfaces; -namespace Domain; +namespace Domain.Project; public class Project { public Guid Id { get; set; } public IEnumerable Layers { get; set; } = []; public uint Width { get; set; } public uint Height { get; set; } + public required HardwareSettings HardwareSettings { get; set; } } \ No newline at end of file diff --git a/Domain/Project/Resolution.cs b/Domain/Project/Resolution.cs new file mode 100644 index 0000000..12d53d8 --- /dev/null +++ b/Domain/Project/Resolution.cs @@ -0,0 +1,3 @@ +namespace Domain.Project; + +public record Resolution(uint X, uint Y); \ No newline at end of file diff --git a/Domain/Project/Size.cs b/Domain/Project/Size.cs new file mode 100644 index 0000000..4c34c3a --- /dev/null +++ b/Domain/Project/Size.cs @@ -0,0 +1,9 @@ +namespace Domain.Project; + +public record Size(decimal Width, decimal Height, SizeUnit Unit); + +public enum SizeUnit +{ + um, + mm +} \ No newline at end of file diff --git a/Domain/Render.cs b/Domain/Render.cs index 8e608fc..a77689d 100644 --- a/Domain/Render.cs +++ b/Domain/Render.cs @@ -1,6 +1,9 @@ using System.Threading.Channels; using Domain.Interfaces; using Domain.RenderPart; +using Make3.CommonTypes.Interfaces.Matrices; + +//using Make3.CommonTypes.BinaryMask; namespace Domain; @@ -15,9 +18,13 @@ public class Render private readonly bool _useBigFrames = true; private readonly CancellationTokenSource _cancellationTokenSource = new(); + //private readonly BinaryMaskFactory _binaryMaskFactory; + private IMatrixAbstractFactory BinaryMaskFactory; + private readonly IMatrixAbstractFactory _binaryMaskFactory; - public Render(Project project) + public Render(Project.Project project, IMatrixAbstractFactory binaryMaskFactory) { + _binaryMaskFactory = binaryMaskFactory; Id = Guid.NewGuid(); ProjectId = project.Id; _width = project.Width; @@ -56,7 +63,7 @@ public class Render for (uint x = 0; x < _width; x += bigFrameWidth) { uint currentBigFrameWidth = Math.Min(bigFrameWidth, _width - x); - var bigFrameRender = new BigFrameRender(_layers, x, y, currentBigFrameWidth, currentBigFrameHeight, Id); + var bigFrameRender = new BigFrameRender(_binaryMaskFactory, _layers, x, y, currentBigFrameWidth, currentBigFrameHeight, Id); await channel.Writer.WriteAsync(bigFrameRender); } } diff --git a/Domain/RenderManager.cs b/Domain/RenderManager.cs index 896e6e0..21b107e 100644 --- a/Domain/RenderManager.cs +++ b/Domain/RenderManager.cs @@ -1,6 +1,8 @@ using System.Collections.Concurrent; using System.Threading.Channels; using Domain.Interfaces; +//using Make3.CommonTypes.BinaryMask; +using Make3.CommonTypes.Interfaces.Matrices; namespace Domain; @@ -8,9 +10,12 @@ public class RenderManager : IRenderManager { private readonly Channel _taskChannel; private readonly ConcurrentDictionary _renders = []; + //private readonly BinaryMaskFactory _binaryMaskFactory; + private IMatrixAbstractFactory _binaryMaskFactory; - public RenderManager(int channelCapacity = 5) + public RenderManager(IMatrixAbstractFactory binaryMaskFactory, int channelCapacity = 5) { + _binaryMaskFactory = binaryMaskFactory; var options = new BoundedChannelOptions(channelCapacity) { FullMode = BoundedChannelFullMode.Wait // Ожидание при переполнении канала @@ -18,15 +23,26 @@ public class RenderManager : IRenderManager _taskChannel = Channel.CreateBounded(options); } - public Task StartRender(Project project) + // public Task StartRender(Project project) + // { + // var render = new Render(project); + // if (_renders.TryAdd(render.Id, render)) + // { + // _ =render.Run(_taskChannel); + // } + // _ = ProcessQueue(); + // return Task.FromResult(render.Id); + // } + // public Task StartRender(Project project) + public async Task StartRender(Project.Project project) { - var render = new Render(project); + var render = new Render(project, _binaryMaskFactory); if (_renders.TryAdd(render.Id, render)) { - _ =render.Run(_taskChannel); + await render.Run(_taskChannel); } _ = ProcessQueue(); - return Task.FromResult(render.Id); + return render.Id; } private async Task ProcessQueue(CancellationToken cancellationToken = default) diff --git a/Domain/RenderPart/BigFrameRender.cs b/Domain/RenderPart/BigFrameRender.cs index 4a6525f..cea2d0c 100644 --- a/Domain/RenderPart/BigFrameRender.cs +++ b/Domain/RenderPart/BigFrameRender.cs @@ -1,5 +1,7 @@ using Domain.Interfaces; -using SkiaSharp; +using Make3.CommonTypes.Interfaces; +using Make3.CommonTypes.Interfaces.Matrices; +//using Make3.CommonTypes.BinaryMask; namespace Domain.RenderPart; @@ -7,8 +9,9 @@ public class BigFrameRender : RenderPartBase { private readonly uint _bigFrameWidth; private readonly uint _bigFrameHeight; - public BigFrameRender(IEnumerable layers, uint row, uint col, uint bigFrameWidth, uint bigFrameHeight, Guid renderId) : - base(layers, row, col, renderId) + public BigFrameRender(IMatrixAbstractFactory matrixAbstractFactory, IEnumerable layers, + uint row, uint col, uint bigFrameWidth, uint bigFrameHeight, Guid renderId) : + base(matrixAbstractFactory, layers, row, col, renderId) { _bigFrameWidth = bigFrameWidth; _bigFrameHeight = bigFrameHeight; @@ -56,12 +59,20 @@ public class BigFrameRender : RenderPartBase private async Task RenderBigFrame(ILayer layer, uint x, uint y, uint bigFrameWidth, uint bigFrameHeight, BigFrameLayerRenderResult? previousLayerResult) { - var automask = previousLayerResult?.Frame ?? new SKBitmap(Convert.ToInt32(bigFrameWidth), Convert.ToInt32(bigFrameHeight)); + var automask = previousLayerResult?.Automask ?? + ((IBinaryMaskFactory)_matrixAbstractFactory.GetFactory()) + .Create((int)bigFrameWidth, (int)bigFrameHeight, previousLayerResult?.Automask.GetBlackCellsPercentage() ?? 0); var result = new BigFrameLayerRenderResult() { - Frame = new SKBitmap(Convert.ToInt32(bigFrameWidth), Convert.ToInt32(bigFrameHeight)), + // Frame = new MagickImage(Convert.ToInt32(bigFrameWidth), Convert.ToInt32(bigFrameHeight)), + Automask = automask, }; - result.Frame = await layer.Render(x, y, bigFrameWidth, bigFrameHeight, automask); + var renderResult = await layer.Render(x, y, bigFrameWidth, bigFrameHeight, automask); + result.Automask = renderResult.Automask; + // result.Table1 = renderResult.Table1; + // result.Table2 = renderResult.Table2; + // result.Table3 = renderResult.Table3; + // result.Table4 = renderResult.Table4; return result; } diff --git a/Domain/RenderPart/RenderPartBase.cs b/Domain/RenderPart/RenderPartBase.cs index 883ec32..b741c97 100644 --- a/Domain/RenderPart/RenderPartBase.cs +++ b/Domain/RenderPart/RenderPartBase.cs @@ -1,4 +1,6 @@ using Domain.Interfaces; +//using Make3.CommonTypes.BinaryMask; +using Make3.CommonTypes.Interfaces.Matrices; namespace Domain.RenderPart; @@ -8,11 +10,13 @@ public abstract class RenderPartBase : IFrameRender protected uint _row; protected uint _col; + protected IMatrixAbstractFactory _matrixAbstractFactory; public Guid RenderId { get; private set; } - protected RenderPartBase(IEnumerable layers, uint row, uint col, Guid renderId) + protected RenderPartBase(IMatrixAbstractFactory matrixAbstractFactory, IEnumerable layers, uint row, uint col, Guid renderId) { + _matrixAbstractFactory = matrixAbstractFactory; _layers = layers; _row = row; _col = col; diff --git a/Domain/RenderResult.cs b/Domain/RenderResult.cs index 442bbfa..61d7e06 100644 --- a/Domain/RenderResult.cs +++ b/Domain/RenderResult.cs @@ -1,3 +1,5 @@ +using Domain.Entities; + namespace Domain; public class RenderResult diff --git a/Make3.RenderServer/Grpc/GrpcConverters.cs b/Make3.RenderServer/Grpc/GrpcConverters.cs new file mode 100644 index 0000000..dafb5b8 --- /dev/null +++ b/Make3.RenderServer/Grpc/GrpcConverters.cs @@ -0,0 +1,117 @@ +using Google.Protobuf; +using LayerClients; + +namespace Make3.RenderServer.Grpc; + +public static class GrpcConverters +{ + private const int StreamChunkSize = 4096; // Размер чанка (4 КБ) + public static double[,] DecodeMatrix(List grpcMatrix) + { + if (grpcMatrix == null || grpcMatrix.Count == 0) + { + throw new ArgumentException("The input grpcMatrix is null or empty."); + } + + // Определяем размерность массива + int rows = grpcMatrix.Count; + int cols = grpcMatrix[0].Values.Count; + + // Создаём двумерный массив + double[,] matrix = new double[rows, cols]; + + // Заполняем массив данными из grpcMatrix + for (int i = 0; i < rows; i++) + { + if (grpcMatrix[i].Values.Count != cols) + { + throw new InvalidOperationException("All rows in grpcMatrix must have the same number of columns."); + } + + for (int j = 0; j < cols; j++) + { + matrix[i, j] = grpcMatrix[i].Values[j]; + } + } + + return matrix; + } + + public static Stream AppendToStream(Stream stream, IEnumerable matrix) + { + using var writer = new BinaryWriter(stream, System.Text.Encoding.Default, true); + foreach (var row in matrix) + { + foreach (var value in row.Values) + { + writer.Write(value); + } + } + + stream.Position = 0; + return stream; + } + + public static double[,] ConvertStreamToMatrix(Stream stream, uint rows, uint columns) + { + var matrix = new double[rows, columns]; + + using var reader = new BinaryReader(stream); + for (uint y = 0; y < rows; y++) + { + for (uint x = 0; x < columns; x++) + { + if (reader.BaseStream.Position < reader.BaseStream.Length) + { + matrix[y, x] = reader.ReadDouble(); // Читаем `double` из потока + } + else + { + throw new EndOfStreamException("Not enough data to read from stream."); + // matrix[y, x] = 0; // Заполняем нулями, если данных недостаточно + } + } + } + + return matrix; + } + + public static async Task SendStream(Stream stream, Func sendChunk) + { + var buffer = new byte[StreamChunkSize]; + int bytesRead; + + while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) + { + await sendChunk(ByteString.CopyFrom(buffer, 0, bytesRead)); + } + } + public static void ReceiveStream(string outputPath, Func getChunk) + { + using var fileStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write); + ByteString chunk; + + while ((chunk = getChunk()) != null) + { + fileStream.Write(chunk.ToByteArray()); + } + } + + public static DecimalValue ConvertDecimalValue(decimal value) + { + var nanoFactor = 1_000_000_000; + var units = decimal.ToInt64(value); + var nanos = decimal.ToInt32((value - units) * nanoFactor); + return new DecimalValue + { + Units = units, + Nanos = nanos, + }; + } + + public static decimal ConvertDecimalValue(DecimalValue value) + { + var nanoFactor = 1_000_000_000; + return value.Units + value.Nanos / nanoFactor; + } +} \ No newline at end of file diff --git a/Make3.RenderServer/Grpc/Protos/Layers/test-layer.proto b/Make3.RenderServer/Grpc/Protos/Layers/test-layer.proto index 91b4b03..fda112a 100644 --- a/Make3.RenderServer/Grpc/Protos/Layers/test-layer.proto +++ b/Make3.RenderServer/Grpc/Protos/Layers/test-layer.proto @@ -3,24 +3,81 @@ import "google/protobuf/wrappers.proto"; option csharp_namespace = "LayerClients"; service TestLayer { - rpc Prerender (PrerenderRequest) returns (PrerenderResponse); + rpc StreamPrerenderData (stream PrerenderRequest) returns (stream PrerenderResponse); rpc Render (RenderRequest) returns (RenderResponse); } message PrerenderRequest { - string optical_schema_data = 1; - bytes mask = 2; - bytes image = 3; - bool invert_mask = 4; + ProjectData project_data = 1; + HardwareData hardware_data = 2; + string optical_schema_data = 3; + bytes image = 4; + google.protobuf.BytesValue mask = 5; + google.protobuf.BoolValue invert_mask = 6; + double difraction_angle = 7; + bool posterize_result = 8; + bool invert_profile = 9; + bool invert_horizontal_angle = 10; + double direct_angle = 11; + double angle_of_view = 12; + double object_angle = 13; + double horizontal_roughness = 14; + double vertical_roughness = 15; +} + +message ProjectData { + double hologram_width = 1; + double hologram_Height = 2; +} + +message HardwareData { + double ppu = 1; + double unit_size = 2; + IlluminationLevels illumination_levels = 3; + Resolution matrix_resolution = 4; + Resolution frame_resolution = 5; + Size frame_size = 6; +} + +message IlluminationLevels { + int32 zero = 1; + int32 linear_low = 2; + int32 linear_high = 3; +} + +message Resolution { + uint32 x = 1; + uint32 y = 2; +} + +message Size { + DecimalValue width = 1; + DecimalValue height = 2; + SizeUnit unit = 3; +} + +message DecimalValue { + // Whole units part of the amount + int64 units = 1; + // Nano units of the amount (10^-9) + // Must be same sign as units + sfixed32 nanos = 2; +} + +enum SizeUnit { + um = 0; + mm = 1; } message PrerenderResponse { - string status = 1; - repeated MatrixRow test_matrix = 2; // Представляем матрицу через строки + repeated MatrixRow grating_period = 1; + repeated MatrixRow angles_horizontal = 2; + repeated MatrixRow phases = 3; + repeated MatrixRow saturation = 4; } message MatrixRow { - repeated double values = 1; // Значения одной строки матрицы + repeated double values = 1; } message RenderRequest { diff --git a/Make3.RenderServer/Layers/TestLayer.cs b/Make3.RenderServer/Layers/TestLayer.cs index 94f7139..f664819 100644 --- a/Make3.RenderServer/Layers/TestLayer.cs +++ b/Make3.RenderServer/Layers/TestLayer.cs @@ -1,62 +1,184 @@ using Domain; +using Domain.Entities; using Domain.Interfaces; +using Domain.Project; using Google.Protobuf; +using Grpc.Core; +using ImageMagick; using LayerClients; -using SkiaSharp; +using Make3.CommonTypes.Interfaces; +using Make3.CommonTypes.Interfaces.Matrices; +using Make3.RenderServer.Grpc; +using IlluminationLevels = LayerClients.IlluminationLevels; +using Resolution = LayerClients.Resolution; +using Size = LayerClients.Size; +using SizeUnit = LayerClients.SizeUnit; namespace Make3.RenderServer.Layers; -public class TestLayer(LayerClients.TestLayer.TestLayerClient grpcClient) : ILayer +public class TestLayer(LayerClients.TestLayer.TestLayerClient grpcClient, IMatrixAbstractFactory matrixAbstractFactory) : ILayer { public uint Order { get; init; } public OpticalSchema OpticalSchema { get; init; } - public SKBitmap? Mask { get; init; } - public required SKBitmap Image { get; init; } + public IBinaryMask? Mask { get; init; } + public required MagickImage Image { get; init; } public bool InvertMask { get; init; } + + + public HardwareSettings HardwareSettings { get; init; } + public double HologramWidth { get; init; } + public double HologramHeight { get; init; } + + public double DifractionAngle { get; set; } + public bool PosterizeResult { get; set; } + public bool InvertProfile { get; set; } + public bool InvertHorizontalAngle { get; set; } + + //Освещение голограммы + public double DirectAngle { get; set; } + public double AngleOfView { get; set; } + /// + /// компенсация для кристалла + /// + public double ObjectAngle { get; set; } + + public double HorizontalRoughness { get; set; } + public double VerticalRoughness { get; set; } private readonly LayerClients.TestLayer.TestLayerClient _grpcClient = grpcClient; + private readonly IMatrixAbstractFactory _matrixAbstractFactory = matrixAbstractFactory; public async Task Prerender() { - using var imageData = Image.Encode(SKEncodedImageFormat.Png, 100); - using var maskData = Mask?.Encode(SKEncodedImageFormat.Png, 100); - var request = new PrerenderRequest + var imageData = Image.ToByteArray(MagickFormat.Png); + using var call = _grpcClient.StreamPrerenderData(); + await GrpcConverters.SendStream(new MemoryStream(imageData), async (imageChunk) => { - OpticalSchemaData = OpticalSchema.ToString(), - Image = ByteString.CopyFrom(imageData.Span), - }; - if (maskData != null) + var request = MakePrerenderRequest(); + request.Image = imageChunk; + await call.RequestStream.WriteAsync(request); + }); + + if (Mask != null) { - request.Mask = ByteString.CopyFrom(maskData.Span); - request.InvertMask = InvertMask; + await GrpcConverters.SendStream(Mask.GetStream(), async (maskChunk) => + { + var request = MakePrerenderRequest(); + request.Mask = maskChunk; + request.InvertMask = InvertMask; + await call.RequestStream.WriteAsync(request); + }); + // request.Mask = ByteString.CopyFrom(maskData); + // request.InvertMask = InvertMask; } - var response = await _grpcClient.PrerenderAsync(request); + + await call.RequestStream.CompleteAsync(); + Stream gratingStream = new MemoryStream(); + Stream anglesStream = new MemoryStream(); + Stream phasesStream = new MemoryStream(); + Stream saturationStream = new MemoryStream(); + Stream table1Stream = new MemoryStream(); // Тестовая таблица + + await foreach (var response in call.ResponseStream.ReadAllAsync()) + { + GrpcConverters.AppendToStream(gratingStream, response.GratingPeriod); + GrpcConverters.AppendToStream(anglesStream, response.AnglesHorizontal); + GrpcConverters.AppendToStream(phasesStream, response.Phases); + GrpcConverters.AppendToStream(saturationStream, response.Saturation); + // GrpcConverters.DecodeMatrix(table1Stream, response.Table1); // Чтение тестовой таблицы + } + // var response = await _grpcClient.PrerenderAsync(request); + var m1 = GrpcConverters.ConvertStreamToMatrix(gratingStream, Image.Width, Image.Height); + } - public async Task Render(uint x, uint y, uint frameWidth, uint frameHeight, SKBitmap? automask) + private PrerenderRequest MakePrerenderRequest() + { + return new PrerenderRequest + { + ProjectData = new ProjectData + { + HologramWidth = HologramWidth, + HologramHeight = HologramHeight, + }, + HardwareData = new HardwareData() + { + Ppu = HardwareSettings.Ppu, + UnitSize = HardwareSettings.UnitSize, + IlluminationLevels = new IlluminationLevels + { + Zero = HardwareSettings.IlluminationLevels.Zero, + LinearLow = HardwareSettings.IlluminationLevels.LinearLow, + LinearHigh = HardwareSettings.IlluminationLevels.LinearHigh, + }, + MatrixResolution = new Resolution + { + X = HardwareSettings.MatrixResolution.X, + Y = HardwareSettings.MatrixResolution.Y, + }, + FrameResolution = new Resolution + { + X = HardwareSettings.FrameResolution.X, + Y = HardwareSettings.FrameResolution.Y, + }, + FrameSize = new Size + { + Width = GrpcConverters.ConvertDecimalValue(HardwareSettings.FrameSize.Width), + Height = GrpcConverters.ConvertDecimalValue(HardwareSettings.FrameSize.Height), + Unit = HardwareSettings.FrameSize.Unit switch + { + Domain.Project.SizeUnit.um => SizeUnit.Um, + Domain.Project.SizeUnit.mm => SizeUnit.Mm, + _ => throw new NotImplementedException() + }, + } + }, + OpticalSchemaData = OpticalSchema.ToString(), + // Image = ByteString.CopyFrom(imageData), + DifractionAngle = DifractionAngle, + PosterizeResult = PosterizeResult, + InvertProfile = InvertProfile, + InvertHorizontalAngle = InvertHorizontalAngle, + VerticalRoughness = VerticalRoughness, + HorizontalRoughness = HorizontalRoughness, + + DirectAngle = DirectAngle, + AngleOfView = AngleOfView, + ObjectAngle = ObjectAngle, + }; + } + + + public async Task Render(uint x, uint y, uint frameWidth, uint frameHeight, IBinaryMask? automask) { //здесь надо кусок изображения взять - using var imageData = Image.Encode(SKEncodedImageFormat.Png, 100); - using var maskData = Mask?.Encode(SKEncodedImageFormat.Png, 100); - using var automaskData = automask?.Encode(SKEncodedImageFormat.Png, 100); + var imageData = Image.ToByteArray(MagickFormat.Png); + // var maskData = Mask?.ToByteArray(MagickFormat.Png); + IBinaryMask? maskData = null; + // using var automaskData = automask?.Encode(SKEncodedImageFormat.Png, 100); + byte[]? automaskData = null; var request = new RenderRequest { X = x, Y = y, FrameWidth = frameWidth, FrameHeight = frameHeight, - Image = ByteString.CopyFrom(imageData.Span), + Image = ByteString.CopyFrom(imageData), // Automask = ByteString.CopyFrom(imageData.Span), }; if (maskData != null) { - request.Mask = ByteString.CopyFrom(maskData.Span); - request.InvertMask = InvertMask; + // request.Mask = ByteString.CopyFrom(maskData); + // request.InvertMask = InvertMask; } - request.Automask = automaskData == null ? null : ByteString.CopyFrom(automaskData.Span); + request.Automask = automaskData == null ? null : ByteString.CopyFrom(automaskData); var response = await _grpcClient.RenderAsync(request); var byteArray = response.RenderedImage.ToByteArray(); - return SKBitmap.Decode(byteArray); + return new IntermediateRenderResult + { + Automask = ((IBinaryMaskFactory)matrixAbstractFactory.GetFactory()) + .Create(10, 20, 0), + }; } } \ No newline at end of file diff --git a/Make3.RenderServer/Program.cs b/Make3.RenderServer/Program.cs index c40f162..2606f3d 100644 --- a/Make3.RenderServer/Program.cs +++ b/Make3.RenderServer/Program.cs @@ -1,5 +1,7 @@ using Domain; using Domain.Interfaces; +using Make3.CommonTypes.Interfaces.Matrices; +using Make3.CommonTypes.Matrices; using Make3.RenderServer; var builder = WebApplication.CreateBuilder(args); @@ -8,6 +10,7 @@ var builder = WebApplication.CreateBuilder(args); // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); +builder.Services.AddScoped(); builder.Services.AddScoped(); // builder.Services.AddGrpc(); diff --git a/Make3.RenderServer/TestProjectBackgroundService.cs b/Make3.RenderServer/TestProjectBackgroundService.cs index 46958c0..d126660 100644 --- a/Make3.RenderServer/TestProjectBackgroundService.cs +++ b/Make3.RenderServer/TestProjectBackgroundService.cs @@ -1,7 +1,10 @@ using Domain; using Domain.Interfaces; +using Domain.Project; +using ImageMagick; +using Make3.CommonTypes.Interfaces; +using Make3.CommonTypes.Interfaces.Matrices; using Make3.RenderServer.Layers; -using SkiaSharp; namespace Make3.RenderServer; @@ -18,44 +21,101 @@ public class TestProjectBackgroundService : BackgroundService protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - var dir = @"C:\Users\Ko12A\OneDrive\Изображения"; - var image1 = OpenImage(Path.Combine(dir, "01_gettyimages_488111026_resized.jpg")); - var image2 = OpenImage(Path.Combine(dir, "kisspng-bmp-file-for.bmp")); - var image3 = OpenImage(Path.Combine(dir, "Zrzut ekranu 2021-07-20 164131.png")); + var dir = @"C:\DOTProjects\ImagesForNewM3"; + var image1 = new MagickImage(Path.Combine(dir, "CrystalTest1_2083x2083_16bit.png"));//"Sphere16b-0.png")); + var image2 = new MagickImage(Path.Combine(dir, "Crystal_Mask_2083x2083.png")); + var image3 = new MagickImage(Path.Combine(dir, "AMask.png")); + + using var scope = _serviceProvider.CreateScope(); + var matrixAbstractFactory = scope.ServiceProvider.GetRequiredService(); var project = new Project { Id = Guid.NewGuid(), + HardwareSettings = new HardwareSettings + { + Ppu = 76.8d, + UnitSize = 12, + IlluminationLevels = new IlluminationLevels(14, 110, 222), + MatrixResolution = new Resolution(1920, 1080), + FrameResolution = new Resolution(1536, 1024), + FrameSize = new Size(240, 160, SizeUnit.um), + }, Height = Convert.ToUInt32(image1.Width), - Width = Convert.ToUInt32(image2.Width), - Layers = [ - new TestLayer(_testLaterGrpcClient) - { - Order = 0, - Image = image1, - OpticalSchema = OpticalSchema.Sp11, - }, - new TestLayer(_testLaterGrpcClient) - { - Order = 1, - Image = image2, - Mask = image3, - InvertMask = false, - OpticalSchema = OpticalSchema.Sp11, - }, - ], + Width = Convert.ToUInt32(image1.Height), }; - using var scope = _serviceProvider.CreateScope(); + project.Layers = + [ + new TestLayer(_testLaterGrpcClient, matrixAbstractFactory) + { + Order = 0, + Image = image1, + Mask = ConvertImageToMask(matrixAbstractFactory, image2), + HologramWidth = 25.0, + HologramHeight = 25.0, + HardwareSettings = project.HardwareSettings, + OpticalSchema = OpticalSchema.Sp11, + InvertMask = false, + DifractionAngle = 33.0, + PosterizeResult = false, + InvertProfile = false, + InvertHorizontalAngle = false, + DirectAngle = 90.0, + AngleOfView = 180.0, + ObjectAngle = 80.0,//90.0 + 10,//35, + HorizontalRoughness = 0.0, + VerticalRoughness = 0.0, + }, + new TestLayer(_testLaterGrpcClient, matrixAbstractFactory) + { + Order = 1, + Image = image2, + Mask = ConvertImageToMask(matrixAbstractFactory, image3), + InvertMask = false, + OpticalSchema = OpticalSchema.Sp11, + }, + ]; var renderManager = scope.ServiceProvider.GetRequiredService(); var renderId = await renderManager.StartRender(project); } - - private SKBitmap OpenImage(string filename) - { - using SKBitmap bitmap = SKBitmap.Decode(filename); - return bitmap.Copy(); - } - + private IBinaryMask ConvertImageToMask(IMatrixAbstractFactory matrixAbstractFactory, MagickImage image) + { + var binaryMaskFactory = (IBinaryMaskFactory)matrixAbstractFactory.GetFactory(); + var result = binaryMaskFactory.Create((int)image.Width, (int)image.Height, 0); + using var pixels = image.GetPixels(); + // for (uint y = 0; y < image.Height; y++) + // { + // for (uint x = 0; x < image.Width; x++) + // { + // var pixel = image.GetPixels().GetPixel((int)x, (int)y); + // var red = pixel.ToColor()?.R ?? 0; + // // var blue = pixel.ToColor()?.B ?? 0; + // // var green = pixel.ToColor()?.G ?? 0; + // var intensity = red;// + blue + green; + // if (intensity == 0) + // { + // result.MakeOpaque(x, y); + // } + // } + // } /// 13 sec - 3 Ch 10sec - 1 ch + + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + var intensity = pixels.GetPixel(x, y).ToColor().R; + //+ pixels.GetPixel(x, y).ToColor().G + pixels.GetPixel(x, y).ToColor().B; + + if (intensity == 0) + { + result.MakeOpaque(x, y); + } + } + } /// 13sec - 3ch, 5 sec - 1 ch + + var p = result.GetBlackCellsPercentage(); + return result; + } } \ No newline at end of file