WPF图像调整大小和存储适用于大多数图像,但无法调整大小或保存在其他图像上 [英] WPF Image resizing and storing works on most images but fails to resize or save on others

查看:195
本文介绍了WPF图像调整大小和存储适用于大多数图像,但无法调整大小或保存在其他图像上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to resize and save the 3 images as defined in the Page_load event.

方法 ResizeAndSave 我正在尝试两种方法: FastResize SlowResize

Within method ResizeAndSave I have 2 methods I'm trying: FastResize and SlowResize.

当我取消注释 FastResize 代码行时:图像1和2被保存并正确调整大小。但是,图像3以尺寸625x441px保存,因此不尊重我想要调整大小的200x200框。

When I uncomment the FastResize codeline: IMAGE 1 and 2 are saved and resized correctly. IMAGE 3 however, is saved in dimensions 625x441px and so does not respect the 200x200 box I want it to resize to.

当我改为使用时SlowResize 代码行:图像1和2再次保存并正确调整大小。但是,图像3根本没有保存。

When I instead use the SlowResize codeline: IMAGE 1 and 2 are again saved and resized correctly. IMAGE 3 however, is not saved at all.

我的代码中没有错误。我将从各种来源导入图像,因此我的代码适用于各种图像格式至关重要。显然有一些关于IMAGE 3的特别之处,我不知道它是什么或如何处理它。

No errors are thrown in my code. I will import images from a variety of sources so it's critical my code works on a wide range of image formats. And apparently there's something special about IMAGE 3 and I don't know what it is or how to handle it.

这是我的完整代码,你应该可以只复制/粘贴并自行测试:

Here's my full code, you should be able to just copy/paste it and test it for yourself:

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, 200, "https://upload.wikimedia.org/wikipedia/commons/d/d8/Square-1_solved.jpg")  
    'IMAGE 3
    ResizeAndSave(200, 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, newWidth, 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, 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, 0, width, height)))
    Dim targetVisual = New DrawingVisual()
    Dim targetContext = targetVisual.RenderOpen()
    targetContext.DrawDrawing(group)
    Dim target = New RenderTargetBitmap(width, height, 96, 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张图像。新代码在尝试处理图像3时失败并出现内存不足异常。 FastResize SlowResize 方法。我的代码或图像中是否存在导致内存使用量增加的情况,可能是某处出现泄漏或我使用的效率低下的调整方法?

@Hans Passant: Both your suggestions on filenaming and pixelWidth usage are spot on and helped me run this code successfully on the 3 images in the Page_load event. I updated my original code.
However, when I run this code as part of my actual application, where I import ~100 images from a feed. The new code fails with an out of memory exception when it tries to process IMAGE 3. This happens for both FastResize and SlowResize methods. Is there something in my code or in the image in question that would cause this increase in memory usage, maybe a leak somewhere or an inefficient resizing method I use?

我有我的机器上有很多可用内存,所以如果这是问题就会非常惊讶,虽然我确实看到系统和压缩内存的大幅增加(至1.1GB) )我的Windows任务管理器中的任务。而且,这么大的内存使用会让我相信我的代码有问题。

I have a lot of memory available on my machine, so would be very surprised if that were the problem, although I do see a big increase in the System and compressed memory (to 1.1GB) task in my Windows task manager. And still, this much memory usage would have me believe that there's something wrong in my code.

它有什么用?

推荐答案


图像3但是,尺寸保存为625x441px

IMAGE 3 however, is saved in dimensions 625x441px

这是因为图像与其他图像略有不同,其DPI(每英寸点数)为300而不是96.其尺寸以像素为单位为3071 x 2172但您使用的是宽度和高度属性,大小以英寸为单位,单位为1/96,对于此图像为982.72 x 695.04。通过使用PixelWidth和PixelHeight属性来修复此问题:

That is because the image is slightly different from the other ones, its DPI (dots per inch) is 300 instead of 96. Its size in pixels is 3071 x 2172 but you are using the Width and Height properties, the size in inches with a unit of 1/96" which is 982.72 x 695.04 for this image. Fix this by using the PixelWidth and PixelHeight properties instead:

Dim tbBitmap As New TransformedBitmap(bfPhoto, 
   New ScaleTransform(nWidth / bfPhoto.PixelWidth, nHeight / bfPhoto.PixelHeight, 0, 0))








图像3然而,根本没有保存

IMAGE 3 however, is not saved at all

这不会加起来完全,但你在这个陈述中确实有一个严重的错误:

That doesn't add up completely, but you do have a critical bug in this statement:

Dim strThumbnail As String = "success" + Date.Now.Second.ToString + ".png"

此名称不够独特,以确保您不会覆盖现有文件。如果代码是快速,则Date.Now.Second将具有相同的值,并且您的代码将覆盖先前写入的图像文件。注意调试时这个bug不会重现,这会使代码人为地慢,第二个会有所不同。

This name is not sufficiently unique to ensure that you don't overwrite an existing file. And if the code is "fast" then Date.Now.Second will have the same value and your code overwrites a previous written image file. Note how this bug won't repro when you debug, that makes the code artificially slower and the second will be different.

你需要一个更好的方法来命名文件,Guid.NewGuid.ToString()是一种非常好的方法,例如,保证是唯一的。或者使用为每个图像递增的简单计数器。你需要专注于清理。

You'll need a better way to name the file, Guid.NewGuid.ToString() is a very good way for example, guaranteed to be unique. Or use a simple counter that you increment for each image. You do need to focus on cleanup.

这篇关于WPF图像调整大小和存储适用于大多数图像,但无法调整大小或保存在其他图像上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆