使用ImageResizer调整图片时触发GDI+通用错误求助
GDI+通用错误排查(ImageResizer图片缩放问题)
问题代码
private void ResizeImage(int width, int height, string szFilePath, string destinationPath) { //var watch = new System.Diagnostics.Stopwatch(); //watch.Start(); Serilog.Log.ForContext<ImageResizeHandler>().Information($"Image resize process start for file :{szFilePath}"); var instructions = getInstructions(width, height); try { ImageResizer.ImageBuilder.Current.Build(szFilePath, szFilePath, instructions); File.Move(szFilePath, destinationPath); //watch.Stop(); Serilog.Log.ForContext<ImageResizeHandler>().Information($"Image resize process end for file :{szFilePath}"); } catch (Exception ex) { Serilog.Log.ForContext<ImageResizeHandler>().Error(ex, $"Failed to Resize the Image - filePath: {szFilePath}"); // If memory leak exception or any other error then use default thumbnail image. File.Copy(HttpContext.Current.Server.MapPath("~/Images/placeholder_160x180.png"), destinationPath); } }
错误日志
System.Runtime.InteropServices.ExternalException (0x80004005): A generic error occurred in GDI+. at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) at System.Drawing.Image.Save(Stream stream, ImageFormat format) at ImageResizer.Plugins.Basic.DefaultEncoder.SavePng(Image img, Stream target) at ImageResizer.Plugins.Basic.DefaultEncoder.Write(Image image, Stream s) at ImageResizer.ImageBuilder.BuildJobBitmapToStream(ImageJob job, Bitmap source, Stream dest) at ImageResizer.ImageBuilder.BuildJob(ImageJob job) at ImageResizer.ImageBuilder.BuildInternal(ImageJob job) at ImageResizer.ImageBuilder.BuildInQueue(ImageJob job, Boolean useSemaphore, Int32 maxQueuingMilliseconds, CancellationToken cancel) at ImageResizer.ImageBuilder.Build(ImageJob job) at ImageResizer.ImageBuilder.Build(Object source, Object dest, Instructions instructions) at CampaignerImageResizer.ImageResizeHandler.ResizeImage(Int32 width, Int32 height, String szFilePath, String destinationPath) in C:\agent\_work\49\s\CampaignerImageResizer\ImageResizeHandler.ashx.cs:line 56
解决方案
避免读写同一文件:当前代码直接将源文件作为输出目标,GDI+读取文件时会锁定文件,无法同时写入。改为先输出到临时文件,再替换原文件:
try { string tempPath = Path.Combine(Path.GetDirectoryName(szFilePath), $"temp_{Guid.NewGuid()}_{Path.GetFileName(szFilePath)}"); ImageResizer.ImageBuilder.Current.Build(szFilePath, tempPath, instructions); // 替换原文件 File.Delete(szFilePath); File.Move(tempPath, szFilePath); File.Move(szFilePath, destinationPath); // ... 原有日志代码 } catch (Exception ex) { // 异常处理时清理临时文件 if (File.Exists(tempPath)) File.Delete(tempPath); // ... 原有异常逻辑 }检查文件权限:确认应用程序身份(如IIS应用池账号)对源文件路径、临时文件路径及目标路径拥有读写权限,避免因权限不足导致写入失败。
验证图片完整性:处理前先检查图片文件是否损坏,避免GDI+处理无效文件报错:
try { using (Image img = Image.FromFile(szFilePath)) { // 图片可正常打开,继续处理 } } catch (Exception ex) { Serilog.Log.ForContext<ImageResizeHandler>().Error(ex, $"Corrupted or invalid image file: {szFilePath}"); // 直接使用占位图,跳过缩放 File.Copy(HttpContext.Current.Server.MapPath("~/Images/placeholder_160x180.png"), destinationPath); return; }显式管理文件流:使用
FileStream控制文件读写的权限和资源释放,避免隐式锁定问题:using (var sourceStream = new FileStream(szFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var tempStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None)) { ImageResizer.ImageBuilder.Current.Build(sourceStream, tempStream, instructions); }
内容的提问来源于stack exchange,提问作者Hiren
相关产品推荐
相关产品推荐

