views:

254

answers:

2

I have a source bitmap that is 1x1 and I am trying to take that image and draw it to a new bitmap. The source bitmap is all red, but for some reason the new bitmap ends up with a gradient (see image). Using the code below, shouldn't the new bitmap be completely red? Where is it getting the white/alpha from?

alt text

private void DrawImage()
{
    Bitmap bmpSOURCE = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
    using (Graphics g = Graphics.FromImage(bmpSOURCE))
    {
     g.Clear(Color.Red);
    }

    Bitmap bmpTest = new Bitmap(300, 100, PixelFormat.Format32bppArgb);
    using (Graphics g = Graphics.FromImage(bmpTest))
    {
     g.CompositingMode = CompositingMode.SourceCopy;
     g.CompositingQuality = CompositingQuality.AssumeLinear;
     g.InterpolationMode = InterpolationMode.HighQualityBicubic;
     g.PageUnit = GraphicsUnit.Pixel;
     g.PixelOffsetMode = PixelOffsetMode.None;
     g.SmoothingMode = SmoothingMode.None;

     Rectangle rectDest = new Rectangle(0, 0, bmpTest.Width, bmpTest.Height);
     Rectangle rectSource = new Rectangle(0, 0, 1, 1);
     g.DrawImage(bmpSOURCE, rectDest, rectSource, GraphicsUnit.Pixel);
    }

    pictureBox1.Image = bmpTest;
}
+6  A: 

This is not a good way to fill an area with a color. A better approach would be to determine the color of the pixel in the source image and use that color to fill the target.

Bitmap source = // get the source

Color color = source.GetPixel(1, 1);

Bitmap target = // get the target    

target.Clear(color);

Nonetheless, the problem is likely the InterpolationMode, as this is what's used when scaling images. Try using Low istead of HighQualityBicubic.

g.InterpolationMode = InterpolationMode.Low;
Adam Robinson
I'm not actually using this to fill an area with a color, this is just a small program to demonstrate the issue. I have tried some different InterpolationMode settings, and the only one that works is NearestNeighbor. That fixes the problem, but I'm still confused as to why the destination image isn't all red? Why would it randomly blend the red with the white?
Jon Tackabury
@Jon: The `InterpolationMode` determines the behavior when scaling images, which is what you're doing here. GDI doesn't (by default) scale images simply by copying or removing pixels on fixed intervals, since that generally yields low-quality results. Instead, it interpolates the new pixels using various algorithms, the specific one being determined by the value of `InterpolationMode`. See http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.interpolationmode.aspx for more information.
Adam Robinson
Excellent, thanks!
Jon Tackabury
The reason it gives you the alpha is due to filtering (http://en.wikipedia.org/wiki/Texture_filtering). In order to provide better looking textures when they are resized the pixels are interpolated smoothly from one color to the next. In your case with filtering on you are seeing the red pixel being interpolated with a pure transparent pixel (sensible since your single pixel has no neighbors to interpolate with). Nearest neighbor interpolation does NO filtering and thus solves your problem.
Ron Warholic
Changing the InterpolationMode to NearestNeighbor does give solid colours, but now it only fills half the image. So instead of an image that is 100px wide with a gradient, I've got an image that is 100px with the left half red and the right half white. Still no good. :(
Jon Tackabury
Relying on interpolation to fill your region is the wrong way to fill a region. Use Graphics.Clear if you intend to clear the entire bitmap or use Graphics.FillRectangle if you want to fill a region.
Ron Warholic
I need to take an image of a unknown size and draw it onto another larger image. Sometimes the source image might be 50x50, sometimes it might be 1x1.
Jon Tackabury
@Jon: I think 1x1 may be a corner case. I would experiment with a 2x2 image and see if you have more success. If that's the case, then I would handle 1x1 images differently using the method described above. Will all images be a have equal height and width, or could you have a 1x2 image?
Adam Robinson
The source images could be any size. A 2x2 image works well onto a small destination image, but not a larger one. It looks like I'm going to have to roll my own image drawing function here to get predictable results.
Jon Tackabury
A: 

Hi,

I found this as solution to your problem,

g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic;

Kind Regards

MMsoft Team