<!DOCTYPE html>
<!-- ========================================== kroc camen of camen design ============================================= -->
<title>code · Under the Hood #1:  Is a PNG 32-Bit? in One Line</title>
<link rel="stylesheet" type="text/css" href="/design/design.css" />
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=no" />
<link rel="alternate" type="application/rss+xml" href="/code/rss" title="Just code" />
<link rel="canonical" href="/code/uth1_is-png-32bit" />
<!-- =================================================================================================================== -->
<header>
	<h1><a href="/" rel="index">
		Camen Design
	</a></h1>
	<nav><ul>
		<li><a href="/">all</a></li>
		<li><a href="/projects">projects</a></li>
		<li><a href="http://forum.camendesign.com">forum</a></li>
	</ul><ul>
		<li><a href="/quote/">quote</a></li>
		<li><a href="/writing/">writing</a></li>
		<li><a href="/blog/">blog</a></li>
		<li><a href="/photo/">photo</a></li>
		<li><a href="/code/" rel="tag">code</a></li>
		<li><a href="/art/">art</a></li>
		<li><a href="/link/">link</a></li>
		<li><a href="/poem/">poem</a></li>
		<li><a href="/audio/">audio</a></li>
	</ul><ul>
		<li><a href="/web-dev/">web-dev</a></li>
		<li><a href="/annoyances/">annoyances</a></li>
		<li><a href="/eve/">eve</a></li>
		<li><a href="/code-is-art/">code-is-art</a></li>
		<li><a href="/inspiration/">inspiration</a></li>
		<li><a href="/windows/">windows</a></li>
		<li><a href="/gift/">gift</a></li>
		<li><a href="/gaming/">gaming</a></li>
		<li><a href="/mac/">mac</a></li>
		<li><a href="/osnews/">osnews</a></li>
		<li><a href="/c64/">c64</a></li>
		<li><a href="/linux/">linux</a></li>
	</ul>
	<a rel="previous" href="/code/cleanly-grouping-by">
		older article →
	</a><a rel="next" href="/code/uth2_css3-hyperlinks">
		← newer article
	</a></nav>
</header>
<!-- =================================================================================================================== -->
<article><header>
	<!-- date published or updated -->
	<time pubdate datetime="2008-07-05T18:06:00+01:00">
		<sup>6:06<abbr>pm</abbr> • 2008</sup>
		<abbr title="July">Jul</abbr> 5
	</time>
	<!-- categories -->
	<ul>
		<li><a href="/code/uth1_is-png-32bit" rel="bookmark tag">code</a></li>
		<li><a href="/code-is-art/uth1_is-png-32bit">code-is-art</a></li>
		<li><a href="/web-dev/uth1_is-png-32bit">web-dev</a></li>
	</ul>
	<!-- licence -->
	<small>
		<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_GB">c</a>
		share + remix
	</small>
</header>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<section>
<h1>Under the Hood #1: <br />Is a PNG 32-Bit? in One Line</h1>
<aside>
	“Under The Hood” is a series breaking down many of the PHP and CSS tricks used in this website to make it more compact and artistically coded
</aside>
<p>
	<strong>To begin</strong> with, I wanted to showcase something very simple, that one could spend many lines of code
	on. For the <a href="?art">art</a> and <a href="?photo">photo</a> sections of the site, I have an upload form
	that attaches an image as an RSS enclosure to the post, and resizes the image for a preview on the home page.
</p><p>
	I’m touchy when it comes to image quality and use PNG wherever possible. I compress my PNGs with PNGCrush
	(Specifically an excellent Dashboard widget called
	<a href="http://www.plasticvicar.com/PNGpong/" rel="external">PNGPong</a>)
</p><p>
	But I also love transparency in PNGs. It’s incredibly flexible, and I’d rather (for maintenance reasons) be able
	to upload 32-bit images when possible. Thankfully PHP can resize 32-bit PNGs without destroying the alpha channel,
	via the
	<a href="http://uk3.php.net/manual/en/function.imagealphablending.php" rel="external"><code>imagealphablending</code></a>
	/
	<a href="http://uk3.php.net/manual/en/function.imagesavealpha.php" rel="external"><code>imagesavealpha</code></a>
	commands.
</p>


<h2>Choosing the Right Preview</h2>
<p>
	The programming issue is of being able to choose the right file type for the preview image shown on the site.
</p>
<dl>
	<dt>JPG upload → JPG preview</dt>
	<dd>
		Obviously
	</dd>
	<dt>PNG (without transparency) upload → JPG preview</dt>
	<dd>
		Why would I want to save the preview image as a JPG if I’m fussy about quality?<br />
		Simply because this site is also supposed to be fast to load, and a PNG image that is resized has many more
		colours due to the anti-aliasing when resizing, causing the file size to bloat massively.
	</dd>
	<dt>PNG (with transparency) upload → PNG preview</dt>
	<dd>
		A resized transparent PNG, without keeping the transparency would just have a horrible black background. We
		can’t be having that
	</dd>
</dl>


<h2>The Code</h2>
<p>
	All credit for this however goes to Wesley Gunn who posted a
	<a href="http://uk3.php.net/manual/en/function.imagecolortransparent.php#79145" rel="external">solution</a> on the
	PHP website, and that I improved upon to condense it into one line. Here’s the original:
</p>

<pre><code>$readPng = fopen  ($argSourceImagePath, "rb");
$readAlp = fread  ($readPng, 52);
           fclose ($readPng);

if(substr(bin2hex($readAlp),50,2) == "04" || substr(bin2hex($readAlp),50,2) == "06")
echo("Png has alpha");</code></pre>

<p>
	Here’s a break down of what’s happening here:
</p>

<pre><code>//open the image file, "Read Binary"
$readPng = fopen  ($argSourceImagePath, "rb");
//read 52 Bytes. this is the PNG header up to the byte(s) that specify transparency
$readAlp = fread  ($readPng, 52);
//close the file
           fclose ($readPng);

//`bin2hex` converts the PNG header to hexadecimal codes, and `substr` strips out the two bytes that
//specify the PNG transparency - "04" is for a greyscale PNG with transparency, and "06" for a 32-bit PNG
if(substr(bin2hex($readAlp),50,2) == "04" || substr(bin2hex($readAlp),50,2) == "06")
echo("Png has alpha");</code></pre>

<p>
	Whilst this is a very good way to achieve the task, I hate spawning temporary variables and would like to do this
	same thing inline so that it could be combined with any <code>if</code> statement. The first thing to do is to read
	the file without having to use a file handle to open and close the file.
	<br /><br />
	Here is my redesign of this code:
</p>

<pre><code>$is_alpha = ord (file_get_contents ($file_path, false, null, 25, 1)) &amp; 4;</code></pre>

<p>
	<q><a href="http://uk.php.net/file_get_contents" rel="external"><code>file_get_contents</code></a></q> returns
	the contents of a file without having to open and close handles, but has the added ability to return a chosen number
	of bytes, starting at a set offset. Perfect! This isn’t binary however, and thus each pair of bytes is treated as
	a single ‘letter’, meaning that the transparency flag is the 25<sup>th</sup> along using
	<code>file_get_contents</code> instead of 50. We return just one ‘letter’, and
	<a href="http://uk2.php.net/manual/en/function.ord.php" rel="external"><code>ord</code></a> returns the
	<abbr>ASCII</abbr> numerical representation of that ‘letter’, either 4 or 6.
</p><p>
	This is also a super fast solution, as <code>file_get_contents</code> is only reading two bytes and that’s it,
	this operation is also cached by PHP.
</p><p>
	Finally the “<code>&amp; 4;</code>” bitwise ANDs the result ignoring all other values that do not contain
	transparency. An example below demonstrates the bitwise operation filtering out both values 4 and 6, and ignoring
	other values
</p>

<pre>00000110 = Binary 6 - a transparent PNG
00000100 = “&amp; 4” mask, only a 1 on the top row and 1 on the bottom row pass through, giving:
--------
00000100 = 4

00000100 = Binary 4 - a greyscale transparent PNG
00000100 = “&amp; 4”
--------
00000100 = 4

An example of an unwanted value
00000011 = Binary 3 - not a transparent PNG
00000100 = “&amp; 4”
--------
00000000 = 0</pre>

<p>
	Therefore my code will return 4 if the PNG is transparent, and 0 if not. In PHP, zero is considered false, and any
	number higher than zero is considered true. Thus you can easy place this code in an <code>if</code> without having
	to specifically check for <q>4</q>, e.g.
</p>

<pre><code>if (ord (file_get_contents ($file_path, false, null, 25, 1)) &amp; 4) {
	//PNG is transparent...
} else {
	//PNG is not transparent...
}</code></pre>


<h2>Limitations</h2>
<p>
	This code will not detect a 256 colour (8-bit) PNG, with transparency (like a <abbr>GIF</abbr>). The normal
	transparency flag is not set in this instance; instead this could be detected by the presence of both “PLTE”
	(‘Palette’ - 256 colours) and “tRNS” in the file. Although the precise location of these is not fixed
	because the size of the palette can vary.
</p><p>
	In order to work around this, I’d just re-save any 8-bit PNG with transparency as a 32-bit one - it’d increase
	file size, but not by a painful amount.
</p>
</section>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
</article>
<footer>
	<nav><a href="http://forum.camendesign.com">‹ Discuss this in the Forum ›</a></nav>
		
	<a href="mailto:kroc@camendesign.com">kroc@camendesign.com</a>
	<nav>view-source:
		<a href="/code/uth1_is-png-32bit.rem">Rem</a> •
		<a href="/code/uth1_is-png-32bit.html">HTML</a> •
		<a href="/design/">CSS</a> •
		<a href="/.system/">PHP</a> •
		<a href="/.htaccess">.htaccess</a>
	</nav>
	<form method="get" action="https://duckduckgo.com">
		<input type="hidden" name="sites" value="camendesign.com" />
		<input type="search" name="q" placeholder="search…" />
		<input type="submit" value="Go" />
	</form>
</footer>
<!-- =================================================================================================== code is art === -->