WPF how to show an Image.Source (BitmapSource) pixel position? - wpf

Let's suppose I've got an image which shows its source in a scaled way, how could i use a
MouseMove event to show in a label or textblock the pixel position in which the cursor is?
(I need the pixel coordinates not the coordinates of the image relative to its size)
Thanks in advance.

You can find out the actual pixel height and width from the ImageSource.
ImageSource imageSource = image.Source;
BitmapImage bitmapImage = (BitmapImage) imageSource ;
Now since you got the image displayed in Image control. You can easily map the mouse position to the Pixel scale.
pixelMousePositionX = e.GetPosition(image).X * bitmapImage.PixelWidth/image.Width;
pixelMousePositionY = e.GetPosition(image).Y * bitmapImage.PixelHeight/image.Height;
Have fun
Jobi Joy

If your Image's XAML as follow:
<Border Grid.Row="1" Grid.Column="0"
BorderThickness="3"
BorderBrush="BlueViolet">
<Image x:Name="Image_Box"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Source="8.jpg"
Stretch="Uniform"
MouseMove="ImageBox_OnMouseMove"
/>
</Border>
Maybe the Image control's width is double.Nan ,So we need to use ActualWidth property. so the Code as follow:
private void ImageBox_OnMouseMove(object sender, MouseEventArgs e)
{
ImageSource imageSource = Image_Box.Source;
BitmapSource bitmapImage = (BitmapSource)imageSource;
TextBoxCursor_X.Text =( e.GetPosition(Image_Box).X * bitmapImage.PixelWidth / Image_Box.ActualWidth).ToString();
TextBoxCursor_Y.Text = (e.GetPosition(Image_Box).Y * bitmapImage.PixelHeight / Image_Box.ActualHeight).ToString();
}

Related

WPF Transform Rectangle in Canvas to Selection in Image

I have a rectangle on a canvas that the user can resize, move and so on to make a selection.
I also have an image the size of the screen behind the canvas (basically a screenshot).
I'd like to translate the selection (the rectangle) in the canvas to a 1:1 selection in the image (I want the image directly behind the rectangle) given I have the rectangle's Canvas.Top, Canvas.Left, Width, Height.
<Grid Name="MainGrid" SnapsToDevicePixels="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image x:Name="MainImage" Stretch="None" RenderOptions.BitmapScalingMode="HighQuality"/>
<Border Background="Black" Opacity="0.4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Canvas Name="MainCanvas" Width="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}}" Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}}" Background="Transparent">
<ContentControl Name="SelectionRect" />
</ContentControl>
</Canvas>
</Grid>
I tried doing this: (MainImage is the image under the canvas)
Rect rect = new Rect(Canvas.GetLeft(SelectionRect), Canvas.GetTop(SelectionRect), SelectionRect.Width, SelectionRect.Height);
Rect from_rect = SelectionRect.TransformToVisual(this).TransformBounds(rect);
BitmapSource cropped_bitmap = new CroppedBitmap(MainImage.Source as BitmapSource,
new Int32Rect((int)from_rect.X, (int)from_rect.Y, (int)from_rect.Width, (int)from_rect.Height));
SelectionRectImageSource = cropped_bitmap;
But the image I get (SelectionRectImageSource) is a moved aside version of the actual pixels behind the selection rectangle.
So basically, I don't understand how these transformations work and how I should use them if at all.
Example:
Thanks a lot!
Dolev.
Looks like you need to correct for the DPI difference between the image (usually 72dpi) and the presentation source (usually 96dpi). Additionally, your first Rect should not be offset by Canvas.Left and Canvas.Top; TransformToVisual will take care of the relative offset for you.
var source = (BitmapSource)MainImage.Source;
var selectionRect = new Rect(SelectionRect.RenderSize);
var sourceRect = SelectionRect.TransformToVisual(MainImage)
.TransformBounds(selectionRect);
var xMultiplier = source.PixelWidth / MainImage.ActualWidth;
var yMultiplier = source.PixelHeight / MainImage.ActualHeight;
sourceRect.Scale(xMultiplier, yMultiplier);
var croppedBitmap = new CroppedBitmap(
source,
new Int32Rect(
(int)sourceRect.X,
(int)sourceRect.Y,
(int)sourceRect.Width,
(int)sourceRect.Height));
SelectionRectImageSource= croppedBitmap;
Depending on where this code resides, you may also need to transform the selection rectangle to MainImage instead of this (as I did).
Also, in case MainImage.Source is smaller than the actual MainImage control, you should probably set the horizontal and vertical alignments of MainImage to Left and Top, respectively, less your translated rectangle end up outside the bounds of the source image. You'll need to clamp the selection rectangle to the dimensions of MainImage too.

WPF ZoomControl and Adorners

This my first post on stack overflow, I hope I get it right. I am using the ZoomControl from WPF Extensions to display an image with pan and zoom support:
<DockPanel Grid.Row="1" x:Name="canvas">
<Controls:ZoomControl x:Name="zoomControl">
<Canvas x:Name="canvas">
<Image x:Name="imageControl" Stretch="None" />
</Canvas>
</Controls:ZoomControl>
</DockPanel>
When the user selects an image with a bowse dialog, I load that image like so:
bmp = new BitmapImage(new Uri(fileName));
this.imageControul.Source = bmp;
I would like to added rectangles\adorners to specific locations (pixel coordinates) on the image the user loaded based on some image processing.
var r = new Rectangle();
r.StrokeThickness = 5;
r.Stroke = Brushes.Black;
r.Fill = Brushes.Transparent;
r.Width = width;
r.Height = height;
Canvas.SetLeft(r, y);
Canvas.SetTop(r, x);
canvas.Children.Add(r);
However, the rectangles are not placed in the expected locations? Wrong scale and location.
Thanks,
John
I expect the problem is that your Canvas is expanding to fill the space rather than being locked to the rectangle. Have a look with a tool like Snoop and see what the bounding boxes of the two are.
You might be able to fix it with Horizontal and VercticalAlignment on the canvas, set them to anything other than Stretch.
If that doesn't work restructure it like this
<ZoomBox>
<Grid>
<Image/>
<Canvas/>
</Grid>
</ZoomBox>
So the Image and the canvas are grouped by the parent Grid which is being transformed.

How to zoom image inside rectangle WPF

I am trying to zoom in and out image inside Rectangle control. But while doing so my entire Rectangle is getting zoomed in instead of just image inside that. for doing so I am using ScaleTransform and TranslateTranform on Rectangle. I should do the same on image instead of Rectangle but I dont know how? Could anyone please help me out.
XAML :
<Rectangle x:Name="LiveViewWindow" Fill="#FFF4F4F5" HorizontalAlignment="Right"
ClipToBounds="True" />
Code:
InteropBitmap m_LiveViewBitmapSource =Imaging.CreateBitmapSourceFromMemorySection(
section, width, height, PixelFormats.Bgr32, width*4, 0) as InteropBitmap;
ImageBrush m_BackgroundFrame = new ImageBrush(m_LiveViewBitmapSource);
RenderOptions.SetBitmapScalingMode(m_BackgroundFrame, BitmapScalingMode.LowQuality);
LiveViewWindow.Fill = m_BackgroundFrame;
n then for I am using Invalidate() property to render InteropBitmap to Rectangle.
You may set the Transform property of the ImageBrush. Get more information in Brush Transformation Overview.

How can i get reference to ItemTemplate's root container and then modify it's properties?

I have a slider on my page which when dragged also should increase the size of the listbox items. How can i achieve this? How can i get reference to the parent container in ItemTemplate and then modify it's height and width? Currently i have this code on my slider value changed event :-
void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Border parentBorder = ((Border)lstAlbumPhotos.ItemTemplate.LoadContent());
double change = e.NewValue * 10;
double percentage = 100 + change;
double newWidth = percentage * _width / 100;
double newHeight = percentage * _height / 100;
parentBorder.Width = newWidth;
parentBorder.Height = newHeight;
}
But it is not working. In the above code Border is my parent container.
Thanks in advance :)
The LoadContent method creates a new instance of the Xaml held in the template. You can not manipulate the content of the template itself in this way. On top of that I really don't think you want to be doing that.
If you really do want to manipulate the width and height of the border in the template then use some binding to an intermediatory object (I'll call it "Sizer") held as a static resource:-
<Grid.Resources>
<local:Sizer x:Key="Sizer" />
</Grid.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="{Binding Width, Source={StaticResource Sizer}}"
Height="{Binding Height, Source={StaticResource Sizer}}" />
You would also bind your slider to this intermediatory object:-
<Slider Value="{Binding Factor, Mode=TwoWay, Source={StaticResource Sizer}}" />
Now you simply have to create a Sizer class that has the properties Factor, Width, Height. You would have it implement INotifyPropertyChanged so that the binding on the properties will be be updated. You then move your math into this object. When Factor is changed you change the Width and Height properties and let the bindings handle update all the existing Borders.

Silveright ScrollViewer with Image and ScaleTransform

I have the following xaml.
<ScrollViewer HorizontalAlignment="Stretch" Margin="107,0,0,0" Name="scrollViewer1" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Visible">
<Image Name="image1" Stretch="None" MouseWheel="image1_MouseWheel" RenderTransformOrigin="0,0">
</Image>
</ScrollViewer>
An the following code behind.
// initialise.
private TransformGroup group = new TransformGroup();
private ScaleTransform st = new ScaleTransform();
group.Children.Add(st);
image1.RenderTransform = group
// mouse event.
TransformGroup group = (TransformGroup)image1.RenderTransform;
ScaleTransform scale = (ScaleTransform)group.Children.Last();
double zoom = e.Delta > 0 ? .2 : -.2;
scale.ScaleX += zoom;
scale.ScaleY += zoom;
How do I get the scroller to take into account that the image is now a different size.
The scroll bars remain the same size, and I cannot work out how to change them.
Thanks
You need the LayoutTransformer from the Silverlight Toolkit. Instead of setting a RenderTransform on your Image, put it inside a LayoutTransformer.
have you tried calling InvalidateScrollInfo on the scrollviewer?

Resources