ImageFunctions.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?php
  2. /**
  3. * Return a rounded pixel equivalent for a labeled CSS/SVG length.
  4. * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers
  5. *
  6. * @param $length String: CSS/SVG length.
  7. * @param $viewportSize: Float optional scale for percentage units...
  8. * @return float: length in pixels
  9. */
  10. function wfScaleSVGUnit( $length, $viewportSize=512 ) {
  11. static $unitLength = array(
  12. 'px' => 1.0,
  13. 'pt' => 1.25,
  14. 'pc' => 15.0,
  15. 'mm' => 3.543307,
  16. 'cm' => 35.43307,
  17. 'in' => 90.0,
  18. 'em' => 16.0, // fake it?
  19. 'ex' => 12.0, // fake it?
  20. '' => 1.0, // "User units" pixels by default
  21. );
  22. $matches = array();
  23. if( preg_match( '/^\s*(\d+(?:\.\d+)?)(em|ex|px|pt|pc|cm|mm|in|%|)\s*$/', $length, $matches ) ) {
  24. $length = floatval( $matches[1] );
  25. $unit = $matches[2];
  26. if( $unit == '%' ) {
  27. return $length * 0.01 * $viewportSize;
  28. } else {
  29. return $length * $unitLength[$unit];
  30. }
  31. } else {
  32. // Assume pixels
  33. return floatval( $length );
  34. }
  35. }
  36. class XmlSizeFilter {
  37. const DEFAULT_WIDTH = 512;
  38. const DEFAULT_HEIGHT = 512;
  39. var $first = true;
  40. var $width = self::DEFAULT_WIDTH;
  41. var $height = self::DEFAULT_HEIGHT;
  42. function filter( $name, $attribs ) {
  43. if( $this->first ) {
  44. $defaultWidth = self::DEFAULT_WIDTH;
  45. $defaultHeight = self::DEFAULT_HEIGHT;
  46. $aspect = 1.0;
  47. $width = null;
  48. $height = null;
  49. if( isset( $attribs['viewBox'] ) ) {
  50. // min-x min-y width height
  51. $viewBox = preg_split( '/\s+/', trim( $attribs['viewBox'] ) );
  52. if( count( $viewBox ) == 4 ) {
  53. $viewWidth = wfScaleSVGUnit( $viewBox[2] );
  54. $viewHeight = wfScaleSVGUnit( $viewBox[3] );
  55. if( $viewWidth > 0 && $viewHeight > 0 ) {
  56. $aspect = $viewWidth / $viewHeight;
  57. $defaultHeight = $defaultWidth / $aspect;
  58. }
  59. }
  60. }
  61. if( isset( $attribs['width'] ) ) {
  62. $width = wfScaleSVGUnit( $attribs['width'], $defaultWidth );
  63. }
  64. if( isset( $attribs['height'] ) ) {
  65. $height = wfScaleSVGUnit( $attribs['height'], $defaultHeight );
  66. }
  67. if( !isset( $width ) && !isset( $height ) ) {
  68. $width = $defaultWidth;
  69. $height = $width / $aspect;
  70. } elseif( isset( $width ) && !isset( $height ) ) {
  71. $height = $width / $aspect;
  72. } elseif( isset( $height ) && !isset( $width ) ) {
  73. $width = $height * $aspect;
  74. }
  75. if( $width > 0 && $height > 0 ) {
  76. $this->width = intval( round( $width ) );
  77. $this->height = intval( round( $height ) );
  78. }
  79. $this->first = false;
  80. }
  81. }
  82. }
  83. /**
  84. * Compatible with PHP getimagesize()
  85. * @todo support gzipped SVGZ
  86. * @todo check XML more carefully
  87. * @todo sensible defaults
  88. *
  89. * @param $filename String: full name of the file (passed to php fopen()).
  90. * @return array
  91. */
  92. function wfGetSVGsize( $filename ) {
  93. $filter = new XmlSizeFilter();
  94. $xml = new XmlTypeCheck( $filename, array( $filter, 'filter' ) );
  95. if( $xml->wellFormed ) {
  96. return array( $filter->width, $filter->height, 'SVG',
  97. "width=\"$filter->width\" height=\"$filter->height\"" );
  98. }
  99. return false;
  100. }
  101. /**
  102. * Determine if an image exists on the 'bad image list'.
  103. *
  104. * The format of MediaWiki:Bad_image_list is as follows:
  105. * * Only list items (lines starting with "*") are considered
  106. * * The first link on a line must be a link to a bad image
  107. * * Any subsequent links on the same line are considered to be exceptions,
  108. * i.e. articles where the image may occur inline.
  109. *
  110. * @param $name string the image name to check
  111. * @param $contextTitle Title: the page on which the image occurs, if known
  112. * @return bool
  113. */
  114. function wfIsBadImage( $name, $contextTitle = false ) {
  115. static $badImages = false;
  116. wfProfileIn( __METHOD__ );
  117. # Run the extension hook
  118. $bad = false;
  119. if( !wfRunHooks( 'BadImage', array( $name, &$bad ) ) ) {
  120. wfProfileOut( __METHOD__ );
  121. return $bad;
  122. }
  123. if( !$badImages ) {
  124. # Build the list now
  125. $badImages = array();
  126. $lines = explode( "\n", wfMsgForContentNoTrans( 'bad_image_list' ) );
  127. foreach( $lines as $line ) {
  128. # List items only
  129. if ( substr( $line, 0, 1 ) !== '*' ) {
  130. continue;
  131. }
  132. # Find all links
  133. $m = array();
  134. if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
  135. continue;
  136. }
  137. $exceptions = array();
  138. $imageDBkey = false;
  139. foreach ( $m[1] as $i => $titleText ) {
  140. $title = Title::newFromText( $titleText );
  141. if ( !is_null( $title ) ) {
  142. if ( $i == 0 ) {
  143. $imageDBkey = $title->getDBkey();
  144. } else {
  145. $exceptions[$title->getPrefixedDBkey()] = true;
  146. }
  147. }
  148. }
  149. if ( $imageDBkey !== false ) {
  150. $badImages[$imageDBkey] = $exceptions;
  151. }
  152. }
  153. }
  154. $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
  155. $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
  156. wfProfileOut( __METHOD__ );
  157. return $bad;
  158. }
  159. /**
  160. * Calculate the largest thumbnail width for a given original file size
  161. * such that the thumbnail's height is at most $maxHeight.
  162. * @param $boxWidth Integer Width of the thumbnail box.
  163. * @param $boxHeight Integer Height of the thumbnail box.
  164. * @param $maxHeight Integer Maximum height expected for the thumbnail.
  165. * @return Integer.
  166. */
  167. function wfFitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
  168. $idealWidth = $boxWidth * $maxHeight / $boxHeight;
  169. $roundedUp = ceil( $idealWidth );
  170. if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight )
  171. return floor( $idealWidth );
  172. else
  173. return $roundedUp;
  174. }