{"id":294,"date":"2010-04-15T10:28:17","date_gmt":"2010-04-15T09:28:17","guid":{"rendered":"http:\/\/bookleteer.com\/blog\/?p=294"},"modified":"2010-04-15T10:41:05","modified_gmt":"2010-04-15T09:41:05","slug":"james-bridle-residency-part-1","status":"publish","type":"post","link":"https:\/\/bookleteer.org\/blog\/2010\/04\/james-bridle-residency-part-1\/","title":{"rendered":"James Bridle : residency part 1"},"content":{"rendered":"<p>I used Bookleteer&#8217;s Storycube API to make physical souvenirs of ebooks, as described in <a href=\"http:\/\/booktwo.org\/notebook\/bookcubes\/\" target=\"_blank\">my post on Bookcubes<\/a>. In this post I&#8217;ll run through the code used to manipulate Bkkeepr data and send it to the API.<br \/>\n<img loading=\"lazy\" decoding=\"async\" alt=\"\" src=\"http:\/\/farm3.static.flickr.com\/2454\/4478550079_a0754c9fe7.jpg\" class=\"alignnone\" width=\"500\" height=\"375\" \/><\/p>\n<p>Bkkeepr pulls a bunch of data out, which includes your username, the book cover image, the book&#8217;s title and author, the dates you started and finished reading it, and the number of bookmarks you made in it.<br \/>\n<img loading=\"lazy\" decoding=\"async\" alt=\"\" src=\"http:\/\/farm5.static.flickr.com\/4042\/4479172426_051a1e84e1.jpg\" class=\"alignnone\" width=\"500\" height=\"375\" \/><\/p>\n<p>The Storycube API only accepts images, not text, so if you want text you&#8217;re going to have to build it into images. Here&#8217;s a useful piece of code for creating images with text on the fly, using the GD Graphics library which is built into most versions of PHP. It&#8217;s not pretty, but it&#8217;s useful for quick prototyping of data into images:<\/p>\n<blockquote><p>\t\t$im = @imagecreatetruecolor(156, 156)<br \/>\n     \t\tor die(&#8216;Cannot Initialize new GD image stream&#8217;);<br \/>\n     \t$grey = imagecolorallocate($im, 231, 231, 231);<br \/>\n\t\timagefilledrectangle($im, 0, 0, 156, 156, $grey);<br \/>\n\t\t$text_color = imagecolorallocate($im, 0, 0, 0);<br \/>\n\t\timagestring($im, 3, 10, 35,  $title, $text_color);<br \/>\n\t\timagestring($im, 3, 75, 50,  &#8216;by&#8217;, $text_color);<br \/>\n\t\timagestring($im, 3, 10, 65,  $author, $text_color);<br \/>\n\t\timagejpeg($im,&#8217;cubes\/title-image.jpg&#8217;);<br \/>\n\t\timagedestroy($im);<\/p><\/blockquote>\n<p>This code creates a new image of 156 x 156 pixels, colours it grey, then writes some text (&#8220;Title&#8221; by &#8220;Author&#8221;) in black across three lines, before saving the images to the &#8216;cubes&#8217; directory, and wiping the temporary image. All these functions are well documented at http:\/\/php.net\/manual\/en\/book.image.php &#8211; mostly, you just supply the text or colour for insertion, and a couple of reference points.<br \/>\n<img loading=\"lazy\" decoding=\"async\" alt=\"\" src=\"http:\/\/farm5.static.flickr.com\/4041\/4479210742_985ab88fd7.jpg\" class=\"alignnone\" width=\"500\" height=\"375\" \/><\/p>\n<p>Exactly the same process is followed to write the start date, finish date (if applicable) and bookmarks panel:<\/p>\n<blockquote><p>\t\t$im = @imagecreatetruecolor(156, 156)<br \/>\n     \t\tor die(&#8216;Cannot Initialize new GD image stream&#8217;);<br \/>\n     \t$grey = imagecolorallocate($im, 231, 231, 231);<br \/>\n\t\timagefilledrectangle($im, 0, 0, 156, 156, $grey);<br \/>\n\t\t$text_color = imagecolorallocate($im, 0, 0, 0);<br \/>\n\t\timagestring($im, 3, 10, 30,  &#8216;Started:&#8217;, $text_color);<br \/>\n\t\timagestring($im, 3, 10, 45,  $started, $text_color);<br \/>\n\t\tif ($finished !== &#8216;0000-00-00 00:00:00&#8217;) {<br \/>\n\t\t\timagestring($im, 3, 10, 70,  &#8216;Finished:&#8217;, $text_color);<br \/>\n\t\t\timagestring($im, 3, 10, 85,  $finished, $text_color);<br \/>\n\t\t\t}<br \/>\n\t\timagestring($im, 3, 10, 105,  &#8216;Bookmarks: &#8216;.$bookmarks_num, $text_color);<br \/>\n\t\t$im = imagerotate($im, 180, 0);<br \/>\n\t\timagejpeg($im,&#8217;cubes\/time-image.jpg&#8217;);<br \/>\n\t\timagedestroy($im);<\/p><\/blockquote>\n<p>Note that here we also use imagerotate() to spin this panel 180\u00b0 so that it&#8217;s the same orientation as the book cover panel.<\/p>\n<p>The next step is to send the completed panels to the Storycube API. First we need to get an authentication token:<\/p>\n<blockquote><p>\t\t$username = &#8216;USERNAME&#8217;;<br \/>\n\t\t$password = &#8216;PASSWORD&#8217;;<br \/>\n\t\t$token = file_get_contents(&#8216;http:\/\/generator.bookleteer.com\/authenticate.html?username=&#8217;.$username.&#8217;&#038;password=&#8217;.$password);<\/p><\/blockquote>\n<p>Then complete a request array, including the authentication token, and send this via curl to Bookleteer:<\/p>\n<blockquote><p>\t\t$fields=array(<br \/>\n                &#8216;token&#8217;=>$token,<br \/>\n                &#8216;author&#8217;=>$user,<br \/>\n                &#8216;title&#8217;=>$title.&#8217; by &#8216;.$author,<br \/>\n                &#8216;creation_date&#8217;=>&#8221;,<br \/>\n                &#8216;num_images&#8217;=>&#8217;6&#8217;,<br \/>\n\t          \t &#8216;image_1&#8217;=>&#8217;@cubes\/cover-image.jpg&#8217;,<br \/>\n\t          \t &#8216;image_2&#8217;=>&#8217;@cubes\/title-image.jpg&#8217;,<br \/>\n\t          \t &#8216;image_3&#8217;=>&#8217;@cubes\/time-image.jpg&#8217;,<br \/>\n\t          \t &#8216;image_4&#8217;=>&#8217;@cubes\/bkkeepr-image.jpg&#8217;,<br \/>\n\t          \t &#8216;image_5&#8217;=>&#8217;@cubes\/blank-image.jpg&#8217;,<br \/>\n\t          \t &#8216;image_6&#8217;=>&#8217;@cubes\/blank-image.jpg&#8217;,<br \/>\n                &#8216;paper_size&#8217;=>&#8217;A4&#8217;,<br \/>\n                &#8216;design&#8217;=>&#8217;Diffusion&#8217;);<\/p>\n<p>\t\t$curl = curl_init();<br \/>\n\t\tcurl_setopt($curl, CURLOPT_URL,&#8217;http:\/\/generator.bookleteer.com\/createStoryCube&#8217;);<br \/>\n\t\tcurl_setopt($curl, CURLOPT_POST, 1);<br \/>\n\t\tcurl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);<br \/>\n\t\tcurl_setopt($curl, CURLOPT_POSTFIELDS,$fields);<br \/>\n\t\t$result=curl_exec ($curl);<br \/>\n\t\t$content_type=curl_getinfo($curl, CURLINFO_CONTENT_TYPE);<br \/>\n\t\tcurl_close ($curl);<\/p><\/blockquote>\n<p>Note that the path to the images in the request array are prefaced by &#8216;@&#8217; &#8211; this is because curl needs to upload the images to the remote server, and also means those need to be local paths: you can&#8217;t send a URL. All images to be sent need to be stored locally &#8211; which is done here by calling Amazon for the cover image and saving it locally (cubes\/cover-image.jpg).<\/p>\n<p>The Storycube API returns either a pdf, or an error code. So we check which it is via the content-type, and if all is well we save the file with a unique timestamp and offer it for download, or we print the error message:<\/p>\n<blockquote><p>\t\tif ($content_type == &#8216;application\/pdf&#8217;) {<br \/>\n\t\t\t$filename = &#8216;bookcube-&#8216;.time().&#8217;.pdf&#8217;;<br \/>\n\t\t\t$fp = fopen(&#8216;cubes\/&#8217;.$filename, &#8216;w&#8217;);<br \/>\n\t\t\tfwrite($fp, $result);<br \/>\n\t\t\tfclose($fp);<br \/>\n\t\t\techo &#8216;Done: <a href=\"path\/to\/cubes\/'.$filename.'\">Download<\/a>&#8216;;<br \/>\n\t\t\t}<br \/>\n\t\telse {<br \/>\n\t\t\techo $result;<br \/>\n\t\t\t}<\/p><\/blockquote>\n<p>And that&#8217;s it.<br \/>\nJames Bridle, April 2010<br \/>\n<img loading=\"lazy\" decoding=\"async\" alt=\"\" src=\"http:\/\/farm5.static.flickr.com\/4001\/4479176742_5d2f08916e.jpg\" class=\"alignnone\" width=\"500\" height=\"375\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I used Bookleteer&#8217;s Storycube API to make physical souvenirs of ebooks, as described in my post on Bookcubes. In this post I&#8217;ll run through the code used to manipulate Bkkeepr data and send it to the API. Bkkeepr pulls a bunch of data out, which includes your username, the book cover image, the book&#8217;s title [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[36],"tags":[37,38],"class_list":["post-294","post","type-post","status-publish","format-standard","hentry","category-residencies","tag-api","tag-residency"],"_links":{"self":[{"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/posts\/294","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/comments?post=294"}],"version-history":[{"count":11,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/posts\/294\/revisions"}],"predecessor-version":[{"id":307,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/posts\/294\/revisions\/307"}],"wp:attachment":[{"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/media?parent=294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/categories?post=294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bookleteer.org\/blog\/wp-json\/wp\/v2\/tags?post=294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}