Jan Kühle - Blog https://kuehle.me/posts 2024-02-12T06:27:57Z Jan Kühle https://kuehle.me jkuehle90@gmail.com Extract color from image using JavaScript and Web Worker /posts/extract_image_color_web_worker/ 2015-02-15T13:28:00Z A demonstration of how to extract the dominant color of an image with pure JavaScript. For performance optimization I utilized a web worker, which had a great impact. <p>In the last week I was presented with the task to automatically extract a color from an image in a webpage and use this as the background color. A quick research resulted in the following steps:</p> <ol> <li> <p>Create a <code>canvas</code> element and draw the image on its 2d context.</p> </li> <li> <p>Get the pixel data from the context using <code>getImageData</code> method.</p> <p><strong>Note:</strong> When you want to load images from another domain, you need to add the <code>crossorigin</code> attribute to the <code>img</code> tag (<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image">more information on the MDN</a>).</p> </li> <li> <p>Calulate the dominant pixel color.</p> </li> </ol> <p>Thankfully there is a nice JavaScript library out there, so we do not need to implement all logic by outself: <a href="http://lokeshdhakar.com/projects/color-thief/">Color Thief</a>. The following example extracts the color from an image and applies as the background color:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>myImage<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/images/example.png<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br /><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br /> <span class="token keyword">var</span> myImage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"myImage"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> myImage<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"load"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> colorThief <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ColorThief</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> color <span class="token operator">=</span> colorThief<span class="token punctuation">.</span><span class="token function">getColor</span><span class="token punctuation">(</span>myImage<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> myImage<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span><br /> <span class="token string">"rgb("</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <p>This works well for a few small images. But when trying to do this for a couple of big images at once, it slows down the browser and results in hangs/lags on the website. Wo don't want that.</p> <p>So I played a bit with <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage">web workers</a> to get the heavy color calculation off the main thread. The only thing, that needs to be done on the main thread is creating the canvas and getting the pixel data from it. All the rest can be done separatly.</p> <p>To explain the use of web workers a little bit, imaging the image from the example above. In the main JavaScript we have to follwing code in the image onload event:</p> <pre class="language-js"><code class="language-js"><span class="token comment">// Setting up the web worker.</span><br /><span class="token keyword">var</span> worker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span><span class="token string">"worker.js"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />worker<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"message"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> color <span class="token operator">=</span> e<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /><br /> myImage<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span><br /> <span class="token string">"rgb("</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> color<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Starting the web worker.</span><br /><span class="token comment">// (Imagine the function getImageDataUsingCanvas to create a</span><br /><span class="token comment">// canvas, drawing the image on its context and then returning</span><br /><span class="token comment">// the image data.)</span><br /><span class="token keyword">var</span> imageData <span class="token operator">=</span> <span class="token function">getImageDataUsingCanvas</span><span class="token punctuation">(</span>myImage<span class="token punctuation">)</span><span class="token punctuation">;</span><br />worker<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span>imageData<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p>Then in the worker.js file, we have the following code:</p> <pre class="language-js"><code class="language-js"><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"message"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> imageData <span class="token operator">=</span> e<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /><br /> <span class="token comment">// The getColor function is a modified version of the</span><br /> <span class="token comment">// ColorThief.getColor function, which directly accepts</span><br /> <span class="token comment">// the pixel data as an argument.</span><br /> <span class="token keyword">var</span> color <span class="token operator">=</span> <span class="token function">getColor</span><span class="token punctuation">(</span>imageData<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function">postMessage</span><span class="token punctuation">(</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p>I made up a full example with and without web workers, so you can see the impact it has on the overall performance:</p> <p><a href="https://embed.plnkr.co/s1KlIF/preview">https://embed.plnkr.co/s1KlIF/preview</a></p> Export a client certificate from Firefox on Android without root /posts/export_client_cert_from_firefox_android/ 2015-11-22T14:04:00Z Exporting a client certificate, which is installed in Firefox on an Android phone can be difficult. Especially when you need the private key and your phone is not rooted. Here's a way. <p>When I set up an SSL certificate for this website I created an account on startssl.com. I finished the account creation on my smartphone with Firefox. During this process a client certificate was added to my browser and startssl.com suggested to export it, so I can use it on other browsers and computers as well.</p> <p>Now here comes the big question: how do you export a client certificate from Firefox on Android?</p> <p>Turns out it's possible (even without rooting your phone). Here are the steps, I had to take. Note that I'm doing this in a Windows 10 PC, but it should work the same way on any other OS.</p> <ol> <li> <p>Install the Android SDK and USB drivers for your smartphone. You need to connect to it using ADB.</p> </li> <li> <p>Activate developer options and USB debugging on your smartphone.</p> </li> <li> <p>Connect your smartphone to your computer using USB cable and make a backup of your Firefox app using ADB:</p> <pre class="language-powershell"><code class="language-powershell">adb backup org<span class="token punctuation">.</span>mozilla<span class="token punctuation">.</span>firefox</code></pre> </li> <li> <p>Download the <a href="https://sourceforge.net/projects/adbextractor/">Android Backup Extractor</a>. It's a tool to convert ADB backup files to tar archives, which you can easily extract. Use it with your backup:</p> <pre class="language-powershell"><code class="language-powershell">java <span class="token operator">-</span>jar <span class="token punctuation">.</span>\android-<span class="token function">backup-extractor</span><span class="token operator">-</span>20151102-bin\abe<span class="token punctuation">.</span>jar unpack <span class="token punctuation">.</span>\backup<span class="token punctuation">.</span>ab <span class="token punctuation">.</span>\backup<span class="token punctuation">.</span>tar</code></pre> <p>Then extract the tar archive with any tool you want (e.g. 7-Zip).</p> </li> <li> <p>Now browse the backup and Locate your Firefox profile. It should be in a folder similar to this:</p> <pre><code>apps\org.mozilla.firefox\f\mozilla\dx7e9l2j.default </code></pre> <p>You should be able to find the files cert9.db and key4.db in it. These files contain the client certificate. In order to extract it you need to the pk12util from Mozilla's <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS#Tools.2C_testing.2C_and_other_technical_details">NSS tools</a>.</p> </li> <li> <p>Download and build the NSS tools. The required process is described on the Mozilla wiki in detail: <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/NSS_Sources_Building_Testing">NSS sources building testing</a>. In short these are the steps, I followed:</p> <ol> <li> <p>Clone the repositories:</p> <pre class="language-powershell"><code class="language-powershell">mkdir nss-with-nspr<br />cd nss-with-nspr<br />hg clone https:<span class="token operator">/</span><span class="token operator">/</span>hg<span class="token punctuation">.</span>mozilla<span class="token punctuation">.</span>org/projects/nspr<br />hg clone https:<span class="token operator">/</span><span class="token operator">/</span>hg<span class="token punctuation">.</span>mozilla<span class="token punctuation">.</span>org/projects/nss</code></pre> </li> <li> <p>Install MozillaBuildSetup-Latest.exe</p> </li> <li> <p>Open start-shell-msvc2013.bat from mozilla build tools, navigate to the created nss-with-nspr\nss and folder and execute the command:</p> <pre class="language-powershell"><code class="language-powershell">make nss_build_all</code></pre> </li> <li> <p>Find pk12util.exe and certutil.exe in a folder similar to nss-with-nspr\dist\WIN954.0_DBG.OBJ\bin.</p> </li> </ol> </li> <li> <p>This step is probably not necessary, when you correctly include the generated libraries in the path, but I was only able to execute pk12util, when my working directory was nss-with-nspr\dist\WIN954.0_DBG.OBJ\lib.</p> <p>Because of this I copied the files cert9.db and key4.db from my extracted Firefox profile to this lib folder.</p> </li> <li> <p>Then you can extract the certificate with the following commands:</p> <pre class="language-powershell"><code class="language-powershell"><span class="token punctuation">.</span><span class="token punctuation">.</span>\bin\certutil<span class="token punctuation">.</span>exe <span class="token operator">-</span>K <span class="token operator">-</span>d sql:<span class="token punctuation">.</span></code></pre> <p>This will show all available certificates. Copy the certificate name from the last column and execute (enter any password you like, when asked):</p> <pre class="language-powershell"><code class="language-powershell"><span class="token punctuation">.</span><span class="token punctuation">.</span>\bin\pk12util<span class="token punctuation">.</span>exe <span class="token operator">-</span>o cert<span class="token punctuation">.</span>p12 <span class="token operator">-</span>n <span class="token string">"YOUR CERTIFICATE NAME"</span> <span class="token operator">-</span>d sql:<span class="token punctuation">.</span></code></pre> </li> <li> <p>Congratulations. You should now have a file cert.p12 in your current working directory, which you can import in your Firefox on Desktop.</p> </li> </ol>