@cloudinary/url-gen
Version:
Cloudinary URL-Gen SDK ========================= [](https://app.travis-ci.com/github/cloudinary/js-url-gen) ## About The Cloudinary URL-Gen SDK allows you to quickly and eas
1,432 lines (1,391 loc) • 616 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.CldUrlGen = {}));
})(this, (function (exports) { 'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/**
*
* @private
* @param {any} a
*/
function isObject$2(a) {
if (typeof a !== 'object' || a instanceof Array) {
return false;
}
else {
return true;
}
}
var Config = /** @class */ (function () {
function Config() {
}
Config.prototype.filterOutNonSupportedKeys = function (userProvidedConfig, validKeys) {
var obj = Object.create({});
if (isObject$2(userProvidedConfig)) {
Object.keys(userProvidedConfig).forEach(function (key) {
if (validKeys.indexOf(key) >= 0) {
obj[key] = userProvidedConfig[key];
}
else {
console.warn('Warning - unsupported key provided to configuration: ', key);
}
});
return obj;
}
else {
return Object.create({});
}
};
return Config;
}());
/**
* This file is for internal constants only.
* It is not intended for public use and is not part of the public API
*/
/**
* @private
*/
var ALLOWED_URL_CONFIG = [
'cname',
'secureDistribution',
'privateCdn',
'signUrl',
'longUrlSignature',
'shorten',
'useRootPath',
'secure',
'forceVersion',
'analytics',
'queryParams'
];
/**
* @private
*/
var ALLOWED_CLOUD_CONFIG = [
'cloudName',
'apiKey',
'apiSecret',
'authToken'
];
var URLConfig = /** @class */ (function (_super) {
__extends(URLConfig, _super);
/**
* @param {IURLConfig} userURLConfig
*/
function URLConfig(userURLConfig) {
var _this = _super.call(this) || this;
var urlConfig = _this.filterOutNonSupportedKeys(userURLConfig, ALLOWED_URL_CONFIG);
Object.assign(_this, {
secure: true
}, urlConfig);
return _this;
}
URLConfig.prototype.extend = function (userURLConfig) {
var urlConfig = this.filterOutNonSupportedKeys(userURLConfig, ALLOWED_URL_CONFIG);
return new URLConfig(Object.assign({}, this, urlConfig));
};
/**
* @param {string} value Sets the cname
*/
URLConfig.prototype.setCname = function (value) {
this.cname = value;
return this;
};
/**
* @param {string} value Sets the secureDistribution
*/
URLConfig.prototype.setSecureDistribution = function (value) {
this.secureDistribution = value;
return this;
};
/**
* @param {boolean} value Sets whether to use a private CDN (Removes cloudName from URL)
*/
URLConfig.prototype.setPrivateCdn = function (value) {
this.privateCdn = value;
return this;
};
/**
* @param value Sets whether or not to sign the URL
*/
URLConfig.prototype.setSignUrl = function (value) {
this.signUrl = value;
return this;
};
/**
* @param value Sets whether or not to use a long signature
*/
URLConfig.prototype.setLongUrlSignature = function (value) {
this.longUrlSignature = value;
return this;
};
/**
* @param value Sets whether or not to shorten the URL
*/
URLConfig.prototype.setShorten = function (value) {
this.shorten = value;
return this;
};
/**
* @param value Sets whether or not to use a root path
*/
URLConfig.prototype.setUseRootPath = function (value) {
this.useRootPath = value;
return this;
};
/**
* @param value Sets whether or not to deliver the asset through https
*/
URLConfig.prototype.setSecure = function (value) {
this.secure = value;
return this;
};
/**
* @param value Sets whether to force a version in the URL
*/
URLConfig.prototype.setForceVersion = function (value) {
this.forceVersion = value;
return this;
};
/**
* @param params Sets additional params
*/
URLConfig.prototype.setQueryParams = function (params) {
this.queryParams = params;
return this;
};
return URLConfig;
}(Config));
var CloudConfig = /** @class */ (function (_super) {
__extends(CloudConfig, _super);
/**
* @param {ICloudConfig} userCloudConfig {@link ICloudConfig}
*
*/
function CloudConfig(userCloudConfig) {
var _this = _super.call(this) || this;
var cloudConfig = _this.filterOutNonSupportedKeys(userCloudConfig, ALLOWED_CLOUD_CONFIG);
Object.assign(_this, cloudConfig);
if (!_this.cloudName) {
throw 'Missing mandatory field cloudName';
}
return _this;
}
CloudConfig.prototype.extend = function (userCloudConfig) {
var cloudConfig = this.filterOutNonSupportedKeys(userCloudConfig, ALLOWED_CLOUD_CONFIG);
return new CloudConfig(Object.assign({}, this, cloudConfig));
};
/**
* @param {string} value Sets the CloudName
*/
CloudConfig.prototype.setCloudName = function (value) {
this.cloudName = value;
return this;
};
/**
* @param {string} value Sets the API Key
*/
CloudConfig.prototype.setApiKey = function (value) {
this.apiKey = value;
return this;
};
/**
* @param {string} value Sets the API Secret
*/
CloudConfig.prototype.setApiSecret = function (value) {
this.apiSecret = value;
return this;
};
return CloudConfig;
}(Config));
var CloudinaryConfig = /** @class */ (function () {
function CloudinaryConfig(configurations) {
if (configurations === void 0) { configurations = {}; }
this.cloud = new CloudConfig(configurations.cloud);
this.url = new URLConfig(configurations.url || {});
}
/**
* @description Setter for the cloudConfig
* @param {ICloudConfig} cld
*/
CloudinaryConfig.prototype.setCloudConfig = function (cld) {
this.cloud = new CloudConfig(cld);
return this;
};
/**
* @description Setter for the urlConfig
* @param {IURLConfig} url
*/
CloudinaryConfig.prototype.setURLConfig = function (url) {
this.url = new URLConfig(url);
return this;
};
CloudinaryConfig.prototype.extend = function (configurations) {
this.cloud = this.cloud.extend(configurations.cloud || {});
this.url = this.url.extend(configurations.url || {});
return this;
};
return CloudinaryConfig;
}());
/**
* @summary SDK
* @memberOf SDK
*/
class QualifierValue {
/**
*
* @param {QualifierValue | QualifierValue[] | any[] | string | number}qualifierValue
*/
constructor(qualifierValue) {
this.values = [];
this.delimiter = ':'; // {value}{delimiter}{value}...
if (this.hasValue(qualifierValue)) {
this.addValue(qualifierValue);
}
}
/**
* @description Joins the provided values with the provided delimiter
*/
toString() {
return this.values.join(this.delimiter);
}
/**
* @description Checks if the provided argument has a value
* @param {any} v
* @private
* @return {boolean}
*/
hasValue(v) {
return typeof v !== 'undefined' && v !== null && v !== '';
}
/**
* @desc Adds a value for the this qualifier instance
* @param {any} value
* @return {this}
*/
addValue(value) {
// Append value or array of values
if (Array.isArray(value)) {
this.values = this.values.concat(value);
}
else {
this.values.push(value);
}
// Remove falsy values
this.values = this.values.filter((v) => this.hasValue(v));
return this;
}
/**
* @description Sets the delimiter for this instance
* @param delimiter
*/
setDelimiter(delimiter) {
this.delimiter = delimiter;
return this;
}
}
class UnsupportedError extends Error {
constructor(message = 'Unsupported') {
super(message);
}
}
/**
* Creates a new UnsupportedError
* @param message
*/
function createUnsupportedError(message) {
return new UnsupportedError(message);
}
/**
* Returns the action's model
*/
function qualifierToJson() {
return this._qualifierModel || { error: createUnsupportedError(`unsupported qualifier ${this.constructor.name}`) };
}
class QualifierModel {
constructor() {
this._qualifierModel = {};
}
toJson() {
return qualifierToJson.apply(this);
}
}
/**
* @summary SDK
* @memberOf SDK
*/
class Qualifier extends QualifierModel {
constructor(key, qualifierValue) {
super();
this.delimiter = '_'; // {key}{delimiter}{qualifierValue}
this.key = key;
if (qualifierValue instanceof QualifierValue) {
this.qualifierValue = qualifierValue;
}
else {
this.qualifierValue = new QualifierValue();
this.qualifierValue.addValue(qualifierValue);
}
}
toString() {
const { key, delimiter, qualifierValue } = this;
return `${key}${delimiter}${qualifierValue.toString()}`;
}
addValue(value) {
this.qualifierValue.addValue(value);
return this;
}
}
/**
* @memberOf Qualifiers.Flag
* @extends {SDK.Qualifier}
* @description the FlagQualifier class
*/
class FlagQualifier extends Qualifier {
constructor(flagType, flagValue) {
let qualifierValue;
if (flagValue) {
qualifierValue = new QualifierValue([flagType, `${flagValue}`]).setDelimiter(':');
}
else {
qualifierValue = flagType;
}
super('fl', qualifierValue);
this.flagValue = flagValue;
}
toString() {
return super.toString().replace(/\./, '%2E');
}
getFlagValue() {
return this.flagValue;
}
}
/**
* Sort a map by key
* @private
* @param map <string, any>
* @Return array of map's values sorted by key
*/
function mapToSortedArray(map, flags) {
const array = Array.from(map.entries());
// objects from the Array.from() method above are stored in array of arrays:
// [[qualifierKey, QualifierObj], [qualifierKey, QualifierObj]]
// Flags is an array of FlagQualifierObj
// We need to convert it to the same form: [flagQualifier] => ['fl', flagQualifier]
flags.forEach((flag) => {
array.push(['fl', flag]); // push ['fl', flagQualifier]
});
return array.sort().map((v) => v[1]);
}
/**
* Returns the action's model
*/
function actionToJson() {
var _a, _b, _c;
const actionModelIsNotEmpty = this._actionModel && Object.keys(this._actionModel).length;
const sourceTransformationError = (_c = (_b = (_a = this._actionModel) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.transformation) === null || _c === void 0 ? void 0 : _c.error;
// Should return error when there is unsupported transformation inside
if (sourceTransformationError && sourceTransformationError instanceof Error) {
return { error: sourceTransformationError };
}
if (actionModelIsNotEmpty) {
return this._actionModel;
}
return { error: createUnsupportedError(`unsupported action ${this.constructor.name}`) };
}
class ActionModel {
constructor() {
this._actionModel = {};
}
toJson() {
return actionToJson.apply(this);
}
}
/**
* @summary SDK
* @memberOf SDK
* @description Defines the category of transformation to perform.
*/
class Action extends ActionModel {
constructor() {
super(...arguments);
// We're using map, to overwrite existing keys. for example:
// addParam(w_100).addQualifier(w_200) should result in w_200. and not w_100,w_200
this.qualifiers = new Map();
// Unlike regular qualifiers, there can be multiple flags in each url component /fl_1,fl_2/
// If the falgs are added to the qualifiers map, only a single flag could exist in a component (it's a map)
// So flags are stored separately until the very end because of that reason
this.flags = [];
this.delimiter = ','; // {qualifier}{delimiter}{qualifier} for example: `${'w_100'}${','}${'c_fill'}`
this.actionTag = ''; // A custom name tag to identify this action in the future
}
prepareQualifiers() { }
/**
* @description Returns the custom name tag that was given to this action
* @return {string}
*/
getActionTag() {
return this.actionTag;
}
/**
* @description Sets the custom name tag for this action
* @return {this}
*/
setActionTag(tag) {
this.actionTag = tag;
return this;
}
/**
* @description Calls toString() on all child qualifiers (implicitly by using .join()).
* @return {string}
*/
toString() {
this.prepareQualifiers();
return mapToSortedArray(this.qualifiers, this.flags).join(this.delimiter);
}
/**
* @description Adds the parameter to the action.
* @param {SDK.Qualifier} qualifier
* @return {this}
*/
addQualifier(qualifier) {
// if string, find the key and value
if (typeof qualifier === 'string') {
const [key, value] = qualifier.toLowerCase().split('_');
if (key === 'fl') {
// if string qualifier is a flag, store it in the flags arrays
this.flags.push(new FlagQualifier(value));
}
else {
// if the string qualifier is not a flag, create a new qualifier from it
this.qualifiers.set(key, new Qualifier(key, value));
}
}
else {
// if a qualifier object, insert to the qualifiers map
this.qualifiers.set(qualifier.key, qualifier);
}
return this;
}
/**
* @description Adds a flag to the current action.
* @param {Qualifiers.Flag} flag
* @return {this}
*/
addFlag(flag) {
if (typeof flag === 'string') {
this.flags.push(new FlagQualifier(flag));
}
else {
if (flag instanceof FlagQualifier) {
this.flags.push(flag);
}
}
return this;
}
addValueToQualifier(qualifierKey, qualifierValue) {
this.qualifiers.get(qualifierKey).addValue(qualifierValue);
return this;
}
}
/**
* @extends SDK.Action
* @description A class for background transformations.
*/
class BackgroundColor extends Action {
constructor(color) {
super();
this.addQualifier(new Qualifier('b', new QualifierValue(color).setDelimiter('_')));
}
}
/**
* Returns RGB or Color
* @private
* @param color
*/
function prepareColor(color) {
if (color) {
return color.match(/^#/) ? `rgb:${color.substr(1)}` : color;
}
else {
return color;
}
}
/**
* @summary SDK
* @memberOf SDK
* @description Defines an action that's a string literal, no validations or manipulations are performed
*/
class RawAction {
constructor(raw) {
this.raw = raw;
}
toString() {
return this.raw;
}
toJson() {
return { error: createUnsupportedError(`unsupported action ${this.constructor.name}`) };
}
}
/**
* Validates obj is an instance of IErrorObject
* @param obj
*/
function isErrorObject(obj) {
const errorObj = obj;
return ('error' in errorObj) && !!errorObj.error;
}
/**
* @description Defines flags that you can use to alter the default transformation behavior.
* @namespace Flag
* @memberOf Qualifiers
*/
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Used when delivering a video file as an image format that supports animation, such as animated WebP.
* Plays all frames rather than just delivering the first one as a static image.
* Use this flag in addition to the flag or parameter controlling the delivery format,
* for example f_auto or fl_awebp.
* Note: When delivering a video in GIF format, it is delivered as an animated GIF by default and this flag is not
* necessary. To deliver a single frame of a video in GIF format, use the page parameter.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function animated() {
return new FlagQualifier('animated');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description When converting animated images to WebP format, generate an animated WebP from all the frames in the
* original
* animated file instead of only from the first still frame.
*
* Note that animated WebPs are not supported in all browsers and versions.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function animatedWebP() {
return new FlagQualifier('awebp');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Trims pixels according to a clipping path included in the original image
* (e.g., manually created using PhotoShop).
* @return {Qualifiers.Flag.FlagQualifier}
*/
function clip$1() {
return new FlagQualifier('clip');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Trims pixels according to a clipping path included in the original image (e.g., manually created
* using PhotoShop)
* using an evenodd clipping rule.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function clipEvenOdd() {
return new FlagQualifier('clip_evenodd');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description * Allows specifying only either width or height so the value of the second axis remains as is, and is not
* recalculated to maintain the aspect ratio of the original image.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function ignoreInitialAspectRatio$1() {
return new FlagQualifier('ignore_aspect_ratio');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Automatically use lossy compression when delivering animated GIF files.
*
* This flag can also be used as a conditional flag for delivering PNG files: it tells Cloudinary to deliver the
* image in PNG format (as requested) unless there is no transparency channel - in which case deliver in JPEG
* format.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function lossy() {
return new FlagQualifier('lossy');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Used internally by Position within an Overlay, this flag will tile the overlay across your image.
*
* <b>Learn more:</b> {@link https://cloudinary.com/documentation/transformation_reference#fl_no_overflow|Overflow in overlays}
* @return {Qualifiers.Flag.FlagQualifier}
*/
function noOverflow() {
return new FlagQualifier('no_overflow');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description When used with automatic fetch_format (f_auto): ensures that images with a transparency channel will be
* delivered in PNG format.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function preserveTransparency() {
return new FlagQualifier('preserve_transparency');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Generates a JPG image using the progressive (interlaced) JPG format.
*
* This format allows the browser to quickly show a low-quality rendering of the image until the full-quality
* image is loaded.
*
* @param {string} mode? The mode to determine a specific progressive outcome as follows:
* * semi - A smart optimization of the decoding time, compression level and progressive rendering
* (less iterations). This is the default mode when using q_auto.
* * steep - Delivers a preview very quickly, and in a single later phase improves the image to
* the required resolution.
* * none - Use this to deliver a non-progressive image. This is the default mode when setting
* a specific value for quality.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function progressive(mode) {
return new FlagQualifier('progressive', mode);
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Modifies percentage-based width & height parameters of overlays and underlays (e.g., 1.0) to be relative to the overlaid region
* @return {Qualifiers.Flag.FlagQualifier}
*/
function regionRelative() {
return new FlagQualifier('region_relative');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Modifies percentage-based width & height parameters of overlays and underlays (e.g., 1.0) to be relative to the containing image instead of the added layer.
* @return {Qualifiers.Flag.FlagQualifier}
*/
function relative() {
return new FlagQualifier('relative');
}
/**
* @summary qualifier
* @memberOf Qualifiers.Flag
* @description Used internally by Position within an Overlay, this flag will tile the overlay across your image.
*
* <b>Learn more:</b> {@link https://cloudinary.com/documentation/layers#automatic_tiling|Tiling overlay}
* @return {Qualifiers.Flag.FlagQualifier}
*/
function tiled() {
return new FlagQualifier('tiled');
}
/**
* @memberOf Qualifiers.Format
* @extends {SDK.QualifierValue}
*/
class FormatQualifier extends QualifierValue {
constructor(val) {
super(val);
this.val = val;
}
getValue() {
return this.val;
}
}
/**
* Flip keys and values for given object
* @param obj
*/
function objectFlip(obj) {
const result = {};
Object.keys(obj).forEach((key) => {
result[obj[key]] = key;
});
return result;
}
/**
* This file is for internal constants only.
* It is not intended for public use and is not part of the public API
*/
const CONDITIONAL_OPERATORS = {
"=": "eq",
"!=": "ne",
"<": "lt",
">": "gt",
"<=": "lte",
">=": "gte",
"&&": "and",
"||": "or",
"*": "mul",
"/": "div",
"+": "add",
"-": "sub",
"^": "pow"
};
const RESERVED_NAMES = {
"aspect_ratio": "ar",
"aspectRatio": "ar",
"current_page": "cp",
"currentPage": "cp",
"duration": "du",
"face_count": "fc",
"faceCount": "fc",
"height": "h",
"initial_aspect_ratio": "iar",
"initial_height": "ih",
"initial_width": "iw",
"initialAspectRatio": "iar",
"initialHeight": "ih",
"initialWidth": "iw",
"initial_duration": "idu",
"initialDuration": "idu",
"page_count": "pc",
"page_x": "px",
"page_y": "py",
"pageCount": "pc",
"pageX": "px",
"pageY": "py",
"tags": "tags",
"width": "w",
"trimmed_aspect_ratio": "tar",
"current_public_id": "cpi",
"initial_density": "idn",
"page_names": "pgnames"
};
const ACTION_TYPE_TO_CROP_MODE_MAP = {
limitFit: 'limit',
limitFill: 'lfill',
minimumFit: 'mfit',
thumbnail: 'thumb',
limitPad: 'lpad',
minimumPad: 'mpad'
};
const ACTION_TYPE_TO_DELIVERY_MODE_MAP = {
colorSpace: 'cs',
dpr: 'dpr',
density: 'dn',
defaultImage: 'd',
format: 'f',
quality: 'q'
};
const ACTION_TYPE_TO_EFFECT_MODE_MAP = {
redEye: 'redeye',
advancedRedEye: 'adv_redeye',
oilPaint: 'oil_paint',
unsharpMask: 'unsharp_mask',
makeTransparent: 'make_transparent',
generativeRestore: 'gen_restore'
};
const ACTION_TYPE_TO_QUALITY_MODE_MAP = {
autoBest: 'auto:best',
autoEco: 'auto:eco',
autoGood: 'auto:good',
autoLow: 'auto:low',
jpegminiHigh: 'jpegmini:1',
jpegminiMedium: 'jpegmini:2',
jpegminiBest: 'jpegmini:0'
};
const ACTION_TYPE_TO_STREAMING_PROFILE_MODE_MAP = {
fullHd: 'full_hd',
fullHdWifi: 'full_hd_wifi',
fullHdLean: 'full_hd_lean',
hdLean: 'hd_lean'
};
const CHROMA_VALUE_TO_CHROMA_MODEL_ENUM = {
444: "CHROMA_444",
420: "CHROMA_420"
};
const COLOR_SPACE_MODEL_MODE_TO_COLOR_SPACE_MODE_MAP = {
'noCmyk': 'no_cmyk',
'keepCmyk': 'keep_cmyk',
'tinySrgb': 'tinysrgb',
'srgbTrueColor': 'srgb:truecolor'
};
const ACTION_TYPE_TO_BLEND_MODE_MAP = {
'antiRemoval': 'anti_removal'
};
const CHROMA_MODEL_ENUM_TO_CHROMA_VALUE = objectFlip(CHROMA_VALUE_TO_CHROMA_MODEL_ENUM);
const COLOR_SPACE_MODE_TO_COLOR_SPACE_MODEL_MODE_MAP = objectFlip(COLOR_SPACE_MODEL_MODE_TO_COLOR_SPACE_MODE_MAP);
const CROP_MODE_TO_ACTION_TYPE_MAP = objectFlip(ACTION_TYPE_TO_CROP_MODE_MAP);
const DELIVERY_MODE_TO_ACTION_TYPE_MAP = objectFlip(ACTION_TYPE_TO_DELIVERY_MODE_MAP);
const EFFECT_MODE_TO_ACTION_TYPE_MAP = objectFlip(ACTION_TYPE_TO_EFFECT_MODE_MAP);
objectFlip(ACTION_TYPE_TO_QUALITY_MODE_MAP);
const STREAMING_PROFILE_TO_ACTION_TYPE_MAP = objectFlip(ACTION_TYPE_TO_STREAMING_PROFILE_MODE_MAP);
/**
* @description Qualifies the delivery of an asset.
* @memberOf Actions.Delivery
* @extends SDK.Action
*/
class DeliveryAction extends Action {
/**
* @param {string} deliveryKey A generic Delivery Action Key (such as q, f, dn, etc.)
* @param {string} deliveryType A Format Qualifiers for the action, such as Quality.auto()
* @param {string} modelProperty internal model property of the action, for example quality uses `level` while dpr uses `density`
* @see Visit {@link Actions.Delivery|Delivery} for an example
*/
constructor(deliveryKey, deliveryType, modelProperty) {
super();
this._actionModel = {};
let deliveryTypeValue;
if (deliveryType instanceof FormatQualifier) {
deliveryTypeValue = deliveryType.getValue();
}
else {
deliveryTypeValue = deliveryType;
}
this._actionModel.actionType = DELIVERY_MODE_TO_ACTION_TYPE_MAP[deliveryKey];
this._actionModel[modelProperty] = deliveryTypeValue;
this.addQualifier(new Qualifier(deliveryKey, deliveryType));
}
}
/**
* @description Contains functions to select the mode when using a progressive format.
* <b>Learn more</b>: {@link https://cloudinary.com/documentation/transformation_reference#fl_progressive|Progressive modes}
* @memberOf Qualifiers
* @namespace Progressive
* @example
* import {Cloudinary} from "@cloudinary/url-gen";
* import {format} from "@cloudinary/url-gen/actions/delivery";
* import {jpg} from "@cloudinary/url-gen/qualifiers/format";
* import {steep} from "@cloudinary/url-gen/qualifiers/progressive";
*
* const yourCldInstance = new Cloudinary({cloud: {cloudName: 'demo'}});
* const image = yourCldInstance.image('woman');
* image.delivery(format(jpg()).progressive(steep()))
*/
class ProgressiveQualifier extends FlagQualifier {
constructor(mode) {
super('progressive', mode);
}
}
/**
* @memberOf Actions.Delivery
* @extends {Actions.Delivery.DeliveryAction}
* @see Visit {@link Actions.Delivery|Delivery} for an example
*/
class DeliveryFormatAction extends DeliveryAction {
constructor(deliveryKey, deliveryType) {
super(deliveryKey, deliveryType, 'formatType');
}
/**
* @description Uses lossy compression when delivering animated GIF files.
* @return {this}
*/
lossy() {
this._actionModel.lossy = true;
this.addFlag(lossy());
return this;
}
/**
* @description Uses progressive compression when delivering JPG file format.
* @return {this}
*/
progressive(mode) {
if (mode instanceof ProgressiveQualifier) {
this._actionModel.progressive = { mode: mode.getFlagValue() };
this.addFlag(mode);
}
else {
this._actionModel.progressive = { mode: mode };
this.addFlag(progressive(mode));
}
return this;
}
/**
* @description Ensures that images with a transparency channel are delivered in PNG format.
*/
preserveTransparency() {
this._actionModel.preserveTransparency = true;
this.addFlag(preserveTransparency());
return this;
}
static fromJson(actionModel) {
const { formatType, lossy, progressive, preserveTransparency } = actionModel;
let result;
if (formatType) {
result = new this('f', formatType);
}
else {
result = new this('f');
}
if (progressive) {
if (progressive.mode) {
result.progressive(progressive.mode);
}
else {
result.progressive();
}
}
lossy && result.lossy();
preserveTransparency && result.preserveTransparency();
return result;
}
}
/**
* @summary SDK
* @description - Defines how to transform an asset
* @memberOf SDK
*/
class Transformation$1 {
constructor() {
this.actions = [];
}
/**
* @param {SDK.Action | string} action
* @return {this}
*/
addAction(action) {
let actionToAdd;
if (typeof action === 'string') {
if (action.indexOf('/') >= 0) {
throw 'addAction cannot accept a string with a forward slash in it - /, use .addTransformation() instead';
}
else {
actionToAdd = new RawAction(action);
}
}
else {
actionToAdd = action;
}
this.actions.push(actionToAdd);
return this;
}
/**
* @description Allows the injection of a raw transformation as a string into the transformation, or a Transformation instance that was previously created
* @param {string | SDK.Transformation} tx
* @example
* import {Transformation} from "@cloudinary/url-gen";
*
* const transformation = new Transformation();
* transformation.addTransformation('w_100/w_200/w_300');
* @return {this}
*/
addTransformation(tx) {
if (tx instanceof Transformation$1) {
// Concat the new actions into the existing actions
this.actions = this.actions.concat(tx.actions);
}
else {
this.actions.push(new RawAction(tx));
}
return this;
}
/**
* @return {string}
*/
toString() {
return this.actions
.map((action) => {
return action.toString();
})
.filter((a) => a)
.join('/');
}
/**
* @description Delivers an animated GIF.
* @param {AnimatedAction} animatedAction
* @return {this}
*/
animated(animatedAction) {
return this.addAction(animatedAction);
}
/**
* @description Adds a border around the image.
* @param {Border} borderAction
* @return {this}
*/
border(borderAction) {
return this.addAction(borderAction);
}
/**
* @description Adjusts the shape of the delivered image. </br>
* <b>Learn more:</b> {@link https://cloudinary.com/documentation/effects_and_artistic_enhancements#distort|Shape changes and distortion effects}
* @param {IReshape} reshapeAction
* @return {this}
*/
reshape(reshapeAction) {
return this.addAction(reshapeAction);
}
/**
* @description Resize the asset using provided resize action
* @param {ResizeSimpleAction} resizeAction
* @return {this}
*/
resize(resizeAction) {
return this.addAction(resizeAction);
}
/**
* @desc An alias to Action Delivery.quality
* @param {string|number} quality
* @return {this}
*/
quality(quality) {
this.addAction(new DeliveryFormatAction('q', quality));
return this;
}
/**
* @desc An alias to Action Delivery.format
* @param {string} format
* @return {this}
*/
format(format) {
this.addAction(new DeliveryFormatAction('f', format));
return this;
}
/**
* @description Rounds the specified corners of an image.
* @param roundCornersAction
* @return {this}
*/
roundCorners(roundCornersAction) {
return this.addAction(roundCornersAction);
}
/**
* @description Adds an overlay over the base image.
* @param {LayerAction} overlayAction
* @return {this}
*/
overlay(overlayAction) {
return this.addAction(overlayAction);
}
/**
* @description Adds an underlay under the base image.
* @param {LayerAction} underlayAction
* @return {this}
*/
underlay(underlayAction) {
underlayAction.setLayerType('u');
return this.addAction(underlayAction);
}
/**
* @description Defines an new user variable.
* @param {VariableAction} variableAction
* @return {this}
*/
addVariable(variableAction) {
return this.addAction(variableAction);
}
/**
* @description Specifies a condition to be met before applying a transformation.
* @param {ConditionalAction} conditionAction
* @return {this}
*/
conditional(conditionAction) {
return this.addAction(conditionAction);
}
/**
* @description Applies a filter or an effect on an asset.
* @param {SimpleEffectAction} effectAction
* @return {this}
*/
effect(effectAction) {
return this.addAction(effectAction);
}
/**
* @description Applies adjustment effect on an asset.
* @param action
* @return {this}
*/
adjust(action) {
return this.addAction(action);
}
/**
* @description Rotates the asset by the given angle.
* @param {RotateAction} rotateAction
* @return {this}
*/
rotate(rotateAction) {
return this.addAction(rotateAction);
}
/**
* @description Applies a pre-defined named transformation of the given name.
* @param {NamedTransformation} namedTransformation
* @return {this}
*/
namedTransformation(namedTransformation) {
return this.addAction(namedTransformation);
}
/**
* @description Applies delivery action.
* @param deliveryAction
* @return {this}
*/
delivery(deliveryAction) {
return this.addAction(deliveryAction);
}
/**
* @description Sets the color of the background.
* @param {Qualifiers.Color} color
* @return {this}
*/
backgroundColor(color) {
return this.addAction(new BackgroundColor(prepareColor(color)));
}
/**
* @description Adds a layer in a Photoshop document.
* @param action
* @return {this}
*/
psdTools(action) {
return this.addAction(action);
}
/**
* @description Extracts an image or a page using an index, a range, or a name from a layered media asset.
* @param action
* @return {this}
*/
extract(action) {
return this.addAction(action);
}
/**
* @description Adds a flag as a separate action.
* @param {Qualifiers.Flag | string} flagQualifier
* @return {this}
*/
addFlag(flagQualifier) {
const action = new Action();
let flagToAdd = flagQualifier;
if (typeof flagQualifier === 'string') {
flagToAdd = new FlagQualifier(flagQualifier);
}
action.addQualifier(flagToAdd);
return this.addAction(action);
}
/**
* @description Inject a custom function into the image transformation pipeline.
* @return {this}
*/
customFunction(customFunction) {
return this.addAction(customFunction);
}
/**
* Transcodes the video (or audio) to another format.
* @param {Action} action
* @return {this}
*/
transcode(action) {
return this.addAction(action);
}
/**
* Applies the specified video edit action.
*
* @param {videoEditType} action
* @return {this}
*/
videoEdit(action) {
return this.addAction(action);
}
toJson() {
const actions = [];
for (const action of this.actions) {
const json = action.toJson();
if (isErrorObject(json)) {
// Fail early and return an IErrorObject
return json;
}
actions.push(json);
}
return { actions };
}
}
/**
* @summary SDK
* @extends {SDK.Transformation}
* @memberOf SDK
*/
class ImageTransformation extends Transformation$1 {
}
/**
* @summary SDK
* @extends {SDK.Transformation}
* @memberOf SDK
*/
class VideoTransformation extends Transformation$1 {
}
/**
*
* @private
* @description An isomorphic Base64 function, provides browser and server support.
* @param {string} input - A string to encode with base64
*/
function base64Encode$1(input) {
// Browser
let encodedResult = '';
if (typeof window !== 'undefined') {
// encodeURI the input to support unicode characters
// Since the URI might be encoded already, we try to decode it once before
encodedResult = btoa(encodeURI(decodeURI(input)));
}
else {
// NodeJS support
encodedResult = global.Buffer.from(input).toString('base64');
}
return encodedResult
.replace(/\+/g, '-') // Convert '+' to '-'
.replace(/\//g, '_'); // Convert '/' to '_';
}
/**
* @description
* Returns a string representing the float value of the input, if the input was a number-like.
* Examples:
* - '1.0' -> '1.0'
* - 1 -> '1.0'
* - '5' -> '5.0'
* - 'auto' -> 'auto'
* @private
* @param {string|number} value
* @return {string}
*/
function toFloatAsString(value) {
// Turn the input to string
// The Function will return `returnValue` value if the input is not a number-like expression
const returnValue = value.toString();
// if the string contains letters, return the input
if (returnValue.match(/[A-Z]/gi)) {
return returnValue;
}
// If the leading digit is 0, and we have more than 1 digit, it's not a number.
// 00, 00000, 0x15 etc.
if (returnValue.length > 1 && returnValue[0] === '0') {
return returnValue;
}
// Final sanity check, parse the number as a float and check if its NaN
const isNumberLike = !isNaN(parseFloat(returnValue)) && returnValue.indexOf(':') === -1;
// If it's a number-like, but the input does not contain a decimal - add it.
if (isNumberLike && returnValue.indexOf('.') === -1) {
return `${returnValue}.0`;
}
else {
// If the input already contains a decimal, just return the value
return returnValue;
}
}
/**
* @memberOf Qualifiers.AspectRatio
* @extends {SDK.QualifierValue}
*/
class AspectRatioQualifierValue extends QualifierValue {
}
/**
* @description Defines a resize using width and height.
* @extends SDK.Action
* @memberOf Actions.Resize
* @see Visit {@link Actions.Resize| Resize} for examples
*/
class ResizeSimpleAction extends Action {
/**
* @param {string} cropType
* @param {number | string} cropWidth The required width of a transformed asset.
* @param {number | string} cropHeight The required height of a transformed asset.
*/
constructor(cropType, cropWidth, cropHeight) {
super();
this._actionModel = { dimensions: {} };
this._actionModel.actionType = CROP_MODE_TO_ACTION_TYPE_MAP[cropType] || cropType;
this.addQualifier(new Qualifier('c', cropType));
cropWidth && this.width(cropWidth);
cropHeight && this.height(cropHeight);
}
/**
* @description Sets the height of the resize
* @param {string | number} x The height in pixels (if an integer is specified) or as a percentage (if a float is specified).
*/
height(x) {
this._actionModel.dimensions.height = x;
return this.addQualifier(new Qualifier('h', x));
}
/**
* @description Sets the width of the resize
* @param {string | number} x The width in pixels (if an integer is specified) or as a percentage (if a float is specified).
*/
width(x) {
this._actionModel.dimensions.width = x;
return this.addQualifier(new Qualifier('w', x));
}
/**
* @description Sets the aspect ratio of the asset.
* For a list of supported types see {@link Qualifiers.AspectRatio|
* AspectRatio values}
* @param {AspectRatioType|number|string} ratio The new aspect ratio, specified as a percentage or ratio.
* @return {this}
*/
aspectRatio(ratio) {
// toFloatAsString is used to ensure 1 turns into 1.0
if (ratio instanceof AspectRatioQualifierValue) {
this._actionModel.dimensions.aspectRatio = `${ratio}`;
return this.addQualifier(new Qualifier('ar', ratio));
}
if (typeof ratio === 'number' || typeof ratio === 'string') {
this._actionModel.dimensions.aspectRatio = toFloatAsString(ratio);
return this.addQualifier(new Qualifier('ar', toFloatAsString(ratio)));
}
if (ratio instanceof FlagQualifier) {
this._actionModel.dimensions.aspectRatio = `${ratio.qualifierValue}`;
return this.addFlag(ratio);
}
}
/**
* @description Modifies percentage-based width & height parameters of overlays and underlays (e.g., 1.0) to be relative to the containing image instead of the added layer.
* @return {this}
*/
relative() {
this._actionModel.relative = true;
return this.addFlag(relative());
}
/**
* @description Modifies percentage-based width & height parameters of overlays and underlays (e.g., 1.0) to be relative to the overlaid region
* @return {this}
*/
regionRelative() {
this._actionModel.regionRelative = true;
return this.addFlag(regionRelative());
}
static fromJson(actionModel) {
const { actionType, dimensions, relative, regionRelative } = actionModel;
const { aspectRatio, width, height } = dimensions;
const cropMode = ACTION_TYPE_TO_CROP_MODE_MAP[actionType] || actionType;
// We are using this() to allow inheriting classes to use super.fromJson.apply(this, [actionModel])
// This allows the inheriting classes to determine the class to be created
const result = new this(cropMode, width,