コード例 #1
0
 /**
  * Convert passed image data, which is assumed to be SVG, to PNG.
  *
  * @param string $svg SVG image data
  * @return string|bool PNG image data, or false on failure
  */
 protected function rasterize($svg)
 {
     // This code should be factored out to a separate method on SvgHandler, or perhaps a separate
     // class, with a separate set of configuration settings.
     //
     // This is a distinct use case from regular SVG rasterization:
     // * We can skip many sanity and security checks (as the images come from a trusted source,
     //   rather than from the user).
     // * We need to provide extra options to some converters to achieve acceptable quality for very
     //   small images, which might cause performance issues in the general case.
     // * We want to directly pass image data to the converter, rather than a file path.
     //
     // See https://phabricator.wikimedia.org/T76473#801446 for examples of what happens with the
     // default settings.
     //
     // For now, we special-case rsvg (used in WMF production) and do a messy workaround for other
     // converters.
     global $wgSVGConverter, $wgSVGConverterPath;
     $svg = $this->massageSvgPathdata($svg);
     // Sometimes this might be 'rsvg-secure'. Long as it's rsvg.
     if (strpos($wgSVGConverter, 'rsvg') === 0) {
         $command = 'rsvg-convert';
         if ($wgSVGConverterPath) {
             $command = wfEscapeShellArg("{$wgSVGConverterPath}/") . $command;
         }
         $process = proc_open($command, array(0 => array('pipe', 'r'), 1 => array('pipe', 'w')), $pipes);
         if (is_resource($process)) {
             fwrite($pipes[0], $svg);
             fclose($pipes[0]);
             $png = stream_get_contents($pipes[1]);
             fclose($pipes[1]);
             proc_close($process);
             return $png ?: false;
         }
         return false;
     } else {
         // Write input to and read output from a temporary file
         $tempFilenameSvg = tempnam(wfTempDir(), 'ResourceLoaderImage');
         $tempFilenamePng = tempnam(wfTempDir(), 'ResourceLoaderImage');
         file_put_contents($tempFilenameSvg, $svg);
         $metadata = SVGMetadataExtractor::getMetadata($tempFilenameSvg);
         if (!isset($metadata['width']) || !isset($metadata['height'])) {
             unlink($tempFilenameSvg);
             return false;
         }
         $handler = new SvgHandler();
         $res = $handler->rasterize($tempFilenameSvg, $tempFilenamePng, $metadata['width'], $metadata['height']);
         unlink($tempFilenameSvg);
         $png = null;
         if ($res === true) {
             $png = file_get_contents($tempFilenamePng);
             unlink($tempFilenamePng);
         }
         return $png ?: false;
     }
 }
コード例 #2
0
	/**
	* Generate a graph for this tag
	* @param string $tag
	* @param string $filePath
	* @return bool, success
	*/
	public function makeSvgGraph( $tag, $filePath ) {
		global $wgSvgGraphDir, $wgContLang, $wgMemc;
		require_once( "$wgSvgGraphDir/svgGraph.php" ); // load classes
		require_once( "$wgSvgGraphDir/svgGraph2.php" ); // load classes
		// Define the object
		$plot = new svgGraph2();
		// Set file path
		$dir = dirname($filePath);
		// Make sure directory exists
		if( !file_exists($dir) && !wfMkdirParents( $dir, 0777, __METHOD__ ) ) {
			throw new MWException( 'Could not create file directory!' );
		}
		// Set some parameters
		$plot->graphicWidth = 1000;
		$plot->graphicHeight = 410;
		$plot->plotWidth = 930;
		$plot->plotHeight = 350;
		$plot->decimalPlacesY = 1;
		$plot->plotOffsetX = 40;
		$plot->plotOffsetY = 30;
		$plot->numGridlinesY = 10 + 1;
		$plot->innerPaddingX = 15;
		$plot->innerPaddingY = 10;
		$plot->outerPadding = 5;
		$plot->minY = 0;
		$plot->maxY = 5;
		// Define the data using the DB rows
		$dataX = $dave = $rave = $dcount = array();
		$totalVal = $totalCount = $sd = $pts = $n = 0;
		// Define the data using the DB rows
		list($res,$u,$maxC,$days) = $this->doQuery( $tag );
		if( !$maxC ) return false;
		// Label spacing
		$int = intval( ceil($days/10) ); // 10 labels at most
		foreach ( $res as $row ) {
			$totalVal += (int)$row->rfh_total;
			$totalCount += (int)$row->rfh_count;
			$dayCount = (real)$row->rfh_count;
			if( !$row->rfh_count ) continue; // bad data
			// Nudge values up by 1 to fit [1,5]
			$dayAve = 1 + (real)$row->rfh_total/(real)$row->rfh_count;
			$sd += pow($dayAve - $u,2);
			$cumAve = 1 + (real)$totalVal/(real)$totalCount;
			$year = intval( substr( $row->rfh_date, 0, 4 ) );
			$month = intval( substr( $row->rfh_date, 4, 2 ) );
			$day = intval( substr( $row->rfh_date, 6, 2 ) );
			# Fill in days with no votes to keep spacing even
			if( isset($lastDate) ) {
				$dayGap = wfTimestamp(TS_UNIX,$row->rfh_date) - wfTimestamp(TS_UNIX,$lastDate);
				$x = intval( $dayGap/86400 );
				# Day gaps...
				for( $x; $x > 1; --$x ) {
					$dataX[] = "";
					$dave[] = $lastDAve;
					$rave[] = $lastRAve;
					$dcount[] = 0;
					$n++;
				}
			}
			$n++;
			# Label point?
			if( $n >= $int || !count($dataX) ) {
				$p = ($days > 31) ? "{$month}-".substr( $year, 2, 2 ) : "{$month}/{$day}";
				$n = 0;
			} else {
				$p = "";
			}
			$dataX[] = $p;
			$dave[] = $dayAve;
			$rave[] = $cumAve;
			$dcount[] = $dayCount;
			$lastDate = $row->rfh_date;
			$lastDAve = $dayAve;
			$lastRAve = $cumAve;
			$pts++;
		}
		// Minimum sample size
		if( $pts < 2 ) {
			return false;
		}
		$sd = sqrt($sd/$pts);
		// Round values for display
		$sd = round( $sd, 3 );
		$u = round( $u, 3 );
		// Re-scale voter count to fit to graph
		$this->dScale = ceil($maxC/5);
		// Cache the scale value to memory
		$key = wfMemcKey( 'feedback', 'scale', $this->page->getArticleId(), $this->period );
		$wgMemc->set( $key, $this->dScale, 7*24*3600 );
		// Fit to [0,4]
		foreach( $dcount as $x => $c ) {
			$dcount[$x] = $c/$this->dScale;
		}
		$plot->dataX = $dataX;
		$plot->dataY['dave'] = $dave;
		$plot->dataY['rave'] = $rave;
		$plot->dataY['dcount'] = $dcount;
		$plot->styleTagsX = 'font-family: monospace; font-size: 9pt;';
		$plot->styleTagsY = 'font-family: sans-serif; font-size: 11pt;';
		$plot->format['dave'] = array( 'style' => 'stroke:blue; stroke-width:1;' );
		$plot->format['rave'] = array( 'style' => 'stroke:green; stroke-width:1;' );
		$plot->format['dcount'] = array( 'style' => 'stroke:red; stroke-width:1;' );
			#'attributes' => "marker-end='url(#circle)'");
		$pageText = $wgContLang->truncate( $this->page->getPrefixedText(), 65 );
		$plot->title = wfMsgExt('ratinghistory-graph',array('parsemag','content'),
			$totalCount, wfMsgForContent("readerfeedback-$tag"), $pageText );
		$plot->styleTitle = 'font-family: sans-serif; font-weight: bold; font-size: 12pt;';
		$plot->backgroundStyle = 'fill:#F0F0F0;';
		// extra code for markers
		// FIXME: http://studio.imagemagick.org/pipermail/magick-bugs/2003-January/001038.html
		/* $plot->extraSVG =
			'<defs>
			  <marker id="circle" style="stroke:red; stroke-width:0; fill:red;"
				viewBox="0 0 10 10" refX="5" refY="7" orient="0"
				markerUnits="strokeWidth" markerWidth="5" markerHeight="5">
				<circle cx="5" cy="5" r="3"/>
			  </marker>
			</defs>';
		*/
		# Create the graph
		@$plot->init();
		$plot->drawGraph();
		if( !$plot->polyLine('dave') ) {
			throw new MWException( 'Could not generate "dave" line!' );
		}
		if( !$plot->polyLine('rave') ) {
			throw new MWException( 'Could not generate "rave" line!' );
		}
		if( !$plot->polyLine('dcount') ) {
			throw new MWException( 'Could not generate "dcount" line!' );
		}
		#$plot->line('dcount');
		// Render!
		$plot->generateSVG( "xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'" );
		// Write to file for cache
		$svgPath = $this->getFilePath( $tag, 'svg' );
		$svgHandler = new SvgHandler();
		wfSuppressWarnings(); // FS notices possible
		if( !file_put_contents( $svgPath, $plot->svg ) ) {
			wfRestoreWarnings();
			throw new MWException( 'Could not write SVG file!' );
		}
		wfRestoreWarnings();
		// Rasterize due to IE suckage
		$status = $svgHandler->rasterize( $svgPath, $filePath, 1000, 410 );
		if( $status !== true ) {
			wfDebug( 'Could not rasterize SVG file from '.$filePath.'!' );
			//return false;
		}
		return true;
	}