When im passing Bmp as stream, function always return,
D4-1D-8C-D9-8F-00-B2-04-E9-80-09-98-EC-F8-42-7E
but file saving on disk correctly.
When I load bpm from disk, function return correct MD5. Also passing "new Bitmap(int x, int y);" with different value return same MD5.
Why its happening?
public static string GetMD5Hash()
{
Bitmap Bmp = new Bitmap(23, 46); //
using (Graphics gfx = Graphics.FromImage(Bmp))
using (SolidBrush brush = new SolidBrush(Color.FromArgb(32, 44, 2)))
{
gfx.FillRectangle(brush, 0, 0, 23, 46);
}
using (var md5 = MD5.Create())
{
using (MemoryStream memoryStream = new MemoryStream())
{
Bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
\//EDITED: Bmp.Save(#"C:\Test\pizdanadysku.bmp"); // Here saving file on disk, im getting diffrent solid color
return BitConverter.ToString(md5.ComputeHash(memoryStream)); //Always return D4-1D-8C-D9-8F-00-B2-04-E9-80-09-98-EC-F8-42-7E - I noticed that is MD5 of empty 1x1px Bmp file
}
}
}
Can somebody explain this strange behaviour?
Stream operations tend to only move forward for various reasons (including the fact some streams can only be read, E.g NetworkStream), so saving the image is likely just progressing the stream to the end.
Additionally, and pointed out by various helpful editors (#jpa).
D4-1D-8C-D9-8F-00-B2-04-E9-80-09-98-EC-F8-42-7E
Is the classic MD5 sum of an empty string.
My gut feeling is you just need to reset the position of the stream to get your desired result
memoryStream.Seek(0, SeekOrigin.Begin)
// or
memoryStream.Position = 0;
Related
HalconDotNet.HOperatorSet.ReadImage(out HObject image, srcPath);
//...
//(graphic stuff)
//...
HalconDotNet.HOperatorSet.WriteImage(imagePart, "png", 0, tmpImgPath); // skip these steps
Image = File.ReadAllBytes(path) // skip these steps
This piece of code is executed thousands of times. The last two steps are just there to have a compatibility step in between Halcon and .NET as I dont know how to combine them.
What I need is a way to convert a HImage(HObject) to a byte[], the same way WriteImage() + File.ReadAllBytes(path) would do. This last bit is important as this piece of code generates inputs for image classification models.
As the models are trained with data loaded from disk with File.ReadAllBytes(path) I'm assuming I need to prepare the data in the same way when using the model. When I read a 100x100 color PNG (solid color) with File.ReadAllBytes() I don't get 100x100x3 bytes, but 342, so I'm assuming the data is still compressed, and further assuming that I need to guarantee similar data when using the model.
This question has some overlap with this one but I need a byte[] instead of bitmap and just can't get it to work.
Can you try?
public static byte[] ImageToByte(Image image)
{
using (var stream = new MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
Or
Image image = Image.FromFile(imagePath);
byte[] byteArr = new byte[] { };
using (var ms = new MemoryStream())
{
image.Save(ms, image.RawFormat);
byteArr = ms.ToArray();
}
For Image you will need System.Drawing
I am trying to add some rectangles to an existing image. When using the following code, everything works fine:
var bytes = File.ReadAllBytes("myPath\\input.jpg");
var stream = new MemoryStream(bytes);
using (var i = new Bitmap(stream))
{
using (var graphics = Graphics.FromImage(i))
{
var selPen = new Pen(Color.Blue);
graphics.DrawRectangle(selPen, 10, 10, 50, 50);
i.Save("myPath\\output.jpg", ImageFormat.Jpeg);
}
}
But saving the image to the same MemoryStream and then later writing all bytes to a file gives me an almost grey-only image.
This does not work:
var bytes = File.ReadAllBytes("myPath\\input.jpg");
var stream = new MemoryStream(bytes);
using (var i = new Bitmap(stream))
{
using (var graphics = Graphics.FromImage(i))
{
var selPen = new Pen(Color.Blue);
graphics.DrawRectangle(selPen, 10, 10, 50, 50);
i.Save(stream, ImageFormat.Jpeg);
}
}
File.WriteAllBytes("myPath\\output.jpg", stream.ToArray());
The (wrong) image looks like this:
As you can see, only part of the image is grey. There still is some part visible (the white one) of the actual image.
Why is this happening and what is the correct solution?
Thanks!
You've double-written to the Stream in the second example; it still contains the original data, and then you've appended more data with the Save. Stream works like a video tape (sort of). If you want to overwrite the stream, you need to do that very carefully (and: not all streams even support that concept - think "network stream", "encryption stream", etc). Note that ToArray (and the GetBuffer / TryGetBuffer methods) see all the data, not just what you're thinking of as the "new" data (a concept that doesn't even exist, really - like a video tape, you only have the "current" position and the length - if you need to know where the first show ends and the second show starts, you need to note that yourself, manually). In this case, adding:
stream.Position = 0; // rewind
stream.SetLength(0); // truncate (important in case the new data is *shorter* than the old)
after reading it and before Save, should fix it.
You are saving the image to an already initialized stream from a byte array.
Create a new stream and save to it.
var stream2 = new MemoryStream();
i.Save(stream2, ImageFormat.Jpeg);
Or simply reset the previous one
memoryStream = new MemoryStream(stream.Capacity());
i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.
this is the code:
[TestMethod]
public void TestMethod1()
{
// Grab the binary data.
byte[] data = File.ReadAllBytes("Chick.jpg");
// Read in the data but do not close, before using the stream.
Stream originalBinaryDataStream = new MemoryStream(data);
Bitmap image = new Bitmap(originalBinaryDataStream);
image.Save(#"c:\test.jpg");
originalBinaryDataStream.Dispose();
// Now lets use a nice dispose, etc...
Bitmap2 image2;
using (Stream originalBinaryDataStream2 = new MemoryStream(data))
{
image2 = new Bitmap(originalBinaryDataStream2);
}
image2.Save(#"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}
Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).
I'm really confused :(
As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)
However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:
You must keep the stream open for the
lifetime of the Bitmap.
I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.
A generic error occurred in GDI+.
May also result from incorrect save path!
Took me half a day to notice that.
So make sure that you have double checked the path to save the image as well.
Perhaps it is worth mentioning that if the C:\Temp directory does not exist, it will also throw this exception even if your stream is still existent.
Copy the Bitmap. You have to keep the stream open for the lifetime of the bitmap.
When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI
public static Image ToImage(this byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var image = Image.FromStream(stream, false, true))
{
return new Bitmap(image);
}
}
[Test]
public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
{
var imageBytes = File.ReadAllBytes("bitmap.bmp");
var image = imageBytes.ToImage();
image.Save("output.bmp");
}
I had the same problem but actually the cause was that the application didn't have permission to save files on C. When I changed to "D:\.." the picture has been saved.
You can try to create another copy of bitmap:
using (var memoryStream = new MemoryStream())
{
// write to memory stream here
memoryStream.Position = 0;
using (var bitmap = new Bitmap(memoryStream))
{
var bitmap2 = new Bitmap(bitmap);
return bitmap2;
}
}
This error occurred to me when I was trying from Citrix. The image folder was set to C:\ in the server, for which I do not have privilege. Once the image folder was moved to a shared drive, the error was gone.
A generic error occurred in GDI+. It can occur because of image storing paths issues,I got this error because my storing path is too long, I fixed this by first storing the image in a shortest path and move it to the correct location with long path handling techniques.
I was getting this error, because the automated test I was executing, was trying to store snapshots into a folder that didn't exist. After I created the folder, the error resolved
One strange solution which made my code to work.
Open the image in paint and save it as a new file with same format(.jpg). Now try with this new file and it works. It clearly explains you that the file might be corrupted in someway.
This can help only if your code has every other bugs fixed
It has also appeared with me when I was trying to save an image into path
C:\Program Files (x86)\some_directory
and the .exe wasn't executed to run as administrator, I hope this may help someone who has same issue too.
For me the code below crashed with A generic error occurred in GDI+on the line which Saves to a MemoryStream. The code was running on a web server and I resolved it by stopping and starting the Application Pool that was running the site.
Must have been some internal error in GDI+
private static string GetThumbnailImageAsBase64String(string path)
{
if (path == null || !File.Exists(path))
{
var log = ContainerResolver.Container.GetInstance<ILog>();
log.Info($"No file was found at path: {path}");
return null;
}
var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;
using (var image = Image.FromFile(path))
{
using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
{
using (var memoryStream = new MemoryStream())
{
thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here
var bytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes, 0, bytes.Length);
}
}
}
}
I came across this error when I was trying a simple image editing in a WPF app.
Setting an Image element's Source to the bitmap prevents file saving.
Even setting Source=null doesn't seem to release the file.
Now I just never use the image as the Source of Image element, so I can overwrite after editing!
EDIT
After hearing about the CacheOption property(Thanks to #Nyerguds) I found the solution:
So instead of using the Bitmap constructor I must set the Uri after setting CacheOption BitmapCacheOption.OnLoad.(Image1 below is the Wpf Image element)
Instead of
Image1.Source = new BitmapImage(new Uri(filepath));
Use:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;
See this: WPF Image Caching
Try this code:
static void Main(string[] args)
{
byte[] data = null;
string fullPath = #"c:\testimage.jpg";
using (MemoryStream ms = new MemoryStream())
using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
using (Bitmap bm = new Bitmap(tmp))
{
bm.SetResolution(96, 96);
using (EncoderParameters eps = new EncoderParameters(1))
{
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
}
data = ms.ToArray();
}
File.WriteAllBytes(fullPath, data);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
return encoders[j];
}
return null;
}
I used imageprocessor to resize images and one day I got "A generic error occurred in GDI+" exception.
After looked up a while I tried to recycle the application pool and bingo it works. So I note it here, hope it help ;)
Cheers
I was getting this error today on a server when the same code worked fine locally and on our DEV server but not on PRODUCTION. Rebooting the server resolved it.
public static byte[] SetImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
public static Bitmap SetByteToImage(byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}
I have read the posts on this subject but none of them explains it to me clearly enough to be able to fix the problem.
I am trying to upload a file from a local directory to the server.
Here is my code:
string fullPath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory + #"Images\Readings", PhotoFileName);
Stream s = System.IO.File.OpenRead(fileUpload);
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, Convert.ToInt32(s.Length));
using (FileStream fs = new FileStream(fullPath, FileMode.Create))
{
fs.Write(buffer, 0, Convert.ToInt32(fs.Length));
Bitmap bmp = new Bitmap((Stream)fs);
bmp.Save(fs, ImageFormat.Jpeg);
}
I keep on getting an Argument Exception: "Parameter is not valid" on line:
Bitmap bmp = new Bitmap((Stream)fs);
Can anyone explain this to me please
There are at least two problems, probably three. First, your copying code is broken:
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, Convert.ToInt32(s.Length));
You've assumed that this will read all of the data in a single Read call, and ignored the return value for Read. Generally, you'd need to loop round, reading data and writing it (the amount you've just read) to the output stream, until you read the end. However, as of .NET 4, Stream.CopyTo makes this much simpler.
Next is how you're creating the bitmap:
using (FileStream fs = new FileStream(fullPath, FileMode.Create))
{
fs.Write(buffer, 0, Convert.ToInt32(fs.Length));
Bitmap bmp = new Bitmap((Stream)fs);
bmp.Save(fs, ImageFormat.Jpeg);
}
You're trying to read from the stream when you've just written to it - but without "rewinding"... so there's no more data left to read.
Finally, I would strongly advise against using Bitmap.Save to write to the same stream that you're loading the bitmap from. Bitmap will keep a stream open, and read from it when it needs to - if you're trying to write to it at the same time, that could be very confusing.
It's not clear why you're using Bitmap at all, to be honest - if you're just trying to save the file that was uploaded, without any changes, just use:
using (Stream input = File.OpenRead(fileUpload),
output = File.Create(fullPath))
{
input.CopyTo(output);
}
This is assuming that fileUpload really is an appropriate filename - it's not clear why you haven't just written the file to the place you want to write it to straight away, to be honest. Or use File.Copy to copy the file. The above code should work with any stream, so you can change it to save the stream straight from the request...
I'm taking a Stream convert it to Image, process that image, then return a FileStream.
Is this a performance problem? If not, whats the optimized way to convert and return back a stream?
public FileStream ResizeImage(int h, int w, Stream stream)
{
var img = Image.FromStream(stream);
/* ..Processing.. */
//converting back to stream? is this right?
img.Save(stream, ImageFormat.Png);
return stream;
}
The situation in which this is running: User uploads image on my site (controller gives me a Stream, i resize this, then send this stream to rackspace (Rackspace takes a FileStream).
You basically want something like this, don't you:
public void Resize(Stream input, Stream output, int width, int height)
{
using (var image = Image.FromStream(input))
using (var bmp = new Bitmap(width, height))
using (var gr = Graphics.FromImage(bmp))
{
gr.CompositingQuality = CompositingQuality.HighSpeed;
gr.SmoothingMode = SmoothingMode.HighSpeed;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.DrawImage(image, new Rectangle(0, 0, width, height));
bmp.Save(output, ImageFormat.Png);
}
}
which will be used like this:
using (var input = File.OpenRead("input.jpg"))
using (var output = File.Create("output.png"))
{
Resize(input, output, 640, 480);
}
That looks as simple as it can be. You have to read the entire image contents to be able to process it and you have to write the result back.
FileStreams are the normal .NET way to handle files, so for normal purposes your approach is okay.
The only thing I don't understand is why you return the FileStream again - it is the same object as was passed by a parameter.
If you are doing a lot of images and only modify parts of the data, memory mapped files could improve performance. However it is a more advanced concept to use.