Problem converting Image to Base64 in Blazor Server - c#

So I am trying to convert an image base64 that will be uploaded to SQL Server.
Current code is:
private async Task OnInputFileChange(InputFileChangeEventArgs args)
{
var maxFiles = 1;
var maxSize = 512000000;
var format = "image/jpg";
test = "Something";
test1 = args.FileCount.ToString();
foreach (var file in args.GetMultipleFiles(maxFiles))
{
var image = await file.RequestImageFileAsync(format, 500, 500);
test = image.Size.ToString();
buffer = new byte[image.Size];
await image.OpenReadStream(maxAllowedSize: maxSize).ReadAsync(buffer);
test1 = buffer.ToString();
var imageDataUrl = $"data:{format};base64,{Convert.ToBase64String(buffer)}";
imageDataUrls.Add(imageDataUrl);
imageString = imageDataUrl;
}
}
It begins fine, however only the top portion of image is actually converted and in the string is followed by thousands of repeating "A". Reconstructing the image just shows the top portion of the image. What am I doing wrong?
Currently I had not uploaded and redownloaded the string, it is all local until I can figure out what is wrong. I am using the imageString for the image source. I am using .net 6.0.

Try this. Works for me. Files since 1 MB.
public static byte[] GetBytes(Stream stream)
{
var bytes = new byte[stream.Length];
stream.Seek(0, SeekOrigin.Begin);
stream.ReadAsync(bytes, 0, bytes.Length);
stream.Dispose();
return bytes;
}
private async Task OnInputFileChange(InputFileChangeEventArgs args)
{
string base64String = "";
try
{
var files = args.GetMultipleFiles();
foreach (var file in files)
{
await using MemoryStream fs = new MemoryStream();
await file.OpenReadStream(maxAllowedSize: 1048576).CopyToAsync(fs);
byte[] somBytes = GetBytes(fs);
base64String = Convert.ToBase64String(somBytes, 0, somBytes.Length);
System.Diagnostics.Debug.Print("Imatge 64: " + base64String + Environment.NewLine);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.Print("ERROR: " + e.Message + Environment.NewLine);
}
}

Related

MVC WebAPI return multiple images

I have 3 images in a directory but my code always returns one of them. I'd like to return 3 images image1.jpg, image2.jpg, image3.jpg and get them in my Xamarin app.
I think returning the result like an array might solve the problem but I don't understand what I need.
var result = new HttpResponseMessage(HttpStatusCode.OK);
MemoryStream ms = new MemoryStream();
for (int i = 0; i < 3; i++)
{
String filePath = HostingEnvironment.MapPath("~/Fotos/Empresas/Comer/" + id + (i + 1) + ".jpg");
FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
Image image = Image.FromStream(fileStream);
image.Save(ms, ImageFormat.Jpeg);
fileStream.Close();
byte[] bytes = File.ReadAllBytes(filePath);
byte[] length = BitConverter.GetBytes(bytes.Length);
// Write length followed by file bytes to stream
ms.Write(length, 0, 3);
ms.Write(bytes, 0, bytes.Length);
}
result.Content = new StreamContent(ms);
return result;
Now i getting bytes, i edit a little bit the code now
byte[] imageAsBytes = client.GetByteArrayAsync(url).Result;
MemoryStream stream1 = new MemoryStream(imageAsBytes);
img.Source = ImageSource.FromStream(() => { return stream1; });
this is my xamarin code to get images, but i still getting nothing =/
If you just return a memorystream is not easy to differentiate one image from the other in the stream, instead of this, you can return a List of byte arrays, then you can access each position in the array and convert from byte array to image...
Here is a fully functional dotnet core webapi controller :
public class GetImagesController : Controller
{
private readonly IWebHostEnvironment _host;
public GetImagesController(IWebHostEnvironment host)
{
_host = host;
}
[HttpGet("{images}")]
public async Task<List<byte[]>> Get([FromQuery]string images)
{
List<byte[]> imageBytes = new List<byte[]>();
String[] strArray = images.Split(',');
for (int i = 0; i < strArray.Length; i++)
{
String filePath = Path.Combine(_host.ContentRootPath, "images", strArray[i]+".jpg");
byte[] bytes = System.IO.File.ReadAllBytes(filePath);
imageBytes.Add(bytes);
}
return imageBytes;
}
}
This controller can be called like this :
https://localhost:44386/getImages?images=P1,P2,P3
Given that you have a folder called images with files P1.jpg, P2.jpg and P3.jpg under your ContentRooPath.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-3.0
You'll need something in the response to delimit where each image starts and finishes. As a basic solution, you could write the image length as an Int32 and follow it with the image data. On the other end, you'll need to read the 4-byte length followed by that x number of bytes:
[HttpGet]
public HttpResponseMessage Get(string id)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
String[] strArray = id.Split(',');
var ms = new MemoryStream();
for (int i = 0; i < strArray.Length; i++)
{
String filePath = HostingEnvironment.MapPath("~/Fotos/Empresas/Comer/" + strArray[i] + (i + 1) + ".jpg");
byte[] bytes = File.ReadAllBytes(filePath);
byte[] length = BitConverter.GetBytes(bytes.Length);
// Write length followed by file bytes to stream
ms.Write(length, 0, 4);
ms.Write(bytes, 0, bytes.Length);
}
result.Content = new StreamContent(ms);
return result;
}

DropBox API calls Uploading a Zero byte file

I am trying to upload a file to dropbox using rest calls but it is not uploading the actual file, it is uploading a zero byte file.
Please check the code and let me know if i am missing something.
var task = Task.Run((Func<Task<int>>)OrderExtractUsecase.DropBox);
task.Wait();
int x = task.Result;
Dropbox task Code is:
static async Task<int> DropBox()
{
try
{
Dropbox_Utility objDropBox = new Dropbox_Utility("<accessid>");
foreach (string temp in fileList)
{
await objDropBox.Upload("/Assist", temp);
}
return 1;
}
catch(Exception ex)
{
return -1;
}
}
Upload task code is:
public async Task<string> Upload(string folder, string filefullpath)
{
string filename = string.Empty;
string fileID = string.Empty;
try
{
filename = Path.GetFileName(filefullpath);
using (FileStream fileStream = File.OpenRead(filefullpath))
{
using (MemoryStream memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
var response = await dbx.Files.UploadAsync(folder + "/" + filename, WriteMode.Overwrite.Instance, body: memoryStream);
fileID = response.Id;
}
}
}
catch (Exception ex) { throw; }
finally { }
return fileID;
}
As awh112 mentioned, you need to reset the position of memoryStream. After the copyTo, the Position of memoryStream is the length of the file. For that reason, your code will upload a zero byte file. I've confirmed as much with the following:
fileStream.CopyTo(memoryStream);
Console.WriteLine(memoryStream.Position);
var response = await dbx.Files.UploadAsync(folder + "/" + filename, WriteMode.Overwrite.Instance, body: memoryStream);
Console.WriteLine((response as FileMetadata).Size);
That prints: (in my case, my test file is just 12 bytes long)
12
0
You can rewind it like this:
fileStream.CopyTo(memoryStream);
Console.WriteLine(memoryStream.Position);
memoryStream.Position = 0;
Console.WriteLine(memoryStream.Position);
var response = await dbx.Files.UploadAsync(folder + "/" + filename, WriteMode.Overwrite.Instance, body: memoryStream);
Console.WriteLine((response as FileMetadata).Size);
That prints:
12
0
12
The resulting uploaded file then contains the expected contents.

Download PNG file to local machine using Dropbox.NET on UWP platform

I am able to upload PNG image to Dropbox folder however, I don't know how to download the PNG (or other images) from Dropbox. What I get from the tutorial page is:
async Task Download(DropboxClient dbx, string folder, string file)
{
using (var response = await dbx.Files.DownloadAsync(folder + "/" + file))
{
Console.WriteLine(await response.GetContentAsStringAsync());
}
}
Do anyone have the sample code for downloading file to local drive? Thanks.
After some findings and tryings, finally I found the solution:
public static async Task Download(string folder, string file)
{
StorageFolder storeFolder = ApplicationData.Current.LocalFolder;
CreationCollisionOption options = CreationCollisionOption.ReplaceExisting;
StorageFile outputFile = await storeFolder.CreateFileAsync("temp.png", options);
using (var dbx = new DropboxClient(yourAccessToken))
{
var response = await dbx.Files.DownloadAsync(downloadFolder);
{
using (var file = await outputFile.OpenStreamForWriteAsync())
{
Stream imageStream = await response.GetContentAsStreamAsync();
CopyStream(imageStream, file);
}
}
}
}
With a helper function:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, len);
}
}
To upload file:
public static async Task Upload(string filename, string filePath)
{
try
{
string TargetPath = "/data/" + filename + ".png";
const int ChunkSize = 4096 * 1024;
using (var dbx = new DropboxClient(yourAccessToken))
{
using (var fileStream = File.Open(filePath, FileMode.Open))
{
if (fileStream.Length <= ChunkSize)
{
await dbx.Files.UploadAsync(TargetPath, null, false, null, false, body: fileStream);
}
else
{
MessageDialog dialog = new MessageDialog("File is too big");
await dialog.ShowAsync();
}
}
}
}
catch (Exception ex)
{
MessageDialog dialog = new MessageDialog("Error uploading file. " + ex.Message);
await dialog.ShowAsync();
}
}
Hope it helps. Thanks.
The Dropbox API .NET SDK DownloadAsync method gives you a IDownloadResponse which offers three methods for getting the file content:
GetContentAsByteArrayAsync
GetContentAsStreamAsync
GetContentAsStringAsync
For example, to save the file content to a local file, you can do something like:
public async Task Download(string remoteFilePath, string localFilePath)
{
using (var response = await client.Files.DownloadAsync(remoteFilePath))
{
using (var fileStream = File.Create(localFilePath))
{
response.GetContentAsStreamAsync().Result.CopyTo(fileStream);
}
}
}
That would download the file content from a file at remote Dropbox file path remoteFilePath to the local path localFilePath.
What #Greg said is correct. I would like to make a small change that localFilePath mentioned in the code, should have an extension also. For example it should be something like C:\Code\image.jgp and not something like C:\Code. If the filelocation specified does not exist, it will be created automatically and this code will work perfectly.
public async Task Download(string remoteFilePath, string localFilePath)
{
using (var response = await client.Files.DownloadAsync(remoteFilePath))
{
using (var fileStream = File.Create(localFilePath))
{
response.GetContentAsStreamAsync().Result.CopyTo(fileStream);
}
}
}
Here is my logic to download a file using Dropbox.Net API:
private async Task Download(DropboxClient dbx, string remoteFilePath, string localFilePath) {
using(var response = await dbx.Files.DownloadAsync(remoteFilePath)) {
var fileSize = response.Response.Size;
var bufferSize = 1024 * 1024;
var buffer = new byte[bufferSize];
using(var stream = await response.GetContentAsStreamAsync()) {
using(System.IO.FileStream file = new System.IO.FileStream(localFilePath, FileMode.OpenOrCreate)) {
var length = stream.Read(buffer, 0, bufferSize);
while (length > 0) {
file.Write(buffer, 0, length);
var percentage = 100 * file.Length / (double) fileSize;
Console.WriteLine(percentage);
length = stream.Read(buffer, 0, bufferSize);
}
}
}
}
}
And you can call it like:
Await(Download(dbx, url, #"yourDestinationFolder\" + item.Name));
Where item.Name is the full name of the downloaded file e.g. setup.exe

converting a base 64 string to an image and saving it

Here is my code:
protected void SaveMyImage_Click(object sender, EventArgs e)
{
string imageUrl = Hidden1.Value;
string saveLocation = Server.MapPath("~/PictureUploads/whatever2.png") ;
HttpWebRequest imageRequest = (HttpWebRequest)WebRequest.Create(imageUrl);
WebResponse imageResponse = imageRequest.GetResponse();
Stream responseStream = imageResponse.GetResponseStream();
using (BinaryReader br = new BinaryReader(responseStream))
{
imageBytes = br.ReadBytes(500000);
br.Close();
}
responseStream.Close();
imageResponse.Close();
FileStream fs = new FileStream(saveLocation, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
try
{
bw.Write(imageBytes);
}
finally
{
fs.Close();
bw.Close();
}
}
}
The top imageUrl declartion is taking in a Base64 image string, and I want to convert it into an image. I think my set of code only works for images like "www.mysite.com/test.jpg" not for a Base64 string. Anybody have some suggestions? Thanks!
Here is an example, you can modify the method to accept a string parameter. Then just save the image object with image.Save(...).
public Image LoadImage()
{
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
return image;
}
It is possible to get an exception A generic error occurred in GDI+. when the bytes represent a bitmap. If this is happening save the image before disposing the memory stream (while still inside the using statement).
You can save Base64 directly into file:
string filePath = "MyImage.jpg";
File.WriteAllBytes(filePath, Convert.FromBase64String(base64imageString));
Here is what I ended up going with.
private void SaveByteArrayAsImage(string fullOutputPath, string base64String)
{
byte[] bytes = Convert.FromBase64String(base64String);
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
image.Save(fullOutputPath, System.Drawing.Imaging.ImageFormat.Png);
}
I would suggest via Bitmap:
public void SaveImage(string base64)
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64)))
{
using (Bitmap bm2 = new Bitmap(ms))
{
bm2.Save("SavingPath" + "ImageName.jpg");
}
}
}
Here is working code for converting an image from a base64 string to an Image object and storing it in a folder with unique file name:
public void SaveImage()
{
string strm = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
//this is a simple white background image
var myfilename= string.Format(#"{0}", Guid.NewGuid());
//Generate unique filename
string filepath= "~/UserImages/" + myfilename+ ".jpeg";
var bytess = Convert.FromBase64String(strm);
using (var imageFile = new FileStream(filepath, FileMode.Create))
{
imageFile.Write(bytess, 0, bytess.Length);
imageFile.Flush();
}
}
In my case it works only with two line of code. Test the below C# code:
String dirPath = "C:\myfolder\";
String imgName = "my_mage_name.bmp";
byte[] imgByteArray = Convert.FromBase64String("your_base64_string");
File.WriteAllBytes(dirPath + imgName, imgByteArray);
That's it. Kindly up vote if you really find this solution works for you. Thanks in advance.
In a similar scenario what worked for me was the following:
byte[] bytes = Convert.FromBase64String(Base64String);
ImageTagId.ImageUrl = "data:image/jpeg;base64," + Convert.ToBase64String(bytes);
ImageTagId is the ID of the ASP image tag.
If you have a string of binary data which is Base64 encoded, you should be able to do the following:
byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
You should be able to write the resulting array to a file.
public bool SaveBase64(string Dir, string FileName, string FileType, string Base64ImageString)
{
try
{
string folder = System.Web.HttpContext.Current.Server.MapPath("~/") + Dir;
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
string filePath = folder + "/" + FileName + "." + FileType;
File.WriteAllBytes(filePath, Convert.FromBase64String(Base64ImageString));
return true;
}
catch
{
return false;
}
}
Using MemoryStream is not a good idea and violates a specification in MSDN for Image.FromStream(), where it says
You must keep the stream open for the lifetime of the Image.
A better solution is using ImageConverter, e.g:
public Image ConvertBase64ToImage(string base64)
=> (Bitmap)new ImageConverter().ConvertFrom(Convert.FromBase64String(base64));
In NetCore 6.0, you can use HttpClient and the async methods in the new File class.
The implementation is very simple:
static async Task DownloadFile(string imageUrl, string pathToSave)
{
var content = await GetUrlContent(url);
if (content != null)
{
await File.WriteAllBytesAsync(pathToSave, content);
}
}
static async Task<byte[]?> GetUrlContent(string url)
{
using (var client = new HttpClient())
using (var result = await client.GetAsync(url))
return result.IsSuccessStatusCode ? await result.Content.ReadAsByteArrayAsync():null;
}
Usage:
await DownloadFile("https://example.com/image.jpg", #"c:\temp\image.jpg");

How to use httpwebrequest to pull image from website to local file

I'm trying to use a local c# app to pull some images off a website to files on my local machine. I'm using the code listed below. I've tried both ASCII encoding and UTF8 encoding but the final file is not an correct. Does anyone see what I'm doing wrong? The url is active and correct and show the image just fine when I put the address in my browser.
private void button1_Click(object sender, EventArgs e)
{
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
// returned values are returned as a stream, then read into a string
String lsResponse = string.Empty;
HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse();
using (StreamReader lxResponseStream = new StreamReader(lxResponse.GetResponseStream()))
{
lsResponse = lxResponseStream.ReadToEnd();
lxResponseStream.Close();
}
byte[] lnByte = System.Text.UTF8Encoding.UTF8.GetBytes(lsResponse);
System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create);
lxFS.Write(lnByte, 0, lnByte.Length);
lxFS.Close();
MessageBox.Show("done");
}
nice image :D
try using the following code:
you needed to use a BinaryReader, 'cause an image file is binary data and thus not encoded in UTF or ASCII
edit: using'ified
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create(
"http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
// returned values are returned as a stream, then read into a string
String lsResponse = string.Empty;
using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse()){
using (BinaryReader reader = new BinaryReader(lxResponse.GetResponseStream())) {
Byte[] lnByte = reader.ReadBytes(1 * 1024 * 1024 * 10);
using (FileStream lxFS = new FileStream("34891.jpg", FileMode.Create)) {
lxFS.Write(lnByte, 0, lnByte.Length);
}
}
}
MessageBox.Show("done");
Okay, here's the final answer. It uses a memorystream as a way to buffer the data from the reaponsestream.
private void button1_Click(object sender, EventArgs e)
{
byte[] lnBuffer;
byte[] lnFile;
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
{
using (BinaryReader lxBR = new BinaryReader(lxResponse.GetResponseStream()))
{
using (MemoryStream lxMS = new MemoryStream())
{
lnBuffer = lxBR.ReadBytes(1024);
while (lnBuffer.Length > 0)
{
lxMS.Write(lnBuffer, 0, lnBuffer.Length);
lnBuffer = lxBR.ReadBytes(1024);
}
lnFile = new byte[(int)lxMS.Length];
lxMS.Position = 0;
lxMS.Read(lnFile, 0, lnFile.Length);
}
}
}
using (System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create))
{
lxFS.Write(lnFile, 0, lnFile.Length);
}
MessageBox.Show("done");
}
A variation of the answer, using async await for async file I/O. See Async File I/O on why this is important.
Download png and write to disk using BinaryReader/Writer
string outFile = System.IO.Path.Combine(outDir, fileName);
// Download file
var request = (HttpWebRequest) WebRequest.Create(imageUrl);
using (var response = await request.GetResponseAsync()){
using (var reader = new BinaryReader(response.GetResponseStream())) {
// Read file
Byte[] bytes = async reader.ReadAllBytes();
// Write to local folder
using (var fs = new FileStream(outFile, FileMode.Create)) {
await fs.WriteAsync(bytes, 0, bytes.Length);
}
}
}
Read all bytes extension method
public static class Extensions {
public static async Task<byte[]> ReadAllBytes(this BinaryReader reader)
{
const int bufferSize = 4096;
using (var ms = new MemoryStream())
{
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) {
await ms.WriteAsync(buffer, 0, count);
}
return ms.ToArray();
}
}
}
You can use the following method to download an image from a web site and save it, using the Image class:
WebRequest req = WebRequest.Create(imageUrl);
WebResponse resp = req.GetResponse();
Image img = Image.FromStream(resp.GetResponseStream());
img.Save(filePath + fileName + ".jpg");

Categories