项目升级.Net7.0+以后,System.Drawing.Common开关已经被删除,且System.Drawing.Common仅在 Windows 上支持 ,于是想办法将原来上传图片验证文件名和获取图片扩展名方法替换一下,便开始搜索相关解决方案。
.Net6.0文档:中断性变更:仅在 Windows 上支持 System.Drawing.Common - .NET | Microsoft Learn
.Net7.0文档:中断性变更:删除了 System.Drawing.Common 配置开关 - .NET | Microsoft Learn
旧行为
在 .NET 6 之前,使用 System.Drawing.Common 包不会产生任何编译时警告,也不会引发任何运行时异常。
新行为
从 .NET 6 开始,当为非 Windows 操作系统编译引用代码时,平台分析器会发出编译时警告。 此外,除非设置了配置选项,否则将引发以下运行时异常:
System.TypeInitializationException : The type initializer for 'Gdip' threw an exception.
---- System.PlatformNotSupportedException : System.Drawing.Common is not supported on non-Windows platforms. See https://aka.ms/systemdrawingnonwindows for more information.
Stack Trace:
at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromFile(String filename, IntPtr& bitmap)
/_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(42,0): at System.Drawing.Bitmap..ctor(String filename, Boolean useIcm)
/_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(25,0): at System.Drawing.Bitmap..ctor(String filename)
/_/src/libraries/System.Resources.ResourceManager/tests/ResourceManagerTests.cs(270,0): at System.Resources.Tests.ResourceManagerTests.EnglishImageResourceData()+MoveNext()
/_/src/libraries/System.Linq/src/System/Linq/Select.cs(136,0): at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
----- Inner Stack Trace -----
/_/src/libraries/System.Drawing.Common/src/System/Drawing/LibraryResolver.cs(31,0): at System.Drawing.LibraryResolver.EnsureRegistered()
/_/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs(65,0): at System.Drawing.SafeNativeMethods.Gdip.PlatformInitialize()
/_/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs(27,0): at System.Drawing.SafeNativeMethods.Gdip..cctor()
可通过将 runtimeconfig.json 文件中的 System.Drawing.EnableUnixSupport
运行时配置开关设置为 true
来启用对 .NET 6 中非 Windows 平台的支持。
runtimeconfig.template.json 模板文件:
{
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
[appname].runtimeconfig.json 输出文件:
{
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
}
上面描述.Net6.0之前还是可以使用System.Drawing.Common,.Net6.0需要设置开关,而.Net7.0中直接将开关删除,由于项目中上传文件验证文件格式等操作,于是便搜索相关替代方案。
在github中发现一个开源项目:https://github.com/iron-software/IronSoftware.System.Drawing
将项目中代码替换为IronSoftware.System.Drawing类库,本文使用的版本为:
保存图片:
/// <summary>
/// 字节数组转换成图片
/// hef 2023.03.10 13:53 将原System.Drawing替换为IronSoftware.Drawing
/// </summary>
/// <param name="buffer"></param>
/// <param name="sImgSavePath"></param>
/// <returns></returns>
static public string ByteToImg(byte[] buffer, string sImgSavePath)
{
AnyBitmap img = AnyBitmap.FromBytes(buffer);
img.SaveAs(sImgSavePath);
return sImgSavePath;
}
获取图片扩展名:
/// <summary>
/// 获取图片后缀
/// hef 2023.03.10 13:54 将原System.Drawing替换为IronSoftware.Drawing
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
static public string GetImageExt(AnyBitmap image)
{
string imageExt = "";
var RawFormat = image.GetImageFormat();
if (RawFormat == AnyBitmap.ImageFormat.Png)
{
imageExt = ".png";
}
if (RawFormat == AnyBitmap.ImageFormat.Jpeg)
{
imageExt = ".jpg";
}
if (RawFormat == AnyBitmap.ImageFormat.Bmp)
{
imageExt = ".bmp";
}
if (RawFormat == AnyBitmap.ImageFormat.Gif)
{
imageExt = ".gif";
}
if (RawFormat == AnyBitmap.ImageFormat.Icon)
{
imageExt = ".icon";
}
if (RawFormat == AnyBitmap.ImageFormat.Wbmp)
{
imageExt = ".bmp";
}
if (RawFormat == AnyBitmap.ImageFormat.Webp)
{
imageExt = ".png";
}
return imageExt;
}
你可以直接获取扩展名:
string sExtName = Enum.GetName(typeof(AnyBitmap.ImageFormat), AnyBitmap.ImageFormat.Gif);
使用上面一行代码得到的值为gif,并不包含.[点]。
使用封装的方法如下,列举两种常用方法,你也可以使用其它方法:
1.通过字节数组转换为AnyBitmap
var vAnyBitmap = FileHelper.ByteToImg(bytes);
2.通过Stream转换为AnyBitmap
var vAnyBitmap = IronSoftware.Drawing.AnyBitmap.FromStream(fileStream);
string sImgExt = FileHelper.GetImageExt(vAnyBitmap);
其它示例:
Bitmap to Stream:
using IronSoftware.Drawing;
using System.IO;
AnyBitmap bitmap = AnyBitmap.FromFile(@"FILE_PATH");
// Get stream of AnyBitmap
MemoryStream stream = bitmap.GetStream();
// Convert AnyBitmap to stream
MemoryStream stream1 = bitmap.ToStream();
Bitmap to String:
using IronSoftware.Drawing;
AnyBitmap bitmap = AnyBitmap.FromFile(@"FILE_PATH");
// Convert AnyBitmap to a string that represents the object
string bitmapString = bitmap.ToString();
Cast to AnyBitmap:
using IronSoftware.Drawing;
using System.IO;
// We create an AnyBitmap object. We will then cast other popular types to Anybitmap.
AnyBitmap anyBitmap;
// Cast System.Drawing bitmap to AnyBitmap
System.Drawing.Bitmap bitmapFromBitmap = new System.Drawing.Bitmap(@"FILE_PATH");
anyBitmap = bitmapFromBitmap;
// Cast System image to AnyBitmap
System.Drawing.Image bitmapFromFile = System.Drawing.Image.FromFile(@"FILE_PATH");
anyBitmap = bitmapFromFile;
// Cast SKBitmap to AnyBitmap
SkiaSharp.SKBitmap skiaBitmap = SkiaSharp.SKBitmap.Decode(@"FILE_PATH");
anyBitmap = skiaBitmap;
// Cast SKimage to AnyBitmap
SkiaSharp.SKImage skiaImage = SkiaSharp.SKImage.FromBitmap(SkiaSharp.SKBitmap.Decode(@"FILE_PATH"));
anyBitmap = skiaImage;
// Cast SixLabors Image to AnyBitmap
SixLabors.ImageSharp.Image<SixLabors.ImageSharp.PixelFormats.Rgba32> imgSharp = SixLabors.ImageSharp.Image.Load<SixLabors.ImageSharp.PixelFormats.Rgba32>(@"FILE_PATH");
anyBitmap = imgSharp;
// Cast Maui image to AnyBitmap (not for NET 4.7.2):
byte[] imageAsBytes = File.ReadAllBytes(@"FILE_PATH");
// var mauiPlatformImage = Microsoft.Maui.Graphics.Platform.PlatformImage.FromStream(new MemoryStream(imageAsBytes));
Clone AnyBitmap:
using IronSoftware.Drawing;
// Clone an AnyBitmap
AnyBitmap clonedframe = AnyBitmap.FromFile(@"FILE_PATH").Clone();
clonedframe.SaveAs("frameClone.jpg");
// Clone frames of any image with a specified crop area
AnyBitmap clonedWithCrop = AnyBitmap.FromFile(@"FILE_PATH").Clone(new Rectangle(0, 0, 150, 150));
clonedWithCrop.SaveAs("cropCloned.jpg");
Create Multipage TIFF and GIF:
using IronSoftware.Drawing;
using System.Collections.Generic;
// Create a multipage Tiff with frames of different dimensions
List<AnyBitmap> tiffBitmaps = new List<AnyBitmap>()
{
AnyBitmap.FromFile("cropframe1.jpg"),
AnyBitmap.FromFile("frame2.jpg"),
AnyBitmap.FromFile("cropframe3.jpg")
};
AnyBitmap multiFrameTiff = AnyBitmap.CreateMultiFrameTiff(tiffBitmaps);
multiFrameTiff.SaveAs("multiTiffwcrops.tiff");
// Create a multipage Gif with frames of different dimensions
List<AnyBitmap> gifBitmaps = new List<AnyBitmap>()
{
AnyBitmap.FromFile("frame1.jpg"),
AnyBitmap.FromFile("frame2.jpg"),
AnyBitmap.FromFile("frame3.jpg"),
AnyBitmap.FromFile("cropframe4.jpg")
};
AnyBitmap multiFrameGif = AnyBitmap.CreateMultiFrameGif(gifBitmaps);
multiFrameGif.SaveAs("multiGif.gif");
Export AnyBitmap:
using IronSoftware.Drawing;
//Export AnyBitmap files to other formats with ability to control loss
AnyBitmap bitmap = new AnyBitmap(@"FILE_PATH");
bitmap.ExportFile("losslogo.png", AnyBitmap.ImageFormat.Png, 100);
Generate AnyBitmap:
using IronSoftware.Drawing;
using System;
using System.IO;
AnyBitmap bitmap;
// Generate AnyBitmap using filepath
bitmap = AnyBitmap.FromFile(@"FILE_PATH");
bitmap.SaveAs("output.bmp");
// Generate AnyBitmap from bytes
byte[] bytes = File.ReadAllBytes(@"FILE_PATH");
bitmap = AnyBitmap.FromBytes(bytes);
bitmap.SaveAs("result.bmp");
// Generate AnyBitmap from memory stream
byte[] bytes2 = File.ReadAllBytes(@"FILE_PATH");
MemoryStream ms = new MemoryStream(bytes2);
bitmap = AnyBitmap.FromStream(ms);
bitmap.SaveAs("output.bmp");
// Generate AnyBitmap from Uri
Uri uri = new Uri("URI_PATH");
bitmap = await AnyBitmap.FromUriAsync(uri);
bitmap.SaveAs("uriImage.bmp");
// Generate AnyBitmap file from SVG file
bitmap = AnyBitmap.FromFile(@"FILE_PATH.svg");
bitmap.SaveAs("result.jpg");
以上示例代码可能与本人使用的版本有不同,可以更新至新版本,希望本文对你有帮助。