oont-contents/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php
2025-02-08 15:10:23 +01:00

471 lines
10 KiB
PHP

<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
require_once __DIR__ . '/tiled-gallery-layout.php';
require_once __DIR__ . '/tiled-gallery-shape.php';
require_once __DIR__ . '/tiled-gallery-item.php';
// phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound
/**
* Tiled gallery rectangular layout.
*/
class Jetpack_Tiled_Gallery_Layout_Rectangular extends Jetpack_Tiled_Gallery_Layout {
/**
* The layout type.
*
* @var string
*/
protected $type = 'rectangular';
/**
* The HTML function.
*
* @param array $context - the context array, unused.
* @return string HTML
*/
public function HTML( $context = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$grouper = new Jetpack_Tiled_Gallery_Grouper( $this->attachments );
Jetpack_Tiled_Gallery_Shape::reset_last_shape();
return parent::HTML( array( 'rows' => $grouper->grouped_images ) );
}
}
/**
* Tiled gallery layout columns class.
*/
class Jetpack_Tiled_Gallery_Layout_Columns extends Jetpack_Tiled_Gallery_Layout {
/**
* The layout type.
*
* @var string
*/
protected $type = 'rectangular'; // It doesn't need separate template for now
/**
* The HTML function.
*
* @param array $context - the context array, unused.
* @return string HTML
*/
public function HTML( $context = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$grouper = new Jetpack_Tiled_Gallery_Grouper( $this->attachments, array( 'Three_Columns', 'Two' ) );
return parent::HTML( array( 'rows' => $grouper->grouped_images ) );
}
}
/**
* Gallery layout rectangle alis.
*/
class Jetpack_Tiled_Gallery_Layout_Rectangle extends Jetpack_Tiled_Gallery_Layout_Rectangular {}
/**
* Image grouping and HTML generation logic class.
*/
class Jetpack_Tiled_Gallery_Grouper {
/**
* The margin.
*
* @var int
*/
public $margin = 4;
/**
* Shapes array.
* This list is ordered. If you put a shape that's likely to occur on top, it will happen all the time.
*
* @var array
*/
public $shapes = array(
'Reverse_Symmetric_Row',
'Long_Symmetric_Row',
'Symmetric_Row',
'One_Three',
'Three_One',
'One_Two',
'Five',
'Four',
'Three',
'Two_One',
'Panoramic',
);
/**
* Shape of the last row in gallery.
*
* @var string
*/
public $last_shape = '';
/**
* All images to be displayed.
*
* @var array
*/
public $images = array();
/**
* Array of tiled gallery rows (groups of images).
*
* @var array
*/
public $grouped_images = array();
/**
* Constructor function.
*
* @param object $attachments - the attachments.
* @param array $shapes - the shapes.
*/
public function __construct( $attachments, $shapes = array() ) {
$content_width = Jetpack_Tiled_Gallery::get_content_width();
$this->overwrite_shapes( $shapes );
$this->last_shape = '';
$this->images = $this->get_images_with_sizes( $attachments );
$this->grouped_images = $this->get_grouped_images();
$this->apply_content_width( $content_width );
}
/**
* Overwrite the shapes.
*
* @param array $shapes - the shapes.
*/
public function overwrite_shapes( $shapes ) {
if ( ! empty( $shapes ) ) {
$this->shapes = $shapes;
}
}
/**
* Get the current row size.
*
* @return array
*/
public function get_current_row_size() {
$images_left = is_countable( $this->images ) ? count( $this->images ) : 0;
if ( $images_left < 3 ) {
return array_fill( 0, $images_left, 1 );
}
foreach ( $this->shapes as $shape_name ) {
$class_name = "Jetpack_Tiled_Gallery_$shape_name";
$shape = new $class_name( $this->images );
if ( $shape->is_possible() ) {
Jetpack_Tiled_Gallery_Shape::set_last_shape( $class_name );
return $shape->shape;
}
}
Jetpack_Tiled_Gallery_Shape::set_last_shape( 'Two' );
return array( 1, 1 );
}
/**
* Get images with sizes.
*
* @param object $attachments - the attachments.
*
* @return array
*/
public function get_images_with_sizes( $attachments ) {
$images_with_sizes = array();
foreach ( $attachments as $image ) {
$meta = wp_get_attachment_metadata( $image->ID );
$image->width_orig = ( isset( $meta['width'] ) && $meta['width'] > 0 ) ? $meta['width'] : 1;
$image->height_orig = ( isset( $meta['height'] ) && $meta['height'] > 0 ) ? $meta['height'] : 1;
$image->ratio = $image->width_orig / $image->height_orig;
$image->ratio = $image->ratio ? $image->ratio : 1;
$images_with_sizes[] = $image;
}
return $images_with_sizes;
}
/**
* Get the current row size.
*
* @return array
*/
public function read_row() {
$vector = $this->get_current_row_size();
$row = array();
foreach ( $vector as $group_size ) {
$row[] = new Jetpack_Tiled_Gallery_Group( array_splice( $this->images, 0, $group_size ) );
}
return $row;
}
/**
* Get grouped images.
*
* @return array
*/
public function get_grouped_images() {
$grouped_images = array();
while ( ! empty( $this->images ) ) {
$grouped_images[] = new Jetpack_Tiled_Gallery_Row( $this->read_row() );
}
return $grouped_images;
}
/**
* Apply content width.
*
* @param int $width - the width.
*
* @todo split in functions
* @todo do not stretch images
*/
public function apply_content_width( $width ) {
foreach ( $this->grouped_images as $row ) {
$row->width = $width;
$group_count = is_countable( $row->groups ) ? count( $row->groups ) : 0;
$row->raw_height = 1 / $row->ratio * ( $width - $this->margin * ( $group_count - $row->weighted_ratio ) );
$row->height = round( $row->raw_height );
$this->calculate_group_sizes( $row );
}
}
/**
* Calculate group sizes.
*
* @param object $row - the row.
*/
public function calculate_group_sizes( $row ) {
// Storing the calculated group heights in an array for rounding them later while preserving their sum
// This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
$group_widths_array = array();
foreach ( $row->groups as $group ) {
$group->height = $row->height;
$image_count = is_countable( $group->images ) ? count( $group->images ) : 0;
// Storing the raw calculations in a separate property to prevent rounding errors from cascading down and for diagnostics
$group->raw_width = ( $row->raw_height - $this->margin * $image_count ) * $group->ratio + $this->margin;
$group_widths_array[] = $group->raw_width;
}
$rounded_group_widths_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $group_widths_array, $row->width );
foreach ( $row->groups as $group ) {
$group->width = array_shift( $rounded_group_widths_array );
$this->calculate_image_sizes( $group );
}
}
/**
* Calculate image sizes.
*
* @param object $group - the group of images.
*/
public function calculate_image_sizes( $group ) {
// Storing the calculated image heights in an array for rounding them later while preserving their sum
// This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
$image_heights_array = array();
foreach ( $group->images as $image ) {
$image->width = $group->width - $this->margin;
// Storing the raw calculations in a separate property for diagnostics
$image->raw_height = ( $group->raw_width - $this->margin ) / $image->ratio;
$image_heights_array[] = $image->raw_height;
}
$image_height_sum = $group->height - count( $image_heights_array ) * $this->margin;
$rounded_image_heights_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $image_heights_array, $image_height_sum );
foreach ( $group->images as $image ) {
$image->height = array_shift( $rounded_image_heights_array );
}
}
}
/**
* Jetpack tiled row class.
*/
class Jetpack_Tiled_Gallery_Row {
/**
* Groups of images
*
* @var object[]
*/
public $groups;
/**
* Image ratio.
*
* @var float
*/
public $ratio;
/**
* Weighted ratio based on all the images.
*
* @var float
*/
public $weighted_ratio;
/**
* Rounded value of the raw width.
*
* @var int
*/
public $width;
/**
* Rounded value of the raw height.
*
* @var int
*/
public $height;
/**
* Raw width of the row.
*
* @var int
*/
public $raw_width;
/**
* Raw height of the row.
*
* @var int
*/
public $raw_height;
/**
* Constructor class.
*
* @param object[] $groups - the group of images.
*/
public function __construct( $groups ) {
$this->groups = $groups;
$this->ratio = $this->get_ratio();
$this->weighted_ratio = $this->get_weighted_ratio();
}
/**
* Get the ratio.
*
* @return float
*/
public function get_ratio() {
$ratio = 0;
foreach ( $this->groups as $group ) {
$ratio += $group->ratio;
}
return $ratio > 0 ? $ratio : 1;
}
/**
* Get weighted ratio.
*
* @return float
*/
public function get_weighted_ratio() {
$weighted_ratio = 0;
foreach ( $this->groups as $group ) {
$image_count = is_countable( $group->images ) ? count( $group->images ) : 0;
$weighted_ratio += $group->ratio * $image_count;
}
return $weighted_ratio > 0 ? $weighted_ratio : 1;
}
}
/**
* Tiled gallery group class.
*/
class Jetpack_Tiled_Gallery_Group {
/**
* Images to be displayed in group.
*
* @var object[]
*/
public $images;
/**
* Image ratio.
*
* @var float
*/
public $ratio;
/**
* Rounded value of the raw width.
*
* @var int
*/
public $width;
/**
* Rounded value of the raw height.
*
* @var int
*/
public $height;
/**
* Raw width of the group.
*
* @var int
*/
public $raw_width;
/**
* Raw height of the group.
*
* @var int
*/
public $raw_height;
/**
* Constructor class.
*
* @param object[] $images - the images.
*/
public function __construct( $images ) {
$this->images = $images;
$this->ratio = $this->get_ratio();
}
/**
* Get the ratio.
*
* @return float
*/
public function get_ratio() {
$ratio = 0;
foreach ( $this->images as $image ) {
if ( $image->ratio ) {
$ratio += 1 / $image->ratio;
}
}
if ( ! $ratio ) {
return 1;
}
return 1 / $ratio;
}
/**
* The items.
*
* @param string $needs_attachment_link - the attachment link.
* @param bool $grayscale - if the image is in grayscale.
*
* @return array
*/
public function items( $needs_attachment_link, $grayscale ) {
$items = array();
foreach ( $this->images as $image ) {
$items[] = new Jetpack_Tiled_Gallery_Rectangular_Item( $image, $needs_attachment_link, $grayscale );
}
return $items;
}
}