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 protected ?thumbnail $thumbnail = null; 12 protected bool $state_failed = false; 13 14 public function __construct(thumbnail $thumbnail) { 15 $this->thumbnail = $thumbnail; 16 } 17 18 protected function getSourceFilepath() { 19 return $this->thumbnail->getSourceFilepath(); 20 } 21 22 protected function getTargetFilepath() { 23 return $this->thumbnail->getFilepath(); 24 } 25 26 protected function getTargetMaxDimension() { 27 return $this->thumbnail->getMaxDimension(); 28 } 29 30 public function act(): bool { 31 if ($this->act_internal()) { 32 // 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 $sourceFilePath = $this->getSourceFilepath(); 34 $targetFilePath = $this->getTargetFilepath(); 35 if (filemtime($sourceFilePath) !== filemtime($targetFilePath)) { 36 touch($sourceFilePath, filemtime($targetFilePath)); 37 } 38 return true; 39 } 40 return false; 41 } 42 43 // Checks if a thumbnail file for the current file version has already been created 44 protected function thumb_needs_update(): bool { 45 return !file_exists($this->getTargetFilepath()) || filemtime($this->getTargetFilepath()) !== filemtime($this->getSourceFilepath()); 46 } 47 48 public function has_failed(): bool { 49 return $this->state_failed; 50 } 51 52 public abstract function act_internal(): bool; 53 54 public abstract function getFileSuffix(): string; 55} 56 57class thumb_pdf_engine extends thumb_engine { 58 59 public function getFileSuffix(): string { 60 return "jpg"; 61 } 62 63 public function act_internal(): bool { 64 if ($this->thumb_needs_update()) { 65 //if file does not exist 66 if (!file_exists($this->getSourceFilepath())) { 67 return false; 68 } 69 $im = new imagick($this->getSourceFilepath()."[0]"); 70 // the following line was in the original code. Issue #6 (https://github.com/ternite/dokuwiki-plugin-mediathumbnails/issues/6) 71 // indicated there might be problems with colors, so I uncommented the line (TS, 2025-10-11) 72 //$im->setImageColorspace(255); 73 $im->setResolution(300, 300); 74 $im->setCompressionQuality(95); 75 $im->setImageFormat('jpeg'); 76 //$im->resizeImage($this->getTargetMaxDimension(),0,imagick::FILTER_LANCZOS,0.9); 77 //$im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 78 $im->writeImage($this->getTargetFilepath()); 79 $im->clear(); 80 $im->destroy(); 81 82 // unfortunately, resizeImage or thumbnailImage leads to a black thumbnail in my setup, so I reopen the file and resize it now. 83 $im = new imagick($this->getTargetFilepath()); 84 $im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 85 $im->writeImage($this->getTargetFilepath()); 86 $im->clear(); 87 $im->destroy(); 88 89 return true; 90 } else { 91 return true; 92 } 93 } 94} 95 96class thumb_img_engine extends thumb_engine { 97 98 public function getFileSuffix(): string { 99 return getFileSuffix($this->getSourceFilepath()); 100 } 101 102 public function act_internal(): bool { 103 if ($this->thumb_needs_update()) { 104 $im = new imagick( $this->getSourceFilepath() ); 105 $im->thumbnailImage($this->getTargetMaxDimension(),$this->getTargetMaxDimension(),true,false); 106 $im->writeImage($this->getTargetFilepath()); 107 $im->clear(); 108 $im->destroy(); 109 110 return true; 111 } else { 112 return true; 113 } 114 } 115} 116 117class thumb_zip_engine extends thumb_engine { 118 119 private array $thumb_paths; 120 private $file_suffix = ""; 121 122 public function __construct(thumbnail $thumbnail, array $thumb_paths) { 123 parent::__construct($thumbnail); 124 $this->thumb_paths = $thumb_paths; 125 } 126 127 public function getFileSuffix(): string { 128 return $this->file_suffix; 129 } 130 131 public function act_internal(): bool { 132 133 $zip = new ZipArchive; 134 if ($zip->open($this->getSourceFilepath()) !== true) { 135 // file is no zip or cannot be opened 136 return false; 137 } 138 139 // The media file exists and acts as a zip file! 140 141 // 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 $thumbnail_found = false; 143 foreach($this->thumb_paths as $thumbnail_path) { 144 $this->file_suffix = substr(strrchr($thumbnail_path,'.'),1); 145 146 if ($zip->locateName($thumbnail_path) !== false) { 147 148 if (!$this->thumb_needs_update()) { 149 return true; 150 } 151 152 // Get the thumbnail file! 153 $fp = $zip->getStream($thumbnail_path); 154 if(!$fp) { 155 return false; 156 } 157 158 $thumbnaildata = ''; 159 while (!feof($fp)) { 160 $thumbnaildata .= fread($fp, 8192); 161 } 162 163 fclose($fp); 164 165 // Write thumbnail file to media folder 166 file_put_contents($this->getTargetFilepath(), $thumbnaildata); 167 168 $thumbnail_found = true; 169 return true; 170 } 171 } 172 173 // if we reach this point, no thumbnail file was found within the zip file 174 if (!$thumbnail_found) { 175 $this->state_failed = true; 176 msg("plugin mediathumbnails: No thumbnail found inside zip file " . $this->getSourceFilepath()); 177 } 178 179 return false; 180 } 181}