Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions docs/aspect-ratio-crop.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Cloudinary Video Player</title>
<link href="https://res.cloudinary.com/cloudinary-marketing/image/upload/f_auto,q_auto/c_scale,w_32/v1597183771/creative_staging/cloudinary_internal/Website/Brand%20Updates/Favicon/cloudinary_web_favicon_192x192.png" rel="icon" type="image/png">

<!-- Bootstrap -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<!-- highlight.js -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/solarized-light.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<script type="text/javascript" src="./scripts.js"></script>

<script type="text/javascript">
window.addEventListener('load', function(){
var player1 = cloudinary.videoPlayer('player-1', { cloudName: 'demo' });
player1.source({
publicId: 'sea_turtle',
aspectRatio: '1:1',
cropMode: 'fill'
});

var player2 = cloudinary.videoPlayer('player-2', { cloudName: 'demo' });
player2.source({
publicId: 'sea_turtle',
aspectRatio: '4:3',
cropMode: 'pad',
cropPadColor: 'blue'
});

var player3 = cloudinary.videoPlayer('player-3', { cloudName: 'demo' });
player3.source({
publicId: 'sea_turtle',
aspectRatio: '9:16',
cropMode: 'smart'
});
}, false);
</script>

</head>
<body>
<div class="container p-4 col-12 col-md-9 col-xl-6">
<nav class="nav mb-2">
<a href="./index.html">&#60;&#60; Back to examples index</a>
</nav>
<h1>Cloudinary Video Player</h1>
<h3 class="mb-4">Aspect ratio & crop mode</h3>

<h4 class="mb-2">fill - crops to fit aspect ratio</h4>
<video
id="player-1"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="500">
</video>

<h4 class="mt-4 mb-2">pad - letterboxes to fit</h4>
<video
id="player-2"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="500">
</video>

<h4 class="mt-4 mb-2">smart with 9:16 (portrait)</h4>
<video
id="player-3"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="280">
</video>

<p class="mt-4">
<a href="https://cloudinary.com/documentation/cloudinary_video_player">Full documentation</a>
</p>

<h3 class="mt-4">Example Code:</h3>
<pre>
<code class="language-javascript">
// Fill - crops to fit aspect ratio (no distortion)
player.source({
publicId: 'sea_turtle',
aspectRatio: '1:1',
cropMode: 'fill'
});

// Pad - letterboxes to fit (no distortion)
player.source({
publicId: 'sea_turtle',
aspectRatio: '4:3',
cropMode: 'pad',
cropPadColor: 'blue'
});

// Portrait (9:16) - smart crop
player.source({
publicId: 'sea_turtle',
aspectRatio: '9:16',
cropMode: 'smart'
});
</code>
</pre>
</div>
</body>
</html>
2 changes: 1 addition & 1 deletion docs/audio.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ <h3 class="mb-4 mt-4">Audio Player - with transformations</h3>
id="player-t"
playsinline
controls
class="cld-video-player"
class="cld-video-player cld-video-player-skin-light"
width="500"
></video>

Expand Down
121 changes: 121 additions & 0 deletions docs/es-modules/aspect-ratio-crop.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Cloudinary Video Player</title>
<link
href="https://res.cloudinary.com/cloudinary-marketing/image/upload/f_auto,q_auto/c_scale,w_32,e_hue:290/creative_staging/cloudinary_internal/Website/Brand%20Updates/Favicon/cloudinary_web_favicon_192x192.png"
rel="icon"
type="image/png"
/>
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div class="container p-4 col-12 col-md-9 col-xl-6">
<nav class="nav mb-2">
<a href="/index.html">&#60;&#60; Back to examples index</a>
</nav>
<h1>Cloudinary Video Player</h1>
<h3 class="mb-4">Aspect ratio & crop mode</h3>

<h4 class="mb-2">fill - crops to fit aspect ratio</h4>
<video
id="player-1"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="500"
></video>

<h4 class="mt-4 mb-2">pad - letterboxes to fit</h4>
<video
id="player-2"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="500"
></video>

<h4 class="mt-4 mb-2">smart with 9:16 (portrait)</h4>
<video
id="player-3"
playsinline
controls
muted
autoplay
class="cld-video-player"
width="280"
></video>

<p class="mt-4">
<a href="https://cloudinary.com/documentation/cloudinary_video_player"
>Full documentation</a
>
</p>

<h3 class="mt-4">Example Code:</h3>
<pre><code class="language-javascript">
// Fill - crops to fit aspect ratio
player.source({
publicId: 'sea_turtle',
aspectRatio: '1:1',
cropMode: 'fill'
});

// Pad - letterboxes to fit
player.source({
publicId: 'sea_turtle',
aspectRatio: '4:3',
cropMode: 'pad',
cropPadColor: 'blue'
});

// Portrait (9:16) - smart crop
player.source({
publicId: 'sea_turtle',
aspectRatio: '9:16',
cropMode: 'smart'
});
</code></pre>
</div>

<script type="module">
import { videoPlayer } from 'cloudinary-video-player';
import 'cloudinary-video-player/cld-video-player.min.css';

const player1 = videoPlayer('player-1', { cloudName: 'demo' });
player1.source({
publicId: 'sea_turtle',
aspectRatio: '1:1',
cropMode: 'fill'
});

const player2 = videoPlayer('player-2', { cloudName: 'demo' });
player2.source({
publicId: 'sea_turtle',
aspectRatio: '4:3',
cropMode: 'pad',
cropPadColor: 'blue'
});

const player3 = videoPlayer('player-3', { cloudName: 'demo' });
player3.source({
publicId: 'sea_turtle',
aspectRatio: '9:16',
cropMode: 'smart'
});
</script>

<link
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
/>
</body>
</html>
1 change: 1 addition & 0 deletions docs/es-modules/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ <h3 class="mt-4">Code examples:</h3>
<ul>
<li><a href="./adaptive-streaming.html">Adaptive Streaming</a></li>
<li><a href="./highlights-graph.html">AI Highlights Graph</a></li>
<li><a href="./aspect-ratio-crop.html">Aspect Ratio & Crop</a></li>
<li><a href="./analytics.html">Analytics</a></li>
<li><a href="./api.html">API and Events</a></li>
<li><a href="./audio.html">Audio Player</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ <h3 class="mt-4">Some code examples:</h3>
<ul>
<li><a href="./adaptive-streaming.html">Adaptive Streaming</a></li>
<li><a href="./highlights-graph.html">AI Highlights Graph</a></li>
<li><a href="./aspect-ratio-crop.html">Aspect Ratio & Crop</a></li>
<li><a href="./analytics.html">Analytics</a></li>
<li><a href="./api.html">API and Events</a></li>
<li><a href="./audio.html">Audio Player</a></li>
Expand Down
28 changes: 22 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions src/config/configSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,19 @@
"default": 2.0,
"description": "Maximum device pixel ratio cap for breakpoint rendition selection (1.0, 1.5, or 2.0)"
},
"aspectRatio": {
"type": "string",
"description": "Aspect ratio for video resize (e.g. 16:9, 9:16, 1:1). Merged into transformation."
},
"cropMode": {
"type": "string",
"enum": ["fill", "pad", "smart"],
"description": "Resize mode: fill, pad, or smart. Merged into transformation."
},
"cropPadColor": {
"type": "string",
"description": "Background color for pad mode, e.g. #000000. Merged into transformation.background."
},
"resourceType": {
"type": "string",
"default": "video"
Expand Down
27 changes: 26 additions & 1 deletion src/plugins/cloudinary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
setupCloudinaryMiddleware,
isRawUrl
} from './common';
import { CROP_MODE } from 'video-player.const';
import VideoSource from './models/video-source/video-source';
import EventHandlerRegistry from './event-handler-registry';
import AudioSource from './models/audio-source/audio-source';
Expand All @@ -30,6 +31,29 @@ const DEFAULT_PARAMS = {
export const CONSTRUCTOR_PARAMS = ['cloudinaryConfig', 'transformation',
'sourceTypes', 'sourceTransformation', 'posterOptions', 'autoShowRecommendations'];

const normalizeAspectCrop = (options) => {
const { aspectRatio, cropMode, cropPadColor, transformation, ...rest } = options;
if (!aspectRatio && !cropMode) return options;
Comment thread
tsi marked this conversation as resolved.

const tx = {};
if (aspectRatio) tx.aspect_ratio = aspectRatio;
if (cropMode) {
if (cropMode === CROP_MODE.SMART) {
tx.crop = CROP_MODE.FILL;
tx.gravity = 'auto';
} else {
tx.crop = cropMode;
if (cropMode === CROP_MODE.PAD && cropPadColor) tx.background = cropPadColor;
}
}
return {
...rest,
transformation: Array.isArray(transformation)
? [tx, ...transformation]
: mergeTransformations(transformation || {}, tx)
};
};

class CloudinaryContext {
constructor(player, options = {}) {
setupCloudinaryMiddleware();
Expand Down Expand Up @@ -124,6 +148,7 @@ class CloudinaryContext {
this.buildSource = (publicId, options = {}) => {
let builtSrc = null;
({ publicId, options } = normalizeOptions(publicId, options));
options = normalizeAspectCrop(options);

options.cloudinaryConfig = extendCloudinaryConfig(this.cloudinaryConfig(), options.cloudinaryConfig || {});
options.transformation = mergeTransformations(this.transformation(), options.transformation || {});
Expand Down Expand Up @@ -161,7 +186,7 @@ class CloudinaryContext {
const width = RENDITIONS.find(rendition => rendition >= requiredWidth) || RENDITIONS[RENDITIONS.length - 1];
options.breakpointTransformation = {
width,
crop: 'limit'
...(!isKeyInTransformation(options.transformation, 'crop') && { crop: 'limit' })
};
}

Expand Down
Loading