diff --git a/Directory.Packages.props b/Directory.Packages.props index e7bf014..a52f98e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,26 +6,24 @@ - + - - - - - - - - + + + + + + + - + - + diff --git a/Progrart.Core/PrimitiveDrawingCore.cs b/Progrart.Core/PrimitiveDrawingCore.cs index 8eb9e51..54f53dd 100644 --- a/Progrart.Core/PrimitiveDrawingCore.cs +++ b/Progrart.Core/PrimitiveDrawingCore.cs @@ -20,10 +20,10 @@ namespace Progrart.Core return Fonts[fontName]; else { - var task=StorageProvider.TryOpenRead(fontName); + var task = StorageProvider.TryOpenRead(fontName); task.Wait(); - var stream=task.Result; - if(stream != null) + var stream = task.Result; + if (stream != null) { SKTypeface typeface = SKTypeface.FromStream(stream); @@ -47,6 +47,44 @@ namespace Progrart.Core { return surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100); } + public SKData ToData(SKEncodedImageFormat format) + { + return surface.Snapshot().Encode(format, 100); + } + public SKData ToData(string extension) + { + SKEncodedImageFormat format = SKEncodedImageFormat.Png; + if (extension.StartsWith('.')) + extension = extension[1..]; + switch (extension) + { + case "jpg": + case "jpeg": + format = SKEncodedImageFormat.Jpeg; + break; + case "bmp": + format = SKEncodedImageFormat.Bmp; + break; + case "webp": + format = SKEncodedImageFormat.Webp; + break; + case "ico": + format = SKEncodedImageFormat.Ico; + break; + case "heif": + format = SKEncodedImageFormat.Heif; + break; + case "avif": + format = SKEncodedImageFormat.Avif; + break; + case "jxl": + format = SKEncodedImageFormat.Jpegxl; + break; + default: + break; + } + return surface.Snapshot().Encode(format, 100); + } public void Dispose() { if (isDisposed) return; diff --git a/Progrart.Core/ProjectSystem/Builder.cs b/Progrart.Core/ProjectSystem/Builder.cs index f7bfaed..d67979c 100644 --- a/Progrart.Core/ProjectSystem/Builder.cs +++ b/Progrart.Core/ProjectSystem/Builder.cs @@ -34,10 +34,11 @@ namespace Progrart.Core.ProjectSystem return; using var reader = new StreamReader(stream); var img = executor.RenderImage(item.Size, reader.ReadToEnd(), args); - using var img_stream = await provider.TryOpenWrite(Path.Combine(project.OutputDir, item.Target ?? item.Source + ".png")); + var outputFile= Path.Combine(project.OutputDir, item.Target ?? item.Source + ".png"); + using var img_stream = await provider.TryOpenWrite(outputFile); if (img_stream is null) return; - img.DrawingCore.ToData().SaveTo(img_stream); + img.DrawingCore.ToData(Path.GetExtension(outputFile)).SaveTo(img_stream); img_stream.Flush(); } public async Task Build(string targetConfig, int maxJobCount = 1) diff --git a/Progrart.Core/Storage/CombinedStorageProvider.cs b/Progrart.Core/Storage/CombinedStorageProvider.cs new file mode 100644 index 0000000..eeb3c25 --- /dev/null +++ b/Progrart.Core/Storage/CombinedStorageProvider.cs @@ -0,0 +1,26 @@ +namespace Progrart.Core.Storage +{ + public class CombinedStorageProvider : IStorageProvider + { + public List providers = new List(); + public async Task TryOpenRead(string path) + { + foreach (var item in providers) + { + var v = await item.TryOpenRead(path); + if (v != null) return v; + } + return null; + } + + public async Task TryOpenWrite(string path) + { + foreach (var item in providers) + { + var v = await item.TryOpenWrite(path); + if (v != null) return v; + } + return null; + } + } +} diff --git a/Progrart.slnx b/Progrart.slnx index 2b08454..4887db8 100644 --- a/Progrart.slnx +++ b/Progrart.slnx @@ -13,4 +13,5 @@ + diff --git a/ProgrartC/Dockerfile b/ProgrartC/Dockerfile new file mode 100644 index 0000000..2952664 --- /dev/null +++ b/ProgrartC/Dockerfile @@ -0,0 +1,47 @@ +# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +# These ARGs allow for swapping out the base used to make the final image when debugging from VS +ARG LAUNCHING_FROM_VS +# This sets the base image for final, but only if LAUNCHING_FROM_VS has been defined +ARG FINAL_BASE_IMAGE=${LAUNCHING_FROM_VS:+aotdebug} + +# This stage is used when running from VS in fast mode (Default for Debug configuration) +FROM mcr.microsoft.com/dotnet/runtime:10.0 AS base +USER $APP_UID +WORKDIR /app + + +# This stage is used to build the service project +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +# Install clang/zlib1g-dev dependencies for publishing to native +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + clang zlib1g-dev +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Directory.Packages.props", "."] +COPY ["ProgrartC/ProgrartC.csproj", "ProgrartC/"] +RUN dotnet restore "./ProgrartC/ProgrartC.csproj" +COPY . . +WORKDIR "/src/ProgrartC" +RUN dotnet build "./ProgrartC.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# This stage is used to publish the service project to be copied to the final stage +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./ProgrartC.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=true + +# This stage is used as the base for the final stage when launching from VS to support debugging in regular mode (Default when not using the Debug configuration) +FROM base AS aotdebug +USER root +# Install GDB to support native debugging +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + gdb +USER app + +# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) +FROM ${FINAL_BASE_IMAGE:-mcr.microsoft.com/dotnet/runtime-deps:10.0} AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["./ProgrartC"] \ No newline at end of file diff --git a/ProgrartC/Program.cs b/ProgrartC/Program.cs new file mode 100644 index 0000000..3c82b63 --- /dev/null +++ b/ProgrartC/Program.cs @@ -0,0 +1,102 @@ +using Progrart.Core; +using Progrart.Core.JSExecution; +using Progrart.Core.ProjectSystem; +using Progrart.Core.Storage; +using SkiaSharp; +using System.Diagnostics; + +namespace ProgrartC +{ + internal class Program + { + static void Main(string[] args) + { + Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); + List includePaths = new List(); + string? sourceFile = null; + string? outputFile = null; + ExecuteArguments executeArguments = new ExecuteArguments(); + for (int i = 0; i < args.Length; i++) + { + string? item = args[i]; + switch (item) + { + case "-I": + i++; + includePaths.Add(args[i]); + break; + case "-o": + i++; + outputFile = args[i]; + break; + default: + if (File.Exists(item)) + { + sourceFile = item; + } + else + { + if (item.StartsWith("-D")) + { + string define = item.Substring(2); + string[] parts = define.Split('=', 2); + if (parts.Length == 2) + { + executeArguments.data[parts[0]] = parts[1]; + } + else + { + executeArguments.data[parts[0]] = "true"; + } + } + } + break; + } + } + if (sourceFile == null) + { + Trace.WriteLine("no input files"); + return; + } + if (outputFile == null) + { + outputFile = Path.ChangeExtension(sourceFile, "png"); + } + CombinedStorageProvider storageProvider = new(); + { + FileInfo sourceFileInfo = new FileInfo(sourceFile); + if (sourceFileInfo.Directory is not null) + includePaths.Add(sourceFileInfo.Directory.FullName); + } + if (!includePaths.Contains(".")) + includePaths.Add("."); + foreach (var item in includePaths) + { + storageProvider.providers.Add(new ClassicStorageProvider(new DirectoryInfo(item))); + } + int Scale = 1024; + + if (executeArguments.data.TryGetValue("Scale", out var scale)) + { + if (!int.TryParse(scale, out Scale)) Scale = 1024; + } + ProgrartExecutor progrartExecutor = new(storageProvider); + var result = progrartExecutor.RenderImage(Scale, File.ReadAllText(sourceFile), executeArguments); + + SKData data; + FileInfo fi = new FileInfo(outputFile); + var ext = fi.Extension.ToLower(); + data = result.DrawingCore.ToData(ext); + if(data is null) + { + Trace.WriteLine("failed to encode image"); + return; + } + using var img_stream = File.OpenWrite(outputFile); + if (img_stream is null) + return; + data.SaveTo(img_stream); + img_stream.Flush(); + } + } +} diff --git a/ProgrartC/ProgrartC.csproj b/ProgrartC/ProgrartC.csproj new file mode 100644 index 0000000..c003786 --- /dev/null +++ b/ProgrartC/ProgrartC.csproj @@ -0,0 +1,21 @@ + + + + Exe + net10.0 + enable + enable + true + true + Linux + + + + + + + + + + + diff --git a/ProgrartC/Properties/launchSettings.json b/ProgrartC/Properties/launchSettings.json new file mode 100644 index 0000000..7cf6405 --- /dev/null +++ b/ProgrartC/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "ProgrartC": { + "commandName": "Project" + }, + "Container (Dockerfile)": { + "commandName": "Docker" + } + } +} \ No newline at end of file