I am getting parameter is not valid error when trying to convert stream to image.
I my C# ASP.NET application, I upload an image to Amazon S3 and download it again for manipulation.
I've checked that the uploaded image is ok by viewing it online on S3.
I am downloading the image using this code:
using (AmazonS3 client = new AmazonS3Client(accessKey, secretKey))
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = "mybucket",
Key = "temp/" + sp.FileGuid + Path.GetExtension(sp.FileName)
};
using (GetObjectResponse response = client.GetObject(request)) // S3Response
{
using (MemoryStream memStream = new MemoryStream())
{
int file_size_in_bytes = Convert.ToInt32(response.Headers.GetValues("Content-Length")[0]);
byte[] buffer = new Byte[file_size_in_bytes];
int numBytesToRead = file_size_in_bytes;
int read;
while ((read = response.ResponseStream.Read(buffer, 0, buffer.Length)) > 0)
{
memStream.Write(buffer, 0, read);
}
response.ResponseStream.Close();
...
I convert the response stream of the image to byte array in order to pass it to WCF service for later manipulation.
In the WCF I do (partial code):
using (Stream filestream = new MemoryStream(sp.ImageFile)
{
**// GET THE ERROR IN THIS LINE!**
System.Drawing.Image image = System.Drawing.Image.FromStream(filestream);
}
sp.ImageFile holds the convert response stream to byte array.
I read the byte array into a stream and create the image again from the stream. In the code above you can see where I get the parameter is not valid error.
I assume that in some place the conversion of the stream data of the image to either byte array or stream masses up the image data, so it created a corrupted image data, but I am not sure.
Spend all day trying to solve this without success. The only way it worked is when I directly pass the uploaded file stream to the System.Drawing.FromStream, but that's not what I want to do.
Really Need your help.
It's possible this may help. If the stream is not positioned at the begining the image may not load.
using (Stream filestream = new MemoryStream(sp.ImageFile)
{
var checkSeek = filestream.Seek(0, SeekOrigin.Begin);
**// GET THE ERROR IN THIS LINE!**
System.Drawing.Image image = System.Drawing.Image.FromStream(filestream);
}
Related
I am trying to store MemoryStream into MagicImage, but when I am trying to upload file with heic format it still uploading with heic format, but it should upload it with jpeg format. So I kind of do not understand where I am doing wrong. So could someone help me? I am trying it open in Frame in web, but it does not open bc it is not converting it to jpeg.
using (MemoryStream ms = new MemoryStream())
{
create.PostedFile.InputStream.CopyTo(ms);
var data = ms.ToArray();
byte[] data1 = null;
using (var image = new MagickImage(data))
{
// Sets the output format to jpeg
image.Format = MagickFormat.Jpeg;
// Create byte array that contains a jpeg file
data1 = image.ToByteArray();
}
var file = new ClientFile
{
Data = data1, // here where it should store it in jpeg
};
While I have never used your way of writing the image, this is what I use in my implementations and it always works:
var image = new MagickImage(sourceStream);
var format = MagickFormat.Jpg;
var stream = new MemoryStream();
image.Write(stream, format);
stream.Position = 0;
EDIT
If you don't add:
stream.Position = 0
sending the stream will not work as it will start saving from the current position which is at the end of the stream.
I am currently working on integrating Amazon Prime on our system and being stuck at getting the label back as ZPL format.
Basically, Amazon returns a base64 string, we will need to convert that string to a byte array, then save that array as a *.gzip file. From that gzip file, we can extract the content and get the zpl label content.
My question is, how we can do all of above without storing any temp files to system. I have researched some solutions but none is working for me.
My current code as below:
var str = "base64string";
var label = Convert.FromBase64String(str);
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var demoFile = archive.CreateEntry("label.zip");
var entryStream = demoFile.Open();
using (var bw = new BinaryWriter(entryStream))
{
bw.Write(label);
}
var data = new MemoryStream();
using (var zip = ZipFile.Read(entryStream))
{
zip["label"].Extract(data);
}
data.Seek(0, SeekOrigin.Begin);
entryStream.Close();
}
using (var fileStream = new FileStream(#"D:\test.zip", FileMode.Create))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
If I save the file as test.zip, I can successfully get the label back. But if I try to extract it directly to another stream, I get an error
A stream from ZipArchiveEntry has been disposed
I've done something similar, taking PNG label data from a zipped web response. This is how I went about that
using (WebClient webClient = new WebClient())
{
// Download. Expect this to be a zip file
byte[] data = webClient.DownloadData(urlString);
MemoryStream memoryStream = new MemoryStream(data);
ZipArchive zipArchive = new ZipArchive(memoryStream);
foreach (var zipEntry in zipArchive.Entries)
{
// Can check file name here and ignore anything in zip we're not expecting
if (!zipEntry.Name.EndsWith(".png")) continue;
// Open zip entry as stream
Stream extractedFile = zipEntry.Open();
// Convert stream to memory stream
MemoryStream extractedMemoryStream = new MemoryStream();
extractedFile.CopyTo(extractedMemoryStream);
// At this point the extractedMemoryStream is a sequence of bytes containing image data.
// In this test project I'm pushing that into a bitmap image, just to see something on screen, but could as easily be written to a file or passed for storage to sql or whatever.
BitmapDecoder decoder = PngBitmapDecoder.Create(extractedMemoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
BitmapFrame frame = decoder.Frames.First();
frame.Freeze();
this.LabelImage.Source = frame;
}
}
I was overthinking it. I finally found a simple way to do it. We just need to convert that base64 string to bytes array and use GzipStream to directly decompress it. I leave the solution here in case someone needs it. Thanks!
var label = Convert.FromBase64String(str);
using (var compressedStream = new MemoryStream(label))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
I have a grid that covers whole screen and i want to make that grid as image and then this image i want to send on server. I have used RenderTargetBitmap for this purpose and successfully make writeablebitmap to save using FileSave Picker. Image save is at normal size as expected 700kb but these bytes are too big for uploading on server. Expected bytes for 700kb image could be 200 thousand but in my situation bytes are more than 30 hundred thousand. There is definitely issue with bytes.
Here is code that i use to save grid as image using file save picker.
await bitmap.RenderAsync(testgrid);
var pixelBuffer = await bitmap.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();
var wb = new WriteableBitmap((int)bitmap.PixelWidth, (int)bitmap.PixelHeight);
using (stream2 = wb.PixelBuffer.AsStream())
{
await stream2.WriteAsync(pixels, 0, pixels.Length);
}
FileSavePicker picker = new FileSavePicker();
picker.FileTypeChoices.Add("JPG File", new List<string>() { ".jpg" });
StorageFile file = await picker.PickSaveFileAsync();
if (file != null)
{
await (wb as WriteableBitmap).SaveAsync(file);
}
The above code successfully save image to given location with normal size.
but when i use above pixel byte array to server. Http send task cancelled exception while send request and i have detail checked on it. It is due to huge amount of Bytes array.
Also if i send a very small grid of 50x50 then uploading done successfully because it has 30 thousand bytes only but image uploaded on the server is empty or corrupted.
Also i have used above converted writeablebitmap to make its bytes array using this method...
using (Stream stream = mywriteablebitmap.PixelBuffer.AsStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
it also returns same number of bytes Array and same error occurred from server.
Please tell me the correct way of making byte array from RenderTargetBitmap and that can easily be uploaded on server.
but when i use above pixel byte array to server. Http send task cancelled exception while send request and i have detail checked on it. It is due to huge amount of Bytes array.
I totally agree with Clemens,you need to encode your image before uploading it. You can use the following codes to encode your image:
private async Task<String> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
{
var encoded = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
await encoder.FlushAsync();
encoded.Seek(0);
var bytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
var base64String=Convert.ToBase64String(bytes);
return base64String;
}
And call it in your codes:
var pixelBuffer = await bitmap.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();
await ToBase64(pixels, (uint)bitmap.PixelHeight, (uint)bitmap.PixelWidth);
For details about encoding Image in WinRT you can refer to Reading and Writing Base64 in the Windows Runtime.
After lot of searching i save the renderTargetBitmap in to isolatedstorage and then access the image file from storage and make its stream byte array using this method.
var stream = await imageStorageFile.OpenStreamForReadAsync();
imageBytes=ReadFully(stream);
public byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
now this method works perfect.
I am try to download a zip file via a url to extract files from. I would rather not have to save it a temp file (which works fine) and rather keep it in memory - it is not very big. For example, if I try to download this file:
http://phs.googlecode.com/files/Download%20File%20Test.zip
using this code:
using Ionic.Zip;
...
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.ContentLength > 0)
{
using (MemoryStream zipms = new MemoryStream())
{
int bytesRead;
byte[] buffer = new byte[32768];
using (Stream stream = response.GetResponseStream())
{
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
zipms.Write(buffer, 0, bytesRead);
ZipFile zip = ZipFile.Read(stream); // <--ERROR: "This stream does not support seek operations. "
}
using (ZipFile zip = ZipFile.Read(zipms)) // <--ERROR: "Could not read block - no data! (position 0x00000000) "
using (MemoryStream txtms = new MemoryStream())
{
ZipEntry csentry= zip["Download File Test.cs"];
csentry.Extract(txtms);
txtms.Position = 0;
using (StreamReader reader = new StreamReader(txtms))
{
string csentry = reader.ReadToEnd();
}
}
}
}
...
Note where i flagged the errors I am receiving. With the first one, it does not like the System.Net.ConnectStream. If I comment that line out and allow it to hit the line where I note the second error, it does not like the MemoryStream. I did see this posting: https://stackoverflow.com/a/6377099/1324284 but I am having the same issues that others mention about not having more then 4 overloads of the Read method so I cannot try the WebClient.
However, if I do everything via a FileStream and save it to a temp location first, then point ZipFile.Read at that temp location, everything works including extracting any contained files into a MemoryStream.
Thanks for any help.
You need to Flush() your MemoryStream and set the Position to 0 before you read from it, otherwise you are trying to read from the current position (where there is nothing).
For your code:
ZipFile zip;
using (Stream stream = response.GetResponseStream())
{
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
zipms.Write(buffer, 0, bytesRead);
zipms.Flush();
zipms.Position = 0;
zip = ZipFile.Read(zipms);
}
I have an image column in bytes in DB & location (which stores the path of the image),
if the path is empty i used image column, if the path is not empty, i load the image to a byte array and return the image as Memory stream either from file path or direct byte image column.
//query
select image,filepath from tablename;
byte[] Image = { };
if(file path is not empty)
{
System.Net.WebClient Client = new System.Net.WebClient();
Image = Client.DownloadData("Path of the image-http://....gif");
}
else
{
Image= datareader.GetOrdinal("image");
}
How do i assign a byte image to memory stream???
You can use the MemoryStream constructor that takes a byte[] instance:
byte[] data = // get data...
using (var stream = new MemoryStream(data))
{
}
If you already have an open stream, then just write the contents of the array:
stream.Write(data, 0, data.Length);