- >
+
+ for($i = 0; $i < sizeof($optConf); $i++) {
+ $lineChunksNum = $optConf[$i];
+ $lineThumbs = [];
+ for($j = 0; $j < $lineChunksNum; $j++)
+ $lineThumbs[] = array_shift($thumbsRemain);
+
+ $lineHeight = $optHeights[$i];
+ $totalHeight += $lineHeight;
+
+ $result->rowSizes[$i] = ceil($lineHeight);
+
+ $totalWidth = 0;
+ $row = [];
+ for($j = 0; $j < sizeof($lineThumbs); $j++) {
+ $thumbRatio = array_shift($ratiosRemain);
+ if($j == sizeof($lineThumbs) - 1)
+ $w = $maxWidth - $totalWidth;
+ else
+ $w = $thumbRatio * $lineHeight;
+
+ $totalWidth += ceil($w);
+ if($j < (sizeof($lineThumbs) - 1) && !in_array($totalWidth, $gridLineOffsets))
+ $gridLineOffsets[] = $totalWidth;
+
+ $tile = new ThumbTile(1, 1, $w, $lineHeight);
+ $result->tiles[$k++] = $row[] = $tile;
+ }
+
+ $result->rowTiles[] = $row;
+ }
+
+ sort($gridLineOffsets, SORT_NUMERIC);
+ $gridLineOffsets[] = $maxWidth;
+
+ $result->colSizes = [$gridLineOffsets[0]];
+ for($i = sizeof($gridLineOffsets) - 1; $i > 0; $i--)
+ $result->colSizes[$i] = $gridLineOffsets[$i] - $gridLineOffsets[$i - 1];
+
+ foreach($rowTiles as $row) {
+ $columnOffset = 0;
+ foreach($row as $tile) {
+ $startColumn = $columnOffset;
+ $width = 0;
+ $tile->colSpan = 0;
+ for($i = $startColumn; $i < sizeof($result->colSizes); $i++) {
+ $width += $result->colSizes[$i];
+ $tile->colSpan++;
+ if($width == $tile->width)
+ break;
+ }
+
+ $columnOffset += $tile->colSpan;
+ }
+ }
+
+ $result->height = ceil($totalHeight + $marginHeight * (sizeof($optHeights) - 1));
+ break;
+ }
+
+ return $result;
+ }
+}
diff --git a/Web/Util/Makima/MasonryLayout.php b/Web/Util/Makima/MasonryLayout.php
new file mode 100644
index 00000000..b23aa483
--- /dev/null
+++ b/Web/Util/Makima/MasonryLayout.php
@@ -0,0 +1,10 @@
+width, $this->height, $this->rowSpan, $this->colSpan] = [ceil($w), ceil($h), $rs, $cs];
+ }
+}
diff --git a/Web/static/css/style.css b/Web/static/css/style.css
index 0750f2f8..0822a786 100644
--- a/Web/static/css/style.css
+++ b/Web/static/css/style.css
@@ -651,6 +651,12 @@ h4 {
image-rendering: -webkit-optimize-contrast;
}
+.post-content .media_makima {
+ width: calc(100% - 4px);
+ height: calc(100% - 4px);
+ object-fit: cover;
+}
+
.post-signature {
margin: 4px;
margin-bottom: 2px;
- {include "../attachment.xml", attachment => $attachment}
+ {var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320}
+ {if isset($GLOBALS["_nesAttGloCou"])}
+ {var $width = $width - 70 * $GLOBALS["_nesAttGloCou"]}
+ {/if}
+ {var $attachmentsLayout = $post->getChildrenWithLayout($width)}
+
diff --git a/Web/Util/Makima/Makima.php b/Web/Util/Makima/Makima.php
new file mode 100644
index 00000000..34097c0d
--- /dev/null
+++ b/Web/Util/Makima/Makima.php
@@ -0,0 +1,305 @@
+photos = $photos;
+ }
+
+ private function getOrientation(Photo $photo, &$ratio): int
+ {
+ [$width, $height] = $photo->getDimensions();
+ $ratio = $width / $height;
+ if($ratio >= 1.2)
+ return Makima::ORIENT_WIDE;
+ else if($ratio >= 0.8)
+ return Makima::ORIENT_REGULAR;
+ else
+ return Makima::ORIENT_SLIM;
+ }
+
+ private function calculateMultiThumbsHeight(array $ratios, float $w, float $h, float $m): float
+ {
+ return ($w - (sizeof($ratios) - 1) * $m) / array_sum($ratios);
+ }
+
+ private function extractSubArr(array $arr, int $from, int $to): array
+ {
+ return array_slice($arr, $from, sizeof($arr) - $from - (sizeof($arr) - $to));
+ }
+
+ function computeMasonryLayout(float $maxWidth, float $maxHeight): MasonryLayout
+ {
+ $orients = [];
+ $ratios = [];
+ $count = sizeof($this->photos);
+ $result = new MasonryLayout;
+
+ foreach($this->photos as $photo) {
+ $orients[] = $this->getOrientation($photo, $ratio);
+ $ratios[] = $ratio;
+ }
+
+ $avgRatio = array_sum($ratios) / sizeof($ratios);
+ if($maxWidth < 0)
+ $maxWidth = $maxHeight = 510;
+
+ $maxRatio = $maxWidth / $maxHeight;
+ $marginWidth = $marginHeight = 2;
+
+ switch($count) {
+ case 2:
+ if(
+ $orients == [Makima::ORIENT_WIDE, Makima::ORIENT_WIDE] # two wide pics
+ && $avgRatio > (1.4 * $maxRatio) && abs($ratios[0] - $ratios[1]) < 0.2 # that can be positioned on top of each other
+ ) {
+ $computedHeight = ceil( min( $maxWidth / $ratios[0], min( $maxWidth / $ratios[1], ($maxHeight - $marginHeight) / 2 ) ) );
+
+ $result->colSizes = [1];
+ $result->rowSizes = [1, 1];
+ $result->width = ceil($maxWidth);
+ $result->height = $computedHeight;
+ $result->tiles = [new ThumbTile(1, 1, $maxWidth, $computedHeight), new ThumbTile(1, 1, $maxWidth, $computedHeight)];
+ } else if(
+ $orients == [Makima::ORIENT_WIDE, Makima::ORIENT_WIDE]
+ || $orients == [Makima::ORIENT_REGULAR, Makima::ORIENT_REGULAR] # two normal pics of same ratio
+ ) {
+ $computedWidth = ($maxWidth - $marginWidth) / 2;
+ $height = min( $computedWidth / $ratios[0], min( $computedWidth / $ratios[1], $maxHeight ) );
+
+ $result->colSizes = [1, 1];
+ $result->rowSizes = [1];
+ $result->width = ceil($maxWidth);
+ $result->height = ceil($height);
+ $result->tiles = [new ThumbTile(1, 1, $computedWidth, $height), new ThumbTile(1, 1, $computedWidth, $height)];
+ } else /* next to each other, different ratios */ {
+ $w0 = (
+ ($maxWidth - $marginWidth) / $ratios[1] / ( (1 / $ratios[0]) + (1 / $ratios[1]) )
+ );
+ $w1 = $maxWidth - $w0 - $marginWidth;
+ $h = min($maxHeight, min($w0 / $ratios[0], $w / $ratios[1]));
+
+ $result->colSizes = [ceil($w0), ceil($w1)];
+ $result->rowSizes = [1];
+ $result->width = ceil($w0 + $w1 + $marginWidth);
+ $result->height = ceil($height);
+ $result->tiles = [new ThumbTile(1, 1, $w0, $h), new ThumbTile(1, 1, $w1, $h)];
+ }
+ break;
+ case 3:
+ # Three wide photos, we will put two of them below and one on top
+ if($orients == [Makima::ORIENT_WIDE, Makima::ORIENT_WIDE, Makima::ORIENT_WIDE]) {
+ $hCover = min($maxWidth / $ratios[0], ($maxHeight - $marginHeight) * (2 / 3));
+ $w2 = ($maxWidth - $marginWidth) / 2;
+ $h = min($maxHeight - $hCover - $margin, min($w2 / $ratios[1], $w2 / $ratios[2]));
+
+ $result->colSizes = [1, 1];
+ $result->rowSizes = [ceil($hCover), ceil($h)];
+ $result->width = ceil($maxWidth);
+ $result->height = ceil($marginHeight + $hCover + $h);
+ $result->tiles = [
+ new ThumbTile(2, 1, $maxWidth, $hCover),
+ new ThumbTile(1, 1, $w2, $h), new ThumbTile(1, 1, $w2, $h),
+ ];
+ } else /* Photos have different sizes or are not wide, so we will put one to left and two to the right */ {
+ $wCover = min($maxHeight * $ratios[0], ($maxWidth - $marginWidth) * (3 / 4));
+ $h1 = ($ratios[1] * ($maxHeight - $marginHeight) / ($ratios[2] + $ratios[1]));
+ $h0 = $maxHeight - $marginHeight - $h1;
+ $w = min($maxWidth - $marginWidth - $wCover, min($h1 * $ratios[2], $h0 * $ratios[1]));
+
+ $result->colSizes = [ceil($wCover), ceil($w)];
+ $result->rowSizes = [ceil($h0), ceil($h1)];
+ $result->width = ceil($w + $wCover + $marginWidth);
+ $result->height = ceil($maxHeight);
+ $result->tiles = [
+ new ThumbTile(1, 2, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0),
+ new ThumbTile(1, 1, $w, $h1),
+ ];
+ }
+ break;
+ case 4:
+ # Four wide photos, we will put one to the top and rest below
+ if($orients == [Makima::ORIENT_WIDE, Makima::ORIENT_WIDE, Makima::ORIENT_WIDE, Makima::ORIENT_WIDE]) {
+ $hCover = min($maxWidth / $ratios[0], ($maxHeight - $marginHeight) / (2 / 3));
+ $h = ($maxWidth - 2 * $marginWidth) / (array_sum($ratios) - $ratios[0]);
+ $w0 = $h * $ratios[1];
+ $w1 = $h * $ratios[2];
+ $w2 = $h * $ratios[3];
+ $h = min($maxHeight - $marginHeight - $hCover, $h);
+
+ $result->colSizes = [ceil($w0), ceil($w1), ceil($w2)];
+ $result->rowSizes = [ceil($hCover), ceil($h)];
+ $result->width = ceil($maxWidth);
+ $result->height = ceil($hCover + $marginHeight + $h);
+ $result->tiles = [
+ new ThumbTile(3, 1, $maxWidth, $hCover),
+ new ThumbTile(1, 1, $w0, $h), new ThumbTile(1, 1, $w1, $h), new ThumbTile(1, 1, $w2, $h),
+ ];
+ } else /* Four photos, we will put one to the left and rest to the right */ {
+ $wCover = min($maxHeight * $ratios[0], ($maxWidth - $marginWidth) * (2 / 3));
+ $w = ($maxHeight - 2 * $marginHeight) / (1 / $ratios[1] + 1 / $ratios[2] + 1 / $ratios[3]);
+ $h0 = $w / $ratios[1];
+ $h1 = $w / $ratios[2];
+ $h2 = $w / $ratios[3] + $marginHeight;
+ $w = min($w, $maxWidth - $marginWidth - $wCover);
+
+ $result->colSizes = [ceil($wCover), ceil($w)];
+ $result->rowSizes = [ceil($h0), ceil($h1), ceil($h2)];
+ $result->width = ceil($wCover + $marginWidth + $w);
+ $result->height = ceil($maxHeight);
+ $result->tiles = [
+ new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0),
+ new ThumbTile(1, 1, $w, $h1),
+ new ThumbTile(1, 1, $w, $h1),
+ ];
+ }
+ break;
+ default:
+ // как лопать пузырики
+ $ratiosCropped = [];
+ if($avgRatio > 1.1) {
+ foreach($ratios as $ratio)
+ $ratiosCropped[] = max($ratio, 1.0);
+ } else {
+ foreach($ratios as $ratio)
+ $ratiosCropped[] = min($ratio, 1.0);
+ }
+
+ $tries = [];
+
+ $firstLine;
+ $secondLine;
+ $thirdLine;
+
+ # Try one line:
+ $tries[$firstLine = $count] = [$this->calculateMultiThumbsHeight($ratiosCropped, $maxWidth, $marginWidth)];
+
+ # Try two lines:
+ for($firstLine = 1; $firstLine < ($count - 1); $firstLine++) {
+ $secondLine = $count - $firstLine;
+ $key = "$firstLine&$secondLine";
+ $tries[$key] = [
+ $this->calculateMultiThumbsHeight(array_slice($ratiosCropped, 0, $firstLine), $maxWidth, $marginWidth),
+ $this->calculateMultiThumbsHeight(array_slice($ratiosCropped, $firstLine), $maxWidth, $marginWidth),
+ ];
+ }
+
+ # Try three lines:
+ for($firstLine = 1; $firstLine < ($count - 2); $firstLine++) {
+ for($secondLine = 1; $secondLine < ($count - $firstLine - 1); $secondLine++) {
+ $thirdLine = $count - $firstLine - $secondLine;
+ $key = "$firstLine&$secondLine&$thirdLine";
+ $tries[$key] = [
+ $this->calculateMultiThumbsHeight(array_slice($ratiosCropped, 0, $firstLine), $maxWidth, $marginWidth),
+ $this->calculateMultiThumbsHeight($this->extractSubArr($ratiosCropped, $firstLine, $firstLine + $secondLine), $maxWidth, $marginWidth),
+ $this->calculateMultiThumbsHeight($this->extractSubArr($ratiosCropped, $firstLine + $secondLine, sizeof($ratiosCropped)), $maxWidth, $marginWidth),
+ ];
+ }
+ }
+
+ # Now let's find the most optimal configuration:
+ $optimalConfiguration = $optimalDifference = NULL;
+ foreach($tries as $config => $heights) {
+ $config = explode('&', $config);
+ $confH = $marginHeight * (sizeof($heights) - 1);
+ foreach($heights as $h)
+ $confH += $h;
+
+ $confDiff = abs($confH - $maxHeight);
+ if(sizeof($config) > 1)
+ if($config[0] > $config[1] || sizeof($config) >= 2 && $config[1] > $config[2])
+ $confDiff *= 1.1;
+
+ if(!$optimalConfiguration || $confDigff < $optimalDifference) {
+ $optimalConfiguration = $config;
+ $optimalDifference = $confDiff;
+ }
+ }
+
+ $thumbsRemain = $this->photos;
+ $ratiosRemain = $ratiosCropped;
+ $optHeights = $tries[implode('&', $optimalConfiguration)];
+ $k = 0;
+
+ $result->width = ceil($maxWidth);
+ $result->rowSizes = [sizeof($optHeights)];
+ $result->tiles = [];
+
+ $totalHeight = 0.0;
+ $gridLineOffsets = [];
+ $rowTiles = []; // vector
+
+ {include "../attachment.xml", attachment => $attachment[2]}