views:

174

answers:

2

People, i'm sure that it's quite easy, but google didn't helped...

Here is the task - i have two byte arrays (as ARGB), representing my images. They have the same size. What operation i should perform (byte by byte) to overlay one image to another? Second image has some transparency, which must be considered.

To clear, im looking for a code like this:

          bytes[] result = new bytes[first.Length];
          for(i = 0; i< first.Lenght;i++)
          {
               result[i] = first[i] !!%SOMETHING%!! second[i];
          }

Simple guesses like bitwise OR (I know - that's stupid ;) ) don't working.

Thx for your answers.

edit: i can't use standart library becouse of security issues (all this strange manipulations occur on Silverlight).

+5  A: 

Assuming that you are in fact working with bitmaps, you'll likely find it easier to just let the library do this for you.

The System.Drawing.Graphics class has a CompositingMode property that can be set to either SourceCopy (the default - overwrites the background colour) or SourceOver (blends with the background color).

See MSDN: How to Use Compositing Mode to Control Alpha Blending for more detail.

If you just want the raw math, alpha blending is pretty simple. For an alpha value a between 0.0 and 1.0, the result should be:

(aOld * oldValue) + ((1 - aOld) * aNew * newValue)

Where oldValue is the previous value before overlay, newValue is what you want to overlay with, and aOld and aNew are the old and new alpha values respectively. You obviously need to do this calculation for the R, G, and B values separately.

See also: Alpha Compositing (wiki link) for a more thorough explanation.


Update: I think it should be easy to figure out how to adapt this to the code in the OP, but I guess not everybody's a math person.

I'm going to assume that the byte[] is a repeating sequence of A, R, G, B values (so Length would be a multiple of 4). If that's not the case, then you'll have to adapt this code to whatever storage format you're using.

bytes[] result = new bytes[first.Length];
for(i = 0; i < first.Length; i += 4)
{
    byte a1 = first[i];
    byte a2 = second[i];
    byte r1 = first[i+1];
    byte r2 = second[i+1];
    byte g1 = first[i+2];
    byte g2 = second[i+2];
    byte b1 = first[i+3];
    byte b2 = second[i+3];

    byte a = a1 + (255 - a1) * a2 / 255;
    byte r = r1 * a1 / 255 + r2 * (255 - a1) * a2 / 65025;
    byte g = g1 * a1 / 255 + g2 * (255 - a1) * a2 / 65025;
    byte b = b1 * a1 / 255 + b2 * (255 - a1) * a2 / 65025;

    result[i] = a;
    result[i+1] = r;
    result[i+2] = g;
    result[i+3] = b;
}
Aaronaught
Sorry, i didn't explained fully... i need something in the way i exactly wrote. see edit pls
ALOR
@ALOR: Well it's a little hard for me to give you a solution in exactly the format you wrote, since a simple byte array tells me nothing about how the colour information is actually stored. A full ARGB value is 4 bytes (or `int`). Do you have 4 byte arrays, one for each channel? Does the array repeat, i.e. A, then R, then G, then B, then A again? Are there any headers? What's in that array?
Aaronaught
Exactly what i needed ) Thx
ALOR
A: 

I think you have the right idea. The operation you use depends on what you want for the output. Here are some operations that are useful:

  1. average - a common way to combine
  2. minimum
  3. maximum
  4. bitwise replace
  5. xor
  6. or
  7. add
  8. subtract
  9. multiply image 1 value by (image 2 scaled 0 to 1). This will put more of image 1 on the bright places of image 2 and not so much on the dark places. Try them out and see what you like best, or better yet, let the user select.

You can probable add or or the transparency bytes, and use one of the other operations for the each of the three colors.

xpda