Freigeben über


rounded corner images in wpf.

this has come up 3 times over last few weeks.. so I am putting it here for the nxt time .. 

"How do I create a mask to round the corners of an image" is how it gets worded, which of course scares me due to history with OpacityMask --in earlier builds, and I think still in beta2- OpacityMasks forced software rendering. no worries it is fixed in later builds..

Here are two alternatives besides OpacityMask...  [now that OpacityMask is hardware accelerated it is also not a huge deal to use it, but not discussing it here cause the SDK does a great job at it..

Option 1:  (recommended, most performant)

Draw a Rectangle with Rounded Corners and Fill it with the ImageBrush ... 

In EID,

  1. Project - > Add Existing Item -  to add your image
  2. Drag the image from Projects Window to Scene
  3. Select Image, Go Tools - > Make Tile Brush -> Make Image Brush
  4. Now you can drag the radius of the rectangle and make it round

Voila!

That is good, how ever it mostly works for images...   Another way that works for any UIElement that you want to "contain" is:  

Option 2: Create a Clipping Path..

  1. Double click on Image in project window to add to scene
  2. Add a rectangle or any other shape to your scene.. position it right on top of the image you want to clip
  3. drag the radius of the rectangle to be of the shape you need the image
  4. Select the Rectangle First -- Note: order matters here
  5. Press Ctrl  and select the Image you added to scene in step1
  6. Select Tools - > Make Clipping Path

Voila!

Option 3:  OpacityMask is well documented in the SDK .. so we won't repeat it here..

When to use which -- some of the criteria I have seen so far was:

  • Performance -- when will do it many, many times
  • Dynamic layout, cause don't know what the image looks like
  • Ability to manipulate/apply transforms to the Image/Brush .. Say to create a "Zoom effect into the image but with out resizing the image frame"  ..

On performance, differences should not be too noticeable unless you do it 100s of times ... but if you do it many times (e.g. image catalog) it will add-up... so should be considered..

Rectangle/Image Brush <    Clipping <  Opacity  Mask    for how expensive it will be.

On Dynamic Resizing (different size images) ,  I find rectangle to be easiest ...

 <Rectangle RadiusX="50" RadiusY="50"

Width="{Binding ElementName=brush,Path=ImageSource.Width}" 
 Height="{Binding ElementName=brush,Path=ImageSource.Height}">
    <Rectangle.Fill>
      <ImageBrush x:Name="brush" ImageSource="f:\users\jaimer\pictures\untitled.png"/>
    </Rectangle.Fill>
  </Rectangle>

In EID,

  1. Go to XAML view and add a x:Name for the brush
  2. Find Width in properties Window ...
  3. Right Click on Width,  Select Databind
  4. Select Explicit Data Context
  5. Check "use a Custom Path expression"
  6. Enter 'ElementName=brush,Path=ImageSource.Width'  (minus the quotes)
  7. Repeat 2-6 for Height

For resizable Clipping Path I did it in code .. cause I was lazy about thinking too much about it..

In EID,

  1. Go to Timeline
  2. Select your image
  3. Go to events Window
  4. Click Add, 
  5. Select SizeChanged , enter OnSizeChanged for the event name.
  6. In the code window, add these two lines

Add

private void OnSizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
  {
    System.Windows.Rect r = new System.Windows.Rect( e.NewSize );
              RectangleGeometry gm = new RectangleGeometry(r, 40, 40); // 40 is radius here
              ((UIElement)sender).Clip = gm ; 

  }

On Animations/Transforms  in EID ..

  • Clipping scenario is straight forward..  No issues.
  • With VisualBrush, EID appears to not let you create Storyboards for animations..  bummer! here is how you can get around it.. 
    • Create a scene and drop the Image (not the brush ) into the scene ..
    • Create all the animations/storyboards against the image..
    • Once you have created all the storyboards, you can create the brush..
    • Give it the same x:Name you had given to the Image and then replace the Target Properties, from  UIElement.RenderTransform to ImageBrush.Transform  .. assuming those are the parts you animated..

That is it .. You now have rounded images.. that will perform well and look neat!