Merge branch 'leaf_url' into image_region
[bookreader.git] / BookReaderIA / datanode / BookReaderImages.php
index 2895724..fd06508 100644 (file)
@@ -24,368 +24,27 @@ the MIME type is "image/jpeg".
     along with BookReader.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-$MIMES = array('gif' => 'image/gif',
-               'jp2' => 'image/jp2',
-               'jpg' => 'image/jpeg',
-               'jpeg' => 'image/jpeg',
-               'png' => 'image/png',
-               'tif' => 'image/tiff',
-               'tiff' => 'image/tiff');
-               
-$EXTENSIONS = array('gif' => 'gif',
-                    'jp2' => 'jp2',
-                    'jpeg' => 'jpeg',
-                    'jpg' => 'jpeg',
-                    'png' => 'png',
-                    'tif' => 'tiff',
-                    'tiff' => 'tiff');
-               
-$exiftool = '/petabox/sw/books/exiftool/exiftool';
-
-// Process some of the request parameters
-$zipPath  = $_REQUEST['zip'];
-$file     = $_REQUEST['file'];
-if (isset($_REQUEST['ext'])) {
-    $ext = $_REQUEST['ext'];
-} else {
-    // Default to jpg
-    $ext = 'jpeg';
-}
-if (isset($_REQUEST['callback'])) {
-    // validate callback is valid JS identifier (only)
-    $callback = $_REQUEST['callback'];
-    $identifierPatt = '/^[[:alpha:]$_]([[:alnum:]$_])*$/';
-    if (! preg_match($identifierPatt, $callback)) {
-        BRfatal('Invalid callback');
-    }
-} else {
-    $callback = null;
-}
-
-/*
- * Approach:
- * 
- * Get info about requested image (input)
- * Get info about requested output format
- * Determine processing parameters
- * Process image
- * Return image data
- * Clean up temporary files
- */
-function getUnarchiveCommand($archivePath, $file)
-{
-    $lowerPath = strtolower($archivePath);
-    if (preg_match('/\.([^\.]+)$/', $lowerPath, $matches)) {
-        $suffix = $matches[1];
-        
-        if ($suffix == 'zip') {
-            return 'unzip -p '
-                . escapeshellarg($archivePath)
-                . ' ' . escapeshellarg($file);
-        } else if ($suffix == 'tar') {
-            return '7z e -so '
-                . escapeshellarg($archivePath)
-                . ' ' . escapeshellarg($file);
-        } else {
-            BRfatal('Incompatible archive format');
-        }
-
-    } else {
-        BRfatal('Bad image stack path');
-    }
-    
-    BRfatal('Bad image stack path or archive format');
-    
-}
-
-/*
- * Returns the image type associated with the file extension.
- */
-function imageExtensionToType($extension)
-{
-    global $EXTENSIONS;
-    
-    if (array_key_exists($extension, $EXTENSIONS)) {
-        return $EXTENSIONS[$extension];
-    } else {
-        BRfatal('Unknown image extension');
-    }            
-}
-
-/*
- * Get the image width, height and depth from a jp2 file in zip.
- */
-function getImageInfo($zipPath, $file)
-{
-    global $exiftool;
-    
-    $fileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
-    $type = imageExtensionToType($fileExt);
-     
-    // We look for all the possible tags of interest then act on the
-    // ones presumed present based on the file type
-    $tagsToGet = ' -ImageWidth -ImageHeight -FileType'        // all formats
-                 . ' -BitsPerComponent -ColorSpace'          // jp2
-                 . ' -BitDepth'                              // png
-                 . ' -BitsPerSample';                        // tiff
-                        
-    $cmd = getUnarchiveCommand($zipPath, $file)
-        . ' | '. $exiftool . ' -S -fast' . $tagsToGet . ' -';
-    exec($cmd, $output);
-    
-    $tags = Array();
-    foreach ($output as $line) {
-        $keyValue = explode(": ", $line);
-        $tags[$keyValue[0]] = $keyValue[1];
-    }
-    
-    $width = intval($tags["ImageWidth"]);
-    $height = intval($tags["ImageHeight"]);
-    $type = strtolower($tags["FileType"]);
-    
-    switch ($type) {
-        case "jp2":
-            $bits = intval($tags["BitsPerComponent"]);
-            break;
-        case "tiff":
-            $bits = intval($tags["BitsPerSample"]);
-            break;
-        case "jpeg":
-            $bits = 8;
-            break;
-        case "png":
-            $bits = intval($tags["BitDepth"]);
-            break;
-        default:
-            BRfatal("Unsupported image type");
-            break;
-    }
-   
-   
-    $retval = Array('width' => $width, 'height' => $height,
-        'bits' => $bits, 'type' => $type);
-    
-    return $retval;
-}
-
-/*
- * Output JSON given the imageInfo associative array
- */
-function outputJSON($imageInfo, $callback)
-{
-    header('Content-type: text/plain');
-    $jsonOutput = json_encode($imageInfo);
-    if ($callback) {
-        $jsonOutput = $callback . '(' . $jsonOutput . ');';
-    }
-    echo $jsonOutput;
-}
-
-// Get the image size and depth
-$imageInfo = getImageInfo($zipPath, $file);
-
-// Output json if requested
-if ('json' == $ext) {
-    // $$$ we should determine the output size first based on requested scale
-    outputJSON($imageInfo, $callback);
-    exit;
-}
-
-// Unfortunately kakadu requires us to know a priori if the
-// output file should be .ppm or .pgm.  By decompressing to
-// .bmp kakadu will write a file we can consistently turn into
-// .pnm.  Really kakadu should support .pnm as the file output
-// extension and automatically write ppm or pgm format as
-// appropriate.
-$decompressToBmp = true;
-if ($decompressToBmp) {
-  $stdoutLink = '/tmp/stdout.bmp';
-} else {
-  $stdoutLink = '/tmp/stdout.ppm';
-}
-
-$fileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
-
-// Rotate is currently only supported for jp2 since it does not add server load
-$allowedRotations = array("0", "90", "180", "270");
-$rotate = $_REQUEST['rotate'];
-if ( !in_array($rotate, $allowedRotations) ) {
-    $rotate = "0";
-}
-
-// Image conversion options
-$pngOptions = '';
-$jpegOptions = '-quality 75';
-
-// 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($_REQUEST['height'])) {
-    $ratio = floatval($_REQUEST['origHeight']) / floatval($_REQUEST['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;
-    }
-
-} else {
-    $scale = $_REQUEST['scale'];
-    if (1 >= $scale) {
-        $scale = 1;
-        $powReduce = 0;
-    } else if (2 == $scale) {
-        $powReduce = 1;
-    } else if (4 == $scale) {
-        $powReduce = 2;
-    } else if (8 == $scale) {
-        $powReduce = 3;
-    } else if (16 == $scale) {
-        $powReduce = 4;
-    } else if (32 == $scale) {
-        $powReduce = 5;
+// Include BookReaderImages class definition
+require_once('BookReaderImages.inc.php');
+
+// Serve request
+$bri = new BookReaderImages();
+try {
+    if ($_REQUEST['page']) {
+        // Need to lookup metadata
+        $bri->serveLookupRequest($_REQUEST);
     } else {
-        // $$$ Leaving this in as default though I'm not sure why it is...
-        $scale = 8;
-        $powReduce = 3;
+        // Request should be fully qualified - no lookup needed
+        $bri->serveRequest($_REQUEST);
     }
-}
-
-// Override depending on source image format
-// $$$ consider doing a 302 here instead, to make better use of the browser cache
-// Limit scaling for 1-bit images.  See https://bugs.edge.launchpad.net/bookreader/+bug/486011
-if (1 == $imageInfo['bits']) {
-    if ($scale > 1) {
-        $scale /= 2;
-        $powReduce -= 1;
-        
-        // Hard limit so there are some black pixels to use!
-        if ($scale > 4) {
-            $scale = 4;
-            $powReduce = 2;
-        }
-    }
-}
-
-if (!file_exists($stdoutLink)) 
-{  
-  system('ln -s /dev/stdout ' . $stdoutLink);  
-}
-
-
-putenv('LD_LIBRARY_PATH=/petabox/sw/lib/kakadu');
-
-$unzipCmd  = getUnarchiveCommand($zipPath, $file);
-
-switch ($imageInfo['type']) {
-    case 'jp2':
-        $decompressCmd = 
-            " | /petabox/sw/bin/kdu_expand -no_seek -quiet -reduce $powReduce -rotate $rotate -i /dev/stdin -o " . $stdoutLink;
-        if ($decompressToBmp) {
-            $decompressCmd .= ' | bmptopnm ';
-        }
-        break;
-
-    case 'tiff':
-        // We need to create a temporary file for tifftopnm since it cannot
-        // work on a pipe (the file must be seekable).
-        // We use the BookReaderTiff prefix to give a hint in case things don't
-        // get cleaned up.
-        $tempFile = tempnam("/tmp", "BookReaderTiff");
+} catch (Exception $e) {
+    header("HTTP/1.0 404 Not Found");
+    header("Content-type: text/plain");
     
-        // $$$ look at bit depth when reducing
-        $decompressCmd = 
-            ' > ' . $tempFile . ' ; tifftopnm ' . $tempFile . ' 2>/dev/null' . reduceCommand($scale);
-        break;
-    case 'jpeg':
-        $decompressCmd = ' | jpegtopnm ' . reduceCommand($scale);
-        break;
-
-    case 'png':
-        $decompressCmd = ' | pngtopnm ' . reduceCommand($scale);
-        break;
-        
-    default:
-        BRfatal('Unknown source file extension: ' . $fileExt);
-        break;
-}
-       
-// Non-integer scaling is currently disabled on the cluster
-// if (isset($_REQUEST['height'])) {
-//     $cmd .= " | pnmscale -height {$_REQUEST['height']} ";
-// }
-
-switch ($ext) {
-    case 'png':
-        $compressCmd = ' | pnmtopng ' . $pngOptions;
-        break;
-        
-    case 'jpeg':
-    case 'jpg':
-    default:
-        $compressCmd = ' | pnmtojpeg ' . $jpegOptions;
-        $ext = 'jpeg'; // for matching below
-        break;
-
+    print "Error serving request:\n";
+    print "  " . $e->getMessage() . "\n\n";
+    print "Debugging information:\n";
+    echo $e->getTraceAsString();
 }
 
-if (($ext == $fileExt) && ($scale == 1) && ($rotate === "0")) {
-    // Just pass through original data if same format and size
-    $cmd = $unzipCmd;
-} else {
-    $cmd = $unzipCmd . $decompressCmd . $compressCmd;
-}
-
-# print $cmd;
-
-
-// $$$ investigate how to flush cache when this file is changed
-header('Content-type: ' . $MIMES[$ext]);
-header('Cache-Control: max-age=15552000');
-passthru ($cmd); # cmd returns image data
-
-if (isset($tempFile)) {
-    unlink($tempFile);
-}
-
-function BRFatal($string) {
-    echo "alert('$string');\n";
-    die(-1);
-}
-
-// Returns true if using a power node
-function onPowerNode() {
-    exec("lspci | fgrep -c Realtek", $output, $return);
-    if ("0" != $output[0]) {
-        return true;
-    } else {
-        exec("egrep -q AMD /proc/cpuinfo", $output, $return);
-        if ($return == 0) {
-            return true;
-        }
-    }
-    return false;
-}
-
-function reduceCommand($scale) {
-    if (1 != $scale) {
-        if (onPowerNode()) {
-            return ' | pnmscale -reduce ' . $scale;
-        } else {
-            return ' | pnmscale -nomix -reduce ' . $scale;
-        }
-    } else {
-        return '';
-    }
-}
-
-
-?>
-
+?>
\ No newline at end of file