xref: /plugin/mediathumbnails/thumb_engines.php (revision a99f150968d94c1d45e20e5e1fcfb35c280afe95)
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			//if file does not exist
59			if (!file_exists($this->getSourceFilepath())) {
60				return false;
61			}
62			$im = new imagick($this->getSourceFilepath()."[0]");
63            // the following line was in the original code. Issue #6 (https://github.com/ternite/dokuwiki-plugin-mediathumbnails/issues/6)
64            // indicated there might be problems with colors, so I uncommented the line (TS, 2025-10-11)
65			//$im->setImageColorspace(255);
66			$im->setResolution(300, 300);
67			$im->setCompressionQuality(95);
68			$im->setImageFormat('jpeg');
69			//$im->resizeImage($this->getTargetMaxDimension(),0,imagick::FILTER_LANCZOS,0.9);
70			//$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
71			$im->writeImage($this->getTargetFilepath());
72			$im->clear();
73			$im->destroy();
74
75			// unfortunately, resizeImage or thumbnailImage leads to a black thumbnail in my setup, so I reopen the file and resize it now.
76			$im = new imagick($this->getTargetFilepath());
77			$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
78			$im->writeImage($this->getTargetFilepath());
79			$im->clear();
80			$im->destroy();
81
82			return true;
83		} else {
84			return true;
85		}
86	}
87}
88
89class thumb_img_engine extends thumb_engine {
90
91	public function getFileSuffix() {
92		return getFileSuffix($this->getSourceFilepath());
93	}
94
95	public function act_internal() {
96		if ($this->thumb_needs_update()) {
97			$im = new imagick( $this->getSourceFilepath() );
98			$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false);
99			$im->writeImage($this->getTargetFilepath());
100			$im->clear();
101			$im->destroy();
102
103			return true;
104		} else {
105			return true;
106		}
107	}
108}
109
110class thumb_zip_engine extends thumb_engine {
111
112	private array $thumb_paths;
113	private $file_suffix = "";
114
115	public function __construct(thumbnail $thumbnail, array $thumb_paths) {
116		parent::__construct($thumbnail);
117		$this->thumb_paths = $thumb_paths;
118	}
119
120	public function getFileSuffix() {
121		return $this->file_suffix;
122	}
123
124	public function act_internal() {
125
126		$zip = new ZipArchive;
127		if ($zip->open($this->getSourceFilepath()) !== true) {
128			// file is no zip or cannot be opened
129			return false;
130		}
131
132		// The media file exists and acts as a zip file!
133
134		// Check all possible paths (configured in configuration key 'thumb_paths') if there is a file available
135		foreach($this->thumb_paths as $thumbnail_path) {
136			$this->file_suffix = substr(strrchr($thumbnail_path,'.'),1);
137
138			if ($zip->locateName($thumbnail_path) !== false) {
139
140				if (!$this->thumb_needs_update()) {
141					return true;
142				}
143
144				// Get the thumbnail file!
145				$fp = $zip->getStream($thumbnail_path);
146				if(!$fp) {
147					return false;
148				}
149
150				$thumbnaildata = '';
151				while (!feof($fp)) {
152					$thumbnaildata .= fread($fp, 8192);
153				}
154
155				fclose($fp);
156
157				// Write thumbnail file to media folder
158				file_put_contents($this->getTargetFilepath(), $thumbnaildata);
159
160				return true;
161			}
162		}
163
164		return true;
165	}
166}