(Difference between revisions)
 Revision as of 22:37, 4 March 2008 (edit) (Initial conversion from Docbook)← Previous diff Revision as of 22:21, 6 March 2008 (edit) (undo) (Initial conversion from Docbook)Next diff → Line 31: Line 31: '''Figure 9-1. Simple rectangular clipping''' '''Figure 9-1. Simple rectangular clipping''' - [[Image:SVG Essentials/I_9_tt180.png|Simple rectangular clipping]] + [[Image:SVG Essentials_I_9_tt180.png|Simple rectangular clipping]] Line 116: Line 116: '''Figure 9-2. Complex path clipping''' '''Figure 9-2. Complex path clipping''' - [[Image:SVG Essentials/I_9_tt181.png|Complex path clipping]] + [[Image:SVG Essentials_I_9_tt181.png|Complex path clipping]] Line 124: Line 124: '''Figure 9-3. Use of a circular/oval clipping path''' '''Figure 9-3. Use of a circular/oval clipping path''' - [[Image:SVG Essentials/I_9_tt182.png|Use of a circular/oval clipping path]] + [[Image:SVG Essentials_I_9_tt182.png|Use of a circular/oval clipping path]] Line 154: Line 154: '''Figure 9-4. Effect of color values on transparency''' '''Figure 9-4. Effect of color values on transparency''' - [[Image:SVG Essentials/I_9_tt183.png|Effect of color values on transparency]] + [[Image:SVG Essentials_I_9_tt183.png|Effect of color values on transparency]] Line 225: Line 225: '''Figure 9-5. Alpha value equal to opacity''' '''Figure 9-5. Alpha value equal to opacity''' - [[Image:SVG Essentials/I_9_tt184.png|Alpha value equal to opacity]] + [[Image:SVG Essentials_I_9_tt184.png|Alpha value equal to opacity]] Line 305: Line 305: '''Figure 9-6. Unmasked image''' '''Figure 9-6. Unmasked image''' - [[Image:SVG Essentials/I_9_tt185.png|Unmasked image]] + [[Image:SVG Essentials_I_9_tt185.png|Unmasked image]] Line 329: Line 329: '''Figure 9-7. Masked image''' '''Figure 9-7. Masked image''' - [[Image:SVG Essentials/I_9_tt188.png|Masked image]] + [[Image:SVG Essentials_I_9_tt188.png|Masked image]] Using less of the picture can substantially improve the graphic as a whole. Using less of the picture can substantially improve the graphic as a whole.

## Revision as of 22:21, 6 March 2008

Sometimes you don't want to see an entire picture; for example, you might wish to draw a picture as though it were seen through binoculars or a keyhole; everything outside the boundary of the eyepieces or keyhole will be invisible. Or, you might want to set a mood by showing an image as though viewed through a translucent curtain. SVG accomplishes such effects with clipping and masking.

## Clipping to a Path

When you create an SVG document, you establish its viewport by specifying the width and height of the area you're interested in. This automatically becomes your clipping area; anything drawn outside these limits will not be displayed. You can establish a clipping area of your own with the <clipPath> element. Here's the simplest case: establishing a rectangular clip path. Inside the <clipPath> element will be the <rect> we wish to clip to. The rectangle itself is not displayed; we only love it for its coordinates. Thus, we are free to add any fill or stroke styles we wish to the elements within the <clipPath>. On the object to be clipped we add a clip-path style property whose value references the <clipPath> element. Note that the property is hyphenated and not capitalized; the element is capitalized and not hyphenated. In Example 9-1, the object being clipped is a small version of the cat picture from Chapter 1, producing Figure 9-1.

Example 9-1. Clipping to a rectangular path

```<defs>
<clipPath id="rectClip">
<rect id="rect1" x="15" y="15"
width="40" height="45"
style="stroke: gray; fill: none;"/>
</clipPath>
</defs>

<!-- clip to rectangle -->

<!--
for reference, show entire picture with clipping area outlined -->
<g transform="translate(100,0)">
<use xlink:href="#rect1"/>    <!-- show clip rectangle -->
</g>
```

Figure 9-1. Simple rectangular clipping

As the name <clipPath> implies, you can clip to any arbitrary path. Indeed, the <clipPath> element can contain any number of basic shapes, <path> elements, or <text> elements. Example 9-2 shows a group of shapes clipped to a curved path and the same group of shapes clipped by text.

Example 9-2. Complex clip paths

```<defs>
<clipPath id="curveClip">
<path id="curve1"
d="M5 55 C 25 5, 45 -25, 75 55, 85 85, 20 105, 40 55 Z"
style="stroke: black; fill: none;"/>
</clipPath>

<clipPath id="textClip">
<text id="text1" x="20" y="20" transform="rotate(60)"
style="font-size: 48pt; stroke: black; fill: none;">
CLIP
</text>
</clipPath>

<g id="shapes">
<rect x="0" y="50" width="90" height="60" style="fill: #999;"/>
<circle cx="25" cy="25" r="25" style="fill: #666;"/>
<polygon points="30 0 80 0 80 100" style="fill: #ccc;"/>
</g>
</defs>

<!-- draw with curved clip-path -->

<g transform="translate(100,0)">
<use xlink:href="#curve1"/>   <!-- show clip path -->
</g>

<!-- draw with text as clip-path -->
<g transform="translate(0,150)">
</g>

<g transform="translate(100,150)">
</g>
```

To help you see the areas better, the preceding SVG draws the clipping path above the entire figure; you see this in the right half of Figure 9-2.

The coordinates for the preceding clip paths have been specified in user coordinates. If you wish to express coordinates in terms of the object bounding box, then set clipPathUnits to objectBoundingBox (the default is userSpaceOnUse). Example 9-3 uses a clip path that will produce a circular (or oval) window on any object that it's applied to.

Example 9-3. clipPathUnits using objectBoundingBox

```<defs>
<clipPath id="circularPath" clipPathUnits="objectBoundingBox">
<circle cx="0.5" cy="0.5" r="0.5"/>
</clipPath>

<g id="shapes">
<rect x="0" y="50" width="100" height="50" style="fill: #999;"/>
<circle cx="25" cy="25" r="25" style="fill: #666;"/>
<polygon points="30 0 80 0 80 100" style="fill: #ccc;"/>
</g>

<g id="words">
<text  x="0"  y="19" style="font-size: 12;">
<tspan x="0"  y="19">If you have form'd a circle</tspan>
<tspan x="12" y="33">to go into,</tspan>
<tspan x="0"  y="47">Go into it yourself</tspan>
<tspan x="12" y="61">and see how you would do.</tspan>
</text>
</g>
</defs>

style="clip-path: url(#circularPath);"/>
```

Figure 9-2. Complex path clipping

In Figure 9-3, the geometric figures happen to have a square bounding box, so the clipping appears circular. The text is bounded by a rectangular area, so the clipping area appears to be an oval.

Figure 9-3. Use of a circular/oval clipping path

Note

Specify a clipping rectangle for <marker> and <symbol> tags with the clip style property. Its value is four whitespace-separated numbers specifying the rectangle's top, right, bottom, and left bounds. This sets the clip rectangle to match the marker or symbol's viewBox, rather than its viewport.

You use the <mask> element to create a mask. You may specify the mask's dimensions with the x, y, width, and height attributes. These dimensions are in terms of the masked objectBoundingBox. If you want the dimensions to be in terms of user space coordinates, set maskUnits to userSpaceOnUse.

Between the beginning <mask> and ending </mask> tags are any basic shapes, text, or paths that you wish to use as the mask. The coordinates on these elements are expressed in user coordinate space by default. If you wish to use the object bounding box for the contents of the mask, set maskContentUnits to objectBoundingBox. (The default is userSpaceOnUse.)

The question then becomes: how does SVG determine the transparency, or alpha value of the mask? We know that each pixel is described by four values: its red, green, and blue color value, and its opacity. While at first glance it would seem logical to use only the opacity value, SVG decides to use all the information available to it rather than throwing away three-fourths of a pixel's information. SVG uses this formula:

```( 0.2125 * red value +
0.7154 * green value +
0.0721 * blue value ) *
opacity value

```

where all of the values are floating point numbers in the range zero to one. You may be surprised that the proportions aren't equal, but if you look at fully saturated red, green, and blue, the green appears to be the brightest, red darker, and blue the darkest. (You can see this in Figure 9-4.) The darker the color, the smaller the resulting alpha value will be, and the less opaque the masked object will be.

Figure 9-4. Effect of color values on transparency

Example 9-4 creates black text and a black circle masked by a totally opaque red, green, blue, and white square. The text and circle are grouped together, and the group uses a mask style property to reference the appropriate mask.

Example 9-4. Masking with opaque colors

```<defs>
<rect x="0" y="0" width="1" height="1" style="fill: #f00;"/>

<rect x="0" y="0" width="1" height="1" style="fill: #0f0;"/>

<rect x="0" y="0" width="1" height="1" style="fill: #00f;"/>

<rect x="0" y="0" width="1" height="1" style="fill: #fff;"/>
</defs>

<!-- display the colors to show relative brightness (luminance) -->
<rect x="10" y="10" width="50" height="50" style="fill: #f00;"/>
<rect x="70" y="10" width="50" height="50" style="fill: #0f0;"/>
<rect x="130" y="10" width="50" height="50" style="fill: #00f;"/>
<rect x="190" y="10" width="50" height="50"
style="fill: #fff; stroke: black;"/>

font-size: 14pt; text-anchor: middle;">
<circle cx="35" cy="115" r="25"  style="fill: black;"/>
<text x="35" y="80">Red</text>
</g>

font-size: 14pt; text-anchor: middle;">
<circle cx="95" cy="115" r="25" style="fill: black;"/>
<text x="95" y="80">Green</text>
</g>

font-size: 14pt; text-anchor: middle;">
<circle cx="155" cy="115" r="25" style="fill: black;"/>
<text x="155" y="80">Blue</text>
</g>

font-size: 14pt; text-anchor: middle;">
<circle cx="215" cy="115" r="25" style="fill: black;"/>
<text x="215" y="80">White</text>
</g>
```

Note

Figuring out the interaction between color, opacity, and final alpha value is not exactly intuitive. If you fill and/or stroke the mask contents in white, the "color factor" adds up to 1.0, and the opacity will then be the only factor that controls the mask's alpha value. Example 9-5 is written this way, and the result is in Figure 9-5.

Figure 9-5. Alpha value equal to opacity

Example 9-5. Mask alpha using opacity only

```<defs>
<rect x="0" y="0" width="1" height="1"
style="fill-opacity: 1.0; fill: white;"/>

<mask id="three-fourths" x="0" y="0" width="1" height="1"
<rect x="0" y="0" width="1" height="1"
style="fill-opacity: 0.75; fill: white;"/>

<mask id="one-half" x="0" y="0" width="1" height="1"
<rect x="0" y="0" width="1" height="1"
style="fill-opacity: 0.5; fill: white;"/>

<mask id="one-fourth" x="0" y="0" width="1" height="1"
<rect x="0" y="0" width="1" height="1"
style="fill-opacity: 0.25; fill: white;"/>
</defs>

<g style="font-size: 14pt; text-anchor:middle; fill:black;">
<circle cx="35" cy="35" r="25"/>
<text x="35" y="80">100%</text>
</g>

<circle cx="95" cy="35" r="25"/>
<text x="95" y="80">75%</text>
</g>

<circle cx="155" cy="35" r="25"/>
<text x="155" y="80">50%</text>
</g>

<circle cx="215" cy="35" r="25"/>
<text x="215" y="80">25%</text>
</g>
</g>
```

## Case Study -- Masking a Graphic

Example 9-6 adds a JPG image to the image that was constructed in Section 8.10. As you can see in Figure 9-6 (reduced to save space and in grayscale to avoid using color ink), the image obscures the curve inside the main ellipse, and the blue sky intrudes horribly on the pale red section.

```<defs>
<font-face font-family="bakbatn">
<font-face-src>
</font-face-src>
</font-face>
</defs>

<!-- draws ellipse and text -->

width="160" height="120"/>
```

The solution is to fade out the edges of the picture, which is easily done by using a radial gradient as a mask. Here's the code to be added to the <defs> section of the document:

```<radialGradient id="fade">
<stop offset="0%" style="stop-color: white; stop-opacity: 1.0;"/>
<stop offset="85%" style="stop-color: white; stop-opacity: 0.5;"/>
<stop offset="100%" style="stop-color: white; stop-opacity: 0.0;"/>
<rect x="72" y="92" width="160" height="120"
```

Then add a mask reference to the <image> tag, resulting in Figure 9-7:

```<image xlink:href="kwanghwamun.jpg" x="72" y="92"
width="160" height="120"