| Index: trunk/phase3/skins/monobook/main.css |
| — | — | @@ -1444,3 +1444,24 @@ |
| 1445 | 1445 | content: "\00BB \0020"; |
| 1446 | 1446 | } |
| 1447 | 1447 | |
| | 1448 | +div.multipageimagenavbox { |
| | 1449 | + border: solid 1px silver; |
| | 1450 | + padding: 4px; |
| | 1451 | + margin: 1em; |
| | 1452 | + -moz-border-radius: 6px; |
| | 1453 | + background: #f0f0f0; |
| | 1454 | +} |
| | 1455 | + |
| | 1456 | +div.multipageimagenavbox div.thumb { |
| | 1457 | + border: none; |
| | 1458 | + margin-left: 2em; |
| | 1459 | + margin-right: 2em; |
| | 1460 | +} |
| | 1461 | + |
| | 1462 | +div.multipageimagenavbox hr { |
| | 1463 | + margin: 6px; |
| | 1464 | +} |
| | 1465 | + |
| | 1466 | +table.multipageimage td { |
| | 1467 | + text-align: center; |
| | 1468 | +} |
| Index: trunk/phase3/skins/common/common.css |
| — | — | @@ -383,4 +383,26 @@ |
| 384 | 384 | table.gallery td.galleryheader { |
| 385 | 385 | text-align: center; |
| 386 | 386 | font-weight: bold; |
| 387 | | -} |
| \ No newline at end of file |
| | 387 | +} |
| | 388 | + |
| | 389 | +div.multipageimagenavbox { |
| | 390 | + border: solid 1px silver; |
| | 391 | + padding: 4px; |
| | 392 | + margin: 1em; |
| | 393 | + -moz-border-radius: 6px; |
| | 394 | + background: #f0f0f0; |
| | 395 | +} |
| | 396 | + |
| | 397 | +div.multipageimagenavbox div.thumb { |
| | 398 | + border: none; |
| | 399 | + margin-left: 2em; |
| | 400 | + margin-right: 2em; |
| | 401 | +} |
| | 402 | + |
| | 403 | +div.multipageimagenavbox hr { |
| | 404 | + margin: 6px; |
| | 405 | +} |
| | 406 | + |
| | 407 | +table.multipageimage td { |
| | 408 | + text-align: center; |
| | 409 | +} |
| Index: trunk/phase3/thumb.php |
| — | — | @@ -17,13 +17,20 @@ |
| 18 | 18 | require_once( 'StreamFile.php' ); |
| 19 | 19 | |
| 20 | 20 | // Get input parameters |
| | 21 | +$p=null; |
| 21 | 22 | |
| 22 | 23 | if ( get_magic_quotes_gpc() ) { |
| 23 | 24 | $fileName = stripslashes( $_REQUEST['f'] ); |
| 24 | 25 | $width = stripslashes( $_REQUEST['w'] ); |
| | 26 | + if ( isset( $_REQUEST['p'] ) ) { // optional page number |
| | 27 | + $page = stripslashes( $_REQUEST['p'] ); |
| | 28 | + } |
| 25 | 29 | } else { |
| 26 | 30 | $fileName = $_REQUEST['f']; |
| 27 | 31 | $width = $_REQUEST['w']; |
| | 32 | + if ( isset( $_REQUEST['p'] ) ) { // optional page number |
| | 33 | + $page = $_REQUEST['p'] ; |
| | 34 | + } |
| 28 | 35 | } |
| 29 | 36 | |
| 30 | 37 | $pre_render= isset($_REQUEST['r']) && $_REQUEST['r']!="0"; |
| — | — | @@ -31,12 +38,18 @@ |
| 32 | 39 | // Some basic input validation |
| 33 | 40 | |
| 34 | 41 | $width = intval( $width ); |
| | 42 | +if ( ! is_null( $page ) ) { |
| | 43 | + $page = intval( $page ); |
| | 44 | +} |
| 35 | 45 | $fileName = strtr( $fileName, '\\/', '__' ); |
| 36 | 46 | |
| 37 | 47 | // Work out paths, carefully avoiding constructing an Image object because that won't work yet |
| 38 | 48 | |
| 39 | 49 | $imagePath = wfImageDir( $fileName ) . '/' . $fileName; |
| 40 | 50 | $thumbName = "{$width}px-$fileName"; |
| | 51 | +if ( ! is_null( $page ) ) { |
| | 52 | + $thumbName = 'page' . $page . '-' . $thumbName; |
| | 53 | +} |
| 41 | 54 | if ( $pre_render ) { |
| 42 | 55 | $thumbName .= '.png'; |
| 43 | 56 | } |
| — | — | @@ -55,6 +68,9 @@ |
| 56 | 69 | |
| 57 | 70 | $img = Image::newFromName( $fileName ); |
| 58 | 71 | if ( $img ) { |
| | 72 | + if ( ! is_null( $page ) ) { |
| | 73 | + $img->selectPage( $page ); |
| | 74 | + } |
| 59 | 75 | $thumb = $img->renderThumb( $width, false ); |
| 60 | 76 | } else { |
| 61 | 77 | $thumb = false; |
| Index: trunk/phase3/includes/MimeMagic.php |
| — | — | @@ -504,6 +504,15 @@ |
| 505 | 505 | # see http://www.php.net/manual/en/ref.mime-magic.php for details. |
| 506 | 506 | |
| 507 | 507 | $m= mime_content_type($file); |
| | 508 | + |
| | 509 | + if ( $m == 'text/plain' ) { |
| | 510 | + // mime_content_type sometimes considers DJVU files to be text/plain. |
| | 511 | + $deja = new DjVuImage( $file ); |
| | 512 | + if( $deja->isValid() ) { |
| | 513 | + wfDebug("$fname: (re)detected $file as image/vnd.djvu\n"); |
| | 514 | + $m = 'image/vnd.djvu'; |
| | 515 | + } |
| | 516 | + } |
| 508 | 517 | } |
| 509 | 518 | else wfDebug("$fname: no magic mime detector found!\n"); |
| 510 | 519 | |
| Index: trunk/phase3/includes/ImagePage.php |
| — | — | @@ -187,6 +187,12 @@ |
| 188 | 188 | |
| 189 | 189 | if ( $this->img->exists() ) { |
| 190 | 190 | # image |
| | 191 | + $page = $wgRequest->getIntOrNull( 'page' ); |
| | 192 | + if ( ! is_null( $page ) ) { |
| | 193 | + $this->img->selectPage( $page ); |
| | 194 | + } else { |
| | 195 | + $page = 1; |
| | 196 | + } |
| 191 | 197 | $width = $this->img->getWidth(); |
| 192 | 198 | $height = $this->img->getHeight(); |
| 193 | 199 | $showLink = false; |
| — | — | @@ -236,9 +242,53 @@ |
| 237 | 243 | $url = $this->img->getViewURL(); |
| 238 | 244 | $showLink = true; |
| 239 | 245 | } |
| | 246 | + |
| | 247 | + if ( $this->img->isMultipage() ) { |
| | 248 | + $wgOut->addHTML( '<table class="multipageimage"><tr><td>' ); |
| | 249 | + } |
| | 250 | + |
| 240 | 251 | $wgOut->addHTML( '<div class="fullImageLink" id="file">' . $anchoropen . |
| 241 | 252 | "<img border=\"0\" src=\"{$url}\" width=\"{$width}\" height=\"{$height}\" alt=\"" . |
| 242 | 253 | htmlspecialchars( $wgRequest->getVal( 'image' ) ).'" />' . $anchorclose . '</div>' ); |
| | 254 | + |
| | 255 | + if ( $this->img->isMultipage() ) { |
| | 256 | + $count = $this->img->pageCount(); |
| | 257 | + |
| | 258 | + if ( $page > 1 ) { |
| | 259 | + $label = $wgOut->parse( wfMsg( 'imgmultipageprev' ), false ); |
| | 260 | + $link = $sk->makeLinkObj( $this->mTitle, $label, 'page='. ($page-1) ); |
| | 261 | + $this->img->selectPage( $page - 1 ); |
| | 262 | + $thumb1 = $sk->makeThumbLinkObj( $this->img, $link, $label, 'none' ); |
| | 263 | + } else { |
| | 264 | + $thumb1 = ''; |
| | 265 | + } |
| | 266 | + |
| | 267 | + if ( $page < $count ) { |
| | 268 | + $label = wfMsg( 'imgmultipagenext' ); |
| | 269 | + $this->img->selectPage( $page + 1 ); |
| | 270 | + $link = $sk->makeLinkObj( $this->mTitle, $label, 'page='. ($page+1) ); |
| | 271 | + $thumb2 = $sk->makeThumbLinkObj( $this->img, $link, $label, 'none' ); |
| | 272 | + } else { |
| | 273 | + $thumb2 = ''; |
| | 274 | + } |
| | 275 | + |
| | 276 | + $select = '<form name="pageselector" action="' . $this->img->getEscapeLocalUrl( '' ) . '" method="GET" onchange="document.pageselector.submit();">' ; |
| | 277 | + $select .= $wgOut->parse( wfMsg( 'imgmultigotopre' ), false ) . |
| | 278 | + ' <select id="pageselector" name="page">'; |
| | 279 | + for ( $i=1; $i <= $count; $i++ ) { |
| | 280 | + if ( $i == $page ) { |
| | 281 | + $select .= "<option value=\"$i\" selected=\"selected\">$i</option>"; |
| | 282 | + } else { |
| | 283 | + $select .= "<option value=\"$i\" >$i</option>\n"; |
| | 284 | + } |
| | 285 | + } |
| | 286 | + $select .= '</select>' . $wgOut->parse( wfMsg( 'imgmultigotopost' ), false ) . |
| | 287 | + '<input type="submit" value="' . |
| | 288 | + htmlspecialchars( wfMsg( 'imgmultigo' ) ) . '"></form>'; |
| | 289 | + |
| | 290 | + $wgOut->addHTML( '</td><td><div class="multipageimagenavbox">' . |
| | 291 | + "$select<hr />$thumb1\n$thumb2<br clear=\"all\" /></div></td></tr></table>" ); |
| | 292 | + } |
| 243 | 293 | } else { |
| 244 | 294 | #if direct link is allowed but it's not a renderable image, show an icon. |
| 245 | 295 | if ($this->img->isSafeFile()) { |
| Index: trunk/phase3/includes/Linker.php |
| — | — | @@ -456,11 +456,16 @@ |
| 457 | 457 | |
| 458 | 458 | /** @todo document */ |
| 459 | 459 | function makeImageLinkObj( $nt, $label, $alt, $align = '', $width = false, $height = false, $framed = false, |
| 460 | | - $thumb = false, $manual_thumb = '' ) |
| | 460 | + $thumb = false, $manual_thumb = '', $page = null ) |
| 461 | 461 | { |
| 462 | 462 | global $wgContLang, $wgUser, $wgThumbLimits, $wgGenerateThumbnailOnParse; |
| 463 | 463 | |
| 464 | 464 | $img = new Image( $nt ); |
| | 465 | + |
| | 466 | + if ( ! is_null( $page ) ) { |
| | 467 | + $img->selectPage( $page ); |
| | 468 | + } |
| | 469 | + |
| 465 | 470 | if ( !$img->allowInlineDisplay() && $img->exists() ) { |
| 466 | 471 | return $this->makeKnownLinkObj( $nt ); |
| 467 | 472 | } |
| — | — | @@ -468,7 +473,7 @@ |
| 469 | 474 | $url = $img->getViewURL(); |
| 470 | 475 | $error = $prefix = $postfix = ''; |
| 471 | 476 | |
| 472 | | - wfDebug( "makeImageLinkObj: '$width'x'$height'\n" ); |
| | 477 | + wfDebug( "makeImageLinkObj: '$width'x'$height', \"$label\"\n" ); |
| 473 | 478 | |
| 474 | 479 | if ( 'center' == $align ) |
| 475 | 480 | { |
| — | — | @@ -564,7 +569,6 @@ |
| 565 | 570 | */ |
| 566 | 571 | function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) { |
| 567 | 572 | global $wgStylePath, $wgContLang, $wgGenerateThumbnailOnParse; |
| 568 | | - $url = $img->getViewURL(); |
| 569 | 573 | $thumbUrl = ''; |
| 570 | 574 | $error = ''; |
| 571 | 575 | |
| — | — | @@ -583,7 +587,7 @@ |
| 584 | 588 | // Use image dimensions, don't scale |
| 585 | 589 | $boxwidth = $width; |
| 586 | 590 | $boxheight = $height; |
| 587 | | - $thumbUrl = $url; |
| | 591 | + $thumbUrl = $img->getViewURL(); |
| 588 | 592 | } else { |
| 589 | 593 | if ( $boxheight === false ) |
| 590 | 594 | $boxheight = -1; |
| — | — | @@ -626,7 +630,7 @@ |
| 627 | 631 | $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">"; |
| 628 | 632 | if( $thumbUrl == '' ) { |
| 629 | 633 | // Couldn't generate thumbnail? Scale the image client-side. |
| 630 | | - $thumbUrl = $url; |
| | 634 | + $thumbUrl = $img->getViewURL(); |
| 631 | 635 | } |
| 632 | 636 | if ( $error ) { |
| 633 | 637 | $s .= htmlspecialchars( $error ); |
| Index: trunk/phase3/includes/Parser.php |
| — | — | @@ -4086,9 +4086,11 @@ |
| 4087 | 4087 | $mwWidth =& MagicWord::get( 'img_width' ); |
| 4088 | 4088 | $mwCenter =& MagicWord::get( 'img_center' ); |
| 4089 | 4089 | $mwFramed =& MagicWord::get( 'img_framed' ); |
| | 4090 | + $mwPage =& MagicWord::get( 'img_page' ); |
| 4090 | 4091 | $caption = ''; |
| 4091 | 4092 | |
| 4092 | 4093 | $width = $height = $framed = $thumb = false; |
| | 4094 | + $page = null; |
| 4093 | 4095 | $manual_thumb = '' ; |
| 4094 | 4096 | |
| 4095 | 4097 | foreach( $part as $key => $val ) { |
| — | — | @@ -4098,6 +4100,9 @@ |
| 4099 | 4101 | # use manually specified thumbnail |
| 4100 | 4102 | $thumb=true; |
| 4101 | 4103 | $manual_thumb = $match; |
| | 4104 | + } elseif ( ! is_null( $match = $mwPage->matchVariableStartToEnd($val) ) ) { |
| | 4105 | + # Select a page in a multipage document |
| | 4106 | + $page = $match; |
| 4102 | 4107 | } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) { |
| 4103 | 4108 | # remember to set an alignment, don't render immediately |
| 4104 | 4109 | $align = 'right'; |
| — | — | @@ -4136,7 +4141,8 @@ |
| 4137 | 4142 | |
| 4138 | 4143 | # Linker does the rest |
| 4139 | 4144 | $sk =& $this->mOptions->getSkin(); |
| 4140 | | - return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb ); |
| | 4145 | + return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, |
| | 4146 | + $framed, $thumb, $manual_thumb, $page ); |
| 4141 | 4147 | } |
| 4142 | 4148 | |
| 4143 | 4149 | /** |
| Index: trunk/phase3/includes/Image.php |
| — | — | @@ -46,6 +46,7 @@ |
| 47 | 47 | $size, # Size in bytes (loadFromXxx) |
| 48 | 48 | $metadata, # Metadata |
| 49 | 49 | $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) |
| | 50 | + $page, # Page to render when creating thumbnails |
| 50 | 51 | $lastError; # Error string associated with a thumbnail display error |
| 51 | 52 | |
| 52 | 53 | |
| — | — | @@ -86,6 +87,7 @@ |
| 87 | 88 | $this->extension = Image::normalizeExtension( $n ? |
| 88 | 89 | substr( $this->name, $n + 1 ) : '' ); |
| 89 | 90 | $this->historyLine = 0; |
| | 91 | + $this->page = 1; |
| 90 | 92 | |
| 91 | 93 | $this->dataLoaded = false; |
| 92 | 94 | } |
| — | — | @@ -307,7 +309,11 @@ |
| 308 | 310 | $this->dataLoaded = true; |
| 309 | 311 | |
| 310 | 312 | |
| 311 | | - $this->metadata = serialize( $this->retrieveExifData( $this->imagePath ) ); |
| | 313 | + if ( $this->mime == 'image/vnd.djvu' ) { |
| | 314 | + $this->metadata = $deja->retrieveMetaData(); |
| | 315 | + } else { |
| | 316 | + $this->metadata = serialize( $this->retrieveExifData( $this->imagePath ) ); |
| | 317 | + } |
| 312 | 318 | |
| 313 | 319 | if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits']; |
| 314 | 320 | else $this->bits = 0; |
| — | — | @@ -323,7 +329,6 @@ |
| 324 | 330 | wfProfileIn( __METHOD__ ); |
| 325 | 331 | |
| 326 | 332 | $dbr =& wfGetDB( DB_SLAVE ); |
| 327 | | - |
| 328 | 333 | $this->checkDBSchema($dbr); |
| 329 | 334 | |
| 330 | 335 | $row = $dbr->selectRow( 'image', |
| — | — | @@ -605,7 +610,7 @@ |
| 606 | 611 | * @todo remember the result of this check. |
| 607 | 612 | */ |
| 608 | 613 | function canRender() { |
| 609 | | - global $wgUseImageMagick; |
| | 614 | + global $wgUseImageMagick, $wgDjvuRenderer; |
| 610 | 615 | |
| 611 | 616 | if( $this->getWidth()<=0 || $this->getHeight()<=0 ) return false; |
| 612 | 617 | |
| — | — | @@ -651,6 +656,7 @@ |
| 652 | 657 | if ( $mime === 'image/vnd.wap.wbmp' |
| 653 | 658 | || $mime === 'image/x-xbitmap' ) return true; |
| 654 | 659 | } |
| | 660 | + if ( $mime === 'image/vnd.djvu' && isset( $wgDjvuRenderer ) && $wgDjvuRenderer ) return true; |
| 655 | 661 | |
| 656 | 662 | return false; |
| 657 | 663 | } |
| — | — | @@ -738,9 +744,16 @@ |
| 739 | 745 | * Return the escapeLocalURL of this image |
| 740 | 746 | * @public |
| 741 | 747 | */ |
| 742 | | - function getEscapeLocalURL() { |
| | 748 | + function getEscapeLocalURL( $query=false) { |
| 743 | 749 | $this->getTitle(); |
| 744 | | - return $this->title->escapeLocalURL(); |
| | 750 | + if ( $query === false ) { |
| | 751 | + if ( $this->page != 1 ) { |
| | 752 | + $query = 'page=' . $this->page; |
| | 753 | + } else { |
| | 754 | + $query = ''; |
| | 755 | + } |
| | 756 | + } |
| | 757 | + return $this->title->escapeLocalURL( $query ); |
| 745 | 758 | } |
| 746 | 759 | |
| 747 | 760 | /** |
| — | — | @@ -840,6 +853,9 @@ |
| 841 | 854 | */ |
| 842 | 855 | function thumbName( $width ) { |
| 843 | 856 | $thumb = $width."px-".$this->name; |
| | 857 | + if ( $this->page != 1 ) { |
| | 858 | + $thumb = "page{$this->page}-$thumb"; |
| | 859 | + } |
| 844 | 860 | |
| 845 | 861 | if( $this->mustRender() ) { |
| 846 | 862 | if( $this->canRender() ) { |
| — | — | @@ -1127,6 +1143,7 @@ |
| 1128 | 1144 | global $wgSVGConverters, $wgSVGConverter; |
| 1129 | 1145 | global $wgUseImageMagick, $wgImageMagickConvertCommand; |
| 1130 | 1146 | global $wgCustomConvertCommand; |
| | 1147 | + global $wgDjvuRenderer, $wgDjvuPostProcessor; |
| 1131 | 1148 | |
| 1132 | 1149 | $this->load(); |
| 1133 | 1150 | |
| — | — | @@ -1153,96 +1170,112 @@ |
| 1154 | 1171 | $err = wfShellExec( $cmd, $retval ); |
| 1155 | 1172 | wfProfileOut( 'rsvg' ); |
| 1156 | 1173 | } |
| 1157 | | - } elseif ( $wgUseImageMagick ) { |
| 1158 | | - # use ImageMagick |
| 1159 | | - |
| 1160 | | - if ( $this->mime == 'image/jpeg' ) { |
| 1161 | | - $quality = "-quality 80"; // 80% |
| 1162 | | - } elseif ( $this->mime == 'image/png' ) { |
| 1163 | | - $quality = "-quality 95"; // zlib 9, adaptive filtering |
| 1164 | | - } else { |
| 1165 | | - $quality = ''; // default |
| 1166 | | - } |
| | 1174 | + } else { |
| | 1175 | + if ( $this->mime === "image/vnd.djvu" && $wgDjvuRenderer ) { |
| | 1176 | + // DJVU image |
| | 1177 | + // The file contains several images. First, extract the |
| | 1178 | + // page in hi-res, if it doesn't yet exist. Then, thumbnail |
| | 1179 | + // it. |
| 1167 | 1180 | |
| 1168 | | - # Specify white background color, will be used for transparent images |
| 1169 | | - # in Internet Explorer/Windows instead of default black. |
| | 1181 | + $cmd = "{$wgDjvuRenderer} -page={$this->page} -size=${width}x${height} " . |
| | 1182 | + wfEscapeShellArg( $this->imagePath ) . |
| | 1183 | + " | {$wgDjvuPostProcessor} > " . wfEscapeShellArg($thumbPath); |
| | 1184 | + wfProfileIn( 'ddjvu' ); |
| | 1185 | + wfDebug( "reallyRenderThumb DJVU: $cmd\n" ); |
| | 1186 | + $err = wfShellExec( $cmd, $retval ); |
| | 1187 | + wfProfileOut( 'ddjvu' ); |
| 1170 | 1188 | |
| 1171 | | - # Note, we specify "-size {$width}" and NOT "-size {$width}x{$height}". |
| 1172 | | - # It seems that ImageMagick has a bug wherein it produces thumbnails of |
| 1173 | | - # the wrong size in the second case. |
| | 1189 | + } elseif ( $wgUseImageMagick ) { |
| | 1190 | + # use ImageMagick |
| 1174 | 1191 | |
| 1175 | | - $cmd = wfEscapeShellArg($wgImageMagickConvertCommand) . |
| 1176 | | - " {$quality} -background white -size {$width} ". |
| 1177 | | - wfEscapeShellArg($this->imagePath) . |
| 1178 | | - // Coalesce is needed to scale animated GIFs properly (bug 1017). |
| 1179 | | - ' -coalesce ' . |
| 1180 | | - // For the -resize option a "!" is needed to force exact size, |
| 1181 | | - // or ImageMagick may decide your ratio is wrong and slice off |
| 1182 | | - // a pixel. |
| 1183 | | - " -resize " . wfEscapeShellArg( "{$width}x{$height}!" ) . |
| 1184 | | - " -depth 8 " . |
| 1185 | | - wfEscapeShellArg($thumbPath) . " 2>&1"; |
| 1186 | | - wfDebug("reallyRenderThumb: running ImageMagick: $cmd\n"); |
| 1187 | | - wfProfileIn( 'convert' ); |
| 1188 | | - $err = wfShellExec( $cmd, $retval ); |
| 1189 | | - wfProfileOut( 'convert' ); |
| 1190 | | - } elseif( $wgCustomConvertCommand ) { |
| 1191 | | - # Use a custom convert command |
| 1192 | | - # Variables: %s %d %w %h |
| 1193 | | - $src = wfEscapeShellArg( $this->imagePath ); |
| 1194 | | - $dst = wfEscapeShellArg( $thumbPath ); |
| 1195 | | - $cmd = $wgCustomConvertCommand; |
| 1196 | | - $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames |
| 1197 | | - $cmd = str_replace( '%h', $height, str_replace( '%w', $width, $cmd ) ); # Size |
| 1198 | | - wfDebug( "reallyRenderThumb: Running custom convert command $cmd\n" ); |
| 1199 | | - wfProfileIn( 'convert' ); |
| 1200 | | - $err = wfShellExec( $cmd, $retval ); |
| 1201 | | - wfProfileOut( 'convert' ); |
| 1202 | | - } else { |
| 1203 | | - # Use PHP's builtin GD library functions. |
| 1204 | | - # |
| 1205 | | - # First find out what kind of file this is, and select the correct |
| 1206 | | - # input routine for this. |
| | 1192 | + if ( $this->mime == 'image/jpeg' ) { |
| | 1193 | + $quality = "-quality 80"; // 80% |
| | 1194 | + } elseif ( $this->mime == 'image/png' ) { |
| | 1195 | + $quality = "-quality 95"; // zlib 9, adaptive filtering |
| | 1196 | + } else { |
| | 1197 | + $quality = ''; // default |
| | 1198 | + } |
| 1207 | 1199 | |
| 1208 | | - $typemap = array( |
| 1209 | | - 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ), |
| 1210 | | - 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( &$this, 'imageJpegWrapper' ) ), |
| 1211 | | - 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ), |
| 1212 | | - 'image/vnd.wap.wmbp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ), |
| 1213 | | - 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ), |
| 1214 | | - ); |
| 1215 | | - if( !isset( $typemap[$this->mime] ) ) { |
| 1216 | | - $err = 'Image type not supported'; |
| 1217 | | - wfDebug( "$err\n" ); |
| 1218 | | - return $err; |
| 1219 | | - } |
| 1220 | | - list( $loader, $colorStyle, $saveType ) = $typemap[$this->mime]; |
| | 1200 | + # Specify white background color, will be used for transparent images |
| | 1201 | + # in Internet Explorer/Windows instead of default black. |
| | 1202 | + |
| | 1203 | + # Note, we specify "-size {$width}" and NOT "-size {$width}x{$height}". |
| | 1204 | + # It seems that ImageMagick has a bug wherein it produces thumbnails of |
| | 1205 | + # the wrong size in the second case. |
| | 1206 | + |
| | 1207 | + $cmd = wfEscapeShellArg($wgImageMagickConvertCommand) . |
| | 1208 | + " {$quality} -background white -size {$width} ". |
| | 1209 | + wfEscapeShellArg($this->imagePath) . |
| | 1210 | + // Coalesce is needed to scale animated GIFs properly (bug 1017). |
| | 1211 | + ' -coalesce ' . |
| | 1212 | + // For the -resize option a "!" is needed to force exact size, |
| | 1213 | + // or ImageMagick may decide your ratio is wrong and slice off |
| | 1214 | + // a pixel. |
| | 1215 | + " -resize " . wfEscapeShellArg( "{$width}x{$height}!" ) . |
| | 1216 | + " -depth 8 " . |
| | 1217 | + wfEscapeShellArg($thumbPath) . " 2>&1"; |
| | 1218 | + wfDebug("reallyRenderThumb: running ImageMagick: $cmd\n"); |
| | 1219 | + wfProfileIn( 'convert' ); |
| | 1220 | + $err = wfShellExec( $cmd, $retval ); |
| | 1221 | + wfProfileOut( 'convert' ); |
| | 1222 | + } elseif( $wgCustomConvertCommand ) { |
| | 1223 | + # Use a custom convert command |
| | 1224 | + # Variables: %s %d %w %h |
| | 1225 | + $src = wfEscapeShellArg( $this->imagePath ); |
| | 1226 | + $dst = wfEscapeShellArg( $thumbPath ); |
| | 1227 | + $cmd = $wgCustomConvertCommand; |
| | 1228 | + $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames |
| | 1229 | + $cmd = str_replace( '%h', $height, str_replace( '%w', $width, $cmd ) ); # Size |
| | 1230 | + wfDebug( "reallyRenderThumb: Running custom convert command $cmd\n" ); |
| | 1231 | + wfProfileIn( 'convert' ); |
| | 1232 | + $err = wfShellExec( $cmd, $retval ); |
| | 1233 | + wfProfileOut( 'convert' ); |
| | 1234 | + } else { |
| | 1235 | + # Use PHP's builtin GD library functions. |
| | 1236 | + # |
| | 1237 | + # First find out what kind of file this is, and select the correct |
| | 1238 | + # input routine for this. |
| | 1239 | + |
| | 1240 | + $typemap = array( |
| | 1241 | + 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ), |
| | 1242 | + 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( &$this, 'imageJpegWrapper' ) ), |
| | 1243 | + 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ), |
| | 1244 | + 'image/vnd.wap.wmbp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ), |
| | 1245 | + 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ), |
| | 1246 | + ); |
| | 1247 | + if( !isset( $typemap[$this->mime] ) ) { |
| | 1248 | + $err = 'Image type not supported'; |
| | 1249 | + wfDebug( "$err\n" ); |
| | 1250 | + return $err; |
| | 1251 | + } |
| | 1252 | + list( $loader, $colorStyle, $saveType ) = $typemap[$this->mime]; |
| 1221 | 1253 | |
| 1222 | | - if( !function_exists( $loader ) ) { |
| 1223 | | - $err = "Incomplete GD library configuration: missing function $loader"; |
| 1224 | | - wfDebug( "$err\n" ); |
| 1225 | | - return $err; |
| 1226 | | - } |
| 1227 | | - if( $colorStyle == 'palette' ) { |
| 1228 | | - $truecolor = false; |
| 1229 | | - } elseif( $colorStyle == 'truecolor' ) { |
| 1230 | | - $truecolor = true; |
| 1231 | | - } elseif( $colorStyle == 'bits' ) { |
| 1232 | | - $truecolor = ( $this->bits > 8 ); |
| 1233 | | - } |
| | 1254 | + if( !function_exists( $loader ) ) { |
| | 1255 | + $err = "Incomplete GD library configuration: missing function $loader"; |
| | 1256 | + wfDebug( "$err\n" ); |
| | 1257 | + return $err; |
| | 1258 | + } |
| | 1259 | + if( $colorStyle == 'palette' ) { |
| | 1260 | + $truecolor = false; |
| | 1261 | + } elseif( $colorStyle == 'truecolor' ) { |
| | 1262 | + $truecolor = true; |
| | 1263 | + } elseif( $colorStyle == 'bits' ) { |
| | 1264 | + $truecolor = ( $this->bits > 8 ); |
| | 1265 | + } |
| 1234 | 1266 | |
| 1235 | | - $src_image = call_user_func( $loader, $this->imagePath ); |
| 1236 | | - if ( $truecolor ) { |
| 1237 | | - $dst_image = imagecreatetruecolor( $width, $height ); |
| 1238 | | - } else { |
| 1239 | | - $dst_image = imagecreate( $width, $height ); |
| | 1267 | + $src_image = call_user_func( $loader, $this->imagePath ); |
| | 1268 | + if ( $truecolor ) { |
| | 1269 | + $dst_image = imagecreatetruecolor( $width, $height ); |
| | 1270 | + } else { |
| | 1271 | + $dst_image = imagecreate( $width, $height ); |
| | 1272 | + } |
| | 1273 | + imagecopyresampled( $dst_image, $src_image, |
| | 1274 | + 0,0,0,0, |
| | 1275 | + $width, $height, $this->width, $this->height ); |
| | 1276 | + call_user_func( $saveType, $dst_image, $thumbPath ); |
| | 1277 | + imagedestroy( $dst_image ); |
| | 1278 | + imagedestroy( $src_image ); |
| 1240 | 1279 | } |
| 1241 | | - imagecopyresampled( $dst_image, $src_image, |
| 1242 | | - 0,0,0,0, |
| 1243 | | - $width, $height, $this->width, $this->height ); |
| 1244 | | - call_user_func( $saveType, $dst_image, $thumbPath ); |
| 1245 | | - imagedestroy( $dst_image ); |
| 1246 | | - imagedestroy( $src_image ); |
| 1247 | 1280 | } |
| 1248 | 1281 | |
| 1249 | 1282 | # |
| — | — | @@ -1712,7 +1745,7 @@ |
| 1713 | 1746 | |
| 1714 | 1747 | function getExifData() { |
| 1715 | 1748 | global $wgRequest; |
| 1716 | | - if ( $this->metadata === '0' ) |
| | 1749 | + if ( $this->metadata === '0' || $this->mime == 'image/vnd.djvu' ) |
| 1717 | 1750 | return array(); |
| 1718 | 1751 | |
| 1719 | 1752 | $purge = $wgRequest->getVal( 'action' ) == 'purge'; |
| — | — | @@ -2210,6 +2243,52 @@ |
| 2211 | 2244 | |
| 2212 | 2245 | return $revisions; |
| 2213 | 2246 | } |
| | 2247 | + |
| | 2248 | + /** |
| | 2249 | + * Select a page from a multipage document. Determines the page used for |
| | 2250 | + * rendering thumbnails. |
| | 2251 | + * |
| | 2252 | + * @param $page Integer: page number, starting with 1 |
| | 2253 | + */ |
| | 2254 | + function selectPage( $page ) { |
| | 2255 | + wfDebug( __METHOD__." selecting page $page \n" ); |
| | 2256 | + $this->page = $page; |
| | 2257 | + if ( ! $this->dataLoaded ) { |
| | 2258 | + $this->load(); |
| | 2259 | + } |
| | 2260 | + if ( ! isset( $this->multiPageXML ) ) { |
| | 2261 | + $this->multiPageXML = new SimpleXMLElement( $this->metadata ); |
| | 2262 | + } |
| | 2263 | + $o = $this->multiPageXML->BODY[0]->OBJECT[$page-1]; |
| | 2264 | + $this->height = intval( $o['height'] ); |
| | 2265 | + $this->width = intval( $o['width'] ); |
| | 2266 | + wfDebug( __METHOD__." >>>>METADATA>>>>\n".$o->asXML() . "\n<<<<<<<\n\n" ); |
| | 2267 | + wfDebug( __METHOD__." >>>>XML OBJECT>>>>\n". print_r($o,true) . "\n<<<<<<<\n\n" ); |
| | 2268 | + } |
| | 2269 | + |
| | 2270 | + /** |
| | 2271 | + * Returns 'true' if this image is a multipage document, e.g. a DJVU |
| | 2272 | + * document. |
| | 2273 | + * |
| | 2274 | + * @return Bool |
| | 2275 | + */ |
| | 2276 | + function isMultipage() { |
| | 2277 | + return ( $this->mime == 'image/vnd.djvu' ); |
| | 2278 | + } |
| | 2279 | + |
| | 2280 | + /** |
| | 2281 | + * Returns the number of pages of a multipage document, or NULL for |
| | 2282 | + * documents which aren't multipage documents |
| | 2283 | + */ |
| | 2284 | + function pageCount() { |
| | 2285 | + if ( ! $this->isMultipage() ) { |
| | 2286 | + return null; |
| | 2287 | + } |
| | 2288 | + if ( ! isset( $this->multiPageXML ) ) { |
| | 2289 | + $this->multiPageXML = new SimpleXMLElement( $this->metadata ); |
| | 2290 | + } |
| | 2291 | + return count( $this->multiPageXML->xpath( '//OBJECT' ) ); |
| | 2292 | + } |
| 2214 | 2293 | |
| 2215 | 2294 | } //class |
| 2216 | 2295 | |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -2186,4 +2186,24 @@ |
| 2187 | 2187 | */ |
| 2188 | 2188 | $wgMaxShellMemory = 102400; |
| 2189 | 2189 | |
| | 2190 | +/** |
| | 2191 | + * DJVU settings |
| | 2192 | + * Path of the djvutoxml executable |
| | 2193 | + * Enable this and $wgDjvuRenderer to enable djvu rendering |
| | 2194 | + */ |
| | 2195 | +# $wgDjvuToXML = 'djvutoxml'; |
| | 2196 | + |
| | 2197 | +/** |
| | 2198 | + * Path of the ddjvu DJVU renderer |
| | 2199 | + * Enable this and $wgDjvuToXML to enable djvu rendering |
| | 2200 | + */ |
| | 2201 | +# $wgDjvuRenderer = 'ddjvu'; |
| | 2202 | + |
| | 2203 | +/** |
| | 2204 | + * Path of the DJVU post processor |
| | 2205 | + * May include command line options |
| | 2206 | + * Default: ppmtojpeg, since ddjvu generates ppm output |
| | 2207 | + */ |
| | 2208 | +$wgDjvuPostProcessor = 'ppmtojpeg'; |
| | 2209 | + |
| 2190 | 2210 | ?> |
| Index: trunk/phase3/includes/ImageGallery.php |
| — | — | @@ -82,6 +82,7 @@ |
| 83 | 83 | */ |
| 84 | 84 | function add( $image, $html='' ) { |
| 85 | 85 | $this->mImages[] = array( &$image, $html ); |
| | 86 | + wfDebug( "ImageGallery::add " . $image->getName() . "\n" ); |
| 86 | 87 | } |
| 87 | 88 | |
| 88 | 89 | /** |
| — | — | @@ -157,8 +158,7 @@ |
| 158 | 159 | # The image is blacklisted, just show it as a text link. |
| 159 | 160 | $thumbhtml = '<div style="height: 152px;">' |
| 160 | 161 | . $sk->makeKnownLinkObj( $nt, htmlspecialchars( $nt->getText() ) ) . '</div>'; |
| 161 | | - } |
| 162 | | - else if( !( $thumb = $img->getThumbnail( 120, 120, $wgGenerateThumbnailOnParse ) ) ) { |
| | 162 | + } else if( !( $thumb = $img->getThumbnail( 120, 120, $wgGenerateThumbnailOnParse ) ) ) { |
| 163 | 163 | # Error generating thumbnail. |
| 164 | 164 | $thumbhtml = '<div style="height: 152px;">' |
| 165 | 165 | . htmlspecialchars( $img->getLastError() ) . '</div>'; |
| Index: trunk/phase3/includes/DjVuImage.php |
| — | — | @@ -208,7 +208,23 @@ |
| 209 | 209 | 'resolution' => $resolution, |
| 210 | 210 | 'gamma' => $gamma / 10.0 ); |
| 211 | 211 | } |
| | 212 | + |
| | 213 | + /** |
| | 214 | + * Return an XML string describing the DjVu image |
| | 215 | + * @return string |
| | 216 | + */ |
| | 217 | + function retrieveMetaData() { |
| | 218 | + global $wgDjvuToXML; |
| | 219 | + if ( isset( $wgDjvuToXML ) ) { |
| | 220 | + $cmd = $wgDjvuToXML . ' --without-anno --without-text ' . $this->mFilename; |
| | 221 | + $xml = wfShellExec( $cmd, $retval ); |
| | 222 | + } else { |
| | 223 | + $xml = null; |
| | 224 | + } |
| | 225 | + return $xml; |
| | 226 | + } |
| | 227 | + |
| 212 | 228 | } |
| 213 | 229 | |
| 214 | 230 | |
| 215 | | -?> |
| \ No newline at end of file |
| | 231 | +?> |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -26,6 +26,9 @@ |
| 27 | 27 | == Major new features == |
| 28 | 28 | |
| 29 | 29 | * (bug 550) Allow blocks on anonymous users only. |
| | 30 | +* (bug 6420) Render thumbnails for DJVU images, support multipage DJVU display |
| | 31 | + on image pages. Added new 'page=' thumbnail option to select a page from a |
| | 32 | + multipage djvu for thumbnail generation. |
| 30 | 33 | |
| 31 | 34 | == Changes since 1.7 == |
| 32 | 35 | |
| Index: trunk/phase3/languages/MessagesDe.php |
| — | — | @@ -1889,6 +1889,14 @@ |
| 1890 | 1890 | |
| 1891 | 1891 | 'loginlanguagelabel' => 'Sprache: $1', |
| 1892 | 1892 | |
| | 1893 | + |
| | 1894 | +# Multipage image navigation |
| | 1895 | +'imgmultipageprev' => '← vorige Seite', |
| | 1896 | +'imgmultipagenext' => 'nächste Seite →', |
| | 1897 | +'imgmultigo' => 'OK', |
| | 1898 | +'imgmultigotopre' => 'Gehe zu Seite', |
| | 1899 | +'imgmultigotopost' => '', |
| | 1900 | + |
| 1893 | 1901 | ); |
| 1894 | 1902 | |
| 1895 | 1903 | |