feat:完善模块化+缩略图模块
@@ -83,7 +83,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Application", "src\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Web", "src\project\rbac\Yi.RBAC.Web\Yi.RBAC.Web.csproj", "{0C031C7D-6F80-4559-977C-AC001036EC44}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ThumbnailSharp", "src\module\Yi.Framework.ThumbnailSharp\Yi.Framework.ThumbnailSharp.csproj", "{60E54034-792C-4A90-BCDF-4D5FFB45089E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ImageSharp", "src\module\Yi.Framework.ImageSharp\Yi.Framework.ImageSharp.csproj", "{60E54034-792C-4A90-BCDF-4D5FFB45089E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.EventBus", "src\module\Yi.Framework.EventBus\Yi.Framework.EventBus.csproj", "{FC559052-36EC-4379-B447-298FAD6045F4}"
|
||||
EndProject
|
||||
@@ -103,7 +103,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.MultiTenancy",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.DictionaryManager", "src\module\Yi.Framework.DictionaryManager\Yi.Framework.DictionaryManager.csproj", "{8941B30D-698B-477A-8737-43E7B4A8695A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Sms.Aliyun", "src\module\Yi.Framework.Sms.Aliyun\Yi.Framework.Sms.Aliyun.csproj", "{063178CF-C5B9-463C-A8A4-F32B743818E2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Sms.Aliyun", "src\module\Yi.Framework.Sms.Aliyun\Yi.Framework.Sms.Aliyun.csproj", "{063178CF-C5B9-463C-A8A4-F32B743818E2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace Yi.Framework.Core.Extensions
|
||||
public static WebApplicationBuilder UseYiModules(this WebApplicationBuilder builder, Type startType)
|
||||
{
|
||||
var moduleManager = new ModuleManager(startType);
|
||||
moduleManager.Invoker();
|
||||
|
||||
Assembly[] assemblies2 = moduleManager.ToAssemblyArray();
|
||||
|
||||
Assembly[] assemblies2 = moduleManager.ToAssemblyArray(moduleManager.Invoker());
|
||||
return builder.UseStartupModules(delegate (StartupModulesOptions options)
|
||||
{
|
||||
options.DiscoverStartupModules(assemblies2);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Yi.Framework.Core.Helper
|
||||
|
||||
public static List<string> ImageType { get; set; } = new List<string>
|
||||
{
|
||||
".jpg",".png",".jpge",".gif"
|
||||
".jpg",".png",".jpge"
|
||||
};
|
||||
|
||||
private static Hashtable _mimeMappingTable;
|
||||
|
||||
@@ -12,17 +12,30 @@ namespace Yi.Framework.Core.Module
|
||||
|
||||
internal class ModuleManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 全部程序集
|
||||
/// </summary>
|
||||
private List<Type> ResultType = new List<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 开始程序集
|
||||
/// </summary>
|
||||
private Type StartType;
|
||||
public ModuleManager(Type startType)
|
||||
{
|
||||
StartType = startType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<Type> Invoker()
|
||||
{
|
||||
StartBFSNodes(StartType);
|
||||
var result= RemoveDuplicate(ResultType);
|
||||
ResultType= ResultType.Distinct().ToList();
|
||||
var result = StartTopologicalSortNodes().Reverse().ToList();
|
||||
|
||||
Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(ModuleManager).Assembly).GetCurrentClassLogger();
|
||||
foreach (var r in result)
|
||||
{
|
||||
@@ -33,17 +46,37 @@ namespace Yi.Framework.Core.Module
|
||||
return result;
|
||||
}
|
||||
|
||||
private Type[]? GetDependsOnType(Type type)
|
||||
{
|
||||
var dependsOnbuild = type.GetCustomAttributes(typeof(DependsOnAttribute), false).FirstOrDefault() as DependsOnAttribute;
|
||||
if (dependsOnbuild is null)
|
||||
{
|
||||
return new Type[0];
|
||||
}
|
||||
return dependsOnbuild.GetDependedTypes();
|
||||
|
||||
private Type[] StartTopologicalSortNodes()
|
||||
{
|
||||
List<TopologicalSortNode<Type>> topologicalSortNodes = new List<TopologicalSortNode<Type>>();
|
||||
|
||||
|
||||
//添加注册到节点
|
||||
foreach (var res in ResultType)
|
||||
{
|
||||
var typeNode = new TopologicalSortNode<Type>(res);
|
||||
topologicalSortNodes.Add(typeNode);
|
||||
}
|
||||
|
||||
Dictionary<Type, TopologicalSortNode<Type>> nodeDic = topologicalSortNodes.ToDictionary(x => x.Data);
|
||||
|
||||
|
||||
//各个节点互相添加依赖
|
||||
foreach (var node in topologicalSortNodes)
|
||||
{
|
||||
GetDependsOnType(node.Data)?.ToList().ForEach(x => node.AddDependent(nodeDic[x]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return TopologicalSortNode<Type>.TopologicalSort(topologicalSortNodes).Select(x => x.Data).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BFS获取全部程序集
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
private void StartBFSNodes(Type node)
|
||||
{
|
||||
ResultType.Add(node);
|
||||
@@ -57,29 +90,30 @@ namespace Yi.Framework.Core.Module
|
||||
}
|
||||
}
|
||||
|
||||
private List<Type> RemoveDuplicate(List<Type> array)
|
||||
|
||||
/// <summary>
|
||||
/// 获取模块 需依赖的模块
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private Type[]? GetDependsOnType(Type type)
|
||||
{
|
||||
HashSet<Type> s = new HashSet<Type>();
|
||||
List<Type> list = new List<Type>();
|
||||
for (int i = array.Count - 1; i >= 0; i--)
|
||||
var dependsOnbuild = type.GetCustomAttributes(typeof(DependsOnAttribute), false).FirstOrDefault() as DependsOnAttribute;
|
||||
if (dependsOnbuild is null)
|
||||
{
|
||||
if (!s.Contains(array[i]))
|
||||
{
|
||||
s.Add(array[i]);
|
||||
list.Add(array[i]);
|
||||
}
|
||||
return new Type[0];
|
||||
}
|
||||
ResultType = list;
|
||||
return list;
|
||||
return dependsOnbuild.GetDependedTypes();
|
||||
}
|
||||
|
||||
|
||||
public List<Assembly> ToAssemblyList()
|
||||
{
|
||||
return ResultType.Select(a => a.Assembly).ToList();
|
||||
}
|
||||
public Assembly[] ToAssemblyArray()
|
||||
public Assembly[] ToAssemblyArray(List<Type> types)
|
||||
{
|
||||
return ResultType.Select(a => a.Assembly).ToArray();
|
||||
return types.Select(a => a.Assembly).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yi.Framework.Core.Module
|
||||
{
|
||||
public class TopologicalSortNode<T>
|
||||
{
|
||||
public T Data { get; private set; }
|
||||
public List<TopologicalSortNode<T>> Dependents { get; private set; }
|
||||
public int IncomingEdges { get; private set; }
|
||||
public TopologicalSortNode(T data)
|
||||
{
|
||||
Data = data;
|
||||
Dependents = new List<TopologicalSortNode<T>>();
|
||||
IncomingEdges = 0;
|
||||
}
|
||||
public void AddDependent(TopologicalSortNode<T> dependent)
|
||||
{
|
||||
Dependents.Add(dependent);
|
||||
dependent.IncomingEdges++;
|
||||
}
|
||||
|
||||
|
||||
public static List<TopologicalSortNode<T>> TopologicalSort(List<TopologicalSortNode<T>> graph)
|
||||
{
|
||||
List<TopologicalSortNode<T>> result = new List<TopologicalSortNode<T>>();
|
||||
Queue<TopologicalSortNode<T>> queue = new Queue<TopologicalSortNode<T>>();
|
||||
// 将所有入度为 0 的节点加入队列
|
||||
foreach (TopologicalSortNode<T> node in graph)
|
||||
{
|
||||
if (node.IncomingEdges == 0)
|
||||
{
|
||||
queue.Enqueue(node);
|
||||
}
|
||||
}
|
||||
// 依次将入度为 0 的节点出队,并将它的依赖节点的入度减 1
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
TopologicalSortNode<T> node = queue.Dequeue();
|
||||
result.Add(node);
|
||||
foreach (TopologicalSortNode<T> dependent in node.Dependents)
|
||||
{
|
||||
dependent.IncomingEdges--;
|
||||
if (dependent.IncomingEdges == 0)
|
||||
{
|
||||
queue.Enqueue(dependent);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果存在入度不为 0 的节点,则说明图中存在环
|
||||
foreach (TopologicalSortNode<T> node in graph)
|
||||
{
|
||||
if (node.IncomingEdges != 0)
|
||||
{
|
||||
throw new ArgumentException("模块之间存在互相依赖!");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ using Yi.Framework.Core.Helper;
|
||||
using Yi.Framework.Ddd.Repositories;
|
||||
using Yi.Framework.Ddd.Services;
|
||||
using Yi.Framework.Ddd.Services.Abstract;
|
||||
using Yi.Framework.ThumbnailSharp;
|
||||
using Yi.Framework.ImageSharp;
|
||||
|
||||
namespace Yi.Framework.FileManager
|
||||
{
|
||||
@@ -27,13 +27,13 @@ namespace Yi.Framework.FileManager
|
||||
public class FileService : ApplicationService, IFileService, IAutoApiService
|
||||
{
|
||||
private readonly IRepository<FileEntity> _repository;
|
||||
private readonly ThumbnailSharpManager _thumbnailSharpManager;
|
||||
private readonly ImageSharpManager _imageSharpManager;
|
||||
private readonly HttpContext _httpContext;
|
||||
public FileService(IRepository<FileEntity> repository, ThumbnailSharpManager thumbnailSharpManager, IHttpContextAccessor httpContextAccessor
|
||||
public FileService(IRepository<FileEntity> repository, ImageSharpManager imageSharpManager, IHttpContextAccessor httpContextAccessor
|
||||
)
|
||||
{
|
||||
_repository = repository;
|
||||
_thumbnailSharpManager = thumbnailSharpManager;
|
||||
_imageSharpManager = imageSharpManager;
|
||||
if (httpContextAccessor.HttpContext is null)
|
||||
{
|
||||
throw new ApplicationException("HttpContext为空");
|
||||
@@ -125,21 +125,16 @@ namespace Yi.Framework.FileManager
|
||||
{
|
||||
Directory.CreateDirectory(thumbnailPath);
|
||||
}
|
||||
//保存至缩略图路径
|
||||
byte[] result = null!;
|
||||
string thumbnailFilePath = Path.Combine(thumbnailPath, filename);
|
||||
try
|
||||
{
|
||||
result = _thumbnailSharpManager.CreateThumbnailBytes(thumbnailSize: 300, imageStream: stream, imageFormat: Format.Jpeg);
|
||||
if(result is null) throw new ArgumentNullException(nameof(result));
|
||||
_imageSharpManager.ImageCompress(f.FileName, f.OpenReadStream(), thumbnailFilePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = new byte[stream.Length];
|
||||
stream.Read(result, 0, result.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await System.IO.File.WriteAllBytesAsync(Path.Combine(thumbnailPath, filename), result);
|
||||
var result = new byte[stream.Length];
|
||||
await stream.ReadAsync(result, 0, result.Length);
|
||||
await File.WriteAllBytesAsync(thumbnailFilePath, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<ProjectReference Include="..\..\framework\Yi.Framework.Core\Yi.Framework.Core.csproj" />
|
||||
<ProjectReference Include="..\..\framework\Yi.Framework.Data\Yi.Framework.Data.csproj" />
|
||||
<ProjectReference Include="..\..\framework\Yi.Framework.Ddd\Yi.Framework.Ddd.csproj" />
|
||||
<ProjectReference Include="..\Yi.Framework.ThumbnailSharp\Yi.Framework.ThumbnailSharp.csproj" />
|
||||
<ProjectReference Include="..\Yi.Framework.ImageSharp\Yi.Framework.ImageSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,11 +4,13 @@ using StartupModules;
|
||||
using Yi.Framework.Core.Attributes;
|
||||
using Yi.Framework.Core;
|
||||
using Yi.Framework.Ddd;
|
||||
using Yi.Framework.ImageSharp;
|
||||
|
||||
namespace Yi.Framework.FileManager
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(YiFrameworkDddModule)
|
||||
typeof(YiFrameworkDddModule),
|
||||
typeof(YiFrameworkImageSharpModule)
|
||||
)]
|
||||
public class YiFrameworkFileManagerModule : IStartupModule
|
||||
{
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace Yi.Framework.ImageSharp;
|
||||
public class ImageSharpManager
|
||||
{
|
||||
public void ImageCompress(string fileName, Stream stream, string savePath)
|
||||
{
|
||||
var extensionName = Path.GetExtension(fileName).ToLower();
|
||||
if (extensionName == ".png")
|
||||
{
|
||||
PngImageCompress(stream, savePath);
|
||||
}
|
||||
else if (extensionName == ".jpg" || extensionName == ".jpeg")
|
||||
{
|
||||
JpgImageCompress(stream, savePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
stream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void PngImageCompress(Stream stream, string savePath)
|
||||
{
|
||||
using (var image = Image.Load(stream))
|
||||
{
|
||||
var encoder = new PngEncoder()
|
||||
{
|
||||
CompressionLevel = PngCompressionLevel.Level6,
|
||||
|
||||
};
|
||||
if (image.Width > 300)
|
||||
{
|
||||
image.Mutate(a => a.Resize(image.Width/2, image.Height/2));
|
||||
}
|
||||
|
||||
image.Save(savePath, encoder);
|
||||
}
|
||||
}
|
||||
public void JpgImageCompress(Stream stream, string savePath)
|
||||
{
|
||||
using (var image = Image.Load(stream))
|
||||
{
|
||||
var encoder = new JpegEncoder()
|
||||
{
|
||||
Quality = 30
|
||||
};
|
||||
if (image.Width > 300)
|
||||
{
|
||||
image.Mutate(a => a.Resize(image.Width / 2, image.Height / 2));
|
||||
}
|
||||
|
||||
|
||||
image.Save(savePath, encoder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -7,9 +7,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yi.Framework.ThumbnailSharp
|
||||
namespace Yi.Framework.ImageSharp
|
||||
{
|
||||
public class YiFrameworkThumbnailSharpModule : IStartupModule
|
||||
public class YiFrameworkImageSharpModule : IStartupModule
|
||||
{
|
||||
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
|
||||
{
|
||||
@@ -17,7 +17,7 @@ namespace Yi.Framework.ThumbnailSharp
|
||||
|
||||
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
|
||||
{
|
||||
services.AddSingleton<ThumbnailSharpManager>();
|
||||
services.AddSingleton<ImageSharpManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
/*MIT License
|
||||
|
||||
Copyright(c) 2017 Mirza Ghulam Rasyid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yi.Framework.ThumbnailSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Image format to use when creating a thumbnail.
|
||||
/// </summary>
|
||||
public enum Format
|
||||
{
|
||||
Jpeg,
|
||||
Bmp,
|
||||
Png,
|
||||
Gif,
|
||||
Tiff
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Thumbnail class that holds various methods to create an image thumbnail.
|
||||
/// </summary>
|
||||
public class ThumbnailSharpManager
|
||||
{
|
||||
private Bitmap CreateBitmapThumbnail(uint thumbnailSize, string imageFileLocation)
|
||||
{
|
||||
Bitmap bitmap = null;
|
||||
Image image = null;
|
||||
float actualHeight = default(float);
|
||||
float actualWidth = default(float);
|
||||
uint thumbnailHeight = default(uint);
|
||||
uint thumbnailWidth = default(uint);
|
||||
try
|
||||
{
|
||||
image = Image.FromFile(imageFileLocation);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (image != null)
|
||||
image = null;
|
||||
}
|
||||
if (image != null)
|
||||
{
|
||||
actualHeight = image.Height;
|
||||
actualWidth = image.Width;
|
||||
if (actualHeight > actualWidth)
|
||||
{
|
||||
if ((uint)actualHeight <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than actual height (portrait image)");
|
||||
thumbnailHeight = thumbnailSize;
|
||||
thumbnailWidth = (uint)((actualWidth / actualHeight) * thumbnailSize);
|
||||
}
|
||||
else if (actualWidth > actualHeight)
|
||||
{
|
||||
|
||||
if ((uint)actualWidth <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than actual width (landscape image)");
|
||||
thumbnailWidth = thumbnailSize;
|
||||
thumbnailHeight = (uint)((actualHeight / actualWidth) * thumbnailSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uint)actualWidth <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than image's size");
|
||||
thumbnailWidth = thumbnailSize;
|
||||
thumbnailHeight = thumbnailSize;
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
bitmap = new Bitmap((int)thumbnailWidth, (int)thumbnailHeight);
|
||||
Graphics resizedImage = Graphics.FromImage(bitmap);
|
||||
resizedImage.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
resizedImage.CompositingQuality = CompositingQuality.HighQuality;
|
||||
resizedImage.SmoothingMode = SmoothingMode.HighQuality;
|
||||
resizedImage.DrawImage(image, 0, 0, thumbnailWidth, thumbnailHeight);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (bitmap != null)
|
||||
bitmap = null;
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
private Bitmap CreateBitmapThumbnail(uint thumbnailSize, Stream imageStream)
|
||||
{
|
||||
Bitmap bitmap = null;
|
||||
Image image = null;
|
||||
float actualHeight = default(float);
|
||||
float actualWidth = default(float);
|
||||
uint thumbnailHeight = default(uint);
|
||||
uint thumbnailWidth = default(uint);
|
||||
try
|
||||
{
|
||||
image = Image.FromStream(imageStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (image != null)
|
||||
image = null;
|
||||
}
|
||||
if (image != null)
|
||||
{
|
||||
actualHeight = image.Height;
|
||||
actualWidth = image.Width;
|
||||
if (actualHeight > actualWidth)
|
||||
{
|
||||
if ((uint)actualHeight <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than actual height (portrait image)");
|
||||
thumbnailHeight = thumbnailSize;
|
||||
thumbnailWidth = (uint)((actualWidth / actualHeight) * thumbnailSize);
|
||||
}
|
||||
else if (actualWidth > actualHeight)
|
||||
{
|
||||
|
||||
if ((uint)actualWidth <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than actual width (landscape image)");
|
||||
thumbnailWidth = thumbnailSize;
|
||||
thumbnailHeight = (uint)((actualHeight / actualWidth) * thumbnailSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uint)actualWidth <= thumbnailSize)
|
||||
throw new Exception("Thumbnail size must be less than image's size");
|
||||
thumbnailWidth = thumbnailSize;
|
||||
thumbnailHeight = thumbnailSize;
|
||||
}
|
||||
try
|
||||
{
|
||||
bitmap = new Bitmap((int)thumbnailWidth, (int)thumbnailHeight);
|
||||
Graphics resizedImage = Graphics.FromImage(bitmap);
|
||||
resizedImage.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
resizedImage.CompositingQuality = CompositingQuality.HighQuality;
|
||||
resizedImage.SmoothingMode = SmoothingMode.HighQuality;
|
||||
resizedImage.DrawImage(image, 0, 0, thumbnailWidth, thumbnailHeight);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (bitmap != null)
|
||||
bitmap = null;
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
private ImageFormat GetImageFormat(Format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case Format.Jpeg:
|
||||
return ImageFormat.Jpeg;
|
||||
case Format.Bmp:
|
||||
return ImageFormat.Bmp;
|
||||
case Format.Png:
|
||||
return ImageFormat.Png;
|
||||
case Format.Gif:
|
||||
return ImageFormat.Gif;
|
||||
default:
|
||||
return ImageFormat.Tiff;
|
||||
}
|
||||
}
|
||||
private async Task<Stream> GetImageStreamFromUrl(Uri urlAddress)
|
||||
{
|
||||
Stream result = null;
|
||||
try
|
||||
{
|
||||
byte[] bytes = await GetImageBytesFromUrl(urlAddress);
|
||||
result = new MemoryStream(bytes);
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private async Task<byte[]> GetImageBytesFromUrl(Uri urlAddress)
|
||||
{
|
||||
byte[] buffer = null;
|
||||
try
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
buffer = await client.GetByteArrayAsync(urlAddress);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
buffer = null;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a thumbnail from file and returns as stream.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageFileLocation">Correct image file location.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as stream. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageFileLocation' is null.</exception>
|
||||
/// <exception cref="FileNotFoundException">'imageFileLocation' does not exist.</exception>
|
||||
public Stream CreateThumbnailStream(uint thumbnailSize, string imageFileLocation, Format imageFormat)
|
||||
{
|
||||
if (String.IsNullOrEmpty(imageFileLocation))
|
||||
throw new ArgumentNullException(nameof(imageFileLocation), "'imageFileLocation' cannot be null");
|
||||
if (!File.Exists(imageFileLocation))
|
||||
throw new FileNotFoundException($"'{imageFileLocation}' cannot be found");
|
||||
Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, imageFileLocation);
|
||||
if (bitmap != null)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
bitmap.Save(stream, GetImageFormat(imageFormat));
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a thumbnail from image stream and returns as stream.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageStream">Valid image stream object.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as stream. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageStream' is null.</exception>
|
||||
public Stream CreateThumbnailStream(uint thumbnailSize, Stream imageStream, Format imageFormat)
|
||||
{
|
||||
if (imageStream == null)
|
||||
throw new ArgumentNullException(nameof(imageStream), "'imageStream' cannot be null");
|
||||
Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, imageStream);
|
||||
if (bitmap != null)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
bitmap.Save(stream, GetImageFormat(imageFormat));
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a thumbnail from image in bytes and returns as stream.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageBytes">Valid image bytes array.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as stream. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageBytes' is null.</exception>
|
||||
public Stream CreateThumbnailStream(uint thumbnailSize, byte[] imageBytes, Format imageFormat)
|
||||
{
|
||||
if (imageBytes == null)
|
||||
throw new ArgumentNullException(nameof(imageBytes), "'imageStream' cannot be null");
|
||||
Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, new MemoryStream(imageBytes));
|
||||
if (bitmap != null)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
bitmap.Save(stream, GetImageFormat(imageFormat));
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a thumbnail from file and returns as bytes.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageFileLocation">Correct image file location.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as bytes. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageFileLocation' is null.</exception>
|
||||
/// <exception cref="FileNotFoundException">'imageFileLocation' does not exist.</exception>
|
||||
public byte[] CreateThumbnailBytes(uint thumbnailSize, string imageFileLocation, Format imageFormat)
|
||||
{
|
||||
if (String.IsNullOrEmpty(imageFileLocation))
|
||||
throw new ArgumentNullException(nameof(imageFileLocation), "'imageFileLocation' cannot be null");
|
||||
if (!File.Exists(imageFileLocation))
|
||||
throw new FileNotFoundException($"'{imageFileLocation}' cannot be found");
|
||||
Stream stream = CreateThumbnailStream(thumbnailSize, imageFileLocation, imageFormat);
|
||||
if (stream != null)
|
||||
{
|
||||
byte[] streamBytes = new byte[stream.Length];
|
||||
stream.Read(streamBytes, 0, streamBytes.Length);
|
||||
return streamBytes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a thumbnail from image stream and returns as bytes.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageStream">Valid image stream object.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as bytes. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageStream' is null.</exception>
|
||||
public byte[] CreateThumbnailBytes(uint thumbnailSize, Stream imageStream, Format imageFormat)
|
||||
{
|
||||
if (imageStream == null)
|
||||
throw new ArgumentNullException(nameof(imageStream), "'imageStream' cannot be null");
|
||||
|
||||
Stream stream = CreateThumbnailStream(thumbnailSize, imageStream, imageFormat);
|
||||
if (stream != null)
|
||||
{
|
||||
byte[] streamBytes = new byte[stream.Length];
|
||||
stream.Read(streamBytes, 0, streamBytes.Length);
|
||||
return streamBytes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a thumbnail from image in bytes and returns as bytes.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="imageBytes">Valid image bytes array.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as bytes. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'imageBytes' is null.</exception>
|
||||
public byte[] CreateThumbnailBytes(uint thumbnailSize, byte[] imageBytes, Format imageFormat)
|
||||
{
|
||||
if (imageBytes == null)
|
||||
throw new ArgumentNullException(nameof(imageBytes), "'imageStream' cannot be null");
|
||||
Stream stream = CreateThumbnailStream(thumbnailSize, imageBytes, imageFormat);
|
||||
if (stream != null)
|
||||
{
|
||||
byte[] streamBytes = new byte[stream.Length];
|
||||
stream.Read(streamBytes, 0, streamBytes.Length);
|
||||
return streamBytes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a thumbnail from valid image url asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="urlAddress">Valid absolute url address with proper scheme.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as stream. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'urlAddress' is null.</exception>
|
||||
public async Task<Stream> CreateThumbnailStreamAsync(uint thumbnailSize, Uri urlAddress, Format imageFormat)
|
||||
{
|
||||
if (urlAddress == null)
|
||||
throw new ArgumentNullException(nameof(urlAddress), "'urlAddress' cannot be null");
|
||||
Stream result = null;
|
||||
Stream stream = await GetImageStreamFromUrl(urlAddress);
|
||||
if (stream != null)
|
||||
{
|
||||
result = CreateThumbnailStream(thumbnailSize, stream, imageFormat);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a thumbnail from valid image url asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="thumbnailSize">Thumbnail size. For portrait image, thumbnail size must be less than its height.
|
||||
/// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height.</param>
|
||||
/// <param name="urlAddress">Valid absolute url address with proper scheme.</param>
|
||||
/// <param name="imageFormat">Image format to use.</param>
|
||||
/// <returns>A thumbnail image as bytes. Returns null if it fails.</returns>
|
||||
/// <exception cref="ArgumentNullException">'urlAddress' is null.</exception>
|
||||
public async Task<byte[]> CreateThumbnailBytesAsync(uint thumbnailSize, Uri urlAddress, Format imageFormat)
|
||||
{
|
||||
if (urlAddress == null)
|
||||
throw new ArgumentNullException(nameof(urlAddress), "'urlAddress' cannot be null");
|
||||
byte[] result = null;
|
||||
byte[] imageBytes = await GetImageBytesFromUrl(urlAddress);
|
||||
if (imageBytes != null)
|
||||
{
|
||||
result = CreateThumbnailBytes(thumbnailSize, imageBytes, imageFormat);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 451 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |