How can I create a rectangular graphic with curved edges?

The raster method I alluded to in a comment was requested.

g1 = Graphics[{
        Polygon[{{0, 0}, {3, 0}, {3, 1}, {0, 1}}, VertexColors -> {Red, Red, Blue, Blue}]
     }]

g2 = Graphics[{Rectangle[{0, 0}, {3, 1}, RoundingRadius -> 0.5]}]

ImageAdd[g1, g2]

Mathematica graphics


Edit

One can use either an image-based (hence rasterized) or a vector-based (resolution-independent) approach to get the rounded corners. I'll first discuss the vector based solution, and then add a raster-based solution. Although Mr. Wizard already posted a raster-based approach, I think it can be improved.

Update

The function roundedGraphics is rewritten so that it contains both a vector and a bitmap option in a single command. The bitmap option isn't used until later.

Vector-based approach

This solves the question but can also be used more generally to put rounded corners on arbitrary objects:

Options[roundedGraphics] = {Background -> White, 
   ImageResolution -> Infinity};
roundedGraphics[g_, w_, h_, r_, opts : OptionsPattern[]] := Module[
  {bgColor = OptionValue[Background],
   resolution = OptionValue[ImageResolution],
   commonOptions = Sequence[
     PlotRange -> {{0, 1}, {0, 1}},
     ImageSize -> {w, h},
     AspectRatio -> Full],
   passepartout},
  passepartout = FilledCurve[
    {{BezierCurve[
         {{0, #1/h}, {0, 1 - #2/h}, {0, 1 - #2/h}, {0, 1}, {#2/w, 
           1}, {1 - #3/w, 1}, {1 - #3/w, 1}, {1, 1}, {1, 
           1 - #3/h}, {1, #4/h}, {1, #4/h}, {1, 0}, {1 - #4/w, 
           0}, {#1/w, 0}, {#1/w, 0}, {0, 0}, {0, #1/h}},
         SplineDegree -> 2
         ] & @@ Apply[PadRight[#, 4, Last[#]] &, {Flatten[{r}]}]},
     {Line[{{0, 0}, {0, 1}, {1, 1}, {1, 0}}]}}
    ];
  If[
     resolution < Infinity,
     SetAlphaChannel @@ Map[
       Rasterize[#, "Image",
         ImageResolution -> resolution] &,
       {#,
        Graphics[{FaceForm[Black], EdgeForm[Black], passepartout},
         Background -> White, commonOptions]}
       ],
     #
     ] &[
   Graphics[{Inset[g, {0, 0}, {Left, Bottom}, {1, 1}], 
     FaceForm[bgColor], EdgeForm[bgColor], passepartout}, 
    Background -> bgColor, commonOptions]]
  ]

For even more generality, I'm allowing each corner to have an individually different radius. But if you only specify a single radius, that number will be used for all corners.

The arguments w, h, and r are the image width, height and rounding radius in pixels.

To get the button with a gradient, I just have to take the "object" g that is passed to cropGraphics as a rectangle with the desired gradient. So let's just copy Mr. Wizard's choice of gradient here:

g1 = Graphics[{Polygon[{{0, 0}, {3, 0}, {3, 1}, {0, 1}}, 
    VertexColors -> {Red, Red, Blue, Blue}]}, ImagePadding -> 0, 
  PlotRangePadding -> 0]

Iv'e made sure the gradient rectangle doesn't have any whitespace around it. Now I'll apply the rounding to it:

roundedGraphics[Show[g1, AspectRatio -> Full], 400, 50, 20]

button

The point of my more complicated looking function is that you can use it with other objects:

im = Import["ExampleData/lena.tif"];
roundedGraphics[im, #1, #2, 10] & @@ ImageDimensions[im]

lena

g3 = Show[ExampleData[{"Geometry3D", "StanfordBunny"}], 
   ImageSize -> 360];

roundedGraphics[
 Show[g3, AspectRatio -> Full, Background -> Black], 400, 400, 20]

bunny

You may wonder what the purpose of the AspectRatio->Full statement in the last example is. To see what it does, change the width w of the roundedGraphics from 400 to 100. With AspectRatio->Full the inset object becomes stretchable. That's especially nice if you want to make a button from an image but the image dimensions don't match the button dimensions:

splash = ImageCrop[ExampleData[{"TestImage", "Splash"}], {400, 400}];    
roundedGraphics[Show[splash, AspectRatio -> Full], 400, 200, 20]

splashhigh

roundedGraphics[Show[splash, AspectRatio -> Full], 400, 100, 20]

splashLow

Here is an example that uses individual rounding radii (when given as a list, they start at the bottom left):

roundedGraphics[
 Show[splash, AspectRatio -> Full], 400, 100, {0, 20, 20, 0}]

RoundNotRound

This kind of arrangement can be useful when making tabs instead of buttons. Since the rounded boundary is defined by a Bezier curve, you can also invoke the interactive graphics editor to adjust the control points and re-shape the output (double-click on the masking border and highlight a point on the inner curve - the mouse pointer turns into a white dot when it's ready to select a curve point).

The masking shape that defines the rounded rectangle is white by default, but you can give it a different color by using the Background option.

The main ideas in this approach come from Yu-Sung Chang for the FilledCurve trick, and this answer regarding cropping of graphics for the Inset approach.

Raster-based approach

If you're going to choose the route via a bitmap representation of the button, then you may as well make better use of the features that a bitmap approach offers and that are hard to duplicate in the vector-based approach.

The obvious additional feature that one can add here is transparency, applied to the corners of the rounded button, so that the rounding also works when the image is superimposed on an arbitrary background.

I suggested that approach in a comment to this answer (which in its last part is identical to what Mr. Wizard used in his answer here):

g1 = 
 Graphics[{Polygon[{{0, 0}, {3, 0}, {3, 1}, {0, 1}}, 
    VertexColors -> {Red, Red, Blue, Blue}]}, PlotRangePadding -> None]

g2 = Graphics[{White, 
   Rectangle[{0, 0}, {3, 1}, RoundingRadius -> 0.5]}, 
  Background -> Black, PlotRangePadding -> None]

Mask

Now I define the button with rounded corners:

button = SetAlphaChannel[g1, g2];

To show the difference to ImageAdd, display the button in front of a background:

Show[button, Background -> Yellow]

button with background

This same method is also built into the function roundedGraphics. You invoke it simply by specifying the option ImageResolution - this tells it that you want a bitmap, and the alpha channel transparency is then automatically set. Here is another example with a gradient that explicitly uses bitmaps with the standard screen resolution:

bitmapButton = roundedGraphics[
  Graphics[
   Raster[Transpose@{(Range[256] - 1)/256},
    ColorFunction -> "NeonColors"],
   ImagePadding -> 0,
   PlotRangePadding -> 0,
   AspectRatio -> Full
   ], 300, 50, {10, 40, 10, 40}, ImageResolution -> 72]

button2

This button now has transparent corners, and by choosing a higher resolution you can get arbitrarily close to the quality of the vectorized version discussed earlier.

The output of roundedGraphics with the ImageResolution option isn't a Graphics object but an Image, so you have to use bitmap commands on it, as in this example:

ImageCompose[ExampleData[{"TestImage", "Tree"}], 
 ImageResize[bitmapButton, 200], {130, 130}]

images


This answer uses RegionPlot to plot the rounded rectangle. In roundedRect, {{xmin, xmax}, {ymin, ymax}} is the range of the rectangle and rad the rounding radius. roundedRect accepts any option of RegionPlot, in particular ColorFunction which you can use to shade the rectangle.

Options[roundedRect] = Options[RegionPlot];
SetOptions[roundedRect, {Frame -> False, Axes -> False, BoundaryStyle -> None}];

roundedRect[range : {{xmin_, xmax_}, {ymin_, ymax_}}, rad_, 
  opt : OptionsPattern[roundedRect]] := Module[{p, norm},
  p = 1/Log2[Sqrt[2] + 2];
  norm[pt_, pt0_] := Total[Abs[pt - pt0]^p]^(1/p) > rad;
  RegionPlot[And @@ (norm[{x, y}, #] & /@ Tuples[range]),
   {x, xmin, xmax}, {y, ymin, ymax}, opt,
   AspectRatio -> Abs[ymax - ymin]/Abs[xmax - xmin],
   Evaluate[Options[roundedRect]]]]

Example

roundedRect[{{0, 5}, {0, 1}}, .4, ColorFunction -> (Blend[{Red, Blue}, #2] &)]

Mathematica graphics

Edit

@Heike I hope you do not mind me making a change to your answer. I think this is more Mathematica like by having the rounding radius as an option.

ClearAll[roundedRect];

Options[roundedRect] = Flatten[{RoundingRadius -> 0.5, Options[RegionPlot]}];
SetOptions[roundedRect, {Frame -> False, Axes -> False, BoundaryStyle -> None}];

roundedRect[range : {{xmin_, xmax_}, {ymin_, ymax_}}, 
  opt : OptionsPattern[roundedRect]] := Module[{p, norm, opts, rad},

  rad = OptionValue[RoundingRadius];
  opts = FilterRules[{opt}, Options[RegionPlot]];

  p = 1/Log2[Sqrt[2] + 2];
  norm[pt_, pt0_] := Total[Abs[pt - pt0]^p]^(1/p) > rad;

  RegionPlot[
   And @@ (norm[{x, y}, #] & /@ Tuples[range]), {x, xmin, xmax}, {y, 
    ymin, ymax}, Evaluate@opts,
   AspectRatio -> Abs[ymax - ymin]/Abs[xmax - xmin]]]

example:

roundedRect[{{0, 5}, {0, 1}}, Frame -> False, RoundingRadius -> 0.4, 
 ColorFunction -> (Blend[{Red, Blue}, #2] &)]