Search code examples
wpfrendertargetbitmaprendertransform

HowTo Get Rendered Image from WPF Image Control


Each WPF Image Control has RenderTransform Property that sets Scale, Skew, Rotate and many more Transformation to Images. After Calling RenderTransform Property, How to get Rendered Image into the BitmapImage or RenderTargetBitmap Class or Any other class?

This is my Code:

Dim InImage As New BitmapImage(New Uri("My Image Path"))

Dim TG As New TransformGroup
TG.Children.Add(New RotateTransform(190))

Dim MyImg As New Image
MyImg.Source = InImage
MyImg.RenderTransform = TG

'Here i need get Transformed Image into a BitmapImage or RenderTargetBitmap Variable  or Any other class variable.

Solution

  • It's a pity that TransformedBitmap does not support rotation with angle other than any multiple of 90 degs (that means we can only rotate 90, 180, 270, ...). Thinking about which objects we can put in a bitmap and apply some Transform? Well we have DrawingGroup, DrawingVisual, ImageBrush, UIElement and via DrawingContext.

    • Using DrawingGroup, we have to put in an ImageDrawing and apply the transform via the Transform property of the DrawingGroup. Then we have to use a DrawingImage, set the Drawing property to the DrawingGroup.

    • Using DrawingVisual, we have to open a DrawingContext, use the DrawImage method after pushing some transform. Then we may have to use RenderTargetBitmap by passing the DrawingVisual in the Render method.

    • Using UIElement (like your idea about using Image control as the medium), we have to render the image on the UIElement. So an Image control suits this best. Every UIElement has a Transform property allowing us to add whatever transform. At last we also have to use a RenderTargetBitmap by passing the UIElement in the Render method.

    • Using ImageBrush, we have to set the ImageSource property to a BitmapImage. Then we can use the Transform or RelativeTransform property to apply some transform. After that we have to use a DrawingImage. Create a simple GeometryDrawing using the ImageBrush as its Brush, and a RectangleGeometry as its Geometry. Finally we just need to set this GeometryDrawing to the Drawing property of the DrawingImage. The output is the DrawingImage. I would like to use this approach to write the code here:

      Dim InImage As New BitmapImage(New Uri("My Image Path"))
      Dim ImgBrush As New ImageBrush(InImage)
      ImgBrush.Viewport = New Rect(0.1,0.1,0.8,0.8)
      ImgBrush.ViewportUnits = BrushMappingMode.RelativeToBoundingBox
      Dim Rotating As New RotateTransform(190)
      Rotating.CenterX = 0.5
      Rotating.CenterY = 0.5
      ImgBrush.RelativeTransform = Rotating
      
      Dim ImgSize As New Rect(0,0,300,400)
      Dim DrawImage As New DrawingImage()
      DrawImage.Drawing = New GeometryDrawing(ImgBrush, null, ImgSize)
      

    Note about the "My Image Path". I've found out that using a Relative image would not work if you don't have any Image folder at the same level with the built exe file. If you don't want to deploy some image folder together with your application, you can add your image as a Resource. To refer to an image added as a Resource in code behind, you have to use a special kind of path:

    pack://application:,,,/Your_Relative_Image_Path
    

    Note that to be sure your image is added as a Resource, try right clicking on the image (under the Projects treeview), select Properties in the popup menu, then look into the Build Action field, it should be Resource.

    Also note about the ImgBrush.Viewport, setting it appropriately will prevent the image from being cut off (that's because the transformed image is rotated). It depends on the ImgSize and how much degree you rotate.