SVG image cover regardless of size/orientation

Viewed 71

Expect the embedded snippet below to generate a screen like the picture on Firefox, etc. The two unclipped images are shown at the bottom for reference - one landscape and one portrait. Above are four demo shapes that I want to be covered by the images without really knowing anything about the image - ideally I could replace just the URLs and get all "correct" images and avoiding any math or conditions.

The patterns and images should be identical, not matched to the demo scenarios. Ultimately I need just ONE such shape in an svg template satisfying any one injected image.

I think I definitely want xMidYMid for both pattern and image. I've tried many permutations of viewBox, heights, widths, slice/meet, patternContentUnits, and patternUnits attributes.

I can't even really figure out what the "wrong" images are being scaled to. It seems like the two demos of each image are exactly the same scale (because the demo rects are all 490 in the long direction, and it's as though the short side of the image is being matched to the long side of the rect or something??)

enter image description here

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 1020 1220" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <pattern
       id="patternA"
       height="1"
       width="1"
       viewBox="0 0 1 1"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid slice">
        <image
            id="imageA"
            width="1" height="1"
            preserveAspectRatio="xMidYMid slice"
            transform=""
            xlink:href="https://images.unsplash.com/photo-1625507371147-797709a083a6?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=334&amp;q=80" />
    </pattern>
    <pattern
       id="patternB"
       height="1"
       width="1"
       viewBox="0 0 1 1"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid slice">
        <image
            id="imageB"
            width="1" height="1"
            preserveAspectRatio="xMidYMid slice"
            transform=""
            xlink:href="https://images.unsplash.com/photo-1625508200971-f63b282addb8?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1189&amp;q=80" />
    </pattern>
    <pattern
       id="patternC"
       height="1"
       width="1"
       viewBox="0 0 1 1"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid meet">
        <image
            id="imageC"
            width="1" height="1"
            preserveAspectRatio="xMidYMid meet"
            transform=""
            xlink:href="https://images.unsplash.com/photo-1625507371147-797709a083a6?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=334&amp;q=80" />
    </pattern>
    <pattern
       id="patternD"
       height="1"
       width="1"
       viewBox="0 0 1 1"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid meet">
        <image
            id="imageD"
            width="1" height="1"
            preserveAspectRatio="xMidYMid meet"
            transform=""
            xlink:href="https://images.unsplash.com/photo-1625508200971-f63b282addb8?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1189&amp;q=80" />
    </pattern>
  </defs>
  <rect
     style="fill:url(#patternA);stroke:black;"
     x="10"
     y="10"
     width="490"
     height="200" />
  <rect
     style="fill:url(#patternB);stroke:blue;"
     x="510"
     y="10"
     width="500"
     height="200" />
  <rect
     style="fill:url(#patternA);stroke:red;"
     x="160"
     y="220"
     width="200"
     height="490" />
  <rect
     style="fill:url(#patternB);stroke:green;"
     x="670"
     y="220"
     width="200"
     height="490" />
  <rect
     style="fill:url(#patternC);stroke:black;"
     x="10"
     y="720"
     width="490"
     height="490" />
  <rect
     style="fill:url(#patternD);stroke:black;"
     x="510"
     y="720"
     width="490"
     height="490" />
</svg>

Instead, the "wrong" demos should cover like this, with the image basically starting at 0x0 in the center and scaling up only until the image exactly covers the rectangle, but no further:

enter image description here

There are similar questions here on SO that I've already used in getting this far.

1 Answers

What you want can't be done I don't think. In order for the image to be scaled correctly to the shape using meet or slice, the size of the image needs to be known.

In your initial attempts, there is nothing there that gives the renderer any idea what the actual dimensions of the images are. Or even what their aspect ratios are.

For example

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 1020 1220" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>

    <pattern
       id="patternA"
       height="1"
       width="1"
       viewBox="0 0 3977 5965"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid slice">
        <image
            id="imageA"
            width="3977" height="5965"
            xlink:href="https://images.unsplash.com/photo-1625507371147-797709a083a6?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=334&amp;q=80" />
    </pattern>
    
    <pattern
       id="patternB"
       height="1"
       width="1"
       viewBox="0 0 3941 2217"
       patternContentUnits="objectBoundingBox"
       preserveAspectRatio="xMidYMid slice">
        <image
            id="imageB"
            width="3941" height="2217"
            xlink:href="https://images.unsplash.com/photo-1625508200971-f63b282addb8?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1189&amp;q=80" />
    </pattern>
    
  </defs>
  <rect
     style="fill:url(#patternA);stroke:black;"
     x="10"
     y="10"
     width="490"
     height="200" />
  <rect
     style="fill:url(#patternB);stroke:blue;"
     x="510"
     y="10"
     width="500"
     height="200" />
  <rect
     style="fill:url(#patternA);stroke:red;"
     x="160"
     y="220"
     width="200"
     height="490" />
  <rect
     style="fill:url(#patternB);stroke:green;"
     x="670"
     y="220"
     width="200"
     height="490" />
  <rect
     style="fill:url(#patternA);stroke:black;"
     x="10"
     y="720"
     width="490"
     height="490" />
  <rect
     style="fill:url(#patternB);stroke:black;"
     x="510"
     y="720"
     width="490"
     height="490" />
</svg>

Related