"Параметр недействителен" при использовании метода Image.fromStream

Я часами борюсь с этой проблемой.

If result = Windows.Forms.DialogResult.OK Then
  Dim path As String = OpenFileDialog1.FileName
  Dim img As Image = Image.FromFile(path)
  Using mStream As New MemoryStream()
    img.Save(mStream, img.RawFormat)
    Dim bArr As Byte() = mStream.ToArray()
  End Using
  Dim params As New List(Of SqlParameter)
  params.Add(New SqlParameter("@Image", bArr))
  CallSP("UpdateImageSP", params)
End If

Это фактически обновит базу данных в столбце varbinary со значением: 0x89504E470D0A1A0A0000000D49484452000004120000041208060000001258D9C6000000017352474200AECE1CE900000004

Время извлечь изображение и показать его в картинке:

Dim dtIcon As DataTable = DataTableGet("getImageSP")
If dtIcon IsNot Nothing AndAlso Not dtIcon.Rows(0)("Image") Is DBNull.Value Then
  Dim imageData As Byte() = DirectCast(dtIcon.Rows(0)("Image"), Byte())
  If imageData.Length > 0 Then
    Using mStream As New MemoryStream(imageData)
      Dim x As Image = Image.FromStream(mStream) --<--ERROR HERE !!
    End Using
    PictureBox1.BackgroundImage = x
  End If
End If

Ошибка "Произошло необработанное исключение типа" System.ArgumentException "в System.Drawing.dll. Дополнительная информация: параметр недействителен".

Я пробовал несколько примеров кода, которые я нашел, результат всегда был таким. Кто-нибудь знает, в чем здесь проблема?

2 ответа

Решение

Изображение может быть неправильно сохранено при загрузке в базу данных, или у вас могут возникнуть проблемы с его преобразованием.

Одна вещь, которую я хотел бы сделать, это объявить тип вашего байтового массива, идущего в SQL:

params.Add(New SqlParameter("@Image", bArr, SqlDbType.VarBinary,-1))

При загрузке изображения в базу данных вы не используете данные в качестве типа изображения. Было бы проще получить двоичные данные, используя File.ReadAllBytes:

Dim bArr As Byte()
bArr = File.ReadAllBytes(path)

Кроме того, вы можете проверить, чтобы убедиться, что сохраненные данные из базы данных выглядят правильно, попытавшись сохранить их на диск, а не загружать в Picturebox. Если вы не можете открыть его как изображение, значит что-то не так с сохраненными данными:

Dim stream As New FileStream([Some Test Path], FileMode.Create, FileAccess.Write)
stream.Write(imageData, 0, imageData.Length)
stream.Close()

Ваш первый фрагмент кода не должен работать. Есть ошибка, потому что этот код создает блок области видимости:

Using mStream As New MemoryStream()
    img.Save(mStream, img.RawFormat)
    Dim bArr As Byte() = mStream.ToArray()
End Using

Как только этот блок закрыт, bArr Массив выходит из области видимости (примечание: не удаляется. Просто выходит из области видимости) при последующем его использовании:

 params.Add(New SqlParameter("@Image", bArr))

Чтобы исправить это, либо расширьте блок области действия, либо объявите bArr перед блоком области:

If result = Windows.Forms.DialogResult.OK Then
     Dim path As String = OpenFileDialog1.FileName
     Dim img As Image = Image.FromFile(path)
     Dim bArr() As Byte
     Using mStream As New MemoryStream()
        img.Save(mStream, img.RawFormat)
        bArr = mStream.ToArray()
     End Using
     Dim params As New List(Of SqlParameter)
     params.Add(New SqlParameter("@Image", bArr))
     CallSP("UpdateImageSP", params)
End If

То, что это пока работает для вас, является случайностью того, что сбор мусора произошел не в то время. Я не знаю, что это решит вашу проблему, но вы все равно должны решить ее.

Чтобы более тщательно проверить проблему по вашему вопросу, я бы временно изменил метод сохранения вашего байта при загрузке в БД, чтобы вы могли сравнивать его байт с байтом с массивом при извлечении его из БД. Найдите и проанализируйте любые различия. Если они одинаковые (это то, на что вы надеетесь), пришло время перейти к следующему шагу.

Если бы мне пришлось угадывать, я бы сказал, что проблема заключается в использовании img.RawFormat когда вы сохраняете его в потоке памяти, это как-то не тот формат, который вы ожидаете. В любом случае вы можете обойти эту проблему, загрузив байтовый массив непосредственно из файла:

If result = Windows.Forms.DialogResult.OK Then
    Dim bArr As Byte() = IO.File.ReadAllBytes(OpenFileDialog1.FileName)
    Dim params As New List(Of SqlParameter)
    params.Add(New SqlParameter("@Image", bArr))
    CallSP("UpdateImageSP", params)
End If

Наконец, код возврата снова имеет проблему области, где ваш x Переменная изображения потенциально может быть собрана в том коротком двухстрочном интервале между тем, когда она выходит из области видимости и когда вы назначаете PictureBox:

Dim dtIcon As DataTable = DataTableGet("getImageSP")
If dtIcon IsNot Nothing AndAlso Not (dtIcon.Rows(0)("Image") Is DBNull.Value) Then
    Dim imageData As Byte() = DirectCast(dtIcon.Rows(0)("Image"), Byte())
    If imageData.Length > 0 Then
        Using mStream As New MemoryStream(imageData)
            PictureBox1.BackgroundImage = Image.FromStream(mStream) 
        End Using
    End If
End If
Другие вопросы по тегам