服务器上的缩略图 - GDI+ 中发生一般性错误
Thumbnails on Server - A generic error occurred in GDI+
我们已经解决这个问题很长时间了,并尝试了很多来自网络的不同修复方法。到目前为止没有任何效果。
问题:基本图像保存正常,缩略图保存失败。在下面的解决方案之前,我曾尝试为所有图像(基本图像、600x600 和 300x300 拇指)创建单独的流,但这也没有用。所有的流都是从同一个字节数组构造的。请记住这一点:这在开发环境、测试环境和 Test2 环境中工作得很好,但在生产环境中无法工作。我已经检查了文件夹的所有设置/环境变量/权限,所有设置都与测试环境相同。
路径如下:
- 基本路径:“~/images/imageUpl/”
- 缩略图添加。路径:"thumbM/"
- 缩略图添加。路径:"thumbS/"
- 图像名称结构:"X_YYYYMMDD_HHMMSS_XX.png"
路径都是正确的 - 因为它适用于 Dev/Test/Test2 环境。
非常感谢任何帮助!
编辑:到目前为止我们尝试了什么:
- 为网络和 IISUser 设置权限
- 对从原始源数据构建的每个图像使用单独的流
- 根据其他示例添加 thread.sleep(30+)
- 从调整大小的位图创建新的位图并保存它
- 用于测试其目录在生产环境中是否存在问题的不同路径
编辑 2:作为参考,这是一个 ASP.NET MVC5 Web 应用程序,运行 of .NET Framework 4.7.2。
图像处理器Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using Newtonsoft.Json;
using System.Threading;
namespace CMS_MVC.Classes
{
public class ImageProcessor : IDisposable
{
public enum PathType : int
{
Relative = 1,
Static = 2
}
private Stream _ImageStream { get; set; }
private HttpContext _Context { get; set; }
public Image BaseImage { get; set; }
private int _instanceId { get; set; }
public ImageProcessor(int instanceId, Stream imageStream, HttpContext context)
{
this._ImageStream = imageStream;
this._Context = context;
this._instanceId = instanceId;
this.BaseImage = Image.FromStream(this._ImageStream);
}
public ImageProcessor(int instanceId, byte[] imageByteArray, HttpContext context)
{
this._Context = context;
this._instanceId = instanceId;
this._ImageStream = new MemoryStream(imageByteArray);
this.BaseImage = Image.FromStream(this._ImageStream);
}
public ImageProcessor(int instanceId, string imagePath, PathType pathType, HttpContext context)
{
this._Context = context;
this._instanceId = instanceId;
if (pathType == PathType.Relative)
{
this._ImageStream = new MemoryStream(File.ReadAllBytes(this._Context.Server.MapPath(imagePath)));
this.BaseImage = Image.FromStream(this._ImageStream);
}
else
{
this._ImageStream = new MemoryStream(File.ReadAllBytes(imagePath));
this.BaseImage = Image.FromStream(this._ImageStream);
}
}
public Dictionary<string, bool> SaveImages(string baseImageSavePath, string imageName, Dictionary<string, Tuple<int, int>> thumbnails = null)
{
Dictionary<string, bool> results = new Dictionary<string, bool>();
string lastResult = "main";
results.Add(lastResult, true);
try
{
this.BaseImage.Save(this._Context.Server.MapPath(Path.Combine(baseImageSavePath, imageName)), ImageFormat.Png);
if (thumbnails != null)
{
foreach (var thumbnail in thumbnails)
{
lastResult = thumbnail.Value.Item1.ToString() + "_" + thumbnail.Value.Item2.ToString();
results.Add(lastResult, true);
using (Bitmap thumbBitmap = this.ResizeImage(thumbnail.Value.Item1, thumbnail.Value.Item2))
{
Thread.Sleep(50);
thumbBitmap.Save(this._Context.Server.MapPath(Path.Combine(baseImageSavePath + thumbnail.Key, imageName)), ImageFormat.Png);
Thread.Sleep(50);
}
}
}
}
catch (Exception ex)
{
results[lastResult] = false;
// Log event
}
return results;
}
private Bitmap ResizeImage(int targetWidth, int targetHeight)
{
Tuple<int, int> destSize = this.CalculateThumbnailSizeAspectRatio(targetWidth, targetHeight);
var destRect = new Rectangle(0, 0, destSize.Item1, destSize.Item2);
var destImage = new Bitmap(destSize.Item1, destSize.Item2);
destImage.SetResolution(this.BaseImage.HorizontalResolution, this.BaseImage.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(this.BaseImage, destRect, 0, 0, this.BaseImage.Width, this.BaseImage.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
private Tuple<int, int> CalculateThumbnailSizeAspectRatio(int targetWidth, int targetHeight)
{
// Resize calculations
}
public void Dispose()
{
if (this._ImageStream != null) this._ImageStream.Dispose();
if (this.BaseImage != null) this.BaseImage.Dispose();
}
}
}
来自 documentation 网站:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.
该站点随后会将您定向到 WIC,但这不是一个好主意。服务器也不支持 WPF Media 类(但缺少关于此的同样明确的声明)。
出现了各种替代方案,这里是an older SO question。
最好的办法是寻找完全托管的解决方案,a.o。图像锐利。
我仍在寻找关于 System.Drawing.Common
的类似声明或见解,一个 .net 核心库。
我们已经解决这个问题很长时间了,并尝试了很多来自网络的不同修复方法。到目前为止没有任何效果。
问题:基本图像保存正常,缩略图保存失败。在下面的解决方案之前,我曾尝试为所有图像(基本图像、600x600 和 300x300 拇指)创建单独的流,但这也没有用。所有的流都是从同一个字节数组构造的。请记住这一点:这在开发环境、测试环境和 Test2 环境中工作得很好,但在生产环境中无法工作。我已经检查了文件夹的所有设置/环境变量/权限,所有设置都与测试环境相同。
路径如下:
- 基本路径:“~/images/imageUpl/”
- 缩略图添加。路径:"thumbM/"
- 缩略图添加。路径:"thumbS/"
- 图像名称结构:"X_YYYYMMDD_HHMMSS_XX.png"
路径都是正确的 - 因为它适用于 Dev/Test/Test2 环境。
非常感谢任何帮助!
编辑:到目前为止我们尝试了什么:
- 为网络和 IISUser 设置权限
- 对从原始源数据构建的每个图像使用单独的流
- 根据其他示例添加 thread.sleep(30+)
- 从调整大小的位图创建新的位图并保存它
- 用于测试其目录在生产环境中是否存在问题的不同路径
编辑 2:作为参考,这是一个 ASP.NET MVC5 Web 应用程序,运行 of .NET Framework 4.7.2。
图像处理器Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using Newtonsoft.Json;
using System.Threading;
namespace CMS_MVC.Classes
{
public class ImageProcessor : IDisposable
{
public enum PathType : int
{
Relative = 1,
Static = 2
}
private Stream _ImageStream { get; set; }
private HttpContext _Context { get; set; }
public Image BaseImage { get; set; }
private int _instanceId { get; set; }
public ImageProcessor(int instanceId, Stream imageStream, HttpContext context)
{
this._ImageStream = imageStream;
this._Context = context;
this._instanceId = instanceId;
this.BaseImage = Image.FromStream(this._ImageStream);
}
public ImageProcessor(int instanceId, byte[] imageByteArray, HttpContext context)
{
this._Context = context;
this._instanceId = instanceId;
this._ImageStream = new MemoryStream(imageByteArray);
this.BaseImage = Image.FromStream(this._ImageStream);
}
public ImageProcessor(int instanceId, string imagePath, PathType pathType, HttpContext context)
{
this._Context = context;
this._instanceId = instanceId;
if (pathType == PathType.Relative)
{
this._ImageStream = new MemoryStream(File.ReadAllBytes(this._Context.Server.MapPath(imagePath)));
this.BaseImage = Image.FromStream(this._ImageStream);
}
else
{
this._ImageStream = new MemoryStream(File.ReadAllBytes(imagePath));
this.BaseImage = Image.FromStream(this._ImageStream);
}
}
public Dictionary<string, bool> SaveImages(string baseImageSavePath, string imageName, Dictionary<string, Tuple<int, int>> thumbnails = null)
{
Dictionary<string, bool> results = new Dictionary<string, bool>();
string lastResult = "main";
results.Add(lastResult, true);
try
{
this.BaseImage.Save(this._Context.Server.MapPath(Path.Combine(baseImageSavePath, imageName)), ImageFormat.Png);
if (thumbnails != null)
{
foreach (var thumbnail in thumbnails)
{
lastResult = thumbnail.Value.Item1.ToString() + "_" + thumbnail.Value.Item2.ToString();
results.Add(lastResult, true);
using (Bitmap thumbBitmap = this.ResizeImage(thumbnail.Value.Item1, thumbnail.Value.Item2))
{
Thread.Sleep(50);
thumbBitmap.Save(this._Context.Server.MapPath(Path.Combine(baseImageSavePath + thumbnail.Key, imageName)), ImageFormat.Png);
Thread.Sleep(50);
}
}
}
}
catch (Exception ex)
{
results[lastResult] = false;
// Log event
}
return results;
}
private Bitmap ResizeImage(int targetWidth, int targetHeight)
{
Tuple<int, int> destSize = this.CalculateThumbnailSizeAspectRatio(targetWidth, targetHeight);
var destRect = new Rectangle(0, 0, destSize.Item1, destSize.Item2);
var destImage = new Bitmap(destSize.Item1, destSize.Item2);
destImage.SetResolution(this.BaseImage.HorizontalResolution, this.BaseImage.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(this.BaseImage, destRect, 0, 0, this.BaseImage.Width, this.BaseImage.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
private Tuple<int, int> CalculateThumbnailSizeAspectRatio(int targetWidth, int targetHeight)
{
// Resize calculations
}
public void Dispose()
{
if (this._ImageStream != null) this._ImageStream.Dispose();
if (this.BaseImage != null) this.BaseImage.Dispose();
}
}
}
来自 documentation 网站:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.
该站点随后会将您定向到 WIC,但这不是一个好主意。服务器也不支持 WPF Media 类(但缺少关于此的同样明确的声明)。
出现了各种替代方案,这里是an older SO question。
最好的办法是寻找完全托管的解决方案,a.o。图像锐利。
我仍在寻找关于 System.Drawing.Common
的类似声明或见解,一个 .net 核心库。