Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add srcset generation #47

Merged
merged 10 commits into from
Aug 29, 2019
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,42 @@ echo $builder->createURL("bridge.png", $params);
// Prints out:
// http://demos.imgix.net/bridge.png?h=100&w=100&s=bb8f3a2ab832e35997456823272103a4
```

## Srcset Generation

The imgix library allows for generation of custom `srcset` attributes, which can be invoked through `createSrcSet()`. By default, the `srcset` generated will allow for responsive size switching by building a list of image-width mappings.

```php
$builder = new UrlBuilder("demos.imgix.net", true, "my-key", false);
echo $builder->createSrcSet("bridge.png");
```

Will produce the following attribute value, which can then be served to the client:

```html
https://demos.imgix.net/bridge.png?w=100&s=ac331d314510e3039a33aa1a7ebc23ee 100w,
https://demos.imgix.net/bridge.png?w=116&s=aac0667a00791c8c8801a2fef134e78a 116w,
https://demos.imgix.net/bridge.png?w=134&s=2fcd42d984155efe26cc1e36e16b2897 134w,
...
https://demos.imgix.net/bridge.png?w=7400&s=6a6cbe01416dc4e0c65d1a2f87b868ac 7400w,
https://demos.imgix.net/bridge.png?w=8192&s=9e6b0a94e81e929ad71829fcccf4d2d8 8192w
```

In cases where enough information is provided about an image's dimensions, `createSrcSet()` will instead build a `srcset` that will allow for an image to be served at different resolutions. The parameters taken into consideration when determining if an image is fixed-width are `w`, `h`, and `ar`. By invoking `createSrcSet()` with either a width **or** the height and aspect ratio (along with `fit=crop`, typically) provided, a different `srcset` will be generated for a fixed-size image instead.

```php
$builder = new UrlBuilder("demos.imgix.net", true, "my-key", false);
echo $builder->createSrcSet("bridge.png", array("h"=>800, "ar"=>"3:2", "fit"=>"crop"));
```

Will produce the following attribute value:

```html
https://demos.imgix.net/bridge.png?ar=3%3A2&dpr=1&fit=crop&h=800&s=39eb37ad41acf7170343aa463424ae49 1x,
https://demos.imgix.net/bridge.png?ar=3%3A2&dpr=2&fit=crop&h=800&s=a8ab13a2c7a17b91db42cb86e45f7c9d 2x,
https://demos.imgix.net/bridge.png?ar=3%3A2&dpr=3&fit=crop&h=800&s=8fefe5daf312f04fb6912a101afbf704 3x,
https://demos.imgix.net/bridge.png?ar=3%3A2&dpr=4&fit=crop&h=800&s=74a6167d6ef8ba410109feda814b9ac0 4x,
https://demos.imgix.net/bridge.png?ar=3%3A2&dpr=5&fit=crop&h=800&s=4449b7f44ba7d6d0527a16d9a10b6e39 5x
```

For more information to better understand `srcset`, we highly recommend [Eric Portis' "Srcset and sizes" article](https://ericportis.com/posts/2014/srcset-sizes/) which goes into depth about the subject.
69 changes: 69 additions & 0 deletions src/Imgix/UrlBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ class UrlBuilder {
private $useHttps;
private $signKey;

// define class constants
// should be private; but visibility modifiers are not supported php version <7.1
const TARGETRATIOS = array(1, 2, 3, 4, 5);
// constants cannot be dynamically assigned; keeping as a class variable instead
private $targetWidths;

public function __construct($domain, $useHttps = false, $signKey = "", $includeLibraryParam = true) {

if (!is_string($domain)) {
Expand All @@ -21,6 +27,7 @@ public function __construct($domain, $useHttps = false, $signKey = "", $includeL
$this->useHttps = $useHttps;
$this->signKey = $signKey;
$this->includeLibraryParam = $includeLibraryParam;
$this->targetWidths = $this->targetWidths();
}

private function validateDomain($domain) {
Expand Down Expand Up @@ -57,4 +64,66 @@ public function createURL($path, $params=array()) {

return $uh->getURL();
}

public function createSrcSet($path, $params=array()) {
$width = array_key_exists('w', $params) ? $params['w'] : NULL;
$height = array_key_exists('h', $params) ? $params['h'] : NULL;
$aspectRatio = array_key_exists('ar', $params) ? $params['ar'] : NULL;

if (($width) || ($height && $aspectRatio)) {
return $this->createDPRSrcSet($path, $params);
}
else {
return $this->createSrcSetPairs($path, $params);
}
}

private function createDPRSrcSet($path, $params) {
$srcset = "";

$size = count(self::TARGETRATIOS);
for ($i = 0; $i < $size; $i++) {
$currentRatio = self::TARGETRATIOS[$i];
$currentParams = $params;
$currentParams['dpr'] = $i+1;
$srcset .= $this->createURL($path, $currentParams) . " " . $currentRatio . "x,\n";
}

return substr($srcset, 0, strlen($srcset) - 2);
}

private function createSrcSetPairs($path, $params) {
$srcset = "";
$currentWidth = NULL;
$currentParams = NULL;

$size = count($this->targetWidths);
for ($i = 0; $i < $size; $i++) {
$currentWidth = $this->targetWidths[$i];
$currentParams = $params;
$currentParams['w'] = $currentWidth;
$srcset .= $this->createURL($path, $currentParams) . " " . $currentWidth . "w,\n";
}

return substr($srcset, 0, strlen($srcset) - 2);
}

private function targetWidths() {
sherwinski marked this conversation as resolved.
Show resolved Hide resolved
$resolutions = array();
$prev = 100;
$INCREMENT_PERCENTAGE = 8;
$MAX_SIZE = 8192;

$ensureEven = function($n) {
return 2 * round($n / 2);
};

while ($prev <= $MAX_SIZE) {
array_push($resolutions, $ensureEven($prev));
$prev *= 1 + ($INCREMENT_PERCENTAGE / 100) * 2;
}

array_push($resolutions, $MAX_SIZE);
return $resolutions;
}
}
Loading