{"id":3526,"date":"2011-10-29T11:20:29","date_gmt":"2011-10-29T15:20:29","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=3526"},"modified":"2011-10-30T22:12:45","modified_gmt":"2011-10-31T02:12:45","slug":"clipping-jpeg-images-into-non-rectangular-polygons-using-polyclip-js","status":"publish","type":"post","link":"http:\/\/www.useragentman.com\/blog\/2011\/10\/29\/clipping-jpeg-images-into-non-rectangular-polygons-using-polyclip-js\/","title":{"rendered":"Clipping JPEG Images Into Non-Rectangular Polygons Using <code>polyClip.js<\/code>"},"content":{"rendered":"<div class=\"box\">\n<div id=\"explanation1\">This photo is not a PNG image with an alpha channel.<\/div>\n<div id=\"explanation2\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/10\/scissors.jpg\">It is a JPEG<\/a> that has been clipped with polyClip.js<\/div>\n<div id=\"explanation3\">\n<p>The text was rotated using CSS3 Transforms, with alternate CSS for older IE using the <a href=\"https:\/\/www.useragentman.com\/IETransformTranslator\">IE Transform Translator<\/a>.  Original photo by <a href=\"http:\/\/www.flickr.com\/photos\/free-stock\/4816852597\/\">Emilian Robert Vicol<\/a> clipped with polyClip.js<\/p>\n<\/p><\/div>\n<div class=\"clipParent\"><img loading=\"lazy\" decoding=\"async\" data-polyclip=\" 0,0,45,3,55,8,64,18,74,24,80,32,86,45,82,32,83,38,86,46,88,52,90,62,90,68,91,76,91,82,91,83,103,87,112,91,121,97,127,102,133,106,136,112,138,116,139,121,139,122,147,125,154,127,163,129,178,131,190,132,204,132,210,131,225,124,286,107,332,96,370,88,401,83,425,79,450,76,457,77,456,80,446,85,430,91,406,99,383,108,365,114,352,119,384,117,416,116,453,114,472,113,474,113,472,118,446,126,419,132,390,138,362,144,343,148,307,153,282,157,266,159,245,160,234,160,219,160,209,163,198,167,182,175,170,183,158,194,156,195,157,201,157,204,157,204,157,210,153,219,148,229,143,236,137,244,132,250,124,258,118,263,113,267,98,276,87,281,77,283,0,284,1,191,10,190,16,191,20,191,21,192,28,191,37,190,39,189,38,190,40,190,48,190,53,191,57,191,69,188,77,187,91,183,109,179,127,173,146,166,162,158,173,153,158,151,144,150,127,151,105,152,86,154,66,157,53,160,49,161,46,165,44,167,41,168,33,168,28,167,28,166,21,170,16,171,11,171,4,170,0,168\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/10\/scissors.jpg\" alt=\"\"  width=\"480\" height=\"360\" class=\"alignleft size-full wp-image-3771\" \/><\/div>\n<\/div>\n<p>There have been many times I have come across the need to <strong>take an image and cut an irregular shape out of it.<\/strong>  Normally, when a developer comes across this requirement, the only thing to do is to open the image up with your favorite graphics editor, use the select tool to cut out the shape you want, and then save the result as a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Portable_Network_Graphics\">PNG<\/a>, since it is the only image format used by all web browsers that support alpha channels.  The problem is that <strong>PNG images, while compressed, are not as small as <a href=\"http:\/\/en.wikipedia.org\/wiki\/Jpeg\">JPEGs<\/a> if the source image is a photograph<\/strong>, and the download time of a page can balloon to unacceptable levels if there are many of these types of image on a page.  When I first came across this problem, I didn&#8217;t think there was an obvious solution, but after a lot of thought, I created <strong>a library that uses <a href=\"http:\/\/en.wikipedia.org\/wiki\/HTML_canvas\">HTML5 <code>canvas<\/code><\/a> to clip a JPEG <\/strong> (or any other image for that matter).  <strong>The library also supports older versions of IE<\/strong> (7-8) using the <a href=\"http:\/\/excanvas.sourceforge.net\/\">Excanvas JavaScript library<\/a> which polyfills <code>canvas<\/code> using <a href=\"http:\/\/en.wikipedia.org\/wiki\/Vector_Markup_Language\">VML<\/a>.<\/p>\n<h2>Okay, How Can I Do The Same Thing?<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/zoltan-dulac\/polyClip\">Download my script from github<\/a> (It includes jQuery 1.6.4 and excanvas release 3.  It should work with later versions &mdash; if it doesn&#8217;t, please let me know and I&#8217;ll fix it ;-) ) .<\/li>\n<li>Include them into the head of your document.<br \/>\n<blockquote class=\"code\">\n<pre>\r\n  &lt;script src=\"\/path\/to\/js\/jquery-1.6.2.min.js\"&gt;&lt;\/script&gt;\r\n\r\n  &lt;!--[if lt IE 9 ]&gt;\r\n   &lt;script src=\"\/path\/to\/js\/excanvas\/excanvas.compiled.js\"&gt;&lt;\/script&gt;\r\n  &lt;![endif]--&gt;\r\n  \r\n  &lt;script src=\"\/path\/to\/js\/polyClip-p.js\"&gt;&lt;\/script&gt;\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<li>Layout your page as normal, placing <code>img<\/code> tags where you want the clipped images to go:<br \/>\n<blockquote class=\"code\">\n<pre>\r\n&lt;div class=\"clipParent\"&gt;\r\n  &lt;img src=\"images\/image.jpg\" \/&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<\/blockquote>\n<p><strong>Note the <code>div<\/code> tag with the class of <code>clipParent<\/code><\/strong>.  You must surround all the image tags with <code>data-polyclip<\/code> attributes set one.  This is so you can style the image correctly, since the library will remove the image tag and replace it with a <code>canvas<\/code> element.\n<\/p><\/blockquote>\n<\/li>\n<li>For every image on your page that you want to clip, calculate the points of the shape you want to cut out of the image and place them in the <code>data-polyclip<\/code> attribute.  For example, let&#8217;s say you have the following shape you want to cut out of a photograph:\n<div class=\"centered ghost\">\n  <img decoding=\"async\" src=\"\/tests\/polyClip\/images\/crop.jpg\"   \/>\n<\/div>\n<div class=\"clipParent centered inFront\">\n  <img decoding=\"async\" src=\"\/tests\/polyClip\/images\/crop.jpg\" data-polyclip=\"487, 4, 500, 239, 19, 239, 43, 195\" data-stroke=\"rgb(0, 0, 0)\" \/><\/p>\n<div class=\"point\" id=\"pt1\" style=\"left: 487px; top: 4px; \"><span>(487, 4)<\/span><\/div>\n<div class=\"point\" id=\"pt2\" style=\"left: 500px; top: 239px\"><span>(500, 239)<\/span><\/div>\n<div class=\"point\" id=\"pt3\" style=\"left: 19px; top: 239px\"><span>(19, 239)<\/span><\/div>\n<div class=\"point\" id=\"pt4\" style=\"left: 43px; top: 195px; \"><span>(43, 195)<\/span><\/div>\n<\/div>\n<p>You would then just set the <code>data-polyclip<\/code> attribute to those points:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;img src=\"image.jpg\" <span class=\"hilite\">data-polyclip=\"487, 4, 500, 239, 19, 239, 43, 195\"<\/span> \/&gt;\r\n<\/pre>\n<\/blockquote>\n<p>Note that the point co-ordinates are comma delimited.  If you don&#8217;t want to calculate these numbers by hand, you can use your favorite imagemap generation tool to do generate the list of coordinates.  Just remember to take the coordinates out of the imagemap code and stick it in the <code>data-polyclip<\/code> attribute (for the examples on this page, I used the on-line tool available at <a href=\"http:\/\/www.image-maps.com\">image-maps.com<\/a>).<\/li>\n<\/ul>\n<h2>Why Should I Do This Instead of Using a PNG?<\/h2>\n<p>Compare the image above with a PNG clipped with the GIMP.   Even when I compressed the PNG with <a href=\"https:\/\/www.useragentman.com\/blog\/2009\/09\/16\/optimizing-png-files-for-both-web-and-print\/\">my PNG optimization script<\/a>, the 191K PNG file is huge compared to it&#8217;s tiny 18K polyclipped JPEG analogue (<strong>Note:<\/strong> file sizes refer to the size of the full image as displayed at the top of this article):<\/p>\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>JPG using polyClip.js (18K)<\/th>\n<th>PNG (191K)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<div class=\"clipParent\"><img loading=\"lazy\" decoding=\"async\" data-polyclip=\"0,0,55,0,64,4,70,12,80,22,82,32,86,45,82,32,83,38,86,46,88,52,90,62,90,68,91,76,91,82,91,83,103,87,112,91,121,97,127,102,133,106,136,112,138,116,139,121,139,122,147,125,154,127,163,129,178,131,190,132,204,132,210,131,225,124,286,107,332,96,370,88,401,83,425,79,450,76,457,77,456,80,446,85,430,91,406,99,383,108,365,114,352,119,384,117,416,116,453,114,472,113,474,113,472,118,446,126,419,132,390,138,362,144,343,148,307,153,282,157,266,159,245,160,234,160,219,160,209,163,198,167,182,175,170,183,158,194,156,195,157,201,157,204,157,204,157,210,153,219,148,229,143,236,137,244,132,250,124,258,118,263,113,267,98,276,87,281,77,283,0,284,1,191,10,190,16,191,20,191,21,192,28,191,37,190,39,189,38,190,40,190,48,190,53,191,57,191,69,188,77,187,91,183,109,179,127,173,146,166,162,158,173,153,158,151,144,150,127,151,105,152,86,154,66,157,53,160,49,161,46,165,44,167,41,168,33,168,28,167,28,166,21,170,16,171,11,171,4,170,0,168\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/10\/scissors.jpg\" alt=\"\"  width=\"480\" height=\"360\" class=\"alignleft size-full wp-image-3771\" \/><\/div>\n<\/td>\n<td>\n<div class=\"pngImage\">\n  <img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/10\/scissors.png\" \/>\n  <\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You may ask whether the amount of JavaScript used in this solution is greater than the bandwidth saved by using JPEG compression.  <strong>Not including jQuery, the amount of JavaScript clocks in at 2K or 13K<\/strong>, depending on the browser used (2K for the compressed polyClip script and 11K for excanvas, which will only be loaded by IE7-8). Although jQuery adds 91K to this equation, it doesn&#8217;t matter that much to me personally since I am probably using it for other parts of my page anyways.  <strong>Even with jQuery, the amount of JavaScript downloaded outweighs using a PNG,<\/strong> especially if your are clipping a larger image or a huge amount of smaller images.<\/p>\n<p><a class=\"exampleLink\" href=\"https:\/\/github.com\/zoltan-dulac\/polyClip\">Download the latest version of polyClip.js from github.<\/a><\/p>\n<h2>A Few Caveats<\/h2>\n<ul>\n<li>In IE7 and 8, the image may appear briefly as a black outline before the image appears. Other than that, it looks about the same as the other browsers.<\/li>\n<li>The image does not show up correctly in Opera Mini.  Then again, a lot of things (e.g. CSS3 text-shadows, CSS3 Transforms, etc.) don&#8217;t show up correctly in Opera Mini. :-)<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/10\/scissorsTeaser.jpg\" \/> Up until now, if a developer needed to clip an image in a non-rectangular shape, it was necessary to save the image as a PNG with an alpha channel. If the image is a photograph, the file-size balloons up to unacceptable levels. My new library, polyClip.js, allows developers to clip these images using photograph friendly JPEGs instead. This article guides you step by step on how to use it yourself.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[132,35,23,7,133,1,134],"tags":[139,137,138,135,136],"class_list":["post-3526","post","type-post","status-publish","format-standard","hentry","category-canvas","category-html5","category-images","category-javascript","category-jquery","category-uncategorized","category-vml","tag-arbitrary-clipping","tag-clipping","tag-non-rectangular-clipping-polygon-clipping","tag-polyclip","tag-polygon"],"_links":{"self":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3526","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=3526"}],"version-history":[{"count":121,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3526\/revisions"}],"predecessor-version":[{"id":3882,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3526\/revisions\/3882"}],"wp:attachment":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=3526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=3526"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=3526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}