Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
75.64% |
59 / 78 |
|
40.00% |
2 / 5 |
CRAP | |
0.00% |
0 / 1 |
ImageUtils | |
75.64% |
59 / 78 |
|
40.00% |
2 / 5 |
50.71 | |
0.00% |
0 / 1 |
olzImage | |
77.78% |
28 / 36 |
|
0.00% |
0 / 1 |
11.10 | |||
getThumbSize | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
generateThumbnails | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
getThumbFile | |
68.75% |
22 / 32 |
|
0.00% |
0 / 1 |
23.81 | |||
fromEnv | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace Olz\Utils; |
4 | |
5 | class ImageUtils { |
6 | use WithUtilsTrait; |
7 | |
8 | public const TABLES_IMG_DIRS = [ |
9 | 'karten' => 'img/karten/', |
10 | 'news' => 'img/news/', |
11 | 'questions' => 'img/questions/', |
12 | 'roles' => 'img/roles/', |
13 | 'snippets' => 'img/snippets/', |
14 | 'termine' => 'img/termine/', |
15 | 'termin_labels' => 'img/termin_labels/', |
16 | 'termin_locations' => 'img/termin_locations/', |
17 | 'termin_templates' => 'img/termin_templates/', |
18 | 'users' => 'img/users/', |
19 | 'weekly_picture' => 'img/weekly_picture/', |
20 | ]; |
21 | |
22 | public function olzImage( |
23 | string $db_table, |
24 | int|string|null $id, |
25 | ?string $index, |
26 | int $dim, |
27 | ?string $lightview = 'image', |
28 | string $attrs = '', |
29 | ): string { |
30 | $data_href = $this->envUtils()->getDataHref(); |
31 | $data_path = $this->envUtils()->getDataPath(); |
32 | if (!isset($this::TABLES_IMG_DIRS[$db_table])) { |
33 | $message = "Ungültige db_table: {$db_table} (in olzImage)"; |
34 | $this->log()->error($message); |
35 | return "<span style='color:#ff0000; font-style:italic;'>{$message}</span>"; |
36 | } |
37 | $db_imgpath = $this::TABLES_IMG_DIRS[$db_table]; |
38 | $imgfile = "{$db_imgpath}{$id}/img/{$index}"; |
39 | if (!$id || !$index || !is_file("{$data_path}{$imgfile}")) { |
40 | $message = "Bild nicht vorhanden (in olzImage): {$imgfile}"; |
41 | $this->log()->error($message); |
42 | return "<span style='color:#ff0000; font-style:italic;'>{$message}</span>"; |
43 | } |
44 | $info = getimagesize("{$data_path}{$imgfile}"); |
45 | $swid = $info[0] ?? 0; |
46 | $shei = $info[1] ?? 0; |
47 | if ($shei < $swid) { |
48 | $wid = $dim; |
49 | $hei = intval($wid * $shei / $swid); |
50 | } else { |
51 | $hei = $dim; |
52 | $wid = intval($hei * $swid / $shei); |
53 | } |
54 | $span_before = $lightview === 'image' ? "<span class='lightgallery'>" : ""; |
55 | $span_after = $lightview === 'image' ? "</span>" : ""; |
56 | $a_before = $lightview ? "<a href='{$data_href}{$imgfile}' aria-label='Bild vergrössern' data-src='{$data_href}{$imgfile}' onclick='event.stopPropagation()'>" : ""; |
57 | $a_after = $lightview ? "</a>" : ""; |
58 | |
59 | $url_without_dim = "{$data_href}img/{$db_table}/{$id}/thumb/{$index}"; |
60 | $thumbdim = $this->getThumbSize($dim); |
61 | $thumbdim2x = $thumbdim * 2; |
62 | return <<<ZZZZZZZZZZ |
63 | {$span_before}{$a_before} |
64 | <img |
65 | src='{$url_without_dim}\${$thumbdim}.jpg' |
66 | srcset='{$url_without_dim}\${$thumbdim2x}.jpg 2x, {$url_without_dim}\${$thumbdim}.jpg 1x' |
67 | alt='' |
68 | width='{$wid}' |
69 | height='{$hei}' |
70 | {$attrs} |
71 | /> |
72 | {$a_after}{$span_after} |
73 | ZZZZZZZZZZ; |
74 | } |
75 | |
76 | public function getThumbSize(int $size): int { |
77 | $ndim = $size - 1; |
78 | for ($i = 1; $i < 9 && ($ndim >> $i) > 0; $i++) { |
79 | } |
80 | return 1 << $i; |
81 | } |
82 | |
83 | /** @param array<string> $image_ids */ |
84 | public function generateThumbnails(array $image_ids, string $entity_img_path): void { |
85 | foreach ($image_ids as $image_id) { |
86 | for ($i = 5; $i < 9; $i++) { |
87 | $size = (1 << $i); |
88 | if (!is_file("{$entity_img_path}thumb/{$image_id}\${$size}.jpg")) { |
89 | $this->log()->info("Generate {$entity_img_path}thumb/{$image_id}\${$size}.jpg..."); |
90 | $this->getThumbFile($image_id, $entity_img_path, $size); |
91 | } |
92 | } |
93 | } |
94 | } |
95 | |
96 | public function getThumbFile(string $image_id, string $entity_img_path, int $size): string { |
97 | if ($size !== 32 && $size !== 64 && $size !== 128 && $size !== 256 && $size !== 512) { |
98 | throw new \Exception("Size must be a power of two (32,64,128,256,512), was: {$size}"); |
99 | } |
100 | $imgfile = "{$entity_img_path}img/{$image_id}"; |
101 | $info = getimagesize($imgfile); |
102 | $swid = $info[0] ?? 0; |
103 | $shei = $info[1] ?? 0; |
104 | if ($shei < $swid) { |
105 | $wid = $size; |
106 | $hei = intval($wid * $shei / $swid); |
107 | } else { |
108 | $hei = $size; |
109 | $wid = intval($hei * $swid / $shei); |
110 | } |
111 | if ($wid <= 0 || $hei <= 0 || $wid > 800 || $hei > 800) { |
112 | $message = "getThumbFile: Invalid dimension: {$size}"; |
113 | $this->log()->warning($message); |
114 | throw new \Exception($message); |
115 | } |
116 | if ($wid > 256 || $hei > 256) { |
117 | $thumbfile = $imgfile; |
118 | } else { |
119 | $thumbfile = "{$entity_img_path}thumb/{$image_id}\${$size}.jpg"; |
120 | } |
121 | if (!is_file($thumbfile)) { |
122 | if (!is_dir(dirname($thumbfile))) { |
123 | mkdir(dirname($thumbfile), 0o777, true); |
124 | } |
125 | $img = imagecreatefromjpeg($imgfile); |
126 | if (!$img) { |
127 | $message = "getThumbFile: Could not open image {$imgfile}"; |
128 | $this->log()->warning($message); |
129 | throw new \Exception($message); |
130 | } |
131 | $thumb = imagecreatetruecolor($wid, $hei); |
132 | imagesavealpha($thumb, true); |
133 | imagecopyresampled($thumb, $img, 0, 0, 0, 0, $wid, $hei, $swid, $shei); |
134 | imagejpeg($thumb, $thumbfile, 90); |
135 | imagedestroy($thumb); |
136 | } |
137 | return $thumbfile; |
138 | } |
139 | |
140 | public static function fromEnv(): self { |
141 | return new self(); |
142 | } |
143 | } |