load image from PC as stream - c#

I am trying to load a picture from my PC as a raw image in order to use it with the Microsoft cognitive services emotion (UWP).
below is a piece of my code:
//Chose Image from PC
private async void chosefile_Click(object sender, RoutedEventArgs e)
{
//Open Dialog
FileOpenPicker open = new FileOpenPicker();
open.ViewMode = PickerViewMode.Thumbnail;
open.SuggestedStartLocation = PickerLocationId.Desktop;
open.FileTypeFilter.Add(".jpg");
open.FileTypeFilter.Add(".jpeg");
open.FileTypeFilter.Add(".gif");
open.FileTypeFilter.Add(".png");
file = await open.PickSingleFileAsync();
if (file != null)
{//imagestream is declared as IRandomAccessStream.
imagestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var image = new BitmapImage();
image.SetSource(imagestream);
imageView.Source = image;
}
else
{
//
}
}
The part above works fine, it selects a photo from the pc (dialog box) and displays it in Image box.
private async void analyse_Click(object sender, RoutedEventArgs e)
{
try
{
emotionResult = await emotionServiceClient.RecognizeAsync(imagestream.AsStream());
}
catch
{
output.Text = "something is wrong in stream";
}
try {
if(emotionResult!= null)
{
Scores score = emotionResult[0].Scores;
output.Text = "Your emotions are: \n" +
"Happiness: " + score.Happiness + "\n" +
"Sadness: " + score.Sadness;
}
}
catch
{
output.Text = "Something went wrong";
}
}
I think the error is due to imagestream.AsStream()
imagestream is declared as IRandomAccessStream.
Can someone please tell me how to fix that part and if the error is in fact due to not loading the image correctly?
EDIT:
Also is there a better way to do this, instead of using stream to pass the emotionServiceClient a saved file instead of a stream?

Your problem is that you've advanced the stream position by virtue of creating the BitmapImage, so your read position is at the end by the time you call emotionServiceClient.RecognizeAsync. So you'll need to 'rewind':
var stream = imagestream.AsStreamForRead();
stream.Position = 0;
emotionResult = await emotionServiceClient.RecognizeAsync(stream);

Why not use their example, instead of trying to hold the file in memory, why don't you hold a path, and then use the path to read the stream at the time.
https://www.microsoft.com/cognitive-services/en-us/Emotion-api/documentation/GetStarted
In there example;
using (Stream imageFileStream = File.OpenRead(imageFilePath))
{
//
// Detect the emotions in the URL
//
emotionResult = await emotionServiceClient.RecognizeAsync(imageFileStream);
return emotionResult;
}
So you would be capturing imageFilePath as the result of the open file dialog.

Related

non-invocable member PictureBox.ImageLocation cannot be used like a method

I am working with the Windows Forms app. It connects to the Flikr website via free API key, searches images that I provide through the textBox and displays the names of the files that correspond to the keyword in the imagesListBox. When I click on the image name in the imagesListBox the image is displayed inside of the pictureBox. Now I am trying to save an image from the pictureBox and I get this error: "non-invocable member PictureBox.ImageLocation cannot be used like a method". Is there another method similar to ImageLocation which I can use to retrieve the image url address? Here is my code for the button which is supposed to save the image:
private void btnSave_Click(object sender, EventArgs e)
{
//method of saving image
try
{
if (pictureBox.Image != null)
{
//5
string filePath = PictureBox.ImageLocation();
string fileName = Path.GetFileName(filePath);
File.Copy(pictureBox.Text, Path.Combine(#"C:\", Path.GetFileName(pictureBox.Text)), true);
MessageBox.Show("The image has been saved to C drive.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
Searching and uploading images from Flikr:
private async void searchButton_Click(object sender, EventArgs e)
{
// if flickrTask already running, prompt user
if (flickrTask?.Status != TaskStatus.RanToCompletion)
{
var result = MessageBox.Show(
"Cancel the current Flickr search?",
"Are you sure?", MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
// determine whether user wants to cancel prior search
if (result == DialogResult.No)
{
return;
}
else
{
flickrClient.CancelPendingRequests(); // cancel search
}
}
// Flickr's web service URL for searches
var flickrURL = "https://api.flickr.com/services/rest/?method=" +
$"flickr.photos.search&api_key={KEY}&" +
$"tags={inputTextBox.Text.Replace(" ", ",")}" +
"&tag_mode=all&per_page=500&privacy_filter=1";
imagesListBox.DataSource = null; // remove prior data source
imagesListBox.Items.Clear(); // clear imagesListBox
pictureBox.Image = null; // clear pictureBox
imagesListBox.Items.Add("Loading..."); // display Loading...
// invoke Flickr web service to search Flick with user's tags
flickrTask = flickrClient.GetStringAsync(flickrURL);
// await flickrTask then parse results with XDocument and LINQ
XDocument flickrXML = XDocument.Parse(await flickrTask);
// gather information on all photos
var flickrPhotos =
from photo in flickrXML.Descendants("photo")
let id = photo.Attribute("id").Value
let title = photo.Attribute("title").Value
let secret = photo.Attribute("secret").Value
let server = photo.Attribute("server").Value
let farm = photo.Attribute("farm").Value
select new FlickrResult
{
Title = title,
URL = $"https://farm{farm}.staticflickr.com/" +
$"{server}/{id}_{secret}.jpg"
};
// clear imagesListBox
imagesListBox.Items.Clear();
// set ListBox properties only if results were found
if (flickrPhotos.Any())
{
imagesListBox.DataSource = flickrPhotos.ToList();
imagesListBox.DisplayMember = "Title";
}
else // no matches were found
{
imagesListBox.Items.Add("No matches");
}
}
Since it has been asked how I get images inside the pictureBox:
// display selected image
private async void imagesListBox_SelectedIndexChanged(
object sender, EventArgs e)
{
if (imagesListBox.SelectedItem != null)
{
string selectedURL = ((FlickrResult)imagesListBox.SelectedItem).URL;
// use HttpClient to get selected image's bytes asynchronously
byte[] imageBytes = await flickrClient.GetByteArrayAsync(selectedURL);
// display downloaded image in pictureBox
using (var memoryStream = new MemoryStream(imageBytes))
{
pictureBox.Image = Image.FromStream(memoryStream);
}
}
}
Change the line to the following. ImageLocation is a property, not a method.
string filePath = pictureBox.ImageLocation;

Sending a raw image to my database (parse), how should I send it?

Getting closer to solve my problem, one step at a time. I now have a raw image data and the last step is to send it to my database and in this case I use Parse. This is the code so far:
The viewmodel with the Selectpicture function and how I get the image raw (works):
public async Task SelectPicture()
{
Setup ();
ImageSource = null;
try
{
var mediaFile = await _Mediapicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
VideoInfo = mediaFile.Path;
ImageSource = ImageSource.FromStream(() => mediaFile.Source);
imageData = ReadStream(mediaFile.Source);
}
catch (System.Exception ex)
{
Status = ex.Message;
}
}
The page where I try to send the picture to my database and where the user can see the picture they selected, this is where I am stuck:
private async void btnPickPicture_Clicked (object sender, EventArgs e)
{
await MyViewModel.SelectPicture ();
imgPicked.Source = MyViewModel.ImageSource; //my image x:name in xaml
System.Diagnostics.Debug.WriteLine (imgPicked.Source);
}
//Below I send it to my parse and in parse they save it as a "File". This is the part where I am not sure how to get it right. I have to pass it as a byte but Iam not sure how to execute it.
async void SendDataClick (object sender, EventArgs args)
{
var createResult = await parseAPI.createInfo
( MyViewModel.ImageData );
}
Code to parse:
static public async Task<bool> createInfo (byte [] thePicture)
use ParseFile for saving images and binary data
// pass the ImageData from your VM into the constructor
ParseFile file = new ParseFile("image.jpg", MyViewModel.ImageData);
// save the file
file.SaveAsync();

Delete an image being used by another process

I am writing a winform application in C# to open an image and overlay another image on top of it.
The bottom image is a .jpg and the top one is a .bmp converted from .svg. The .jpg and the .svg are the only ones I want to keep in the folder. The .bmp works as a temp.
I was using the following code to overlay the images. But I am having trouble to delete the temp .bmp as it is used by another process. I think it is this combine code still have access to the last .bmp file.
Could anyone help me on this? Thanks.
private void buttonSearch_Click(object sender, EventArgs e)
{
FailInfo.Text = "";
deletebmp(strFolderPath);
...
// Check if the specified front image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathF))
{
labelFront.Text = strFileNameF;
var svgConvert = SvgDocument.Open(svgFilePathF);
svgConvert.Draw().Save(bmpFilePathF);
pictureBoxFront.Image = Image.FromFile(strFilePathF);
}
else
{
labelFront.Text = "Couldn't find the file!";
pictureBoxFront.Image = null;
}
// Check if the specified back image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathBF))
{
labelBack.Text = strFileNameBF;
strFilePathB = strFilePathBF;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "FAIL";
labelResult.BackColor = Color.FromArgb(255, 0, 0);
var svgConvert = SvgDocument.Open(svgFilePathBF);
bmpFilePathB = strFolderPath + strFileNameBF + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBF;
inspectionres(svgFilePathB);
labelreason.Visible = true;
}
else if (File.Exists(strFilePathBP))
{
labelBack.Text = strFileNameBP;
strFilePathB = strFilePathBP;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "PASS";
labelResult.BackColor = Color.FromArgb(0, 255, 0);
var svgConvert = SvgDocument.Open(svgFilePathBP);
bmpFilePathB = strFolderPath + strFileNameBP + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBP;
inspectionres(svgFilePathB);
labelreason.Visible = false;
}
else
{
labelBack.Text = "Couldn't find the file!";
pictureBoxBack.Image = null;
labelResult.Text = "ERROR";
labelResult.BackColor = Color.FromArgb(0, 255, 255);
labelreason.Visible = false;
}
}
//
// Overlay the SVG file on top of the JPEG file
//
private Bitmap Combine(string jpegFile, string bmpFile)
{
Image image1 = Image.FromFile(jpegFile);
Image image2 = Image.FromFile(bmpFile);
Bitmap temp = new Bitmap(image1.Width, image1.Height);
using (Graphics g = Graphics.FromImage(temp))
{
g.DrawImageUnscaled(image1, 0, 0);
g.DrawImageUnscaled(image2, 0, 0);
}
return temp;
}
//
// Show the overlaid graphic in the picturebox
//
private void checkBoxOverlay_CheckedChanged(object sender, EventArgs e)
{
try
{
if (FindFront)
if (checkBoxOverlay.Checked)
pictureBoxFront.Image = Combine(strFilePathF, bmpFilePathF);
else
pictureBoxFront.Image = Image.FromFile(strFilePathF);
else
pictureBoxFront.Image = null;
if (FindBack)
if (checkBoxOverlay.Checked)
pictureBoxBack.Image = Combine(strFilePathB, bmpFilePathB);
else
pictureBoxBack.Image = Image.FromFile(strFilePathB);
else
pictureBoxBack.Image = null;
}
catch (Exception ex)
{
MessageBox.Show("Error loading image" + ex.Message);
}
}
//
// Option of changing the image folder
//
private void buttonPath_Click(object sender, EventArgs e)
{
FolderBrowserDialog FolderBrowserDialog1 = new FolderBrowserDialog();
if (FolderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
strFolderPath = FolderBrowserDialog1.SelectedPath + "\\";
}
}
//
// Pull the inspection result info from the SVG file
//
private void inspectionres(string filename)
{
XDocument document = XDocument.Load(filename);
XElement svg_Element = document.Root;
string sb = null;
var faillist = (from svg_path in svg_Element.Descendants("{http://www.w3.org/2000/svg}text") select svg_path).ToList();
foreach (var item in faillist)
{
sb += item.ToString();
}
}
//
// Delete all the .bmp files generated from .svg files
//
private void deletebmp(string path)
{
// Unload the images from the picturebox if applicable
pictureBoxFront.Image = null;
pictureBoxBack.Image = null;
string[] files = Directory.GetFiles(path, "*.bmp");
for (int i = 0; i < files.Length; i ++ )
File.Delete(files[i]);
}
}
Image implements IDisposable, so simply setting the pictureBox.Image property to null will not release resources (in your case, the file). Your Combine method also leaves the images open. You have to call Dispose before attempting to delete the file:
Image image1 = Image.FromFile(path1);
File.Delete(path1); // error - file is locked
Image image2 = Image.FromFile(path2);
image2.Dispose();
File.Delete(path2); // works
An alternative approach (and I assume you're using WinForms here, in WPF it's a little different) would be to load the bitmap from the file manually (using FromStream). Then, you can close the stream immediately and delete the file:
Image image;
using (Stream stream = File.OpenRead(path))
{
image = System.Drawing.Image.FromStream(stream);
}
pictureBox.Image = image;
File.Delete("e:\\temp\\copy1.png"); //works
Vesan's answer didn't helped me so I found an different solution.
So I can safe/open an image and if I want instantly delete the image.
i used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
All above answers are perfectly fine, but I've got a different approach.
Using Image abstract class, you will not get quite a lot of options for manipulating and resizing image.
Rather you do as follows:-
Bitmap img = new Bitmap(item);
img.SetResolution(100, 100);
Image imgNew = Image.FromHbitmap(img.GetHbitmap());
pictureBox1.Image = imgNew;
img.Dispose();

File Save Picker - Save Edited Image (C# Metro app)

I want to open an image, edit it, and then save it. I am able to open a file, but I have problems saving it. The way I have written the code, I can only save a file with .jpg but there is nothing in it.
Please explain to me how to save the image I have opened and edited(not made yet).
public sealed partial class MainPage : Page
{
BitmapImage originalImage = new BitmapImage();
public MainPage()
{
this.InitializeComponent();
}
private async void OpenButton_Click(object sender, RoutedEventArgs e)
{
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".gif");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.SettingsIdentifier = "PicturePicker";
filePicker.CommitButtonText = "Select File";
StorageFile selectedFile = await filePicker.PickSingleFileAsync();
var stream = await selectedFile.OpenAsync(FileAccessMode.Read);
if (selectedFile != null)
{
originalImage.SetSource(stream);
pictureBox.Source = originalImage;
}
}
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("jpeg image", new List<string>() { ".jpg" });
savePicker.SuggestedFileName = "EditedImage";
StorageFile file = await savePicker.PickSaveFileAsync();
}
}
After creating an Images file you need to Update it see FileSavePicker class.
Add the following code in your SaveButton_Click method and try modify it.
This will let you update your created file into real image file.
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
if (status == FileUpdateStatus.Complete)
{
OutputTextBlock.Text = "File " + file.Name + " was saved.";
}
else
{
OutputTextBlock.Text = "File " + file.Name + " couldn't be saved.";
}
}
else
{
OutputTextBlock.Text = "Operation cancelled.";
}

Error in async method

In WinRT app I have one FlipView myFlipView with some pictures and one Image myImage. On myFlipView's event SelectionChanged there is the following method:
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
To sum up it finds uri of current image in myFlipView and set that image in myImage but with some modifications defined in ModifyPicture. It works perfectly on tablets but on computers with mouses there is one error. When I click arrows attached to FlipView very fast then myImage shows wrong picture. For example if in myFlipView I have 10 pictures (p1, p2, ..., p10) and currently p1 is chosen, when I change to p2 on myImage also p2 appears. But when I click very fast sometimes in FlipView I have for example p9 and in myImage p8. I suppose it is connected with fact that method is called many times but I don't know how to fix it. Thank you in advance for help :)
You should probably save the Task/IAsyncOperation that's already running and cancel it if the event handler is called again before it completes.
See this article on how to cancel running tasks.
Pseudo-code (as I don't know C#):
Task loadAndSetImage(uri) {
return new Task...
}
flipView_SelectionChanged {
if (myFlipView == null) return;
if (this.runningTask && !this.runningTask.IsCanceled) {
this.runningTask.Cancel();
}
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
this.runningTask = loadAndSetImage(newUri);
this.runningTask.ContinueWith( (t) => this.runningTask = null; );
}
In addition to or instead of cancelling internal tasks as ma_il mentions - you could break/cancel your async method execution if you detect that it should be canceled. E.g.
private int myFlipView_SelectionChangedCallId;
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
var callId = ++myFlipView_SelectionChangedCallId;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
if (callId != myFlipView_SelectionChangedCallId) return;
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
if (callId != myFlipView_SelectionChangedCallId) return;
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
Also if your ModifyPicture method does any heavy pixel processing - you would want to run it on a background thread and await it.

Categories

Resources