How to download image from URL - c#

Is there a way to download an image directly from a url in c# if the url does not have an image format at the end of the link? Example of URL:
https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d969d392b63b27ec4f4b24a
I know how to download the image when the url ends with an image format. Eg:
http://img1.wikia.nocookie.net/__cb20101219155130/uncyclopedia/images/7/70/Facebooklogin.png

Simply
You can use following methods.
using (WebClient client = new WebClient())
{
client.DownloadFile(new Uri(url), #"c:\temp\image35.png");
// OR
client.DownloadFileAsync(new Uri(url), #"c:\temp\image35.png");
}
These methods are almost same as DownloadString(..) and DownloadStringAsync(...). They store the file in Directory rather than in C# string and no need of Format extension in URi
If You don't know the Format(.png, .jpeg etc) of Image
public void SaveImage(string imageUrl, string filename, ImageFormat format)
{
WebClient client = new WebClient();
Stream stream = client.OpenRead(imageUrl);
Bitmap bitmap; bitmap = new Bitmap(stream);
if (bitmap != null)
{
bitmap.Save(filename, format);
}
stream.Flush();
stream.Close();
client.Dispose();
}
Using it
try
{
SaveImage("--- Any Image URL---", "--- Any Image Path ---", ImageFormat.Png)
}
catch(ExternalException)
{
// Something is wrong with Format -- Maybe required Format is not
// applicable here
}
catch(ArgumentNullException)
{
// Something wrong with Stream
}

Depending whether or not you know the image format, here are ways you can do it :
Download Image to a file, knowing the image format
using (WebClient webClient = new WebClient())
{
webClient.DownloadFile("http://yoururl.com/image.png", "image.png") ;
}
Download Image to a file without knowing the image format
You can use Image.FromStream to load any kind of usual bitmaps (jpg, png, bmp, gif, ... ), it will detect automaticaly the file type and you don't even need to check the url extension (which is not a very good practice). E.g:
using (WebClient webClient = new WebClient())
{
byte [] data = webClient.DownloadData("https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d9");
using (MemoryStream mem = new MemoryStream(data))
{
using (var yourImage = Image.FromStream(mem))
{
// If you want it as Png
yourImage.Save("path_to_your_file.png", ImageFormat.Png) ;
// If you want it as Jpeg
yourImage.Save("path_to_your_file.jpg", ImageFormat.Jpeg) ;
}
}
}
Note : ArgumentException may be thrown by Image.FromStream if the downloaded content is not a known image type.
Check this reference on MSDN to find all format available.
Here are reference to WebClient and Bitmap.

.NET has changed a bit over the years, making the other answers on this post pretty dated:
They use Image from System.Drawing (which is not available for .NET Core) to find the image format
They use System.Net.WebClient which is deprecated
We don't recommend that you use the WebClient class for new development. Instead, use the System.Net.Http.HttpClient class.
.NET Core asynchronous solution
Getting the file extension
The first part of getting the file extension is to remove all the unnecessary parts from the URL.
We can use Uri.GetLeftPart() with UriPartial.Path to get everything from the Scheme up to the Path.
In other words, https://www.example.com/image.png?query&with.dots becomes https://www.example.com/image.png.
After that, we can use Path.GetExtension() to get only the extension (in my previous example, .png).
var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
var fileExtension = Path.GetExtension(uriWithoutQuery);
Downloading the image
From here it should be straight forward. Download the image with HttpClient.GetByteArrayAsync, create the path, ensure the directory exists and then write the bytes to the path with File.WriteAllBytesAsync()
private async Task DownloadImageAsync(string directoryPath, string fileName, Uri uri)
{
using var httpClient = new HttpClient();
// Get the file extension
var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
var fileExtension = Path.GetExtension(uriWithoutQuery);
// Create file path and ensure directory exists
var path = Path.Combine(directoryPath, $"{fileName}{fileExtension}");
Directory.CreateDirectory(directoryPath);
// Download the image and write to the file
var imageBytes = await httpClient.GetByteArrayAsync(uri);
await File.WriteAllBytesAsync(path, imageBytes);
}
Note that you need the following using directives.
using System;
using System.IO;
using System.Threading.Tasks;
using System.Net.Http;
Example usage
var folder = "images";
var fileName = "test";
var url = "https://cdn.discordapp.com/attachments/458291463663386646/592779619212460054/Screenshot_20190624-201411.jpg?query&with.dots";
await DownloadImageAsync(folder, fileName, new Uri(url));
Notes
It's bad practice to create a new HttpClient for every method call. It is supposed to be reused throughout the application. I wrote a short example of an ImageDownloader(50 lines) with more documentation that correctly reuses the HttpClient and properly disposes of it that you can find here.

For anyone who wants to download an image WITHOUT saving it to a file:
Image DownloadImage(string fromUrl)
{
using (System.Net.WebClient webClient = new System.Net.WebClient())
{
using (Stream stream = webClient.OpenRead(fromUrl))
{
return Image.FromStream(stream);
}
}
}

.net Framework allows PictureBox Control to Load Images from url
and Save image in Laod Complete Event
protected void LoadImage() {
pictureBox1.ImageLocation = "PROXY_URL;}
void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
pictureBox1.Image.Save(destination); }

Most of the posts that I found will timeout after a second iteration. Particularly if you are looping through a bunch if images as I have been. So to improve the suggestions above here is the entire method:
public System.Drawing.Image DownloadImage(string imageUrl)
{
System.Drawing.Image image = null;
try
{
System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
webRequest.AllowWriteStreamBuffering = true;
webRequest.Timeout = 30000;
webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
webRequest.ServicePoint.MaxIdleTime = 5000;
using (System.Net.WebResponse webResponse = webRequest.GetResponse())
{
using (System.IO.Stream stream = webResponse.GetResponseStream())
{
image = System.Drawing.Image.FromStream(stream);
}
}
webRequest.ServicePoint.CloseConnectionGroup(webRequest.ConnectionGroupName);
webRequest = null;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
return image;
}

This method did it for me,
I got the main code from here
then using this fix
I was able to make a method that could get around the dreaded forbidden 403 error
Here is the method
private static void DownloadImage(string url, string saveFilename)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// we need the user agent and default credentials if not,
// we get a forbidden request 303 error, which pretty much means the server thinks we are a bot -- which we are.... hehehehehehe
httpWebRequest.UserAgent = "Case Banana"; // note -- this string can be anything you like, I recommend making it atleast 10 characters
httpWebRequest.UseDefaultCredentials = true;
var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
if ((httpWebResponse.StatusCode != HttpStatusCode.OK &&
httpWebResponse.StatusCode != HttpStatusCode.Moved &&
httpWebResponse.StatusCode != HttpStatusCode.Redirect)
|| !httpWebResponse.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase))
{
return;
}
using (var stream = httpWebResponse.GetResponseStream())
{
using (var fileStream = File.OpenWrite(saveFilename))
{
var bytes = new byte[4096];
var read = 0;
do
{
if (stream == null)
{
continue;
}
read = stream.Read(bytes, 0, bytes.Length);
fileStream.Write(bytes, 0, read);
} while (read != 0);
}
}
}

Everyone has given a great solution for this problem but theere is a main issue behind all solutions given by everyone and that it will not create SSL/TLS secure channel if the image is hosted on https So, what should we do then? Answer is simple just add these 2 lines before creating a WebClient request
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Try this it worked for me
Write this in your Controller
public class DemoController: Controller
public async Task<FileStreamResult> GetLogoImage(string logoimage)
{
string str = "" ;
var filePath = Server.MapPath("~/App_Data/" + SubfolderName);//If subfolder exist otherwise leave.
// DirectoryInfo dir = new DirectoryInfo(filePath);
string[] filePaths = Directory.GetFiles(#filePath, "*.*");
foreach (var fileTemp in filePaths)
{
str= fileTemp.ToString();
}
return File(new MemoryStream(System.IO.File.ReadAllBytes(str)), System.Web.MimeMapping.GetMimeMapping(str), Path.GetFileName(str));
}
Here is my view
<div>Download Logo</div>

Related

How Can I get the real name of an image from a url

I have the next url about an image:
https://i.discogs.com/HE17wcv1sG6NDK1WcVyoQjSqUGDZva3SYvm6vXoCMOo/rs:fit/g:sm/q:90/h:600/w:600/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk2OTY5/NjktMTQ4NDkzNzkw/Ni00MDcyLmpwZWc.jpeg
If I open the url with the navigator and then I press de right button to save this image in my hard disc the name solved by the navigator for this file image is distinct.
How can i get the last name of the file in c#?
If you're set on using WebClient then you can download the data into memory, check for the Content-Disposition header, and then change the filename accordingly. I've added commented out parts that you can use instead of their synchronous counterparts if you're using this method asynchronously.
// private static async Task DownloadImageAsync(string url, string folder)
private static void DownloadImage(string url, string folder)
{
var uri = new Uri(url);
string fileName = Path.GetFileName(uri.AbsolutePath);
WebClient client = new WebClient();
// byte[] fileData = await client.DownloadDataTaskAsync(url);
byte[] fileData = client.DownloadData(url);
string disposition = client.ResponseHeaders.Get("Content-Disposition"); // try to get the disposition
if (!string.IsNullOrEmpty(disposition) // check it has a value
&& ContentDispositionHeaderValue.TryParse(disposition, out var parsedDisposition) // check it can be parsed
&& !string.IsNullOrEmpty(parsedDisposition.FileName)) // check a filename is specified
{
fileName = parsedDisposition.FileName.Trim('"'); // replace the normal filename with the parsed one
}
// await File.WriteAllBytesAsync(Path.Combine(folder, fileName), fileData);
File.WriteAllBytes(Path.Combine(folder, fileName), fileData);
}
Usage: DownloadImage(myurl, #"C:\Users\Me\Desktop");
That said, WebClient is a bit old-fashioned and you should probably use HttpClient for newer developments:
private static async Task DownloadImageAsync(string url, string folder)
{
var uri = new Uri(url);
string fileName = Path.GetFileName(uri.AbsolutePath);
using var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
if (!string.IsNullOrEmpty(response.Content.Headers.ContentDisposition?.FileName))
{
fileName = response.Content.Headers.ContentDisposition.FileName.Trim('"');
}
using var outputFile = File.Create(Path.Combine(folder, fileName));
await response.Content.CopyToAsync(outputFile);
}
Usage: await DownloadImageAsync(myurl, #"C:\Users\Me\Desktop");
Microsoft recommend using a single static instance of HttpClient throughout your application (docs). This does have pitfalls though, so depending on your application, you might want to look into using IHttpClientFactory, which works to solve the issues that come from using a static HttpClient.

How to close an access made by unknown proccess to a file through WPF, C#?

I'm trying to access a file with my WPF project and I get an exception saying it couldn't access the file because another process is using it.
I don't see any reason because the only process which used it was syncronized and it should close the file after it used it. I tried the "client.Dispose();" below, but it didn't help.
Any advice may be a help! Thanks.
I'm trying to access "currentQr" file in local url. Here's my code:
private void BtnScanQR(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
currentQr= System.IO.Path.GetFullPath(openFileDialog.FileName).Replace(#"\\", #"\");
if (!bL.IsQRExist(currentQr))
{
/////// some code
}
}
}
It calls "bL.IsQRExist(currentQr)" which calls "dal" :
public bool IsQRExist(string currentQr)
{
return Dal.IsQRExist(currentQr);
}
Here's my Dal.IsQRExist function, Which calls directly to "DecodeQR" function:
public bool IsQRExist(string currentQr)
{
Product p = Tools.ConvertQRToProduct(currentQr);
if (GetProductID(p) == -1)
return false;
return true; }
And in "Tools.DecodeQR" there's the Actual access to the file:
public static string DecodeQR(string downloadUrl) //'unzip' qrCode from url and interperts its meaning
{
string imageUrl = downloadUrl;
// Install-Package ZXing.Net -Version 0.16.5
var client = new WebClient();
var stream = client.OpenRead(imageUrl);
if (stream == null) return "";
var bitmap = new Bitmap(stream);
IBarcodeReader reader = new BarcodeReader();
var result = reader.Decode(bitmap);
client.Dispose();
return result.Text;
}
After this only access to the file, I'm trying to access the file again in another proccess but it says that another proccess (must be this one i descibed here, cause when i cancled this it didn't throw the exception).
So how can I make sure the file isn't being accessed anymore after this code above?
And I also thinks maybe is there a way to close all accesses to a file, whether they were made in this code or any other code.
Thanks
Since Bitmap is an IDisposable, you have to make sure that you properly dispose of it after usage, which is usually done by creating it in a using statement.
In addition, when you load a Bitmap from a local file, you would not have to deal with Streams at all.
This should be sufficient:
public static string DecodeQR(string imageFilePath)
{
using (var bitmap = new Bitmap(imageFilePath))
{
return new BarcodeReader().Decode(bitmap).Text;
}
}
I think the file handle, that isn't closed, is held by the variable stream which receives the file opened by WebClient.OpenRead. You will need to dispose the stream resource as well.
With a using block it's disposed automatically when the block is exited - where using guarantees to invoke Dispose even in case of exceptions thrown inside the using block. Which is quite good, when you want to open that same file later again.
Also I think you don't need a WebClient if you deal with a local file. Just opening that file as a FileStream seems more straight forward.
using System.IO;
...
public static string DecodeQR(string localImageFile)
{
using (var stream = new FileStream(localImageFile,
FileMode.Open, FileMode.Read))
{
if (stream == null) return "";
var bitmap = new Bitmap(stream);
// Install-Package ZXing.Net -Version 0.16.5
var reader = new BarcodeReader();
var result = reader.Decode(bitmap);
return result.Text;
}
}

DevOps description field image download / Save file

Since we have moved to Dev Ops my application fails to download the images that are in any field stored in a work item.
I have an image URL that has already been stripped out of the description files via a regular expression.
If I take this link and paste it in to a browser then it returns the images (so the url is valid)
The issue is that within the call to download the image we dont have any authentication credentials and its trying to return me to a login page.
I do authenticate with the dev ops server within my application and it caches these.
readonly VssCredentials creds = new VssClientCredentials();
I have tried to use a webclient to make the call but you cant cast the VSScredentuals to system.net credentials
this used to work before
using (WebClient webClient = new WebClient())
{
byte[] data = webClient.DownloadData(src);
using (MemoryStream mem = new MemoryStream(data))
{
using (var yourImage = Image.FromStream(mem))
{
// If you want it as Png
yourImage.Save(#"c:\temp\path_to_your_file.png", ImageFormat.Png);
// If you want it as Jpeg
yourImage.Save(#"c:\temp\path_to_your_file.jpg", ImageFormat.Jpeg);
}
}
}
I have tried also using
using (var client = new TfvcHttpClient(new Uri(src), creds))
{
var itemRequestData = Create(src);
}
private static TfvcItemRequestData Create(string folderPath)
{
return new TfvcItemRequestData
{
IncludeContentMetadata = true,
IncludeLinks = true,
ItemDescriptors =
new[]
{
new TfvcItemDescriptor
{
Path = folderPath,
RecursionLevel = VersionControlRecursionType.Full
}
}
};
}
But how do i then write the itemRequestData to a file?
Or am i going about this the wrong way?
thanks
Try this:
using (WebClient webClient = new WebClient())
{
webClient.Headers.Add("Authorization", "Basic " + base64Token);
byte[] data = webClient.DownloadData(src);
// ....
}
Where base64Token is your Personal Access Token converted to base64 with a ":" at the start.
For example if your token is abcdefg you need to convert :abcdefg to base64 and use it as the authorization token.

C# add video file to stream

I have a function that add an Image file to stream like this:
//sourceImage is a url for an image
public Stream AddImageToStream(string sourceImage)
{
try
{
using (WebClient webClient = new WebClient())
{
byte[] data = webClient.DownloadData(sourceImage);
using (MemoryStream mem = new MemoryStream(data))
{
using (var yourImage = Image.FromStream(mem))
{
Image img = yourImage;
var ms = img.ToStream(ImageFormat.Png);
img.Dispose();
return ms;
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
I can't find Video class in C#.
How can implement this function for video files?
Basically you already know how to turn the downloaded content into a MemoryStream:
public Stream DownloadToStream(string url)
{
using (var webClient = new System.Net.WebClient())
{
byte[] data = webClient.DownloadData(url);
var ms = new System.IO.MemoryStream(data);
return ms;
}
}
But this will need the video or whatever to fit into memory, there is no progress handling and nothing asynchronous. Also you should Dispose() the returned stream when you finished your operations with it.
There is no Video class in the basic .NET framework as videos are a complex topic. If you want to process it, you should look into some of the frameworks/libraries for that and definitely have to learn about asynchronous processing and streams.
Update: If you can use current versions of the framework you might be interested in using HttpClient.GetStreamAsync. This will not consume all your memory. Still if you want to edit the video data you will require a framework specialized on video editing.

How to read Build-Action: Resource items

How do you read a resource that has build action Resource instead of build-action Embedded Resource. The layout of Resource is waay better, but I want to know how to do it without using the Application (WPF) object.
I have done this for gathering images from the resources where the build action is Resource from an external application. However we have to have a reference to System.Windows.Resources and use the Application.GetResourceStream()
Basically we use the following method.
private static Stream GetResourceStream(string resourcePath)
{
try
{
string s = System.IO.Packaging.PackUriHelper.UriSchemePack;
var uri = new Uri(resourcePath);
StreamResourceInfo sri = System.Windows.Application.GetResourceStream(uri);
return sri.Stream;
}
catch (Exception e)
{
return null;
}
}
Now this returns a stream which can then by converted to a byte[] array or used to build other object types.
This could be called like.
//set variables
string myAssembly = "Test.Assembly";
string resourceItem = "resources/myimage.png";
//get the stream
using (var bSteam = GetResourceStream(string.Format("pack://application:,,,/{0};component//{1}", myAssembly, resourceItem)))
{
//covert the stream to a memory stream and return the byte array
using (var ms = new MemoryStream())
{
bSteam.CopyTo(ms);
return ms.ToArray();
}
}
Like I said it does use the Application.GetResourceStream(). If you want to avoid using this method this answer may not be suitable.
Cheers,

Categories