First commit

This commit is contained in:
DESKTOP-QG096I2\RentPc
2025-07-23 20:55:18 +03:00
parent 6c99a025fd
commit 361c920574
40 changed files with 1319 additions and 0 deletions
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,132 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\watermark.net.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:watermark.net.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\watermark.net.csproj||{04B8AB82-A572-4FEF-95CE-5222444B6B64}|",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:watermark.net.csproj||{04B8AB82-A572-4FEF-95CE-5222444B6B64}|"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.common\\watermarker.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.common\\watermarker.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\sourceimage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\sourceimage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\imagewatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\imagewatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\textwatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\textwatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Watermark.Net.csproj",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeDocumentMoniker": "Watermark.Net.csproj",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeToolTip": "Watermark.Net.csproj",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2025-07-23T00:08:42.641Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "ImageWatermark.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\ImageWatermark.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\ImageWatermark.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\ImageWatermark.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\ImageWatermark.cs",
"ViewState": "AgIAAA4AAAAAAAAAAAAQwEMAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:18:31.318Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "SourceImage.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\SourceImage.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\SourceImage.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\SourceImage.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\SourceImage.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:18:29.952Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Watermark.Net",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeDocumentMoniker": "Watermark.Net.csproj",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeToolTip": "Watermark.Net.csproj",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2025-07-22T00:16:02.548Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "UnitTest.cs",
"DocumentMoniker": "D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs",
"RelativeDocumentMoniker": "..\\..\\..\\Watermark.NET\\UnitTest\\UnitTest.cs",
"ToolTip": "D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs",
"RelativeToolTip": "..\\..\\..\\Watermark.NET\\UnitTest\\UnitTest.cs",
"ViewState": "AgIAABgAAAAAAAAAAADgvyYAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:10:06.88Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "TextWatermark.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\TextWatermark.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\TextWatermark.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\TextWatermark.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\TextWatermark.cs",
"ViewState": "AgIAABoAAAAAAAAAAAAUwFIAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-21T23:58:35.959Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "Watermarker.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Common\\Watermarker.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Common\\Watermarker.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Common\\Watermarker.cs",
"RelativeToolTip": "src\\WatermarkNet.Common\\Watermarker.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABUAAAAcAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-15T22:39:18.693Z"
}
]
}
]
}
]
}
@@ -0,0 +1,132 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\watermark.net.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:watermark.net.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\watermark.net.csproj||{04B8AB82-A572-4FEF-95CE-5222444B6B64}|",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:watermark.net.csproj||{04B8AB82-A572-4FEF-95CE-5222444B6B64}|"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.common\\watermarker.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.common\\watermarker.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\sourceimage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\sourceimage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\imagewatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\imagewatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|d:\\dev\\getready\\watermark.net\\watermark.net\\src\\watermarknet.types\\textwatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}|Watermark.Net.csproj|solutionrelative:src\\watermarknet.types\\textwatermark.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Watermark.Net.csproj",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeDocumentMoniker": "Watermark.Net.csproj",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeToolTip": "Watermark.Net.csproj",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2025-07-23T00:08:42.641Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "ImageWatermark.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\ImageWatermark.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\ImageWatermark.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\ImageWatermark.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\ImageWatermark.cs",
"ViewState": "AgIAAA4AAAAAAAAAAAAQwEMAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:18:31.318Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "SourceImage.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\SourceImage.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\SourceImage.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\SourceImage.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\SourceImage.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:18:29.952Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Watermark.Net",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeDocumentMoniker": "Watermark.Net.csproj",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\Watermark.Net.csproj",
"RelativeToolTip": "Watermark.Net.csproj",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2025-07-22T00:16:02.548Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "UnitTest.cs",
"DocumentMoniker": "D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs",
"RelativeDocumentMoniker": "..\\..\\..\\Watermark.NET\\UnitTest\\UnitTest.cs",
"ToolTip": "D:\\dev\\Watermark.NET\\UnitTest\\UnitTest.cs",
"RelativeToolTip": "..\\..\\..\\Watermark.NET\\UnitTest\\UnitTest.cs",
"ViewState": "AgIAABgAAAAAAAAAAADgvyYAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-22T00:10:06.88Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "TextWatermark.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\TextWatermark.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Types\\TextWatermark.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Types\\TextWatermark.cs",
"RelativeToolTip": "src\\WatermarkNet.Types\\TextWatermark.cs",
"ViewState": "AgIAABoAAAAAAAAAAAAUwFIAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-21T23:58:35.959Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "Watermarker.cs",
"DocumentMoniker": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Common\\Watermarker.cs",
"RelativeDocumentMoniker": "src\\WatermarkNet.Common\\Watermarker.cs",
"ToolTip": "D:\\dev\\GetReady\\Watermark.Net\\Watermark.Net\\src\\WatermarkNet.Common\\Watermarker.cs",
"RelativeToolTip": "src\\WatermarkNet.Common\\Watermarker.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABUAAAAcAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-07-15T22:39:18.693Z"
}
]
}
]
}
]
}
+21
View File
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<AssemblyVersion>0.25.7.23</AssemblyVersion>
<Title>Waternark.NET</Title>
<Authors>Geckon01</Authors>
<Description>Watermark.Net is .NET library for adding text and image watermarks to images. Built on SixLabors.ImageSharp, it provides a simple yet comprehensive API for all your watermarking needs.</Description>
<FileVersion>0.25.7.23</FileVersion>
<Version>0.25.7.23</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.3" />
</ItemGroup>
</Project>
+43
View File
@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Watermark.Net", "Watermark.Net.csproj", "{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "..\UnitTest\UnitTest.csproj", "{26E6D8A0-CFB1-4A30-A4DD-D6DBBDADB388}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "..\Sample\Sample.csproj", "{E28B3D42-E65D-4178-A25B-8B76FC6F9673}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Watrmark.Net CLI", "..\Watrmark.Net CLI\Watrmark.Net CLI.csproj", "{EC1F992E-6B68-45E7-8879-8576F728A6F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5000C6D8-A7CD-4815-A724-EEE51AD8AFDA}.Release|Any CPU.Build.0 = Release|Any CPU
{26E6D8A0-CFB1-4A30-A4DD-D6DBBDADB388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26E6D8A0-CFB1-4A30-A4DD-D6DBBDADB388}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26E6D8A0-CFB1-4A30-A4DD-D6DBBDADB388}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26E6D8A0-CFB1-4A30-A4DD-D6DBBDADB388}.Release|Any CPU.Build.0 = Release|Any CPU
{E28B3D42-E65D-4178-A25B-8B76FC6F9673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E28B3D42-E65D-4178-A25B-8B76FC6F9673}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E28B3D42-E65D-4178-A25B-8B76FC6F9673}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E28B3D42-E65D-4178-A25B-8B76FC6F9673}.Release|Any CPU.Build.0 = Release|Any CPU
{EC1F992E-6B68-45E7-8879-8576F728A6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC1F992E-6B68-45E7-8879-8576F728A6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC1F992E-6B68-45E7-8879-8576F728A6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC1F992E-6B68-45E7-8879-8576F728A6F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BDD35E29-9EA2-4833-B2F4-26E051B7AF10}
EndGlobalSection
EndGlobal
@@ -0,0 +1,342 @@
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Watermark.Net.src.WatermarkNet.Enums;
using Watermark.Net.src.WatermarkNet.Types;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Image = SixLabors.ImageSharp.Image;
namespace Watermark.Net.src.WatermarkNet.Core
{
public class Watermarker
{
private string _outputDir;
/// <summary>
/// Gets or sets the output directory for processed images.
/// </summary>
public string OutputDir { get { return _outputDir; } set { _outputDir = value; } }
public Watermarker()
{
}
public Watermarker(string outputDir)
{
_outputDir = outputDir;
}
/// <summary>
/// Processes all images in a directory applying watermark.
/// </summary>
/// <param name="directory">Source directory containing images to process.</param>
/// <param name="watermark">Watermark configuration.</param>
/// <returns>List of processed images with watermark information.</returns>
public List<WmarkedImage> ProcessDirectory<T>(string directory, T watermark)
where T : WatermarkImageBase
{
List<WmarkedImage> processedImages = new List<WmarkedImage>();
foreach (var imageFile in Directory.GetFiles(directory))
{
//Do not process directories and hidden files
if (File.GetAttributes(imageFile).HasFlag(FileAttributes.Directory) || File.GetAttributes(imageFile).HasFlag(FileAttributes.Hidden))
continue;
WmarkedImage? resultedImage = null;
if (typeof(T).IsAssignableTo(typeof(ImageWatermark)))
{
var concreateWatermark = (ImageWatermark)Convert.ChangeType(watermark, typeof(ImageWatermark));
resultedImage = ProcessImage(imageFile, this.OutputDir, concreateWatermark);
}
if (typeof(T).IsAssignableTo(typeof(TextWatermark)))
{
var concreateWatermark = (TextWatermark)Convert.ChangeType(watermark, typeof(TextWatermark));
resultedImage = ProcessImage(imageFile, this.OutputDir, concreateWatermark);
}
if (resultedImage != null)
processedImages.Add(resultedImage);
}
return processedImages;
}
/// <summary>
/// Applies an image watermark to a single image.
/// </summary>
/// <param name="imagePath">Path to source image file.</param>
/// <param name="outputDirectory">Output directory for processed image.</param>
/// <param name="watermark">Image watermark configuration.</param>
/// <returns>Processed image information or null on failure.</returns>
/// <exception cref="FileNotFoundException">Thrown when source image or watermark image is missing.</exception>
public WmarkedImage? ProcessImage(string imagePath, string outputDirectory, ImageWatermark watermark)
{
if (!File.Exists(imagePath)) { throw new FileNotFoundException("Source file not found!", imagePath); }
if (!File.Exists(watermark.ImagePath)) { throw new FileNotFoundException("Watermark file not found!", imagePath); }
if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); }
WmarkedImage? resultedImage = null;
using (var targetImage = Image.Load(imagePath))
using (var watermarkImage = Image.Load(watermark.ImagePath))
{
var scaledWmWidth = (int)Math.Round(watermarkImage.Width * watermark.Scale);
var scaledWmHeight = (int)Math.Round(watermarkImage.Height * watermark.Scale);
watermarkImage.Mutate(x => x.Resize(new Size(scaledWmWidth, scaledWmHeight)));
using (var markedImage = targetImage.Clone(ctx => this.ApplyScalingWaterMarkImage(ctx, watermark, watermarkImage, targetImage)))
{
resultedImage = new WmarkedImage(markedImage, outputDirectory + Path.DirectorySeparatorChar + Path.GetFileName(imagePath));
markedImage.Save(resultedImage.Path);
}
}
return resultedImage;
}
/// <summary>
/// Applies a text watermark to a single image.
/// </summary>
/// <param name="imagePath">Path to source image file.</param>
/// <param name="outputDirectory">Output directory for processed image.</param>
/// <param name="watermark">Text watermark configuration.</param>
/// <returns>Processed image information or null on failure.</returns>
/// <exception cref="FileNotFoundException">Thrown when source image is missing.</exception>
public WmarkedImage? ProcessImage(string imagePath, string outputDirectory, TextWatermark watermark)
{
if(!File.Exists(imagePath)) { throw new FileNotFoundException("Source file not found!", imagePath); }
if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); }
WmarkedImage? resultedImage = null;
using (var targetImage = Image.Load(imagePath))
{
using (var markedImage = targetImage.Clone(ctx => this.ApplyScalingWaterMarkText(ctx, watermark)))
{
resultedImage = new WmarkedImage(markedImage, outputDirectory + Path.DirectorySeparatorChar + Path.GetFileName(imagePath));
markedImage.Save(resultedImage.Path);
}
}
return resultedImage;
}
/// <summary>
/// Calculates origin point for text watermark based on position and size.
/// </summary>
/// <param name="width">Target image width.</param>
/// <param name="height">Target image height.</param>
/// <param name="watermarkSize">Watermark text size.</param>
/// <param name="position">Position on target image.</param>
/// <returns>Calculated origin point coordinates.</returns>
private PointF CalcWatermarkOrigin(int width, int height, float watermarkSize, ImagePosition position)
{
var origin = new PointF(0, 0);
//Static value 1 pt is 72 px per inch
var pixelsPerInch = 72;
var wmHeight = watermarkSize / pixelsPerInch;
switch (position)
{
case ImagePosition.TopLeft:
origin = new PointF(watermarkSize / 2, wmHeight / 2);
break;
case ImagePosition.TopCenter:
origin = new PointF(width / 2, wmHeight / 2);
break;
case ImagePosition.TopRight:
origin = new PointF(width - watermarkSize * 2, wmHeight / 2);
break;
case ImagePosition.CenterLeft:
origin = new PointF(watermarkSize / 2, height / 2.5f);
break;
case ImagePosition.Center:
origin = new PointF(width / 2, height / 2.5f);
break;
case ImagePosition.CenterRight:
origin = new PointF(width - watermarkSize * 2, height / 2.5f);
break;
case ImagePosition.BottomLeft:
origin = new PointF(watermarkSize / 2, height - watermarkSize * 2);
break;
case ImagePosition.BottomCenter:
origin = new PointF(width / 2, height - watermarkSize * 2);
break;
case ImagePosition.BottomRight:
origin = new PointF(width - watermarkSize * 2, height - watermarkSize * 2);
break;
default:
break;
}
return origin;
}
/// <summary>
/// Calculates origin point for image watermark based on position and dimensions.
/// </summary>
/// <param name="width">Target image width.</param>
/// <param name="height">Target image height.</param>
/// <param name="wmWidth">Watermark image width.</param>
/// <param name="wmHeight">Watermark image height.</param>
/// <param name="position">Position on target image.</param>
/// <returns>Calculated origin point coordinates.</returns>
private Point CalcWatermarkOrigin(int width, int height, int wmWidth,int wmHeight, ImagePosition position)
{
var origin = new Point(0, 0);
var wmPaddingX = width - wmWidth;
var paddingSide = wmPaddingX / 2;
switch (position)
{
case ImagePosition.TopLeft:
origin = new Point(wmWidth / 2, wmHeight / 2);
break;
case ImagePosition.TopCenter:
origin = new Point((int)paddingSide, wmHeight / 2);
break;
case ImagePosition.TopRight:
origin = new Point(width - wmWidth * 2, wmHeight / 2);
break;
case ImagePosition.CenterLeft:
origin = new Point(wmWidth / 2, height / 2);
break;
case ImagePosition.Center:
origin = new Point((int)paddingSide, (int)(height / 2));
break;
case ImagePosition.CenterRight:
origin = new Point(width - wmWidth * 2, height / 2);
break;
case ImagePosition.BottomLeft:
origin = new Point(wmWidth / 2, height - wmHeight);
break;
case ImagePosition.BottomCenter:
origin = new Point((int)paddingSide, height - wmHeight);
break;
case ImagePosition.BottomRight:
origin = new Point(width - wmWidth * 2, height - wmHeight);
break;
default:
break;
}
return origin;
}
/// <summary>
/// Determines horizontal alignment based on watermark position.
/// </summary>
/// <param name="imagePosition">Watermark position on image.</param>
/// <returns>Corresponding horizontal alignment setting.</returns>
private HorizontalAlignment HorizontalAlignmentFromPosition(ImagePosition imagePosition)
{
switch (imagePosition)
{
case ImagePosition.TopCenter:
return HorizontalAlignment.Center;
break;
case ImagePosition.Center:
return HorizontalAlignment.Center;
break;
case ImagePosition.BottomCenter:
return HorizontalAlignment.Center;
break;
}
return HorizontalAlignment.Left;
}
/// <summary>
/// Applies text watermark to image with automatic scaling and positioning.
/// </summary>
/// <param name="processingContext">Image processing context.</param>
/// <param name="watermark">Text watermark configuration.</param>
/// <returns>Processing context with applied watermark.</returns>
private IImageProcessingContext ApplyScalingWaterMarkText(IImageProcessingContext processingContext, TextWatermark watermark)
{
Size imgSize = processingContext.GetCurrentSize();
FontRectangle size = TextMeasurer.MeasureSize(watermark.Text, new TextOptions(watermark.Font));
// Find out how much we need to scale the text to fill the space (up or down)
float scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height);
// Create a new font
Font scaledFont = new Font(watermark.Font, scalingFactor / 16 * (watermark.Font.Size * watermark.Scale));
ImagePosition[] centerImagePositions = { ImagePosition.CenterLeft, ImagePosition.CenterRight, ImagePosition.Center };
//processingContext.SetGraphicsOptions(new GraphicsOptions { AlphaCompositionMode = SixLabors.ImageSharp.PixelFormats.PixelAlphaCompositionMode.Clear});
//If set, apply backround color
if (watermark.BackroundColor != null)
processingContext.BackgroundColor((Color)watermark.BackroundColor);
var textOptions = new RichTextOptions(scaledFont)
{
ColorFontSupport = ColorFontSupport.MicrosoftColrFormat,
Origin = CalcWatermarkOrigin(imgSize.Width, imgSize.Height, scaledFont.Size, watermark.Position),
HorizontalAlignment = HorizontalAlignmentFromPosition(watermark.Position),
VerticalAlignment = VerticalAlignment.Top,
};
if (watermark.Pave)
{
foreach (ImagePosition position in (ImagePosition[])Enum.GetValues(typeof(ImagePosition)))
{
textOptions.Origin = CalcWatermarkOrigin(imgSize.Width, imgSize.Height, scaledFont.Size, position);
textOptions.HorizontalAlignment = HorizontalAlignmentFromPosition(position);
processingContext.DrawText(textOptions, watermark.Text, watermark.Color);
}
return processingContext;
}
return processingContext
.DrawText(textOptions, watermark.Text, watermark.Color);
}
/// <summary>
/// Applies image watermark to target image with scaling and positioning.
/// </summary>
/// <param name="processingContext">Image processing context.</param>
/// <param name="watermark">Image watermark configuration.</param>
/// <param name="watermarkImage">Watermark image instance.</param>
/// <param name="targetImage">Target image being processed.</param>
/// <returns>Processing context with applied watermark.</returns>
private IImageProcessingContext ApplyScalingWaterMarkImage(IImageProcessingContext processingContext, ImageWatermark watermark, Image watermarkImage, Image targetImage)
{
var scaleFactor = 1f;
if (targetImage.Width > targetImage.Height)
scaleFactor = (float)targetImage.Width / targetImage.Height;
else
scaleFactor = (float) targetImage.Height / targetImage.Width;
var wmPaddingX = (targetImage.Width - watermarkImage.Width) / 2;
var wmPaddingY = (targetImage.Height - watermarkImage.Height) / 2;
//scaleFactor = 1;
var minWmPadding = 50;
var scaledWmWidth = wmPaddingX > minWmPadding && wmPaddingY > minWmPadding
? watermarkImage.Width * scaleFactor
: watermarkImage.Width / scaleFactor;
var scaledWmHeight = wmPaddingX > minWmPadding && wmPaddingY > minWmPadding
? watermarkImage.Height * scaleFactor
: watermarkImage.Height / scaleFactor;
//If set, apply backround color
if (watermark.BackroundColor != null)
processingContext.BackgroundColor((Color)watermark.BackroundColor);
watermarkImage.Mutate(x => x.Resize(new Size((int)scaledWmWidth, (int)scaledWmHeight)));
var wmPositionOrigin = CalcWatermarkOrigin(targetImage.Width, targetImage.Height, watermarkImage.Width, watermarkImage.Height, watermark.Position);
if (watermark.Pave)
{
foreach (ImagePosition position in (ImagePosition[])Enum.GetValues(typeof(ImagePosition)))
{
wmPositionOrigin = CalcWatermarkOrigin(targetImage.Width, targetImage.Height, watermarkImage.Width, watermarkImage.Height, position);
try
{
processingContext.DrawImage(watermarkImage, wmPositionOrigin, watermark.Opacity);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
return processingContext;
}
return processingContext.DrawImage(watermarkImage, wmPositionOrigin, watermark.Opacity);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Watermark.Net.src.WatermarkNet.Enums
{
public enum ImagePosition
{
TopLeft = 0,
TopCenter = 1,
TopRight = 2,
CenterLeft = 3,
Center = 4,
CenterRight = 5,
BottomLeft = 6,
BottomCenter = 7,
BottomRight = 8
}
}
@@ -0,0 +1,75 @@
using System;
using System.IO;
namespace Watermark.Net.src.WatermarkNet.Types
{
/// <summary>
/// Represents a configurable image-based watermark with scaling, positioning, and transparency controls.
/// </summary>
public class ImageWatermark : WatermarkImageBase
{
private string _imagePath;
private float? _opacity;
/// <summary>
/// Gets or sets the absolute path to the watermark image file.
/// Supported formats: PNG, JPEG, BMP, GIF.
/// </summary>
/// <exception cref="FileNotFoundException">
/// Thrown when setting a value that doesn't point to an existing file.
/// </exception>
public string ImagePath
{
get => _imagePath;
set
{
if (!File.Exists(value))
throw new FileNotFoundException("Watermark image not found", value);
_imagePath = value;
}
}
/// <summary>
/// Gets or sets the transparency level of the watermark.
/// Range: 0.0 (fully transparent) to 1.0 (completely opaque).
/// Default: 1.0
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when value is outside the 0.0-1.0 range.
/// </exception>
public float Opacity
{
get => _opacity ?? 1f;
set
{
if (value < 0 || value > 1)
throw new ArgumentOutOfRangeException(nameof(Opacity),
"Opacity must be between 0.0 and 1.0");
_opacity = value;
}
}
/// <summary>
/// Gets or sets the scale factor applied to the watermark image relative to the target image.
/// Default: 0.2 (20% of target image width)
/// </summary>
public float Scale { get; set; } = 0.2f;
/// <summary>
/// Initializes a new instance of the ImageWatermark class with specified image path.
/// </summary>
/// <param name="imagePath">Path to the watermark image file.</param>
public ImageWatermark(string imagePath) : this()
{
ImagePath = imagePath;
}
/// <summary>
/// Initializes a new instance of the ImageWatermark class with default values.
/// </summary>
public ImageWatermark() { }
}
}
@@ -0,0 +1,13 @@
using SixLabors.ImageSharp;
namespace Watermark.Net.src.WatermarkNet.Types
{
internal class SourceImage
{
private string _path;
private Image _image;
public Image Image => _image;
public String Path => _path;
}
}
@@ -0,0 +1,83 @@
using SixLabors.Fonts;
using SixLabors.ImageSharp;
namespace Watermark.Net.src.WatermarkNet.Types
{
/// <summary>
/// Represents a configurable text-based watermark with styling, positioning, and rendering options.
/// </summary>
public class TextWatermark : WatermarkImageBase
{
private string _text;
private Font _font;
private float _padding;
private Color _color;
/// <summary>
/// Gets or sets the color of the text watermark.
/// Default: White (#FFFFFF)
/// </summary>
public Color Color
{
get => _color;
set => _color = value;
}
/// <summary>
/// Gets or sets the text content for the watermark.
/// </summary>
/// <exception cref="ArgumentException">Thrown when value is null or whitespace.</exception>
public string Text
{
get => _text;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Watermark text cannot be empty", nameof(Text));
_text = value;
}
}
/// <summary>
/// Gets or sets the font used to render the text watermark.
/// Default: Arial 12pt
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when value is null.</exception>
public Font Font
{
get => _font;
set => _font = value ?? throw new ArgumentNullException(nameof(Font));
}
/// <summary>
/// Gets or sets the padding space around the text watermark in pixels.
/// Default: 10px
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown when value is negative.</exception>
public float Padding
{
get => _padding;
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(Padding), "Padding cannot be negative");
_padding = value;
}
}
/// <summary>
/// Gets or sets the rotation angle for the text watermark in degrees.
/// Default: 0 (no rotation)
/// </summary>
public float Rotation { get; set; } = 0;
/// <summary>
/// Initializes a new instance of the TextWatermark class with default values.
/// </summary>
public TextWatermark()
{
_color = Color.White;
_font = SystemFonts.CreateFont("Arial", 12);
_padding = 10f;
}
}
}
@@ -0,0 +1,60 @@
using SixLabors.ImageSharp;
using Watermark.Net.src.WatermarkNet.Enums;
namespace Watermark.Net.src.WatermarkNet.Types
{
public class WatermarkImageBase
{
protected ImagePosition _postion;
protected float _scale;
protected int _rotateAngle;
protected bool _pave;
protected Color? _backround;
public ImagePosition Position
{
get { return _postion; }
set
{
_postion= value;
}
}
public float Scale
{
get { return _scale; }
set
{
if(value <= 0) { throw new ArgumentOutOfRangeException("Scale", "Image scale can not be less or equal zero."); }
_scale= value;
}
}
public int RotateAngle
{
get { return _rotateAngle; }
set
{
if (Math.Abs(value) > 180) { throw new ArgumentOutOfRangeException("RotateAngle", "Image rotate angle can not be larger than 180°."); }
_rotateAngle= value;
}
}
public bool Pave
{
get { return _pave; }
set { _pave = value; }
}
public Color? BackroundColor
{
get { return _backround; }
set { _backround = value; }
}
public WatermarkImageBase()
{
_scale= 1.0f;
}
}
}
@@ -0,0 +1,15 @@
using SixLabors.ImageSharp;
namespace Watermark.Net.src.WatermarkNet.Types
{
public class WmarkedImage
{
public string Path { get; }
public Image Image { get; }
public WmarkedImage(Image image, string path)
{
this.Image = image;
this.Path= path;
}
}
}