Problem/Motivation

This is not urgent in any way, just something I was thinking about a bit.

I don't know how common my scenario is, but I added the module to a project with quite a few existing image styles and I didn't really know about their aspect ratio upfront. I ended up writing a small script that give me that information.

But it is still a lot of clicking and editing existing images styles. With existing image styles, most of the time you just want to add the manual crop effect to N image styles.

Proposed resolution

When creating a crop type, show a list of image styles, with their estimated size and aspect ratio of that. See my quick script below. It's not too reliable as the result depends on the original size when the image style is only scaling and not cropping. But it's a useful overview at what kind of image styles you have. Showing the size also gives you an idea what to use for hard/soft limit.

Those image styles could even be checkboxes, and enabling them would automatically add an effect in the first position that does manual cropping with the new crop type.

Thoughts?

use Drupal\image\Entity\ImageStyle;

$styles = ImageStyle::loadMultiple();

function getGCDBetween($a, $b)
{
  while ($b != 0)
  {
    $m = $a % $b;
    $a = $b;
    $b = $m;
  }
  return $a;
}


foreach ($styles as $style) {
  $dimensions = ['width' => 1280, 'height' => 720];
  $style->transformDimensions($dimensions, 'public://example.jpg');
  print $style->id() . ": ${dimensions['width']} x ${dimensions['height']}\n";

  $gcd = getGCDBetween($dimensions['width'], $dimensions['height']);

  print "GCD: $gcd\n";

  print "Aspect ratio: " . $dimensions['width'] / $gcd . " : " . $dimensions['height'] / $gcd . "\n\n";

}

Remaining tasks

User interface changes

API changes

Data model changes

Comments

Berdir created an issue. See original summary.

slashrsm’s picture

Issue tags: +Media Initiative, +D8Media

This would be very nice UX improvement.

woprrr’s picture

In IWC that calculation is used in (OLD) version (why not migrate this in CROP API ?)


  /**
   * Parse the effect into one image style and get the sizes data.
   *
   * @param \Drupal\image\Entity\ImageStyle $image_style
   *   The image style.
   *
   * @return array<integer>|NULL
   *   The data dimensions (width & height) into this ImageStyle.
   */
  public function getImageStyleSizes(ImageStyle $image_style) {
    foreach ($image_style->getEffects() as $effect) {
      /** @var \Drupal\image\ImageEffectInterface $effect */
      if ($effect->getPluginId() != 'image_widget_crop_crop') {
        $data = $effect->getConfiguration()['data'];
        if (isset($data) && (isset($data['width']) && isset($data['height']))) {
          $sizes = [
            'width' => (int) $data['width'],
            'height' => (int) $data['height']
          ];
          return $sizes;
        }
      }
    }
  }

  /**
   * Gets crop's size.
   *
   * @param \Drupal\image\Entity\ImageStyle $image_style
   *   The image style.
   *
   * @return string|NULL
   *   The ratio to the lowest common denominator.
   */
  public function getSizeRatio(ImageStyle $image_style) {
    // Get the properties of this ImageStyle.
    $properties = $this->getImageStyleSizes($image_style);
    if (isset($properties) && (!empty($properties['width']) || !empty($properties['height']))) {
      $gcd = $this->calculateGCD($properties['width'], $properties['height']);
      if (!empty($gcd) && $gcd != '1') {
        return round($properties['width'] / $gcd) . ':' . round($properties['height'] / $gcd);
      }
      // When you have a non-standard size ratio,
      // is not displayed the lowest common denominator.
      if (!empty($gcd)) {
        return $properties['width'] . ':' . $properties['height'];
      }
      // If you not have an available ratio return an free aspect ratio.
      return '0:0';
    }
  }

  /**
   * Calculate the greatest common denominator of two numbers.
   *
   * @param int $a
   *   First number to check.
   * @param int $b
   *   Second number to check.
   *
   * @return integer|null
   *  Greatest common denominator of $a and $b.
   */
  private static function calculateGCD($a, $b) {
    if (extension_loaded('gmp_gcd')) {
      $gcd = gmp_intval(gmp_gcd($a, $b));
    }
    else {
      if ($b > $a) {
        $gcd = self::calculateGCD($b, $a);
      }
      else {
        while ($b > 0) {
          $t = $b;
          $b = $a % $b;
          $a = $t;
        }
        $gcd = $a;
      }
    }
    return $gcd;
  }

This can be used to all modules implement CROP API to determine the aspect ration / sizes of image style. (An test onto gmp_gcd because that is an old version of IWC, after a small benchmark i ve seen gmp_gcd are slower to while (0010sec)

woprrr’s picture

Hi there !! I continue this interesting subject now

What we want for this UI ? finally we need to reformat the list of crop types and add additional information (hard/soft limits ratio estimation whatever you dream :D ... )? We already have the "Used in" which has been added during the sprint IWC which gives good information about where the type crops are used.

The idea of ​​estimating the ratio seems to me really a very interesting feature, but how identify an aspect ratio provide by Crop type field and estimated ratio (visually?). In any case I think it is necessary at first to proceed to a conversion of \Drupal\crop\CropTypeListBuilder Views to be able to then use handlers for more flexibility and customization about any need by the SiteBuilders. What's your opinion about that ? Can I create a parent issue to convert ListBuilder to view and after define what you really want for this Feature request ?

@Berdir we can purpose a service/drush command to have somes informations about crops usages.