I am using Bing Maps to make some kind of editor. One of the things the editor needs to do as add an Image to the map and have it not scale. I can add the image with out any problem but I cant seem to keep it from scaling when you change your zoom level. Is there a way to set the scale to be fixed when you create the image and add it to the map. I really want to avoid always changing the scale of the image when the zoom level changes as there can be ton of these images on the map.
I did find this question but that did not seem to fix my problem.
here is the code I am using so far:
MapLayer imageLayer = new MapLayer();
Image image = new Image();
image.Height = 150;
BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri("../../triangle.jpg", UriKind.Relative);
myBitmapImage.DecodePixelHeight = 150;
myBitmapImage.EndInit();
image.Source = myBitmapImage;
image.Opacity = 0.6;
image.Stretch = System.Windows.Media.Stretch.None;
//The map location to place the image at
Location location = new Location() { Latitude = 37.8197222222222, Longitude = -122.478611111111};
//Center the image around the location specified
PositionOrigin position = PositionOrigin.Center;
imageLayer.AddChild(image, location, position);
MapWithPolygon.Children.Add(imageLayer);
The code you provided won't scale the image when zooming. It's possible that it might look slightly scaled due to the background changing but the physical pixel size of the image will not change. The image will only scale if you bounded it to a LocationRect instead of a location.
Related
Bitmap image = ReadBitmap("image.png");
Bitmap imageCopy = new Bitmap(image);
Bitmap canvas = new Bitmap(imageCopy.Width+100, imageCopy.Height);
// From this bitmap, the graphics can be obtained, because it has the right PixelFormat
using(Graphics g = Graphics.FromImage(canvas))
{
// Draw the original bitmap onto the graphics of the new bitmap
g.DrawImage(image, 0, 0);
}
// Use tempBitmap as you would have used originalBmp
InputPictureBox.Image = image;
OutputPictureBox.Image = canvas;
I haven't understood the output of this c# code.
The original image is not placed at the correct position. It should have been at (0, 0).
Also, I need a black background.
So, what is going on and how to correct this?
You are loading an Image, then a copy of this source is created using:
Bitmap bitmap = new Bitmap();
When you create a copy of an Image this way, you sacrifice/alter some details:
Dpi Resolution: if not otherwise specified, the resolution is set to the UI resolution. 96 Dpi, as a standard; it might be different with different screen resolutions and scaling. The System in use also affects this value (Windows 7 and Windows 10 will probably/possibly provide different values)
PixelFormat: If not directly copied from the Image source or explicitly specified, the PixelFormat is set to PixelFormat.Format32bppArgb.
From what you were saying, you probably wanted something like this:
var imageSource = Image.FromStream(new MemoryStream(File.ReadAllBytes(#"[SomeImageOfLena]"))), true, false)
var imageCopy = new Bitmap(imageSource.Width + 100, imageSource.Height, imageSource.PixelFormat))
imageCopy.SetResolution(imageSource.HorizontalResolution, imageSource.VerticalResolution);
using (var g = Graphics.FromImage(imageCopy)) {
g.Clear(Color.Black);
g.CompositingMode = CompositingMode.SourceCopy;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imageSource, (imageCopy.Width - imageSource.Width) / 2, 0);
pictureBox1.Image?.Dispose();
pictureBox2.Image?.Dispose();
pictureBox1.Image = imageSource;
pictureBox2.Image = imageCopy;
}
This is the result:
(The upper/lower frame black color is actually the Picturebox background color)
When the original Image Dpi Resolution is different from the base Dpi Resolution used when creating an Image copy with new Bitmap(), your results may be different from what is expected.
This is what happens with a source Image of 150, 96 and 72 Dpi in the same scenario:
Another important detail is the IDisposable nature of the Image object.
When you create one, you have to Dispose() of it; explicitly, calling the Dispose method, or implicitly, enclosing the Image contructor in a Using statement.
Also, possibly, don't assign an Image object directly loaded from a FileStream.
GDI+ will lock the file, and you will not be able to copy, move or delete it.
With the file, all resources tied to the Images will also be locked.
Make a copy with new Bitmap() (if you don't care of the above mentioned details), or with Image.Clone(), which will preserve the Image Dpi Resolution and PixelFormat.
I am not completely clear on what you are actually needing to do. But anyway, here is a WPF-friendly example of how to draw an image at a specific position inside another image.
Note if all you want to do is display the image in different size and/or put a black border around it, there are much simpler ways to do simply that, without having to create a second image, such as just laying out the image inside a panel that already has the border style you want.
Notice that I am using classes from the System.Windows.Media namespace because that is what WPF uses. These don't mix easily with the older classes from System.Drawing namespace (some of the class names conflict, and Microsoft's .Net framework lacks built-in methods for converting objects between those types), so normally one needs to simply decide whether to use one or the other sets of drawing tools. I assume you have been trying to use System.Drawing. Each has its own pros and cons that would take too long to explain here.
// using System.Windows.Media;
// using System.Windows.Media.Imaging;
private void DrawTwoImages()
{
// For InputPictureBox
var file = new Uri("C:\\image.png");
var inputImage = new BitmapImage(file);
// If your image is stored in a Resource Dictionary, instead use:
// var inputImage = (BitmapImage) Resources["image.png"];
InputPicture.Source = inputImage;
// imageCopy isn't actually needed for this example.
// But since you had it in yours, here is how it's done, anyway.
var imageCopy = inputImage.Clone();
// Parameters for setting up our output picture
int leftMargin = 50;
int topMargin = 5;
int rightMargin = 50;
int bottomMargin = 5;
int width = inputImage.PixelWidth + leftMargin + rightMargin;
int height = inputImage.PixelHeight + topMargin + bottomMargin;
var backgroundColor = Brushes.Black;
var borderColor = (Pen) null;
// Use a DrawingVisual and DrawingContext for drawing
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
// Draw the black background
dc.DrawRectangle(backgroundColor, borderColor, new Rect(0, 0, width, height));
// Copy input image onto output image at desired position
dc.DrawImage(inputImage, new Rect(leftMargin, topMargin,
inputImage.PixelWidth, inputImage.PixelHeight));
}
// For displaying output image
var rtb = new RenderTargetBitmap( width, height, 96, 96, PixelFormats.Pbgra32 );
rtb.Render(dv);
OutputPicture.Source = rtb;
}
Actually i am wondering to erase an image to transparency. like i have an image on page background and another image above that. Now i want that if i erase above image by finger then lower image should be appear, simply means to say image will become transparent.i'm doing something like this but its not meet my requirements.
Your suggestions are Welcome :)
private void Canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
currentPoint = e.GetPosition(this.canvas);
//Initialize line according to currentpoint position.
Line line = new Line()
{
X1 = currentPoint.X,
Y1 = currentPoint.Y,
X2 = oldPoint.X,
Y2 =oldPoint.Y
};
line.StrokeDashCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
line.StrokeThickness = 20;
line.Stroke = new SolidColorBrush(Colors.Black) ;
////////////////////////////////
//Set color & thickness of line.
//Line add in canvas children to draw image & assign oldpoint.
this.canvas.Children.Add(line);
oldPoint = currentPoint;
}
You can do it with 3 different ways:
Using opaque overlay and UIElement.Clip property. But you need to deal with Geometry. And I'm afraid it will be very CPU cost.
Using WriteableBitmap and changing an alpha channel of image. You can do it using WriteableBitmapEx.
Using opaque overlay and UIElement.OpacityMask property. I think it's the best way to accomplish that, as you're not limited to use bitmap (so you can place any XAML control below overlay) as in the second way.
Using GDI+ I am attempting to make a simple square that consists of an image. This rectangle will be moved. There are a few issues I've been running into. First of all, how to locally refer to the image (it is set to always copy), how to get the image centered in the square, and how to keep the image stationary when the square moves?
Bitmap runnerImage = (Bitmap)Image.FromFile(#"newRunner.bmp", true);//this results in an error without full path
TextureBrush imageBrush = new TextureBrush(runnerImage);
imageBrush.WrapMode = System.Drawing.Drawing2D.WrapMode.Clamp;//causes the image to get smaller/larger if movement is tried
Graphics.FillRectangle(imageBrush, displayArea);
Without using wrapMode.clamp it defaults to tiling, which looks like the image is tiled and moving the square moves from one image to the next
how to locally refer to the image (it is set to always copy)
You can add the image to a resource file and then reference that Image from there within the code. (See link http://msdn.microsoft.com/en-us/library/7k989cfy%28v=vs.90%29.aspx)
How to get the image centered in the square, and how to keep the image
stationary when the square moves?
This can be achieved using TranslateTransform with displayArea's location
(See link http://msdn.microsoft.com/en-us/library/13fy233f%28v=vs.110%29.aspx)
TextureBrush imageBrush = new TextureBrush(runnerImage);
imageBrush.WrapMode = WrapMode.Clamp;//causes the image to get smaller/larger if movement is tried
Rectangle displayArea = new Rectangle(25, 25, 100, 200); //Random values I assigned
Point xDisplayCenterRelative = new Point(displayArea.Width / 2, displayArea.Height / 2); //Find the relative center location of DisplayArea
Point xImageCenterRelative = new Point(runnerImage.Width / 2, runnerImage.Height / 2); //Find the relative center location of Image
Point xOffSetRelative = new Point(xDisplayCenterRelative.X - xImageCenterRelative.X, xDisplayCenterRelative.Y - xImageCenterRelative.Y); //Find the relative offset
Point xAbsolutePixel = xOffSetRelative + new Size(displayArea.Location); //Find the absolute location
imageBrush.TranslateTransform(xAbsolutePixel.X, xAbsolutePixel.Y);
e.Graphics.FillRectangle(imageBrush, displayArea);
e.Graphics.DrawRectangle(Pens.Black, displayArea); //I'm using PaintEventArgs graphics
Edit: I assumed that Image Size is always <= Square Size
I want to resize the image that I am going to display by keeping its aspect ratio.
How can I achieve that. ?
public MainPage()
{
InitializeComponent();
myImage = new Image();
Uri uri = new Uri("Penguins.jpg", UriKind.Relative);
bit = new BitmapImage(uri);
myImage.Source = bit;
imagePanel.Children.Add(myImage);
}
Here the image is stored in the variable bit. How can I resize it by keeping its aspect ratio ?
Thanks.
There is a Stretch property in Image class. You can set None, Uniform or UniformToFill to keep aspect ratio when image is resized in order to fill image area
I would like to display an image composed of two images.
I want image rectangle.png to show with image sticker.png on top of it with its left-hand corner at pixel 10, 10.
Here is as far as I got, but how do I combine the images?
Image image = new Image();
image.Source = new BitmapImage(new Uri(#"c:\test\rectangle.png"));
image.Stretch = Stretch.None;
image.HorizontalAlignment = HorizontalAlignment.Left;
Image imageSticker = new Image();
imageSticker.Source = new BitmapImage(new Uri(#"c:\test\sticker.png"));
image.OverlayImage(imageSticker, 10, 10); //how to do this?
TheContent.Content = image;
You need a Panel to add both Image controls to. A Grid or Canvas will allow this, but I would go with the Grid as it will constrain the Image controls (thereby stretching or shrinking them as appropriate).
Image image = new Image();
image.Source = new BitmapImage(new Uri(#"c:\test\rectangle.png"));
image.Stretch = Stretch.None;
image.HorizontalAlignment = HorizontalAlignment.Left;
Image imageSticker = new Image();
imageSticker.Source = new BitmapImage(new Uri(#"c:\test\sticker.png"));
imageStiker.Margin = new Thickness(10, 10, 0, 0);
Grid grid = new Grid();
grid.Children.Add(image);
grid.Children.Add(imageSticker);
TheContent.Content = grid;
You can just put one Image control over the top of the other Image control in your View. Place both into a Grid or Canvas, and just overlay one of the images on top of the other. This also lets you using opacity to do blending, and works very well.
If you need to get them into the same image, there are a couple of options....
You could make a WritableBitmap out of the first image, then manually "paint" the other image pixels on top of the first one. This then can act as an image source for your image in the display.
Alternatively, you could do the overlay I mentioned above, and render this into a RenderTargetBitmap. This could then be used as your image source.