MediaWiki  REL1_22
DjVu.php
Go to the documentation of this file.
00001 <?php
00029 class DjVuHandler extends ImageHandler {
00030 
00034     function isEnabled() {
00035         global $wgDjvuRenderer, $wgDjvuDump, $wgDjvuToXML;
00036         if ( !$wgDjvuRenderer || ( !$wgDjvuDump && !$wgDjvuToXML ) ) {
00037             wfDebug( "DjVu is disabled, please set \$wgDjvuRenderer and \$wgDjvuDump\n" );
00038             return false;
00039         } else {
00040             return true;
00041         }
00042     }
00043 
00048     function mustRender( $file ) {
00049         return true;
00050     }
00051 
00056     function isMultiPage( $file ) {
00057         return true;
00058     }
00059 
00063     function getParamMap() {
00064         return array(
00065             'img_width' => 'width',
00066             'img_page' => 'page',
00067         );
00068     }
00069 
00075     function validateParam( $name, $value ) {
00076         if ( in_array( $name, array( 'width', 'height', 'page' ) ) ) {
00077             if ( $value <= 0 ) {
00078                 return false;
00079             } else {
00080                 return true;
00081             }
00082         } else {
00083             return false;
00084         }
00085     }
00086 
00091     function makeParamString( $params ) {
00092         $page = isset( $params['page'] ) ? $params['page'] : 1;
00093         if ( !isset( $params['width'] ) ) {
00094             return false;
00095         }
00096         return "page{$page}-{$params['width']}px";
00097     }
00098 
00103     function parseParamString( $str ) {
00104         $m = false;
00105         if ( preg_match( '/^page(\d+)-(\d+)px$/', $str, $m ) ) {
00106             return array( 'width' => $m[2], 'page' => $m[1] );
00107         } else {
00108             return false;
00109         }
00110     }
00111 
00116     function getScriptParams( $params ) {
00117         return array(
00118             'width' => $params['width'],
00119             'page' => $params['page'],
00120         );
00121     }
00122 
00131     function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
00132         global $wgDjvuRenderer, $wgDjvuPostProcessor;
00133 
00134         // Fetch XML and check it, to give a more informative error message than the one which
00135         // normaliseParams will inevitably give.
00136         $xml = $image->getMetadata();
00137         if ( !$xml ) {
00138             $width = isset( $params['width'] ) ? $params['width'] : 0;
00139             $height = isset( $params['height'] ) ? $params['height'] : 0;
00140             return new MediaTransformError( 'thumbnail_error', $width, $height,
00141                 wfMessage( 'djvu_no_xml' )->text() );
00142         }
00143 
00144         if ( !$this->normaliseParams( $image, $params ) ) {
00145             return new TransformParameterError( $params );
00146         }
00147         $width = $params['width'];
00148         $height = $params['height'];
00149         $page = $params['page'];
00150         if ( $page > $this->pageCount( $image ) ) {
00151             return new MediaTransformError(
00152                 'thumbnail_error',
00153                 $width,
00154                 $height,
00155                 wfMessage( 'djvu_page_error' )->text()
00156             );
00157         }
00158 
00159         if ( $flags & self::TRANSFORM_LATER ) {
00160             $params = array(
00161                 'width' => $width,
00162                 'height' => $height,
00163                 'page' => $page
00164             );
00165             return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
00166         }
00167 
00168         if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
00169             return new MediaTransformError(
00170                 'thumbnail_error',
00171                 $width,
00172                 $height,
00173                 wfMessage( 'thumbnail_dest_directory' )->text()
00174             );
00175         }
00176 
00177         $srcPath = $image->getLocalRefPath();
00178         # Use a subshell (brackets) to aggregate stderr from both pipeline commands
00179         # before redirecting it to the overall stdout. This works in both Linux and Windows XP.
00180         $cmd = '(' . wfEscapeShellArg(
00181             $wgDjvuRenderer,
00182             "-format=ppm",
00183             "-page={$page}",
00184             "-size={$params['physicalWidth']}x{$params['physicalHeight']}",
00185             $srcPath );
00186         if ( $wgDjvuPostProcessor ) {
00187             $cmd .= " | {$wgDjvuPostProcessor}";
00188         }
00189         $cmd .= ' > ' . wfEscapeShellArg( $dstPath ) . ') 2>&1';
00190         wfProfileIn( 'ddjvu' );
00191         wfDebug( __METHOD__ . ": $cmd\n" );
00192         $retval = '';
00193         $err = wfShellExec( $cmd, $retval );
00194         wfProfileOut( 'ddjvu' );
00195 
00196         $removed = $this->removeBadFile( $dstPath, $retval );
00197         if ( $retval != 0 || $removed ) {
00198             wfDebugLog( 'thumbnail',
00199                 sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
00200                     wfHostname(), $retval, trim( $err ), $cmd ) );
00201             return new MediaTransformError( 'thumbnail_error', $width, $height, $err );
00202         } else {
00203             $params = array(
00204                 'width' => $width,
00205                 'height' => $height,
00206                 'page' => $page
00207             );
00208             return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
00209         }
00210     }
00211 
00217     function getDjVuImage( $image, $path ) {
00218         if ( !$image ) {
00219             $deja = new DjVuImage( $path );
00220         } elseif ( !isset( $image->dejaImage ) ) {
00221             $deja = $image->dejaImage = new DjVuImage( $path );
00222         } else {
00223             $deja = $image->dejaImage;
00224         }
00225         return $deja;
00226     }
00227 
00234     function getMetaTree( $image, $gettext = false ) {
00235         if ( isset( $image->dejaMetaTree ) ) {
00236             return $image->dejaMetaTree;
00237         }
00238 
00239         $metadata = $image->getMetadata();
00240         if ( !$this->isMetadataValid( $image, $metadata ) ) {
00241             wfDebug( "DjVu XML metadata is invalid or missing, should have been fixed in upgradeRow\n" );
00242             return false;
00243         }
00244         wfProfileIn( __METHOD__ );
00245 
00246         wfSuppressWarnings();
00247         try {
00248             // Set to false rather than null to avoid further attempts
00249             $image->dejaMetaTree = false;
00250             $image->djvuTextTree = false;
00251             $tree = new SimpleXMLElement( $metadata );
00252             if ( $tree->getName() == 'mw-djvu' ) {
00253                 foreach ( $tree->children() as $b ) {
00254                     if ( $b->getName() == 'DjVuTxt' ) {
00255                         $image->djvuTextTree = $b;
00256                     } elseif ( $b->getName() == 'DjVuXML' ) {
00257                         $image->dejaMetaTree = $b;
00258                     }
00259                 }
00260             } else {
00261                 $image->dejaMetaTree = $tree;
00262             }
00263         } catch ( Exception $e ) {
00264             wfDebug( "Bogus multipage XML metadata on '{$image->getName()}'\n" );
00265         }
00266         wfRestoreWarnings();
00267         wfProfileOut( __METHOD__ );
00268         if ( $gettext ) {
00269             return $image->djvuTextTree;
00270         } else {
00271             return $image->dejaMetaTree;
00272         }
00273     }
00274 
00275     function getImageSize( $image, $path ) {
00276         return $this->getDjVuImage( $image, $path )->getImageSize();
00277     }
00278 
00279     function getThumbType( $ext, $mime, $params = null ) {
00280         global $wgDjvuOutputExtension;
00281         static $mime;
00282         if ( !isset( $mime ) ) {
00283             $magic = MimeMagic::singleton();
00284             $mime = $magic->guessTypesForExtension( $wgDjvuOutputExtension );
00285         }
00286         return array( $wgDjvuOutputExtension, $mime );
00287     }
00288 
00289     function getMetadata( $image, $path ) {
00290         wfDebug( "Getting DjVu metadata for $path\n" );
00291         return $this->getDjVuImage( $image, $path )->retrieveMetaData();
00292     }
00293 
00294     function getMetadataType( $image ) {
00295         return 'djvuxml';
00296     }
00297 
00298     function isMetadataValid( $image, $metadata ) {
00299         return !empty( $metadata ) && $metadata != serialize( array() );
00300     }
00301 
00302     function pageCount( $image ) {
00303         $tree = $this->getMetaTree( $image );
00304         if ( !$tree ) {
00305             return false;
00306         }
00307         return count( $tree->xpath( '//OBJECT' ) );
00308     }
00309 
00310     function getPageDimensions( $image, $page ) {
00311         $tree = $this->getMetaTree( $image );
00312         if ( !$tree ) {
00313             return false;
00314         }
00315 
00316         $o = $tree->BODY[0]->OBJECT[$page - 1];
00317         if ( $o ) {
00318             return array(
00319                 'width' => intval( $o['width'] ),
00320                 'height' => intval( $o['height'] )
00321             );
00322         } else {
00323             return false;
00324         }
00325     }
00326 
00327     function getPageText( $image, $page ) {
00328         $tree = $this->getMetaTree( $image, true );
00329         if ( !$tree ) {
00330             return false;
00331         }
00332 
00333         $o = $tree->BODY[0]->PAGE[$page - 1];
00334         if ( $o ) {
00335             $txt = $o['value'];
00336             return $txt;
00337         } else {
00338             return false;
00339         }
00340 
00341     }
00342 
00343 }