WPF图像调整大小和存储适用于大多数图像,但无法调整大小或保存在其他图像上

我正在尝试调整大小并保存Page_load事件中定义的3个图像.

方法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()是一个非常好的方法,例如,保证是唯一的.或者使用为每个图像递增的简单计数器.你需要专注于清理.

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...