Skip to content

Commit

Permalink
Merge pull request #19 from jmleroux/jml-svg-templates
Browse files Browse the repository at this point in the history
SVG templates
  • Loading branch information
liuggio committed Mar 27, 2016
2 parents 5336a12 + 1bf3f01 commit be84d40
Show file tree
Hide file tree
Showing 15 changed files with 333 additions and 401 deletions.
20 changes: 20 additions & 0 deletions spec/Fixtures/flat-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions spec/Fixtures/flat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions spec/Fixtures/invalid_template/plastic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 13 additions & 12 deletions spec/Fixtures/license.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions spec/Fixtures/xml_template/plastic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 3 additions & 27 deletions spec/PUGX/Poser/Render/SvgFlatRenderSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use PUGX\Poser\Badge;
use PUGX\Poser\Calculator\TextSizeCalculatorInterface;

class SvgFlatRenderSpec extends ObjectBehavior
{
Expand Down Expand Up @@ -37,32 +36,9 @@ public function getMatchers()

function it_should_render_a_license_mit_exactly_like_this_svg()
{
$template = <<<EOF
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="a">
<rect width="40" height="20" rx="3" fill="#fff"/>
</mask>
<g mask="url(#a)">
<rect width="20" height="20" fill="#555"/>
<rect x="20" width="20" height="20" fill="#007ec6"/>
<rect width="40" height="20" fill="url(#b)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="11" y="15" fill="#010101" fill-opacity=".3">license</text>
<text x="11" y="14">license</text>
<text x="29" y="15" fill="#010101" fill-opacity=".3">MIT</text>
<text x="29" y="14">MIT</text>
</g>
</svg>
EOF;

$fixture = __DIR__ . '/../../../Fixtures/flat.svg';
$template = file_get_contents($fixture);
$badge = Badge::fromURI('license-MIT-blue.svg');
$this->render($badge)->__toString()->shouldBeLike($template);
}


}
}
27 changes: 3 additions & 24 deletions spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function it_should_render_a_svg()
public function getMatchers()
{
return array(
'beAValidSVGImage' => function($subject) {
'beAValidSVGImage' => function ($subject) {

$regex = '/^<svg.*width="((.|\n)*)<\/svg>$/';
$matches = array();
Expand All @@ -36,29 +36,8 @@ public function getMatchers()

function it_should_render_a_license_mit_exactly_like_this_svg()
{
$template = <<<EOF
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="a">
<rect width="40" height="20" rx="0" fill="#fff"/>
</mask>
<g mask="url(#a)">
<rect width="20" height="20" fill="#555"/>
<rect x="20" width="20" height="20" fill="#007ec6"/>
<rect width="40" height="20" fill="url(#b)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="11" y="15" fill="#010101" fill-opacity=".3">license</text>
<text x="11" y="14">license</text>
<text x="29" y="15" fill="#010101" fill-opacity=".3">MIT</text>
<text x="29" y="14">MIT</text>
</g>
</svg>
EOF;

$fixture = __DIR__ . '/../../../Fixtures/flat-square.svg';
$template = file_get_contents($fixture);
$badge = Badge::fromURI('license-MIT-blue.svg');
$this->render($badge)->__toString()->shouldBeLike($template);
}
Expand Down
24 changes: 20 additions & 4 deletions spec/PUGX/Poser/Render/SvgRenderSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,31 @@ function it_should_render_a_svg()
$this->render($badge)->shouldBeAValidSVGImage();
}

function it_should_not_render_an_invalid_svg($calculator)
{
$templatesDir = __DIR__ . '/../../../Fixtures/invalid_template';
$this->beConstructedWith($calculator, $templatesDir);
$badge = Badge::fromURI('version-stable-97CA00.svg');
$this->shouldThrow(new \RuntimeException('Generated string is not a valid XML'))->duringRender($badge);
}

function it_should_not_render_non_svg_xml($calculator)
{
$templatesDir = __DIR__ . '/../../../Fixtures/xml_template';
$this->beConstructedWith($calculator, $templatesDir);
$badge = Badge::fromURI('version-stable-97CA00.svg');
$this->shouldThrow(new \RuntimeException('Generated xml is not a SVG'))->duringRender($badge);
}

public function getMatchers()
{
return array(
'beAValidSVGImage' => function($subject) {
'beAValidSVGImage' => function ($subject) {

$regex = '/^<svg.*width="((.|\n)*)<\/svg>$/';
$matches = array();
$regex = '/^<svg.*width="((.|\n)*)<\/svg>$/';
$matches = array();

return preg_match($regex, (string) $subject, $matches, PREG_OFFSET_CAPTURE, 0);
return preg_match($regex, (string) $subject, $matches, PREG_OFFSET_CAPTURE, 0);
}
);
}
Expand Down
147 changes: 147 additions & 0 deletions src/Render/LocalSvgRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

/*
* This file is part of the badge-poser package.
*
* (c) PUGX <http://pugx.github.io/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace PUGX\Poser\Render;

use PUGX\Poser\Badge;
use PUGX\Poser\Calculator\GDTextSizeCalculator;
use PUGX\Poser\Calculator\TextSizeCalculatorInterface;
use PUGX\Poser\Image;
use SimpleXMLElement;

/**
* Local SVG renderer.
* Generate SVG badges from local templates.
*
* @author JM Leroux <[email protected]>
*/
abstract class LocalSvgRenderer implements RenderInterface
{
const VENDOR_COLOR = '#555';

/**
* @var TextSizeCalculatorInterface
*/
private $textSizeCalculator;

/**
* @var string
*/
private $templatesDirectory;

/**
* @param TextSizeCalculatorInterface $textSizeCalculator
* @param null|string $templatesDirectory
*/
public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null, $templatesDirectory = null)
{
$this->textSizeCalculator = $textSizeCalculator;
if (null === $this->textSizeCalculator) {
$this->textSizeCalculator = new GDTextSizeCalculator();
}

$this->templatesDirectory = $templatesDirectory;
if (null === $this->templatesDirectory) {
$this->templatesDirectory = __DIR__ . '/../Resources/templates';;
}
}

/**
* @param Badge $badge
*
* @return mixed
*/
public function render(Badge $badge)
{
$template = $this->getTemplate($this->getTemplateName());
$parameters = $this->buildParameters($badge);

return $this->renderSvg($template, $parameters, $badge->getFormat());
}

/**
* @return string
*/
abstract protected function getTemplateName();

/**
* @param $format
*
* @return string SVG content of the template
*/
private function getTemplate($format)
{
$filepath = sprintf('%s/%s.svg', $this->templatesDirectory, $format);

if (!file_exists($filepath)) {
throw new \InvalidArgumentException(sprintf('No template for format %s', $format));
}

return file_get_contents($filepath);
}

/**
* @param $text
*
* @return float
*/
private function stringWidth($text)
{
return $this->textSizeCalculator->calculateWidth($text);
}

/**
* @param string $render
* @param array $parameters
* @param string $format
*
* @return Image
*/
private function renderSvg($render, $parameters, $format)
{
foreach ($parameters as $key => $variable) {
$render = str_replace(sprintf('{{ %s }}', $key), $variable, $render);
}

try {
$xml = new SimpleXMLElement($render);
} catch (\Exception $e) {
throw new \RuntimeException('Generated string is not a valid XML');
}
if ('svg' !== $xml->getName()) {
throw new \RuntimeException('Generated xml is not a SVG');
}

return Image::createFromString($render, $format);
}

/**
* @param Badge $badge
*
* @return array
*/
private function buildParameters(Badge $badge)
{
$parameters = array();

$parameters['vendorWidth'] = $this->stringWidth($badge->getSubject());
$parameters['valueWidth'] = $this->stringWidth($badge->getStatus());
$parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth'];
$parameters['vendorColor'] = static::VENDOR_COLOR;
$parameters['valueColor'] = $badge->getHexColor();
$parameters['vendor'] = $badge->getSubject();
$parameters['value'] = $badge->getStatus();
$parameters['vendorStartPosition'] = round($parameters['vendorWidth'] / 2, 1) + 1;
$parameters['valueStartPosition'] = $parameters['vendorWidth'] + round($parameters['valueWidth'] / 2, 1) - 1;

return $parameters;
}
}
Loading

0 comments on commit be84d40

Please sign in to comment.