xref: /plugin/mediathumbnails/thumb_engines.php (revision 33e1a0054f2dab2cf0a761eedbc1a23c7b1ef21b)
1<?php
2/**
3 * DokuWiki Plugin mediathumbnails (thumb_engine class and subclasses)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Thomas Schäfer <thomas.schaefer@itschert.net>
7 */
8
9abstract class thumb_engine {
10
11	private ?thumbnail $thumbnail = null;
12
13	public function __construct(thumbnail $thumbnail) {
14		$this->thumbnail = $thumbnail;
15	}
16
17	protected function getSourceFilepath() {
18		return $this->thumbnail->getSourceFilepath();
19	}
20
21	protected function getTargetFilepath() {
22		return $this->thumbnail->getFilepath();
23	}
24
25	protected function getTargetMaxDimension() {
26		return $this->thumbnail->getMaxDimension();
27	}
28
29	public function act() {
30		if ($this->act_internal()) {
31			// Set timestamp to the source file's timestamp (this is used to check in later passes if the file already exists in the correct version).
32			if (filemtime($this->getSourceFilepath()) !== filemtime($this->getTargetFilepath())) {
33				touch($this->getTargetFilepath(), filemtime($this->getSourceFilepath()));
34			}
35			return true;
36		}
37		return false;
38	}
39
40	// Checks if a thumbnail file for the current file version has already been created
41	protected function thumb_needs_update() {
42		return !file_exists($this->getTargetFilepath()) || filemtime($this->getTargetFilepath()) !== filemtime($this->getSourceFilepath());
43	}
44
45	public abstract function act_internal();
46
47	public abstract function getFileSuffix();
48}
49
50class thumb_pdf_engine extends thumb_engine {
51
52	public function getFileSuffix() {
53		return "jpg";
54	}
55
56	public function act_internal() {
57		if ($this->thumb_needs_update()) {
58			$im = new imagick($this->getSourceFilepath()."[0]");
59            // the following line was in the original code. Issue #6 (https://github.com/ternite/dokuwiki-plugin-mediathumbnails/issues/6)
60            // indicated there might be problems with colors, so I uncommented the line (TS, 2025-10-11)
61			//$im->setImageColorspace(255);
62			$im->setResolution(300, 300);
63			$im->setCompressionQuality(95);
64			$im->setImageFormat('jpeg');
65			//$im->resizeImage($this->getTargetMaxDimension(),0,imagick::FILTER_LANCZOS,0.9);
66			//$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
67			$im->writeImage($this->getTargetFilepath());
68			$im->clear();
69			$im->destroy();
70
71			// unfortunately, resizeImage or thumbnailImage leads to a black thumbnail in my setup, so I reopen the file and resize it now.
72			$im = new imagick($this->getTargetFilepath());
73			$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
74			$im->writeImage($this->getTargetFilepath());
75			$im->clear();
76			$im->destroy();
77
78			return true;
79		} else {
80			return true;
81		}
82	}
83}
84
85class thumb_img_engine extends thumb_engine {
86
87	public function getFileSuffix() {
88		return getFileSuffix($this->getSourceFilepath());
89	}
90
91	public function act_internal() {
92		if ($this->thumb_needs_update()) {
93			$im = new imagick( $this->getSourceFilepath() );
94			$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
95			$im->writeImage($this->getTargetFilepath());
96			$im->clear();
97			$im->destroy();
98
99			return true;
100		} else {
101			return true;
102		}
103	}
104}
105
106class thumb_zip_engine extends thumb_engine {
107
108	private array $thumb_paths;
109	private $file_suffix = "";
110
111	public function __construct(thumbnail $thumbnail, array $thumb_paths) {
112		parent::__construct($thumbnail);
113		$this->thumb_paths = $thumb_paths;
114	}
115
116	public function getFileSuffix() {
117		return $this->file_suffix;
118	}
119
120	public function act_internal() {
121
122		$zip = new ZipArchive;
123		if ($zip->open($this->getSourceFilepath()) !== true) {
124			// file is no zip or cannot be opened
125			return false;
126		}
127
128		// The media file exists and acts as a zip file!
129
130		// Check all possible paths (configured in configuration key 'thumb_paths') if there is a file available
131		foreach($this->thumb_paths as $thumbnail_path) {
132			$this->file_suffix = substr(strrchr($thumbnail_path,'.'),1);
133
134			if ($zip->locateName($thumbnail_path) !== false) {
135
136				if (!$this->thumb_needs_update()) {
137					return true;
138				}
139
140				// Get the thumbnail file!
141				$fp = $zip->getStream($thumbnail_path);
142				if(!$fp) {
143					return false;
144				}
145
146				$thumbnaildata = '';
147				while (!feof($fp)) {
148					$thumbnaildata .= fread($fp, 8192);
149				}
150
151				fclose($fp);
152
153				// Write thumbnail file to media folder
154				file_put_contents($this->getTargetFilepath(), $thumbnaildata);
155
156				return true;
157			}
158		}
159
160		return true;
161	}
162}