Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / How can I skip transparent pixels with "rect" method?
- - By quarcy Date 2011-02-10 06:52
I would like to paint my png picture with color. I tried to use

    @cover.rect( 0, 0,@cover.width, @cover.height, :fill => true, :dest_ignore=>:transparent,:color => color,:alpha_blending => true)

but it also effects that pixels are not 0x00FFFFFF (like 0x00FEFEFE) :(

The following code works OK, but it is too slow.

    @cover = Gosu::Image.new(...)
    color = Gosu::Color.new(...)
    @cover.each do |c|
      unless c[3] == 0
        c[0] = c[3]*color.red/255.0 + (1.0-c[3])*c[0]
        c[1] = c[3]*color.green/255.0 + (1.0-c[3])*c[1]
        c[2] = c[3]*color.blue/255.0 + (1.0-c[3])*c[2]
      end
    end
Parent - - By banister Date 2011-02-10 14:48
:transparent is a pseudo-color that matches any color that has an alpha channel of 0. In your case you do not want :transparent but instead specifically: [1, 1, 1, 0] (in float notation). You can also use the clear method instead of a filled rect.

so try:

@cover.clear :dest_ignore=> [1, 1, 1, 0], :color => color, :alpha_blend => true
Parent - - By meustrus Date 2011-02-10 18:35
I'm seeing this and thinking of a faster way to do something I've been trying to do...is there any way to provide a color mask, that would have the same sort of effect as this code but would not affect the alpha channel at all? So, it just recolors the image but doesn't make it any more opaque. Also, is there a fast way to provide an additive or subtractive color mask, or a desaturation mask?
Parent - - By banister Date 2011-02-10 23:29
can you provide a tiny code sample for such a color mask effect as i dont understand exactly what you mean
Parent - - By meustrus Date 2011-02-11 18:44
A "code sample" isn't exactly going to explain it. Think of it like there is a provided color, with alpha channel. If alpha=0, the entire image is unchanged. If alpha=1.0, the entire image becomes that color, except that the alpha channel is unaffected. For intermediate alpha values, the color of each individual pixel is brought closer to the provided color. Technically, this mode would function exactly like drawing a color over the whole image with :alpha_blend except that it would keep the alpha channel of the source image.

Reading below, I think a mode like this could solve the OP's problem as well.

I guess the second question could basically be solved with :mode => :add. What about a desaturation filter? How could that be quickly implemented?
Parent - By jlnr (dev) Date 2011-02-12 07:19

> What about a desaturation filter? How could that be quickly implemented?


Are you always going to draw the image at full transparency? Then you could just create a grayscale version once at startup, then always draw it over the full-color one with varying transparency.
Creating a grayscale version is not that hard, you could probably do it with a brutally long binary regexp over Image#to_blob and then feed that back into Image.new. That should be sufficiently fast and make you the hacker of the day at any good party. ;) (Maybe you can just use TexPlay for that, I don't know.)
Parent - - By banister Date 2011-02-13 04:00 Edited 2011-02-13 04:16
I can add this as a :mode option. Does this drawing mode have a name?

Let me get it straight what you want:

* normal alpha blend takes place between source and destination pixels, using source alpha for the blend (as per usual)
* However, alpha channel of the resulting pixel is not blended and is instead set to the alpha channel of the destination pixel.

Is this right?

This, i think, is different to what the OP wanted, i could be wrong; but i think he wanted an alpha blend to take place but instead base it on the destination pixel's alpha channel, rather than the source pixel's alpha channel. I think he also wanted to keep the result pixel's alpha the same as the destination pixel's alpha.
Parent - - By meustrus Date 2011-02-15 18:19 Edited 2011-02-15 21:48
That's exactly what I want. I think it's what the OP wanted too, based on his slow code to accomplish what he wanted. We can't be entirely sure, though; there's some lack of clarity based on exactly what he asked for.

I guess I would call this a color mask, so maybe :mode => :mask ? For that matter, why isn't :alpha_blend => true a :mode? Also note the long thread below...
Parent - - By banister Date 2011-02-16 00:24 Edited 2011-02-16 00:42
:alpha_blend isn't a mode because it existed before i added all that :mode jazz. but you're right, ill probably add alpha_blend as a mode (along with your new mode) and phase out the :alpha_blend option.

In the OP's (Image#each) example c[3] is actually the destination alpha, not the source alpha (which would be color.alpha) and he is using c[3] as the basis for alpha blending; that's why i figured he wanted the opposite of you -- but it's possible he just made a mistake.
Parent - - By RunnerPack Date 2011-02-16 05:02
I don't think alpha blending should be (a) mode(s), unless you can have multiple modes active at once.
Parent - - By banister Date 2011-02-16 05:46
You have a point. Currently it's possible to apply one of the drawing modes AND have it alpha blended with the background; this wouldn't be possible if alpha blending just became another mode.

Out of interest can you think of a good name for applying the alpha blend to rgb but leaving alpha of the destination intact?

i thought about :alpha_blend => :keep_dest_alpha

But that seems unwieldy at best
Parent - By erisdiscord Date 2011-02-16 13:24
:dest_alpha_mask? The much more terrible and obscure :source_atop from Cocoa? :D

Maybe let us define our own? :)
Parent - By RunnerPack Date 2011-02-16 18:48
How about ":dest_alpha => :keep" or ":dest_alpha => :overwrite" (as the default)? In other words, don't muck up the existing alpha-blending syntax just to add this feature.
Parent - - By meustrus Date 2011-02-17 20:28
Alright, then let's defer to the similar discussion below where I see " ':alpha_blend => <true, :source, :dest, :none, or false>' where true and :source are equivalent, as are false and :none." Some solution like that might work as desired. Another option is to allow multiple modes, though that could get confusing: [:add, :alpha_blend] would presumably first add dest to source, then blend the result. How exactly does this function now? How do you alpha blend and add at the same time?

As for what the OP said, I would think that his code would cause "color" to be blended only with partially transparent pixels. I'm starting to get very confused so I don't think I can explain what I'm thinking.
Parent - By banister Date 2011-02-21 15:45
TexPlay 0.3.3 released, features a few more :alpha_blend modes

:alpha_blend => :source   (default, same as :alpha_blend => true)
:alpha_blend => :dest, uses destination pixels alpha instead of source's alpha for alpha blending
:alpha_blend => :source_with_fixed_alpha, same as :source but doesn't affect alpha channel of destination pixel
:alpha_blend => :dest_with_fixed_alpha, same as :dest but doesn't affect alpha channel of destination pixel
:alpha_blend => false (no alpha blending, same as current behaviour. nil also accepted)

THere's also a few easter eggs in thsi release, require 'texplay/alone' let's you do image manip ostensively without gosu -- (really just wraps and hides gosu stuff): TexPlay.create_image(100, 100).clear(color: :red).save("blah.png")

and require 'texplay/live' a REPL session for image editting; totally undocumented and therefore hard to use :P requires 'pry' gem
Parent - - By banister Date 2011-02-22 04:33
also, could you get back to me on whether this release does what you want? :) also let me know if performance is ok:) thx
Parent - By meustrus Date 2011-02-24 20:23
I tested it and it did what I expected. Performance is fine, although it's not like I'm doing this operation every frame so there wouldn't be any major problems anyway.
Parent - - By RavensKrag Date 2011-02-21 01:26 Edited 2011-02-21 01:33
I would deffer to less technical terminology and call it something like "color blend," as from what I can tell, that's the intended use case.  You want the image tinted a specific color, with a specific "magnitude" of that color being used to tint.

Or just call it "tint."  That's probably better.

I'm almost positive the OP wants a function that can be used like a minuscule ruby photoshop.  Just select an image, apply a tinge of color to the whole image, and then BAM.  Done.  This operation sounds similar to locking transparency and dragging a big semi-transparent brush over everything.  No hassle for the coder, just easy results.  I would find that sort of library highly desirable myself, although I can imagine the coding might get a bit intense for whoever had to implement the library.
Parent - - By RunnerPack Date 2011-02-21 01:46
Naming conventions aside, it's already possible to fill with a color having a less-than-opaque alpha value. What's not currently possible (without using a slow Ruby loop structure) is the "locking transparency" part, which is what's under discussion in this particular thread.
Parent - - By RavensKrag Date 2011-02-21 02:02 Edited 2011-02-21 02:41
What I'm trying to say is, I don't think the results posted by AmIMeYet are what the OP intended.  I believe he wanted to basically shift the color pallet of the image, so to speak.  I'm not knowledgeable about the technical terminology here, so try to bear with me. 

I believe gave an incorrect example of the use case in my previous post.  Upon reading the original post as well as the posts in the other "branch" of this thread, it seems like what is desired is a "mask" which would block out all but a single color.  Not sure if that's how it works out from the coding perspective, but conceptually that's how I would visualize it.  Imagine the normal image is something seen normally, and the effect is like putting red cellophane in front of your eyes.  Now only the red light gets in, so everything is in shades of red.  Think greyscale.  Though, I suppose in this case it would be... red-scale?

This would explain why quarcy mentions additive and subtractive masks, and desaturation masks.  This also explains the "loosing image quality" thing.  I believe quarcy is saying that you loose detail within the image as a result of this fill, as a result of the desired tint effect which would preserve detail.  Not in detail in terms of artifacts or something, but visual detail.

In contrast, what you have described sounds to me like just a standard bucket fill, but using a transparent color instead of a color with 100% opacity.

Basically, while the other people are trying to examine this as a programming problem, I'm trying to approach this from an artist's perspective.  Thus, I'm trying to analyze the intent of the OP's statements, while disregarding implementation.
Parent - By RavensKrag Date 2011-02-21 02:32 Edited 2011-02-21 02:50
EDIT:
Ok, so it's called HSL or HSV.  I used "T" for "tone," relying on my extremely shaky art foundation.

Oh, duh.  Just use the HST color space instead of RGB.  I know that's possible with Gosu::Color objects, but does that work with this structure? If so, you could just copy over the hue of the the specified color to each pixel that is not :transparent.  You'd have to take into account the saturation and tone as well, but my epiphany doesn't go that far ^_^;

I could be describing a totally different problem here though, so I'll stop my speculation-based train of thought right here before I de-rail the thread...
Parent - - By banister Date 2011-02-21 05:28 Edited 2011-02-21 05:45
an alpha blend _is_ a form of tinting ; it's tinting the colors of the destination pixel with the color of  the source pixel. Strictly speaking an alpha blend is just a linear interpolation from the destination color towards the source color ; the higher the alpha value the stronger the tint -- until the destination pixel (at alpha 255) simply becomes the source pixel.

To achieve  a red tint on an image you simply draw a pure red filled rect over the image with an alpha value < 255.

EDIT: and if you want 'red-scale' you simply use the :multiply mode with a pure red (255, 0, 0, 255) filled rect - this will block all channels except the red (and alpha) channels.
Parent - - By RavensKrag Date 2011-02-21 10:17
Ah, ok then, I clearly didn't understand the question posed in this thread then.  Please excuse my ignorance, and I sincerely apologize.  I also apparently misunderstood how alpha blend worked.  I thought it included some sort of interpolation of alpha values.  Next time I will google before-hand and try not to post in the forum at far-past-midnight local time.
Parent - By banister Date 2011-02-21 10:26
hahah dont worry man :)
Parent - By banister Date 2011-02-11 03:37
this probably wont help now, but the next release of texplay will have a very fast and sophisticated color match language that will let you select or ignore precisely the colors you want, specified in terms of each channel
Parent - By meustrus Date 2011-02-17 20:38
quarcy, there's some considerable confusion as to what you're asking. Your question itself states that you only want to ignore 0x00FFFFFF, and not other transparent values, but your replies contradict this. Your code specifically is a variant of :alpha_blend except that the color being blended is assumed to have the same alpha value as what is currently at the destination. I think that your code would cause full alpha values to be replaced completely by "color" and partially transparent values would be partially between "color" and their original color. Technically, that would be "alpha blending with destination alpha instead of source alpha".

I think that the only important effect that you're trying to achieve is an alpha blend that does not affect transparency. Are you trying to create a silhouette of the original object, such that the entire image is a single color but with the same shape as the original object? I think that's what you're trying to accomplish, and the way that would happen is to have a form of :alpha_blend which simply does not overwrite the destination alpha.
- - By quarcy Date 2011-02-10 21:34
No, it still won't work.
"clear" method with :dest_ignore=> [1.0, 1.0, 1.0, 0.0] dose not make any effect. It looks like the background color is [1.0,1.00000011920929,1.0,0.0] instead of what you mentioned. I think this is not the main point because what I what to ignore is pseudo-color (any color that has an alpha channel of 0). I don't know whether a bug is in here, but :transparent doesn't match all pseudo-colors.
Parent - - By banister Date 2011-02-10 22:11 Edited 2011-02-10 22:18
can you give me a code example + image that reproduces your problem? and ill play with it.

Though perhaps what the issue is is that your alpha component is not exactly zero but is 0.00001 or something? In this case, use a tolerance to be sure to catch those too:

image.clear :dest_ignore => :transparent, ;tolerance => 0.01, :color => color
Parent - - By quarcy Date 2011-02-11 00:32
Here is my code. Just directly run it and look at the shape of those three graphics shown on screen.
http://www.2shared.com/file/rhsnb1bq/projgosu-game.html
Parent - - By banister Date 2011-02-11 01:31
Ok I played with the image. The pixels that are causing the problem have a very low alpha value, but not 0. Like 0.3 or less.

The reason why your :dest_ignore strategy didn't work, even with :alpha_blend => true was because the blending doesn't happen until after the pixels are updated.

So the situation with image.clear :dest_ignore => :transparent, :alpha_blend => true, :color => color

was:

* select all non 100% alpha pixels, and color them (replacing the alpha value to the alpha of the new color too)
* alpha blend these new pixels with the background

So, at the point you're alpha blending it's already too late as the alpha values of those low alpha pixels have already been changed to the alpha of the source color

What you instead want to do is use :dest_ignore with a :tolerance   to ignore low alpha pixels too

I added the following to your example code and it now works as expected:
   
@cover.clear :dest_ignore=> :transparent, :color => color, :tolerance => 0.5
Parent - - By quarcy Date 2011-02-11 02:12
The reason that I don't use tolerance is it has some obviously negative effect on quality.
Try this image too and look at the upper-left conner of those picture. The shapes of the man's hair are different.
http://www.2shared.com/photo/8bcL7WNo/Battler.html
I am thinking I have to totally ignore the alpha channel. :(
Parent - - By banister Date 2011-02-11 02:20
First of all, we have to consider each image on its own terms and think about the special considerations for each one.

For the image you gave me tolerance seems like the perfect solution, and the result i got by using it appeared to be exactly what you wanted. So use it, in this case.

Secondly, 'tolerance' does not and cannot have a 'negative effect on image quality'. It just doesn't make sense to say this -- it may not be _appropriate_ for a given situation and so using it may give weird results --- but you have to THINK about the given situation and decide if it's going to work or not.

In summary: Tolerance is not always going to be the right tool for the job. However for the image you sent me, it appears perfect. For other images it may not be the right tool. Either way -- tolerance does not and cannot cause a 'negative effect on image quality'

Thankyou.
Parent - - By quarcy Date 2011-02-11 02:47
OK, using :tolerance is not the right solution. Any other suggestions?
Parent - - By banister Date 2011-02-11 03:00
Nevermind, I guess I just don't understand your problem. In my opinion you're not being nearly clear enough in your description, and you seem to keep creating new constraints as this thread progresses.

I have other things to do, hopefully someone else here can help you. Good luck :)
Parent - - By AmIMeYet Date 2011-02-11 15:14
I think quarcy want's to draw a color onto the bitmap, using the alpha of the original image. Basically, you color the whole image, but with alpha=0, you color red*0, blue*0 and green*0, so nothing. But with alpha=10, you color the image by a little. Which I think is what he was doing here (although it's not very clear):
c[0] = c[3]*color.red/255.0 + (1.0-c[3])*c[0]
c[1] = c[3]*color.green/255.0 + (1.0-c[3])*c[1]
c[2] = c[3]*color.blue/255.0 + (1.0-c[3])*c[2]

(also note that he basically disregards color.alpha here, that is, the alpha of the color to apply)

With the @cover.clear thing, you basically draw a given color onto a new image, skipping where it is transparent, but then with a tolerance so that things don't have to be completely transparent to not be painted. But then, you'll basically get a hard edge of when you *do* finally start coloring. Images look a bit 'aliased' that way.

Below is a comparison image. To the left, you have the original. In the middle, you have the image.each implementation. To the right, there's the dest_ignore with tolerance. You can clearly see the 'clipped color' effect.

I think the title of this thread should not be 'skip transparent pixels', but rather 'draw with below transparency' or something. Am I right, quarcy?
Parent - - By banister Date 2011-02-12 01:33 Edited 2011-02-12 02:13
Oh, he wants to alpha blend, but alpha blend using the destination pixel's alpha rather than the source pixel's alpha.

Alpha blending (afaik) is always done with respect to the source pixel's alpha and this is how texplay works.

Can anyone think of a nice, general, API change to support this? maybe :reverse_alpha_blend => true, (currently it's :alpha_blend => true for source-based alpha blending)
Parent - - By RunnerPack Date 2011-02-12 04:55 Edited 2011-02-16 04:50
How about: ':dest_alpha_blend => true'?

If both options were set to true, you could multiply the two alpha channels before blending; I don't know if that would be useful, but it doesn't sound hard to implement ;)

If you want mutually exclusive, you could change it to: ':alpha_blend => <true, :source, :dest, :none, or false>' where true and :source are equivalent, as are false and :none.

EDIT: Fixed the colons and clarified (I hope).
Parent - - By banister Date 2011-02-12 06:05
I think this is a pretty nice idea. though do you mean true or :true?
Parent - By RunnerPack Date 2011-02-12 06:22
Oh, sorry, yeah I went a little crazy with the colons :P Just "true" and "false" should suffice; retaining backward-compatibility is all I meant...
Parent - - By erisdiscord Date 2011-02-12 06:09
I think Apple calls this NSCompositeSourceAtop but I think it's a terrible name:

> Source image wherever both images are opaque, destination image wherever destination image is opaque but source image is transparent, and transparent elsewhere. (R = S*Da + D*(1 - Sa))
> R => The premultiplied result color.
> S => The source color
> D => The destination color
> Sa => The alpha value of the source color
> Da => The alpha value of the destination color


I suppose you could look at the NSCompositingOperation constants anyway to get some inspiration.
Parent - - By RunnerPack Date 2011-02-12 06:27
I'm not sure it needs that D*(1-Sa) business... You just need to do a regular composite but without affecting the destination alpha channel.
Parent - - By erisdiscord Date 2011-02-12 16:22
D*(1-Sa) isn't my devising, of course; I just copy-pasted the documentation of the constant that sounded most like what was described for the sake of comparison. I think Apple's NSCompositingOperation constants are kind of confusing and not very powerful, though.
Parent - - By RunnerPack Date 2011-02-12 17:03 Edited 2011-02-12 17:13
Sorry, I didn't mean to imply that you wrote OSX or it's Cocoa subsystem ;)

I found this, though, and I think you're right: http://amarsagoo.blogspot.com/2007/01/nscompositingoperation-visual-quick.html
Parent - By erisdiscord Date 2011-02-12 22:24
Haha, I wish I could take credit. Except for the parts that suck, like the documentation. :D

Thanks for finding that blog post, though—the textual descriptions are (to me) pretty confusing and hard to follow. Now I can know at a glance which constant I want to use, or more likely, that there isn't one that does what I want after all~
Up Topic Gosu / Gosu Exchange / How can I skip transparent pixels with "rect" method?

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill