You are here

animated_gif.module in Animated GIF 8

File

animated_gif.module
View source
<?php

/**
 * @file
 * Contains hook implementations for animated_gif module.
 */
declare (strict_types=1);
use Drupal\file\Entity\File;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements template_preprocess_image_formatter().
 */
function animated_gif_preprocess_image_formatter(&$variables) {
  $image = $variables['item'];
  $imageValues = $image
    ->getValue();
  $file = File::load($imageValues['target_id']);
  if ($file && $file
    ->getMimeType() === 'image/gif' && _animated_gif_is_animated($file
    ->getFileUri())) {
    $variables['image']['#theme'] = 'image';
    unset($variables['image']['#style_name']);
    unset($variables['image_style']);
  }
}

/**
 * Implements template_preprocess_responsive_image_formatter().
 */
function animated_gif_preprocess_responsive_image_formatter(&$variables) {
  $image = $variables['item'];
  $imageValues = $image
    ->getValue();
  $file = File::load($imageValues['target_id']);
  if ($file && $file
    ->getMimeType() === 'image/gif' && _animated_gif_is_animated($file
    ->getFileUri())) {
    $variables['responsive_image']['#theme'] = 'image';
    unset($variables['image']['#responsive_image_style_id']);
    unset($variables['image_style']);
  }
}

/**
 * Implements template_preprocess_image_style().
 */
function animated_gif_preprocess_image_style(&$variables) {

  // File entity ID is not available here so we need to load it by URI.
  $files = \Drupal::entityTypeManager()
    ->getStorage('file')
    ->loadByProperties([
    'uri' => $variables['uri'],
  ]);
  if (empty($files)) {
    return;
  }

  /** @var \Drupal\file\FileInterface $file */
  $file = reset($files);
  if ($file
    ->getMimeType() === 'image/gif' && _animated_gif_is_animated($file
    ->getFileUri())) {
    $variables['image']['#uri'] = $variables['uri'];
    unset($variables['image']['#style_name']);
    unset($variables['image_style']);
    unset($variables['style_name']);
  }
}

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function animated_gif_field_widget_image_image_form_alter(&$element, FormStateInterface $form_state, $context) {
  if (!empty($element['#default_value']['fids'])) {
    $fid = reset($element['#default_value']['fids']);
    $file = File::load($fid);
    if ($file && $file
      ->getMimeType() === 'image/gif' && _animated_gif_is_animated($file
      ->getFileUri())) {
      $element[] = [
        '#type' => 'container',
        '#markup' => t('GIF images are not being processed by image styles, use with caution!'),
        '#attributes' => [
          'class' => [
            'messages',
            'messages--warning',
          ],
        ],
      ];
    }
  }
}

/**
 * Helper method to know if a gif image is animated.
 *
 * @param string $fileUri
 *   The uri file.
 *
 * @return bool
 *   Return true if file contains multiple "frames".
 *
 * @SuppressWarnings(PHPMD.ErrorControlOperator)
 */
function _animated_gif_is_animated(string $fileUri) : bool {
  $fopen = @fopen($fileUri, 'rb');
  if (!$fopen) {
    return FALSE;
  }
  $count = 0;

  // An animated gif contains multiple "frames", with each frame having a
  // header made up of:
  // * a static 4-byte sequence (\x00\x21\xF9\x04)
  // * 4 variable bytes
  // * a static 2-byte sequence (\x00\x2C)
  // We read through the file til we reach the end of the file, or we've found
  // at least 2 frame headers.
  while (!feof($fopen) && $count < 2) {

    // Read 100kb at a time.
    $chunk = fread($fopen, 1024 * 100);
    $count += preg_match_all('#\\x00\\x21\\xF9\\x04.{4}\\x00[\\x2C\\x21]#s', (string) $chunk);
  }
  fclose($fopen);
  return $count > 1;
}