sixty-nine/php-cloud-lib

View on GitHub
src/SixtyNine/Cloud/Command/CommandsHelper.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

namespace SixtyNine\Cloud\Command;

use Imagine\Image\ImageInterface;
use SixtyNine\Cloud\Builder\CloudBuilder;
use SixtyNine\Cloud\Builder\FiltersBuilder;
use SixtyNine\Cloud\Builder\PalettesBuilder;
use SixtyNine\Cloud\Builder\WordsListBuilder;
use SixtyNine\Cloud\Color\ColorGeneratorInterface;
use SixtyNine\Cloud\Color\RandomColorGenerator;
use SixtyNine\Cloud\Color\RotateColorGenerator;
use SixtyNine\Cloud\Factory\FontsFactory;
use SixtyNine\Cloud\Factory\PlacerFactory;
use SixtyNine\Cloud\FontSize\BoostFontSizeGenerator;
use SixtyNine\Cloud\FontSize\DimFontSizeGenerator;
use SixtyNine\Cloud\FontSize\FontSizeGeneratorInterface;
use SixtyNine\Cloud\FontSize\LinearFontSizeGenerator;
use SixtyNine\Cloud\Placer\PlacerInterface;
use SixtyNine\Cloud\Renderer\CloudRenderer;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Webmozart\Assert\Assert;

class CommandsHelper
{
    protected $fontSizeBoosts = array('linear', 'dim', 'boost');
    protected $paletteTypes = array('cycle', 'random');
    protected $outputFormats = array('gif', 'jpeg', 'png');

    /**
     * @param string $name
     * @return PlacerInterface
     * @throws \InvalidArgumentException
     */
    public function getPlacer($name)
    {
        $availablePlacers = PlacerFactory::getInstance()->getPlacersNames();

        if ($name) {
            Assert::oneOf($name, $availablePlacers, 'Word placer not found: ' . $name);
            return $name;
        }

        Assert::notEmpty($availablePlacers, 'No word placers available');
        return $availablePlacers[0];
    }

    /**
     * @param FontsFactory $factory
     * @param string $font
     * @return string
     * @throws \InvalidArgumentException
     */
    public function getFont(FontsFactory $factory, $font)
    {
        if ($font) {
            return $font;
        }

        Assert::notEmpty($factory->getFonts(), 'No font file found');
        return $factory->getFonts()[0];
    }

    /**
     * @param string $type
     * @return FontSizeGeneratorInterface
     * @throws \InvalidArgumentException
     */
    public function getFontSizeGenerator($type = 'linear')
    {
        Assert::oneOf($type, $this->fontSizeBoosts, 'Invalid font size boost: ' . $type);

        $generatorClass = LinearFontSizeGenerator::class;
        if ($type === 'dim') {
            $generatorClass = DimFontSizeGenerator::class;
        }
        if ($type === 'boost') {
            $generatorClass = BoostFontSizeGenerator::class;
        }

        return new $generatorClass();
    }

    /**
     * @param string $paletteName
     * @param string $paletteType
     * @param string $palettesFile
     * @return bool|ColorGeneratorInterface
     * @throws \InvalidArgumentException
     */
    public function getColorGenerator($paletteName, $paletteType, $palettesFile = null)
    {
        if ($paletteName && $paletteType) {

            Assert::oneOf($paletteType, $this->paletteTypes, 'Palette type must be either "cycle" or "random"');

            $file = $palettesFile
                ? $palettesFile
                : __DIR__ . '/../Resources/palettes.yml'
            ;
            $paletteBuilder = PalettesBuilder::create()->importPalettes($file);

            $palette = $paletteBuilder->getNamedPalette($paletteName);
            $generatorClass = ($paletteType === 'cycle')
                ? RotateColorGenerator::class
                : RandomColorGenerator::class
            ;
            return new $generatorClass($palette);
        }

        return false;
    }

    /**
     * @param ImageInterface $image
     * @param string $outputFormat
     * @param string $outputFile
     * @throws \InvalidArgumentException
     */
    public function output(ImageInterface $image, $outputFormat, $outputFile = null)
    {
        Assert::oneOf($outputFormat, $this->outputFormats, 'Invalid output format: ' . $outputFormat);

        if ($outputFile) {
            $image->save($outputFile, array('format' => $outputFormat));
            return;
        }

        echo $image->get($outputFormat);
    }

    /**
     * @param CloudBuilder $cloudBuilder
     * @param FontsFactory $factory
     * @param PlacerInterface $placer
     * @param bool $renderBoxes
     * @return \Imagine\Gd\Image|ImageInterface
     */
    protected function render(
        CloudBuilder $cloudBuilder,
        FontsFactory $factory,
        PlacerInterface $placer = null,
        $renderBoxes = false,
        $renderMask = false
    ) {
        $renderer = new CloudRenderer($cloudBuilder->build(), $factory);

        if ($renderBoxes) {
            $renderer->renderBoundingBoxes('#888888');
        }

        if ($placer) {
            $renderer->renderUsher($placer, '#333333');
        }

        if ($renderMask) {
            $renderer->renderMask($cloudBuilder->getMask(), '#ababab');
        }

        $renderer->renderCloud();

        return $renderer->getImage();
    }

    /**
     * @param int $minWordLength
     * @param int $maxWordLength
     * @param null $changeCase
     * @param bool $noRemoveNumbers
     * @param bool $noRemoveUnwanted
     * @param bool $noRemoveTrailing
     * @return FiltersBuilder
     */
    public function getFilterBuilder(
        $minWordLength,
        $maxWordLength,
        $changeCase = null,
        $noRemoveNumbers = false,
        $noRemoveUnwanted = false,
        $noRemoveTrailing = false
    ) {
        $filtersBuilder = FiltersBuilder::create()
            ->setMinLength($minWordLength)
            ->setMaxLength($maxWordLength)
            ->setRemoveNumbers(!$noRemoveNumbers)
            ->setRemoveUnwanted(!$noRemoveTrailing)
            ->setRemoveTrailing(!$noRemoveUnwanted)
        ;

        if ($changeCase && in_array($changeCase, $filtersBuilder->getAllowedCase())) {
            $filtersBuilder->setCase($changeCase);
        }

        return $filtersBuilder;
    }

    /**
     * @param WordsListBuilder $builder
     * @param string $type
     * @param string $file
     * @param string $url
     */
    public function insertWords(WordsListBuilder $builder, $type, $file = null, $url = null)
    {
        Assert::true(null !== $file || null !== $url);
        Assert::oneOf($type, array('from-url', 'from-file'), 'Invalid type for createCloud: ' . $type);

        if ($type === 'from-file') {
            Assert::fileExists($file, 'File not found: ' . $file);
            $builder->importWords(file_get_contents($file));
        } else {
            $builder->importUrl($url);
        }

    }

    /**
     * @param WordsListBuilder $builder
     * @param string $sortBy
     * @param string $sortOrder
     */
    public function sortWords(WordsListBuilder $builder, $sortBy, $sortOrder)
    {
        if ($sortBy && $sortOrder) {
            $builder->sort($sortBy, $sortOrder);
        }
    }

    /**
     * @param string $type
     * @param InputInterface $input
     * @throws \InvalidArgumentException
     */
    public function createCloud($type, InputInterface $input)
    {
        Assert::oneOf($type, array('from-url', 'from-file'), 'Invalid type for createCloud: ' . $type);

        $stopwatch = new Stopwatch();
        $stopwatch->start('createCloud');

        // Build the filters
        $filtersBuilder = $this->getFilterBuilder(
            $input->getOption('min-word-length'),
            $input->getOption('max-word-length'),
            $input->getOption('case'),
            $input->getOption('no-remove-numbers'),
            $input->getOption('no-remove-unwanted'),
            $input->getOption('no-remove-trailing')
        );

        // Create a placer
        $placerName = $this->getPlacer($input->getOption('placer'));
        $placer = PlacerFactory::getInstance()->getPlacer(
            $placerName,
            $input->getOption('width'),
            $input->getOption('height')
        );

        // Get the font file
        $fontsPath = $input->getOption('fonts-path')
            ? realpath($input->getOption('fonts-path'))
            : constant('BASE_PATH') . '/fonts'
        ;
        $factory = FontsFactory::create($fontsPath);
        $font = $this->getFont($factory, $input->getOption('font'));

        // Create the list builder
        $listBuilder = WordsListBuilder::create()
            ->setMaxWords($input->getOption('max-word-count'))
            ->setFilters($filtersBuilder->build())
            ->randomizeOrientation($input->getOption('vertical-probability'))
        ;

        $this->insertWords($listBuilder, $type, $input->getOption('save-to-file'), $input->getArgument('url'));

        $this->sortWords($listBuilder, $input->getOption('sort-by'), $input->getOption('sort-order'));

        // Apply a color generator if needed
        $colorGenerator = $this->getColorGenerator(
            $input->getOption('palette'),
            $input->getOption('palette-type'),
            $input->getOption('palettes-file')
        );

        if ($colorGenerator) {
            $listBuilder->randomizeColors($colorGenerator);
        }

        // Build the list
        $list = $listBuilder->build('list');

        // Create a cloud builder
        $cloudBuilder = CloudBuilder::create($factory)
            ->setBackgroundColor($input->getOption('background-color'))
            ->setDimension($input->getOption('width'), $input->getOption('height'))
            ->setFont($font)
            ->setFontSizes($input->getOption('min-font-size'), $input->getOption('max-font-size'))
            ->setPlacer($placerName)
            ->setSizeGenerator($this->getFontSizeGenerator($input->getOption('font-size-boost')))
            ->useList($list)
        ;

        if ($input->getOption('precise')) {
            $cloudBuilder->setPrecise();
        }

        // Render the cloud and show the bounding boxes and the usher if needed
        $image = $this->render(
            $cloudBuilder,
            $factory,
            $input->getOption('render-usher') ? $placer : null,
            $input->getOption('render-boxes'),
            $input->getOption('render-mask')
        );

        $this->output($image, $input->getOption('format'), $input->getOption('save-to-file'));

        $event = $stopwatch->stop('createCloud');
        return $event;
    }
}