Skip to content

Commit

Permalink
Add better support for SVG images
Browse files Browse the repository at this point in the history
  • Loading branch information
gchtr committed Feb 21, 2022
1 parent 7eaf1d6 commit ab65831
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 30 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
- Added `get_timber_image_loading()` function.
- Added `get_timber_picture_responsive()` function.
- Added `get_timber_picture_fallback_image()` function.
- Added `get_timber_image_mime_type` function.
- Added better support for SVG images.
- Fixed a bug when Timmy tried to resize files that it shouldn’t (video files for example).
- Fixed issue when Timmy created upscaled image files even though it shouldn’t.
- Changed oversize configuration option naming from `oversize` to `upscale`. You can still use `oversize`, but it will be deprecated in the future.
Expand Down
40 changes: 40 additions & 0 deletions lib/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,46 @@ public static function get_mime_types() {
return $mime_types;
}

/**
* Gets SVG size from the width/height or viewport of an SVG.
*
* @since 1.0.0
*
* @param string $svg The path to the SVG file.
*
* @return array|null
*/
public static function get_svg_dimensions( $svg ) {
$svg = simplexml_load_file( $svg );
$width = 0;
$height = 0;

if ( false === $svg ) {
return null;
}

$attributes = $svg->attributes();

if ( isset( $attributes->width, $attributes->height ) ) {
$width = floatval( $attributes->width );
$height = floatval( $attributes->height );
} elseif ( isset( $attributes->viewBox ) ) {
$sizes = explode( ' ', $attributes->viewBox );

if ( isset( $sizes[2], $sizes[3] ) ) {
$width = (float) $sizes[2];
$height = (float) $sizes[3];
}
} else {
return null;
}

return [
'width' => $width,
'height' => $height,
];
}

/**
* Output an error message.
*
Expand Down
78 changes: 75 additions & 3 deletions lib/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class Image {

protected $full_src;

/**
* Absolute attachment path.
*
* @var
*/
protected $path;

protected $meta;

protected $max_width;
Expand All @@ -43,6 +50,13 @@ class Image {

protected $upscale;

/**
* Dimensions for SVG image.
*
* @var array
*/
protected $svg_dimensions = [];

final protected function __construct() {}

/**
Expand Down Expand Up @@ -108,6 +122,19 @@ public function full_src() {
return $this->full_src;
}

/**
* Gets absolute attachment path.
*
* @return false|string
*/
public function path() {
if ( empty( $this->path ) ) {
$this->path = get_attached_file( $this->id );
}

return $this->path;
}

/**
* Gets the src (url) for the image.
*
Expand Down Expand Up @@ -407,7 +434,13 @@ public function sizes() {
}

public function max_width() {
if ( empty( $this->max_width ) ) {
if ( $this->is_svg() ) {
$dimensions = $this->svg_dimensions();

if ( $dimensions['width'] > 0 ) {
$this->max_width = round( $dimensions['width'] );
}
} elseif ( empty( $this->max_width ) ) {
$this->load_attachment_meta_data();

$this->max_width = $this->meta['width'];
Expand All @@ -417,7 +450,13 @@ public function max_width() {
}

public function max_height() {
if ( empty( $this->max_height ) ) {
if ( $this->is_svg() ) {
$dimensions = $this->svg_dimensions();

if ( $dimensions['height'] > 0 ) {
$this->max_height = round( $dimensions['height'] );
}
} elseif ( empty( $this->max_height ) ) {
$this->load_attachment_meta_data();

$this->max_height = $this->meta['height'];
Expand All @@ -433,27 +472,47 @@ public function max_height() {
*/
public function width() {
list( $width, $height ) = Helper::get_dimensions_for_size( $this->size );

if ( $this->is_svg() ) {
$dimensions = $this->svg_dimensions();

if ( empty( $dimensions ) ) {
return false;
}
} else {
list( $width ) = Helper::get_dimensions_upscale( $width, $height, [
'upscale' => $this->upscale,
'resize' => $this->size['resize'],
'max_width' => $this->max_width(),
'max_height' => $this->max_height(),
] );
}

return $width;
}

public function height() {
list( $width, $height ) = Helper::get_dimensions_for_size( $this->size );

$height = Helper::maybe_fix_height( $height, $width, $this->max_width(), $this->max_height() );
if ( $this->is_svg() ) {
$dimensions = $this->svg_dimensions();

if ( empty( $dimensions ) ) {
return false;
}

if ( $dimensions['width'] && $dimensions['height'] ) {
$height = Helper::get_height_from_width( $width, $dimensions['width'], $dimensions['height'] );
}
} else {
$height = Helper::maybe_fix_height( $height, $width, $this->max_width(), $this->max_height() );
list( , $height ) = Helper::get_dimensions_upscale( $width, $height, [
'upscale' => $this->upscale,
'resize' => $this->size['resize'],
'max_width' => $this->max_width(),
'max_height' => $this->max_height(),
] );
}

return $height;
}
Expand Down Expand Up @@ -674,6 +733,19 @@ public function description() {
return null;
}

/**
* Gets dimensions for an SVG image.
*
* @return array
*/
public function svg_dimensions() {
if ( empty( $this->svg_dimensions ) ) {
$this->svg_dimensions = Helper::get_svg_dimensions( $this->path() );
}

return $this->svg_dimensions;
}

/**
* Gets the mime type for a Timber image.
*
Expand Down
1 change: 1 addition & 0 deletions tests/assets/svg-400-200.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tests/assets/svg-without-viewbox.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 0 additions & 26 deletions tests/test-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,33 +217,7 @@ public function test_get_timber_image_full_with_gif() {
$this->assertEquals( $image, $result );
}

/**
* Tests whether we get the full src of an SVG with size full.
*
* @since 0.14.4
*/
public function test_get_timber_image_full_with_svg() {
$attachment = $this->create_image( [ 'file' => 'sveegee.svg' ] );
$result = get_timber_image( $attachment, 'full' );

$image = ' src="' . $this->get_upload_url() . '/sveegee.svg" alt=""';

$this->assertEquals( $image, $result );
}

/**
* Tests whether we get the full src of an SVG with size large.
*
* @since 0.14.4
*/
public function test_get_timber_image_large_with_svg() {
$attachment = $this->create_image( [ 'file' => 'sveegee.svg' ] );
$result = get_timber_image( $attachment, 'large' );

$image = ' src="' . $this->get_upload_url() . '/sveegee.svg" alt=""';

$this->assertEquals( $image, $result );
}

/**
* @since 0.14.5
Expand Down
61 changes: 61 additions & 0 deletions tests/test-svg.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

/**
* Class TestSvg
*/
class TestSvg extends TimmyUnitTestCase {
/**
* Tests whether we get the full src of an SVG with size full.
*
* @since 0.14.4
*/
public function test_get_timber_image_full_with_svg() {
$attachment = $this->create_image( [ 'file' => 'sveegee.svg' ] );
$result = get_timber_image( $attachment, 'full' );

$image = ' src="' . $this->get_upload_url() . '/sveegee.svg" alt=""';

$this->assertEquals( $image, $result );
}

/**
* Tests whether we get the full src of an SVG with size large.
*
* @since 0.14.4
*/
public function test_get_timber_image_large_with_svg() {
$attachment = $this->create_image( [ 'file' => 'sveegee.svg' ] );
$result = get_timber_image( $attachment, 'large' );

$image = ' src="' . $this->get_upload_url() . '/sveegee.svg" alt=""';

$this->assertEquals( $image, $result );
}

public function test_svg_responsive_square() {
$attachment = $this->create_image( [ 'file' => 'sveegee.svg' ] );
$result = get_timber_image_responsive( $attachment, 'large' );

$image = ' src="' . $this->get_upload_url() . '/sveegee.svg" width="1400" height="1400" loading="lazy" alt=""';

$this->assertEquals( $image, $result );
}

public function test_svg_responsive_rect() {
$attachment = $this->create_image( [ 'file' => 'svg-400-200.svg' ] );
$result = get_timber_image_responsive( $attachment, 'large' );

$image = ' src="' . $this->get_upload_url() . '/svg-400-200.svg" width="1400" height="700" loading="lazy" alt=""';

$this->assertEquals( $image, $result );
}

public function test_svg_responsive_rect_without_viewbox() {
$attachment = $this->create_image( [ 'file' => 'svg-without-viewbox.svg' ] );
$result = get_timber_image_responsive( $attachment, 'large' );

$image = ' src="' . $this->get_upload_url() . '/svg-without-viewbox.svg" loading="lazy" alt=""';

$this->assertEquals( $image, $result );
}
}

0 comments on commit ab65831

Please sign in to comment.