X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=BookReaderIA%2Fdatanode%2FBookReaderImages.inc.php;h=d0e2c79572cfc480f42573a0b5379863abd5caa4;hb=65036b29a1937e3ea03cb826f2d99ef0430025e1;hp=5af62e16360a657ef910aa919cfe0278b37ef6b2;hpb=f212751b862695e030da3cf93f6a7567c6c1856c;p=bookreader.git diff --git a/BookReaderIA/datanode/BookReaderImages.inc.php b/BookReaderIA/datanode/BookReaderImages.inc.php index 5af62e1..d0e2c79 100644 --- a/BookReaderIA/datanode/BookReaderImages.inc.php +++ b/BookReaderIA/datanode/BookReaderImages.inc.php @@ -24,6 +24,8 @@ the MIME type is "image/jpeg". along with BookReader. If not, see . */ +require_once("BookReaderMeta.inc.php"); + class BookReaderImages { public $MIMES = array('gif' => 'image/gif', @@ -41,12 +43,138 @@ class BookReaderImages 'png' => 'png', 'tif' => 'tiff', 'tiff' => 'tiff'); - + + // Width when generating thumbnails + public $imageSizes = array( + 'thumb' => 100, + 'small' => 240, + 'medium' => 500, + 'large' => 1024, + ); + // Paths to command-line tools var $exiftool = '/petabox/sw/books/exiftool/exiftool'; var $kduExpand = '/petabox/sw/bin/kdu_expand'; /* + * Serve an image request that requires looking up the book metadata + * + * Code path: + * - Get book metadata + * - Parse the requested page (e.g. cover_t.jpg, n5_r4.jpg) to determine which page type, + * size and format (etc) is being requested + * - Determine the leaf number corresponding to the page + * - Determine scaling values + * - Serve image request now that all information has been gathered + */ + + function serveLookupRequest($requestEnv) { + $brm = new BookReaderMeta(); + try { + $metadata = $brm->buildMetadata($_REQUEST['id'], $_REQUEST['itemPath'], $_REQUEST['subPrefix'], $_REQUEST['server']); + } catch (Exception $e) { + $this->BRfatal($e->getMessage); + } + + $page = $_REQUEST['page']; + + // Index of image to return + $imageIndex = null; + + // deal with subPrefix + if ($_REQUEST['subPrefix']) { + $parts = split('/', $_REQUEST['subPrefix']); + $bookId = $parts[count($parts) - 1 ]; + } else { + $bookId = $_REQUEST['id']; + } + + $pageInfo = $this->parsePageRequest($page, $bookId); + + $basePage = $pageInfo['type']; + + switch ($basePage) { + case 'title': + if (! array_key_exists('titleIndex', $metadata)) { + $this->BRfatal("No title page asserted in book"); + } + $imageIndex = $metadata['titleIndex']; + break; + + case 'cover': + if (! array_key_exists('coverIndices', $metadata)) { + $this->BRfatal("No cover asserted in book"); + } + $imageIndex = $metadata['coverIndices'][0]; // $$$ TODO add support for other covers + break; + + case 'preview': + // Preference is: + // Cover page if book was published >= 1950 + // Title page + // Cover page + // Page 0 + + if ( array_key_exists('date', $metadata) && array_key_exists('coverIndices', $metadata) ) { + if ($brm->parseYear($metadata['date']) >= 1950) { + $imageIndex = $metadata['coverIndices'][0]; + break; + } + } + if (array_key_exists('titleIndex', $metadata)) { + $imageIndex = $metadata['titleIndex']; + break; + } + if (array_key_exists('coverIndices', $metadata)) { + $imageIndex = $metadata['coverIndices'][0]; + break; + } + + // First page + $imageIndex = 0; + break; + + case 'n': + // Accessible index page + $imageIndex = intval($pageInfo['value']); + break; + + case 'page': + // Named page + $index = array_search($pageInfo['value'], $metadata['pageNums']); + if ($index === FALSE) { + // Not found + $this->BRfatal("Page not found"); + break; + } + + $imageIndex = $index; + break; + + default: + // Shouldn't be possible + $this->BRfatal("Unrecognized page type requested"); + break; + + } + + $leaf = $brm->leafForIndex($imageIndex, $metadata['leafNums']); + + $requestEnv = array( + 'zip' => $metadata['zip'], + 'file' => $brm->imageFilePath($leaf, $metadata['subPrefix'], $metadata['imageFormat']), + 'ext' => 'jpg', + ); + + // Return image data - will check privs + $this->serveRequest($requestEnv); + + } + + /* + * Returns a page image when all parameters such as the image stack location are + * passed in. + * * Approach: * * Get info about requested image (input) @@ -56,7 +184,6 @@ class BookReaderImages * Return image data * Clean up temporary files */ - function serveRequest($requestEnv) { // Process some of the request parameters $zipPath = $requestEnv['zip']; @@ -79,7 +206,7 @@ class BookReaderImages } if ( !file_exists($zipPath) ) { - $this->BRfatal('Image stack does not exist'); + $this->BRfatal('Image stack does not exist at ' . $zipPath); } // Make sure the image stack is readable - return 403 if not $this->checkPrivs($zipPath); @@ -123,42 +250,31 @@ class BookReaderImages // The pbmreduce reduction factor produces an image with dimension 1/n // The kakadu reduction factor produceds an image with dimension 1/(2^n) - // $$$ handle continuous values for scale if (isset($requestEnv['height'])) { - $ratio = floatval($requestEnv['origHeight']) / floatval($requestEnv['height']); - if ($ratio <= 2) { - $scale = 2; - $powReduce = 1; - } else if ($ratio <= 4) { - $scale = 4; - $powReduce = 2; - } else { - //$powReduce = 3; //too blurry! - $scale = 2; - $powReduce = 1; - } - + $powReduce = $this->nearestPow2Reduce($requestEnv['height'], $imageInfo['height']); + $scale = pow(2, $powReduce); + } else if (isset($requestEnv['width'])) { + $powReduce = $this->nearestPow2Reduce($requestEnv['width'], $imageInfo['width']); + $scale = pow(2, $powReduce); + } else { // $$$ could be cleaner // Provide next smaller power of two reduction - $scale = intval($requestEnv['scale']); - if (1 >= $scale) { - $powReduce = 0; - } else if (2 > $scale) { - $powReduce = 0; - } else if (4 > $scale) { - $powReduce = 1; - } else if (8 > $scale) { - $powReduce = 2; - } else if (16 > $scale) { - $powReduce = 3; - } else if (32 > $scale) { - $powReduce = 4; - } else if (64 > $scale) { - $powReduce = 5; + $scale = $requestEnv['scale']; + if (!$scale) { + $scale = 1; + } + if (array_key_exists($scale, $this->imageSizes)) { + $srcRatio = floatval($imageInfo['width']) / floatval($imageInfo['height']); + if ($srcRatio > 1) { + // wide + $dimension = 'width'; + } else { + $dimension = 'height'; + } + $powReduce = $this->nearestPow2Reduce($this->imageSizes[$scale], $imageInfo[$dimension]); } else { - // $$$ Leaving this in as default though I'm not sure why it is... - $powReduce = 3; + $powReduce = $this->nearestPow2ForScale($scale); } $scale = pow(2, $powReduce); } @@ -184,7 +300,6 @@ class BookReaderImages system('ln -s /dev/stdout ' . $stdoutLink); } - putenv('LD_LIBRARY_PATH=/petabox/sw/lib/kakadu'); $unzipCmd = $this->getUnarchiveCommand($zipPath, $file); @@ -386,7 +501,7 @@ class BookReaderImages $bits = intval($tags["BitDepth"]); break; default: - $this->BRfatal("Unsupported image type"); + $this->BRfatal("Unsupported image type $type for file $file in $zipPath"); break; } @@ -530,8 +645,7 @@ class BookReaderImages } function BRfatal($string) { - echo "alert('$string');\n"; - die(-1); + throw new Exception("Image error: $string"); } // Returns true if using a power node @@ -576,6 +690,105 @@ class BookReaderImages } return $pathParts['filename'] . '.' . $ext; } + + // Returns the nearest power of 2 reduction factor that results in a larger image + function nearestPow2Reduce($desiredDimension, $sourceDimension) { + $ratio = floatval($sourceDimension) / floatval($desiredDimension); + return $this->nearestPow2ForScale($ratio); + } + + // Returns nearest power of 2 reduction factor that results in a larger image + function nearestPow2ForScale($scale) { + $scale = intval($scale); + if ($scale <= 1) { + return 0; + } + $binStr = decbin($scale); // convert to binary string. e.g. 5 -> '101' + return strlen($binStr) - 1; + } + + /* + * Parses a page request like "page5_r2.jpg" or "cover_t.jpg" to corresponding + * page type, size, reduce, and format + */ + function parsePageRequest($pageRequest, $bookPrefix) { + + $pageInfo = array(); + + // Pull off extension + if (preg_match('#(.*)\.([^.]+)$#', $pageRequest, $matches) === 1) { + $pageRequest = $matches[1]; + $extension = $matches[2]; + if ($extension == 'jpeg') { + $extension = 'jpg'; + } + } else { + $extension = 'jpg'; + } + $pageInfo['extension'] = $extension; + + // Split parts out + $parts = explode('_', $pageRequest); + + // Remove book prefix if it was included (historical) + if ($parts[0] == $bookPrefix) { + array_shift($parts); + } + + if (count($parts) === 0) { + $this->BRfatal('No page type specified'); + } + $page = array_shift($parts); + + $pageTypes = array( + 'page' => 'str', + 'n' => 'num', + 'cover' => 'single', + 'preview' => 'single', + 'title' => 'single' + ); + + // Look for known page types + foreach ( $pageTypes as $pageName => $kind ) { + if ( preg_match('#^(' . $pageName . ')(.*)#', $page, $matches) === 1 ) { + $pageInfo['type'] = $matches[1]; + switch ($kind) { + case 'str': + $pageInfo['value'] = $matches[2]; + break; + case 'num': + $pageInfo['value'] = intval($matches[2]); + break; + case 'single': + break; + } + } + } + + if ( !array_key_exists('type', $pageInfo) ) { + $this->BRfatal('Unrecognized page type'); + } + + // Look for other known parts + foreach ($parts as $part) { + $start = substr($part, 0, 1); + + switch ($start) { + case 't': + $pageInfo['size'] = $start; + break; + case 'r': + $pageInfo['reduce'] = substr($part, 0); + break; + default: + // Unrecognized... just let it pass + break; + } + } + + return $pageInfo; + } + } ?> \ No newline at end of file