My Aim:
I'd like to have the ability to retrieve the colour on the screen including the cursor, from certain coordinates.
In other words, I suppose you could say I'd like to retrieve the colour of the cursor (or at least, a certain point/pixel on the cursor).
My Difficulty:
I have some code already to retrieve the colour on the screen from certain coordinates, however I believe it does not include the cursor. I believe this to be because the method I'm using takes a screenshot (without the cursor), and reads colour from that.
My Current Code:
public static Color RetrieveColour(Point Coordinates)
{
//Use this 'image' to create a Graphics class.
using (Graphics Destination = Graphics.FromImage(ScreenPixel))
{
//Creates a graphic from the specified handler to a window.
//In this case, it uses a handler which has been initialised to zero.
using (Graphics Source = Graphics.FromHwnd(IntPtr.Zero))
{
//Handler from the source device context.
IntPtr HandlerSourceDC = Source.GetHdc();
//Handler to the destination device context.
IntPtr HandlerDC = Destination.GetHdc();
//BitBlt is responsible for doing the copying.
//Returns a non-zero value for upon success.
int retval = BitBlt(HandlerDC, 0, 0, 1, 1, HandlerSourceDC, Coordinates.X, Coordinates.Y, (int)CopyPixelOperation.SourceCopy);
//Release the handlers.
Destination.ReleaseHdc();
Source.ReleaseHdc();
}
}
//Retrieve the colour of the pixel at the specified coordinates.
return ScreenPixel.GetPixel(0, 0);
}
I should probably add, it should work with non-Windows cursors. By this I mean custom cursors from other applications (if that has any bearing on future answers).
As far as I am currently aware, the only way that you'd be able to do this is if you were to create a custom driver that can act as an intermediary between the user.
I haven't read much of it, but you might want to look into this project
http://www.codeproject.com/KB/cs/DesktopCaptureWithMouse.aspx?display=Print
Previously posted here: C# - Capturing the Mouse cursor image
Related
I am adding two different images on win2d canvas in different points and different size and run application display two images perfect points set to display. Then how I am select image and move on canvas.
Win2D is an immediate mode graphics library (from Wikipedia)
Immediate mode rendering is a style for application programming interfaces of graphics libraries, in which client calls directly cause rendering of graphics objects to the display. It does not preclude the use of double-buffering. In contrast to retained mode, lists of objects to be rendered are not saved by the API library. Instead, the application must re-issue all drawing commands required to describe the entire scene each time a new frame is required, regardless of actual changes. This method provides the maximum amount of control and flexibility to the application program.
So it's up to you to keep the reference of any object you want to modify, because once it's drawn it is lost.
So define your CanvasBitmap as a global resource or create some type of ResourceLocator. Then create a your own class that stores x,y,width,height kinda like a custom object;
public class GenericItem
{
public CanvasBitmap b;
public int x;
public int y;
public int w;
public int h;
}
Modified Example from Win2D:
CanvasBitmap cat, mouse;
GenericItem gi_cat;
load your bitmaps in:
async Task CreateResourcesAsync(CanvasControl sender)
{
cat = await CanvasBitmap.LoadAsync(sender, "ShawnsCat.jpg");
mouse = await CanvasBitmap.LoadAsync(sender, "Mouse.png");
// create your GenericItem here
gi_cat = new GenericItem();
// fill in your x,y,width,height,bitmap
}
now draw
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
args.DrawingSession.DrawImage(gi_cat.b, gi_cat.x, gi_cat.y);
}
now you can modify gi_cat.x gi_cat.y and whatever property you added.
gi_cat.x = 500;
gi_cat.y = 250;
and you can cause a redraw calling the Invalidate Method on the canvas control.
name_of_your_canvas.Invalidate();
which will cause the canvas control to redraw with the new position.
Basically you have to handle everything yourself. If you looking for a DOM like approach then just use the regular Canvas control available in XAML.
I have a pretty in depth Win2D Walkthrough here :
Win2D Getting Started: Windows Universal Application
I think I am fundamentally misunderstanding the way render targets work. In my understanding RenderTargets are just Textures that the spritebatch draw calls draw to.
So I tried this code to render GUI windows in order to make sure they can only draw in their client area and its cropped outside that.
for (int i = Controls.Count - 1; i >= 0; i--)
{
RenderTarget2D oldTarget;
if (graphics.GetRenderTargets().Count() == 0) oldTarget = null;
else oldTarget = (RenderTarget2D)graphics.GetRenderTargets()[0].RenderTarget; // Get the old target being used.
graphics.SetRenderTarget(canvas); //set the target to a temporary RT
graphics.Clear(Color.Black); // Clear it
Control c = Controls[i]; // Get the current control (a form in this case)
c.Draw(spriteBatch, gameTime); // Draw it to the temp RT
graphics.SetRenderTarget(oldTarget); // Set the RT back to the main RT
Vector2 dest = c.DrawCoOrds(); // Gets the draw coordinates of the control
spriteBatch.Begin();
spriteBatch.Draw(canvas, new Rectangle((int)dest.X, (int)dest.Y, c.Bounds.Width, c.Bounds.Height), new Rectangle((int)dest.X, (int)dest.Y, c.Bounds.Width, c.Bounds.Height), Color.White);
// take the rect from the temp RT and draw it to the main RT.
spriteBatch.End();
}
However this code only draws the last form in the list which means it must be clearing the main RT somehow but i dont understand why. I only call clear when the RT is set to the temp canvas.
i think the best method to draw gui controls is with ScissorRectangle, because lets draw only inside that rectangle, that can be the client area of the gui control.
MSDN: GraphicsDevice.ScissorRectangle
You need to enable this funcionality through a RasterizerState.
RasterizerState ScissorState = new RasterizerState()
{
ScissorTestEnabled = true;
}
Before you draw, call SpriteBatch.Begin with this state.
A video of my own gui running in a xbox360 :)
How did you create your render target and back buffer? By default you can't write to a render target multiple times after changing to a different render target. This is why:
http://blogs.msdn.com/b/shawnhar/archive/2007/11/21/rendertarget-changes-in-xna-game-studio-2-0.aspx
You can change the default behavior by creating your render targets with RenderTargetUsage.PreserveContents., and the back buffer by overriding GraphicsDeviceManager.PrepareDeviceSettings., changing GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage, as described in the link. Although I believe overriding those settings is done differently in XNA 4.
All that being said, changing away from the default behavior has performance considerations, and is not recommended. You should find a way to do this differently. One possibility would be to create a separate render target for each of your windows, draw all of them, switch to the back buffer and draw the render targets to it.
A better option would be to use the scissor rectangle rasterizer state as proposed by #Blau.
I am using stylus input to draw lines in a canvas. I want to change the color of the stroke with the pen pressure. so I used:
DrawingAttributes dattribute = new DrawingAttributes();
inkcan.EditingMode = InkCanvasEditingMode.Ink;
if (stylusInput.pressureFactor < 0.5)
dattribute.Color = Colors.Red;
else
dattribute.Color = Colors.Blue;
inkcan.DefaultDrawingAttributes = dattribute;
but I have found that the color changes only when I lift off and retouch the pen to tablet surface. I am not sure how to fix that problem.
Any help would be greatly appreciated.
Look at this question: InkCanvas Eraser
In the MSDN it states:
If you change the EraserShape, the cursor rendered on the InkCanvas is
not updated until the next EditingMode change.
The effect you are experiencing might be caused by the EditingMode being changed when you pull the pen off the canvas and put it back down.
If so, you could toggle the EditingMode property as I suggested in the linked answer.
EDIT
Have a look at this a 3rd down it says:
Off course, life is never as simple as that, so there is one more
little issue to handle. Apparently, the InkCanvas uses different
renderers for the final result compared to while the strokes are being
drawn. To show a transparency based on the pressure while the
drawing action is still in progress, we need to use the protected
property called DyamicRenderer which gets/sets the object used to
render the strokes on a drawing context while the stroke is being
drawn. This rendering object must be a descendent of DynamicRenderer.
All you need to do here is override the OnDraw method and change the
brush that is used. When you assign a new value to this property, the
InkCanvas actually changes an internal 'PlugIn list' which is called
whenever data is entered using the stylus.
This might be it.
The if condition is evaluated only once, so there is no reason for the colour to change while you are drawing. Unfortunately, there seems to be no "onpressurechanged" event, so you would probably have to set up a loop that checks the pressure every x milliseconds and adjusts the colour accordingly.
Since you don't want to freeze the UI, you would either need to run it in another thread and delegate the colour change back to the UI thread, or you can queue the pressure checks onto the window dispatcher with "applicationIdle" priority. This would look something like:
void checkPressure(InkCanvas inkcan)
{
//return if touch is lifted code here
DrawingAttributes dattribute = new DrawingAttributes();
if (stylusInput.pressureFactor < 0.5)
dattribute.Color = Colors.Red;
else
dattribute.Color = Colors.Blue;
inkcan.DefaultDrawingAttributes = dattribute;
this.Dispatcher.BeginInvoke(new MyPressureDelegate(checkPressure), DispatcherPriority.ApplicationIdle, inkcan);
}
assuming your stylusInput shares scope with the function, of course. Otherwise you'd need to pass it in along with the canvas in an object array.
It's a little hard to explain what I need but i'll try:
I need to write application (winform) which will be some kind of filter to image/other forms behind it. With one exception - all behind form should looks as is except of red (for example) color, which have to be replaced to any other specified color, white for example.
So let's imagine I have opened windows Word with few lines of text. With red and black letters.
So when i place my application above this text - it should "filter" red symbols and fill them to white.
So as i understand this task: i have to snap area behind the form, then process it (replace colors) and after draw this image on my form body.
Any links or keywords for solution?
UPD:
so - this is my final solution:
do form transparent (using TransparencyKey and BackColor properties)
place picturebox over the form
when we need to update image in picturebox - we replace current image with pictureBox1.Image = null;, then refreshing form with (this.Refresh()) and do new snapshot
thanks for all ;-)
UPD 2:
sample http://dl.dropbox.com/u/4486681/result.png
UPD 3:
here are sources
you can create a snapshot of the desktop using the following code:
public Bitmap CaptureScreen()
{
Bitmap b = new Bitmap(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height);
Graphics g = Graphics.FromImage(b);
g.CopyFromScreen(0, 0, 0, 0, b.Size);
g.Dispose();
return b;
}
Replace the dimensions and position with the coordinates of your form. This way you get a bitmap of what's behind your form. Then you can do the color replacement on that bitmap.
Please note that due to settings like ClearType and other anti-aliasing mechanisms, you have to also take into account "intermediate pixels" when doing the color replacement. Otherwise things will look funny :-)
I don't know if this can be done at all (let's see what others answer :-).
You can get a handle to the screen device context, which gives you a bitmap of the screen.
HDC dc = GetDC(NULL);
(This is C++, you'll have to use P/Invoke, or create a mixed-mode library in C++)
Then you can redraw a region of the screen with your filtering process.
Now the problems start:
how do you know that the pixels in your interesting region has changed ?
if the region changes, are the changes visible or are they hidden by your own drawing.
You could have a button somewhere that hides your own app momentarily and shows it back when re-pressed, and filters the new content.
Good luck. Any possibility of sharing the user scenario ?
is there a way, to make a picture transparent in CF2.0? I have to lay a small Image over a textbox, but it has to be transparent so the User can see the text anyway. Do you have an Idea?
Thank you very much
twickl
Edit:
Thanks for your answers, I will check those links out!
To complete my Post, here is what I´m trying to do:
I want to show a small image (the image does not exist yet and I have to make ist, so I´m totaly open for all formats) that is an X on the right end of a textbox. By clicking that X the Text inside the textbox will be erased...like on the iPhone. But I can not build my own control becuse in my Project are so many TextBoxes that are allready custom Controls with the windows TextBox on it, that it will be to much work and testing to switch all of them to custom controls. So I have the Idea to make a small Panel, Picturebox, whatever, that lays above the Textbox. But it has to be transparent. The OS is Windows CE 5.0 with CF 2.0 on it.
Depending on what kind of transparency you need, you might choose any of these options:
1.) If you have an image with a specific portion that should be entirely transparent, you can use ImageAttributes.SetColorKey() to set a single transparent color and then pass this to Graphics.DrawImage. Your image will need to have one color (e.g. Color.Cyan) that will be drawn completely transparent.
2.) If you'd like the entire image to be partially transparent, e.g. for a fade in/fade out effect, you can P/Invoke the AlphaBlend() function, as demonstrated here.
3.) If you have an image with transparency information built in, e.g. a transparent PNG image that needs to be rendered on a variety of background colors, these previous methods will not work and you need to use the COM based IImage interface.
The COM interop from .NETCF is documented on this page (search for "IImage interface" on that page).
Option 3 is the most flexible, but it also involves the most implementation effort. If you follow up with more information about the kind of image you want to draw transparently and your target platform, we might be able to help more.
I did it by deriving a class from PictureBox and handling OnPaint. The key is the ImageAttributes object passed to DrawImage. I'm assuming pixel 0,0 is the transparent color, but you could handle that differently.
public partial class TransparentPictureBox : PictureBox
{
private Color tColor;
public TransparentPictureBox()
{
InitializeComponent();
}
public new Image Image
{
get { return base.Image; }
set
{
if (value == base.Image)
return;
if (value != null)
{
Bitmap bmp = new Bitmap(value);
tColor = bmp.GetPixel(0, 0);
this.Width = value.Width;
this.Height = value.Height;
}
base.Image = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(this.BackColor);
if (Image == null)
return;
ImageAttributes attr = new ImageAttributes();
// Set the transparency color.
attr.SetColorKey(tColor, tColor);
Rectangle dstRect = new Rectangle(0, 0, base.Image.Width, base.Image.Height);
e.Graphics.DrawImage(base.Image, dstRect, 0, 0, base.Image.Width, base.Image.Height, GraphicsUnit.Pixel, attr);
}
}