View source
<?php
namespace Drupal\system\Plugin\ImageToolkit;
use Drupal\Component\Utility\Color;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\ImageToolkit\ImageToolkitBase;
use Drupal\Core\ImageToolkit\ImageToolkitOperationManagerInterface;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class GDToolkit extends ImageToolkitBase {
protected $resource = NULL;
protected $type;
protected $preLoadInfo = NULL;
protected $streamWrapperManager;
protected $fileSystem;
public function __construct(array $configuration, $plugin_id, array $plugin_definition, ImageToolkitOperationManagerInterface $operation_manager, LoggerInterface $logger, ConfigFactoryInterface $config_factory, StreamWrapperManagerInterface $stream_wrapper_manager, FileSystemInterface $file_system) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $operation_manager, $logger, $config_factory);
$this->streamWrapperManager = $stream_wrapper_manager;
$this->fileSystem = $file_system;
}
public function __destruct() {
if (is_resource($this->resource)) {
imagedestroy($this->resource);
}
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('image.toolkit.operation.manager'), $container
->get('logger.channel.image'), $container
->get('config.factory'), $container
->get('stream_wrapper_manager'), $container
->get('file_system'));
}
public function setResource($resource) {
if (!(is_object($resource) && $resource instanceof \GdImage)) {
if (!is_resource($resource) || get_resource_type($resource) != 'gd') {
throw new \InvalidArgumentException('Invalid resource argument');
}
}
$this->preLoadInfo = NULL;
$this->resource = $resource;
return $this;
}
public function getResource() {
if (!(is_resource($this->resource) || is_object($this->resource) && $this->resource instanceof \GdImage)) {
$this
->load();
}
return $this->resource;
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['image_jpeg_quality'] = [
'#type' => 'number',
'#title' => t('JPEG quality'),
'#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
'#min' => 0,
'#max' => 100,
'#default_value' => $this->configFactory
->getEditable('system.image.gd')
->get('jpeg_quality', FALSE),
'#field_suffix' => t('%'),
];
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configFactory
->getEditable('system.image.gd')
->set('jpeg_quality', $form_state
->getValue([
'gd',
'image_jpeg_quality',
]))
->save();
}
protected function load() {
if (!$this
->isValid()) {
return FALSE;
}
$function = 'imagecreatefrom' . image_type_to_extension($this
->getType(), FALSE);
if (function_exists($function) && ($resource = $function($this
->getSource()))) {
$this
->setResource($resource);
if (imageistruecolor($resource)) {
return TRUE;
}
else {
$data = [
'width' => imagesx($resource),
'height' => imagesy($resource),
'extension' => image_type_to_extension($this
->getType(), FALSE),
'transparent_color' => $this
->getTransparentColor(),
'is_temp' => TRUE,
];
if ($this
->apply('create_new', $data)) {
imagecopy($this
->getResource(), $resource, 0, 0, 0, 0, imagesx($resource), imagesy($resource));
imagedestroy($resource);
}
}
return (bool) $this
->getResource();
}
return FALSE;
}
public function isValid() {
return (bool) $this->preLoadInfo || (bool) $this->resource;
}
public function save($destination) {
$scheme = StreamWrapperManager::getScheme($destination);
if ($scheme && $this->streamWrapperManager
->isValidScheme($scheme)) {
$local_wrappers = $this->streamWrapperManager
->getWrappers(StreamWrapperInterface::LOCAL);
if (!isset($local_wrappers[$scheme])) {
$permanent_destination = $destination;
$destination = $this->fileSystem
->tempnam('temporary://', 'gd_');
}
$destination = $this->fileSystem
->realpath($destination);
}
$function = 'image' . image_type_to_extension($this
->getType(), FALSE);
if (!function_exists($function)) {
return FALSE;
}
if ($this
->getType() == IMAGETYPE_JPEG) {
$success = $function($this
->getResource(), $destination, $this->configFactory
->get('system.image.gd')
->get('jpeg_quality'));
}
else {
if (in_array($this
->getType(), [
IMAGETYPE_PNG,
IMAGETYPE_WEBP,
], TRUE)) {
imagealphablending($this
->getResource(), FALSE);
imagesavealpha($this
->getResource(), TRUE);
}
$success = $function($this
->getResource(), $destination);
}
if (isset($permanent_destination) && $success) {
try {
$this->fileSystem
->move($destination, $permanent_destination, FileSystemInterface::EXISTS_REPLACE);
return TRUE;
} catch (FileException $e) {
return FALSE;
}
}
return $success;
}
public function parseFile() {
$data = @getimagesize($this
->getSource());
if ($data && in_array($data[2], static::supportedTypes())) {
$this
->setType($data[2]);
$this->preLoadInfo = $data;
return TRUE;
}
return FALSE;
}
public function getTransparentColor() {
if (!$this
->getResource() || $this
->getType() != IMAGETYPE_GIF) {
return NULL;
}
$transparent = imagecolortransparent($this
->getResource());
if ($transparent >= 0) {
$palette_size = imagecolorstotal($this
->getResource());
if ($palette_size == 0 || $transparent < $palette_size) {
$rgb = imagecolorsforindex($this
->getResource(), $transparent);
unset($rgb['alpha']);
return Color::rgbToHex($rgb);
}
}
return NULL;
}
public function getWidth() {
if ($this->preLoadInfo) {
return $this->preLoadInfo[0];
}
elseif ($res = $this
->getResource()) {
return imagesx($res);
}
else {
return NULL;
}
}
public function getHeight() {
if ($this->preLoadInfo) {
return $this->preLoadInfo[1];
}
elseif ($res = $this
->getResource()) {
return imagesy($res);
}
else {
return NULL;
}
}
public function getType() {
return $this->type;
}
public function setType($type) {
if (in_array($type, static::supportedTypes())) {
$this->type = $type;
}
return $this;
}
public function getMimeType() {
return $this
->getType() ? image_type_to_mime_type($this
->getType()) : '';
}
public function getRequirements() {
$requirements = [];
$info = gd_info();
$requirements['version'] = [
'title' => t('GD library'),
'value' => $info['GD Version'],
];
if (!function_exists('imagefilter') || !function_exists('imagerotate')) {
$requirements['version']['severity'] = REQUIREMENT_WARNING;
$requirements['version']['description'] = t('The GD Library for PHP is enabled, but was compiled without support for functions used by the rotate and desaturate effects. It was probably compiled using the official GD libraries from http://www.libgd.org instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See <a href="http://php.net/manual/book.image.php">the PHP manual</a>.');
}
return $requirements;
}
public static function isAvailable() {
return function_exists('imagegd2');
}
public static function getSupportedExtensions() {
$extensions = [];
foreach (static::supportedTypes() as $image_type) {
$extension = mb_strtolower(image_type_to_extension($image_type, FALSE));
$extensions[] = $extension;
if ($extension === 'jpeg') {
$extensions[] = 'jpg';
$extensions[] = 'jpe';
}
}
return $extensions;
}
public function extensionToImageType($extension) {
if (in_array($extension, [
'jpe',
'jpg',
])) {
$extension = 'jpeg';
}
foreach ($this
->supportedTypes() as $type) {
if (image_type_to_extension($type, FALSE) === $extension) {
return $type;
}
}
return IMAGETYPE_UNKNOWN;
}
protected static function supportedTypes() {
return [
IMAGETYPE_PNG,
IMAGETYPE_JPEG,
IMAGETYPE_GIF,
IMAGETYPE_WEBP,
];
}
}