{"id":7135,"date":"2015-11-07T17:16:14","date_gmt":"2015-11-07T21:16:14","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=7135"},"modified":"2015-11-09T02:18:13","modified_gmt":"2015-11-09T06:18:13","slug":"creating-alpha-channel-jpegs-using-svg","status":"publish","type":"post","link":"http:\/\/www.useragentman.com\/blog\/2015\/11\/07\/creating-alpha-channel-jpegs-using-svg\/","title":{"rendered":"Creating Alpha Channel JPEGs Using SVG"},"content":{"rendered":"\r\n<div id=\"header-image\" class=\"stars full-bleed-container\">\r\n<picture class=\"full-bleed\" title='alternative image format' id='alternate-image'>\r\n              <!--[if IE 9]><video style='display: none;'><![endif]-->\r\n              <source srcset='\/images\/7135\/sun-rays-alpha\/sun-xrays-320.svgz 320w, \/images\/7135\/sun-rays-alpha\/sun-xrays-600.svgz 600w, \/images\/7135\/sun-rays-alpha\/sun-xrays-640.svgz 640w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1024.svgz 1024w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1200.svgz 1200w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1727.svgz 1727w, \/images\/7135\/sun-rays-alpha\/sun-xrays-2016.svgz 2016w' type='image\/svg+xml'>\r\n              <!--[if IE 9]><\/video><![endif]-->\r\n              <img srcset='\/images\/7135\/sun-rays-alpha\/sun-xrays-320.png 320w, \/images\/7135\/sun-rays-alpha\/sun-xrays-600.png 600w, \/images\/7135\/sun-rays-alpha\/sun-xrays-640.png 640w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1024.png 1024w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1200.png 1200w, \/images\/7135\/sun-rays-alpha\/sun-xrays-1727.png 1727w, \/images\/7135\/sun-rays-alpha\/sun-xrays-2016.png 2016w'  \/>\r\n        <\/picture>\r\n<\/div>\r\n<\/div>\r\n<p>The image of the sun above is <strong>not a PNG<\/strong> on top of the animated stars, <strong>it is a plain-old JPEG with an alpha channel.<\/strong>  This was created by embedding an SVG and alpha channel inside of an SVG and compressing it to form an SVGZ file.  The types of SVG files are much <strong>smaller than their lossless PNG<\/strong> equivalents and are a great fallback\/alternative to JPEG-XR, JPEG 2000 and WEBP, which support both lossy compression and alpha channeling as well (<a href=\"https:\/\/www.useragentman.com\/blog\/2015\/01\/14\/using-webp-jpeg2000-jpegxr-apng-now-with-picturefill-and-modernizr\/\">see my previous blog post on the subject for more details<\/a>).  <strong>It even works in Firefox,<\/strong> where the other image formats don&#8217;t:<\/p>\n\r\n<table class=\"dataTable withCheckmarks\">\r\n<thead>\r\n<tr>\r\n<th><\/th><th>WEBP<\/th><th>JPEG-2000<\/th><th>JPEG-XR<\/th><th>JPEG embedded in SVG<\/th>\r\n<\/tr>\r\n<\/thead>\r\n<tbody>\r\n<tr><th>Chrome<\/th><td class=\"check\">\u2714<td><\/td><td><\/td><td class=\"check\">\u2714<\/td><\/tr>\r\n<tr><th>Safari<\/th><td><\/td><td class=\"check\">\u2714<\/td><td><\/td><td class=\"check\">\u2714<\/td><\/tr>\r\n<tr><th>IE9+<\/th><td><\/td><td><\/td><td class=\"check\">\u2714<\/td><td class=\"check\">\u2714<\/td><\/tr>\r\n<tr><th>Firefox<\/th><td><\/td><td><\/td><td><\/td><td class=\"check\">\u2714<\/td><\/tr>\r\n<\/tbody>\r\n<\/table>\r\n<p>Since <a href=\"http:\/\/caniuse.com\/#search=image%20format\">it looks like Firefox won&#8217;t support any of the other formats any time soon<\/a>, this is a really good cross-browser solution to optimize your alpha-channeled images.  <\/p>\n<p><a href=\"http:\/\/w3.eleqtriq.com\/\">Dirk Weber<\/a> details how <a href=\"http:\/\/w3.eleqtriq.com\/2014\/08\/applying-alpha-channels-to-jpgs\/\">he did this with Adobe Photoshop<\/a> by using an SVG and two JPEGs.  This was a great start, but making one asset into three is not optimal since it adds a bit of HTTP overhead.  I then saw <a href=\"http:\/\/mario-klingemann.tumblr.com\/\">Mario Klingemann<\/a>&#8216;s web application <a href=\"http:\/\/quasimondo.com\/ZorroSVG\/\">Zorro SVG<\/a>, which uses base64 encoding to combine the files into the SVG code.  It then compresses the SVG into an SVGZ file using gzip.  I took the ideas from both posts and incorporated them into my <a href=\"https:\/\/github.com\/zoltan-dulac\/html5ImageConverter\">html5ImageConverter<\/a> so I can create these images quickly on the command line (which is great for mass batch conversions).<\/p>\n<h2>How To Create Them<\/h2>\n<h3>Using ZorroSVG<\/h3>\n<p>The quickest way to play around with these images without installing any software is by using the <a href=\"http:\/\/quasimondo.com\/ZorroSVG\/\">Zorro SVG<\/a> website.  Just upload your image via the form and download the resultant SVG file.  This is great, quick way to start off playing with these files but if you have lots of files to convert, this can take quite a bit of time.  <\/p>\n<h3>Using The Command Line html5ImageConverter<\/h3>\n<p>In order to speed up the batch conversion of multiple files, I created a tool, <code>createAlphaJPEG.sh<\/code>, as part of my <a href=\"https:\/\/github.com\/zoltan-dulac\/html5ImageConverter\">html5ImageConverter<\/a> toolset.  Download the html5ImageConverter and type in the following command:<\/p>\n<blockquote class=\"code\">\n<pre>\r\ncreateAlphaJPEG.sh --q=50 --compress-svg dice.png\r\n<\/pre>\n<\/blockquote>\n<p>The <code>--q=50<\/code> is used to control the JPEG compression quality and <code>--compress-svg<\/code> ensures we create a compressed SVGZ version of the file.  If you want to convert more than one PNG file, use the following:<\/p>\n<blockquote class=\"code\">\n<pre>\r\ncreateAlphaJPEG.sh --q=50 --compress-svg file1.png file2.png file3.png\r\n<\/pre>\n<\/blockquote>\n<p>How does <code>createAlphaJPEG.sh<\/code> create alpha channeled JPEGs?  How do you make your own command-line tools to generate them?  Read on.<\/p>\n<h3>Using The Command Line without html5ImageConverter<\/h3>\n<p>If you want to &#8220;roll your own&#8221; PNG to SVGZ converter, let me walk you through the steps that the html5ImageConverter uses to generate these files:<\/p>\n<ol>\n<li>\nLet&#8217;s start with a PNG file, like this:<br \/>\n<img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320.png\" alt=\"PNG rendition of dice with alpha channel\" class=\"aligncenter size-full wp-image-7140\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320.png 320w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320-300x225.png 300w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/li>\n<li>Next, we use <a href=\"http:\/\/www.imagemagick.org\/script\/index.php\">ImageMagick<\/a> to extract the alpha channel from the PNG and convert it to grayscale with this command:<br \/>\n<blockquote class=\"code\">\n<pre>\r\nconvert dice.png -alpha extract -colorspace Gray dice_alpha.png\r\n<\/pre>\n<\/blockquote>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/11\/dice-320_alpha.png\" alt=\"dice-320_alpha\" width=\"320\" height=\"240\" class=\"aligncenter size-full wp-image-7138\" \/><\/li>\n<li>We then convert the original image and the extracted alpha channel image to JPEG format:<br \/>\n<blockquote class=\"code\">\n<pre>\r\nconvert dice.png -define quality=80 dice.jpg\r\nconvert dice_alpha.png -define quality=80 dice_alpha.jpg\r\n<\/pre>\n<\/blockquote>\n<p>Here is dice.jpg:<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320.jpg\" alt=\"dice-320\" width=\"320\" height=\"240\" class=\"aligncenter size-full wp-image-7139\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320.jpg 320w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320-300x225.jpg 300w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><br \/>\nand here is dice_alpha.jpg:<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/10\/dice-320_alpha.jpg\" alt=\"dice-320\" width=\"320\" height=\"240\" class=\"aligncenter size-full wp-image-7139\" \/><br \/>\n(<strong>Note:<\/strong> I am using 80% quality here.  You can compress the image even more if you want to).<\/p>\n<\/li>\n<li>We then create an SVG that will contain the images.<br \/>\n<blockquote class=\"code\">\n<pre>\r\n&lt;svg xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\" \r\n  viewBox=\"0 0 320 240\" width=\"320\" height=\"240\" \r\n  xmlns=\"http:\/\/www.w3.org\/2000\/svg\"&gt;\r\n  &lt;defs&gt;\r\n    &lt;mask id=\"a\" maskUnits=\"userSpaceOnUse\" \r\n        maskContentUnits=\"userSpaceOnUse\"&gt;\r\n      &lt;image width=\"320px\" height=\"240px\" \r\n        xlink:href=\"dice_alpha.jpg\"&gt;&lt;\/image&gt;\r\n    &lt;\/mask&gt;\r\n  &lt;\/defs&gt;\r\n  &lt;image style=\"mask: url(#a);\" \r\n    xlink:href=\"dice.jpg\"&gt;&lt;\/image&gt;\r\n&lt;\/svg&gt;\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<li>The problem with the above SVG is that, as said earlier in this post, we will have three assets to download (<a href=\"http:\/\/mario-klingemann.tumblr.com\/\">Mario Klingemann<\/a> mentions on the <a href=\"http:\/\/quasimondo.com\/ZorroSVG\/\">Zorro SVG<\/a> website that relative URLs are also not handled consistently, so there is an issue with SVG).  In order to fix this, let&#8217;s base64 the JPGs using the <code>base64<\/code> command:<br \/>\n<blockquote class=\"code\">\n<pre>\r\ncat dice_alpha.png | base64 | pbcopy\r\n<\/pre>\n<\/blockquote>\n<p>(<strong>Note:<\/strong> <code>pbcopy<\/code> takes the output of the <code>cat<\/code> command and puts it into the OSX clipboard so you can paste it into the editor that contains your SVG.  If you want to do the same thing for Windows or Linux, use the <code>xclip<\/code> and <code>clip<\/code> command respectively).<\/p>\n<p>Using the base64 command on the <code>dice_alpha.jpg<\/code> and <code>dice.jpg<\/code> above, we get the following SVG code:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;svg xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\" \r\n  viewBox=\"0 0 320 240\" width=\"320\" height=\"240\" \r\n  xmlns=\"http:\/\/www.w3.org\/2000\/svg\"&gt;\r\n  &lt;defs&gt;\r\n    &lt;mask id=\"a\" maskUnits=\"userSpaceOnUse\" \r\n        maskContentUnits=\"userSpaceOnUse\"&gt;\r\n      &lt;image width=\"320px\" height=\"240px\" \r\n        xlink:href=\"data:image\/jpeg;base64,\/9j\/4AAQSkZJRgA...\"&gt;&lt;\/image&gt;\r\n    &lt;\/mask&gt;\r\n  &lt;\/defs&gt;\r\n  &lt;image style=\"mask: url(#a);\" \r\n    xlink:href=\"data:image\/jpeg;base64,\/9j\/4AAQSkZJRgABAQAAAQA...\"&gt;&lt;\/image&gt;\r\n&lt;\/svg&gt;\r\n<\/pre>\n<\/blockquote>\n<p>(<strong>Another Note:<\/strong> We only put the first few characters of the base64 code above since it is quite huge).\n<\/li>\n<li>\nWe save the final SVG file and compress it with <code>gzip<\/code>.  If the resultant SVG is saved in the file <code>dice.svg<\/code>, then we compress the SVG file with this command:<\/p>\n<blockquote class=\"code\">\n<pre>\r\ngzip -9 $stub.svg\r\nmv $stub.svg.gz $stub.svgz\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<li>\nLoad the image in your webpage with the <code>&lt;picture&gt;<\/code> element:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;picture title='alternative image format' id='alternate-image'&gt;\r\n      &lt;!--[if IE 9]&gt;&lt;video style='display: none;'&gt;&lt;![endif]--&gt;\r\n      &lt;source srcset='dice.svgz' type='image\/svg+xml'&gt;\r\n      &lt;!--[if IE 9]&gt;&lt;\/video&gt;&lt;![endif]--&gt;\r\n      &lt;img srcset='dice-320.png'  \/&gt;\r\n&lt;\/picture&gt;\r\n<\/pre>\n<\/blockquote>\n<p>(the IE conditional-commented <code>&lt;video&gt;<\/code> tags are there to prevent bugs in IE9 and down).  If you are using picturefill, this code will load the SVG in all browser that support it.  If you aren&#8217;t, then it will load the SVG in browsers that support it as long as they can natively use the <code>&lt;picture&gt;<\/code> tag.  For more information about how to use the <code>&lt;picture&gt;<\/code> tag, read the &#8220;Use &lt;picture&gt; For Still Images section of my blog post<a href=\"https:\/\/www.useragentman.com\/blog\/2015\/01\/14\/using-webp-jpeg2000-jpegxr-apng-now-with-picturefill-and-modernizr\/#using-picturefill\">Using WEBP\/JPEG 2000\/JPEG-XR\/APNG Now With Picturefill and Modernizr<\/a>.  <a href=\"http:\/\/sarasoueidan.com\">Sara Soueidan<\/a> excellent in-depth article <a href=\"http:\/\/sarasoueidan.com\/blog\/svg-picture\/\">Better SVG Fallback and Art Direction With The &lt;picture&gt; Element<\/a> is a thorough examination of the  <code>&lt;picture&gt;<\/code> tag.\n<\/li>\n<li>\nThe result should be this:<br \/>\n<\/p>\n<div class=\"full-bleed-container stars with-dice\">\n<picture title='alternative image format' id='alternate-image'>\n      <!--[if IE 9]><video style='display: none;'><![endif]--><source srcset='\/blog\/wp-content\/uploads\/2015\/11\/dice-320.svgz' type='image\/svg+xml'><!--[if IE 9]><\/video><![endif]--><br \/>\n      <img srcset='\/blog\/wp-content\/uploads\/2015\/10\/dice-320.png'  \/>\n<\/picture>\n<\/div>\n<\/li>\n<li>\nIf you have troubles loading the SVG into your browser, you may want to make sure your webserver is configured correctly. You can either read the kaioa.com article on <a href=\"http:\/\/kaioa.com\/node\/45\">How to Configure Apache to Serve SVG\/SVGZ the Right Way<\/a>, or you can put this code into a <code>.htaccess<\/code> file inside the directory that will serve the SVGZ files:<\/p>\n<blockquote class=\"code\">\n<pre>\r\nAddType image\/svg+xml svg svgz\r\nAddEncoding gzip svgz\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<\/ol>\n<p><strong>Note that some browsers (e.g. Firefox) need to have their cache cleared<\/strong> in order to see the image after these server tweaks are added.<\/p>\n<h3>Using Photoshop<\/h3>\n<p>As mentioned earlier, <a href=\"http:\/\/w3.eleqtriq.com\/\">Dirk Weber<\/a> details how <a href=\"http:\/\/w3.eleqtriq.com\/2014\/08\/applying-alpha-channels-to-jpgs\/\">he did this with Adobe Photoshop<\/a> by using an SVG and two JPEGs.  You can take the two JPEGs created in his tutorial and use steps 5-8 in the commandline tutorial above to put the data into one SVG file. <\/p>\n<h2>Can You Do Animations?<\/h2>\n<p>If you create a &#8220;sprite-sheet&#8221; containing all of the frames in one still SVG image, You can use CSS <code>steps()<\/code> function to animate through the frames using CSS animations.  Since a previous blog post covered <a href=\"https:\/\/www.useragentman.com\/blog\/2015\/01\/14\/using-webp-jpeg2000-jpegxr-apng-now-with-picturefill-and-modernizr\/#producing-truecolor-animations\">this animation technique with JPEG-XR and JPEG-2000 alpha channeled images<\/a>, I won&#8217;t cover it again here.  Instead, <strong>drag the animated JPEG\/SVG sun below and see how it works in action.<\/strong><\/p>\n<p><iframe id=\"sun-alpha-demo\" src=\"\/images\/7135\/sun-anim\/sun-svgz.html\" class=\"full-bleed\"><br \/>\n<\/iframe><\/p>\n<p><a class=\"exampleLink\" href=\"\/images\/7135\/sun-anim\/sun-svgz.html\">View the clean-room version of the above example<\/a><\/p>\n<h2>How Do These Files Compare with Alpha-Channeled WEBP\/JPEG-XR and JPEG 2000 Images?<\/h2>\n<p>That is a very good question.  In a lot of cases, JPEG doesn&#8217;t compress as well as WEBP, JPEG 2000 or JPEG-XR, since they have better compression algorithms.  The question of &#8220;which format is better than which&#8221; is a topic unto itself, which I will leave for a separate blog post.<\/p>\n<h2>Further Reading<\/h2>\n<ul>\n<li><a href=\"http:\/\/w3.eleqtriq.com\/2014\/08\/applying-alpha-channels-to-jpgs\/\">Applying Alpha Channels to JPGs<\/a> by <a href=\"http:\/\/w3.eleqtriq.com\/\">Dirk Weber<\/a>.<\/li>\n<li><a href=\"http:\/\/blog.teamtreehouse.com\/css-sprite-sheet-animations-steps\">CSS Sprite Sheet Animations with steps()<\/a> by <a href=\"https:\/\/twitter.com\/guilh\">Guil Hernandez<\/a>.<\/li>\n<li><a href=\"http:\/\/sarasoueidan.com\/blog\/svg-picture\/\">Better SVG Fallback and Art Direction With The &lt;picture&gt; Element<\/picture><\/a> by the always amazing <a href=\"http:\/\/sarasoueidan.com\">Sara Soueidan<\/a>.<\/li>\n<li>My previous blog post, <a href=\"https:\/\/www.useragentman.com\/blog\/2015\/01\/14\/using-webp-jpeg2000-jpegxr-apng-now-with-picturefill-and-modernizr\/\">Using WEBP\/JPEG 2000\/JPEG-XR\/APNG Now With Picturefill and Modernizr<\/a>.<\/li>\n<\/ul>\n<h2>Credits<\/h2>\n<ul>\n<li>Photo of the sun at the top of this article courtesy <a href=\"http:\/\/www.jpl.nasa.gov\/spaceimages\/\">NASA\/JPL-Caltech<\/a>.<\/li>\n<li><a href=\"http:\/\/sohowww.nascom.nasa.gov\/data\/realtime\/gif\/\">Rotating sun animation<\/a> was taken from the <a href=\"http:\/\/sohowww.nascom.nasa.gov\/\">The Solar &amp; Heliospheric Observatory\u2019s website<\/a> (alpha channel added by me).<\/li>\n<\/ul>\n<p><!--\n\n\n<h2>Making libpng for APNG files<\/h2>\n\n\nhttp:\/\/www.linuxfromscratch.org\/blfs\/view\/svn\/general\/libpng.html\n- ensure you do an 'LDFLAGS=\"-L\/usr\/lib\/\" export LDFLAGS' in OSX.\n- http:\/\/registry.gimp.org\/node\/24394 has more notes on compiling.\n\nhttp:\/\/superuser.com\/questions\/97762\/how-to-pipe-text-from-command-line-to-the-clipboard\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2015\/11\/sun-alpha-thumb.jpg\" alt=\"sun-alpha-thumb\" \/> PNGs with alpha channels are great, but they can take up a lot of bandwidth.  Alternative image formats such as JPEG-XR, JPEG 2000 and WEBP are more efficient, but they are not supported by FIrefox (and may never be).  In comes a full cross-browser solution: SVG files that encapulate a JPEG with an alpha channel.  This post will cover how to create these image files a number of different ways, and show how you can animate these images as well.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7135","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/7135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=7135"}],"version-history":[{"count":73,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/7135\/revisions"}],"predecessor-version":[{"id":7199,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/7135\/revisions\/7199"}],"wp:attachment":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=7135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=7135"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=7135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}