Forked from
project / cloudinary
10 commits ahead of the upstream repository.
-
Oleksandr Kuzava authoredOleksandr Kuzava authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
cloudinary.module 15.49 KiB
<?php
/**
* @file
* File for the Cloudinary module.
*/
/**
* Sample file on cloudinary for image effect preview.
*/
use Cloudinary\Transformation\Transformation;
use Drupal\image\Entity\ImageStyle;
/**
* Url prefix of cloudinary preview image.
*/
define('CLOUDINARY_PREVIEW_IMAGE_PREFIX', 'https://res.cloudinary.com/demo/image/upload/');
/**
* Effects for effects param visible states.
*/
define('CLOUDINARY_VISIBLE_STATES_EFFECT', 'sepia,brightness,saturation,hue,oil_paint,vignette,pixelate,pixelate_faces,gradient_fade,blur,tilt_shift,sharpen,unsharp_mask,pixelate_region,red,blue,green,contrast,vibrance,fill_light,blur_region,blur_faces,make_transparent,trim,shadow,colorize');
/**
* Crop mode for gravity visible states.
*/
define('CLOUDINARY_VISIBLE_STATES_CROP', 'fill,crop,thumb,pad,lfill,lpad,mpad');
/**
* Implements hook_theme().
*/
function cloudinary_theme() {
return [
'cloudinary_crop_summary' => [
'variables' => [
'data' => NULL,
],
],
];
}
/**
* Theme function for Cloudinary effect.
*/
function theme_cloudinary_crop_summary($variables) {
$attributes = 'None';
$data = cloudinary_preprocess_transformation($variables['data']);
if (!empty($data)) {
$attribute = [];
foreach ($data as $key => $value) {
if (is_array($value)) {
$value = implode('.', array_filter($value));
}
$attribute[] = "$key: $value";
}
$attributes = implode(', ', $attribute);
}
return t('Image will have cloudinary effects applied with attributes : @attributes', ['@attributes' => $attributes]);
}
/**
* Implements hook_theme_registry_alter().
*/
function cloudinary_theme_registry_alter(&$theme_registry) {
foreach ($theme_registry['image_style_preview']['preprocess functions'] as &$function) {
if ($function == 'template_preprocess_image_style_preview') {
$function = 'cloudinary_preprocess_image_style_preview';
break;
}
}
}
/**
* Returns HTML for a cloudinary preview of an image style.
*
* @ingroup themeable
*/
function cloudinary_preprocess_image_style_preview(&$variables) {
// Style information.
$style = $variables['style'];
$variables['style_id'] = $style->id();
$variables['style_name'] = $style->label();
// Cache bypass token.
$variables['cache_bypass'] = \Drupal::time()->getRequestTime();
// Get sample image path from Cloudinary demo sandbox.
$original = CLOUDINARY_PREVIEW_IMAGE_PREFIX . 'sample.jpg';
// Generate image style for provided sample image.
$data = cloudinary_stream_wrapper_transformation($variables['style_id'], NULL);
$derivative_width = !empty($data['width']) && ($data['width'] > 0) ? $data['width'] : 160;
$derivative_height = !empty($data['height']) && ($data['height'] > 0) ? $data['height'] : 160;
if (empty($data)) {
$data = [];
}
// Unset named transformations since they are specific to Cloudinary accounts,
// and will not work with a demo sandbox.
if (isset($data['transformation'])) {
unset($data['transformation']);
}
$transformation = Transformation::fromParams($data);
$transformation_string = $transformation->toUrl();
if ($transformation_string) {
$transformation_string .= '/';
}
$preview = CLOUDINARY_PREVIEW_IMAGE_PREFIX . $transformation_string . 'sample.jpg';
$variables['derivative']['rendered']['#uri'] = $preview;
$variables['derivative']['url'] = \Drupal::service('file_url_generator')->generateAbsoluteString($preview);
// Sample image info.
$sample_width = 160;
$sample_height = 160;
// Set up original file information.
$variables['original'] = [
'url' => \Drupal::service('file_url_generator')->generateAbsoluteString($original),
'width' => 864,
'height' => 576,
];
if ($variables['original']['width'] > $variables['original']['height']) {
$variables['preview']['original']['width'] = min($variables['original']['width'], $sample_width);
$variables['preview']['original']['height'] = round($variables['preview']['original']['width'] / $variables['original']['width'] * $variables['original']['height']);
}
else {
$variables['preview']['original']['height'] = min($variables['original']['height'], $sample_height);
$variables['preview']['original']['width'] = round($variables['preview']['original']['height'] / $variables['original']['height'] * $variables['original']['width']);
}
// Set up derivative file information.
$variables['derivative'] = [
'url' => \Drupal::service('file_url_generator')->generateAbsoluteString($preview),
'width' => $derivative_width,
'height' => $derivative_height,
];
if ($variables['derivative']['width'] > $variables['derivative']['height']) {
$variables['preview']['derivative']['width'] = min($variables['derivative']['width'], $sample_width);
$variables['preview']['derivative']['height'] = round($variables['preview']['derivative']['width'] / $variables['derivative']['width'] * $variables['derivative']['height']);
}
else {
$variables['preview']['derivative']['height'] = min($variables['derivative']['height'], $sample_height);
$variables['preview']['derivative']['width'] = round($variables['preview']['derivative']['height'] / $variables['derivative']['height'] * $variables['derivative']['width']);
}
// Build the preview of the original image.
$variables['original']['rendered'] = [
'#theme' => 'image',
'#uri' => $original,
'#alt' => t('Sample original image'),
'#title' => '',
'#attributes' => [
'width' => $variables['original']['width'],
'height' => $variables['original']['height'],
'style' => 'width: ' . $variables['preview']['original']['width'] . 'px; height: ' . $variables['preview']['original']['height'] . 'px;',
],
];
// Build the preview of the image style derivative. Timestamps are added
// to prevent caching of images on the client side.
$variables['derivative']['rendered'] = [
'#theme' => 'image',
'#uri' => $variables['derivative']['url'] . '?cache_bypass=' . $variables['cache_bypass'],
'#alt' => t('Sample modified image'),
'#title' => '',
'#attributes' => [
'width' => 'auto',
'height' => 'auto',
'style' => 'width: ' . $variables['preview']['derivative']['width'] . 'px; height: ' . $variables['preview']['derivative']['height'] . 'px;',
],
];
}
/**
* Implements hook_cloudinary_stream_wrapper_transformation().
*/
function cloudinary_cloudinary_stream_wrapper_transformation() {
$path = \Drupal::service('extension.list.module')->getPath('cloudinary');
return [
'cloudinary_crop' => [
'title' => t('Cloudinary crop'),
'callback' => 'cloudinary_transformation_cloudinary_crop',
'file' => $path . '/includes/cloudinary.transformation.cloudinary.inc',
],
'cloudinary_named_transformation' => [
'title' => t('Cloudinary named transformation'),
'callback' => 'cloudinary_transformation_cloudinary_named_transformation',
'file' => $path . '/includes/cloudinary.transformation.cloudinary.inc',
],
'image_crop' => [
'title' => t('Crop'),
'callback' => 'cloudinary_transformation_image_crop',
'file' => $path . '/includes/cloudinary.transformation.drupal.inc',
],
'image_desaturate' => [
'title' => t('Desaturate'),
'callback' => 'cloudinary_transformation_image_desaturate',
],
'image_resize' => [
'title' => t('Resize'),
'callback' => 'cloudinary_transformation_image_resize',
],
'image_rotate' => [
'title' => t('Rotate'),
'callback' => 'cloudinary_transformation_image_rotate',
],
'image_scale' => [
'title' => t('Scale'),
'callback' => 'cloudinary_transformation_image_scale',
],
'image_scale_and_crop' => [
'title' => t('Scale and crop'),
'callback' => 'cloudinary_transformation_image_scale_and_crop',
],
'focal_point_scale_and_crop' => [
'title' => t('Focal Point Scale and Crop'),
'callback' => 'cloudinary_transformation_image_scale_and_crop',
'file' => $path . '/includes/cloudinary.transformation.drupal.inc',
],
];
}
/**
* Convert image effect to special structure for cloudinary style.
*/
function cloudinary_transformation_image($data, $extra = NULL) {
if ($extra) {
if (is_array($extra)) {
$data = array_merge($data, $extra);
}
else {
$data['crop'] = $extra;
}
}
$type = CLOUDINARY_STREAM_WRAPPER_TRANSFORMATION_NEW;
if (isset($data['type'])) {
$type = $data['type'];
unset($data['type']);
}
return ['type' => $type, 'data' => $data];
}
/**
* Ajax callback for cloudinary image preview on effect edit form.
*/
function cloudinary_crop_form_preview_callback($form, $form_state) {
$data = cloudinary_from_image_effect_prepare($form_state['values']['data']);
$form['data']['cloudinary']['preview']['thumbnail']['#markup'] = cloudinary_crop_form_preview($data);
return $form['data']['cloudinary']['preview']['thumbnail'];
}
/**
* Generate cloudinary image preview for effect edit form.
*/
function cloudinary_crop_form_preview($data) {
$filename = 'sample.jpg';
if (isset($data['gravity'])) {
switch ($data['gravity']) {
case 'face':
case 'face:center':
case 'rek_face':
$filename = 'bike.jpg';
break;
case 'faces':
case 'faces:center':
case 'rek_faces':
$filename = 'couple.jpg';
break;
}
}
if (isset($data['effect'])) {
switch ($data['effect']) {
case 'redeye':
case 'rek_redeye':
$filename = 'itaib_redeye_msjmif.jpg';
break;
case 'pixelate_faces':
case 'blur_faces':
$filename = 'couple.jpg';
break;
}
}
$original = CLOUDINARY_PREVIEW_IMAGE_PREFIX . $filename;
$data = cloudinary_prepare_transformation($data);
$transformation = Transformation::fromParams($data);
$transformation_string = $transformation->toUrl();
if ($transformation_string) {
$transformation_string .= '/';
}
$preview = CLOUDINARY_PREVIEW_IMAGE_PREFIX . $transformation_string . $filename;
return [
'#theme' => 'image_style_preview',
'#style' => ImageStyle::load('thumbnail'),
'#original' => $original,
'#preview' => $preview,
];
}
/**
* Prepare cloudinary transformation with attributes.
*
* Return multiple transformations if angle set.
*/
function cloudinary_prepare_transformation($data, $only = TRUE) {
$data = cloudinary_preprocess_transformation($data);
// Rotation Angle.
if (isset($data['angle']) || isset($data['angles'])) {
if (isset($data['crop']) && $data['crop'] != 'crop') {
unset($data['crop']);
}
if (isset($data['angle']) && count($data) > 1) {
$angle = $data['angle'];
unset($data['angle']);
if (isset($data['angles'])) {
$data['angle'] = array_values(array_filter($data['angles']));
unset($data['angles']);
}
$new_data = [$data];
$new_data[] = ['angle' => $angle];
if ($only !== TRUE) {
$new_data['multiple'] = TRUE;
}
return $new_data;
}
}
return $data;
}
/**
* Preprocess cloudinary transformation.
*
* Unset empty value fields.
*
* Merge field value to cloudinary format.
*/
function cloudinary_preprocess_transformation($data) {
$data = array_filter($data);
// Merge border with and border color.
if (isset($data['border_width'])) {
$border = $data['border_width'] . 'px_solid_rgb:';
$border_color = '000';
// Check and convert short #FFFFFF syntax to full #FFF syntax.
if (isset($data['border_color'])) {
$bc = $data['border_color'];
$len = strlen($bc);
if ($len == 7 || $len == 4) {
$border_color = substr($bc, 1);
if ($len == 7 && $bc[0] == $bc[1] && $bc[2] == $bc[3] && $bc[4] == $bc[5]) {
$border_color = $bc[0] . $bc[2] . $bc[4];
}
}
}
// Append border color to border.
$border .= $border_color;
$data['border'] = $border;
// Unset unused attributes.
unset($data['border_width'], $data['border_color']);
}
// Meger effect with effects param.
if (isset($data['effect']) && isset($data['effects_param'])) {
$data['effect'] .= ':' . $data['effects_param'];
}
return $data;
}
/**
* Prepare cloudinary image effect before save.
*/
function cloudinary_from_image_effect_prepare($data) {
// Unset border_color if border_width is empty.
if (empty($data['border_width'])) {
$data['border_color'] = '';
}
// Unset angles if automatic_rotation unchecked.
if (empty($data['automatic_rotation'])) {
$data['angles'] = [];
}
// Unset effects_param if effect doesn't have param.
$effect_param_effects = explode(',', CLOUDINARY_VISIBLE_STATES_EFFECT);
if (!in_array($data['effect'], $effect_param_effects)) {
$data['effects_param'] = '';
}
// Unset gravity if mode doesn't have.
$gravity_corp_modes = explode(',', CLOUDINARY_VISIBLE_STATES_CROP);
if (!in_array($data['crop'], $gravity_corp_modes)) {
$data['gravity'] = '';
}
// Unset x,y if crop mode isn't crop.
if ($data['crop'] != 'crop') {
$data['x'] = $data['y'] = '';
}
return $data;
}
/**
* Build options for corp modes.
*/
function _cloudinary_options_crop($key = NULL) {
$data = [
'' => t('None'),
'scale' => t('Scale'),
'limit' => t('Limit'),
'fill' => t('Fill'),
'fit' => t('Fit'),
'crop' => t('Crop'),
'thumb' => t('Thumb'),
'pad' => t('Pad'),
'lfill' => t('Limited Fill'),
'lpad' => t('Limit & Pad'),
'mfit' => t('Fit (Scale Up)'),
'mpad' => t('Pad (No Scale)'),
'imagga_crop' => t('Imagga crop'),
'imagga_scale' => t('Imagga scale'),
];
if (!is_null($key) && isset($data[$key])) {
return $data[$key];
}
return $data;
}
/**
* Build options for angles.
*/
function _cloudinary_options_angles($key = NULL) {
$data = [
'auto_left' => t('Auto left'),
'auto_right' => t('Auto right'),
'exif' => t('Use EXIF data'),
'hflip' => t('Horizontal flip'),
'ignore' => t('Ignore'),
'vflip' => t('Vertical flip'),
];
if (!is_null($key) && isset($data[$key])) {
return $data[$key];
}
return $data;
}
/**
* Build options for effect.
*/
function _cloudinary_options_effect($key = NULL) {
$data = [
'' => t('None'),
'grayscale' => t('Grayscale'),
'blackwhite' => t('Blackwhite'),
'sepia' => t('Sepia'),
'brightness' => t('Brightness'),
'saturation' => t('Saturation'),
'hue' => t('Hue'),
'oil_paint' => t('Oil paint'),
'vignette' => t('Vignette'),
'pixelate' => t('Pixelate'),
'pixelate_faces' => t('Pixelate faces'),
'gradient_fade' => t('Gradient fade'),
'blur' => t('Blur'),
'improve' => t('Improve'),
'tilt_shift' => t('Tilt shift'),
'sharpen' => t('Sharpen'),
'unsharp_mask' => t('Unsharp mask'),
'pixelate_region' => t('Pixelate region'),
'red' => t('Red'),
'blue' => t('Blue'),
'green' => t('Green'),
'contrast' => t('Contrast'),
'vibrance' => t('Vibrance'),
'auto_color' => t('Auto color'),
'auto_brightness' => t('Auto brightness'),
'auto_contrast' => t('Auto contrast'),
'fill_light' => t('Fill light'),
'blur_region' => t('Blur region'),
'blur_faces' => t('Blur faces'),
'make_transparent' => t('Make transparent'),
'trim' => t('Trim'),
'mask' => t('Mask'),
'shadow' => t('Shadow'),
'negate' => t('Negate'),
'screen' => t('Screen'),
'multiply' => t('Multiply'),
'colorize' => t('Colorize'),
'redeye' => t('Remove red eyes'),
'rek_redeye' => t('ReKognition: Remove red eyes'),
'overlay' => t('Overlay'),
'gamma' => t('Gamma'),
];
if (!is_null($key) && isset($data[$key])) {
return $data[$key];
}
return $data;
}