WPF conversion file from base64 and assignment source - c# - c#

I gather from json files that the user clicks on a wpf list ( c # ) .
Click to call a json pass me the file content in Base64 . I would convert it and have it displayed immediately without writing it on the user's hard .
And ' possible to convert it and leave it on the ram can then see immediately , as well as assign it to the object's source imageViewer?
Thank you
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock FontFamily="{StaticResource Lato Thin}" Margin="10,0,0,0" Foreground="#007AFF" Text="{x:Static res:strings.indietroPage}" MouseDown="GoBackFrame_MouseDown" FontSize="20" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Image Grid.Row="1" Source="{Binding uriImageSource}" Name="imageViewer"></Image>
</Grid>
first I was saving to disk first and then visualized , but I need that is not saved to disk , and you receive immediately as Source
File.WriteAllBytes(System.IO.Path.GetTempPath() + attachmentDownload.Name + "." + attachmentDownload.Extension, Convert.FromBase64String(attachmentDownload.B64Content));
i have try this
fileSourceBytes = Convert.FromBase64String(attachmentDownload.B64Content);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = new MemoryStream(fileSourceBytes);
bi.EndInit();
imageViewer.Source = bi;
but receive an error:
Object reference not set to an instance of an object.

solution:
codebehind
public Byte[] fileSourceBytes { get; set; }
fileSourceBytes = Convert.FromBase64String(attachmentDownload.B64Content);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = new MemoryStream(fileSourceBytes);
bi.EndInit();
uriImageSource = bi;
xaml:
<Image Grid.Row="1" Source="{Binding uriImageSource}" Name="imageViewer"></Image>

Maybe the best solution would be if you would just bind the BitmapImage to the ImageViewer's Source property.
ViewModel:
BitmapImage _imageViewerSource;
public BitmapImage ImageViewerSource {
get { return _imageViewerSource; }
private set
{
_imageViewerSource = value;
OnPropertyChanged("ImageViewerSource"); // or OnPropertyChanged(nameof(ImageViewerSource)); if you are using VS2015+
}
}
Xaml:
<Image Source="{Binding ImageViewerSource, Mode=OneWay}"/>

This should solve your problem issue
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes(Convert.FromBase64String(base64););
writer.StoreAsync().GetResults();
}
BitmapImage image = new BitmapImage();
image.SetSource(stream);
}

Related

Set and Change Button Image by Cliciking on it WPF, C#

I've got a class, which holds 8 BitmapImage in an array. The Images are added in the following way in the class constructor:
public SymbolCollection(string[] symbolNames)
{
Symbols = new BitmapImage[8];
for (int i = 0; i < Symbols.Length; i++)
{
Symbols[i] = new BitmapImage();
Symbols[i].BeginInit();
Symbols[i].UriSource = new Uri(#"/Resources/" + symbolNames[i] + ".png", UriKind.Relative);
Symbols[i].EndInit();
}
}
The button's ImageSource are set to the following:
<Button x:Name="buttonPlayer1" HorizontalAlignment="Left" Height="80" Margin="44,387,0,0" VerticalAlignment="Top" Width="80" Click="OnPlayerSymbolClick">
<Button.Template>
<ControlTemplate>
<Image Source="{Binding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
I tried to set the image to the button in the MainWindow() method and change it in the OnPlayerSymbolClick() method, but the image doesn't even show up:
public MainWindow()
{
this.InitializeComponent();
SetSymbolCollection();
Uri u = symbolCollectionHolder[0].Symbols[0].UriSource;
Debug.WriteLine(u.ToString());
Image i = new Image();
BitmapImage bmp = new BitmapImage();
bmp.UriSource = u;
i.Source = bmp;
buttonPlayer1.Content = i;
}
private void OnPlayerSymbolClick(object sender, RoutedEventArgs e)
{
ImageBrush imagebrush = new ImageBrush();
imagebrush.ImageSource = symbolCollectionHolder[0].Symbols[1];
buttonPlayer1.Background = imagebrush;
buttonPlayer1.Content = imagebrush;
Debug.WriteLine(buttonPlayer1.Background.ToString());
Debug.WriteLine(imagebrush.ImageSource.ToString());
}
The Build Action for the png-s are set to Resource and there's a Resources folder in the project.
When an image resource file is to be loaded into a BitmapImage in code behind, you should use a Resource File Pack URI:
Symbols[i] = new BitmapImage(new Uri(
"pack://application:,,,/Resources/" + symbolNames[i] + ".png"));
Besides that, setting the Content or Background property is pointless when the Button's Template doesn't use these properties.
You probably wanted to write the Template like this:
<Button x:Name="buttonPlayer1" ...>
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Source="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
which would require an ImageSource (or a derived object) as value of the Button's Content.
You could directly pass one of your Symbols:
buttonPlayer1.Content = Symbols[0];

Programmatically setting Image.Source property: I get an empty image

I have a folder inside my project which includes some images, for example: "Cards/1-1.png".
I have an Image element linked with XAML, and I'm trying to set it's Source property programmatically:
BitmapImage bitmap = new BitmapImage();
string filename= "Cards/1-1.png";
bitmap.UriSource = new Uri("/Poker;component/" + filename, UriKind.Relative);
cardImage1.Source= bitmap; // myImage linked with XAML
I try to fill 5 images, and I checked the filenames, they're correct. But the images are still empty (they're inside the StackPanel on the right):
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right"
Background="Green">
<Image Width="80" Height="100" Margin="10" x:Name="cardImage1"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage2"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage3"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage4"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage5"/>
</StackPanel>
BitmapImage implements ISupportInitialize interface which means any property change after initialization of object will be ignored unless wrap in BeginInit() and EndInit().
Quote from MSDN:
BitmapImage implements the ISupportInitialize interface to optimize
initialization on multiple properties. Property changes can only occur
during object initialization. Call BeginInit to signal that
initialization has begun and EndInit to signal that initialization has
completed. After initialization, property changes are ignored.
BitmapImage objects created using the BitmapImage constructor are
automatically initialized and property changes are ignored.
So, change your code to wrap property initialization like this:
BitmapImage bitmap = new BitmapImage();
string filename= "Cards/1-1.png";
bitmap.BeginInit();
bitmap.UriSource = new Uri("/Poker;component/" + filename, UriKind.Relative);
bitmap.EndInit();
cardImage1.Source= bitmap; // myImage linked with XAML
OR
Initialize all relevant properties at time of initialization by passing Uri in constructor like this:
string filename= "Cards/1-1.png";
BitmapImage bitmap = new BitmapImage(new Uri("/Poker;component/" + filename,
UriKind.Relative));
I tried this code but it isn't working, i found a way to do what you exactly need:
cardImage1.Source = new BitmapImage(new Uri("/Poker;component/" + filename, UriKind.Relative));
you assigned BitmapImage.Source to Image.Source, i think that's why it isn't working.
Hope it helps.

wpf - why dont images display in the listbox even there are values of the images in code

I need you to help me with a problem I am experiencing with. I have a single listbox that is supposed to display a Car Detials (right side) and Car Image (left side) after retrieving them from the database. Note: convert byte into images from database which is working fine. Problem is that the images dont display in the listbox (left side) but only Car Details displayed. Missing Images! I make sure Car and CarImage in WPF style to binding. No idea what I have done wrong in my code or wpf style. I would much aprreciate if you are willing to take a look at my codes what is problem. Your help much appreciated. Thanks!
WPF:
<ListBox Style="{DynamicResource ListBoxStyle1}" DisplayMemberPath="Car" X:Name="listboxCars" />
WPF Style - Car Information (right side) and Car Image (left side):
<DataTemplate x:Key="templateListBoxItem">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
Margin="0,0,10,0">
<!-- binding it to Car Image from database -->
<Image Source="{Binding Path=CarImage}"
Stretch="Fill"
Height="40"
Width="40"></Image>
</Border>
<!-- same here to binding to Car -->
<TextBlock Text="{Binding Path=Car}"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="0"></TextBlock>
</Grid>
</DataTemplate>
<Style x:Key="ListBoxStyle1" TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate" Value="{StaticResource ResourceKey=templateListBoxItem}"></Setter>
</Style>
This method to retrieve a list of Car Informations with its own Images from database
public List<CarInfo> GetCarImagesList (int days)
{
Cars = new List<CarInfo>();
const string sqlQuery = "select Car, CarImage from CarTemplates where Days = #days order by Car asc";
using (var command = new SqlCommand(sqlQuery, sqlConn))
{
try
{
command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("#days", days);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
byte[] buffer = new byte[10000];
var car = new CarInfo
{
Car = reader["Car"].ToString()
};
if (!reader.IsDBNull(reader.GetOrdinal("CarImage")))
{
long size = reader.GetBytes(reader.GetOrdinal("CarImage"), 0, buffer, 0, 10000);
using (MemoryStream strm = new MemoryStream())
{
strm.Write(buffer, 0, (int) size);
strm.Position = 0;
System.Drawing.Image img = System.Drawing.Image.FromStream(strm);
car.CarImage = img;
}
}
Cars.Add(car);
}
}
.
.
.
return Cars;
}
Last thing: when you click the button, the listbox will display CarInformation (right side) and CarImage (left side). In runtime I check that there is a list of CarInformations and CarImages in _databaseCarList. There is even value (byte) of Images (list.CarImage) but why dont images display?
private void Button1_Click(object sender, SelectionChangedEventArgs e)
{
_carImageList = new CarImageExtractor();
const int oneDay = 1;
var lstCar = new List<CarInfo>();
_databaseCarList = new ObservableCollection<CarInfo>(_carImageList.GetCarImagesList(oneDay));
if (_databaseCarList != null)
{
foreach (var list in _databaseCarList)
{
lstCar.Add(new CarInfo{Car = list.Car, CarImage = list.CarImage});
}
listboxCars.ItemsSource = lstCar;
}
}
You are using a WindowsForms image (System.Drawing.Image) that is not support by WPF as ImageSource for the Image. (When debugging in VisualStudio you should get binding errors from ImageSourceConverter)
For WPF you need to use BitmapImage.
Change your property CarImage to type System.Windows.Media.Imaging.BitmapImage and change the initialization code of your image to the following.
strm.Write(buffer, 0, (int) size);
strm.Position = 0;
BitmapImage img = new BitmapImage();
img.BeginInit();
img.StreamSource= strm;
img.EndInit();
car.CarImage = img;

Converted BitmapImage not displaying on Page

I am having a problem with my Windows Phone application. When I get the photo from a web service, I want to display it as an image on the page. The web service returns a byte[] as the image data.
Dispatcher.BeginInvoke(() =>
{
tempImage = new BitmapImage();
globalWrapper = (PhotoWrapper)JsonConvert.DeserializeObject(
response.Content, typeof(PhotoWrapper));
tempImage.SetSource(new MemoryStream(globalWrapper.PictureBinary, 0,
globalWrapper.PictureBinary.Length));
globalWrapper.ImageSource = tempImage;
PictureList.Items.Add(globalWrapper);
});
PictureList is a ListBox defined as:
<ListBox Name="PictureList" ItemsSource="{Binding}" Margin="0,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Click="details_Click">
<Button.Content>
<Image Source="{Binding ImageSource}"></Image>
</Button.Content>
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, my question is, how do you receive a byte[] from a webservice as JSON and display it on the page? I feel like I am pretty close here but am missing something rather elementary.
If you're certain that the byte[] data is valid, it could be something to do with the CacheOption property of the BitmapUmage. This property controls when data is actually loaded from the stream into the bitmap. The default is OnDemand, which only loads data from the stream when the image is displayed. You might want to try the OnLoad option instead, which loads it immediately, allowing you to close the stream.
Dispatcher.BeginInvoke(() =>
{
globalWrapper = (PhotoWrapper)JsonConvert.DeserializeObject(
response.Content, typeof(PhotoWrapper));
tempImage = new BitmapImage();
tempImage.BeginInit();
tempImage.CacheOption = BitmapCacheOption.OnLoad;
tempImage.SetSource(new MemoryStream(globalWrapper.PictureBinary, 0,
globalWrapper.PictureBinary.Length));
tempImage.EndInit();
globalWrapper.ImageSource = tempImage;
PictureList.Items.Add(globalWrapper);
});

Image from isolated storage

I am trying to bind an image that is saved in isolated storage and display it on the same screen as the camera, but I can't seem to get the image to display. I don't know if it because I am not saving it on the phones camera roll, but I am not saving them because I am gonna take multiple pictures and display them like a film strip across the bottom of the view finder for the camera. Can anyone help me please?
I am using this tutorial Here
public partial class Page1 : PhoneApplicationPage
{
private static ObservableCollection<PhotoImage> photoList = new ObservableCollection<PhotoImage>();//For the class and list
private int savedCounter = 0;
public Page1()
{
InitializeComponent();
}
private void ShutterButton_Click(object sender, RoutedEventArgs e)
{
if (cam != null)
{
try
{
// Start image capture.
cam.CaptureImage();
}
catch (Exception ex)
{
this.Dispatcher.BeginInvoke(delegate()
{
txtDebug.Text = ex.Message;
});
}
}
}
void cam_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e)
{
// Increments the savedCounter variable used for generating JPEG file names.
savedCounter++;
}
void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
{
string fileName = "MyImage" + savedCounter + ".jpg";
try
{
// Save picture to the library camera roll.
//library.SavePictureToCameraRoll(fileName, e.ImageStream);//dont want to save it to the camera roll
// Set the position of the stream back to start
e.ImageStream.Seek(0, SeekOrigin.Begin);
// Save picture as JPEG to isolated storage.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to isolated storage.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
photoList.Add(new PhotoImage(fileName));//here is where I set with the file name
listBoxSearch.ItemsSource = photoList; //here is the binding
});
}
finally
{
// Close image stream
e.ImageStream.Close();
}
}
public class PhotoImage
{
public string PhotoItem { get; set; }
public PhotoImage(string pItem)
{
this.PhotoItem = pItem;
}
}
here is my XAML code
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="640" />
<ColumnDefinition Width="160" />
</Grid.ColumnDefinitions>
<Canvas x:Name="viewfinderCanvas" Width="640" HorizontalAlignment="Left" Margin="0,0,0,143">
<!--Camera viewfinder -->
<Canvas.Background>
<VideoBrush x:Name="viewfinderBrush" />
</Canvas.Background>
<TextBlock Height="40" Name="txtDebug" Width="626" FontSize="24" FontWeight="ExtraBold" Canvas.Left="14" Canvas.Top="297" />
</Canvas>
<!--Button StackPanel to the right of viewfinder>-->
<StackPanel Grid.Column="1" >
<Button x:Name="ShutterButton" Content="SH" Click="ShutterButton_Click" FontSize="26" FontWeight="ExtraBold" Height="75" />
</StackPanel>
<Grid>
<ListBox Foreground="RoyalBlue" Height="131" Name="listBoxSearch" Width="438" TabIndex="10" Margin="96,343,106,6">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="Auto" >
<Image Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0" Source="{Binding PhotoItem }" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
Okay - the issue is that does not have an implicit converter that knows how to take an IsoStorage URI and load it.
One easy solution is to add another property to your PhotoImage class and bind to it instead - here's a quick and dirty:
public ImageSource SourceItem
{
get
{
BitmapImage image = new BitmapImage();
image.SetSource(isStore.OpenFile(PhotoItem, FileMode.Open));
return image;
}
}
Note that this is not a great solution - I am just showing you the general idea. Things to think about when implementing your own:
The stream is not being discarded. Wrap the Stream in a using when setting it into image.
Depending on what you are trying to do, you may want to use image.CreateOptions to make the app more responsive (but then you need to figure out how to handle the stream needing to be kept opened)
Finally, the image that will be loaded will be at full resolution. You may want to look into PictureDecoder.DecodeJpeg() to load a thumbnail of the image instead (or look at the thumbnail provided by the camera object)

Categories