How do I bind a Byte array to an Image in WPF with a value converter?

17

I'm trying to bind a Byte array from my databse to a WPF Image.

My XAML:

<Window.Resources>
    <local:BinaryImageConverter x:Key="imgConverter" />
</Window.Resources>
...
<Image Source="{Binding Path=ImageData, Converter={StaticResource imgConverter}}" />

I've modified code published by Ryan Cromwell for a value converter:

Class BinaryImageConverter
    Implements IValueConverter
    Private Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        If value IsNot Nothing AndAlso TypeOf value Is Byte() Then
            Dim bytes As Byte() = TryCast(value, Byte())
            Dim stream As New MemoryStream(bytes)
            Dim image As New BitmapImage()
            image.BeginInit()
            image.StreamSource = stream
            image.EndInit()
            Return image
        End If
        Return Nothing
    End Function
    Private Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New Exception("The method or operation is not implemented.")
    End Function
End Class

The image.EndInit() line of the BinaryImageConverter's Convert() function throws this NotSupportedException:

"No imaging component suitable to complete this operation was found."

InnerException: "Exception from HRESULT: 0x88982F50"

I don't understand what I'm doing wrong. How can I get this working?


Update

It seems the problem was the bytes coming out of the database. There must have been a problem with the way I was putting them in.

See my working code below.

.net
wpf
data-binding
xaml
image
asked on Stack Overflow Mar 26, 2009 by Zack Peterson • edited Mar 26, 2009 by Zack Peterson

5 Answers

28

You can bind a byte[] to an Image.

Here a Sample:

Xaml:

<Image Source="{Binding UserImage}"/>

Code:

private byte[] userImage;

public byte[] UserImage
   {
       get { return userImage; }
       set
       {
           if (value != userImage)
           {
               userImage = value;
               OnPropertyChanged("UserImage");
           }
       }
   }
answered on Stack Overflow Dec 8, 2011 by sebastianb • edited Dec 13, 2012 by Charlie
13

Thanks for all your help. I've now got it working. I'm still not sure exactly what the problem was.

This is how I put images into my database…

Private Sub ButtonUpload_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    Dim FileOpenStream As Stream = Nothing
    Dim FileBox As New Microsoft.Win32.OpenFileDialog()
    FileBox.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
    FileBox.Filter = "Pictures (*.jpg;*.jpeg;*.gif;*.png)|*.jpg;*.jpeg;*.gif;*.png|" & _
                     "All Files (*.*)|*.*"
    FileBox.FilterIndex = 1
    FileBox.Multiselect = False
    Dim FileSelected As Nullable(Of Boolean) = FileBox.ShowDialog(Me)
    If FileSelected IsNot Nothing AndAlso FileSelected.Value = True Then
        Try
            FileOpenStream = FileBox.OpenFile()
            If (FileOpenStream IsNot Nothing) Then

                Dim ByteArray As Byte()
                Using br As New BinaryReader(FileOpenStream)
                    ByteArray = br.ReadBytes(FileOpenStream.Length)
                End Using

                Dim g As New ZackGraphic
                g.Id = Guid.NewGuid
                g.ImageData = ByteArray
                g.FileSize = CInt(ByteArray.Length)
                g.FileName = FileBox.FileName.Split("\").Last
                g.FileExtension = "." + FileBox.FileName.Split(".").Last.ToLower
                g.DateAdded = Now

                Dim bmp As New BitmapImage
                bmp.BeginInit()
                bmp.StreamSource = New MemoryStream(ByteArray)
                bmp.EndInit()
                bmp.Freeze()

                g.PixelWidth = bmp.PixelWidth
                g.PixelHeight = bmp.PixelHeight

                db.AddToZackGraphic(g)
                db.SaveChanges()

            End If
        Catch Ex As Exception
            MessageBox.Show("Cannot read file from disk. " & Ex.Message, "Add a New Image", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK)
        Finally
            If (FileOpenStream IsNot Nothing) Then
                FileOpenStream.Close()
            End If
        End Try
    End If
End Sub

This is my value converter used to bind a Byte array to an Image…

Class BinaryImageConverter
    Implements IValueConverter
    Private Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        If value IsNot Nothing AndAlso TypeOf value Is Byte() Then
            Dim ByteArray As Byte() = TryCast(value, Byte())
            Dim bmp As New BitmapImage()
            bmp.BeginInit()
            bmp.StreamSource = New MemoryStream(ByteArray)
            bmp.EndInit()
            Return bmp
        End If
        Return Nothing
    End Function
    Private Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New Exception("The method or operation is not implemented.")
    End Function
End Class

This is my XAML that uses the converter display the image…

<Window xmlns:local="clr-namespace:MyProjectName" ... >
    <Window.Resources>
        <local:BinaryImageConverter x:Key="imgConverter" />
    </Window.Resources>
...
<Image Source="{Binding Path=ImageData, Converter={StaticResource imgConverter}}" />
answered on Stack Overflow Mar 26, 2009 by Zack Peterson • edited Mar 26, 2009 by Zack Peterson
2

Try using this

Dim imageSource as ImageSource
Dim bitmapDecoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
imageSource = bitmapDecoder.Frames[0];
imageSource.Freeze();
Return imageSource
answered on Stack Overflow Mar 26, 2009 by bendewey
1

I believe this is actually a security permission issue. Try running with administrator privileges, and see if that works, and go from there.

EDIT: I disagree with the downvote and comment. Take a look at this link:

http://social.expression.microsoft.com/Forums/en-US/wpf/thread/617f6711-0373-44cc-b72c-aeae20f0f7a8/

This user had the exact same error, and it was caused by security settings. Therefore, I stand by my answer (which may not be the cause, but it is certainly worth a try)

answered on Stack Overflow Mar 26, 2009 by Razzie • edited Mar 26, 2009 by Razzie
1

My guess would be that the bytes are not a legitimate image format. I believe that error code corresponds to WINCODEC_ERR_COMPONENTNOTFOUND, which would be consistent with invalid bytes.

What format is the byte array supposed to be in? Can you save it to disk, and try to open it with another imaging program?

answered on Stack Overflow Mar 26, 2009 by casperOne

User contributions licensed under CC BY-SA 3.0