【问题标题】:How to resize and image and save as byte array如何调整大小和图像并保存为字节数组
【发布时间】:2020-06-27 01:04:53
【问题描述】:

我试图让用户选择一个图像文件,然后根据需要将图像大小调整为几个不同的大小,然后将调整大小的图像保存到将保存到数据库中的字节数组中。将图像转换为字节数组时(但仅在调整图像大小时),我不断收到错误。希望有人能告诉我我做错了什么。

仅供参考,我不是专业的程序员,当我发布我的代码时通常会受到批评。我绝对愿意接受您可能有的任何反馈或建议,所以请善待..lol

我通常在 Image.Save(mStream, TheImage.RawFormat) 行的 SaveImage() 函数中收到此错误 System.ArgumentNullException: '值不能为空。参数名称:编码器'

有时我会遇到框架错误,并且无法确定错误发生在哪里。

编辑:我最终扩展了 Image 类,到目前为止它似乎工作得很好。

Imports System.Drawing.Imaging
Imports System.IO

Module Extentions
    <Runtime.CompilerServices.Extension()>
    Public Function GetBytes(ByRef bc As Image, Optional Format As ImageFormat = Nothing) As Byte()
        'Converts Image to Byte Array
        If Format Is Nothing Then Format = ImageFormat.Jpeg
        Using mStream As New MemoryStream()
            bc.Save(mStream, Format)
            Return mStream.ToArray()
        End Using
    End Function

    <Runtime.CompilerServices.Extension()>
    Public Function ReSize(ByRef bc As Image, MaxWidth As Integer, MaxHeight As Integer) As Image
        'Resize image to fit within MaxWidth & MaxHeight while keeping aspect ratio
        If MaxWidth < bc.Width Or MaxHeight < bc.Height Then
            Dim Scale As Double = Math.Min(MaxWidth / bc.Width, MaxHeight / bc.Height)
            Dim NewWidth As Integer = CInt(Math.Round(bc.Width * Scale))
            Dim NewHeight As Integer = CInt(Math.Round(bc.Height * Scale))
            Return New Bitmap(bc, New Size(NewWidth, NewHeight))
        Else
            Return bc
        End If
    End Function
End Module

现在我正在处理的表单中的代码要简单得多..

    Private Sub SelectImage_Click(sender As Object, e As EventArgs) Handles SelectImage.Click
        Dim Popup As New OpenFileDialog
        With Popup
            .Filter = "Images|*.gif;*.png;*.jpg;*.bmp"
            .Title = "Select Image"
            .FileName = ""
            .FilterIndex = 1
            .Multiselect = False
            .RestoreDirectory = True
        End With

        If Popup.ShowDialog = vbOK Then
            'Load Image from disk
            OriginalImage = Image.FromFile(Popup.FileName)

            'Resize and display image on form
            Picture.Image = OriginalImage.ReSize(200, 150)

            'Save Large Image
            FullImage = OriginalImage.ReSize(400, 300).GetBytes

            'Save Small Image
            SmallImage = OriginalImage.ReSize(100, 75).GetBytes

            ImageSelected = True
        End If
    End Sub

这是我的原始代码...

    Private OriginalImage As Image
    Private FullImage As Byte()
    Private SmallImage As Byte()
    Private ImageSelected As Boolean
Private Sub SelectImage_Click(sender As Object, e As EventArgs) Handles SelectImage.Click
        Dim Popup As New OpenFileDialog
        With Popup
            .Filter = "Images|*.gif;*.png;*.jpg;*.bmp"
            .Title = "Select Image"
            .FileName = ""
            .FilterIndex = 1
            .Multiselect = False
            .RestoreDirectory = True
        End With

        If Popup.ShowDialog = vbOK Then
            'Load Image from disk
            OriginalImage = Image.FromFile(Popup.FileName)

            'Resize and display image on form
            Picture.Image = ResizeImage(OriginalImage, 200, 150)

            'Save Large Image
            Dim ResizedImage As Image = ResizeImage(OriginalImage, 400, 300)
            FullImage = SaveImage(ResizedImage)

            'Save Small Image
            ResizedImage = ResizeImage(OriginalImage, 100, 75)
            SmallImage = SaveImage(ResizedImage)

            ImageSelected = True
        End If
    End Sub

    Private Function ResizeImage(ByRef InputImage As Image, MaxWidth As Integer, MaxHeight As Integer) As Image
        'ReSize the Image if needed to save space in the database
        If MaxWidth < InputImage.Width Or MaxHeight < InputImage.Height Then
            'ReSize Image
            Dim Scale As Double = Math.Min(MaxWidth / InputImage.Width, MaxHeight / InputImage.Height)
            Return New Bitmap(InputImage, New Size(Math.Round(InputImage.Width * Scale), Math.Round(InputImage.Height * Scale)))
        Else
            'Image size was OK
            Return InputImage
        End If
    End Function

    Private Function GetImage(ImageData As Byte()) As Image
        'Converts Byte Array to Image
        Using mStream As New MemoryStream(ImageData)
            Return Image.FromStream(mStream)
        End Using
    End Function

    Private Function SaveImage(TheImage As Image) As Byte()
        'Converts Image to Byte Array
        Using mStream As New MemoryStream()
            TheImage.Save(mStream, TheImage.RawFormat)
            Return mStream.ToArray()
        End Using
    End Function


    'These are functions I was playing around with because I was getting
    'System.ArgumentNullException: 'Value cannot be null. Parameter name: encoder'
    'in the SaveImage() function on TheImage.Save(mStream, TheImage.RawFormat)
    'and I wasn't using the encoder parameter. I couldn't get these to help me though.

    Private Function SaveImage2(TheImage As Image) As Byte()
        'Converts Image to Byte Array
        Dim CodecInfo As Imaging.ImageCodecInfo = GetEncoderInfo("image/jpeg")
        Dim Parameters As New Imaging.EncoderParameters(1)
        Parameters.Param(0) = New Imaging.EncoderParameter(Imaging.Encoder.Quality, 75L)
        Using mStream As New MemoryStream()
            TheImage.Save(mStream, CodecInfo, Parameters)
            Return mStream.ToArray()
        End Using
    End Function

    Private Function GetEncoderInfo(MimeType As String) As Imaging.ImageCodecInfo
        Dim encoders As Imaging.ImageCodecInfo()
        encoders = Imaging.ImageCodecInfo.GetImageEncoders()
        For j As Integer = 0 To encoders.Length - 1
            If encoders(j).MimeType = MimeType Then Return encoders(j)
        Next
        Return Nothing
    End Function

【问题讨论】:

  • 使用ImageResizer
  • TheImage.Save(mStream, ImageFormat.Png).
  • 更具体地说,当您在内存中生成新的位图时,RawFormat 设置为ImageFormat.MemoryBmp。您无法使用该格式保存图像(它不是 real 格式)。顺便说一句,据我所知,您应该设置 Option Strict On 并解决问题,然后才能获得与预期值不完全匹配的扭曲图像或图像尺寸。
  • 谢谢!我知道是这样的。我只是不知道如何使用 ImageFormat.Png 设置格式。我打开了 option strict ,看看你对双精度/整数转换的意思,我也会解决这个问题。如果你想发表你的评论作为答案,我会接受。

标签: vb.net winforms bitmap encoder .net-4.7.2


【解决方案1】:

当你用这个构造函数创建一个新的位图时:

new Bitmap([OriginalImage], [Width], [Height])

您可能认为[OriginalImage] 格式已被考虑在内。它不是。使用指定大小创建新的原始位图,并在新容器内绘制 [OriginalImage]
新的 Bitmap 对象在内存中创建,其 ImageFormatImageFormat.MemoryBmp
这个ImageFormat 没有编码器/解码器。

当您使用 Image.Save(Stream, Format) 方法重载并传递新的位图对象 RawFormat 保存图像时,您将传递 ImageFormat.MemoryBmp
然后 Image 类尝试从指定的ImageFormat 获取编码器(使用内部的FindEncoder() 方法),当然返回null,导致异常:

System.ArgumentNullException: '值不能为空。参数名称: 编码器'

您可以自己测试,尝试从OriginalImageResizedImage 对象中获取编码器/解码器(使用ImageCodecInfo.GetImageDecoders()ImageCodecInfo.GetImageEncoders()):

Dim originalCodec As ImageCodecInfo = ImageCodecInfo.GetImageDecoders().
    FirstOrDefault(Function(cc) cc.FormatID.Equals(ResizedImage.RawFormat.Guid))

您会看到,当您尝试获取 ResizedImage 格式的编码器/解码器时,originalCodec 将为空 (nothing),而它将返回 OriginalImage 的编码器/解码器格式。

由于预定义的ImageFormatImageFormat.Png,所以你可以在保存图片到MemoryStream时更改设置该格式的方法:

Using mStream As New MemoryStream()
    TheImage.Save(mStream, ImageFormat.Png)
    Return mStream.ToArray()
End Using

不止一次在内部完成的事情。
例如:Image.Save(MemoryStream stream)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多