import { FileNode } from "mazlo-api/types"; import theme from "mazlo-theme"; import { Crop } from "../components/ImageCrop"; import { getDefaultCrop } from "./image"; type ImageUrlParams = { fit?: "cover" | "contain" | "fill"; p?: "center" | "top" | "left" | "right" | "bottom"; w?: number; h?: number; cx?: number; cy?: number; cw?: number; ch?: number; b?: string; }; export type Image = { aspectRatio?: string | number; // TODO: remove crop: Crop; // TODO: remove crops?: { [cropName: string]: Crop }; file: FileNode; }; export const getScaledDimensions = (image: Image, size: number) => { const { height, width } = image.file?.attributes?.meta || {}; const max = Math.max(height, width); const scale = max ? size / max : 1; // contain return { height: scale * height, width: scale * width }; }; export const getImageAspectRatio = ( image: Image, forceAspect?: number | string ): number => { const aspectRatio = forceAspect || image?.aspectRatio; if (typeof aspectRatio === "number") return aspectRatio; if ( (!aspectRatio || aspectRatio === "original") && image.file?.attributes?.meta ) { const { width, height } = image.file.attributes.meta; return width / height; } if (!aspectRatio) return 16 / 9; const [width, height] = aspectRatio.split(":"); return parseInt(width, 10) / parseInt(height, 10); }; const round = (n) => +n.toFixed(); const getImageUrl = ( image?: Image, options?: { crop?: string; aspectRatio?: number | string; fit?: "cover" | "contain" | "fill"; position?: "center" | "top" | "left" | "right" | "bottom"; height?: number; width?: number; backgroundColor?: string; } ) => { if (!image || !image.file) return { uri: "" }; const { url, meta } = image.file.attributes; const cropFrame = options?.crop && theme.cropSizes[options.crop]; const crop = cropFrame ? image.crops?.[options.crop] || getDefaultCrop(meta, cropFrame.height, cropFrame.width) : image.crop; if (!url) return { uri: "" }; if (!crop && !options) return { uri: url }; const imageParams: ImageUrlParams = {}; if (crop) { const { x, y, scale } = crop; let { height, width } = cropFrame || {}; if (!height || !width) { // TODO: remove const aspectRatio = getImageAspectRatio(image, options?.aspectRatio); width = 1000; height = width / aspectRatio; } imageParams.cx = round(x / scale); imageParams.cy = round(y / scale); imageParams.cw = round(width / scale); imageParams.ch = round(height / scale); } if (options?.width) { imageParams.w = round(options.width); } if (options?.height) { imageParams.h = round(options.height); } if (options?.fit) { imageParams.fit = options.fit; } if (options?.position) { imageParams.p = options.position; } if (options?.backgroundColor) { imageParams.b = options.backgroundColor; } const imageParamKeys = Object.keys(imageParams); return imageParamKeys.length ? { uri: `${url}?${imageParamKeys .map((key) => `${key}=${imageParams[key]}`) .join("&")}`, } : { uri: url }; }; export default getImageUrl;