-
Notifications
You must be signed in to change notification settings - Fork 152
Add srcset and sizes attributes to the img tag
#117
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
Changes from all commits
1297b9d
db4da95
379d668
6af2e16
86331b6
4bc0166
0262b2b
8cd3110
c81bc1a
9ae20db
60093cf
0732165
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,12 +94,212 @@ function cl_form_tag($callback_url, $options = array()) | |
| return $form; | ||
| } | ||
|
|
||
| // Examples | ||
| // cl_image_tag("israel.png", array("width"=>100, "height"=>100, "alt"=>"hello") # W/H are not sent to cloudinary | ||
| // cl_image_tag("israel.png", array("width"=>100, "height"=>100, "alt"=>"hello", "crop"=>"fit") # W/H are sent to cloudinary | ||
| function cl_image_tag($source, $options = array()) | ||
|
|
||
| /** | ||
| * @internal Helper function. Gets or populates srcset breakpoints using provided parameters | ||
| * | ||
| * Either the breakpoints or min_width, max_width, max_images must be provided. | ||
| * | ||
| * @param array $srcset_data { | ||
| * | ||
| * @var array breakpoints An array of breakpoints. | ||
| * @var int min_width Minimal width of the srcset images. | ||
| * @var int max_width Maximal width of the srcset images. | ||
| * @var int max_images Number of srcset images to generate. | ||
| * } | ||
| * | ||
| * @return array Array of breakpoints | ||
| * | ||
| * @throws InvalidArgumentException In case of invalid or missing parameters | ||
| */ | ||
| function get_srcset_breakpoints($srcset_data) | ||
| { | ||
| $source = cloudinary_url_internal($source, $options); | ||
| $breakpoints = Cloudinary::option_get($srcset_data, "breakpoints", array()); | ||
|
|
||
| if (!empty($breakpoints)) { | ||
| return $breakpoints; | ||
| } | ||
|
|
||
| foreach (array('min_width', 'max_width', 'max_images') as $arg) { | ||
| if (empty($srcset_data[$arg]) || !is_numeric($srcset_data[$arg]) || is_string($srcset_data[$arg])) { | ||
| throw new InvalidArgumentException('Either valid (min_width, max_width, max_images) ' . | ||
| 'or breakpoints must be provided to the image srcset attribute'); | ||
| } | ||
| } | ||
|
|
||
| $min_width = $srcset_data['min_width']; | ||
| $max_width = $srcset_data['max_width']; | ||
| $max_images = $srcset_data['max_images']; | ||
|
|
||
| if ($min_width > $max_width) { | ||
| throw new InvalidArgumentException('min_width must be less than max_width'); | ||
| } | ||
|
|
||
| if ($max_images <= 0) { | ||
| throw new InvalidArgumentException('max_images must be a positive integer'); | ||
| } elseif ($max_images == 1) { | ||
| // if user requested only 1 image in srcset, we return max_width one | ||
| $min_width = $max_width; | ||
| } | ||
|
|
||
| $step_size = ceil(($max_width - $min_width) / ($max_images > 1 ? $max_images - 1 : 1)); | ||
|
|
||
| $curr_breakpoint = $min_width; | ||
|
|
||
| while ($curr_breakpoint < $max_width) { | ||
| array_push($breakpoints, $curr_breakpoint); | ||
| $curr_breakpoint += $step_size; | ||
| } | ||
|
|
||
| array_push($breakpoints, $max_width); | ||
|
|
||
| return $breakpoints; | ||
| } | ||
|
|
||
| /** | ||
| * @internal Helper function. Generates a single srcset item url | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Update PHPDoc |
||
| * | ||
| * @param string $public_id Public ID of the resource | ||
| * @param int $width Width in pixels of the srcset item | ||
| * @param array $options Additional options | ||
| * | ||
| * @return mixed|null|string|string[] Resulting URL of the item | ||
| */ | ||
| function generate_single_srcset_url($public_id, $width, $options) | ||
| { | ||
| $curr_options = Cloudinary::array_copy($options); | ||
| /* | ||
| The following line is used for the next purposes: | ||
| 1. Generate raw transformation string | ||
| 2. Cleanup transformation parameters from $curr_options. | ||
| We call it intentionally even when the user provided custom transformation in srcset | ||
| */ | ||
| $raw_transformation = Cloudinary::generate_transformation_string($curr_options); | ||
|
|
||
| if (!empty($options["srcset"]["transformation"])) { | ||
| $curr_options["transformation"] = $options["srcset"]["transformation"]; | ||
| $raw_transformation = Cloudinary::generate_transformation_string($curr_options); | ||
| } | ||
|
|
||
| $curr_options["raw_transformation"] = $raw_transformation . "/c_scale,w_{$width}"; | ||
|
|
||
| // We might still have width and height params left if they were provided. | ||
| // We don't want to use them for the second time | ||
| $unwanted_params = array('width', 'height'); | ||
| foreach ($unwanted_params as $key) { | ||
| unset($curr_options[$key]); | ||
| } | ||
|
|
||
| return cloudinary_url_internal($public_id, $curr_options); | ||
| } | ||
|
|
||
| /** | ||
| * @internal Helper function. Generates srcset attribute value of the HTML img tag | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Update PHPDoc |
||
| * | ||
| * @param array $srcset_data { | ||
| * | ||
| * @var array breakpoints An array of breakpoints. | ||
| * @var int min_width Minimal width of the srcset images. | ||
| * @var int max_width Maximal width of the srcset images. | ||
| * @var int max_images Number of srcset images to generate. | ||
| * } | ||
| * | ||
| * @param array $options Additional options. | ||
| * | ||
| * @return string Resulting srcset attribute value | ||
| * | ||
| * @throws InvalidArgumentException In case of invalid or missing parameters | ||
| */ | ||
| function generate_image_srcset_attribute($public_id, $srcset_data, $options = array()) | ||
| { | ||
| if (empty($srcset_data)) { | ||
| return null; | ||
| } | ||
| if (is_string($srcset_data)) { | ||
| return $srcset_data; | ||
| } | ||
|
|
||
| $breakpoints = get_srcset_breakpoints($srcset_data); | ||
|
|
||
| // The code below is a part of `cloudinary_url` code that affects $options. | ||
| // We call it here, to make sure we get exactly the same behavior. | ||
| // TODO: Refactor this code, unify it with `cloudinary_url` or fix `cloudinary_url` and remove it | ||
| Cloudinary::check_cloudinary_field($public_id, $options); | ||
| $type = Cloudinary::option_get($options, "type", "upload"); | ||
|
|
||
| if ($type == "fetch" && !isset($options["fetch_format"])) { | ||
| $options["fetch_format"] = Cloudinary::option_consume($options, "format"); | ||
| } | ||
| //END OF TODO | ||
|
|
||
| $items = array(); | ||
| foreach ($breakpoints as $breakpoint) { | ||
| array_push($items, generate_single_srcset_url($public_id, $breakpoint, $options) . " {$breakpoint}w"); | ||
| } | ||
|
|
||
| return implode(", ", $items); | ||
| } | ||
|
|
||
| /** | ||
| * @internal Helper function. Generates sizes attribute value of the HTML img tag | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Update PHPDoc |
||
| * | ||
| * @param array $srcset_data { | ||
| * | ||
| * @var array breakpoints An array of breakpoints. | ||
| * @var int min_width Minimal width of the srcset images. | ||
| * @var int max_width Maximal width of the srcset images. | ||
| * @var int max_images Number of srcset images to generate. | ||
| * } | ||
| * | ||
| * @return string Resulting sizes attribute value | ||
| * | ||
| * @throws InvalidArgumentException In case of invalid or missing parameters | ||
| */ | ||
| function generate_image_sizes_attribute($srcset_data) | ||
| { | ||
| if (empty($srcset_data) or is_string($srcset_data)) { | ||
| return null; | ||
| } | ||
|
|
||
| $breakpoints = get_srcset_breakpoints($srcset_data); | ||
|
|
||
| $sizes_items = array(); | ||
| foreach ($breakpoints as $breakpoint) { | ||
| array_push($sizes_items, "(max-width: {$breakpoint}px) {$breakpoint}px"); | ||
| } | ||
|
|
||
| return implode(", ", $sizes_items); | ||
| } | ||
|
|
||
| /** | ||
| * Generates HTML img tag | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Update PHPDoc |
||
| * | ||
| * @param string $public_id Public ID of the resource | ||
| * | ||
| * @param array $options Additional options | ||
| * | ||
| * Examples: | ||
| * | ||
| * W/H are not sent to cloudinary | ||
| * cl_image_tag("israel.png", array("width"=>100, "height"=>100, "alt"=>"hello") | ||
| * | ||
| * W/H are sent to cloudinary | ||
| * cl_image_tag("israel.png", array("width"=>100, "height"=>100, "alt"=>"hello", "crop"=>"fit") | ||
| * | ||
| * @return string Resulting img tag | ||
| * | ||
| */ | ||
| function cl_image_tag($public_id, $options = array()) | ||
| { | ||
| $original_options = null; | ||
|
|
||
| if (!empty($options['srcset'])) { | ||
| // Since cloudinary_url is destructive, we need to save a copy of original options passed to this function | ||
| $original_options = Cloudinary::array_copy($options); | ||
| } | ||
|
|
||
| $source = cloudinary_url_internal($public_id, $options); | ||
|
|
||
| if (isset($options["html_width"])) { | ||
| $options["width"] = Cloudinary::option_consume($options, "html_width"); | ||
| } | ||
|
|
@@ -128,10 +328,31 @@ function cl_image_tag($source, $options = array()) | |
| } | ||
| } | ||
| $html = "<img "; | ||
|
|
||
| if ($source) { | ||
| $html .= "src='" . htmlspecialchars($source, ENT_QUOTES) . "' "; | ||
| } | ||
| $html .= Cloudinary::html_attrs($options) . "/>"; | ||
|
|
||
| if (!empty($options["srcset"])) { | ||
| $srcset_data = $options["srcset"]; | ||
| $options["srcset"] = generate_image_srcset_attribute($public_id, $srcset_data, $original_options); | ||
|
|
||
| if (!empty($srcset_data["sizes"]) && $srcset_data["sizes"] === true) { | ||
| $options["sizes"] = generate_image_sizes_attribute($srcset_data); | ||
| } | ||
|
|
||
| // width and height attributes override srcset behavior, they should be removed from html attributes. | ||
| $unwanted_attributes = array('width', 'height'); | ||
| foreach ($unwanted_attributes as $key) { | ||
| unset($options[$key]); | ||
| } | ||
| } | ||
|
|
||
| $attr_data = Cloudinary::option_consume($options, 'attributes', array()); | ||
| // Explicitly provided attributes override options | ||
| $attributes = array_merge($options, $attr_data); | ||
|
|
||
| $html .= Cloudinary::html_attrs($attributes) . "/>"; | ||
|
|
||
| return $html; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Update PHPDoc