Crop an Image in WPF - wpf

Give an image:
Image tileSet = new Image();
tileSet.Source = new BitmapImage(new Uri(#".."));
How can i cropt it, defining a rectangle area?

You can use CroppedBitmap for that
var fullBitmap = new BitmapImage(new Uri(#".."));
tileSet.Source = new CroppedBitmap(fullBitmap, new Int32Rect(0, 0, 100, 100));

To build a little on dkozl's answer above,
I found the DPI of the original image to crop and the DPI of the display were creating an "offset" of where I was intending to crop the original image.
The "offset" can be corrected by matching the image Width and Height in pixels with the DPI of the screen, instead of letting the Image element to it's own automatic sizing.
You do this by setting the Stretch to None, and the Width & Height of the image as below:
<Image
x:Name="imageToCrop"
Stretch="None"
Width="{Binding Source.PixelWidth,RelativeSource={RelativeSource Self}}"
Height="{Binding Source.PixelHeight,RelativeSource={RelativeSource Self}}"/>

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.

Reduce Image resolution in WPF image control

I have a image control in WPF. I need to reduce the image size control width and height. But when i Do that , the image is not looking good. The data loss is more.
So i thought to reduce the image resolution instead of just changing the image control width and height.
can any one help me how to change the image resolution of the binded image in WPF image control
[I mean image is already binded to image control now I have to the change the resolution only]
In .NET 4 they changed the default image scaling to a low quality one...so you can use BitmapScalingMode to switch back to the higher quality one:
<Image RenderOptions.BitmapScalingMode="HighQuality"
Source="myimage.png"
Width="100"
Height="100" />
http://10rem.net/blog/2010/05/01/crappy-image-resizing-in-wpf-try-renderoptionsbitmapscalingmode
You can also combine the above with other options like the Decode options if your source image is a huge image (this just reduces memory usage in your application).
http://www.shujaat.net/2010/08/wpf-saving-application-memory-by.html
other options to prevent "blurryness" is to put UseLayoutRounding="True" on your root element (i.e. Window)....it's recommended to use this in .NET 4 rather than SnapToDevicePixels:
When should I use SnapsToDevicePixels in WPF 4.0?
http://blogs.msdn.com/b/text/archive/2009/08/27/layout-rounding.aspx
You can use the DecodePixelWidth property like this:
<Image Stretch="Fill">
<Image.Source>
<BitmapImage CacheOption="OnLoad" DecodePixelWidth="2500" UriSource="Images/image.jpg"/>
</Image.Source>
</Image>
1) Have a try with a ViewBox : put your image within a ViewBox.
2) Sometimes the rendering engine looses quality because of pixel alignement issues, especially on low-resolution device. Have a look to SnapsToDevicePixels property, and try to set it to true in the containing control AND / OR in the ViewBox.
3) Obviously you could write a Control that perform a resolution change but it is quite some work.
Try this.
Image img = new Image();
var buffer = System.IO.File.ReadAllBytes(_filePath);
MemoryStream ms = new MemoryStream(buffer);
BitmapImage src = new BitmapImage();
src.BeginInit();
src.StreamSource = ms;
src.DecodePixelHeight = 200;//Your wanted image height
src.DecodePixelWidth = 300; //Your wanted image width
src.EndInit();
img.Source = src;

WPF Image, how to remove blur?

I have
I need
XAML:
<Image Height="500"
MouseLeftButtonDown="image_MouseLeftButtonDown"
MouseRightButtonDown="image_MouseRightButtonDown"
Name="image"
Stretch="Fill"
Width="500" />`
C#:
wbmap = new WriteableBitmap(50, 50, 500, 500, PixelFormats.Indexed8, palette);
wbmap.WritePixels(new Int32Rect(0, 0, wbmap.PixelWidth, wbmap.PixelHeight), pixels, wbmap.PixelWidth * wbmap.Format.BitsPerPixel / 8, 0);
image.Source = wbmap;
As tkerwin mentioned, change the BitmapScalingMode to NearestNeighbor in you XAML Image code:
RenderOptions.BitmapScalingMode="NearestNeighbor"
Perhaps you need to change the bitmap scaling mode to nearest neighbor.
Add RenderOptions.BitmapScalingMode="NearestNeighbor" to your Image tag.
Increase resolution / scale without anti-aliasing.
Whats happening is WPF is scaling the image but "averaging" the pixels, rather than doing a more blocky scale.
See this post:
Resize bitmap like in MS Paint

Resources