Skip to content
Merged
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
16 changes: 11 additions & 5 deletions .github/workflows/dotnet-ci-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,27 @@ jobs:
strategy:
fail-fast: false
matrix:
dotnet-version: [ "8.0.x", "9.0.x", "10.0.x" ]
include:
- dotnet-version: "8.0.x"
target-framework: "net8.0"
- dotnet-version: "9.0.x"
target-framework: "net8.0"
- dotnet-version: "10.0.x"
target-framework: "net10.0"
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore ResizingClient
run: dotnet restore source/ResizingClient/ResizingClient.csproj
run: dotnet restore source/ResizingClient/ResizingClient.csproj -p:TargetFramework=${{ matrix.target-framework }}
- name: Build ResizingClient
run: dotnet build source/ResizingClient/ResizingClient.csproj -c Release --no-restore
run: dotnet build source/ResizingClient/ResizingClient.csproj -c Release --no-restore -p:TargetFramework=${{ matrix.target-framework }}
- name: Restore ResizingClient.Tests
run: dotnet restore source/ResizingClient.Tests/ResizingClient.Tests.csproj
run: dotnet restore source/ResizingClient.Tests/ResizingClient.Tests.csproj -p:TargetFramework=net8.0
- name: Test ResizingClient.Tests
run: dotnet test source/ResizingClient.Tests/ResizingClient.Tests.csproj -c Release --no-restore
run: dotnet test source/ResizingClient.Tests/ResizingClient.Tests.csproj -c Release --no-restore -p:TargetFramework=net8.0

build-server:
runs-on: windows-latest
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Install nuget package
Install-Package ResizingClient
```

ResizingClient package supports `net45`, `netstandard2.0`, and `net8.0`.
ResizingClient package supports `net45`, `netstandard2.0`, `net8.0`, and `net10.0`.


upload to server
Expand All @@ -78,7 +78,10 @@ convert format to url
using ResizingClient;
// ...
var url1 = ResizingUtil.Format(url,100,100,ResizingMode.Pad);
var url1 = ResizingUtil.Format(url,100,100);
var url2 = ResizingUtil.Format(url,100,100);
var tencentUrl = ResizingUtil.FormatTencentCdnUrl("https://img.example.com/a.jpg", 100, 100, ResizingMode.Crop);
var aliyunUrl = ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/a.jpg", 100, 100, ResizingMode.Max);
var awsUrl = ResizingUtil.FormatAwsCdnUrl("https://img.example.com/a.jpg", 100, 100, ResizingMode.Pad);

```

Expand Down
87 changes: 87 additions & 0 deletions source/ResizingClient.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,92 @@ public void FormatUrl_UsesExpectedModeToken()
Assert.AreEqual("https://img.example.com/u/face/100x100m.jpg", ResizingUtil.FormatUrl("/u/face/{0}x{1}{2}.jpg", 100, 100, ResizingMode.Max));
Assert.AreEqual("https://img.example.com/u/face/100x100p.jpg", ResizingUtil.FormatUrl("/u/face/{0}x{1}{2}.jpg", 100, 100, ResizingMode.Pad));
}

[TestMethod]
public void Format_IsBackwardCompatibleAlias()
{
ResizingUtil.Host = "https://img.example.com";

Assert.AreEqual("https://img.example.com/u/face/100x100p.jpg", ResizingUtil.Format("/u/face/{0}x{1}{2}.jpg", 100, 100, ResizingMode.Pad));
}

[TestMethod]
public void FormatTencentCdnUrl_UsesExpectedQuery()
{
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?imageMogr2/thumbnail/200x300/gravity/center/crop/200x300",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?imageMogr2/thumbnail/200x300",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Max));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?imageMogr2/thumbnail/200x300/pad/1",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Pad));
}

[TestMethod]
public void FormatAliyunCdnUrl_UsesExpectedQuery()
{
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-oss-process=image/resize,m_fill,w_200,h_300",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-oss-process=image/resize,m_lfit,w_200,h_300",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Max));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-oss-process=image/resize,m_pad,w_200,h_300",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Pad));
}

[TestMethod]
public void FormatAwsCdnUrl_UsesExpectedQuery()
{
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-amz-process=image/resize,w_200,h_300,m_cover",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-amz-process=image/resize,w_200,h_300,m_fit",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Max));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-amz-process=image/resize,w_200,h_300,m_pad",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg", 200, 300, ResizingMode.Pad));
}

[TestMethod]
public void CdnUrls_AppendWithAmpersandWhenQueryExists()
{
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&x-oss-process=image/resize,m_fill,w_200,h_300",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg?v=1", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&imageMogr2/thumbnail/200x300",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg?v=1", 200, 300, ResizingMode.Max));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&x-amz-process=image/resize,w_200,h_300,m_pad",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg?v=1", 200, 300, ResizingMode.Pad));
}

[TestMethod]
public void CdnUrls_InsertQueryBeforeFragment()
{
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-oss-process=image/resize,m_fill,w_200,h_300#preview",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg#preview", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&x-oss-process=image/resize,m_fill,w_200,h_300#preview",
ResizingUtil.FormatAliyunCdnUrl("https://img.example.com/u/face/a.jpg?v=1#preview", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?imageMogr2/thumbnail/200x300/gravity/center/crop/200x300#preview",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg#preview", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&imageMogr2/thumbnail/200x300/gravity/center/crop/200x300#preview",
ResizingUtil.FormatTencentCdnUrl("https://img.example.com/u/face/a.jpg?v=1#preview", 200, 300, ResizingMode.Crop));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?x-amz-process=image/resize,w_200,h_300,m_pad#preview",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg#preview", 200, 300, ResizingMode.Pad));
Assert.AreEqual(
"https://img.example.com/u/face/a.jpg?v=1&x-amz-process=image/resize,w_200,h_300,m_pad#preview",
ResizingUtil.FormatAwsCdnUrl("https://img.example.com/u/face/a.jpg?v=1#preview", 200, 300, ResizingMode.Pad));
}
}
}
2 changes: 1 addition & 1 deletion source/ResizingClient/ResizingClient.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0;net8.0</TargetFrameworks>
<TargetFrameworks>net45;netstandard2.0;net8.0;net10.0</TargetFrameworks>
<RootNamespace>ResizingClient</RootNamespace>
<AssemblyName>ResizingClient</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
Expand Down
74 changes: 68 additions & 6 deletions source/ResizingClient/ResizingUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,71 @@
{
public static string Host { get; set; } = System.Configuration.ConfigurationManager.AppSettings["ResizingServer.Host"];
public static string ApiKey { get; set; } = System.Configuration.ConfigurationManager.AppSettings["ResizingServer.ApiKey"];

public static string UploadUrl { get; set; } = System.Configuration.ConfigurationManager.AppSettings["ResizingServer.UploadUrl"];

public static string FormatUrl(string format, int width, int height, ResizingMode mode = ResizingMode.Crop)
{
return
$"{Host}{string.Format(format, width, height, GetMode(mode))}";
return $"{Host}{string.Format(format, width, height, GetMode(mode))}";
}

public static string Format(string format, int width, int height, ResizingMode mode = ResizingMode.Crop)
{
return FormatUrl(format, width, height, mode);
}

public static string FormatTencentCdnUrl(string url, int width, int height, ResizingMode mode = ResizingMode.Crop)
{
var query = $"imageMogr2/thumbnail/{width}x{height}";
switch (mode)
{
case ResizingMode.Crop:
query = $"{query}/gravity/center/crop/{width}x{height}";
break;
case ResizingMode.Pad:
query = $"{query}/pad/1";
break;
}
return AppendQuery(url, query);
}

public static string FormatAliyunCdnUrl(string url, int width, int height, ResizingMode mode = ResizingMode.Crop)
{
var modeToken = "m_fill";
switch (mode)
{
case ResizingMode.Max:
modeToken = "m_lfit";
break;
case ResizingMode.Pad:
modeToken = "m_pad";
break;
}

return AppendQuery(url, $"x-oss-process=image/resize,{modeToken},w_{width},h_{height}");
}

public static string FormatAwsCdnUrl(string url, int width, int height, ResizingMode mode = ResizingMode.Crop)
{
var fitToken = "m_cover";
switch (mode)
{
case ResizingMode.Max:
fitToken = "m_fit";
break;
case ResizingMode.Pad:
fitToken = "m_pad";
break;
}

return AppendQuery(url, $"x-amz-process=image/resize,w_{width},h_{height},{fitToken}");
}

public static Task<UploadResult> Upload(Stream stream, string filename, string category)
{
stream.Seek(0, SeekOrigin.Begin);
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int) stream.Length);
stream.Read(bytes, 0, (int)stream.Length);

Check warning on line 78 in source/ResizingClient/ResizingUtil.cs

View workflow job for this annotation

GitHub Actions / build (10.0.x, net10.0)

Avoid inexact read with 'System.IO.Stream.Read(byte[], int, int)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2022)

Check warning on line 78 in source/ResizingClient/ResizingUtil.cs

View workflow job for this annotation

GitHub Actions / build (10.0.x, net10.0)

Avoid inexact read with 'System.IO.Stream.Read(byte[], int, int)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2022)
return Upload(bytes, filename, category);
}

Expand All @@ -33,7 +84,7 @@
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(bytes)), "file", filename);

Expand All @@ -47,6 +98,17 @@
}
}
}

static string AppendQuery(string url, string query)
{
if (string.IsNullOrWhiteSpace(url)) return url;
var fragmentIndex = url.IndexOf('#');
var fragment = fragmentIndex >= 0 ? url.Substring(fragmentIndex) : string.Empty;
var urlWithoutFragment = fragmentIndex >= 0 ? url.Substring(0, fragmentIndex) : url;
var separator = urlWithoutFragment.IndexOf('?', StringComparison.Ordinal) >= 0 ? "&" : "?";

Check failure on line 108 in source/ResizingClient/ResizingUtil.cs

View workflow job for this annotation

GitHub Actions / build-server

Argument 2: cannot convert from 'System.StringComparison' to 'int'
return $"{urlWithoutFragment}{separator}{query}{fragment}";
}

static string GetMode(ResizingMode mode)
{
switch (mode)
Expand All @@ -61,4 +123,4 @@
return "c";
}
}
}
}
7 changes: 7 additions & 0 deletions source/ResizingServer/ResizingServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,15 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.NETFramework.ReferenceAssemblies.net45.1.0.3\build\Microsoft.NETFramework.ReferenceAssemblies.net45.targets" Condition="Exists('..\packages\Microsoft.NETFramework.ReferenceAssemblies.net45.1.0.3\build\Microsoft.NETFramework.ReferenceAssemblies.net45.targets')" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.NETFramework.ReferenceAssemblies.net45.1.0.3\build\Microsoft.NETFramework.ReferenceAssemblies.net45.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NETFramework.ReferenceAssemblies.net45.1.0.3\build\Microsoft.NETFramework.ReferenceAssemblies.net45.targets'))" />
</Target>
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
Expand Down
1 change: 1 addition & 0 deletions source/ResizingServer/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Owin.zh-Hans" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.NETFramework.ReferenceAssemblies.net45" version="1.0.3" targetFramework="net45" developmentDependency="true" />
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net452" />
<package id="Microsoft.Owin" version="3.1.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net452" />
Expand Down
Loading