This is the problem:
I save a Bitmap in .png with colors say ARGB(50,210,102,70) with dimension 1 x 1 pixel.
I retrieve the same image again and use the GetPixel(0,0) method, what I get is ARGB(50,209,102,70).
There is a slight variation in the retrieved value, the RGB values slightly differ but the A value remains same.
However when i use 255 for A value, the correct RGB values are returned.
So,.. Using a value less than 255 for A results in the problem mentioned above.
Here is the code which saves the Bitmap.
Bitmap bmpPut = new Bitmap(1, 1); //Also tried with 'PixelFormat.Format32bppArgb'
bmpPut.SetPixel(0, 0, Color.FromArgb(254, 220, 210, 70));
bmpPut.Save("1.png"); //Also tried with using 'ImageFormat.Png'
Here is the code which gets the pixel color
Bitmap bit = new Bitmap(Image.FromFile("1.png"));
MessageBox.Show("R:" + bit.GetPixel(0, 0).R.ToString() +
"| G: " + bit.GetPixel(0, 0).G.ToString() +
"| B: " + bit.GetPixel(0, 0).B.ToString() +
"| A: " + bit.GetPixel(0, 0).A.ToString());
What i get is ARGB(254,219,209,70)
P.S.: I read a few similar questions, they were'nt addressing this exact issue and I din't find a solution yet.
mammago has found a workaround, namely using the class constructor to construct a Bitmap object directly from a file, rather than constructing a Bitmap object indirectly via the Image object returned by Image.FromFile().
The purpose of this answer is to explain why that works, and in particular, what the actual difference is between the two approaches that causes different per-pixel color values to be obtained.
One proposal for the difference was color management. However, this appears to be a non-starter, as neither invocation is asking for color-management (ICM) support.
You can, however, tell a lot by inspecting the source code for the .NET BCL. In a comment, mammago posted links to the code for the Image and Bitmap class implementations, but wasn't able to discern the relevant differences.
Let's start with the Bitmap class constructor that creates a Bitmap object directly from a file, since that's the simplest:
public Bitmap(String filename) {
IntSecurity.DemandReadFileIO(filename);
// GDI+ will read this file multiple times. Get the fully qualified path
// so if our app changes default directory we won't get an error
filename = Path.GetFullPath(filename);
IntPtr bitmap = IntPtr.Zero;
int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromFile(filename, out bitmap);
if (status != SafeNativeMethods.Gdip.Ok)
throw SafeNativeMethods.Gdip.StatusException(status);
status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != SafeNativeMethods.Gdip.Ok) {
SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw SafeNativeMethods.Gdip.StatusException(status);
}
SetNativeImage(bitmap);
EnsureSave(this, filename, null);
}
Lots of stuff going on there, but most of it is not relevant. The first bits of code simply obtain and validate the path. After that is the important bit: a call to the native GDI+ function, GdipCreateBitmapFromFile, one of the many Bitmap-related functions provided by the GDI+ flat API. It does exactly what you would think, it creates a Bitmap object from a path to an image file without using color matching (ICM). This is the function that does the heavy lifting. The .NET wrapper then checks for errors and validates the resulting object again. If validation fails, it cleans up and throws an exception. If validation succeeds, it saves the handle in a member variable (the call to SetNativeImage), and then calls a function (EnsureSave) that does nothing unless the image if a GIF. Since this one isn't, we'll ignore that completely.
Okay, so conceptually, this is just a big, expensive wrapper around GdipCreateBitmapFromFile that performs a bunch of redundant validation.
What about Image.FromFile()? Well, the overload you're actually calling is just a stub that forwards to the other overload, passing false to indicate that color matching (ICM) is not desired. The code for the interesting overload is as follows:
public static Image FromFile(String filename,
bool useEmbeddedColorManagement) {
if (!File.Exists(filename)) {
IntSecurity.DemandReadFileIO(filename);
throw new FileNotFoundException(filename);
}
// GDI+ will read this file multiple times. Get the fully qualified path
// so if our app changes default directory we won't get an error
filename = Path.GetFullPath(filename);
IntPtr image = IntPtr.Zero;
int status;
if (useEmbeddedColorManagement) {
status = SafeNativeMethods.Gdip.GdipLoadImageFromFileICM(filename, out image);
}
else {
status = SafeNativeMethods.Gdip.GdipLoadImageFromFile(filename, out image);
}
if (status != SafeNativeMethods.Gdip.Ok)
throw SafeNativeMethods.Gdip.StatusException(status);
status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, image));
if (status != SafeNativeMethods.Gdip.Ok) {
SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, image));
throw SafeNativeMethods.Gdip.StatusException(status);
}
Image img = CreateImageObject(image);
EnsureSave(img, filename, null);
return img;
}
This looks very much the same. It validates the file name in a slightly different way, but that isn't failing here, so we can ignore these differences. If embedded color management was not requested, it delegates to another native GDI+ flat API function to do the heavy lifting: GdipLoadImageFromFile.
Others have speculated that the difference may be a result of these two different native functions. It's a good theory, but I disassembled these functions, and though they have distinct implementations, there are no salient differences that would account for the behavior observed here. GdipCreateBitmapFromFile will perform validation, attempt to load a metafile if possible, and then call down to the constructor for an internal GpBitmap class to do the actual loading. GdipLoadImageFromFile is implemented similarly, except that it arrives at the GpBitmap class constructor indirectly via the internal GpImage::LoadImage function. Furthermore, I was unable to reproduce the behavior you described by calling these native functions directly in C++, so that eliminates them as candidates for an explanation.
Interestingly, I was also unable to reproduce the behavior you describe by casting the result of Image.FromFile to a Bitmap, e.g.:
Bitmap bit = (Bitmap)(Image.FromFile("1.png"));
Although not a good idea to rely on it, you can see that this is actually legal if you go back to the source code for Image.FromFile. It calls the internal CreateImageObject function, which delegates either to Bitmap.FromGDIplus to Metafile.FromGDIplus according to the actual type of the image being loaded. The Bitmap.FromGDIplus function just constructs a Bitmap object, calls the SetNativeImage function we have already seen to set its underlying handle, and returns that Bitmap object. Therefore, when you load a bitmap image from a file, Image.FromFile actually returns a Bitmap object. And this Bitmap object behaves identically to one created using the Bitmap class constructor.
The key to reproducing the behavior is to create a new Bitmap object based on the result of Image.FromFile, which is what exactly your original code did:
Bitmap bit = new Bitmap(Image.FromFile("1.png"));
This will call the Bitmap class constructor that takes an Image object, which delegates internally to one that takes explicit dimensions:
public Bitmap(Image original, int width, int height) : this(width, height) {
Graphics g = null;
try {
g = Graphics.FromImage(this);
g.Clear(Color.Transparent);
g.DrawImage(original, 0, 0, width, height);
}
finally {
if (g != null) {
g.Dispose();
}
}
}
And here is where we finally find an explanation for the behavior you describe in the question! You can see that it creates a temporary Graphics object from the specified Image object, fills the Graphics object with a transparent color, and finally draws a copy of the specified Image into that Graphics context. At this point, it is not the same image you're working with, but a copy of that image. This is where color matching can kick in, as well as a variety of other things that potentially affect the image.
In fact, aside from the unexpected behavior described in the question, the code you had written hid a bug: it fails to dispose the temporary Image object created by Image.FromFile!
Mystery solved. Apologies for the long, indirect answer, but hopefully it has taught you something about debugging! Do continue to use the solution recommended by mammago, as it is both simple and correct.
Replacing
Bitmap bit = new Bitmap(Image.FromFile("1.png"));
with
Bitmap bit = new Bitmap("1.png");
Should do the trick.
It seems like Image.FromFile() isn't as precise as the Bitmap constructor.
This question is specific to System.Drawing.Bitmap.
Consider this situation: I create a bitmap like so
public Bitmap GetImage(string sourceImage)
{
//sourceImage contains something like "C:\\Users\\my.name\\path\\to\\image.jpg"
//error/valid filename checking omitted in this example
Bitmap img = new Bitmap(sourceImage);
return img;
}
Now my code goes and does things with that Bitmap. Later, an unrelated section of the code decides that it is done with that image and it doesn't need to retain the Bitmap object anymore. However, there is a chance that it will be needed again, so it wants to remember what sourceImage was so that if it does need it again, it knows how to recreate it. This is mostly due to memory; storing a pathway string takes less space than storing a (potentially) large image.
Does a Bitmap remember where it came from, or must it carry around that information with it?
I considered just assigning sourceImage to the Tag property, however I'm using Tag for other things and I'd rather not overcomplicate it. I'm hoping the source information is still accessible to save me the trouble.
I would recommend creating a container class to provide the extra functionality
class BitmapContainer : IDisposable
{
Bitmap Value {get; private set;}
string OriginalLocation {get; private set;}
public BitmapContainer(string sourceImage)
{
Value = new Bitmap(sourceImage);
OriginalLocation = sourceImage;
//you get the picture
}
//Don't forget to implement a dispose pattern because Bitmap uses native resources
}
You could even make the bitmap getter intelligent and load the Bitmap if not currently loaded, and have another method for unloading (Dispose and set to null) until needed again
Background:
I'm building an application which will open a potentially large number of photos, generate a thumbnail to present to the user, then allow things like exif data viewing/clearing and minor post processing.
I want to allow the user to scroll through the images without pausing to load each one as it becomes visible, but I also don't want to keep dozens or hundreds of full size bitmap images in memory.
I had built a prototype of this task using System.Drawing using Image objects and their GenerateThumbnailImage method, but decided to move to WPF and use System.Windows.Media.ImageSource derived objects and the TransformedBitmap with a ScaledTransform to generate the thumbnail.
What I found, though, is that when I create a TransformedBitmap, it has a reference back to the source image, which is available and still present in memory. How do I release this source object?
Some relevant C# code:
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using System;
...
private void LoadImage(){
//Called by my class internally to handle generating the thumbnail
//Intent is to keep only metadata and a thumbnail bitmap in memory
Stream handle = File.OpenRead(FileName);
BitmapDecoder source = BitmapDecoder.Create(handle,BitmapCreateOptions.None,BitmapCacheOption.OnLoad);
handle.Dispose();
//Determine a scaling ratio to force the larger of height or width to fit inside my desired thumbnail size (int)MaxDim.
ScaleRatio = Math.Min(MaxDim/Math.Max(source.Frames[0].PixelHeight,source.Frames[0].PixelWidth),1); //a public member of the class, Double
_ImageSource = new TransformedBitmap(source.Frames[0],new ScaleTransform(ScaleRatio,ScaleRatio)); //private member of the class, ImageSource
_ImageSource.Freeze();
_Exif = source.Frames[0].Metadata; //private member of the class, ImageMetadata
}
The problem here is that while I hoped that the (BitmapDecoder)source would be released, I can still access the object via _ImageSource.Source.
I have considered using CopyPixels or encoding the TransformedBitmap back into a byte[] stream to create a new, hopefully unattached bitmap, but both of those methods seem like unnecessary reprocessing if I can just abandon or dispose of the source or if there is some simple and fast way to create a shallow clone that I haven't discovered. My attempt at a shallow clone using BitmapFrame.Create(TransformedBitmap) doesn't free the memory either, but also doesn't leave me with an obvious reference.
Some testing watching memory consumption shows each image loaded costs about 30MB. An approximately 200x200#32bpp image should be about 160kB, not counting overhead.
The question again as a TL;DR: how do I release the reference to the source bitmap after a TransformedBitmap uses it?
Is there a way to access the underlying memory of a BitmapImage object with c# pointers?
I know that there's a CopyPixels method but it makes a copy of the pixels array into a new array (duplicating memory requirements). If you open a large image (2gb) it allocates a lot of un-useful stuff. And if you want to operate some sort of elaboration, like CCLA, it takes a huge amount of memory.
I need only to read the pixel array.
Is it possible to address pixels directly like you can do in System.Drawing.Bitmap?
I wrote a fast bitmap access for System.Drawing.Bitmap, but as I'm using WPF, I need the same functionality for BitmapSource. Otherwise I have to duplicate the image loading (Bitmap for my old method and BitmapSource to show the image in WPF) taking a lot of memory and time.
Thank you
Lorenzo
A bitmap source does not necessarily have backing memory for the entire image. An example of when it does not would be an image file on disk which is lazy loaded.
The only access you have with WIC, and therefore WPF, is the CopyPixels method. Certain subclasses of BitmapSource will allow access to a buffer, but they are internally just allocating memory and calling CopyPixels themselves.
I would assume that whatever operation does not require access to the entire image at a time. If so, you can call CopyPixels to a smaller buffer, and window your access to the image. Most decoders, when a single pixel is requested, will buffer the entire stride, or in the case of JPEG, then entire block.
I am not sure what CCLA is, and cannot find a definition that seems to fit, but if it is some sort of transform on the source image, you can implement it as a BitmapSource. That way, you can compose a full chain which will
read the image from disk (TiffBitmapEncoder et al.)
scale or translate them (TransformedBitmap)
then window it to only the portion you need (CroppedBitmap)
use a format conversion (FormatConvertedBitmap)
pass it to your algorithm (CclaTransformBitmap)
and finally render it to a WritableBitmap, which gives you access to the buffer
With careful attention to the CacheOption used on the source image, as well as the order of transforms, you should be able to access an arbitrarily large image without significant memory impact.
If you already have a performant algorithm for GDI (System.Drawing), there is no sense re-implementing it. You can still display your final bitmap using Imaging.CreateBitmapSourceFromHBitmap or by using a WindowsFormsHost to host the control you previously built.
I have a function that takes in a Handle to an image:
DoSomethingWithImage( int imageHandle)
{
}
In my main, I have an Image myImage, which resides in memory.
How can I get a Handle to myImage, so that I can pass in that Handle to DoSomethingWithImage() ?
main()
{
//memorySTream is a byte[]
Image myImage = Image.FromStream(memoryStream, true);
DoSomethingWithImage( ??? );
}
Image is just the abstract base class; descendants aren't necessarily guaranteed to even have a Windows handle. You need to know the specific type of image - and so does the SDK you're using, most likely; it is probably assuming that the handle corresponds to a specific format (I would guess bitmap).
If the image is in fact a Bitmap, then you would want to use the Bitmap.GetHbitmap method. On the other hand, if the image is really a Metafile, then you need to use the Metafile.GetHenhmetafile method to get a handle.