views:

492

answers:

4

My scenario:

  • I have one color background image JPG.
  • I have one black text on white background JPG.
  • Both images are the same size (height and width)

I want to overlay the image with black text and white background over the color background image, i.e. the white background becomes transparent to see the color background beneath it.

How can I do this with GDI in C#?

Thanks!

+1  A: 

If the images are the same size, iterate over them and "AND" the colors for each pixel. For the white pixels, you should get the color of the other image, and for the black ones you should get black.

If they're not the same size, scale first.

I'm making this up off the top of my head, but something like:

Color destColor = Color.FromArgb(pixel1.ToArgb() & pixel2.ToArgb());
GalacticCowboy
This might work, both images are the same size. Can you provide a quick code snippet or a link to one?
Bryan Denny
You cannot AND color objects directly, you will need to AND the component values.
Ed Swangren
That's what I did. ??
GalacticCowboy
Thanks, I used this to come up with a solution: http://stackoverflow.com/questions/1071374/merging-jpgs-with-gdi-in-c/1074302#1074302
Bryan Denny
You AND a Color object with an int. FromArgb returns a "Color", ToArgb return an int.
Ed Swangren
@Ed - I still don't see what you're seeing. Please read my code and tell me EXACTLY how I'm not doing EXACTLY what you say I need to do???????
GalacticCowboy
PS - I know exactly what error you think I made; I'm just trying to point out that you mis-read my code and are complaining about an error that DOES NOT EXIST.
GalacticCowboy
A: 

check out this article. it give you code for making a specified color as the transparent color in your image http://www.codedblog.com/2007/08/28/generating-a-transparent-gif-image-using-c/

Muad'Dib
That will most likely not work for a jpg image which probably contains compression artifacts.
Ed Swangren
Also, that method is specific to GIF images, MakeTransparent() works for pngs, but not sure about jpg's as they do not inherently support alpha channels (though I am not sure of the implementation, that fact probably does not matter).
Ed Swangren
true, it is for GIF's, not JPG's
Muad'Dib
+2  A: 

Thanks to GalacticCowboy I was able to come up with this solution:

using (Bitmap background = (Bitmap)Bitmap.FromFile(backgroundPath))
{
     using (Bitmap foreground = (Bitmap)Bitmap.FromFile(foregroundPath))
     {
          // check if heights and widths are the same
          if (background.Height == foreground.Height & background.Width == foreground.Width)
          {
               using (Bitmap mergedImage = new Bitmap(background.Width, background.Height))
               {
                    for (int x = 0; x < mergedImage.Width; x++)
                    {
                         for (int y = 0; y < mergedImage.Height; y++)
                         {
                              Color backgroundPixel = background.GetPixel(x, y);
                              Color foregroundPixel = foreground.GetPixel(x, y);
                              Color mergedPixel = Color.FromArgb(backgroundPixel.ToArgb() & foregroundPixel.ToArgb());
                              mergedImage.SetPixel(x, y, mergedPixel);
                          }
                    }
                    mergedImage.Save("filepath");
               }

          }
     }
}

Works like a charm. Thanks!

Bryan Denny
Looks good. Glad it helped you out.
GalacticCowboy
+1  A: 

There exist easier and faster way. You should use ImageAttributes when you draw image that must be partially visible.

Image BackImage = Image.FromFile(backgroundPath);
using (Graphics g = Graphics.FromImage(BackImage))
{
    using (ForeImage = Image.FromFile(foregroundPath))
    {   
        ImageAttributes imageAttr = new ImageAttributes();
        imageAttr.SetColorKey(Color.FromArgb(245, 245, 245), Color.FromArgb(255, 255, 255),
            ColorAdjustType.Default);
        g.DrawImage(ForeImage, new Rectangle(0, 0, BackImage.Width, BackImage.Height),
            0, 0, BackImage.Width, BackImage.Height, GraphicsUnit.Pixel, imageAttr);
    }
}

SetColorKey method will make color from specified range transparent, so you can make your white bitmap pixels transparent, including all pixels that are affected to jpeg compression artefacts.

arbiter
I haven't tried this, so I could be wrong, but a typical drawback of using a transparent color like this is that you get a sharp edge at the cut-over from transparent to opaque that would be softened if using another approach.
GalacticCowboy
I haven't tried it too, this snippet was written from head. But what I supposed to say, is that DrawImage has a lot of possibilities using ImageAttributes, so the authors task can be correctly done (after some additional investigation from his side) without slow pixel by pixel composition
arbiter
I guess it comes down to desired outcome - processing speed vs. image quality. I tried your approach and it is significantly faster (0.1 seconds vs. about 2 seconds, for 800x600 images) but there is a lot of noise around the edges of the text that gets blended away using my approach.
GalacticCowboy