My C# program needs to display, of many possible images, one at a time. The images are on the web and I have a precise URL for each one. The program needs to either load the image from the web or, if it has been loaded previously, load it from memory/file (as the previous loading from the web should have saved it to memory/file). How do I implement this? I can get the loading from the web with a WebRequest object, but that's not enough to save it for later, faster, use.
WebRequest request = WebRequest.Create(imageURL);
Stream stream = request.GetResponse().GetResponseStream();
pictureBoxFirstPack.Image = Image.FromStream(stream);
I'm pretty sure you should be able to do this:
MemoryStream ms = new MemoryStream();
stream.CopyTo(ms);
Byte[] data = ms.ToArray();
Once you have it as a Byte array you can store it in a dictionary, a database, or wherever you like really.
Use the Image.Save method to save the downloaded image (follow an example from MSDN: http://msdn.microsoft.com/en-us/library/9t4syfhh.aspx)
// Construct a bitmap from the button image resource.
Bitmap bmp1 = new Bitmap(typeof(Button), "Button.bmp");
// Save the image as a GIF.
bmp1.Save("c:\\button.gif", System.Drawing.Imaging.ImageFormat.Gif);
One of the possible ways to check if the image already exists in your local storage is to calculate the hash-sum of every downloaded image and save it inside a dictionary
SHA256Managed sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
var hash = BitConverter.ToString(checksum).Replace("-", String.Empty);
// Store hash into a dictionary
You can use the WebClient to download file like this:
string fileNameLocally = #"c:\file.jpg";
using(WebClient client = new WebClient())
{
client.DownloadFile(imageURL, fileNameLocally);
//you can also use DownloadAsyncFile this methods do not block the calling thread.
}
Related
I've got a bunch of images stored on disk, with the mimetype of the image stored in a database. If I want to save the image to disk I can use Image.Save(string) (or the Async version) without needing to know the MimeType of the image.
However, if I want to save to a stream (for example, Response.Body) then I have to use Image.Save(Stream, IImageEncoder).
How do I get the IImageEncoder I need to save to the stream (without just declaring that "All my images ar png/jpeg/bmp" and using e.g. JpegEncoder)?
ImageSharp can already tell you the mimetype of the input image. With your code if the
mimetype doesn't match the input stream then the decode will fail.
(Image Image, IImageFormat Format) imf = await Image.LoadWithFormatAsync(file.OnDiskFilename);
using Image img = imf.Image;
img.Save(Response.Body, imf.Format);
What we are missing however in the current API v1.0.1 is the ability to save asynchronously while passing the format. We need to add that.
It took a bit of messing about, but I've figured it out:
var file = ... // From DB
ImageFormatManager ifm = Configuration.Default.ImageFormatsManager;
IImageFormat format = ifm.FindFormatByMimeType(file.MimeType);
IImageDecoder decoder = ifm.FindDecoder(format);
IImageEncoder encoder = ifm.FindEncoder(format);
using Image img = await Image.LoadAsync(file.OnDiskFilename, decoder);
// Do what you want with the Image, e.g.: img.Mutate(i => i.Resize(width.Value, height.Value));
Response.ContentType = format.DefaultMimeType; // In case the stored mimetype was something weird
await img.SaveAsync(Response.Body, encoder);
(Although I'm happy to be shown a better way)
I am working on Universal Windows Applications, in my current project I used Unified Communications Web API (UCWA) to display the skype user status it's working fine but when I am trying to display the skype user photo at that time I got stuck.
I followed below link to display the photo
https://msdn.microsoft.com/en-us/skype/ucwa/getmyphoto
I got response code of 200 OK for my GET request but I don't know how to display the image from my response.
Please tell me how to resolve it.
-Pradeep
I got Result, After getting HTTP Response then I am converting those response content to stream type by using this below line.
var presenceJsonStr = await httpResponseMessage.Content.ReadAsStreamAsync();
This is the code to display the image
var photo = await AuthenticationHelper.Photo();
// Create a .NET memory stream.
var memStream = new MemoryStream();
// Convert the stream to the memory stream, because a memory stream supports seeking.
await photo.CopyToAsync(memStream);
// Set the start position.
memStream.Position = 0;
// Create a new bitmap image.
var bitmap = new BitmapImage();
// Set the bitmap source to the stream, which is converted to a IRandomAccessStream.
bitmap.SetSource(memStream.AsRandomAccessStream());
// Set the image control source to the bitmap.
imagePreivew.ImageSource = bitmap;
Assuming you put an Accept header specifying an image type, you should be able to look at the Content-Length header to determine if the user has an image set on the server. If the length is zero you should consider providing a default image to be displayed. If not, I would suggest taking a look at Convert a Bitmapimage into a Byte Array and Vice Versa in UWP Platform as you should treat the response body as a byte array with its length defined by the Content-Length header.
If for some reason no Accept header was provided, the response body is not an image/* type, and looks like a string then you might be dealing with a Base64 encoded image. This case should be much less likely to deal with, but if you need advice I would suggest looking at Reading and Writing Base64 in the Windows Runtime.
You can directly use the URL generated for the user photo resource. Just set the URL of the image as the source of the Image container. You application would load it automatically.
I have a Windows Form program that will generate HTML code dynamically and a WebBrowser will display the generated code.
Is it the only way, to save a temp HTML file, then display it in thw WebBrowser? Is there a way that I don't need to save and display instantly in the WebBrowser?
Yes. You can use the WebBrowser.DocumentStream property like this:
var myHTMLString = "<html><body><h1>Hello!</h1></body></html>";
// Convert your html string into a byte array
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(myHTMLString);
// Create a MemoryStream from the byte array
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes);
// Assign the new MemoryStream to the web browser
myWebBrowser.DocumentStream = ms;
Hope it helps!
I'm very new to this stuff of saving images to the DB, and even when I thought it was very straight forward, it wasn't. What I'm trying to do is read and image file from the same computer in any format, display it in a picture box, and then convert the image to bytes to save it in the DB. Until now, I can display the image in the picture box, but I can't convert the image to bytes. Here's my code:
private void DisplayImage()
{
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
try
{
Stream file;
if ((archivo = openFileDialog.OpenFile()) != null)
{
using (file)
{
pictureBox.Image = Image.FromStream(file);
}
}
}
catch (Exception ex)
{
...
}
}
}
That's a simple method that just displays the image in the picture box. The real problem is with the following method:
public static byte[] ConvertImageToBytes(Image image)
{
if (image != null)
{
MemoryStream ms = new MemoryStream();
using (ms)
{
image.Save(ms, ImageFormat.Bmp);
byte[] bytes = ms.ToArray();
return bytes;
}
}
else
{
return null;
}
}
When it tries to save the image to the memory stream, I get the error:
System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
Any ideas on what's happening?
You should use the RawFormat property of the original image as a parameter to the Save method, not default to a Bitmap. This will avoid image format type errors. eg:
image.Save(ms, image.RawFormat);
ms.Position = 0;
byte [] bytes=ms.ToArray();
I'd advise actually saving images to the file-system and simply storing the file path (preferably relative) in the database.
BLOBs (ie images etc) in a database cannot be indexed, are often stored in a secondary, slower access database area and will quickly blow out the size of the database (slower backups etc).
Cant you simply Read the file and load it to a byte[] using the File class:
byte[] imgData = System.IO.File.ReadAllBytes(#"C:\My Pic\Myfile.jpg");
You can pick the image path from your Open Dialog box.
That particular exception generally means that you are trying to save the image as the wrong format. In your code you specify ImageFormat.Bmp - is it actually a bitmap image, or did you perhaps load it from a JPEG or PNG? Attempting to save as a different format from the one you loaded will fail with ExternalException, as specified in the documentation.
Incidentally, I don't recommend storing images in a database and I believe most people here will agree. Databases may be able to handle this task but they are not optimized for it, and you end up hurting the performance of both your database and your application. Unless you are using SQL Server 2008 FILESTREAM columns, it is more efficient to store images on the file system.
It may be stupid to answer my own question, but I just found out that if I want to convert the Image object to bytes, I have to leave the original stream open. I saw this issue in another page I can't quite remember, and I tested it by leaving the stream open and it's true. So the format wasn't the problem. But I will take the advice of all of you and store the images in a separate directory. Thanks for your help guys!
The problem with this is that stream must be open during the lifetime of of the image otherwise will fail.
One solution that worked for me is just to create a copy of the image like this:
using (var ms = new MemoryStream(bytes))
{
_image = new Bitmap(Image.FromStream(ms));
}
I am using this C# code to access an image file in order to read metadata from it.
BitmapSource img = BitmapFrame.Create(uri);
Unfortunately the image file specified by uri becomes locked until the program ends. How do I prevent the image from being locked?
maybe this could help ?
edit
BitmapSource img = BitmapFrame.Create(uri,BitmapCreateOptions.None,BitmapCacheOption.OnLoad);
BitmapCreateOptions.None = default option
BitmapCacheOption.OnLoad = Caches the entire image into memory at load time. All requests for image data are filled from the memory store.
from here
If you want to be able to delete/change the file immediately afterwards, read the whole file into memory, and then give it the MemoryStream instead. For example:
MemoryStream data = new MemoryStream(File.ReadAllBytes(file));
BitmapSource bitmap = BitmapFrame.Create(data);
You can also use generic stream:
Stream stream = File.OpenRead(filename);
Bitmap template = new Bitmap(stream); // or (Bitmap) Bitmap.FromStream(stream)
stream.Close();