it Would be nice to have a fast color replace function for Image.
My current solution to get the idea.
void Image::replace_color(const Color &old_c, const Color &new_c) {
if(old_c!=new_c) {
lock();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if(get_pixel(x,y)==old_c) {
set_pixel(x, y, new_c);
}
}
}
unlock();
}
}
Your idea is good, but please let me give a couple of suggestions:
get/set_pixel(), but if they are actual functions you are doing too much for an inner loop. If possible, your function should be responsible of computing and advancing the pointer to each pixel. If the pointer was tagged as _restrict, even better.Given color is float, this is kinda difficult..
On Jul 12, 2017 7:13 PM, "Pedro J. Estébanez" notifications@github.com
wrote:
Your idea is good, but please let me give a couple of suggestions:
- Right now I don't remember the exact implementation of
get/set_pixel(), but if they are actual functions you are doing too
much for an inner loop. If possible, your function should be responsible of
computing and advancing the pointer to each pixel. If the pointer was
tagged as _restrict, even better.- It would be more useful if instead of replacing just one color value
with another, it could work on a color range, with a tolerance, more or
less the way color replace works in Photoshop.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/9623#issuecomment-314912890,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AF-Z278k5reDvmykDL0_tHcAYcrFOLGjks5sNUUEgaJpZM4OWKbs
.
Well usually this use case is for pixel art, where colors are almost always 8-bit integers, which is however harder to do with a float color API. You have to use a short color range to prevent a precision mistake. That seems fine if it's for baking sprites offline, but replacing a color by another can also be done with shaders in realtime.
If there is a CIELab color implementation within Godot, then using a range within that space based on Euclidian distance would be nice from a perceptual standpoint. I'm not sure how important this is for a game engine, but it's an idea. The range then gets you some precision error protection and a fancy 'soft' color selection.
As it does not seems to be a recurring use-case, shouldn't it be more appropriate to let such feature be developed in a custom module ?
It seems indeed quite limited to low-res pixel art games, so I'm not sure if it's really meaningful to add it to the Image API. The main reason would be if the GDScript version is really too slow, did you test it?
Agree with @akien-mga and @ducdetronquito, this seems to be a very specific feature that should not be into the API.
In any case, this can be implemented as a shader, which seems to be the appropriate place to do such processing.
True @groud
One use case is an ability to convert image with transparency to color. I figured I could just use:
image.convert(Image.FORMAT_RGB8)
so that transparancy will be replaced with black color automatically. This one is a rather specific use case to allow exporting cross-game compatible assets for legacy games that can't handle transparency.
Also see more practical use case below in the issue #26493.
Also including GDScript version of replace_color:
static func replace_color(p_image: Image, p_old_c: Color, p_new_c: Color):
if p_old_c == p_new_c:
return
p_image.lock()
for y in p_image.get_height():
for x in p_image.get_width():
if p_image.get_pixel(x, y) == p_old_c:
p_image.set_pixel(x, y, p_new_c)
p_image.unlock()
Most helpful comment
Agree with @akien-mga and @ducdetronquito, this seems to be a very specific feature that should not be into the API.
In any case, this can be implemented as a shader, which seems to be the appropriate place to do such processing.