Thumbnails in PHP erstellen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Hier erfahrt ihr wie ihr Vorschaubilder in PHP erstellt, speichert oder "on the fly" anzeigt.
    == Thumbnail Klasse ==

    Quellcode

    1. <?php
    2. /**
    3. * Generates a thumbnail of given source file image.
    4. *
    5. * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
    6. */
    7. class Thumbnail {
    8. /**
    9. * path to source file
    10. *
    11. * @var string
    12. */
    13. protected $sourceFile = '';
    14. /**
    15. * maximum image width
    16. *
    17. * @var integer
    18. */
    19. protected $maxWidth = 100;
    20. /**
    21. * maximum image height
    22. *
    23. * @var integer
    24. */
    25. protected $maxHeight = 100;
    26. /**
    27. * true, to show source information in thumbnail
    28. *
    29. * @var boolean
    30. */
    31. protected $appendSourceInfo = false;
    32. /**
    33. * true, to prefer embedded thumbnails
    34. *
    35. * @var boolean
    36. */
    37. protected $useEmbedded = true;
    38. /**
    39. * true, to generate quadratic thumbnails
    40. *
    41. * @var boolean
    42. */
    43. protected $quadratic = false;
    44. /**
    45. * mime type of the thumbnail
    46. *
    47. * @var string
    48. */
    49. protected $mimeType = '';
    50. /**
    51. * name of the source image
    52. *
    53. * @var string
    54. */
    55. protected $sourceName = '';
    56. /**
    57. * width of the source image
    58. *
    59. * @var integer
    60. */
    61. protected $sourceWidth = 0;
    62. /**
    63. * height of the source image
    64. *
    65. * @var integer
    66. */
    67. protected $sourceHeight = 0;
    68. /**
    69. * file size of the source image
    70. *
    71. * @var integer
    72. */
    73. protected $sourceSize = 0;
    74. /**
    75. * height of the source information
    76. *
    77. * @var integer
    78. */
    79. protected static $sourceInfoLineHeight = 16;
    80. /**
    81. * image type of the source image
    82. *
    83. * @var integer
    84. */
    85. protected $imageType = 0;
    86. /**
    87. * Creates a new Thumbnail object.
    88. *
    89. * @param string $sourceFile
    90. */
    91. public function __construct($sourceFile) {
    92. $this->sourceFile = $sourceFile;
    93. }
    94. /**
    95. * setup dimenstions
    96. *
    97. * @param boolean $appendSourceInfo
    98. */
    99. public function setup($appendSourceInfo = false, $sourceName = null, $useEmbedded = true, $quadratic = false) {
    100. $this->appendSourceInfo = $appendSourceInfo;
    101. $this->useEmbedded = $useEmbedded;
    102. $this->quadratic = $quadratic;
    103. if ($this->appendSourceInfo) {
    104. // get source info
    105. if ($sourceName != null) $this->sourceName = $sourceName;
    106. else $this->sourceName = basename($this->sourceFile);
    107. list($this->sourceWidth, $this->sourceHeight, $type) = @getImageSize($this->sourceFile);
    108. $this->sourceSize = @filesize($sourceFile);
    109. }
    110. }
    111. /**
    112. * Creates a thumbnail picture (jpg/png) of a big image
    113. *
    114. * @param boolean $rescale
    115. * @return string thumbnail
    116. */
    117. protected function makeThumbnail($rescale = false) {
    118. list($width, $height, $this->imageType) = @getImageSize($this->sourceFile);
    119. // check image size
    120. if ($this->checkSize($width, $height, $rescale)) {
    121. return false;
    122. }
    123. // try to extract the embedded thumbnail first (faster)
    124. $thumbnail = false;
    125. if (!$rescale && $this->useEmbedded) {
    126. $thumbnail = $this->extractEmbeddedThumbnail();
    127. }
    128. if (!$thumbnail) {
    129. // calculate uncompressed filesize
    130. // and cancel to avoid a memory_limit error
    131. $memoryLimit = ini_get('memory_limit');
    132. if ($memoryLimit != '') {
    133. $memoryLimit = substr($memoryLimit, 0, -1) * 1024 * 1024;
    134. $fileSize = $width * $height * ($this->imageType == 3 ? 4 : 3);
    135. if (($fileSize * 2.1) + memory_get_usage() > ($memoryLimit)) {
    136. return false;
    137. }
    138. }
    139. // calculate new picture size
    140. $x = $y = 0;
    141. if ($this->quadratic) {
    142. $newWidth = $newHeight = $this->maxWidth;
    143. if ($this->appendSourceInfo) $newHeight -= self::$sourceInfoLineHeight * 2;
    144. if ($width > $height) {
    145. $x = ceil(($width - $height) / 2);
    146. $width = $height;
    147. }
    148. else {
    149. $y = ceil(($height - $width) / 2);
    150. $height = $width;
    151. }
    152. }
    153. else {
    154. $maxHeight = $this->maxHeight;
    155. if ($this->appendSourceInfo) $maxHeight -= self::$sourceInfoLineHeight * 2;
    156. if ($this->maxWidth / $width < $maxHeight / $height) {
    157. $newWidth = $this->maxWidth;
    158. $newHeight = round($height * ($newWidth / $width));
    159. }
    160. else {
    161. $newHeight = $maxHeight;
    162. $newWidth = round($width * ($newHeight / $height));
    163. }
    164. }
    165. // resize image
    166. $imageResource = false;
    167. // jpeg image
    168. if ($this->imageType == 2 && function_exists('imagecreatefromjpeg')) {
    169. $imageResource = @imageCreateFromJPEG($this->sourceFile);
    170. }
    171. // gif image
    172. if ($this->imageType == 1 && function_exists('imagecreatefromgif')) {
    173. $imageResource = @imageCreateFromGIF($this->sourceFile);
    174. }
    175. // png image
    176. if ($this->imageType == 3 && function_exists('imagecreatefrompng')) {
    177. $imageResource = @imageCreateFromPNG($this->sourceFile);
    178. }
    179. // could not create image
    180. if (!$imageResource) {
    181. return false;
    182. }
    183. // resize image
    184. if (function_exists('imageCreateTrueColor') && function_exists('imageCopyResampled')) {
    185. $imageNew = @imageCreateTrueColor($newWidth, $newHeight);
    186. imageAlphaBlending($imageNew, false);
    187. @imageCopyResampled($imageNew, $imageResource, 0, 0, $x, $y, $newWidth, $newHeight, $width, $height);
    188. imageSaveAlpha($imageNew, true);
    189. }
    190. else if (function_exists('imageCreate') && function_exists('imageCopyResized')) {
    191. $imageNew = @imageCreate($newWidth, $newHeight);
    192. imageAlphaBlending($imageNew, false);
    193. @imageCopyResized($imageNew, $imageResource, 0, 0, $x, $y, $newWidth, $newHeight, $width, $height);
    194. imageSaveAlpha($imageNew, true);
    195. }
    196. else return false;
    197. // create thumbnail
    198. ob_start();
    199. if ($this->imageType == 1 && function_exists('imageGIF')) {
    200. @imageGIF($imageNew);
    201. $this->mimeType = 'image/gif';
    202. }
    203. else if (($this->imageType == 1 || $this->imageType == 3) && function_exists('imagePNG')) {
    204. @imagePNG($imageNew);
    205. $this->mimeType = 'image/png';
    206. }
    207. else if (function_exists('imageJPEG')) {
    208. @imageJPEG($imageNew, '', 90);
    209. $this->mimeType = 'image/jpeg';
    210. }
    211. else {
    212. return false;
    213. }
    214. @imageDestroy($imageNew);
    215. $thumbnail = ob_get_contents();
    216. ob_end_clean();
    217. }
    218. if ($thumbnail && $this->appendSourceInfo && !$rescale) {
    219. $thumbnail = $this->appendSourceInfo($thumbnail);
    220. }
    221. return $thumbnail;
    222. }
    223. /**
    224. * Appends information about the source image to the thumbnail.
    225. *
    226. * @param string $thumbnail
    227. * @return string
    228. */
    229. protected function appendSourceInfo($thumbnail) {
    230. if (!function_exists('imageCreateFromString') || !function_exists('imageCreateTrueColor')) {
    231. return $thumbnail;
    232. }
    233. $imageSrc = imageCreateFromString($thumbnail);
    234. // get image size
    235. $width = imageSX($imageSrc);
    236. $height = imageSY($imageSrc);
    237. // increase height
    238. $heightDst = $height + self::$sourceInfoLineHeight * 2;
    239. // create new image
    240. $imageDst = imageCreateTrueColor($width, $heightDst);
    241. imageAlphaBlending($imageDst, false);
    242. // set background color
    243. $background = imageColorAllocate($imageDst, 102, 102, 102);
    244. imageFill($imageDst, 0, 0, $background);
    245. // copy image
    246. imageCopy($imageDst, $imageSrc, 0, 0, 0, 0, $width, $height);
    247. imageSaveAlpha($imageDst, true);
    248. // get font size
    249. $font = 2;
    250. $fontWidth = imageFontWidth($font);
    251. $fontHeight = imageFontHeight($font);
    252. $fontColor = imageColorAllocate($imageDst, 255, 255, 255);
    253. // write source info
    254. if($maxWidth) $this->maxWidth = $maxWidth;
    255. if($maxHeight) $this->maxHeight = $maxHeight;
    256. $line1 = $this->sourceName;
    257. // imageString supports only ISO-8859-1 encoded strings
    258. // if (CHARSET != 'ISO-8859-1') {
    259. // $line1 = StringUtil::convertEncoding(CHARSET, 'ISO-8859-1', $line1);
    260. // }
    261. // truncate text if necessary
    262. $maxChars = floor($width / $fontWidth);
    263. if (strlen($line1) > $maxChars) {
    264. $line1 = $this->truncateSourceName($line1, $maxChars);
    265. }
    266. $line2 = $this->sourceWidth.'x'.$this->sourceHeight;
    267. // write line 1
    268. // calculate text position
    269. $textX = 0;
    270. $textY = 0;
    271. if ($fontHeight < self::$sourceInfoLineHeight) {
    272. $textY = intval(round((self::$sourceInfoLineHeight - $fontHeight) / 2));
    273. }
    274. if (strlen($line1) * $fontWidth < $width) {
    275. $textX = intval(round(($width - strlen($line1) * $fontWidth) / 2));
    276. }
    277. imageString($imageDst, $font, $textX, $height + $textY, $line1, $fontColor);
    278. // write line 2
    279. // calculate text position
    280. $textX = 0;
    281. $textY = 0;
    282. if ($fontHeight < self::$sourceInfoLineHeight) {
    283. $textY = self::$sourceInfoLineHeight + intval(round((self::$sourceInfoLineHeight - $fontHeight) / 2));
    284. }
    285. if (strlen($line2) * $fontWidth < $width) {
    286. $textX = intval(round(($width - strlen($line2) * $fontWidth) / 2));
    287. }
    288. imageString($imageDst, $font, $textX, $height + $textY, $line2, $fontColor);
    289. // output image
    290. ob_start();
    291. if ($this->imageType == 1 && function_exists('imageGIF')) {
    292. @imageGIF($imageDst);
    293. $this->mimeType = 'image/gif';
    294. }
    295. else if (($this->imageType == 1 || $this->imageType == 3) && function_exists('imagePNG')) {
    296. @imagePNG($imageDst);
    297. $this->mimeType = 'image/png';
    298. }
    299. else if (function_exists('imageJPEG')) {
    300. @imageJPEG($imageDst, '', 90);
    301. $this->mimeType = 'image/jpeg';
    302. }
    303. else {
    304. return false;
    305. }
    306. @imageDestroy($imageDst);
    307. $thumbnail = ob_get_contents();
    308. ob_end_clean();
    309. return $thumbnail;
    310. }
    311. /**
    312. * Extracts the embedded thumbnail picture of a jpeg or tiff image
    313. *
    314. * @return string thumbnail
    315. */
    316. protected function extractEmbeddedThumbnail() {
    317. if (!function_exists('exif_thumbnail')) {
    318. return false;
    319. }
    320. $width = $height = $type = 0;
    321. $thumbnail = @exif_thumbnail($this->sourceFile, $width, $height, $type);
    322. if ($thumbnail && $type && $width && $height) {
    323. // resize the extracted thumbnail again if necessary
    324. // (normally the thumbnail size is set to 160px
    325. // which is recommended in EXIF >2.1 and DCF)
    326. $this->mimeType = image_type_to_mime_type($type);
    327. if (!$this->checkSize($width, $height) && function_exists('sys_get_temp_dir')) {
    328. // get temporary file name
    329. $this->sourceFile = tempnam(sys_get_temp_dir(), 'Tux');
    330. // create tmp file
    331. $fh = fopen($this->sourceFile, "w");
    332. fwrite($fh, $thumbnail);
    333. fclose($fh);
    334. unset($thumbnail, $tmpFile);
    335. // resize tmp file again
    336. return $this->makeThumbnail(true);
    337. }
    338. return $thumbnail;
    339. }
    340. return false;
    341. }
    342. /**
    343. * Checks the size of an image.
    344. */
    345. protected function checkSize($width, $height, $rescale = true) {
    346. $maxHeight = $this->maxHeight;
    347. if ($this->appendSourceInfo && $rescale) {
    348. $maxHeight -= self::$sourceInfoLineHeight * 2;
    349. }
    350. if ($width > $this->maxWidth || $height > $maxHeight) {
    351. return false;
    352. }
    353. return true;
    354. }
    355. /**
    356. * Returns the mime type of the generated thumbnail.
    357. *
    358. * @return string
    359. */
    360. public function getMimeType() {
    361. return $this->mimeType;
    362. }
    363. /**
    364. * Truncates the given file name to needed length.
    365. *
    366. * @param string $name
    367. * @param string $maxChars
    368. * @return string
    369. */
    370. protected static function truncateSourceName($name, $maxChars) {
    371. $extension = '';
    372. $lastPosition = strrpos($name, '.');
    373. if ($lastPosition !== null) {
    374. $extension = substr($name, $lastPosition);
    375. $name = substr($name, 0, $lastPosition);
    376. $maxChars -= strlen($extension);
    377. }
    378. return substr($name, 0, $maxChars - 3) . '...' . $extension;
    379. }
    380. /**
    381. *
    382. * @return boolean
    383. */
    384. public function save($targetFile, $maxWidth = 0, $maxHeight = 0) {
    385. $recover = array();
    386. if($maxWidth) {
    387. $recover['maxWidth'] = $this->maxWidth;
    388. $this->maxWidth = $maxWidth;
    389. }
    390. if($maxHeight) {
    391. $recover['maxHeight'] = $this->maxHeight;
    392. $this->maxHeight = $maxHeight;
    393. }
    394. // get thumbnail
    395. try {
    396. $success = true;
    397. if (($thumbnailData = $this->makeThumbnail())) {
    398. // save thumbnail
    399. $fh = fopen($targetFile, 'w');
    400. fwrite($fh, $thumbnailData);
    401. unset($thumbnailData);
    402. fclose($fh);
    403. }
    404. }
    405. catch (Exception $e) {
    406. $success = false;
    407. }
    408. foreach($recover as $key => $val) {
    409. $this->$key = $val;
    410. }
    411. return $success;
    412. }
    413. protected static function sendLastModified($timestamp) {
    414. // Getting headers sent by the client.
    415. $headers = apache_request_headers();
    416. // Checking if the client is validating his cache and if it is current.
    417. if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) >= $timestamp)) {
    418. // this timestamp can also be used to identify the user ;) see
    419. // Client's cache IS current, so we just respond '304 Not Modified'.
    420. header('Last-Modified: '.gmdate('D, d M Y H:i:s', $timestamp).' GMT', true, 304);
    421. exit;
    422. } else {
    423. // Image not cached or cache outdated, we respond '200 OK' and output the image.
    424. header('Last-Modified: '.gmdate('D, d M Y H:i:s', $timestamp).' GMT', true, 200);
    425. }
    426. }
    427. /**
    428. * send header and content for the picture
    429. */
    430. public function display($maxWidth = 100, $maxHeight = 100, $age = '3 MONTH') {
    431. $recover = array();
    432. if($maxWidth) {
    433. $recover['maxWidth'] = $this->maxWidth;
    434. $this->maxWidth = $maxWidth;
    435. }
    436. if($maxHeight) {
    437. $recover['maxHeight'] = $this->maxHeight;
    438. $this->maxHeight = $maxHeight;
    439. }
    440. $filemtime = @filemtime($this->sourceFile);
    441. $thumbnailData = $this->makeThumbnail();
    442. $size = strlen($thumbnailData);
    443. self::sendLastModified($filemtime);
    444. header('Accept-Ranges: bytes');
    445. header('Content-Length: '.$size);
    446. header('Content-Type: image/jpeg');
    447. header('Expires: '.gmdate('D, d M Y H:i:s', time() + strtotime($age)).' GMT');
    448. echo $thumbnailData;
    449. foreach($recover as $key => $val) {
    450. $this->$key = $val;
    451. }
    452. }
    453. }
    454. ?>
    Alles anzeigen


    == Beispiele ==
    === Bild in meheren Größen speichern ===

    Quellcode

    1. <?php
    2. require_once('Thumbnail.php');
    3. // this is the source
    4. $thumb = new Thumbnail('demo/easy-coding.png');
    5. // quadratic
    6. $thumb->save('/tmp/easy-coding.png', 150, 150);
    7. // 4:3 format
    8. $thumb->save('/tmp/easy-coding.png', 100, 75);
    9. ?>
    Alles anzeigen


    == Bild "on the fly" anzeigen ==
    Den Original Bildnamen könnt ihr zum Beispiel als $_GET Parameter oder mit mod_rewrite Regeln durchleiten. Im Beispiel wird die Vorschau für das Bild "easy-coding.png" erzeugt.
    Der dritte Parameter der Methode display kann einen Zeitausdruck wie "3 month" enthalten, dann wird das Bild für drei Monate im Browser Cache des Benutzers gespeichert, ohne dass es erneut angefragt wird und damit Traffickosten verursacht. Allerdings bekommt der Benutzer auf diese Weise auch nicht von Änderungen mit, deswegen sollte der Intervall je nach Anwendung besser bei "1 day" liegen.

    Quellcode

    1. <?php
    2. require_once('Thumbnail.php');
    3. $thumb = new Thumbnail('demo/easy-coding.png');
    4. // just display on the fly
    5. $thumb->display(150, 150);


    == Demo ==
    Die Live Demo findet ihr unter demo.easy-coding.de/php/thumbnail/, herunterladen könnt ihr euch den Code dann unter demo.easy-coding.de/php/thumbnail/download.zip

    10.092 mal gelesen