protected function GDOperationTrait::getEntropyCropByGridding in Image Effects 8.3
Same name and namespace in other branches
- 8 src/Plugin/ImageToolkit/Operation/gd/GDOperationTrait.php \Drupal\image_effects\Plugin\ImageToolkit\Operation\gd\GDOperationTrait::getEntropyCropByGridding()
- 8.2 src/Plugin/ImageToolkit/Operation/gd/GDOperationTrait.php \Drupal\image_effects\Plugin\ImageToolkit\Operation\gd\GDOperationTrait::getEntropyCropByGridding()
Computes the entropy crop of an image, using recursive gridding.
Parameters
resource $src: The source image resource.
string $crop_width: The width of the crop.
string $crop_height: The height of the crop.
bool $simulate: If TRUE, the crop will be simulated, and image markers will be overlaid on the source image.
int $grid_width: The maximum width of the sub-grid window.
int $grid_height: The maximum height of the sub-grid window.
int $grid_rows: The number of rows of the sub-grid.
int $grid_columns: The number of columns of the sub-grid.
int $grid_sub_rows: The number of rows of the sub-grid for the sum calculation.
int $grid_sub_columns: The number of columns of the sub-grid for the sum calculation.
Return value
\Drupal\image_effects\Component\PositionedRectangle The PositionedRectangle object marking the crop area.
2 calls to GDOperationTrait::getEntropyCropByGridding()
- SmartCrop::execute in src/
Plugin/ ImageToolkit/ Operation/ imagemagick/ SmartCrop.php - SmartCrop::execute in src/
Plugin/ ImageToolkit/ Operation/ gd/ SmartCrop.php - Performs the actual manipulation on the image.
File
- src/
Plugin/ ImageToolkit/ Operation/ gd/ GDOperationTrait.php, line 499
Class
- GDOperationTrait
- Trait for GD image toolkit operations.
Namespace
Drupal\image_effects\Plugin\ImageToolkit\Operation\gdCode
protected function getEntropyCropByGridding($src, $crop_width, $crop_height, $simulate, $grid_width, $grid_height, $grid_rows, $grid_columns, $grid_sub_rows, $grid_sub_columns) {
// Source image data.
$source_rect = new PositionedRectangle(imagesx($src), imagesy($src));
$source_image_aspect = imagesy($src) / imagesx($src);
// If simulating, create an image serving as the layer for the visual
// markers.
if ($simulate) {
// @todo when #2583041 is committed, add a check for memory
// availability before creating the resource.
$marker_layer_resource = imagecreatetruecolor(imagesx($src), imagesy($src));
imagefill($marker_layer_resource, 0, 0, imagecolorallocatealpha($marker_layer_resource, 0, 0, 0, 127));
}
// Determine dimensions of the grid window. The window dimensions are
// limited to reduce entropy compared to the source. It needs to respect the
// aspect ratio of the source image.
if ($source_image_aspect < $grid_height / $grid_width) {
$grid_height = (int) round($grid_width * $source_image_aspect);
}
else {
$grid_width = (int) round($grid_height / $source_image_aspect);
}
// Analyse the grid window to find the highest entropy sub-grid. Loop until
// the window size is smaller than the crop area, nesting sub-windows.
$window_nesting = 0;
$window_x_offset = 0;
$window_y_offset = 0;
$window_width = imagesx($src);
$window_height = imagesy($src);
while ($window_width > $crop_width || $window_height > $crop_height) {
// Determine the working size of the grid window. Resample the source
// image grid area into the grid window, if it is bigger than the bounds
// given.
if ($window_width >= $grid_width && $window_height >= $grid_height) {
$work_window_width = $grid_width;
$work_window_height = $grid_height;
}
else {
$work_window_width = $window_width;
$work_window_height = $window_height;
}
// If the grid window is smaller than the matrix, it does not make sense
// to dig deeper.
if ($work_window_width < $grid_columns || $work_window_height < $grid_rows) {
break;
}
// Add a grid to the source image rectangle.
$source_rect
->addGrid('grid_' . $window_nesting, $window_x_offset, $window_y_offset, $window_width, $window_height, $grid_rows, $grid_columns);
// Create the grid window.
$grid_rect = new PositionedRectangle($work_window_width, $work_window_height);
$grid_rect
->addGrid('grid_0', 0, 0, $work_window_width, $work_window_height, $grid_rows, $grid_columns);
// @todo when #2583041 is committed, add a check for memory
// availability before creating the resource.
$grid_resource = imagecreatetruecolor($work_window_width, $work_window_height);
imagefill($grid_resource, 0, 0, imagecolorallocatealpha($grid_resource, 0, 0, 0, 127));
imagecopyresampled($grid_resource, $src, 0, 0, $window_x_offset, $window_y_offset, $work_window_width, $work_window_height, $window_width, $window_height);
// Build the entropy matrix of the window.
$entropy_matrix = [];
for ($row = 0; $row < $grid_rows; $row++) {
for ($column = 0; $column < $grid_columns; $column++) {
$cell_top_left = $grid_rect
->getPoint('grid_0_' . $row . '_' . $column);
$cell_dimensions = $grid_rect
->getSubGridDimensions('grid_0', $row, $column, 1, 1);
$entropy_matrix[$row][$column] = $this
->getAreaEntropy($grid_resource, $cell_top_left[0], $cell_top_left[1], $cell_dimensions[0], $cell_dimensions[1]);
}
}
// Find the sub-matrix that has the highest entropy sum.
$entropy_sum_matrix = MatrixUtility::cumulativeSum($entropy_matrix);
$max_sum_position = MatrixUtility::findMaxSumSubmatrix($entropy_sum_matrix, $grid_sub_rows, $grid_sub_columns);
// Position the highest entropy sub-matrix on the source image.
list($window_x_offset, $window_y_offset) = $source_rect
->getPoint('grid_' . $window_nesting . '_' . $max_sum_position[0] . '_' . $max_sum_position[1]);
list($window_width, $window_height) = $source_rect
->getSubGridDimensions('grid_' . $window_nesting, $max_sum_position[0], $max_sum_position[1], $grid_sub_rows, $grid_sub_columns);
if ($simulate) {
switch ($window_nesting % 3) {
case 0:
$color = imagecolorallocatealpha($marker_layer_resource, 255, 0, 0, 0);
break;
case 1:
$color = imagecolorallocatealpha($marker_layer_resource, 0, 255, 255, 0);
break;
case 2:
$color = imagecolorallocatealpha($marker_layer_resource, 255, 255, 0, 0);
break;
}
// Add grid points on marker layer.
for ($row = 0; $row <= $grid_rows; $row++) {
for ($column = 0; $column <= $grid_columns; $column++) {
$coord = $source_rect
->getPoint('grid_' . $window_nesting . '_' . $row . '_' . $column);
imagefilledellipse($marker_layer_resource, $coord[0], $coord[1], 6, 6, $color);
}
}
// Polygon on marker layer.
$rect = new PositionedRectangle($window_width, $window_height);
$rect
->translate([
$window_x_offset,
$window_y_offset,
]);
$rect
->translate([
-2,
-2,
]);
for ($i = -2; $i <= 2; $i++) {
imagepolygon($marker_layer_resource, $this
->getRectangleCorners($rect), 4, $color);
$rect
->translate([
1,
1,
]);
}
}
// Destroy the window.
imagedestroy($grid_resource);
$window_nesting++;
}
// Overlay marker layer onto source at 70% transparency.
if ($simulate) {
$this
->imageCopyMergeAlpha($src, $marker_layer_resource, 0, 0, 0, 0, imagesx($src), imagesy($src), 70);
imagedestroy($marker_layer_resource);
}
// Determine the Rectangle containing the crop.
$window_x_center = $window_x_offset + (int) ($window_width / 2);
$window_y_center = $window_y_offset + (int) ($window_height / 2);
$crop_x_offset = $window_x_center - (int) ($crop_width / 2);
$crop_y_offset = $window_y_center - (int) ($crop_height / 2);
$rect = new PositionedRectangle($crop_width, $crop_height);
$rect
->translate([
$crop_x_offset,
$crop_y_offset,
]);
if ($crop_x_offset < 0) {
$rect
->translate([
-$crop_x_offset,
0,
]);
}
if ($crop_y_offset < 0) {
$rect
->translate([
0,
-$crop_y_offset,
]);
}
if ($crop_x_offset + $crop_width > imagesx($src)) {
$rect
->translate([
-($crop_x_offset + $crop_width - imagesx($src)),
0,
]);
}
if ($crop_y_offset + $crop_height > imagesy($src)) {
$rect
->translate([
0,
-($crop_y_offset + $crop_height - imagesy($src)),
]);
}
return $rect;
}