I am trying to create a bitmap copy of a view to use it as a drag shadow for a drag & drop operation.
I have used the techniques described here:
How to capture UIView to UIImage without loss of quality on retina display
How Do I Take a Screen Shot of a UIView?
How to get a color image in iPhone sdk (to render a solid fill into the view, resulted in an empty image too)
But the result is always a transparent/empty image (it's not nil/null, I checked)
The views I'm trying to copy contain (transparent) SVGs.
Here is my code:
// always results in an fully transparent/empty image
private UIView CreateDragShadow(UIView view)
{
UIGraphics.BeginImageContextWithOptions(view.Bounds.Size, false, 0.0f);
CGContext context = UIGraphics.GetCurrentContext();
//view.DrawViewHierarchy(view.Bounds, true); // "old" way
view.Layer.RenderInContext(context); // recommended way
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
UIImageView dropShadow = new UIImageView();
dropShadow.Image = image;
return dropShadow;
}
I have also written a little test function to see if the view gets added to the superview correctly, which works and correctly produces a white UIView with "Drag shadow" written on it:
// this produces a white drag shadow image with "Drag shadow" written on it
private UIView CreateDragShadowTest(UIView view)
{
// test with a simple UITextView to see if the approach works
UITextView viewTestShadow = new UITextView(view.Frame);
viewTestShadow.Bounds = view.Bounds;
viewTestShadow.Text = "Drag shadow";
return viewTestShadow;
}
Does anybody know what's going on?
I'm also open to entirely different ways of doing this.
Best regards!
I have since found an answer on the Xamarin documentation page that I couldn't find mentioned anywhere else when searching SO
The new code is:
private UIView CreateDragShadow(UIView view)
{
UIView dropShadow = view.SnapshotView(true);
return dropShadow;
}
Which exposes snapshotViewAfterScreenUpdates (found here: Apple Doc snapshotViewAfterScreenUpdates) and conveniently produces a UIView snapshot.
This solution has worked for me, but I would still like to know what I was doing wrong with the other approaches, if anybody knows.
Related
and thanks for taking a peek at my conundrum.
I am trying to write a series of strings to an image as overlays, then later be able to come back and move, or delete one of them selectively using WPF framework...
I've been looking into the FindVisualChildren function, but for the moment cant make heads or tails of how to detect the proximity to the mouse (for selectivity), or actually detect one of my created strings (Perhaps I should be making them dynamic 'Label' elements...????)
Insomnia sucks, and my brains are turning to mush.
TIA for any advice!
Okay, sorry for the lack of sample code, been a long night... well two nights actually (See earlier comment about insomnia)
public void WriteTextToImage(Point position)
{
ImageSource bitmapSource = imgFrame.Source;
var vis = new DrawingVisual();
using (DrawingContext drawingContext = vis.RenderOpen())
{
// Set the pen color... Why is this called a brush if it's for
// writing? perhaps I should overload it and call it crayon?
SolidColorBrush brush = new SolidColorBrush((Color)cpColor.SelectedColor);
drawingContext.DrawImage(bitmapSource, new Rect(0, 0, imgFrame.Source.Width, imgFrame.Source.Height));
//Write some pretty words, (actually print some general stuff)
drawingContext.DrawText(new FormattedText(tbCurrentLabel.Text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface("Arial"), slFontSize.Value, brush),position);
}
//Slap this puppy to the screen
var image = new DrawingImage(vis.Drawing);
//Iterate the label text to the next digit or value
IterateLabel();
}
Basically what will happen is the user will click the screen in several places to make marks on the image for printing, but I want to include support to move those marks, and delete them as needed.
I hope this explains what I am trying to accomplish a little better.
Thanks again!
Excellent! thanks NineBerry, I figured it was going to be something like that. I was originally thinking a label, but the textblock worked perfectly.
Here's the updated code showing how I am getting it done now.
public void WriteTextToImage(Point position)
{
SolidColorBrush brush = new SolidColorBrush((Color)cpColor.SelectedColor);
//Get something to write on (not an old receipt...)
TextBlock textBlock = new TextBlock();
//Say something useful... well something atleast...
textBlock.Text = tbCurrentLabel.Text;
textBlock.FontSize = slFontSize.Value;
textBlock.Foreground = brush;
Canvas.SetLeft(textBlock, position.X);
Canvas.SetTop(textBlock, position.Y);
canvas.Children.Add(textBlock);
//Need to update the canvas, was not seeing children before doing this.
canvas.UpdateLayout();
//Iterate the label text
IterateLabel();
}`
I would like to show 1 million locations on a map based on OpenStreetMap.
I work on C# VS2013 and GMAP.NET WPF. But, when I added markers for each location, the map cannot be shown up because the marker is a bitmap image.
And 1 million markers consume too much memory on my laptop (with 8 GB mem).
The code is:
public void add_marker(List<Tuple<double, double>> latLongList, ref GMapControl myMap)
{
System.Windows.Media.Imaging.BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(#"C:\djx_2014_6_3\my_projects\test_gmap_dot_net\GMap_WPF\try1\try_gmap_wpf\try_gmap_wpf\images\map_marker.png", UriKind.Absolute);
bitmapImage.DecodePixelHeight = 5;
bitmapImage.DecodePixelWidth = 5;
bitmapImage.EndInit();
foreach(var v in latLongList)
{
GMap.NET.PointLatLng point = new GMap.NET.PointLatLng(v.Item1, v.Item2);
GMapMarker marker = new GMapMarker(point);
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = bitmapImage;
marker.Shape = image;
marker.ZIndex = 5;
myMap.Markers.Add(marker);
}
}
I do not want to use the image as markers but I cannot find out how to use default marker in openStreetMap.
Any help would be appreciated.
WPF wasn't designed to be used for things like this. First of all you're creating a Bitmap for each tag, which is a user control and comes with some pretty heavy overhead for GUI hit-testing and binding etc. Secondly, WPF renders with DirectX, which means at some point all that data has to be set up with vertex buffers and uploaded into the graphics card. If you use data binding or try to create separate UI elements then this is going to take a lot of initial set-up time and memory, as you have already discovered. And if you try to draw them yourself (e.g. by creating your own user control and overriding OnRender) then it can be even worse, since all that work is now being done every frame (apart from buffered stuff which still incurs the initial setup anyway so you're back to square one).
If I had to do this myself I would start by organizing the data set with an appropriate 2D structure such as a k-d tree, an R*-tree or even a basic quad-tree. This will allow you to quickly determine at any given moment which markers are in the view frustum.
Next, I would add the appropriate bindings to scrollbars etc so that I could monitor exactly where the current view frustum was, and then each frame I would update the list of visible tags based on that. So long as you don't have more than a few thousand objects comes into view at once you should be ok, otherwise you'll have to stagger the updates over multiple frames with a queue.
If that doesn't suit your needs then you really have only two options left: 1) generate the raw bitmap data yourself manually, or 2) use a more suitable technology.
I'm working with Windows Phone 8/C# Silverlight and using code similar to this to render text:
TextBlock drawStringInstance = new TextBlock();
drawStringInstance.Text = str;
drawStringInstance.Opacity = 1;
drawStringInstance.Measure(new Size(1000000, 1000000));
WriteableBitmap wb = new WriteableBitmap((int)drawStringInstance.ActualWidth, height);
wb.Render(drawStringInstance, null);
wb.Invalidate();
Notice that I don't save the image and draw it directly so there shouldn't be any saving artifacts. If I just place the text block I get much crisper text with less aliasing as such (left is the "good" rendering):
Is there something I can do to improve this or is this an inherent issue with the approach of WriteableBitmap.Render()?
I think you're not supposed to render elements that are not in the visual tree. In fact , your code does not render anything on my emulator.
Just add the textblock somewhere on the page (perhaps set the margin to -1000 so that it does not show) , then render it.
What's the quickest way to show a red/green light indicator on a C# form?
I originally thought about using radio buttons, but not sure how to set the color of the dot, only the foreground/background text.
Then I thought about drawing a circle. Couldn't find a toolbox shape for that, and didn't want to write code just to draw the circle.
Basically, I'm writing a little application specific monitor, that shows a red light if certain services are down, or certain web services are not responding.
This is what I have so far using a square button instead of a circle. The code is just what I want, I just want a round shape.
if (allGood)
{
btnIISIndicator.BackColor = Color.Green;
}
else
{
btnIISIndicator.BackColor = Color.Red;
}
This is simple, just use System.Windows.Shapes for the object and System.Windows.Media.Brushes for the colors.
For a circle you can do the following:
System.Windows.Shapes.Ellipse circle = new System.Windows.Shapes.Ellipse();
circle.Height = 20; //or some size
circle.Width = 20; //height and width is the same for a circle
circle.Fill = System.Windows.Media.Brushes.Red;
Then you can make a function to do your check for red and green.
Also, you can use hex values for the colors as well:
circle.Fill = new System.Windows.Media.SolidColorBrush((Color)ColorConverter.ConvertFromString("#RRGGBB"));
Not exactly related to the question at hand, but your code could be shortened somewhat using the ternary operator as such:
btnIISIndicator.BackColor = allGood ? Color.Green : Color.Red;
But that all depends on your (or your organization's) definition of readability and maintainability.
I would just make a panel or PictureBox and set the Background image to that of a red/green light. Either make the images in PhotoShop/PaintShop/MS Paint or download some stock images off the web.
Whenever the status changes, just swap the image out.
just try this it works for me.
SolidColorBrush solidColor=new SolidColorBrush();
solidColor.Color=Colors.Red;
ellips_circle.Fill=solidColor;
Use an image, but theres some great icons available here so you dont have to actually make some.
Create red and green bitmaps and use the PictureBox control to show the bitmaps.
I just use some standard images and put them in a picturebox. works great on our apps.
I simply used a non enabled button as indicator since I did not manage to install the WinUI for shapes. Same suggestion as question but simplified.
indicatorButton.Enabled = false;
...
if (allGood)
{
indicatorButton.BackColor = Color.Green;
indicatorButton.Text = "On";
}
else
{
indicatorButton.BackColor = Color.Red;
indicatorButton.Text = "Off";
}
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);
}
}