xref: /webtrees/app/MediaFile.php (revision a99c693842ed6ceb1157d751f995cb80ed1195c8)
18f5f5da8SGreg Roach<?php
28f5f5da8SGreg Roach/**
38f5f5da8SGreg Roach * webtrees: online genealogy
48f5f5da8SGreg Roach * Copyright (C) 2017 webtrees development team
58f5f5da8SGreg Roach * This program is free software: you can redistribute it and/or modify
68f5f5da8SGreg Roach * it under the terms of the GNU General Public License as published by
78f5f5da8SGreg Roach * the Free Software Foundation, either version 3 of the License, or
88f5f5da8SGreg Roach * (at your option) any later version.
98f5f5da8SGreg Roach * This program is distributed in the hope that it will be useful,
108f5f5da8SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
118f5f5da8SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128f5f5da8SGreg Roach * GNU General Public License for more details.
138f5f5da8SGreg Roach * You should have received a copy of the GNU General Public License
148f5f5da8SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
158f5f5da8SGreg Roach */
168f5f5da8SGreg Roachnamespace Fisharebest\Webtrees;
178f5f5da8SGreg Roach
188f5f5da8SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
198f5f5da8SGreg Roachuse League\Glide\Urls\UrlBuilderFactory;
208f5f5da8SGreg Roach
218f5f5da8SGreg Roach/**
228f5f5da8SGreg Roach * A GEDCOM media file.  A media object can contain many media files,
238f5f5da8SGreg Roach * such as scans of both sides of a document, the transcript of an audio
248f5f5da8SGreg Roach * recording, etc.
258f5f5da8SGreg Roach */
268f5f5da8SGreg Roachclass MediaFile {
278f5f5da8SGreg Roach	/** @var string The filename */
288f5f5da8SGreg Roach	private $multimedia_file_refn = '';
298f5f5da8SGreg Roach
308f5f5da8SGreg Roach	/** @var string The file extension; jpeg, txt, mp4, etc. */
318f5f5da8SGreg Roach	private $multimedia_format = '';
328f5f5da8SGreg Roach
338f5f5da8SGreg Roach	/** @var string The type of document; newspaper, microfiche, etc. */
348f5f5da8SGreg Roach  private $source_media_type = '';
358f5f5da8SGreg Roach	/** @var string The filename */
368f5f5da8SGreg Roach
378f5f5da8SGreg Roach	/** @var string The name of the document */
388f5f5da8SGreg Roach  private $descriptive_title = '';
398f5f5da8SGreg Roach
408f5f5da8SGreg Roach  /** @var Media $media The media object to which this file belongs */
418f5f5da8SGreg Roach  private $media;
428f5f5da8SGreg Roach
438f5f5da8SGreg Roach	/**
448f5f5da8SGreg Roach	 * Create a MediaFile from raw GEDCOM data.
458f5f5da8SGreg Roach	 *
468f5f5da8SGreg Roach	 * @param string $gedcom
478f5f5da8SGreg Roach	 * @param Media  $media
488f5f5da8SGreg Roach	 */
498f5f5da8SGreg Roach	public function __construct($gedcom, Media $media) {
508f5f5da8SGreg Roach		$this->media = $media;
518f5f5da8SGreg Roach
528f5f5da8SGreg Roach		if (preg_match('/^\d FILE (.+)/m', $gedcom, $match)) {
538f5f5da8SGreg Roach			$this->multimedia_file_refn = $match[1];
548f5f5da8SGreg Roach		}
558f5f5da8SGreg Roach
568f5f5da8SGreg Roach		if (preg_match('/^\d FORM (.+)/m', $gedcom, $match)) {
578f5f5da8SGreg Roach			$this->multimedia_format = $match[1];
588f5f5da8SGreg Roach		}
598f5f5da8SGreg Roach
608f5f5da8SGreg Roach		if (preg_match('/^\d TYPE (.+)/m', $gedcom, $match)) {
618f5f5da8SGreg Roach			$this->source_media_type = $match[1];
628f5f5da8SGreg Roach		}
638f5f5da8SGreg Roach
648f5f5da8SGreg Roach		if (preg_match('/^\d TITL (.+)/m', $gedcom, $match)) {
658f5f5da8SGreg Roach			$this->descriptive_title = $match[1];
668f5f5da8SGreg Roach		}
678f5f5da8SGreg Roach	}
688f5f5da8SGreg Roach
698f5f5da8SGreg Roach	/**
708f5f5da8SGreg Roach	 * Get the filename
718f5f5da8SGreg Roach	 *
728f5f5da8SGreg Roach	 * @return string
738f5f5da8SGreg Roach	 */
746e6a9947SGreg Roach	public function filename(): string {
756e6a9947SGreg Roach		return $this->multimedia_file_refn;
768f5f5da8SGreg Roach	}
778f5f5da8SGreg Roach
788f5f5da8SGreg Roach	/**
798f5f5da8SGreg Roach	 * Get the format
808f5f5da8SGreg Roach	 *
818f5f5da8SGreg Roach	 * @return string
828f5f5da8SGreg Roach	 */
836e6a9947SGreg Roach	public function format(): string {
848f5f5da8SGreg Roach		return $this->multimedia_format;
858f5f5da8SGreg Roach	}
868f5f5da8SGreg Roach
878f5f5da8SGreg Roach	/**
888f5f5da8SGreg Roach	 * Get the type
898f5f5da8SGreg Roach	 *
908f5f5da8SGreg Roach	 * @return string
918f5f5da8SGreg Roach	 */
926e6a9947SGreg Roach	public function type(): string {
938f5f5da8SGreg Roach		return $this->source_media_type;
948f5f5da8SGreg Roach	}
958f5f5da8SGreg Roach
968f5f5da8SGreg Roach	/**
978f5f5da8SGreg Roach	 * Get the title
988f5f5da8SGreg Roach	 *
998f5f5da8SGreg Roach	 * @return string
1008f5f5da8SGreg Roach	 */
1016e6a9947SGreg Roach	public function title(): string {
1028f5f5da8SGreg Roach		return $this->descriptive_title;
1038f5f5da8SGreg Roach	}
1048f5f5da8SGreg Roach
1058f5f5da8SGreg Roach	/**
1068f5f5da8SGreg Roach	 * Get the filename on the server - for those (very few!) functions which actually
1078f5f5da8SGreg Roach	 * need the filename, such as mediafirewall.php and the PDF reports.
1088f5f5da8SGreg Roach	 *
1098f5f5da8SGreg Roach	 * @return string
1108f5f5da8SGreg Roach	 */
1118f5f5da8SGreg Roach	public function getServerFilename() {
1128f5f5da8SGreg Roach		$MEDIA_DIRECTORY = $this->media->getTree()->getPreference('MEDIA_DIRECTORY');
1138f5f5da8SGreg Roach
1148f5f5da8SGreg Roach		if ($this->isExternal() || !$this->file) {
1158f5f5da8SGreg Roach			// External image, or (in the case of corrupt GEDCOM data) no image at all
1168f5f5da8SGreg Roach			return $this->file;
1178f5f5da8SGreg Roach		} else {
1188f5f5da8SGreg Roach			// Main image
1198f5f5da8SGreg Roach			return WT_DATA_DIR . $MEDIA_DIRECTORY . $this->file;
1208f5f5da8SGreg Roach		}
1218f5f5da8SGreg Roach	}
1228f5f5da8SGreg Roach
1238f5f5da8SGreg Roach	/**
1248f5f5da8SGreg Roach	 * check if the file exists on this server
1258f5f5da8SGreg Roach	 *
1268f5f5da8SGreg Roach	 * @return bool
1278f5f5da8SGreg Roach	 */
1288f5f5da8SGreg Roach	public function fileExists() {
1298f5f5da8SGreg Roach		return file_exists($this->getServerFilename());
1308f5f5da8SGreg Roach	}
1318f5f5da8SGreg Roach
1328f5f5da8SGreg Roach	/**
1338f5f5da8SGreg Roach	 * Determine if the file is an external url
1348f5f5da8SGreg Roach	 *
1358f5f5da8SGreg Roach	 * @return bool
1368f5f5da8SGreg Roach	 */
1378f5f5da8SGreg Roach	public function isExternal() {
1388f5f5da8SGreg Roach		return strpos($this->file, '://') !== false;
1398f5f5da8SGreg Roach	}
1408f5f5da8SGreg Roach
1418f5f5da8SGreg Roach	/**
1428f5f5da8SGreg Roach	 * get the media file size in KB
1438f5f5da8SGreg Roach	 *
1448f5f5da8SGreg Roach	 * @return string
1458f5f5da8SGreg Roach	 */
1468f5f5da8SGreg Roach	public function getFilesize() {
1478f5f5da8SGreg Roach		$size = $this->getFilesizeraw();
1488f5f5da8SGreg Roach		// Round up to the nearest KB.
1498f5f5da8SGreg Roach		$size = (int) (($size + 1023) / 1024);
1508f5f5da8SGreg Roach
1518f5f5da8SGreg Roach		return /* I18N: size of file in KB */
1528f5f5da8SGreg Roach			I18N::translate('%s KB', I18N::number($size));
1538f5f5da8SGreg Roach	}
1548f5f5da8SGreg Roach
1558f5f5da8SGreg Roach	/**
1568f5f5da8SGreg Roach	 * get the media file size, unformatted
1578f5f5da8SGreg Roach	 *
1588f5f5da8SGreg Roach	 * @return int
1598f5f5da8SGreg Roach	 */
1608f5f5da8SGreg Roach	public function getFilesizeraw() {
1618f5f5da8SGreg Roach		try {
1628f5f5da8SGreg Roach			return filesize($this->getServerFilename());
1638f5f5da8SGreg Roach		} catch (\ErrorException $ex) {
1648f5f5da8SGreg Roach			DebugBar::addThrowable($ex);
1658f5f5da8SGreg Roach
1668f5f5da8SGreg Roach			return 0;
1678f5f5da8SGreg Roach		}
1688f5f5da8SGreg Roach	}
1698f5f5da8SGreg Roach
1708f5f5da8SGreg Roach	/**
1718f5f5da8SGreg Roach	 * Deprecated? This does not need to be a function here.
1728f5f5da8SGreg Roach	 *
1738f5f5da8SGreg Roach	 * @return string
1748f5f5da8SGreg Roach	 */
1758f5f5da8SGreg Roach	public function getMediaType() {
1768f5f5da8SGreg Roach		if (preg_match('/\n\d TYPE (.+)/', $this->gedcom, $match)) {
1778f5f5da8SGreg Roach			return strtolower($match[1]);
1788f5f5da8SGreg Roach		} else {
1798f5f5da8SGreg Roach			return '';
1808f5f5da8SGreg Roach		}
1818f5f5da8SGreg Roach	}
1828f5f5da8SGreg Roach
1838f5f5da8SGreg Roach	/**
1848f5f5da8SGreg Roach	 * get image properties
1858f5f5da8SGreg Roach	 *
1868f5f5da8SGreg Roach	 * @return array
1878f5f5da8SGreg Roach	 */
1888f5f5da8SGreg Roach	public function getImageAttributes() {
1898f5f5da8SGreg Roach		$imgsize = [];
1908f5f5da8SGreg Roach		if ($this->fileExists()) {
1918f5f5da8SGreg Roach			try {
1928f5f5da8SGreg Roach				$imgsize = getimagesize($this->getServerFilename());
1938f5f5da8SGreg Roach				if (is_array($imgsize) && !empty($imgsize['0'])) {
1948f5f5da8SGreg Roach					// this is an image
1958f5f5da8SGreg Roach					$imageTypes     = ['', 'GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF', 'TIFF', 'JPC', 'JP2', 'JPX', 'JB2', 'SWC', 'IFF', 'WBMP', 'XBM'];
1968f5f5da8SGreg Roach					$imgsize['ext'] = $imageTypes[0 + $imgsize[2]];
1978f5f5da8SGreg Roach					// this is for display purposes, always show non-adjusted info
1988f5f5da8SGreg Roach					$imgsize['WxH'] = /* I18N: image dimensions, width × height */
1998f5f5da8SGreg Roach						I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1']));
2008f5f5da8SGreg Roach				}
2018f5f5da8SGreg Roach			} catch (\ErrorException $ex) {
2028f5f5da8SGreg Roach				DebugBar::addThrowable($ex);
2038f5f5da8SGreg Roach
2048f5f5da8SGreg Roach				// Not an image, or not a valid image?
2058f5f5da8SGreg Roach				$imgsize = false;
2068f5f5da8SGreg Roach			}
2078f5f5da8SGreg Roach		}
2088f5f5da8SGreg Roach
2098f5f5da8SGreg Roach		if (!is_array($imgsize) || empty($imgsize['0'])) {
2108f5f5da8SGreg Roach			// this is not an image, OR the file doesn’t exist OR it is a url
2118f5f5da8SGreg Roach			$imgsize[0]      = 0;
2128f5f5da8SGreg Roach			$imgsize[1]      = 0;
2138f5f5da8SGreg Roach			$imgsize['ext']  = '';
2148f5f5da8SGreg Roach			$imgsize['mime'] = '';
2158f5f5da8SGreg Roach			$imgsize['WxH']  = '';
2168f5f5da8SGreg Roach		}
2178f5f5da8SGreg Roach
2188f5f5da8SGreg Roach		if (empty($imgsize['mime'])) {
2198f5f5da8SGreg Roach			// this is not an image, OR the file doesn’t exist OR it is a url
2208f5f5da8SGreg Roach			// set file type equal to the file extension - can’t use parse_url because this may not be a full url
2218f5f5da8SGreg Roach			$exp            = explode('?', $this->file);
2228f5f5da8SGreg Roach			$imgsize['ext'] = strtoupper(pathinfo($exp[0], PATHINFO_EXTENSION));
2238f5f5da8SGreg Roach			// all mimetypes we wish to serve with the media firewall must be added to this array.
2248f5f5da8SGreg Roach			$mime = [
2258f5f5da8SGreg Roach				'DOC' => 'application/msword',
2268f5f5da8SGreg Roach				'MOV' => 'video/quicktime',
2278f5f5da8SGreg Roach				'MP3' => 'audio/mpeg',
2288f5f5da8SGreg Roach				'PDF' => 'application/pdf',
2298f5f5da8SGreg Roach				'PPT' => 'application/vnd.ms-powerpoint',
2308f5f5da8SGreg Roach				'RTF' => 'text/rtf',
2318f5f5da8SGreg Roach				'SID' => 'image/x-mrsid',
2328f5f5da8SGreg Roach				'TXT' => 'text/plain',
2338f5f5da8SGreg Roach				'XLS' => 'application/vnd.ms-excel',
2348f5f5da8SGreg Roach				'WMV' => 'video/x-ms-wmv',
2358f5f5da8SGreg Roach			];
2368f5f5da8SGreg Roach			if (empty($mime[$imgsize['ext']])) {
2378f5f5da8SGreg Roach				// if we don’t know what the mimetype is, use something ambiguous
2388f5f5da8SGreg Roach				$imgsize['mime'] = 'application/octet-stream';
2398f5f5da8SGreg Roach				if ($this->fileExists()) {
2408f5f5da8SGreg Roach					// alert the admin if we cannot determine the mime type of an existing file
2418f5f5da8SGreg Roach					// as the media firewall will be unable to serve this file properly
2428f5f5da8SGreg Roach					Log::addMediaLog('Media Firewall error: >Unknown Mimetype< for file >' . $this->file . '<');
2438f5f5da8SGreg Roach				}
2448f5f5da8SGreg Roach			} else {
2458f5f5da8SGreg Roach				$imgsize['mime'] = $mime[$imgsize['ext']];
2468f5f5da8SGreg Roach			}
2478f5f5da8SGreg Roach		}
2488f5f5da8SGreg Roach
2498f5f5da8SGreg Roach		return $imgsize;
2508f5f5da8SGreg Roach	}
2518f5f5da8SGreg Roach
2528f5f5da8SGreg Roach	/**
2538f5f5da8SGreg Roach	 * Generate a URL for an image.
2548f5f5da8SGreg Roach	 *
2558f5f5da8SGreg Roach	 * @param int    $width  Maximum width in pixels
2568f5f5da8SGreg Roach	 * @param int    $height Maximum height in pixels
2578f5f5da8SGreg Roach	 * @param string $fit    "crop" or "contain"
2588f5f5da8SGreg Roach	 *
2598f5f5da8SGreg Roach	 * @return string
2608f5f5da8SGreg Roach	 */
2618f5f5da8SGreg Roach	public function imageUrl($width, $height, $fit) {
2628f5f5da8SGreg Roach		// Sign the URL, to protect against mass-resize attacks.
2638f5f5da8SGreg Roach		$glide_key = Site::getPreference('glide-key');
2648f5f5da8SGreg Roach		if (empty($glide_key)) {
2658f5f5da8SGreg Roach			$glide_key = bin2hex(random_bytes(128));
2668f5f5da8SGreg Roach			Site::setPreference('glide-key', $glide_key);
2678f5f5da8SGreg Roach		}
2688f5f5da8SGreg Roach
2698f5f5da8SGreg Roach		if (Auth::accessLevel($this->getTree()) > $this->getTree()->getPreference('SHOW_NO_WATERMARK')) {
2708f5f5da8SGreg Roach			$mark = 'watermark.png';
2718f5f5da8SGreg Roach		} else {
2728f5f5da8SGreg Roach			$mark = '';
2738f5f5da8SGreg Roach		}
2748f5f5da8SGreg Roach
2758f5f5da8SGreg Roach		$url = UrlBuilderFactory::create(WT_BASE_URL, $glide_key)
2768f5f5da8SGreg Roach			->getUrl('mediafirewall.php', [
2778f5f5da8SGreg Roach				'mid'       => $this->getXref(),
2788f5f5da8SGreg Roach				'ged'       => $this->tree->getName(),
2798f5f5da8SGreg Roach				'w'         => $width,
2808f5f5da8SGreg Roach				'h'         => $height,
2818f5f5da8SGreg Roach				'fit'       => $fit,
2828f5f5da8SGreg Roach				'mark'      => $mark,
2838f5f5da8SGreg Roach				'markh'     => '100h',
2848f5f5da8SGreg Roach				'markw'     => '100w',
2858f5f5da8SGreg Roach				'markalpha' => 25,
2868f5f5da8SGreg Roach				'or'        => 0, // Intervention uses exif_read_data() which is very buggy.
2878f5f5da8SGreg Roach			]);
2888f5f5da8SGreg Roach
2898f5f5da8SGreg Roach		return $url;
2908f5f5da8SGreg Roach	}
2918f5f5da8SGreg Roach
2928f5f5da8SGreg Roach	/**
2938f5f5da8SGreg Roach	 * What file extension is used by this file?
2948f5f5da8SGreg Roach	 *
2958f5f5da8SGreg Roach	 * @return string
2968f5f5da8SGreg Roach	 */
2978f5f5da8SGreg Roach	public function extension() {
298*a99c6938SGreg Roach		if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->multimedia_file_refn, $match)) {
2998f5f5da8SGreg Roach			return strtolower($match[1]);
3008f5f5da8SGreg Roach		} else {
3018f5f5da8SGreg Roach			return '';
3028f5f5da8SGreg Roach		}
3038f5f5da8SGreg Roach	}
3048f5f5da8SGreg Roach
3058f5f5da8SGreg Roach	/**
3068f5f5da8SGreg Roach	 * What is the mime-type of this object?
3078f5f5da8SGreg Roach	 * For simplicity and efficiency, use the extension, rather than the contents.
3088f5f5da8SGreg Roach	 *
3098f5f5da8SGreg Roach	 * @return string
3108f5f5da8SGreg Roach	 */
3118f5f5da8SGreg Roach	public function mimeType() {
3128f5f5da8SGreg Roach		// Themes contain icon definitions for some/all of these mime-types
3138f5f5da8SGreg Roach		switch ($this->extension()) {
3148f5f5da8SGreg Roach		case 'bmp':
3158f5f5da8SGreg Roach			return 'image/bmp';
3168f5f5da8SGreg Roach		case 'doc':
3178f5f5da8SGreg Roach			return 'application/msword';
3188f5f5da8SGreg Roach		case 'docx':
3198f5f5da8SGreg Roach			return 'application/msword';
3208f5f5da8SGreg Roach		case 'ged':
3218f5f5da8SGreg Roach			return 'text/x-gedcom';
3228f5f5da8SGreg Roach		case 'gif':
3238f5f5da8SGreg Roach			return 'image/gif';
3248f5f5da8SGreg Roach		case 'htm':
3258f5f5da8SGreg Roach			return 'text/html';
3268f5f5da8SGreg Roach		case 'html':
3278f5f5da8SGreg Roach			return 'text/html';
3288f5f5da8SGreg Roach		case 'jpeg':
3298f5f5da8SGreg Roach			return 'image/jpeg';
3308f5f5da8SGreg Roach		case 'jpg':
3318f5f5da8SGreg Roach			return 'image/jpeg';
3328f5f5da8SGreg Roach		case 'mov':
3338f5f5da8SGreg Roach			return 'video/quicktime';
3348f5f5da8SGreg Roach		case 'mp3':
3358f5f5da8SGreg Roach			return 'audio/mpeg';
3368f5f5da8SGreg Roach		case 'mp4':
3378f5f5da8SGreg Roach			return 'video/mp4';
3388f5f5da8SGreg Roach		case 'ogv':
3398f5f5da8SGreg Roach			return 'video/ogg';
3408f5f5da8SGreg Roach		case 'pdf':
3418f5f5da8SGreg Roach			return 'application/pdf';
3428f5f5da8SGreg Roach		case 'png':
3438f5f5da8SGreg Roach			return 'image/png';
3448f5f5da8SGreg Roach		case 'rar':
3458f5f5da8SGreg Roach			return 'application/x-rar-compressed';
3468f5f5da8SGreg Roach		case 'swf':
3478f5f5da8SGreg Roach			return 'application/x-shockwave-flash';
3488f5f5da8SGreg Roach		case 'svg':
3498f5f5da8SGreg Roach			return 'image/svg';
3508f5f5da8SGreg Roach		case 'tif':
3518f5f5da8SGreg Roach			return 'image/tiff';
3528f5f5da8SGreg Roach		case 'tiff':
3538f5f5da8SGreg Roach			return 'image/tiff';
3548f5f5da8SGreg Roach		case 'xls':
3558f5f5da8SGreg Roach			return 'application/vnd-ms-excel';
3568f5f5da8SGreg Roach		case 'xlsx':
3578f5f5da8SGreg Roach			return 'application/vnd-ms-excel';
3588f5f5da8SGreg Roach		case 'wmv':
3598f5f5da8SGreg Roach			return 'video/x-ms-wmv';
3608f5f5da8SGreg Roach		case 'zip':
3618f5f5da8SGreg Roach			return 'application/zip';
3628f5f5da8SGreg Roach		default:
3638f5f5da8SGreg Roach			return 'application/octet-stream';
3648f5f5da8SGreg Roach		}
3658f5f5da8SGreg Roach	}
3668f5f5da8SGreg Roach
3678f5f5da8SGreg Roach	/**
3688f5f5da8SGreg Roach	 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
3698f5f5da8SGreg Roach	 *
3708f5f5da8SGreg Roach	 * @param int      $width      Pixels
3718f5f5da8SGreg Roach	 * @param int      $height     Pixels
3728f5f5da8SGreg Roach	 * @param string   $fit        "crop" or "contain"
3738f5f5da8SGreg Roach	 * @param string[] $attributes Additional HTML attributes
3748f5f5da8SGreg Roach	 *
3758f5f5da8SGreg Roach	 * @return string
3768f5f5da8SGreg Roach	 */
3778f5f5da8SGreg Roach	public function displayImage($width, $height, $fit, $attributes = []) {
3788f5f5da8SGreg Roach		// Default image for external, missing or corrupt images.
3798f5f5da8SGreg Roach		$image
3808f5f5da8SGreg Roach			= '<i' .
3818f5f5da8SGreg Roach			' dir="auto"' . // For the tool-tip
3828f5f5da8SGreg Roach			' class="icon-mime-' . str_replace('/', '-', $this->mimeType()) . '"' .
3838f5f5da8SGreg Roach			' title="' . strip_tags($this->getFullName()) . '"' .
3848f5f5da8SGreg Roach			'></i>';
3858f5f5da8SGreg Roach
3868f5f5da8SGreg Roach		// Use a thumbnail image.
3878f5f5da8SGreg Roach		if ($this->isExternal()) {
3888f5f5da8SGreg Roach			$src    = $this->getFilename();
3898f5f5da8SGreg Roach			$srcset = [];
3908f5f5da8SGreg Roach		} else {
3918f5f5da8SGreg Roach			// Generate multiple images for displays with higher pixel densities.
3928f5f5da8SGreg Roach			$src    = $this->imageUrl($width, $height, $fit);
3938f5f5da8SGreg Roach			$srcset = [];
3948f5f5da8SGreg Roach			foreach ([2, 3, 4] as $x) {
3958f5f5da8SGreg Roach				$srcset[] = $this->imageUrl($width * $x, $height * $x, $fit) . ' ' . $x . 'x';
3968f5f5da8SGreg Roach			}
3978f5f5da8SGreg Roach		}
3988f5f5da8SGreg Roach
3998f5f5da8SGreg Roach		$image = '<img ' . Html::attributes($attributes + [
4008f5f5da8SGreg Roach					'dir'    => 'auto',
4018f5f5da8SGreg Roach					'src'    => $src,
4028f5f5da8SGreg Roach					'srcset' => implode(',', $srcset),
4038f5f5da8SGreg Roach					'alt'    => strip_tags($this->getFullName()),
4048f5f5da8SGreg Roach				]) . '>';
4058f5f5da8SGreg Roach
4068f5f5da8SGreg Roach		$attributes = Html::attributes([
4078f5f5da8SGreg Roach			'class' => 'gallery',
4088f5f5da8SGreg Roach			'type'  => $this->mimeType(),
4098f5f5da8SGreg Roach			'href'  => $this->imageUrl(0, 0, ''),
4108f5f5da8SGreg Roach		]);
4118f5f5da8SGreg Roach
4128f5f5da8SGreg Roach		return '<a ' . $attributes . '>' . $image . '</a>';
4138f5f5da8SGreg Roach	}
4148f5f5da8SGreg Roach}
415