urlForImage.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. "use strict";
  2. var __assign = (this && this.__assign) || function () {
  3. __assign = Object.assign || function(t) {
  4. for (var s, i = 1, n = arguments.length; i < n; i++) {
  5. s = arguments[i];
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  7. t[p] = s[p];
  8. }
  9. return t;
  10. };
  11. return __assign.apply(this, arguments);
  12. };
  13. var __importDefault = (this && this.__importDefault) || function (mod) {
  14. return (mod && mod.__esModule) ? mod : { "default": mod };
  15. };
  16. Object.defineProperty(exports, "__esModule", { value: true });
  17. exports.parseSource = exports.SPEC_NAME_TO_URL_NAME_MAPPINGS = void 0;
  18. var parseAssetId_1 = __importDefault(require("./parseAssetId"));
  19. var parseSource_1 = __importDefault(require("./parseSource"));
  20. exports.parseSource = parseSource_1.default;
  21. exports.SPEC_NAME_TO_URL_NAME_MAPPINGS = [
  22. ['width', 'w'],
  23. ['height', 'h'],
  24. ['format', 'fm'],
  25. ['download', 'dl'],
  26. ['blur', 'blur'],
  27. ['sharpen', 'sharp'],
  28. ['invert', 'invert'],
  29. ['orientation', 'or'],
  30. ['minHeight', 'min-h'],
  31. ['maxHeight', 'max-h'],
  32. ['minWidth', 'min-w'],
  33. ['maxWidth', 'max-w'],
  34. ['quality', 'q'],
  35. ['fit', 'fit'],
  36. ['crop', 'crop'],
  37. ['saturation', 'sat'],
  38. ['auto', 'auto'],
  39. ['dpr', 'dpr'],
  40. ['pad', 'pad'],
  41. ];
  42. function urlForImage(options) {
  43. var spec = __assign({}, (options || {}));
  44. var source = spec.source;
  45. delete spec.source;
  46. var image = (0, parseSource_1.default)(source);
  47. if (!image) {
  48. throw new Error("Unable to resolve image URL from source (".concat(JSON.stringify(source), ")"));
  49. }
  50. var id = image.asset._ref || image.asset._id || '';
  51. var asset = (0, parseAssetId_1.default)(id);
  52. // Compute crop rect in terms of pixel coordinates in the raw source image
  53. var cropLeft = Math.round(image.crop.left * asset.width);
  54. var cropTop = Math.round(image.crop.top * asset.height);
  55. var crop = {
  56. left: cropLeft,
  57. top: cropTop,
  58. width: Math.round(asset.width - image.crop.right * asset.width - cropLeft),
  59. height: Math.round(asset.height - image.crop.bottom * asset.height - cropTop),
  60. };
  61. // Compute hot spot rect in terms of pixel coordinates
  62. var hotSpotVerticalRadius = (image.hotspot.height * asset.height) / 2;
  63. var hotSpotHorizontalRadius = (image.hotspot.width * asset.width) / 2;
  64. var hotSpotCenterX = image.hotspot.x * asset.width;
  65. var hotSpotCenterY = image.hotspot.y * asset.height;
  66. var hotspot = {
  67. left: hotSpotCenterX - hotSpotHorizontalRadius,
  68. top: hotSpotCenterY - hotSpotVerticalRadius,
  69. right: hotSpotCenterX + hotSpotHorizontalRadius,
  70. bottom: hotSpotCenterY + hotSpotVerticalRadius,
  71. };
  72. // If irrelevant, or if we are requested to: don't perform crop/fit based on
  73. // the crop/hotspot.
  74. if (!(spec.rect || spec.focalPoint || spec.ignoreImageParams || spec.crop)) {
  75. spec = __assign(__assign({}, spec), fit({ crop: crop, hotspot: hotspot }, spec));
  76. }
  77. return specToImageUrl(__assign(__assign({}, spec), { asset: asset }));
  78. }
  79. exports.default = urlForImage;
  80. // eslint-disable-next-line complexity
  81. function specToImageUrl(spec) {
  82. var cdnUrl = (spec.baseUrl || 'https://cdn.sanity.io').replace(/\/+$/, '');
  83. var filename = "".concat(spec.asset.id, "-").concat(spec.asset.width, "x").concat(spec.asset.height, ".").concat(spec.asset.format);
  84. var baseUrl = "".concat(cdnUrl, "/images/").concat(spec.projectId, "/").concat(spec.dataset, "/").concat(filename);
  85. var params = [];
  86. if (spec.rect) {
  87. // Only bother url with a crop if it actually crops anything
  88. var _a = spec.rect, left = _a.left, top_1 = _a.top, width = _a.width, height = _a.height;
  89. var isEffectiveCrop = left !== 0 || top_1 !== 0 || height !== spec.asset.height || width !== spec.asset.width;
  90. if (isEffectiveCrop) {
  91. params.push("rect=".concat(left, ",").concat(top_1, ",").concat(width, ",").concat(height));
  92. }
  93. }
  94. if (spec.bg) {
  95. params.push("bg=".concat(spec.bg));
  96. }
  97. if (spec.focalPoint) {
  98. params.push("fp-x=".concat(spec.focalPoint.x));
  99. params.push("fp-y=".concat(spec.focalPoint.y));
  100. }
  101. var flip = [spec.flipHorizontal && 'h', spec.flipVertical && 'v'].filter(Boolean).join('');
  102. if (flip) {
  103. params.push("flip=".concat(flip));
  104. }
  105. // Map from spec name to url param name, and allow using the actual param name as an alternative
  106. exports.SPEC_NAME_TO_URL_NAME_MAPPINGS.forEach(function (mapping) {
  107. var specName = mapping[0], param = mapping[1];
  108. if (typeof spec[specName] !== 'undefined') {
  109. params.push("".concat(param, "=").concat(encodeURIComponent(spec[specName])));
  110. }
  111. else if (typeof spec[param] !== 'undefined') {
  112. params.push("".concat(param, "=").concat(encodeURIComponent(spec[param])));
  113. }
  114. });
  115. if (params.length === 0) {
  116. return baseUrl;
  117. }
  118. return "".concat(baseUrl, "?").concat(params.join('&'));
  119. }
  120. function fit(source, spec) {
  121. var cropRect;
  122. var imgWidth = spec.width;
  123. var imgHeight = spec.height;
  124. // If we are not constraining the aspect ratio, we'll just use the whole crop
  125. if (!(imgWidth && imgHeight)) {
  126. return { width: imgWidth, height: imgHeight, rect: source.crop };
  127. }
  128. var crop = source.crop;
  129. var hotspot = source.hotspot;
  130. // If we are here, that means aspect ratio is locked and fitting will be a bit harder
  131. var desiredAspectRatio = imgWidth / imgHeight;
  132. var cropAspectRatio = crop.width / crop.height;
  133. if (cropAspectRatio > desiredAspectRatio) {
  134. // The crop is wider than the desired aspect ratio. That means we are cutting from the sides
  135. var height = Math.round(crop.height);
  136. var width = Math.round(height * desiredAspectRatio);
  137. var top_2 = Math.max(0, Math.round(crop.top));
  138. // Center output horizontally over hotspot
  139. var hotspotXCenter = Math.round((hotspot.right - hotspot.left) / 2 + hotspot.left);
  140. var left = Math.max(0, Math.round(hotspotXCenter - width / 2));
  141. // Keep output within crop
  142. if (left < crop.left) {
  143. left = crop.left;
  144. }
  145. else if (left + width > crop.left + crop.width) {
  146. left = crop.left + crop.width - width;
  147. }
  148. cropRect = { left: left, top: top_2, width: width, height: height };
  149. }
  150. else {
  151. // The crop is taller than the desired ratio, we are cutting from top and bottom
  152. var width = crop.width;
  153. var height = Math.round(width / desiredAspectRatio);
  154. var left = Math.max(0, Math.round(crop.left));
  155. // Center output vertically over hotspot
  156. var hotspotYCenter = Math.round((hotspot.bottom - hotspot.top) / 2 + hotspot.top);
  157. var top_3 = Math.max(0, Math.round(hotspotYCenter - height / 2));
  158. // Keep output rect within crop
  159. if (top_3 < crop.top) {
  160. top_3 = crop.top;
  161. }
  162. else if (top_3 + height > crop.top + crop.height) {
  163. top_3 = crop.top + crop.height - height;
  164. }
  165. cropRect = { left: left, top: top_3, width: width, height: height };
  166. }
  167. return {
  168. width: imgWidth,
  169. height: imgHeight,
  170. rect: cropRect,
  171. };
  172. }
  173. //# sourceMappingURL=urlForImage.js.map