147d2d32aSternite<?php 247d2d32aSternite/** 347d2d32aSternite * DokuWiki Plugin mediathumbnails (thumb_engine class and subclasses) 447d2d32aSternite * 547d2d32aSternite * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 647d2d32aSternite * @author Thomas Schäfer <thomas.schaefer@itschert.net> 747d2d32aSternite */ 847d2d32aSternite 947d2d32aSterniteabstract class thumb_engine { 1047d2d32aSternite 11*e19533e1Sternite protected ?thumbnail $thumbnail = null; 12*e19533e1Sternite protected bool $state_failed = false; 1347d2d32aSternite 1447d2d32aSternite public function __construct(thumbnail $thumbnail) { 1547d2d32aSternite $this->thumbnail = $thumbnail; 1647d2d32aSternite } 1747d2d32aSternite 1847d2d32aSternite protected function getSourceFilepath() { 1947d2d32aSternite return $this->thumbnail->getSourceFilepath(); 2047d2d32aSternite } 2147d2d32aSternite 2247d2d32aSternite protected function getTargetFilepath() { 2347d2d32aSternite return $this->thumbnail->getFilepath(); 2447d2d32aSternite } 2547d2d32aSternite 2647d2d32aSternite protected function getTargetMaxDimension() { 2747d2d32aSternite return $this->thumbnail->getMaxDimension(); 2847d2d32aSternite } 2947d2d32aSternite 30*e19533e1Sternite public function act(): bool { 3147d2d32aSternite if ($this->act_internal()) { 3247d2d32aSternite // 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). 33*e19533e1Sternite $sourceFilePath = $this->getSourceFilepath(); 34*e19533e1Sternite $targetFilePath = $this->getTargetFilepath(); 35*e19533e1Sternite if (filemtime($sourceFilePath) !== filemtime($targetFilePath)) { 36*e19533e1Sternite touch($sourceFilePath, filemtime($targetFilePath)); 3747d2d32aSternite } 3847d2d32aSternite return true; 3947d2d32aSternite } 4047d2d32aSternite return false; 4147d2d32aSternite } 4247d2d32aSternite 4347d2d32aSternite // Checks if a thumbnail file for the current file version has already been created 44*e19533e1Sternite protected function thumb_needs_update(): bool { 4547d2d32aSternite return !file_exists($this->getTargetFilepath()) || filemtime($this->getTargetFilepath()) !== filemtime($this->getSourceFilepath()); 4647d2d32aSternite } 4747d2d32aSternite 48*e19533e1Sternite public function has_failed(): bool { 49*e19533e1Sternite return $this->state_failed; 50*e19533e1Sternite } 5147d2d32aSternite 52*e19533e1Sternite public abstract function act_internal(): bool; 53*e19533e1Sternite 54*e19533e1Sternite public abstract function getFileSuffix(): string; 5547d2d32aSternite} 5647d2d32aSternite 5747d2d32aSterniteclass thumb_pdf_engine extends thumb_engine { 5847d2d32aSternite 59*e19533e1Sternite public function getFileSuffix(): string { 6047d2d32aSternite return "jpg"; 6147d2d32aSternite } 6247d2d32aSternite 63*e19533e1Sternite public function act_internal(): bool { 6447d2d32aSternite if ($this->thumb_needs_update()) { 65a99f1509Sternite //if file does not exist 66a99f1509Sternite if (!file_exists($this->getSourceFilepath())) { 67a99f1509Sternite return false; 68a99f1509Sternite } 6947d2d32aSternite $im = new imagick($this->getSourceFilepath()."[0]"); 7033e1a005Sternite // the following line was in the original code. Issue #6 (https://github.com/ternite/dokuwiki-plugin-mediathumbnails/issues/6) 7133e1a005Sternite // indicated there might be problems with colors, so I uncommented the line (TS, 2025-10-11) 7233e1a005Sternite //$im->setImageColorspace(255); 7347d2d32aSternite $im->setResolution(300, 300); 7447d2d32aSternite $im->setCompressionQuality(95); 7547d2d32aSternite $im->setImageFormat('jpeg'); 7647d2d32aSternite //$im->resizeImage($this->getTargetMaxDimension(),0,imagick::FILTER_LANCZOS,0.9); 7747d2d32aSternite //$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 7847d2d32aSternite $im->writeImage($this->getTargetFilepath()); 7947d2d32aSternite $im->clear(); 8047d2d32aSternite $im->destroy(); 8147d2d32aSternite 8247d2d32aSternite // unfortunately, resizeImage or thumbnailImage leads to a black thumbnail in my setup, so I reopen the file and resize it now. 8347d2d32aSternite $im = new imagick($this->getTargetFilepath()); 8447d2d32aSternite $im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 8547d2d32aSternite $im->writeImage($this->getTargetFilepath()); 8647d2d32aSternite $im->clear(); 8747d2d32aSternite $im->destroy(); 8847d2d32aSternite 8947d2d32aSternite return true; 9047d2d32aSternite } else { 9147d2d32aSternite return true; 9247d2d32aSternite } 9347d2d32aSternite } 9447d2d32aSternite} 9547d2d32aSternite 9647d2d32aSterniteclass thumb_img_engine extends thumb_engine { 9747d2d32aSternite 98*e19533e1Sternite public function getFileSuffix(): string { 9947d2d32aSternite return getFileSuffix($this->getSourceFilepath()); 10047d2d32aSternite } 10147d2d32aSternite 102*e19533e1Sternite public function act_internal(): bool { 10347d2d32aSternite if ($this->thumb_needs_update()) { 10447d2d32aSternite $im = new imagick( $this->getSourceFilepath() ); 10547d2d32aSternite $im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 10647d2d32aSternite $im->writeImage($this->getTargetFilepath()); 10747d2d32aSternite $im->clear(); 10847d2d32aSternite $im->destroy(); 10947d2d32aSternite 11047d2d32aSternite return true; 11147d2d32aSternite } else { 11247d2d32aSternite return true; 11347d2d32aSternite } 11447d2d32aSternite } 11547d2d32aSternite} 11647d2d32aSternite 11747d2d32aSterniteclass thumb_zip_engine extends thumb_engine { 11847d2d32aSternite 11947d2d32aSternite private array $thumb_paths; 12047d2d32aSternite private $file_suffix = ""; 12147d2d32aSternite 12247d2d32aSternite public function __construct(thumbnail $thumbnail, array $thumb_paths) { 12347d2d32aSternite parent::__construct($thumbnail); 12447d2d32aSternite $this->thumb_paths = $thumb_paths; 12547d2d32aSternite } 12647d2d32aSternite 127*e19533e1Sternite public function getFileSuffix(): string { 12847d2d32aSternite return $this->file_suffix; 12947d2d32aSternite } 13047d2d32aSternite 131*e19533e1Sternite public function act_internal(): bool { 13247d2d32aSternite 13347d2d32aSternite $zip = new ZipArchive; 13447d2d32aSternite if ($zip->open($this->getSourceFilepath()) !== true) { 13547d2d32aSternite // file is no zip or cannot be opened 13647d2d32aSternite return false; 13747d2d32aSternite } 13847d2d32aSternite 13947d2d32aSternite // The media file exists and acts as a zip file! 14047d2d32aSternite 141*e19533e1Sternite // Check all possible paths (configured in configuration key 'thumb_paths') if there is a file available - if there are multiple files, the first one found is used. 142*e19533e1Sternite $thumbnail_found = false; 14347d2d32aSternite foreach($this->thumb_paths as $thumbnail_path) { 14447d2d32aSternite $this->file_suffix = substr(strrchr($thumbnail_path,'.'),1); 14547d2d32aSternite 14647d2d32aSternite if ($zip->locateName($thumbnail_path) !== false) { 14747d2d32aSternite 14847d2d32aSternite if (!$this->thumb_needs_update()) { 14947d2d32aSternite return true; 15047d2d32aSternite } 15147d2d32aSternite 15247d2d32aSternite // Get the thumbnail file! 15347d2d32aSternite $fp = $zip->getStream($thumbnail_path); 15447d2d32aSternite if(!$fp) { 15547d2d32aSternite return false; 15647d2d32aSternite } 15747d2d32aSternite 15847d2d32aSternite $thumbnaildata = ''; 15947d2d32aSternite while (!feof($fp)) { 16047d2d32aSternite $thumbnaildata .= fread($fp, 8192); 16147d2d32aSternite } 16247d2d32aSternite 16347d2d32aSternite fclose($fp); 16447d2d32aSternite 16547d2d32aSternite // Write thumbnail file to media folder 16647d2d32aSternite file_put_contents($this->getTargetFilepath(), $thumbnaildata); 16747d2d32aSternite 168*e19533e1Sternite $thumbnail_found = true; 16947d2d32aSternite return true; 17047d2d32aSternite } 17147d2d32aSternite } 17247d2d32aSternite 173*e19533e1Sternite // if we reach this point, no thumbnail file was found within the zip file 174*e19533e1Sternite if (!$thumbnail_found) { 175*e19533e1Sternite $this->state_failed = true; 176*e19533e1Sternite msg("plugin mediathumbnails: No thumbnail found inside zip file " . $this->getSourceFilepath()); 177*e19533e1Sternite } 178*e19533e1Sternite 179*e19533e1Sternite return false; 18047d2d32aSternite } 18147d2d32aSternite}