-
Notifications
You must be signed in to change notification settings - Fork 452
/
SvgIconRasterizer.php
165 lines (149 loc) · 6.13 KB
/
SvgIconRasterizer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<?php
namespace Concrete\Core\Package\Packer\Filter;
use Concrete\Core\File\Service\VolatileDirectory;
use Concrete\Core\Package\Packer\PackerFile;
use Illuminate\Filesystem\Filesystem;
use RuntimeException;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Generate bitmap icons starting from source SVG icons.
*/
class SvgIconRasterizer implements FilterInterface
{
/**
* The concrete5 version for which the bitmap icons should be created for.
*
* @var string
*/
protected $coreVersion;
/**
* Should the bitmap icons be created only if they don't exist, or if they are older than the source SVG files?
*
* @var bool
*/
protected $checkEditDate;
/**
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;
/**
* @var \Concrete\Core\File\Service\VolatileDirectory
*/
protected $volatileDirectory;
/**
* @var \Illuminate\Filesystem\Filesystem
*/
protected $fs;
/**
* Initialize the instance.
*
* @param string $coreVersion the concrete5 version for which the bitmap icons should be created for
* @param bool $checkEditDate set to true if the bitmap icons should be created only if they don't exist, or if they are older than the source SVG files
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @param \Concrete\Core\File\Service\VolatileDirectory $volatileDirectory
* @param \Illuminate\Filesystem\Filesystem $fs
*/
public function __construct($coreVersion, $checkEditDate, OutputInterface $output, VolatileDirectory $volatileDirectory, Filesystem $fs)
{
$this->coreVersion = $coreVersion;
$this->checkEditDate = (bool) $checkEditDate;
$this->output = $output;
$this->volatileDirectory = $volatileDirectory;
$this->fs = $fs;
}
/**
* {@inheritdoc}
*
* @see \Concrete\Core\Package\Packer\Filter\FilterInterface::apply()
*/
public function apply(PackerFile $file)
{
if (!$file->isDirectory()) {
return [$file];
}
$bitmapData = $this->getBitmapData($file);
if ($bitmapData === null) {
return [$file];
}
if ($this->checkEditDate) {
if ($this->isBitmapNewerThanSVG($file, $bitmapData)) {
if ($this->output->getVerbosity() >= OutputInterface::OUTPUT_NORMAL) {
$this->output->writeln(t("Skipping generation of bitmap icon for file %s because it's newer than the vector icon", $file->getRelativePath()));
}
return [$file];
}
}
if ($this->output->getVerbosity() >= OutputInterface::OUTPUT_NORMAL) {
$this->output->writeln(t('Generating the bitmap icon from the vector file %s', $file->getRelativePath()));
}
$newFileAbs = $this->createBitmap($file, $bitmapData);
$bitmapRelativePath = $file->getRelativePathWithExtension($bitmapData['extension']);
return [$file, PackerFile::newlyCreatedFile($newFileAbs, $bitmapRelativePath)];
}
/**
* Get the details of the bitmap data to be generated for a file.
*
* @param \Concrete\Core\Package\Packer\PackerFile $file
*
* @return array|null return an array with keys ['extension', 'width', 'height'] if there's a bitmap file associated to the file, NULL otherwise
*/
protected function getBitmapData(PackerFile $file)
{
switch ($file->getType()) {
case PackerFile::TYPE_SVGICON_BLOCKTYPE:
return version_compare($this->coreVersion, '5.7') < 0 ? ['extension' => 'png', 'width' => 16, 'height' => 16] : ['extension' => 'png', 'width' => 50, 'height' => 50];
case PackerFile::TYPE_SVGICON_PACKAGE:
return version_compare($this->coreVersion, '5.7') < 0 ? ['extension' => 'png', 'width' => 97, 'height' => 97] : ['extension' => 'png', 'width' => 200, 'height' => 200];
case PackerFile::TYPE_SVGICON_THEME:
return ['extension' => 'png', 'width' => 120, 'height' => 90];
default:
return null;
}
}
/**
* Check if there's already a bitmap file, and that it's not older than the SVG file.
*
* @param \Concrete\Core\Package\Packer\PackerFile $file the SVG file
* @param array $bitmapData the result of the getBitmapData() method
*
* @return bool return true if the bitmap file already exists and it's newer than the SVG file
*/
protected function isBitmapNewerThanSVG(PackerFile $file, array $bitmapData)
{
$bitmapFile = $file->getAbsolutePathWithExtension($bitmapData['extension']);
if (!$this->fs->isFile($bitmapFile)) {
return false;
}
$svgTimestamp = $this->fs->lastModified($file->getAbsolutePath());
$bitmapTimestamp = $this->fs->lastModified($bitmapFile);
return $svgTimestamp && $bitmapTimestamp && $svgTimestamp < $bitmapTimestamp;
}
/**
* Create the bitmap associated to an SVG file.
*
* @param \Concrete\Core\Package\Packer\PackerFile $sourceFile the SVG file
* @param array $bitmapData the result of the getBitmapData() method
*
* @throws \RuntimeException
*
* @return string
*/
protected function createBitmap(PackerFile $sourceFile, array $bitmapData)
{
$bitmapPath = tempnam($this->volatileDirectory->getPath(), 'ico');
$cmd = 'inkscape';
$cmd .= ' --file=' . escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $sourceFile->getAbsolutePath()));
$cmd .= ' --export-' . $bitmapData['extension'] . '=' . escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $bitmapPath));
$cmd .= ' --export-area-page';
$cmd .= ' --export-width=' . $bitmapData['width'];
$cmd .= ' --export-height=' . $bitmapData['height'];
$cmd .= ' 2>&1';
$output = [];
$rc = -1;
@exec($cmd, $output, $rc);
if ($rc !== 0) {
throw new RuntimeException(t('Error invoking inkscape to rasterize an image: %s', trim(implode("\n", $output))), $rc);
}
return $bitmapPath;
}
}