在方法ResizeAndSave中我有两种方法我正在尝试:FastResize和SlowResize.
当我取消注释FastResize代码行时:IMAGE 1和2被保存并正确调整大小.但是,图像3以尺寸625x441px保存,因此不尊重我想要调整大小的200×200框.
当我改为使用SlowResize代码行时:图像1和2再次保存并正确调整大小.但是,图像3根本没有保存.
我的代码中没有抛出任何错误.我将从各种来源导入图像,因此我的代码适用于各种图像格式至关重要.显然,IMAGE 3有一些特别的东西,我不知道它是什么或如何处理它.
这是我的完整代码,你应该能够复制/粘贴它并自己测试它:
Imports System.Drawing Imports System.Drawing.Imaging Imports System.IO Imports System.Xml Imports System.Data.sqlClient Imports System.Net Imports System.Windows.Media.Imaging Imports System.Windows.Media Partial Class importFeeds Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object,ByVal e As System.EventArgs) Handles Me.Load 'IMAGE 1 ResizeAndSave(200,200,"https://upload.wikimedia.org/wikipedia/commons/8/82/Dell_logo.png") 'IMAGE 2 ResizeAndSave(200,"https://upload.wikimedia.org/wikipedia/commons/d/d8/Square-1_solved.jpg") 'IMAGE 3 ResizeAndSave(200,"http://cdn2.emobassets.eu/media/catalog/product/1/1/1116220.jpg") End Sub Private Sub ResizeAndSave(ByVal maxWidth As Integer,ByVal maxHeight As Integer,ByVal imageURL As String) Dim imgRequest As WebRequest = WebRequest.Create(imageURL) Dim imgResponse As WebResponse = imgRequest.GetResponse() Dim streamPhoto As Stream = imgResponse.GetResponseStream() Dim memStream As New MemoryStream streamPhoto.CopyTo(memStream) memStream.Position = 0 Dim bfPhoto As BitmapFrame = ReadBitmapFrame(memStream) Dim newWidth,newHeight As Integer Dim scaleFactor As Double If bfPhoto.Width > maxWidth Or bfPhoto.Height > maxHeight Then If bfPhoto.Width > maxWidth Then scaleFactor = maxWidth / bfPhoto.Width newWidth = Math.Round(bfPhoto.Width * scaleFactor,0) newHeight = Math.Round(bfPhoto.Height * scaleFactor,0) End If If newHeight > maxHeight Then scaleFactor = maxHeight / newHeight newWidth = Math.Round(newWidth * scaleFactor,0) newHeight = Math.Round(newHeight * scaleFactor,0) End If End If Dim bfResize As BitmapFrame = FastResize(bfPhoto,newWidth,newHeight) 'Dim bfResize As BitmapFrame = SlowResize(bfPhoto,newHeight,BitmapScalingMode.Linear) Dim baResize As Byte() = ToByteArray(bfResize) Dim strThumbnail As String = Guid.NewGuid.ToString() + ".png" Dim saveToPath As String = Server.MapPath(ConfigurationManager.AppSettings("products_photospath")) + "\49\" + strThumbnail File.WriteAllBytes(saveToPath,baResize) End Sub Private Shared Function FastResize(bfPhoto As BitmapFrame,nWidth As Integer,nHeight As Integer) As BitmapFrame Dim tbBitmap As New TransformedBitmap(bfPhoto,New ScaleTransform(nWidth / bfPhoto.PixelWidth,nHeight / bfPhoto.PixelHeight,0)) Return BitmapFrame.Create(tbBitmap) End Function 'http://weblogs.asp.net/bleroy/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi Public Shared Function SlowResize(photo As BitmapFrame,width As Integer,height As Integer,scalingMode As BitmapScalingMode) As BitmapFrame Dim group = New DrawingGroup() RenderOptions.SetBitmapScalingMode(group,scalingMode) group.Children.Add(New ImageDrawing(photo,New Windows.Rect(0,width,height))) Dim targetVisual = New DrawingVisual() Dim targetContext = targetVisual.RenderOpen() targetContext.DrawDrawing(group) Dim target = New RenderTargetBitmap(width,height,96,PixelFormats.[Default]) targetContext.Close() target.Render(targetVisual) Dim targetFrame = BitmapFrame.Create(target) Return targetFrame End Function Private Shared Function ToByteArray(bfResize As BitmapFrame) As Byte() Using msStream As New MemoryStream() Dim pbdDecoder As New PngBitmapEncoder() pbdDecoder.Frames.Add(bfResize) pbdDecoder.Save(msStream) Return msStream.ToArray() End Using End Function Private Shared Function ReadBitmapFrame(streamPhoto As Stream) As BitmapFrame Dim bdDecoder As BitmapDecoder = BitmapDecoder.Create(streamPhoto,BitmapCreateOptions.PreservePixelFormat,BitmapCacheOption.None) Return bdDecoder.Frames(0) End Function End Class
更新1
@Hans Passant:你对filenaming和pixelWidth使用的建议都是正确的,并帮助我在Page_load事件中的3个图像上成功运行此代码.
我更新了原始代码.
但是,当我将此代码作为实际应用程序的一部分运行时,我从Feed中导入~100个图像.新代码在尝试处理IMAGE 3时失败并出现内存不足异常.对于FastResize和SlowResize方法都会发生这种情况.我的代码或相关图像中是否存在导致内存使用量增加的情况,可能是某处出现泄漏或我使用的效率低下的调整方法?
我的机器上有很多可用的内存,所以如果这是问题就会非常惊讶,虽然我确实看到我的Windows任务管理器中的系统和压缩内存(到1.1GB)任务大幅增加.而且,这么多的内存使用会让我相信我的代码中存在错误.
它能是什么?
IMAGE 3 however,is saved in dimensions 625x441px
这是因为图像与其他图像略有不同,它的DPI(每英寸点数)是300而不是96.它的像素大小是3071 x 2172但你使用的是宽度和高度属性,大小以英寸为单位单位为1/96“,对于此图像为982.72 x 695.04.通过使用PixelWidth和PixelHeight属性来修复此问题:
Dim tbBitmap As New TransformedBitmap(bfPhoto,0))
IMAGE 3 however,is not saved at all
这并没有完全相加,但你在这个声明中确实有一个严重的错误:
Dim strThumbnail As String = "success" + Date.Now.Second.ToString + ".png"
此名称不够独特,以确保您不会覆盖现有文件.如果代码是“快速”,则Date.Now.Second将具有相同的值,并且您的代码将覆盖先前写入的图像文件.请注意,在调试时,这个bug不会重现,这会使代码人为地慢,第二个会有所不同.
你需要一个更好的方法来命名文件,Guid.NewGuid.ToString()是一个非常好的方法,例如,保证是唯一的.或者使用为每个图像递增的简单计数器.你需要专注于清理.