Passed
Push — master ( 8e0f36...cdb6de )
by Aimeos
06:20
created

Svg   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
dl 0
loc 159
rs 10
c 1
b 0
f 0
wmc 21

8 Methods

Rating   Name   Duplication   Size   Complexity  
A save() 0 15 4
A getHeight() 0 3 2
A __construct() 0 17 4
A scale() 0 20 4
A getWidth() 0 3 2
A __clone() 0 3 1
A supports() 0 3 2
A box() 0 15 2
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2019-2022
6
 * @package MW
7
 * @subpackage Media
8
 */
9
10
11
namespace Aimeos\MW\Media\Image;
12
13
use enshrined\svgSanitize\Sanitizer;
14
15
16
/**
17
 * Image class for SVG files
18
 *
19
 * @package MW
20
 * @subpackage Media
21
 */
22
class Svg
23
	extends \Aimeos\MW\Media\Image\Base
24
	implements \Aimeos\MW\Media\Image\Iface
25
{
26
	private $svg;
27
28
29
	/**
30
	 * Initializes the new image object.
31
	 *
32
	 * @param string $content File content
33
	 * @param string $mimetype Mime type of the media data
34
	 * @throws \Aimeos\MW\Media\Exception If image couldn't be retrieved from the given file name
35
	 */
36
	public function __construct( string $content, string $mimetype )
37
	{
38
		parent::__construct( $mimetype );
39
40
		if( ( $string = @gzdecode( $content ) ) !== false ) {
41
			$content = $string;
42
		}
43
44
		$sanitizer = new Sanitizer();
45
		$sanitizer->removeRemoteReferences( true );
46
47
		if( ( $content = $sanitizer->sanitize( $content ) ) === false ) {
48
			throw new \Aimeos\MW\Media\Exception( 'Invalid SVG file: ' . print_r( $sanitizer->getXmlIssues(), true ) );
49
		}
50
51
		if( ( $this->svg = @simplexml_load_string( $content ) ) === false ) {
52
			throw new \Aimeos\MW\Media\Exception( 'Invalid SVG file' );
53
		}
54
	}
55
56
57
	/**
58
	 * Clone resources
59
	 */
60
	public function __clone()
61
	{
62
		$this->svg = clone $this->svg;
63
	}
64
65
66
	/**
67
	 * Returns the height of the image
68
	 *
69
	 * @return int Height in pixel
70
	 */
71
	public function getHeight() : int
72
	{
73
		return ( isset( $this->svg['height'] ) ? (int) preg_replace( '/[^0-9.]/', '', $this->svg['height'] ) : 1 );
74
	}
75
76
77
	/**
78
	 * Returns the width of the image
79
	 *
80
	 * @return int Width in pixel
81
	 */
82
	public function getWidth() : int
83
	{
84
		return ( isset( $this->svg['width'] ) ? (int) preg_replace( '/[^0-9.]/', '', $this->svg['width'] ) : 1 );
85
	}
86
87
88
	/**
89
	 * Stores the media data at the given file name.
90
	 *
91
	 * @param string|null $filename File name to save the data into or null to return the data
92
	 * @param string|null $mimetype Mime type to save the content as or null to leave the mime type unchanged
93
	 * @return string|null File content if file name is null or null if data is saved to the given file name
94
	 * @throws \Aimeos\MW\Media\Exception If image couldn't be saved to the given file name
95
	 */
96
	public function save( string $filename = null, string $mimetype = null ) : ?string
97
	{
98
		if( ( $content = $this->svg->asXml() ) === false ) {
99
			throw new \Aimeos\MW\Media\Exception( 'Could not create SVG file' );
100
		}
101
102
		if( $filename === null ) {
103
			return $content;
104
		}
105
106
		if( file_put_contents( $filename, $content ) === false ) {
107
			throw new \Aimeos\MW\Media\Exception( 'Could not save SVG file' );
108
		}
109
110
		return null;
111
	}
112
113
114
	/**
115
	 * Scales the image to the given width and height.
116
	 *
117
	 * @param int|null $width New width of the image or null for automatic calculation
118
	 * @param int|null $height New height of the image or null for automatic calculation
119
	 * @param int $fit "0" keeps image ratio, "1" adds padding while "2" crops image to enforce image size
120
	 * @return \Aimeos\MW\Media\Image\Iface Self object for method chaining
121
	 */
122
	public function scale( int $width = null, int $height = null, int $fit = 0 ) : Iface
123
	{
124
		if( $width == null && $height == null ) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $height of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $width of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
125
			return $this;
126
		}
127
128
		$w = $this->getWidth();
129
		$h = $this->getHeight();
130
		$newMedia = clone $this;
131
132
		if( $fit === 2 ) {
133
			$newMedia->svg['viewBox'] = $this->box( $w, $h, $width / $height, $height / $width );
134
		} else {
135
			$newMedia->svg['viewBox'] = $this->box( $w, $h, $w / $h, $h / $w );
136
		}
137
138
		$newMedia->svg['width'] = $width;
139
		$newMedia->svg['height'] = $height;
140
141
		return $newMedia;
142
	}
143
144
145
	/**
146
	 * Returns the supported image mime types
147
	 *
148
	 * @param array|string $mimetypes Mime type or list of mime types to check against
149
	 * @return array List of supported mime types
150
	 */
151
	public static function supports( $mimetypes = [] ) : array
152
	{
153
		return empty( $mimetypes ) ? ['image/svg+xml'] : array_intersect( ['image/svg+xml'], (array) $mimetypes );
154
	}
155
156
157
	/**
158
	 * Returns the fitted width and height.
159
	 *
160
	 * @param int $srcWidth Width of the image
161
	 * @param int $srcHeight Height of the image
162
	 * @param int|null $destWidth New width of the image
163
	 * @param int|null $destHeight New height of the image
164
	 * @return array Array containing the new width at position 0 and the new height as position 1
165
	 */
166
	protected function box( int $srcWidth, int $srcHeight, float $wRatio, float $hRatio ) : string
167
	{
168
		$newWidth = $srcWidth;
169
		$newHeight = $srcHeight;
170
171
		if( $wRatio > $hRatio ) {
172
			$newHeight = (int) round( $srcHeight / $wRatio );
173
		} else {
174
			$newWidth = (int) round( $srcWidth / $hRatio );
175
		}
176
177
		$x = round( ( $srcWidth - $newWidth ) / 2 );
178
		$y = round( ( $srcHeight - $newHeight ) / 2 );
179
180
		return $x . ' ' . $y . ' ' . $newWidth . ' ' . $newHeight;
181
	}
182
}
183