Three small tips for shrinking SVG images


I work on the SuperTinyIcons project. Our aim is to make pixel perfect SVG icons in under 1KB. Because SVG can be quite verbose, every single redundant byte we can eliminate is a byte we can use in drawing.

Here are three quick tips for shaving a few bytes off an SVG.

Decimal Magic

SVG co-ordinates can have decimal precision, like: 123.456. But what about co-ordinates which are less than one? 0.123 can be rewritten as .123 - we can drop the 0!

These two sed commands will turn 0. to . and -0. to -.

sed -i -z "s/ 0\./ \./g" *.svg
sed -i -z "s/\-0\./\-\./g" *.svg

What's my (new) line?

For boring technical reasons to do with teletype printers, Windows machines use two characters to represent a newline. CR the Carriage Return send the print-head back to the start of the line, then LF is the Line Feed to move the paper by one line.

Unix just uses LF. Because no-one uses teletypes.

The brilliant dos2unix program will convert all Windows-style newlines to Unix style. Magic!

Last Line

Most text editors add a newline to the end of any file you create. Why? Who knows.

Remove any trailing newlines from the file with:

sed -i -z s/\\n$// *.svg

Using the above three commands, I've been able to shave off dozens of bytes from these files. A worthy endeavour, I'm sure you'll agree!

If you want to make images as small as humanly possible, come join us.


Share this post on…

8 thoughts on “Three small tips for shrinking SVG images”

  1. Chris Midgley says:

    Most text editors add a newline to the end of any file you create. Why? Who knows.

    It's a POSIX standard. Having files end with newlines makes them work better with certain Unix tools, such as cat. Why text editors have adopted this standard is a different question -- I'd understand why the old Unix ones would, but not the newer or Windows ones.

    Reply
  2. I love me a good byte pinching.

    Have you considered increasing viewport sizing to remove decimal points?
    If a design requires 2 decimal precision then increasing the viewport sizing by a factor of 100 will save another byte per number used.

    How about using easily dividable viewport sizes?
    Using viewport="0 0 960 960" is dividable by more integers, producing integers, than say a "0 0 1000 1000".

    Reply
    1. says:

      That's a good point. I made the rather arbitrary to go for a viewport of 512x512. Some of the icons use a different size and then transform. See https://edent.github.io/SuperTinyIcons/images/svg/linux.svg

      <svg xmlns="http://www.w3.org/2000/svg"
      aria-label="Linux" role="img"
      viewBox="0 0 512 512" fill="#333"><rect
      width="512" height="512"
      rx="15%"
      fill="#fff"/>
      <g transform="matrix(2 0 0 2 256 256)">
         <path d="M-32-25c-3 7-24 29-22 51 8 92 36 30 78 53 0 0 75-42 15-110-17-24-2-43-13-59s-30-17-44-2 6 37-14 67"/>
         <path d="M42 21s9-18-8-31c16 17 6 32 6 32h-3C36-13 27 6 14-56 29-73 0-88 0-60h-9c1-24-20-12-8 5-1 37-23 52-23 78-7-18 6-32 6-32s-18 15-7 37 31 17 17 27c22 15 56 5 55-27 1-8 22-5 24-3s-3-4-13-4m-56-78c-7-2-5-11-2-11s8 7 2 11m19 1c-5-7-1-14 4-13s5 13-4 13" fill="#eee"/>
         <g fill="#fc2" stroke="#333" stroke-width="1">
            <path d="M-41 31l21 30c11 7 5 35-25 21-17-5-31-4-33-13s4-10 3-14c-4-22 14-11 19-22s5-16 15-2M71 45c-4-6 0-17-14-16-6 12-23 24-24 0-10 0-3 24-7 35-9 27 17 29 28 16l26-18c2-3 5-6-9-17m-92-92c-3-6 11-14 16-14s12 4 19 6 4 9 2 10S3-35-5-35s-10-8-16-12"/><path d="M-21-48c8 6 17 11 35-3"/>
         </g>
         <path d="M-10-54c-2 0 1-2 2-1m7 1c1-1-1-2-3-1"/>
      </g>
      </svg>
      

      If you think a 960 viewport would be better, please propose the change!

      Reply
      1. I tried to replicate linux.svg in both 960 and 360 viewports.
        In this specific case, the points all fall easily inside 512, so there's no advantage increasing to 960.
        So, I tried using 360 and came within 10 bytes ish of your result, with the transform removed.

        If I was starting a new SVG, I'd advise using either 960, 360, or 60 dependant upon the complexity (or the accuracy required to remove decimal places).
        Other multiples of 60 are equally usable.
        The reasoning: At lower multiples, base 60 numbers have more natural divisors (1, 2, 3, 4, 5, 6, 8, 9, 10, 12) than binary, hexadecimal, or decimal.
        Caveat: This doesn't mean better results cannot be attained using specific viewports, though it should prove a better start point generically.

        Reply
    2. I recently had need to redevelop the social icons for my personal site.
      Started with Super Tiny Icons, changed viewport to 96 sq then resized and compressed accordingly.
      All of them came out slightly smaller, though I wouldn't vouch for comparative accuracy, but good enough:
      https://codepen.io/2kool2/pen/ExNpjBL/left/

      Github comparison

      STI:

      Mine:

      Twitter comparison

      STI:

      Mine:

      I believe this decrease is mostly due to using a maximum 2 digit viewport (0 0 96 96).
      Plus any benefit from using an readily divisible number (96 rather than 99 or 100).

      Reply
      1. Examples failed to publish, here's the d values instead:

        Github STI:
        "M335 499c14 0 12 17 12 17H165s-2-17 12-17c13 0 16-6 16-12l-1-50c-71 16-86-28-86-28-12-30-28-37-28-37-24-16 1-16 1-16 26 2 40 26 40 26 22 39 59 28 74 22 2-17 9-28 16-35-57-6-116-28-116-126 0-28 10-51 26-69-3-6-11-32 3-67 0 0 21-7 70 26 42-12 86-12 128 0 49-33 70-26 70-26 14 35 6 61 3 67 16 18 26 41 26 69 0 98-60 120-117 126 10 8 18 24 18 48l-1 70c0 6 3 12 16 12z"

        Github mine:
        "M60 72c2 0 2 2 2 2H38s-1-2 1-2 2-1 2-2v-6c-9 2-11-4-11-4l-4-4c-3-2 0-2 0-2 4 0 6 3 6 3 3 5 7 4 9 3l3-5c-8 0-16-3-16-16 0-3 2-6 4-8-1-1-2-4 0-9 0 0 3-1 9 3h17c6-4 9-3 9-3 2 5 1 8 1 9 2 2 3 5 3 8 0 13-8 16-15 16l2 6v9c0 1 0 2 2 2z"

        Twitter STI:
        "M437 152a72 72 0 01-40 12a72 72 0 0032-40a72 72 0 01-45 17a72 72 0 00-122 65a200 200 0 01-145-74a72 72 0 0022 94a72 72 0 01-32-7a72 72 0 0056 69a72 72 0 01-32 1a72 72 0 0067 50a200 200 0 01-105 29a200 200 0 00309-179a200 200 0 0035-37"

        Twitter mine:
        "M68 35l-5 1 4-4-5 2-6-3a9 9 0 00-8 10c-7 0-13-3-17-8-2 3-1 8 2 11l-3-1c0 4 2 8 6 8l-4 1c2 3 5 5 8 6-3 2-8 3-12 3 4 3 8 4 13 4a24 24 0 0023-26l4-4"

        Reply

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">