tags:

views:

82

answers:

3

I load my textures using

Texture2D.FromFile()

then draw them using

spriteBatch.Draw()

But here's the point: I want to change some colors of the image to another ones. So my questions:

  1. How to change single color of the image to another single color (eg. blue to red).

  2. In fact, what I really want to do is changing group of colors to another group of colors. For example red and similar hues to red to blue and similar hues to blue. You can do this for example in Corel PHOTO-PAINT ("Replace Color").

Please have in mind, that I'm a beginner in XNA. Best regards, Jack

EDIT:

Thank you very much for help, guys. Callum's answer is very helpful indeed. But I'm wondering is there a built-in function to solve my second problem, because writing your own may be time-consuming. And I think, that kind of function may be very useful. Something like:

color.SetNewColor(Color color_from, Color color_to, int range)

That kind of function, as I've said before, is built in Corel PHOTO-PAINT. To explain it better, here is the example of what I'm talking about:

link text

So, I only set color_from, color_to and range. I think it works like that: it checks every color of the image, if it is in range of color_from, it is changed to adequate color in hue of color_to.

+3  A: 

I assume you mean change individual pixels? In that case use the GetData() and SetData() methods of the Texture2D class.


For example, you can get an array containing the colours of the individual pixels by doing this:

// Assume you have a Texture2D called texture

Color[] data = new Color[texture.Width * texture.Height];
texutre.GetData(data);

// You now have a packed array of Colors. 
// So, change the 3rd pixel from the right which is the 4th pixel from the top do:

data[4*texture.Width+3] = Color.Red;

// Once you have finished changing data, set it back to the texture:

texture.SetData(data);

Note you can use the other overloads of GetData() to select only a section.


So, to replace each pixel of a specified colour to another colour:

// Assume you have a Texture2D called texture, Colors called colorFrom, colorTo

Color[] data = new Color[texture.Width * texture.Height];
texutre.GetData(data);

for(int i = 0; i < data.Length; i++)
    if(data[i] == colorFrom)
        data[i] = colorTo;

texture.SetData(data);

To see if hues are similar, try this method:

private bool IsSimilar(Color original, Color test, int redDelta, int blueDelta, int greenDelta)
{
    return Math.Abs(original.R - test.R) < redDelta && Math.Abs(original.G - test.G) < greenDelta && Math.Abs(original.B - test.B) < blueDelta;
}

where *delta is the tolerance of change for each colour channel that you want to accept.


To answer your edit, no there is a built in function, but you can just use a mixture of ideas from the two sections above:

Color[] data = new Color[texture.Width * texture.Height];
texutre.GetData(data);

for(int i = 0; i < data.Length; i++)
    if(IsSimilar(data[i], colorFrom, range, range, range))
        data[i] = colorTo;

texture.SetData(data);
Callum Rogers
"To answer your edit, no there is a built in function, but you can just use a mixture of ideas from the two sections above:"Well, it is definitely not that easy, but I'll try to write the function I was talking about, when I'll find some time. If anybody could post something helpful, I'll be thankful.
Jack
+1  A: 

Callum hit it on the head if you are changing the color of 2D images as it seems you are - but as you can see you actually need to determine the actual pixel you want to modify and edit it rather than "replace yellow with green" for example.

The same logic could be used to do this replacement (simply loop through the pixels of the image and check the color - I can say that be wary when editing textures like this though as they seemed to cause some pretty serious spikes in performance depending on what was done and how often. I didn't fully investigate but I think it was causing quite a bit of garbage collection.

David Larrabee
You are correct with garbage collection causing a performance spike as `Color[]` arrays are allocated and assigned data to. You can remedy this by creating your own type that stores the current `Color[]` data array and the texture it is from and then just changing the array then using `SetData()` each time - it is noticeably faster but comes at the cost of increased memory usage.
Callum Rogers
+1  A: 

Callum's solution is powerful and flexible.

A more limited solution that is slightly easier to implement is to leverage the spriteBatch color parameter.

The variables

Texture2D sprite; //Assuming you have loaded this somewhere
Color color = Color.Red; //The color you want to use
Vector2 position = new Vector2(0f, 0f); //the position to draw the sprite

The drawing code

//Start the spriteBatch segment, enable alpha blending for transparency    
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

//Draw our sprite at the specified position using a specified color
spriteBatch.Draw(sprite, position, color);

//end the spritebatch
spriteBatch.End();

If your sprite is all white, then using this method will turn your sprite red. Also, make sure you are using a file format with transparency in it, PNG is a favorite.

Error 454