Telegram Bot download image file - c#

I'm trying to download file (image ) using my bot, but when I download the image ( which is done successfully ) after using getFile, the image I received is very small 1.7 kb while it's bigger than that on my mobile phone

This is an old post. But since there is not a good documentation on how you should download file in telegram bot, for anyone wondering, that's how you should do it(One way of it):
DownloadFile(message.Photo[message.Photo.Length - 1].FileId, #"c:\photo.jpg");
in which:
private static async void DownloadFile(string fileId, string path)
{
try
{
var file = await Bot.GetFileAsync(fileId);
using (var saveImageStream = new FileStream(path, FileMode.Create))
{
await file.FileStream.CopyToAsync(saveImageStream);
}
}
catch (Exception ex)
{
Console.WriteLine("Error downloading: " + ex.Message);
}
}
The message.Photo[message.Photo.Length - 1] is the last element in message.Photo array, which contains the highest quality image data. Obviously you can use DownloadFile to download other kind of files(for example message.Document) as well.

the getFile Method present a JSON object (the 1.7 KB response) that contain the data for accessing your image file.
also note that telegram create an array of image for any image. the first element of this array contain the small thumbnail of your original image and the latest element of the array contain your original image.

var file = await Bot.GetFileAsync(message.Document.FileId);
FileStream fs=new FileStream("Your Destination Path And File Name",FileMode.Create);
await Bot.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();

I use telegram.bot v14.10.0 but I can't find file.FileStream so I find alternative way to get image from telegram. my way is to use telegram api directly for this case.
var test = _myBot.GetFileAsync(e.Message.Photo[e.Message.Photo.Count() - 1].FileId);
var download_url = #"https://api.telegram.org/file/bot<token>/" + test.Result.FilePath;
using (WebClient client = new WebClient())
{
client.DownloadFile(new Uri(download_url), #"c:\temp\NewCompanyPicure.png");
}
//then do what you want with it

You need use await botClient.DownloadFileAsync(file.FilePath, saveImageStream); instead await file.FileStream.CopyToAsync(saveImageStream);
Your code should look like this:
static async void DownloadFile(ITelegramBotClient botClient, string fileId, string path)
{
try
{
var file = await botClient.GetFileAsync(fileId);
using (var saveImageStream = new FileStream(path, FileMode.Create))
{
await botClient.DownloadFileAsync(file.FilePath, saveImageStream);
}
}
catch (Exception ex)
{
Console.WriteLine("Error downloading: " + ex.Message);
}
}
Telegram.Bot from version 14.2.0 commit in examples: https://github.com/TelegramBots/Telegram.Bot.Examples/commit/ff5a44133ad3b0d3c1e4a8b82edce959d0ee0d0e

Related

Create a valid PDF from a web request

I'm trying to create a scanning solution. Basically the user is physically scanning a page. The printer is making an API call, passing in the binary data of the scan in the body.
I'm trying to save this as a PDF on the server, but when I go to open the file, i'm getting an error "There is an error while reading a stream".
var bodyStream = new StreamReader(HttpContext.Current.Request.InputStream);
bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
var bodyText = bodyStream.ReadToEnd();
string pathToFiles = HttpContext.Current.Server.MapPath("~\\UploadedFiles\\WriteLines.pdf");
try
{
using (StreamWriter outputFile = new StreamWriter(pathToFiles, false))
{
outputFile.WriteLine(bodyText);
}
HttpContext.Current.Response.ContentType = "application/pdf";
}
catch (Exception ex)
{
throw (ex);
}
This is just testing something, and I have permissions etc for writing the file, it's just not creating a valid file.
Any thoughts on what I should use? I have looked into some libraries, but they don't seem to cover what i'm after
StreamReader.ReadToEnd convert bytes to string in particular encoding (UTF8 by default). I don't think this work for PDF.
You need copy bytes directly in the output file :
var bodyStream = HttpContext.Current.Request.InputStream;
bodyStream.Seek(0, SeekOrigin.Begin);
string pathToFiles = HttpContext.Current.Server.MapPath("~\\UploadedFiles\\WriteLines.pdf");
using (FileStream outputFile = File.Create(pathToFiles))
{
bodyStream.CopyTo(outputFile);
}

Uploading files to server - c#

I build a client server application for uploading file from a client folder to server.
My server WebMethod for uploading follows -
[WebMethod]
public string UploadFile(byte[] f, string fileName)
{
// the byte array argument contains the content of the file
// the string argument contains the name and extension
// of the file passed in the byte array
new general().logError("UploadFile " + fileName);
try
{
// instance a memory stream and pass the
// byte array to its constructor
MemoryStream ms = new MemoryStream(f);
FileStream fs = new FileStream(System.Web.Hosting.HostingEnvironment.MapPath
("~/data/") + fileName, FileMode.Create);
// write the memory stream containing the original
// file as a byte array to the filestream
ms.WriteTo(fs);
// clean up
ms.Close();
fs.Close();
fs.Dispose();
new general().logError("After saving the file");
// return OK if we made it this far
return "OK";
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
The function that calls this WebMethod follows -
private void uploadIt(string fName)
{
FileStream f = File.OpenRead(fName);
cloudius.cloudius m = new cloudius.cloudius();
using (MemoryStream ms = new MemoryStream())
{
f.CopyTo(ms);
//string[] drive = fName.Split(':');
string[] p = fName.Split('\\');
string b = m.UploadFile(ms.ToArray(), p[p.Length - 1]); //
}
}
When running the aboce code I get the following error -
Client found response content type of 'text/html', but expected 'text/xml'.
Any idea what is causing this error ?
By the looks of things after some research, it looks like it is a form of a error page coming back. Go have a look here as well as here.
Hope this gives you some form of clarification on your problem.
Hey buddy if the main purpose of your method is just to upload a file you can use :
FileUpload fu; // Get the FileUpload object.
using (FileStream fs = File.OpenWrite("file.dat"))
{
fu.PostedFile.InputStream.CopyTo(fs);
fs.Flush();
}
That will be more efficient, as you will be directly streaming the input file to the destination host, without first caching in memory or on disk.

Corrupt file download from Google Drive

I'm having issues with the download process, it downloads, but the file downloaded is the same byte size: 108102 bytes; regardless of whether the actual file is smaller or bigger than this.
I'm able to upload a PDF file successfully and set its permissions to make it viewable by anyone with the link https://drive.google.com/open?id=UNIQUE_ID_HERE. Below is the function I use to download the file asynchronously:
/// <summary>Downloads the media from the given URL.</summary>
private async Task DownloadFile(DriveService service, string url)
{
var downloader = new MediaDownloader(service);
downloader.ChunkSize = DownloadChunkSize;
// add a delegate for the progress changed event for writing to console on changes
downloader.ProgressChanged += Download_ProgressChanged;
var fileName = DownloadDirectoryName + #"\cover_new.pdf";
Console.WriteLine("Downloading file from link: {0}", url);
using (var fileStream = new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
var progress = await downloader.DownloadAsync(url, fileStream);
if (progress.Status == DownloadStatus.Completed)
{
Console.WriteLine(fileName + " was downloaded successfully: " + progress.BytesDownloaded);
}
else
{
Console.WriteLine("Download {0} was interrupted in the middle. Only {1} were downloaded. ", fileName, progress.BytesDownloaded);
}
}
}
Also, I'm able to open this file using the link successfully from a different browser without any credentials entered.
I was incorrectly trying to download the file using a URL like: https://drive.google.com/open?id=UNIQUE_ID_HERE.
Changes I made to my method:
The second parameter, url, is now a file object. I was passing the URL, but instead I should fetch the file using service.Files.Get() and using its Id.
Rename the second parameter to fileToDownload, for clarity.
Since I now have a file object downloadfile for the file I want to download, I can call its DownloadAsync method, sending it the filestream I already had.
The new code below:
private async Task DownloadFile(DriveService service, Google.Apis.Drive.v3.Data.File fileToDownload)
{
var downloader = new MediaDownloader(service);
downloader.ChunkSize = DownloadChunkSize;
// add a delegate for the progress changed event for writing to console on changes
downloader.ProgressChanged += Download_ProgressChanged;
var fileName = DownloadDirectoryName + #"\cover_new.pdf";
var downloadfile = service.Files.Get(fileToDownload.Id);
Console.WriteLine("Downloading file with id: {0}", fileToDownload);
using (var fileStream = new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
var progress = await downloadfile.DownloadAsync(fileStream);
if (progress.Status == DownloadStatus.Completed)
{
Console.WriteLine(fileName + " was downloaded successfully: " + progress.BytesDownloaded);
}
else
{
Console.WriteLine("Download {0} was interrupted in the middle. Only {1} were downloaded. ", fileName, progress.BytesDownloaded);
}
}
}
I hope this helps someone out there.

From URL of Video GetThumbnail Using Nreco

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.

How to download image from URL

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>

Categories