ID:146846
 
I'm making a library to handle pixel functions. I'd like to add GetPixelColor(), of course, but unfortunately, the only way I could think of doing it is this:

icon
proc
GetPixelColor(px as num,py as num)

set background=1

var/list/result=list()
var/icon/pixel=src.GetPixel(px,py)

for(var/r=0,r<=255,r++)
for(var/g=0,g<=255,g++)
for(var/b=0,b<=255,b++)

var/icon/test=icon('trans.dmi')

test.DrawBox(rgb(r,g,b),1,1)//Draw a small 1x1 box in the southwest corner of test

test.Shift(NORTH,py-1)
test.Shift(EAST,px-1)

if(test==pixel)
result["red"]=r
result["green"]=g
result["blue"]=b
break

if(!result.len)
src << "<font color=red><tt>ERROR: No value found on GetPixelColor([px],[py])<br>src:[src]</tt></font color=red>"
return 0
else
return result


The problem? That's the most inneficient piece of code ever. In order to find a pixel color, it would have to create 256**3, or 16581375, dynamic icons. I think that Garthor, in Chatters, summed it up quite well, saying "Wizkidd, you're trying to find the product of 345 and 217 by looping through a million numbers and seeing which one is right".

Can anyone think of a way to make this more efficient? As it is now, it simply takes too long and causes too much overhead for me to even consider putting it in my library.

For those that care, GetPixel() returns a specific pixel of an icon at coordinates px,py of the icon, and px and py stand for pixel x and pixel y, respectively.

[edit]
Realized that I posted this in Design Philosophy instead of Code Problems. Moved it.
well, a faster way, but still a bit slow would be to mask out each color first and run through them one at a time, so you only test each R G B and seperately, thus only 256*3 total tests. Make a copy of the pixel icon so you dont alter the original and name it something like pixelcopy.

To mask out, you multiple the icon like this

pixelcopy *= rgb(255,0,0) for red
pixelcopy *= rgb(0,255,0) for green
pixelcopy *= rgb(0,0,255) for blue

leaving only the Red component in the pixelcopy icon. Then loop through 256 times testing only red at this time (since you already know green and blue are 0 in both icons) till the icons match. When they do, recopy pizel copy from scratch, mask out green, and test only green component. repeat for blue. this gives you the RGB components seperately and much faster. Make sense?

-Lutelian
In response to zackla21
Ok, I actually decided I needed to do this for a project im working on, and I discovered something interesting. BYOND doesnt do icon_add correctly. I have does this same thing in assembly, masking bits to determing the r g b values of something, and things simliar, and it works. When I mask out the G and B in BYOND, a portion of the G and B is tainted. I am working on a code solution to this, because what I wrote should have worked (minus the listing of the incorrect operator *=).

Will keep you posted. When I get Get_Pixel_RGB working, I shall share with everyone.

-Lute
In response to zackla21
zackla21 wrote:
Ok, I actually decided I needed to do this for a project im working on, and I discovered something interesting. BYOND doesnt do icon_add correctly. I have does this same thing in assembly, masking bits to determing the r g b values of something, and things simliar, and it works. When I mask out the G and B in BYOND, a portion of the G and B is tainted. I am working on a code solution to this, because what I wrote should have worked (minus the listing of the incorrect operator *=).

The palette shouldn't get messed up if you're only adding or subtracting a simple color. Likely your code is doing something wrong.

As it is, Wiz's method in the original post won't even work, because you can't use == to check for the equality of two different icons. It doesn't work that way. Currently the only way to get the pixel color is basically to delve into the data itself. I was going to write a routine to help with that, but it's kind of moot now because of the new 4.0 format.

Lummox JR
In response to Lummox JR
Lummox JR wrote:
Currently the only way to get the pixel color is basically to delve into the data itself. I was going to write a routine to help with that, but it's kind of moot now because of the new 4.0 format.

I was working along those lines as well, but decided to scrap the work in the wake of the new format.

Hiead
In response to Hiead
My post got lost so I will have to repost.

I am masking out the blue and green so that only red is left in an icon, using

src.Blend(rgb(255,0,0),ICON_AND)

this should remove all blue and green factors, and leave only red, but it doesnt. I should be able to go through and then change out all the red for another color, like green using

for (var/r=0,r<=255,r++)
src.SwapColor(rgb(r,0,0),rgb(0,255,0))

If only red was left in the icon by the masking above as it should be, then this would cycle through and eventually find each red color in the icon, and swap it with bright green. I could also

for (var/r=0,r<=255,r++)
src.SwapColor(rgb(r,0,0),rgb(0,255,0))

to replace each red luminence with an equal green luminence

But it doesn't work, it stays red

The only way that would happen is if there were still some amounts of green or blue left in it which means I would have to use a nested loop of

for (var/r=0,r<=255,r++)
for (var/g=0,g<=255,g++)
for (var/b=0,b<=255,b++)
src.SwapColor(rgb(r,g,b),rgb(0,r,0))

Now, this is pointless, for several reasons. 1) This would turn the entire icon green except for the masked layer. Just different shades. If I wanted to do this, I could quickly use SetIntensity to do it. But I am doing this nested loop to illustrate a point. 2) It takes a while, about 2 or 3 minutes to loop all the way through this. But it illustrates my point. This works, because some of the green and blue are left in the icon. Masking out the bits with and should remove all green and blue

r g b
10101010 01010101 10101010
&11111111 00000000 00000000
=10101010 00000000 00000000

But it doesnt. some remnants of the g and b are being left in, or its creating some sort of ...... nonreal r value, like a floating point, which doesn't even make sense.

So, my original idea of getting r g b of each pixel x,y has been scrapped. It isn't impossible with BYOND, but much more work than I want to do. I could send the icon to the rsc, browse with some Javascript using pixelgrab, etc, but that has become too much work. Now I'm just trying to find out whats wrong with this picture for the sake of finding out whats wrong. If I figure something out, I'll post it and my code. If anyone else figures out whats going.... please let me know

-Lute
In response to zackla21
An interesting thing to note though

I thought I had tried this before, but I didn't. ICON_ADD doesn't work, cause the rgb loop (as I stated before). But I just tried this and it worked. If I do src.SetIntensity(1,0,0), it removes all the green and blue, as if it were anded. An interesting note. I'll let you know what else I discover. I am determined to crack this and make it work whether it kills me or not.

-Lute
In response to zackla21
I don't think I follow what you're doing but if you want to only leave out the red in the icon you can simply do this

icon -= rgb(0,255,255)


Also, if you want to display code in the forums, use DM tags.

<dm>
*Code*
</dm>
In response to DeathAwaitsU
yeah, I know, I forget about tags. And yeah, thats basically what I'm trying to do, but ICON_ADD should have worked too, and yet it didn't so meh. I got working what I wanted working. I use a set of shift intensities to alter the icons colors, and then can change what I want to what I want. But it doesn't tell me directly which pixel was which color. But I can shift any pixel of a given luminence to what color I want. But I am going to keep looking into this. Mathmatecially speaking. . . There should be a way to make this work, getting a pixels color. I will find a way.