3 namespace Drupal\imagemagick;
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Core\Cache\Cache;
7 use Drupal\Core\Cache\CacheBackendInterface;
8 use Drupal\Core\Config\ConfigFactoryInterface;
9 use Drupal\Core\Config\Schema\SchemaCheckTrait;
10 use Drupal\Core\Config\TypedConfigManagerInterface;
11 use Drupal\Core\StringTranslation\StringTranslationTrait;
14 * Provides the ImageMagick format mapper.
16 class ImagemagickFormatMapper implements ImagemagickFormatMapperInterface {
19 use StringTranslationTrait;
24 * @var \Drupal\Core\Cache\CacheBackendInterface
29 * The MIME type guessing service.
31 * @var \Drupal\imagemagick\MimeTypeMapper
33 protected $mimeTypeMapper;
36 * The config factory service.
38 * @var \Drupal\Core\Config\ConfigFactoryInterface
40 protected $configFactory;
43 * The typed config service.
45 * @var \Drupal\Core\Config\TypedConfigManagerInterface
47 protected $typedConfig;
50 * Constructs an ImagemagickFormatMapper object.
52 * @param \Drupal\Core\Cache\CacheBackendInterface $cache_service
54 * @param \Drupal\imagemagick\ImagemagickMimeTypeMapper $mime_type_mapper
55 * The MIME type mapping service.
56 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
58 * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
59 * The typed config service.
61 public function __construct(CacheBackendInterface $cache_service, ImagemagickMimeTypeMapper $mime_type_mapper, ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typed_config) {
62 $this->cache = $cache_service;
63 $this->mimeTypeMapper = $mime_type_mapper;
64 $this->configFactory = $config_factory;
65 $this->typedConfig = $typed_config;
71 public function validateMap(array $map) {
74 // Get current config object and change the format map.
75 $data = $this->configFactory->get('imagemagick.settings')->get();
76 $data['image_formats'] = $map;
78 // Validates against schema.
79 $schema_errors = $this->checkConfigSchema($this->typedConfig, 'imagemagick.settings', $data);
80 if ($schema_errors !== TRUE) {
81 foreach ($schema_errors as $key => $value) {
82 list(, $path) = explode(':', $key);
83 $components = explode('.', $path);
84 if ($components[0] === 'image_formats') {
85 if (isset($components[2])) {
86 $errors[$components[1]]['variables'][$components[2]][] = $value;
89 $errors[$components[1]]['format'][] = $value;
96 foreach ($map as $key => $value) {
97 if (Unicode::strtoupper($key) != $key) {
98 // Formats must be typed in uppercase.
99 $errors[$key]['format'][] = $this->t("The format (@key) must be entered in all uppercase characters.", ['@key' => $key])->render();
101 if (!isset($value['mime_type'])) {
102 // Formats must have a MIME type mapped.
103 $errors[$key]['format'][] = $this->t("Missing mime_type variable.")->render();
105 elseif (!in_array($value['mime_type'], $this->mimeTypeMapper->getMimeTypes())) {
106 // MIME type must exist.
107 $errors[$key]['variables']['mime_type'][] = $this->t("MIME type (@mime_type) not found.", ['@mime_type' => $value['mime_type']])->render();
117 public function isFormatEnabled($format) {
118 $format = Unicode::strtoupper($format);
119 return $format ? isset($this->resolveEnabledFormats()[$format]) : FALSE;
125 public function getMimeTypeFromFormat($format) {
126 $format = Unicode::strtoupper($format);
127 if ($this->isFormatEnabled($format)) {
128 return $this->resolveEnabledFormats()[$format];
136 public function getFormatFromExtension($extension) {
137 $extension = Unicode::strtolower($extension);
138 $enabled_extensions = $this->resolveEnabledExtensions();
139 return $extension ? (isset($enabled_extensions[$extension]) ? $enabled_extensions[$extension] : NULL) : NULL;
145 public function getEnabledFormats() {
146 return array_keys($this->resolveEnabledFormats());
152 public function getEnabledExtensions() {
153 return array_keys($this->resolveEnabledExtensions());
157 * Returns the enabled image formats, processing the config map.
159 * Results are cached for subsequent access. Saving the config will
160 * invalidate the cache.
163 * An associative array with ImageMagick formats as keys and their MIME
166 protected function resolveEnabledFormats() {
167 if ($cache = $this->cache->get("imagemagick:enabled_formats")) {
168 $enabled_image_formats = $cache->data;
171 $config = $this->configFactory->get('imagemagick.settings');
172 $image_formats = $config->get('image_formats');
173 $enabled_image_formats = [];
174 foreach ($image_formats as $format => $data) {
175 if (!isset($data['enabled']) || (isset($data['enabled']) && $data['enabled'])) {
176 if (isset($data['mime_type']) && in_array($data['mime_type'], $this->mimeTypeMapper->getMimeTypes())) {
177 $enabled_image_formats[$format] = $data['mime_type'];
181 ksort($enabled_image_formats);
182 $this->cache->set("imagemagick:enabled_formats", $enabled_image_formats, Cache::PERMANENT, $config->getCacheTags());
184 return $enabled_image_formats;
188 * Returns the enabled image file extensions, processing the config map.
190 * Results are cached for subsequent access. Saving the config will
191 * invalidate the cache.
194 * An associative array with file extensions as keys and their ImageMagick
197 protected function resolveEnabledExtensions() {
198 if ($cache = $this->cache->get("imagemagick:enabled_extensions")) {
199 $extensions = $cache->data;
202 // Get configured image formats.
203 $image_formats = $this->configFactory->get('imagemagick.settings')->get('image_formats');
205 // Get only enabled formats.
206 $enabled_image_formats = array_keys($this->resolveEnabledFormats());
209 foreach ($enabled_image_formats as $format) {
210 if (isset($image_formats[$format]) && is_array($image_formats[$format])) {
211 $image_formats[$format] += [
214 'exclude_extensions' => NULL,
219 // Scans the enabled formats to determine enabled file extensions and
220 // their mapping to the internal Image/GraphicsMagick format.
222 $excluded_extensions = [];
223 foreach ($enabled_image_formats as $format) {
224 $format_extensions = $this->mimeTypeMapper->getExtensionsForMimeType($image_formats[$format]['mime_type']);
225 $weight_checked_extensions = [];
226 foreach ($format_extensions as $ext) {
227 if (!isset($extensions[$ext])) {
228 $weight_checked_extensions[$ext] = $format;
231 // Extension is already present in the array, lower weight format
233 if ($image_formats[$format]['weight'] < $image_formats[$extensions[$ext]]['weight']) {
234 $weight_checked_extensions[$ext] = $format;
238 $extensions = array_merge($extensions, $weight_checked_extensions);
239 // Accumulate excluded extensions.
240 if ($image_formats[$format]['exclude_extensions']) {
241 $exclude_extensions_string = Unicode::strtolower(preg_replace('/\s+/', '', $image_formats[$format]['exclude_extensions']));
242 $excluded_extensions = array_merge($excluded_extensions, array_intersect($format_extensions, explode(',', $exclude_extensions_string)));
246 // Remove the excluded extensions.
247 $excluded_extensions = array_unique($excluded_extensions);
248 $excluded_extensions = array_combine($excluded_extensions, $excluded_extensions);
249 $extensions = array_diff_key($extensions, $excluded_extensions);
252 $this->cache->set("imagemagick:enabled_extensions", $extensions, Cache::PERMANENT, $this->configFactory->get('imagemagick.settings')->getCacheTags());