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.
Related
I am writing a proxy for some site using ASP.NET Core 2.0. Proxy works fine if all it does is just re-translating HttpResponseMessage to the browser. My proxy based on this example. But I need to make some changes site content, for instance, some of the href contains an absolute reference. So when I click them from my proxy, I get to the original site, and it is a problem.
I get access to target page content, using way I find here. But when I try to copy changed content to HttpResponse.Body I run into NotSupportedException with message GZipStream does not support reading. My code is bellow:
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
if (responseMessage == null)
{
throw new ArgumentNullException(nameof(responseMessage));
}
var response = context.Response;
response.StatusCode = (int)responseMessage.StatusCode;
//work with headers
using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
string str;
using (var gZipStream = new GZipStream(responseStream, CompressionMode.Decompress))
using (var streamReader = new StreamReader(gZipStream))
{
str = await streamReader.ReadToEndAsync();
//some stings changes...
}
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gZipStream = new GZipStream(mso, CompressionMode.Compress))
{
await msi.CopyToAsync(gZipStream);
await gZipStream.CopyToAsync(response.Body, StreamCopyBufferSize, context.RequestAborted);
}
}
//next string works, but I don't change content this way
//await responseStream.CopyToAsync(response.Body, StreamCopyBufferSize, context.RequestAborted);
}
}
After some search, I find out, after compression into GZipStream gZipStream.CanRead is false, it seems to be false always if CompressionMode is Compressed. I also tried to copy msi into response.Body, it doesn't throw exceptions, but in the browser I get an empty page (document Response in Network in browser console is also empty).
Is it possible to copy compressed GZipStream to another Stream or my way is entirely wrong?
GZipStream is not meant to be copied from directly. Your mso Stream is holding the compressed data.
But you can drop the mso stream entirely and copy from your msi stream to the response.Body:
using (var msi = new MemoryStream(bytes))
{
using (var gZipStream = new GZipStream(response.Body, CompressionMode.Compress)) //<-- declare your response.Body as the target for the compressed data
{
await msi.CopyToAsync(gZipStream, StreamCopyBufferSize, context.RequestAborted); //copy the msi stream to the response.Body through the gZipStream
}
}
I working on a sharepoint project in which i have to upload the videos in the document library as videoset. after creating a video set i have have to upload the video and fetch the thumbnail from the video and upload it. video is uploaded succesfully using
spfile = item.Folder.Files.Add(fuUpload.FileName, fuUpload.PostedFile.InputStream, true);
I am using using Nreco to get thumbnail from the video. However my code works fine on local machine but its giving error "http://mysite/Download/abc/abc.mp4: Server returned 401 Unauthorized (authorization failed) (exit code: 1)" when i am using my application from other pc browsers.
ffMpeg.GetVideoThumbnail(videoPath, ms, 10); the error line.
here is the code i am using
private MemoryStream SaveThumbnail(string videoPath)
{
MemoryStream ms;
try
{
videoPath = "http://mysitehttp/Download/abc/abc.mp4"
ms = new MemoryStream();
SPSecurity.RunWithElevatedPrivileges(delegate() {
var ffMpeg = new NReco.VideoConverter.FFMpegConverter();
ffMpeg.GetVideoThumbnail(videoPath, ms, 10);
});
}
catch(Exception ex)
{
throw ex;
}
return ms;
}
Finally I have managed to solve this. For some reason SharePoint did not allow me to access the file directly from URL using NReco so i tweaked the function like this.
Instead of using file URL as argument i used the file object it self. and copied the stream on server temp folder in virtual directories then i used the file path on the system for NRreco to create the thumbnail. and in the end deleted the file from the server.
private MemoryStream SaveThumbnail(SPFile videoFile)
{
MemoryStream ms;
try
{
//Creating Temp File Path to be used by Nreco
ms = new MemoryStream();
SPSecurity.RunWithElevatedPrivileges(delegate() {
string destinationFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + videoFile.Name);
//Copying the content the content of the file at temp loaction from stream
using (FileStream fileStream = File.Create(destinationFile))
{
Stream lStream = videoFile.OpenBinaryStream();
byte[] contents = new byte[lStream.Length];
lStream.Read(contents, 0, (int)lStream.Length);
lStream.Close();
// Use write method to write to the file specified above
fileStream.Write(contents, 0, contents.Length);
fileStream.Close();
}
var ffMpeg = new NReco.VideoConverter.FFMpegConverter();
ffMpeg.GetVideoThumbnail(destinationFile, ms, 10);
System.IO.File.Delete(destinationFile);
});
}
catch(Exception ex)
{
throw ex;
}
return ms;
}
Someone might save some time from my answer. if anyone has a better solution let me know please.
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>
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,
Here is my code to Serialize, Deserialize and Save an image to the file system. I have looked at many examples of serialization/deserialization and I just want to get some feedback as I am sure my code could be improved. Any feedback would be greatly appreciated. I know this is a common problem so hopefully this question will be a good resource for others in the future.
This is the revised code using recommendations:
private void Form1_Load(object sender, EventArgs e)
{
RunTest();
}
private void RunTest()
{
byte[] jpgba = ConvertFileToByteArray("D:\\Images\\Image01.jpg");
using (Image jpgimg = ConvertByteArrayToImage(jpgba))
{
SaveImageToFileSystem(jpgimg, "D:\\Images\\Image01_Copy.jpg");
}
byte[] pngba = ConvertFileToByteArray("D:\\Images\\Image02.png");
using (Image pngimg = ConvertByteArrayToImage(pngba))
{
SaveImageToFileSystem(pngimg, "D:\\Images\\Image02_Copy.png");
}
byte[] gifba = ConvertFileToByteArray("D:\\Images\\Image03.gif");
using (Image gifimg = ConvertByteArrayToImage(gifba))
{
SaveImageToFileSystem(gifimg, "D:\\Images\\Image03_Copy.gif");
}
MessageBox.Show("Test Complete");
this.Close();
}
private static byte[] ConvertFileToByteArray(String FilePath)
{
return File.ReadAllBytes(FilePath);
}
private static Image ConvertByteArrayToImage(byte[] ImageByteArray)
{
using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
return Image.FromStream(ms);
}
}
private static void SaveImageToFileSystem(Image ImageObject, string FilePath)
{
// ImageObject.Save(FilePath, ImageObject.RawFormat);
// This method only works with .png files.
// This method works with .jpg, .png and .gif
// Need to copy image before saving.
using (Image img = new Bitmap(ImageObject.Width, ImageObject.Height))
{
using (Graphics tg = Graphics.FromImage(img))
{
tg.DrawImage(ImageObject, 0, 0);
}
img.Save(FilePath, img.RawFormat);
}
return;
}
What I have see from quick look:
Streams should be wrapped in using(...) pattern, in your case if exception occurs during processing, then Dispose() won't be called.
using (FileStream fs = new FileStream(FilePath, FileMode.Open))
{
// Another small optimization, removed unnecessary variable
byte[] iba = new byte[(int)fs.Length];
fs.Read(iba, 0, iba.Length);
}
You should catch only exceptions you expect. For example in SerializeImage this will be IOException. Catching all exceptions is very bad practice.
}
catch (IOException ex)
{
Image.FromStream method depends on stream, so if you close underlying stream and return Image you can receive unpredictable behavior (well, in most cases this will work, but sometimes error occurs). So you need to create image copy and return it.
using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
using (Image img = Image.FromStream(ms))
{
return new Bitmap(img);
}
}
You are not disposed tg graphics object and img object in SaveImage method (but disposed ImageObject, see next paragraph). And in general I do not see necessity in such logic, simply call ImageObject.Save(..., ImageFormat.Png) if you want to save image preserving quality.
In the same method (SaveImage) you are disposed ImageObject parameter. This is also bad practice in most cases, consider disposing this image outside worker method by using using(...) pattern.
Here's a bit more:
private void RunTest()
{
// byte array that can be stored in DB
byte[] iba;
// image object to display in picturebox or used to save to file system.
iba = ReadImage("D:\\Images\\Image01.jpg");
using (Image img = DeserializeImage(iba))
{
SaveImage(img, "D:\\Images\\Image01_Copy.jpg");
}
iba = ReadImage("D:\\Images\\Image02.png");
using (Image img1 = DeserializeImage(iba))
{
SaveImage(img1, "D:\\Images\\Image02_Copy.png");
}
iba = ReadImage("D:\\Images\\Image03.gif");
using (var img2 = DeserializeImage(iba))
{
SaveImage(img2, "D:\\Images\\Image03_Copy.gif");
}
MessageBox.Show("Test Complete");
}
private static byte[] ReadImage(String filePath)
{
// This seems to be the easiest way to serialize an image file
// however it would be good to take a image object as an argument
// in this method.
using (var fs = new FileStream(filePath, FileMode.Open))
{
Int32 fslength = Convert.ToInt32(fs.Length);
var iba = new byte[fslength];
fs.Read(iba, 0, fslength);
return iba;
}
}
private static Image DeserializeImage(byte[] imageByteArray)
{
using (var ms = new MemoryStream(imageByteArray))
{
return Image.FromStream(ms);
}
}
private static void SaveImage(Image imageObject, string filePath)
{
// I could only get this method to work for .png files.
// imageObject.Save(filePath, imageObject.RawFormat);
// This method works with .jpg, .png and .gif
// Need to copy image before saving.
using (Image img = new Bitmap(imageObject.Width, imageObject.Height))
{
using (Graphics tg = Graphics.FromImage(img))
{
tg.DrawImage(imageObject, 0, 0);
}
img.Save(filePath, img.RawFormat);
}
return;
}
Note what you called Serializing is just reading the bytes in. Serializing is more what you're doing when you Save.
I got rid of all the try/catch blocks. The best they were doing for you is telling you whether the problem happened in Reading, Saving or Deserializing. You can determine that from the stack trace, which you were destroying by only displaying ex.Message.
You were also returning null on a serious exception, propagating failure.
Beside that I agree with everything arbiter said.
As John Saunder says, serializing and deserializing are more than just reading the raw data from a file. See Wiki on Serialization
For images in .net, you don't need to use anything more than the provided framework methods (most of the time)
So Loading an Image (De-Serialization) in .net is.
using System.Drawing.Image;
Image test;
test = Image.FromFile(#"C:\myfile.jpg")
test = Image.FromStream(myStream); // or you can load from an existing stream
Likewise, Saving the image (Serialization) is:
test.Save(#"C:\anotherFile.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
These are the basics of loading and saving an image in .net. If you have a more specific scenario, ask another question.