I'm sure the GdipImageRotateFlip function would work as well.
I usually forget about those Gdi+ functions,
when there are other ways of doing things,
but I know you, mms, are deep into GdiPlus,
so I definitely appreciate your input.
This post is primary in response to post #18 (and expounding on #17), in particular the code and images attached to post #18. (Additional response to post #19 added)
While I was driving home the day I posted #17, I thought about the line from my post:
Quote:
In this case I didn't create a background bitmap with the alpha gradient preset in it, but just created the brush and used FillRectangle which serves the same purpose.
I thought that maybe that was a bit too perfunctory or obtuse and what I meant to convey would be missed.
That proved to be the case, as evident by post #18.
The point I meant to get across, is for this method of fading the foreground image to work, you would have to create an "inversely" faded version of the background to draw over the foreground.
The method assumes the background is a known element of the "control", and would not change, so an alpha gradient modified version of it would only have to be done once, or perhaps infrequently (each time the background was modified), if the user was allowed to change the "background" image of the control.
So, the method would be to create a bitmap to hold the faded (modified alpha) version of the background, then drawing that faded version over the foreground whenever updating the control.
For ease of demonstration, I was using a solid background color.
In this case I chose black, but it could have been anything.
So, to fully illustrate the method, I should have create a bitmap, and filled it with the alpha gradient version of my black background, and then drawn it on top of my foreground (so the foreground image would fade into my black background).
Since I was going to create the linear gradient brush to fill my faded background version of my bitmap, I said to myself, why bother creating the bitmap. Just use the linear gradient brush in place of using DrawImage (or a texture brush) of the faded version of the bitmap.
But, since I was using the linear brush directly, in place of the faded bitmap or texturebrush, I wrote the caveat quoted above to alert you to the fact I didn't create a faded background image.
The implication was meant to let you know the code has to be modified to accomodate the chosen background. If you want to have a more complicated background image (like a checkerboard), then you have to create the inverse faded version of that background to be use to draw over the foreground.
I realized as I was driving home that I probably should have been clearer about that.
So, as a quick exercise, I took the code you provided in post #18, and modified it to create a linear alpha gradient version of the background checkboard pattern in a bitmap.
This bitmap is then drawn over the foreground image to "fade" the forground into the background.
{edit: I hit the wrong button so posted when I meant to preview changes, rather than double post, I'll continue editing this post}
--------------------
These comments are in regards to post #19, using the "double opacity gradient code".
--------------------
That code seems to be doing a lot more work than is necessary, and is probably not accomplishing the actual desired outcome.
The main thing that seems odd is the double modification of opacity for both the "background" checkerboard image, and the foreground image.
Since you are modifying the opacity of the foreground, (and the checkerboard should represent the background), the checkerboard image should not be alpha modified.
The only reason to modify the checkerboard image, would be that the checkerboard didn't represent the background, but rather another layer to be blended to the background.
The way you're doing it, the Resulting images may look very different on Johnny's computer vs Suzie's.
The expected approach would be along the lines of.
1. Draw a solid (full alpha) checkboard to represent the background image.
2. Draw an alpha modified foreground image on top of that.
That should look pretty much the same on anyone's computer.
But, what you're doing is:
1. Modify the background's alpha, we'll call it raB (ra = reduced alpha).
2. Modify the foreground's alpha, we'll call it raF.
3. Combine them in a result bitmap, we'll call it raR (reduced alpha result).
You've probably noted that when you draw with raR, that you may see previous content, which is why you draw a white rectangle to "clear" an area before using the raR brush on top of an area that has been previously painted.
That is because, even though you used complimentary values (they total to 255) when alpha adjusting corresponding pixels in the two source images, the result in the combine bitmap is not fully opaque (the alpha value is not 255).
If you removed the two lines in your loops that change the alpha of your checkerboard images, the results should not look too different.
But, because the checkerboard was full alpha, the resulting image also has full alpha, and when you use the brush you would not have to clear the area under the brush to white, since all pixels would be replaced by the source brush.
The reason your existing code may produce result pictureboxes that look different on two different computers is, since the combined bitmap is not fully opaque, the background color of the picturebox "tinges" the color of the not fully opaque pixels.
Johnny's "Control" color may not be the same as Suzie's so would influence the result displayed in the pictureboxes differently.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
The implication was meant to let you know the code has to be modified to accommodate the chosen background. If you want to have a more complicated background image (like a checkerboard), then you have to create the inverse faded version of that background to be use to draw over the foreground.
I realized as I was driving home that I probably should have been clearer about that.
Inverse faded - I missed that conceptually.
Quote:
You've probably noted that when you draw with raR, that you may see previous content, which is why you draw a white rectangle to "clear" an area before using the raR brush on top of an area that has been previously painted.
That is because, even though you used complimentary values (they total to 255) when alpha adjusting corresponding pixels in the two source images, the result in the combine bitmap is not fully opaque (the alpha value is not 255).
If you removed the two lines in your loops that change the alpha of your checkerboard images, the results should not look too different.
But, because the checkerboard was full alpha, the resulting image also has full alpha, and when you use the brush you would not have to clear the area under the brush to white, since all pixels would be replaced by the source brush.
I did notice this when I was playing around, but didn't understand exactly why..
For those reading through this..
passel's update includes code where the
upper and lower alpha fade "zones" stay fixed (in position) while
the graticule image may be dragged (re-positioned) into, or out of,
these alpha fade zones, thus allowing adjusting of the total amount
of area of the graticule image effected
by the alpha opacity gradient effect.
Although this doesn't get me to the where I need to be for viewport-ing
its still demonstrates an alpha effect that I have never seen any other
sample/demo/example available on the internet perform with any .Net language!
Special thank you for taking the time to provide very verbose commenting as well.
Dynamically adjusting alpha opacity gradients using cruve adjusted greyscale banding
passel's last posting has me very excited.
It opens up a whole new realm of possibilities.
Here's what I was thinking.
What if you defined the level of alpha opacity values dynamically
using a vertical strip of varying greyscale values adjustable at runtime.
An image set next to this strip would be (correspondingly)
vertically alpha opacity gradient faded,
depending on the matching line greyscale value (y value position).
where:
White - completely visible
Black - completely invisible
mid-grey, rgb(128,128,128) - 50% transparent
and so on..
The strip would only need to be wide enough so that the user could
distinguish the single greyscale color of each horizontal line.
Some code in the mousedown event of this picStrip picturebox control
(that's filled with horizontal lines of varying greyscale colors)
would make visible (pop-up) a small panel with a triangular slider inside
(see post #11 of this thread) next to the picStrip, corresponding to the Y value location retrieved from the mousedown event,
that would allow adjusting of the greyscale color value.
(and therefore the alpha opacity at that point).
Sounds good (that's the easy part).
However, the alpha opacity gradient should be always be a
relatively smooth gradient,
with no sharp delineations or "gradient breaks".
To accomplish this I'm thinking that the set of greyscale values should
be defined not just by any random series of linearbrushgradient calls,
but by some kind of curve.
What type of curve I don't know?
B-Spline, Hermite, Cubic B-Spline, Cardinal..probably a series of bezier curves..
There's a really smart guy named Thorsten Gudera who has created
(in VB.Net no less) a kind of adjusting-via-curves virtual control.
The working code is found inside a download
called "ColorCurves" in a public Skydrive here.
Right now it's designed as an up-down oriented adjuster,
but I want to be able to rotate it 90 degree clockwise,
to use it in more of a side-to-side manner,
with the points on the curve defined by
those greyscale lines values I mentioned earlier,
(where the x-offset of each curve point value
from the greyscale gradient filled picStrip is form 0 to 255).
That's a little harder (because I don't really understand
how the Mr Gudera is handling his array of curve points..adding some
at runtime,
then somehow making the curve bend in response to the added points).
I need to set up some special debugging output to watch how things work internally..
However, I know I'm basically going to have to figure out,
given a graphic path, (for instance, a bezier curve),
how can I retrieve (access an an array of) all the points
that go into making up the bezier curve(s)
(with out having to resort to using something stupid like GetPixel).
What's the difference?
Don't expect MSDN to readily give you the answer to that question.
Well, after hours and hours of research,
and having made up a little test program attached below,
here's the answer:
Its all about how Flatten() works.
But first I want to give a link to the only other xvbt forum thread that
deal with PathPoints - it's here.
Now you need to look at the screenshot attached below (if you haven't already).
The important thing to note is that the far left multi-line textbox
(in a sort of purplish color) only gives values for to 46 points,
while the far right multi-line textbox (sort of a greenish color),
lists values for 390 points.
This proves (at least to me), that pathdata.points is not effected by
a Flatten() method call while PathPoints is effected.
Without making any Flatten() call I get 25 points
With make a Flatten() call I get 64 points
If I use:
Code:
Dim flattening As Single = 0.001
myPath.Flatten(New Drawing2D.Matrix, flattening)
..I get 390 points.
Do you understand?
Good - please explain it to me then
The best I can figure is that using a smaller value for flattening
in the above code increases the accuracy with which the
pathpoints are defined
(i.e. they are spaced closer together and there are more of them).
So why not call it the Accuracy() method?
Maybe "Flatten" has to do with something like
creating fake imaginary lines that are used for some kind of
interpolation to create points - who knows.
Even using this new code to get the points that make up a bezier curve
I still have no idea how to use this new found data to create a function
that somehow knows which endpoints and controls point are needed,
such that if you move a point (that used to be found along a known bezier curve),
the curve can be re-shaped (moved, re-situated) so it passes through a new user-defined point.
If I could get such a function then all the points
to the left and right of the new point
would "fall in line" along the new bezier curve,
and I wouldn't have to write (use) some special smoothing math,
like that which was used for fitting-a-curve-to_points-using-least-squares code.
Please note on the vbHelper page linked to directly above
that even the Rod Stephens, himself, admits:
Quote:
I don't know how to solve the system of these three equations.
...passel's update includes code where the
upper and lower alpha fade "zones" stay fixed (in position) while
the graticule image may be dragged (re-positioned) into, or out of,
these alpha fade zones, ...
While the code allowed you to drag the instrument face around, that was really code left over from the original example, not the intended demo.
The original code also allowed scaling the image, which I disabled when I modified the example for _2. I probably should have disable the dragging as well.
The point was to drag in the square underneath the display to scroll and rotate the pitch ladder, to see it fading out at the top and bottom as the pitch ladder scrolled, not as the instrument was moved.
The background would have to be moved as part of the control, not left in place.
The purpose for using this method is to minimize the processing that has to be done each time the display is updated, since the alpha modification would only have to be done once.
Now, if that is considered too restrictive, then you can adjust the alpha of the foreground image every time it is drawn, which would be more along the lines of what you expected from the begining.
So, I modified the example again, this time leaving in all the mouse dragging options:
1. left dragging in the box below the drawing to rotate and/or roll the pitch ladder up and down,
2. right dragging left/right in the box below the drawing to scale the image
3. left dragging in the picture area to move the image
4. right dragging in the picture area to increase/decrease the size of the drawing area.
The code now copies the pitch ladder to the display one line at a time, using a color matrix to adjust the alpha for each line.
Therefore, we're adjusting the alpha of the foreground directly when drawn, so don't need to pre-fade a background image and use it to draw the faded background over foreground image to "fade" it.
Fading the foreground drawing should be conceptually simpler, since it is the intuitive approach to what you want, at the expense of more processing having to be done every drawing cycle.
I don't know if using lockbits and marshalling the bitmap data would be faster than using a color matrix on each line as this code does, but it would probably be worth testing. I was a little surprised by how fast this worked on most of the machines I've tried it on.
The one exception is an older laptop that I've had for about 7 years now. It was ridiculously slow on that machine, taking a second or so to update once.
I suspect if I marshalled the bitmap and operated on the array directly, it might make updating the foreground alpha every draw acceptable on that machine, but I don't know if I'll get around to trying it.
As for flattening, my understanding is that a curve is generally not flat.
A line seqment is flat.
When you flatten a curve, you are approximating the curve by converting it into a series of line segments.
Flattening a curve refers to the conversion of the curve to line segments, not how many or how few line segments you choose to approximate the curve.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Towards the development of a generic, multiple methods, AOG class
Thanks for the posting passel.
Quote:
I don't know if using lockbits and marshaling the bitmap data would be faster
than using a color matrix on each line as this code does,
but it would probably be worth testing.
Yes I think additional testing might prove prudent.
What about the case where the desired alpha opacity gradient lies along some kind of curve,
(like, for instance, a bezier curve)?
I'm imagining a closed curve where the various alpha opacity gradient
levels could be represented as curvy contours
where the centroid would be dynamic based on the "blob-like" shape-outline
(perhaps using Green's theorem).
The curvy contours, would, of course, be drag-adjustable at runtime.
Quote:
edit: finding pictures of a centroid of a closed curve was
actually a lot hard than I thought, but here's one from this page.
Would the use of the color matrix alpha blending,
which is essentially a square-ish/rect-based method, allow this?
..or another way of putting it:
"Could color matrix alphablending be used on a per pixel basis?"
I'm still trying to understand the differences between the alpha_graticule_passel2
and alpha_graticule_passel3 code attachments.
Both use color matrix alpha adjusting, or course.
In the alpha_graticule_passel3 code, the alpha opacity gradient appears to
adjusted in connection with the matrix transforms
(and therefore provides the ability to have a rotatable alpha opacity gradient),
while in the alpha_graticule_passel2 code the AOG (alpha opacity gradient)
appears fixed at the top and bottom of the picturebox.
Concerning an issue with the alpha_graticule_passel2 code:
There is also a small line artifact that I don't think should be there
when the foreground graphic is too far up or down,
(see line artifact screenshot collection attached below)
The fix is simple, though.
Change this line in the frmPDF_Load:
Code:
For y As Integer = 0 To cy - 1
to this:
Code:
For y As Integer = 0 To cy
I will try to spend some time isolating the
relevant AOG code routines and creating a generic-zed
"CreateAOG_Method1" and ""CreateAOG_Method2""
that maybe can be worked into a class that is
encapsulated into a separate vb file
that could be added to any project like
the checkboard.vb file that contains the
"Public Class CheckerBoard" for rendering
checkboard-as-transparent. It has proven most useful.
This method (the Graphics.BeginContainer method) returns a GraphicsContainer that represents the state
of this Graphics at the time of the method call.
Use this method with the EndContainer method to create nested graphics containers.
Graphics containers retain graphics state, such as transformation, clipping region, and rendering properties.
When you call the BeginContainer method of a Graphics,
an information block that holds the state of the Graphics is put on a stack.
The BeginContainer method returns a GraphicsContainer that identifies that information block.
When you pass the identifying object to the EndContainer method,
the information block is removed from the stack and is used to restore the Graphics to the state
it was in at the time of the BeginContainer method call.
Containers can be nested; that is, you can call the BeginContainer method several times
before you call the EndContainer method. Each time you call the BeginContainer method, an information block is put on the stack,
and you receive a GraphicsContainer for the information block.
When you pass one of those objects to the EndContainer method,
the Graphics is returned to the state it was in at the time of the BeginContainer method call
that returned that particular GraphicsContainer.
The information block placed on the stack by that BeginContainer method call is removed from the stack,
and all information blocks placed on that stack after that BeginContainer method call are also removed.
Calls to the Save method place information blocks on the same stack as calls to the BeginContainer method.
Just as an EndContainer method call is paired with a BeginContainer method call,
a Restore method call is paired with a Save method call.
When you call the EndContainer method, all information blocks placed on the stack
(by the Save method or by the BeginContainer method)
after the corresponding call to the BeginContainer method are removed from the stack.
Likewise, when you call the Restore method, all information blocks placed on the stack
(by the Save method or by the BeginContainer method)
after the corresponding call to the Save method are removed from the stack.
The graphics state established by the BeginContainer method includes the rendering qualities of the default graphics state;
any rendering-quality state changes existing when the method is called are reset to the default values.
Unfortunately this way of defining things is so self-referral as to be almost useless (especially to a old VB6-er)
I'm guessing its maybe some kind of wrapper to save the device context state?
"Stack" is maybe hinting at something to do with memory?
From the methods like "CreateObjRef", "InitializeLifetimeService", "GetLifetimeService" and
"MemberwiseClone(Boolean)" I guess it requires an advanced understanding of the
"MarshalByRefObject Class" to be clued into exactly how it works..
Anyway, I find the following alpha_graticule_passel2 code lines
(which I added some comments to) to be most significant:
Code:
'Upper fade
dRect.Y = cy - y
gSB.DrawImage(stagingBitmap, dRect, 0, cy - y, picPFD.Width, 1, GraphicsUnit.Pixel, ia)
'Lower Fade
dRect.Y = cy + y
gSB.DrawImage(stagingBitmap, dRect, 0, cy + y, picPFD.Width, 1, GraphicsUnit.Pixel, ia)
This suggests to me that using X values (instead of Y values),
left and right alpha fade zones could possibly be set up as well,
as an option for a generic-ized CreateAOG_method1 class.
...
Would the use of the color matrix alpha blending,
which is essentially a square-ish/rect-based method, allow this?
..or another way of putting it:
"Could color matrix alphablending be used on a per pixel basis?"
A linear gradient means the gradient is oriented along a line. The gradient itself doesn't have to linear, as evident by the Bell Curve selection.
Also, as you noted before, you can divide the gradient up into a number of segments and define a linear color ramp over each segment to approximate any curve to whatever degree you want.
When you use a linear gradient brush to fill an area, the gradient color change is along the axis you defined. All pixels in a line perpendicular to that axis in the fill area are the same color as the pixel on the axis that is part of that line (the intersection).
Using a color matrix to change a line of pixels to the same alpha value (or color), is essentially emulating a linear gradient brush.
Your original drawing showed a reticule that faded into the background at the top and bottom.
If the curve you're talking about is along one dimension (top to bottom or side to side), so that all the pixels perpendicular to the desired fade direction are the same alpha value as that point along the curve, then you can use a color matrix to relatively quickly set those alpha values a line at a time.
But if you want to fade in multiple directions, then you would have to break the color matrix blocks into multiple smaller sections.
You could do 1x1 pixel blocks, but that would be ridiculous.
As soon as you want to fade in more than one direction simultaneously, using a color matrix is not so useful.
Quote:
I'm still trying to understand the differences between the alpha_graticule_passel2
and alpha_graticule_passel3 code attachments.
The primary difference is passel2 simulates the foreground fading into the background by obscuring the "foreground" by drawing a translucent background image over top of the foreground.
passel3 doesn't care about the background or fool with it in any way.
It actually fades the foreground dynamically as it draws it on the background.
Originally, I was using an intermediate bitmap, transferring and fading the foreground image line by line into it, and then drawing the intermediate bitmap onto the background.
But before I posted I thought, why go through that waste since drawing and fading the foreground image directly on the background is the same code and work as drawing it on the intermediate bitmap. And of course, it is actually less code since you don't need the additional drawing, bitmap, graphics object, etc.
Quote:
Concerning an issue with the alpha_graticule_passel2 code:
There is also a small line artifact that I don't think should be there
when the foreground graphic is too far up or down,
I assumed there could be a common "off by one" problem at the ends, but I didn't take the time to test it since in my mind, the idea was that the "control" represented a set, a combination of a specified foreground scrolling tape on a specified background. The tape would fade at the top and bottom as it scrolled. Since the "foreground" tape area didn't reach the top or bottom of the obscuration area it didn't matter if I was off by one (or 2, or 3).
I didn't consider you moving the tape, since the method was not designed with that in mind.
Yes, I've used that in several of the examples I've posted, including the original VB drawing code example that this code was pulled from.
I don't know that I've read the details before.
I simply use it so that I can either return the graphics object back to the state it was when it was handed to me, or locally when I need to temporarily make some changes to the graphics transforms, but return back to the current state when the sub manipulations are done.
I don't care to know the details of how it does it work, just how to use it.
Quote:
Anyway, I find the following alpha_graticule_passel2 code lines
(which I added some comments to) to be most significant:
Code:
'Upper fade
dRect.Y = cy - y
gSB.DrawImage(stagingBitmap, dRect, 0, cy - y, picPFD.Width, 1, GraphicsUnit.Pixel, ia)
'Lower Fade
dRect.Y = cy + y
gSB.DrawImage(stagingBitmap, dRect, 0, cy + y, picPFD.Width, 1, GraphicsUnit.Pixel, ia)
This suggests to me that using X values (instead of Y values),
left and right alpha fade zones could possibly be set up as well,
as an option for a generic-ized CreateAOG_method1 class.
Again, if you're talking fading both top and bottom, and left and right, at the same time, then no, I don't see this being useful.
The first pass works, because the destination bitmap is empty (fully transparent).
After the first pass, the bitmap now contains a version of the foreground faded in one direction.
You can't fade the foreground in the other direction on top of this bitmap (it won't fade existing pixels in the destination).
But, as I write this, I realize, that it can be done, but each pass would have to be done on a new empty bitmap.
So, the process would essentially be:
1. Create a new bitmap (an empty, fully transparent bitmap) (eg. Dim bmap as New Bitmap(200,200) ).
2. Transfer your foreground image (let's say horizontal line by line) into this bitmap, alpha fading each line according to your vertical curve.
3. Create another new bitmap.
4. Transfer your faded image (now would be vertical line by line) into the new bitmap, alpha fading each line according to the horizontal curve.
(or you could skip step 3 and do step 4 directly to the background).
5. If you used the second bitmap, then draw the image on your background (or create a texture brush, and fill).
In passel3, the gradient "curve" is defined by the values in an array.
The array is of the single type, values range 0.0 (fully transparent) to 1.0, fully opaque.
There is one array element for each line of the bitmap, defining the alpha value to be used when drawing that line.
So, yes you can easily have the user modify the values in that array, which will immediately affect the alpha gradient of the foreground image the next time you draw it.
Alpha fading is a relatively subtle effect (compared to color gradients), with a limited range of values, over a limited number of pixels on the screen, so it may be hard to distinguish a particular curve vs a number of linear segments that hit various point along the curve.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
As soon as you want to fade in more than one direction simultaneously, using a color matrix is not so useful.
That's what I wanted to know - so I'll still keep the per pixel approach
(as used in the attachment to post #19 of this thread)
handy for those cases.
Quote:
But, as I write this, I realize, that it can be done, but each pass would have to be done on a new empty bitmap.
So, the process would essentially be:
1. Create a new bitmap (an empty, fully transparent bitmap) (eg. Dim bmap as New Bitmap(200,200) ).
2. Transfer your foreground image (let's say horizontal line by line) into this bitmap, alpha fading each line according to your vertical curve.
3. Create another new bitmap.
4. Transfer your faded image (now would be vertical line by line) into the new bitmap, alpha fading each line according to the horizontal curve.
(or you could skip step 3 and do step 4 directly to the background).
5. If you used the second bitmap, then draw the image on your background (or create a texture brush, and fill).
This is good info,
So if someone actually wanted to develop a demo sample
it could have three options:
1.) Top/bottom alpha fade
2.) Left/right alpha fade
2.) Both sets of alpha fading together together - essentially visible in the middle and then faded along the outer edges of all sides,
(maybe call it a "all borders" alpha fade or "picture frame" fade..)
Quote:
So, yes you can easily have the user modify the values in that array,
which will immediately affect the alpha gradient of the foreground image the next time you draw it.
Real time AOG adjust- Yes!
In regards to the alpha_graticule_passel_3 code
I'm thinking the array approach,
possibly coupled with rotational transforms,
could be used for something like
a fake combobox that instead of the traditional drop down
would have alpha text flyouts both up and down
that fade off into transparency after a few items in either direction,
using the so-called "Joystick" mode.
Note: I've seen how awkward its is to have to actually scroll thru
a long lit of items in a combobox control drop down squeezed
into a tiny space and I don't like it at all.
Quote:
Alpha fading is a relatively subtle effect (compared to color gradients),
with a limited range of values, over a limited number of pixels on the screen,
so it may be hard to distinguish a particular curve vs
a number of linear segments that hit various point along the curve.
This is part of what makes adjusting alpha opacity gradients using curves such a challenge,
but maybe some forum members who has taken the time to download
and look at the Thorsten curve adjustor might have some ideas on how:
A.) It could be isolated as a separate code module (class?) that could be
added to create a curve adjusting virtual control
B.) The code could be modified to be more "array injection friendly" - right now all the points are created at runtime,
and ideally it would be nice to be able to feed an array of points (or PointF values)
into the curve adjustor virtual control routine so it can shown up in the form load,
pre-setu..based on a file stored config.
alpha fading (and alpha opacity adjust at runtime) using trackbar slider control
I'm working on the viewporter demo, but ran into some issues using texturebrush
for cropping. I may end up using bitmap cloning instead.
In the meantime I need to brush up on my color matrix to understand how
to manipulate passel's colormatrix alphablending code.
I've only done a few color matrix examples, like the blur example attached to this post, and
the few colormatrix demos for dynamic alpha mask creation in the fuzzy lines thread.
However there was an issue.
Do you remember when I suggested (asked) in this fuzzy lines post:
Quote:
What I'm hoping is that variables could be
substituted for the numerical values in Color Matrix creation code..
Well in order to provide dynamic runtime adjusting of the alpha opacity value I needed
to feed (inject) the value from a trackbar slider control directly into the colormatrix value set.
So here's what I came up with (and amazing it works):
Quote:
Dim sngOpacityValue As Single = (trackBarImage.Value * 0.01)
lbl2.Text = "Image Opacity Value = " & CStr(sngOpacityValue * 100) & "%"
' Create a new color matrix with the alpha value set to the opacity specified in the slider
Dim cm As New ColorMatrix()
' Initialize the color matrix. ' Note the variable ("sngOpacityValue") used to set the opacity value dynamically
' based on adjusting the trackbar slider control at runtime
Dim matrixItems As Single()() = { _
New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, sngOpacityValue, 0}, _
New Single() {0, 0, 0, 0, 1}}
Dim colorMatrix As New ColorMatrix(matrixItems)
Anyway project and screenshot attached - got to get back to work on the viewporting project..
Oh, and note that while the text fade can fade into any color
this type of image alpha fading code can not fade into another background image,
It just fades an image to black,
which represents the rgb(0,0,0) value on the color matrix I guess..
...
So here's what I came up with (and amazing it works):
...
I suppose eventually you'd figure out that that is what I'm doing in my code.
The comments in "passel2" for instance says:
Quote:
'Since the color matrix is created as a unity matrix (no effect on the drawing),
' we only need to modify the alpha scale component, Matrix33, to effect alpha channel alone.
edit: Where I say "unity" matrix, I meant "identity" matrix. I know I get that wrong so need to be on the lookout, but it isn't ingrained yet. I think I confuse it with "unity" amplifiers, so "my bad".
So, to explain further, you're creating a new color matrix-
Dim cm As New ColorMatrix()
That creates a "unity" matrix.
It is all zero's, except the diagonal values (0,0)(1,1)(2,2) etc. are set to 1.
You want to change the (3,3) value to affect the alpha.
You are creating a 5x5 array (0,0)-(4,4), setting the same unity pattern, but modifying the (3,3) value to your variable to change the alpha component.
You are only modifying 1 of the 25 values in the matrix.
Since only one value needs to be modified, why create an array and load all 25. Why not just change the one value.
cm.Matrix33 = sngOpacityValue
So, your code would look like:
Code:
Dim sngOpacityValue As Single = (trackBarImage.Value * 0.01)
lbl2.Text = "Image Opacity Value = " & CStr(sngOpacityValue * 100) & "%"
' Create a new color matrix with the alpha value set to the opacity specified in the slider
Dim cm As New ColorMatrix()
' Note the variable ("sngOpacityValue") used to set the opacity value dynamically
' based on adjusting the trackbar slider control at runtime
cm.Matrix33 = sngOpacityValue
Your existing code is creating the matrix twice (using New).
Even if you do want to change multiple values of the matrix so will want to use the 5x5 array, you shouldn't use New on the declaration since you are never going to use that one. It should just be:
Dim cm as ColorMatrix.
Quote:
...
Oh, and note that while the text fade can fade into any color
this type of image alpha fading code can not fade into another background image,
It just fades an image to black,
which represents the rgb(0,0,0) value on the color matrix I guess..
I'm not sure what you're saying here.
The text fade can fade into another background image.
Simply load an image into the pictureBoxText, and don't clear the picturebox to white when your draw.
You're currently loading an image into pictureBoxImage in the form load, but I don't know why, since you clear the pictureBoxImage to transparent in the paint event anyway. Having an image loaded will never be seen.
Perhaps you meant to load the image into pictureBoxText, and that has thrown off your observations.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Still trying to understand matrices & easy instructs for adding resources to project
Thanks for taking a look at the code.
Even though the code attachments in my last post work
I do want to do things the "proper" way.
Quote:
Originally Posted by passel
That creates a "unity" matrix.
What exactly is consider a "unity" matrix?
Is it just one matrix just joined with another matrix?
or
Is it just one matrix just joined with its inverse matrix?
or
Is it just one matrix just joined with another matrix in some way
where alpha opacity is adjust is being done?
Quote:
cm.Matrix33 = sngOpacityValue
So does the "Matrix33" in "cm.Matrix33" automatically mean you are only
working with alpha opacity adjusting of matrices
(as opposed to cm.Matrix00 or any other cm.Matrix##)?
Thanks for point out the unnecessary New matrix creation.
I'm still working on an encapsulating a CreateAOG function as
a public class and this will help.
In the meantime though I'm trying to get a viewport that
contains a cropped image that is trackbar-slider selectable.
I know I can do this with texturebrush,
but I found another cropping routine that uses bitmap cloning
and wanted to play around with it.
Code:
Private Function CropBitmap(ByRef bmp As Bitmap, ByVal cropX As Integer, _
ByVal cropY As Integer, ByVal cropWidth As Integer, ByVal cropHeight As Integer) As Bitmap
'Get/set rectangular dimensions of cropped image
Dim rect As New Rectangle(cropX, cropY, cropWidth, cropHeight)
'Uses bmp clone cropping method for cropping
Dim cropped As Bitmap = bmp.Clone(rect, bmp.PixelFormat)
'Returns the cropped image as bitmap
Return cropped
End Function
The attached solution can be used for graticules or sidescrolling landscapes
(like in sidescroller games) or just about anything where you need
to dynamically (at runtime) select, cutout ( clip ), and show a cropped part of an image.
..and not the rect to select the cropped portion of the source graphics,
which basically makes it useless from what I'm trying to do.
The attachment below represents only an intermediate step for me, however,
because I need the cropped image in the viewport to be alphablended
at the upper and lower ends, but since the image is stored purely as a memory bitmap
then it should just be a matter of merging that image and the
background image into passel's "unity" matrix.
The rest of this post is not for passel,
but for the VB newbies out there
who may be wondering:
How can I merge and use graphics resources into a new B.Net 2010 express solution / project,
(in a way that works with the IDE instead of fighting it,
and with minimizing the possibility of causing .resx file errors
when I have to change things later)?
So here's my "little" set of mini-instructions:
Quote:
Open up VB.Net 2010 express and click on "new project".
Choose "Windows Form Application" (in the middle - should be the default), and press the "OK" button.
Immediately afterwards, in the Solution Explore pane,
select "Solution 'Windows Application 1 (one project)", then on the
File Menu select "Save WindowsApplication1.sln AS"
In the "Save Project" dialog box that comes up at the far right of the second line down
("Location') there is a "Browse" button.
Click on the "Browse" button, and create a new folder, naming it the same
as what you are going to call the project and the solution.
Yes I know the .Net IDE doesn't require this but it's my
K.I.S.S methodology approach that avoids a lot of confusion in the future.
Plus once you create the folder, name it and click on it then before you press the "Select Folder", take the time to copy the
the text in the textbox to the right of the "Folder:" line at the bottom
of the select folder dialog to the clipboard (Ctrl key + C key).
Only then should you press the "Select Folder" button.
You will be back to the "Save Project" dialog box. Do NOT paste the new folder name you copied to the clipboard into the
"Solution Name:" line, but instead paste it (Ctrl key & "V" key)
into the "Name:" line.
You will see that the "Solution Name" line automatically changes to whatever
is on the "Name: line".
Press the "Save" button, you will be back into the IDE,
then please notice in the Solution Explorer pane,
that both the solution and the project both have the same name
(so the text in the "Name:" line above actually designates the "Project Name:",
so why doesn't the dialog box line just say "Project Name:" ).
Having the solution and the project both have the same name
is also part of my K.I.S.S methodology approach.
Okay, so you are ready to add graphic resources to your project, right?
No.
Instead,
under the File menu, press "Save All",
then go to the folder you just created.
Let's say you named the folder "Test".
If so, then the "Test" folder
should be another "Test" folder with:
1.) a "Test.sln" solution file
2.) a "Test.suo" solution file (Note: .suo files are undocumented --only Microsoft knows what's supposed to be inside them)
3.) another "Test" folder
Open this (twice nested) "Test" folder,
and it should have the usual stuff:
1.) bin folder, MyProject folder, and an obj folder
2.) test.vbproj file, test.vbproj.user file, Form1.Designer.vb file, and Form1.vb file
Inside this folder create a new folder called "Resources"
(name it exactly this and not "Resource1" or "MyResources" or anything else,
because the IDE is going to be looking for that specific folder with that specific name in that specific nested folder location).
Now transfer all the graphic files (.bmp, .jpg, .gif, .png or whatever),
for your project into that "Resources" folder
What I do next is get both the VB.Net IDE window, and
the Windows Explorer window (opened to the Resources folder), tiled side-by-side on your desktop. (Aero snapping
under Windows 7 works great for this).
In the IDE window select the project name in the Solution Explorer
and at the bottom of the Project menu you should see projectname Properties
(like if you name your project "Test" it will be "Test Properties").
Once the Project properties pane is open,
select "Resources" on the left
and on the right it will have a small grid
with the column names of "Name", "Value", "Comment"
Under the column labelled "Name" will be: "String1".
"String1" is actually just a useless placeholder
(so just ignore it), but directly above it,
is something that says "AddResource").
You may be tempted to click on this, but don't: DO NOT click "AddResource".
It will not give drop down list of Resource folder files to be added,
(instead you get a list of graphic files types
I would be happy if it just opened a "browse for file" dialog but it doesn't!)
So here's what you do instead:
just drag a graphic from the "Resources" folder directly under
where it says "String1" and drop it.
Yeah it really is that easy.
Magically a bunch of things happen:
1.) the greyness that makes up the Project Properties Resource pane goes away
and you get a big white space.
2.) A small thumbnail has been added to the big white space
3.) You'll notice in the Solution Explorer pane that
--a.) It has "found" the "Resources" folder you created manually
--b.) It now lists the new graphic file (slightly indented) under the Resources folder
You are now a VB.Net Add Resources ninja - pat yourself on the back!
Where is this procedure explained like this - nowhere!!!!
It has taken me a lot of trial and error to figure out that this is (for me at least),
the best and most reliable way to make sure the
VB.Net finds (and keeps track of) your graphics without having to
deal with the different type of pathing schemes .Net uses to replace the
oh-so-much-simpler VB6 App.Path call.
This way can even store icons, cursors, etc.
Why not just drag the files into the Solution Explorer?
Then it ends up in "Miscellaneous Files" and if you attach the image to
a picturebox and then delete the picturebox the IDE has a "hissy fit"
-- .resx errors out the ying yang. You've been warned.
Anyway...to attach the graphic to a picturebox,
I recommend using something like this code:
Quote:
Public Class Form1
'In Form declarations
Dim bm1 As Bitmap
'In Form Load event
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
bm1 = New Bitmap(My.Resources.graphicresourcename)
'remember to add a Picturebox control to your form..
PictureBox1.Image = bm1
End Sub
End Class
..if you don't know exactly what
"graphicresourcename" should be don't worry about it.
Just type in "My.Resources", then hit the period key and
the IDE Intellisense will give you a list of all the graphic resources
you've dropped and dragging into the Project properties -> Resources pane.
Note; The names it gives the resources,
while based on the graphic's file name,
are just aliases and can be renamed to whatever you like.
Be warned though there is no easy (mouseover) way to
determine which alias name belongs to which graphics file.
For instance, if you have added both "test.bmp" and "test.jpg" as
project resources - the IDE will pick different, but somewhat similar, names
as aliases and determining what alias is referring to which file may become
slightly confusing.
...
What exactly is consider a "unity" matrix?
...
It is something I've made up (unintentionally) by confusing, I think, "Unity" amplifiers, which don't change the voltage levels of a signal, with an "Identity" matrix, which doesn't change the values processed through it.
Hopefully this gaff will help cement the proper term in my mind.
So to be clear, I meant "identity" matrix.
When you create a matrix without initialization parameters, it will be set to the identity matrix, so you know it will not have any effect on the drawing.
You can then just modify the parts you want to affect.
Quote:
So does the "Matrix33" in "cm.Matrix33" automatically mean you are only
working with alpha opacity adjusting of matrices
It doesn't mean you're only working with alpha opacity, but it is one of the fields of the matrix that involves alpha.
It is the field that your code is changing.
The ## in the Matrix## property are the row and column of that field in the matrix.
The rows and columns refer to the different color components.
The first row and first column (0) manipulate or use the red component.
The second row and second column (1) manipulate or use the green component.
The third row and column (2) manipulate or use the blue component.
The fourth row and column (3) manipulate or use the alpha component.
I forget the fifth row, as it is rarely used. It may be scaling, so can be use to skew colors, but you can look it up, as I may be incorrect.
(p.s. a quick view with the F1 help on color matrix says the fifth element is "w" and it always 1. Don't know just what that means, but is not important for the type of manipulation we're doing).
So, the identity matrix has the diagonals (0,0),(1,1),(2,2) etc... set to 1, and all other values set to 0.
(0,0) set to 1 says I want the 100% of the red component coming in to be the value of the red component coming out.
(1,1) set to 1 says I want 100% of the green component coming in to be the value of the green component coming out.
(2,2) set to 1 says I want 100% of the blue component coming in to be the value of the blue component coming out.
(3,3) set to 1 says I want 100% of the alpha component coming in to be the value of the alpha component coming out.
If we change any of the diagonal values, then we are scaling that particular color component coming in to a percentage of itself going out.
So, if we only want to change the alpha component to a scaled value of itself, then we change the value of the (3,3) field.
Now when you move away from the diagonals, then you are using the value of one component coming in to affect another component.
For instance, assume we start with the identity matrix, if we set (0,0) (red in, red out) to 0, then there will be no red in the output (based on the red component).
But, if we set another value in the first row(the red row), then we change the red component coming in to another color component, i.e.
if we set (0,1) = 1, then the red will become green. Magenta (red,blue) will become Cyan (green,blue), White (red,green,blue) will also become cyan (green, blue), because the green is already at 100% and the red is missing.
Of course, values less than 1 causes a percentage of the input to affect the output.
I guess I'll stop here as there are numerous tutorials already.
Quote:
Note: I found the Graphics.DrawImageUnscaledAndClipped method , but the rect structure represents:
..and not the rect to select the cropped portion of the source graphics,
which basically makes it useless from what I'm trying to do.
Someone pointed out in another thread that drawimageunscaled isn't doing what we would think it should do, so is not really what we're looking for anyway.
Also, all these "passel" examples we've been playing with here are doing cropped image transfers to the viewport.
Only a 256x256 portion of the source bitmap (256x1160) is being transferred to the display.
When you drag up and down in the box below the display you are selecting the portion of the source bitmap to transfer to the display. That is how it scrolls up and down.
Originally it used DrawImage with destination rectangle (dr, which never changed) and source rectangle (sr, whose Y value was modified to select the portion of the bitmap to transfer).
But, since we wanted to change the alpha and needed to use an imageAttributes object, we had to change to the DrawImage that had parameters of destination rectangle, with source defined by (x,y,width,height) instead of a source rectangle.
I don't know why they didn't provide a dest rect, src rect, with attributes version of drawImage.
Perhaps once they got to 30 overloads, they got tired.
As a quick test, you can make a couple changes in your last posted example:
Code:
Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics
' g.DrawImageUnscaled(bmLandScapeHorizontalStripCropped, 160, 116)
g.DrawImage(bmLandScapeHorizontalStrip, New Rectangle(160, 116, 240, 200), New Rectangle(tbHorizontal2.Value, 0, 240, 200), GraphicsUnit.Pixel)
End Sub
Private Sub tbHorizontal2_Scroll(sender As System.Object, e As System.EventArgs) Handles tbHorizontal2.Scroll
'Used for sidescrolling landscape background strip
'Grab a new horizontal crop section and transfer it to the viewport picbox
' bmLandScapeHorizontalStripCropped = CropBitmap(bmLandScapeHorizontalStrip, tbHorizontal2.Value, 0, _
' intHorizontalLanscapeViewportWidth, My.Resources.landscape_strip.Height)
' picLandscape.Image = bmLandScapeHorizontalStripCropped
Me.Invalidate() 'Used to update cropped landscape image on form (see Form Paint event)
End Sub
You should see that this is much more responsive since there is quite a bit less overhead in just drawing a portion of the existing bitmap, rather than creating multiple copies of the bitmap.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
It is something I've made up (unintentionally) by confusing, I think,
"Unity" amplifiers, which don't change the voltage levels of a signal,
with an "Identity" matrix, which doesn't change the values processed through it.
Hopefully this gaff will help cement the proper term in my mind.
So to be clear, I meant "identity" matrix.
Yes, thanks for clearing that up.
I thought I was just being a bit dense in not understanding what you were referring to.
This Identity matrix Wikipedia article says and Identity matrix is also known as a "unit matrix" (but not "unity matrix"),
whereas this purplemath page says the definition of an Identity matrix is a:
Quote:
diagonal matrix whose non-zero entries are all 1's
..by now I understand that, by your definition, an identity matrix is a:
Quote:
Originally Posted by passel
matrix without initialization parameters
Then there is this..
Quote:
Originally Posted by passel
The ## in the Matrix## property are the row and column of that field in the matrix.
Now when you move away from the diagonals, then you are using the value of one component coming in to affect another component.
A valuable piece of information
(even though I must say it's still easier for me to understand
color adjusting VB6 Long values then parsing all the permutation possibilities of colormatrix adjusting).
Does it say this (or infer) this anywhere in the documentation for the ColorMatrix class (or is this something I also missed?).
There is a MSDN Recoloring page I just found were the different sub-articles seem to imply this is the case
but I haven't found where it's said as succinctly as you said it..
(they always seem to want to lump color transforms with
scaling, rotation, and various other "translation" transforms).
Quote:
Originally Posted by passel
I don't know why they didn't provide a dest rect, src rect, with attributes version of DrawImage.
Perhaps once they got to 30 overloads, they got tired.
I wondered this as well.
I made the code changes you suggested,
but did you notice that my sample provided methods for
drawing to both a picturebox control and the form,
(I hid the picturebox but left the code in
so people would know how to do it either way).
Thus in applying your code you (probably unintentionally)
commented out my picturebox code,
but I restored it since it was intentionally supposed to be there.
It is, as you say, more responsive, but the DrawImage call,
because it's slow on some machines,
introduces a noticeable flicker.
As a solution I can set the Form's DoubleBuffer property to True and
the flickering issue is eliminated,
but the Picturebox doesn't have a DoubleBuffer property,
so, as an alternative, per this bobpowell article,
I have added the following code to form load:
Code:
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or _
ControlStyles.DoubleBuffer, True)
Me.UpdateStyles()
I think both the picturebox cropped image scrolling, and
the form cropped image scrolling, are now both pretty responsive.
However if there was an alternative to where I didn't have to use DrawImage at all
I think it would be faster still.
Well, that could be it too, I may have mixed the term "unit" matrix for "unity".
I guess I still don't try to understand the math behind the matrix and vectors that closely, as it is confusing to me as well.
But for the color matrix it is fairly easy for me to understand it this way.
"Inputs on the Left", "Outputs on the Top"
So "Red" is the first input (envision the Red Magnitude going into the matrix from the left on the first row).
The first output (first column) is red, so if I want red in to affect red out I put a number at (0,0)(first column, first row).
If I wanted the Red input (row 0) to affect the green output, then I would put a number in the Green column of that row (0,1).
If I wanted Red input to affect the Blue output then (0,2), or affect alpha level (0,3).
Likewise, Green input would be on the second row, and if I wanted to affect the Red output, put a number in the green input row, red output column (1,0).
(1,1) would be green in, green out.
etc....
Blue input affecting Green output, blue input row(2), green output column(1), put a number in (2,1).
etc...
That understanding makes it relatively easy to manipulate the matrix to do what you want, without having to understand the vector/matrix math behind how it does it.
Quote:
but the Picturebox doesn't have a DoubleBuffer property,
A picturebox is always doubled-buffered by design, so no property.
Quote:
However if there was an alternative to where I didn't have to use DrawImage at all
I think it would be faster still.
Well, if it is just panning background like a side scroller, you have the standard methods, using bitblt, or using a texturebrush.
I don't know if I'll get around to trying lockbits in that scenario, but I might try a drawimage, vs bitblt, vs texturebrush method in a standard sidescroller type situation at some point. But a number of different simultaneous projects at work are coming up, so I might be more busy than usual over then next few months, so may not feel like playing around as much.
I don't know if using lockbits would be much faster for than those last two methods for straight transfers.
If you wanted to do on the fly alpha blending, or other manipulations, then accessing the pixels directly would probably end up being the best method.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
viewport with adjustable cropped graticule image using alpha per pixel masking
Quote:
Originally Posted by passel
If you wanted to do on the fly alpha blending, or other manipulations, then accessing the pixels directly would probably end up being the best method.
Yes, I ended up using the FastPix code to access the pixels directly as you suggested.
The screenshot is elegantly simple but the coding is anything but..
I know of no other VB.Net demo that incorporates
this alphablended clone-cropped viewport alpha fade effect
(using a runtime per pixel alpha mask
created using a special custom linear colorblend brush rect fill).
It was a truly painful learning curve to climb.
I'm glad its done at last.
Towards an alpha thumb for a trackbar slider virtual control
Okay, the viewport with adjustable cropped graticule image using alpha per pixel masking works great
but I want to be able to control it with a trackbar slider that has alpha image thumb.
It's simple you just set:
Code:
TrackBar1.Thumb.Image.OpacityPercentage = 50
..unfortunately this doesn't work.
The Trackbar control doesn't have a "TrackBar1.Thumb.Image" property
let alone a "TrackBar1.Thumb.Image.OpacityPercentage" setting.
But all the other controls have an "Image.OpacityPercentage" setting, right?
Actual NONE of the VB.Net WinForms controls has such a property!
(what were the Microsoft VisualStudio.net developers thinking! )
Try googling for: vb.net control "OpacityPercentage"
..and see how many results you get (none involved slider control thumbs).
That's basically why I figure if I want this I'll have to roll my own.
(Note: I would try a custom usercontrol, based on an ownerdrawn trackbar,
if it weren't so ugly to begin with..)
My first though was just to recycle the code from the last post in the fuzzylines thread,
then just add mousemove dragging (and I still may do this),
but I wondered if there was an easier way?
Unlike VB6, VB.Net is supposed to support 32bpp .Png graphic picture files
with alpha opacity gradients, right?
Then there should be hundreds of code examples of dragging such alpha images, right?
Wrong! <*sigh*>
Googling for:
""vb.net" "per pixel alpha" drag only turned up 66 results
(mostly semi-transparent form code --and yeah I tried it without quotes and various
other keyword permutations like ".net alpha drag",
"perpixelalpha drag" and "alpha opacity gradient drag"
but the searching just kept looping back to this thread )
Quote:
Originally Posted by edit
I did find this xvbt thread though, that tantalizingly encouraged me, but Cadde's code still PInvokes behind.Net wrappers,
and boops boops' code is only designed to work when doing a partial screenshot grab (the part behind a form).
Okay, then, looks like I have to make up the first ever demo example of dragging an alpha image using VB.Net.
The 32bpp alpha png is from this psc project.
The result is attached below.
Its hard to tell from the screenshot but the code filters out non-visible pixels
in the mousedown event (it will not allow dragging of transparent pixels),
However I wish there was a way to adjust the sensitivity of this.
Maybe some kind of function/routine to vary the "opacity dragging threshold",
because right now it seems like that even if a pixel is 1% semi-transparently visible,
then that pixel still allows dragging,
and if I could I would like the set the "opacity dragging threshold" to
something in the 10 to 20% range.
...
The result is attached below.
Its hard to tell from the screenshot but the code filters out non-visible pixels
in the mousedown event (it will not allow dragging of transparent pixels),
However I wish there was a way to adjust the sensitivity of this.
Maybe some kind of function/routine to vary the "opacity dragging threshold",
because right now it seems like that even if a pixel is 1% semi-transparently visible,
then that pixel still allows dragging,
and if I could I would like the set the "opacity dragging threshold" to
something in the 10 to 20% range.
So, if you want it, why not do it?
I'm assuming you wrote the code.
The last line in your "PointIsOverPicture" function tests the Alpha level.
Return (bm1.GetPixel(i, j).A > 0)
Change the 0 to the percentage you want to be a valid pixel (say > 50%)
Return (bm1.GetPixel(i, j).A > 127) 'or Cint( .5 * 255), if you want
A quick test is to put a band of translucent pixels through the middle of your clock face.
Code:
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
'bm1 = New Bitmap(My.Resources.clockface3_copy) '32 bits per pixel .bmp image doesn't work!
bm1 = New Bitmap(My.Resources.clockface3) 'png with alpha works!
Dim x As Integer, y As Integer, colr As Color
For y = (bm1.Height \ 2) - 5 To (bm1.Height \ 2) + 5 '10 pixel high band in the middle
For x = 0 To bm1.Width - 1
colr = bm1.GetPixel(x, y)
colr = Color.FromArgb(126, colr)
bm1.SetPixel(x, y, colr)
Next
Next
'Debug only (label's visible property set to False)
lblWidth.Text = "Image Width = " & My.Resources.clockface3.Width
lblHeight.Text = "Image Height = " & My.Resources.clockface3.Height
spriteLocation = New Rectangle(0, 0, _
(My.Resources.clockface3.Width), _
(My.Resources.clockface3.Height))
End Sub
With the threshold set to (> 127) in PointIsOverPicture, you can't drag in the translucent band across the clock face.
If you set the opacity in the loop above to 128, then you can drag in the translucent band. (or you could lower the threshold to > 125).
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
This works great tested with your form load code
(and maybe in the future I will tie it in with a runtime trackbar slider control adjust),
however the new form load code also causes a visual artifact (see attached screenshot).
Note: I widened your GetPixel/SetPixel code to 60 pixels..
Quote:
For y = (bm1.Height \ 2) - 30 To (bm1.Height \ 2) + 30 '60 pixel high band in the middle
For x = 0 To bm1.Width - 1
colr = bm1.GetPixel(x, y)
colr = Color.FromArgb(126, colr)
bm1.SetPixel(x, y, colr)
Next
Next
..so you could get a better look..
Is there a quick GetPixel code that test that can be used/inserted
to only adjust the pixels based on an opacity threshold?
For instance:
1.) Totally visible pixels would be adjusted
2.) Totally non-visible (transparent) pixels would not be adjusted
3.) Partially visible (semi-transparent) pixels would undergo some kind of variable level "case..select" branch decided adjust
based on the alpha level (say between 25 and 250)
For #3, would use use the Color.FromArgb method to extract the "A" value
from colr and then (somehow) feed it back into colr
(all tied it with an if statement for doing the test)?
I know I could make the test using GetPixel on a separate greyscale mask,
but I'm trying not to have to use such a programmaticly-at-runtime created mask (in order to save memory).
Well, since you have to get the pixel to modify it, then, yes, simply add an If condition.
I noticed the artifacts but figured you could account for them if you wanted. It is mostly just the fully transparent pixels around the face being set to no longer transparent.
But you do have some semi-transparent pixels in the shadow.
But the purpose wasn't to demonstrate adjusting the transparency of an image.
The assumption is you have an image with the transparency you want, you just wanted to specify the level of opacity to considered not part of the image, so modifying the image in code was the simplest way to demonstrate that, without having to manually update the image in a paint program and redo the example.
If you don't want the squared off edges cause by increasing the alpha value of pixels less than the opacity level being set, then only adjust pixels with alpha values greater than the value being set.
Of course, again, adjusting the image dynamically is not the point, it just saved work on having to create a modified image to demonstrate the "not dragging" criteria.
Code:
For y = (bm1.Height \ 2) - 15 To (bm1.Height \ 2) + 15
For x = 0 To bm1.Width - 1
colr = bm1.GetPixel(x, y)
If colr.A > 126 Then
colr = Color.FromArgb(126, colr)
bm1.SetPixel(x, y, colr)
End If
Next
Next
Quote:
...
1.) Totally visible pixels would be adjusted
2.) Totally non-visible (transparent) pixels would not be adjusted
3.) Partially visible (semi-transparent) pixels would undergo
some kind of variable level "case..select" branch decided adjust
based on the alpha level (say between 25 and 250)
The simplest solution to those three conditions would be to multiply by a scale factor, which is essentially what we usually use the color matrix for.
Since we want fully opaque pixels (255) to be set to 126, set the scale factor to 126/255.
The three conditions multiplied by the scale factor give us:
1. (255 * 126/255 = 126) 'Fully opaque adjusted to 126
2. (0 * 126/255 = 0) 'Totally transparent not adjusted
3. (X * 126/255 = scaled down version of X)
Code:
Dim x As Integer, y As Integer, colr As Color, alpha As Integer
Dim sf As Single = 126.0F / 255.0F 'we want Full (255) Alpha to scale to 126. Other alpha's will scale proportionally
For y = (bm1.Height \ 2) - 30 To (bm1.Height \ 2) + 30 '10 pixel high band in the middle
For x = 0 To bm1.Width - 1
colr = bm1.GetPixel(x, y) 'get the pixel color
alpha = CInt(sf * colr.A) 'scale the Alpha component by our scale factor
colr = Color.FromArgb(alpha, colr) 'Update our color with the scaled alpha
bm1.SetPixel(x, y, colr) 'update the pixel with the modified color
Next
Next
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
alpha opacity threshold dragging with dynamic (runtime) alpha adjust
Quote:
Originally Posted by passel
If you don't want the squared off edges
(caused by increasing the alpha value of pixels less than the opacity level being set),
then only adjust pixels with alpha values greater than the value being set.
Your first set of updated code clears the visual artifacts.
Quote:
Originally Posted by passel
The simplest solution to those three conditions would be to multiply by a scale factor,
which is essentially what we usually use the color matrix for...
I would never ever have come up with this code.
(I did a google search for "vb.net" "scaled alpha"
and I didn't find anything like your code coming up
so I'm thinking not many other people have played around with
using scaled alpha code in combination with alpha opacity dragging threshold coding).
Thank you.
But which set of code is more flexible?
It turns out to be the second set of code.
The scaled alpha code allows a trackbar slider to adjust the alpha (opacity /transparency level) dynamically at runtime and
still have allow the alpha opacity dragging threshold to function properly.
You'll notice in the screenshot how the trackbar slider control
really sticks out in a very ugly way because there is no way to
set the background color to transparent.
(error: "Property not supported")
Darn you Microsoft!
How hard could it be to make something that looks like a trackbar slider and yet still allows a form background to show through.
So I tried making up a custom slider that uses:
Code:
Public Class MySlider
Inherits UserControl
It's a bit crude (there's no real tick frequency adjusting code.. probably needs some kind of code that uses "Mod"),
but it basically works and exposes both a "pos" (position value)
and seems to have the ability to generate a pos changed event.
Of course I intend to use a much nicer thumb
but this will give me something to play with
to try and make a slider with a transparent background png
(and soft fuzzy shadowing) that can have its pixels alpha adjusted at runtime.
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET. subscribe