]> git.mxchange.org Git - friendica.git/blob - src/Content/Image.php
Continued:
[friendica.git] / src / Content / Image.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2024, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Content;
23
24 use Friendica\Content\Image\Collection\MasonryImageRow;
25 use Friendica\Content\Image\Entity\MasonryImage;
26 use Friendica\Content\Post\Collection\PostMedias;
27 use Friendica\Core\Renderer;
28
29 class Image
30 {
31         public static function getBodyAttachHtml(PostMedias $PostMediaImages): string
32         {
33                 $media = '';
34
35                 if ($PostMediaImages->haveDimensions()) {
36                         if (count($PostMediaImages) > 1) {
37                                 $media = self::getHorizontalMasonryHtml($PostMediaImages);
38                         } elseif (count($PostMediaImages) == 1) {
39                                 $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [
40                                         '$image' => $PostMediaImages[0],
41                                         '$allocated_height' => $PostMediaImages[0]->getAllocatedHeight(),
42                                         '$allocated_max_width' => ($PostMediaImages[0]->previewWidth ?? $PostMediaImages[0]->width) . 'px',
43                                 ]);
44                         }
45                 } else {
46                         if (count($PostMediaImages) > 1) {
47                                 $media = self::getImageGridHtml($PostMediaImages);
48                         } elseif (count($PostMediaImages) == 1) {
49                                 $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single.tpl'), [
50                                         '$image' => $PostMediaImages[0],
51                                 ]);
52                         }
53                 }
54
55                 return $media;
56         }
57
58         /**
59          * @param PostMedias $images
60          * @return string
61          * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
62          */
63         private static function getImageGridHtml(PostMedias $images): string
64         {
65                 // Image for first column (fc) and second column (sc)
66                 $images_fc = [];
67                 $images_sc = [];
68
69                 for ($i = 0; $i < count($images); $i++) {
70                         ($i % 2 == 0) ? ($images_fc[] = $images[$i]) : ($images_sc[] = $images[$i]);
71                 }
72
73                 return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/grid.tpl'), [
74                         'columns' => [
75                                 'fc' => $images_fc,
76                                 'sc' => $images_sc,
77                         ],
78                 ]);
79         }
80
81         /**
82          * Creates a horizontally masoned gallery with a fixed maximum number of pictures per row.
83          *
84          * For each row, we calculate how much of the total width each picture will take depending on their aspect ratio
85          * and how much relative height it needs to accomodate all pictures next to each other with their height normalized.
86          *
87          * @param array $images
88          * @return string
89          * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
90          */
91         private static function getHorizontalMasonryHtml(PostMedias $images): string
92         {
93                 static $column_size = 2;
94
95                 $rows = array_map(
96                         function (PostMedias $PostMediaImages) {
97                                 if ($singleImageInRow = count($PostMediaImages) == 1) {
98                                         $PostMediaImages[] = $PostMediaImages[0];
99                                 }
100
101                                 $widths = [];
102                                 $heights = [];
103                                 foreach ($PostMediaImages as $PostMediaImage) {
104                                         if ($PostMediaImage->width && $PostMediaImage->height) {
105                                                 $widths[] = $PostMediaImage->width;
106                                                 $heights[] = $PostMediaImage->height;
107                                         } else {
108                                                 $widths[] = $PostMediaImage->previewWidth;
109                                                 $heights[] = $PostMediaImage->previewHeight;
110                                         }
111                                 }
112
113                                 $maxHeight = max($heights);
114
115                                 // Corrected width preserving aspect ratio when all images on a row are the same height
116                                 $correctedWidths = [];
117                                 foreach ($widths as $i => $width) {
118                                         $correctedWidths[] = $width * $maxHeight / $heights[$i];
119                                 }
120
121                                 $totalWidth = array_sum($correctedWidths);
122
123                                 $row_images2 = [];
124
125                                 if ($singleImageInRow) {
126                                         unset($PostMediaImages[1]);
127                                 }
128
129                                 foreach ($PostMediaImages as $i => $PostMediaImage) {
130                                         $row_images2[] = new MasonryImage(
131                                                 $PostMediaImage->uriId,
132                                                 $PostMediaImage->url,
133                                                 $PostMediaImage->preview,
134                                                 $PostMediaImage->description ?? '',
135                                                 100 * $correctedWidths[$i] / $totalWidth,
136                                                 100 * $maxHeight / $correctedWidths[$i]
137                                         );
138                                 }
139
140                                 // This magic value will stay constant for each image of any given row and is ultimately
141                                 // used to determine the height of the row container relative to the available width.
142                                 $commonHeightRatio = 100 * $correctedWidths[0] / $totalWidth / ($widths[0] / $heights[0]);
143
144                                 return new MasonryImageRow($row_images2, count($row_images2), $commonHeightRatio);
145                         },
146                         $images->chunk($column_size)
147                 );
148
149                 return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/horizontal_masonry.tpl'), [
150                         '$rows' => $rows,
151                         '$column_size' => $column_size,
152                 ]);
153         }
154 }