{"id":2316,"date":"2012-06-04T15:33:41","date_gmt":"2012-06-04T21:33:41","guid":{"rendered":"http:\/\/bililite.com\/blog\/?p=2316"},"modified":"2012-06-05T08:12:14","modified_gmt":"2012-06-05T14:12:14","slug":"using-imagettftext-with-off-site-font-urls","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2012\/06\/04\/using-imagettftext-with-off-site-font-urls\/","title":{"rendered":"Using <code>imagettftext<\/code> with Off-site Font URLs"},"content":{"rendered":"<p>I'd like to keep my font files on Amazon S3 and save the cost of storing them on my web server. <code>imagettftext<\/code> doesn't say whether I can use a URL for the font file, but <code>imagettfbbox<\/code> unambiguously <a href=\"http:\/\/us.php.net\/imagettfbbox\">says<\/a>:\r\n<blockquote><em>fontfile<\/em> \r\nThe name of the TrueType font file (can be a URL). <\/blockquote>\r\nUnfortunately, <a href=\"http:\/\/stackoverflow.com\/questions\/9489785\/can-imagettfbbox-use-urls\">they are lying<\/a>, for both functions. The font file needs to reside in the local filesystem.<\/p>\r\n<p>But <a href=\"http:\/\/bililite.com\/blog\/2012\/02\/03\/nearly-free-speech\/\" title=\"Nearly Free Speech\">I pay for storage<\/a> and I want to have <a href=\"\/webservices\/?page=fonts\">plenty of open-source fonts<\/a> available for the <a href=\"\/webservices\/\">webservices<\/a> and that adds up. So I have to pull the fonts from Amazon S3 into a temporary file and pass that to <code>imagettftext\/imagettfbbox<\/code>. But then I need to remember to delete the temporary file as soon as I'm done with it, to minimize the storage cost. The only way to guarantee that (that I know about) is with the old C++ techinque <em><a href=\"http:\/\/en.wikipedia.org\/wiki\/RAII\">Resource Acquisition Is Initialization<\/a><\/em>&mdash;create an object that I know will be destroyed and make deleting the file part of that object's destructor. (We usually don't have to worry about that sort of thing in PHP since the most common resource we use is memory, and the garbage collector takes care of deleting unused memory resources).<\/p>\r\n<p>I also want to keep track of which fonts have already been downloaded, since I can use the same temporary file.<\/p>\r\n<p>So the following class uses my <a href=\"http:\/\/bililite.com\/blog\/2012\/04\/03\/using-s3-files-in-php\/\" title=\"Using S3 files in PHP\">CDN class<\/a> for access to the files, and requires a writeable directory for the cache for the temporary files. <code class=\"language-php\">$fontdir<\/code> is the local directory where the class looks for the font files initially, pulling then off the S3 server if not available locally.<\/p>\r\n<!--more-->\r\n<pre><code class=\"language-php\">class Fonts{\r\n\tprivate $fontfiles;\r\n\tprivate $fontdir;\r\n\tprivate $cachedir\r\n\tprivate $cdn;\r\n\t\r\n\r\n\tfunction __construct ($fontdir, $cachedir, $cdn){\r\n\t\t$this-&gt;fontdir = $cdn-&gt;slash($fontdir);\r\n\t\t$this-&gt;cachedir = realpath($cachedir);\r\n\t\t$this-&gt;cdn = $cdn;\r\n\t\t$this-&gt;fontfiles = array();\r\n\t}\r\n\t\r\n\tfunction fontfile($fontname){\r\n\t\t\/\/ if we already have a cached file, use it.\r\n\t\tif (isset($this-&gt;fontfiles[$fontname])) return $this-&gt;fontfiles[$fontname];\r\n\t\t$fontfile = $this-&gt;$cdn-&gt;realpath($this-&gt;fontdir.$fontname.'.ttf');\r\n\t\tif (!$this-&gt;$cdn-&gt;isCDN($fontfile)) return $fontfile; \/\/ if it's available locally, use it \r\n\t\t$tempFont = tempnam ($this-&gt;cachedir, 'font');\r\n\t\tfile_put_contents($tempFont, file_get_contents($fontfile)); \/\/ copy doesn't seem to work\r\n\t\t$this-&gt;fontfiles[$fontname] = $tempFont;\r\n\t\treturn $tempFont;\r\n\t}\r\n\t\r\n\tfunction __destruct(){\r\n\t\tforeach ($this-&gt;fontfiles as $fontfile) unlink($fontfile);\r\n\t}\r\n}<\/code><\/pre>\r\n<p>And use it as<\/p>\r\n<pre><code class=\"language-php\">$fontserver = new Fonts ('\/fonts\/', '\/cache\/', new S3('http:\/\/bililite.s3.amazonaws.com'));\r\n$fontfile = $fontserver->fontfile('DejaVuSans');\r\nimagefttext($image, $size, $x, $y, $color, $fontfile, 'Hello, World');<\/code><\/pre>\r\n<p>As an aside, this post reinforced the value of blogging: I had originally written this class as a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Singleton_pattern\">Singleton<\/a>, effectively with a global font list. When I wrote (and  researched links for) this, I discovered <a href=\"http:\/\/code.google.com\/p\/google-singleton-detector\/wiki\/WhySingletonsAreControversial\">how<\/a> <a href=\"http:\/\/accu.org\/index.php\/journals\/337\">bad<\/a> Singletons are, and rewrote it as a simple class.<\/p>\r\n\r\n\r\n","protected":false},"excerpt":{"rendered":"I'd like to keep my font files on Amazon S3 and save the cost of storing them on my web server. imagettftext doesn't say whether I can use a URL for the font file, but imagettfbbox unambiguously says: fontfile The name of the TrueType font file (can be a URL). Unfortunately, they are lying, for [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2316"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=2316"}],"version-history":[{"count":14,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2316\/revisions"}],"predecessor-version":[{"id":2330,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2316\/revisions\/2330"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=2316"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=2316"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=2316"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}