72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
import { getImgproxyUrl } from './imgproxy';
|
|
|
|
/**
|
|
* Next.js Image Loader for imgproxy
|
|
*
|
|
* @param {Object} props - properties from Next.js Image component
|
|
* @param {string} props.src - The source image URL
|
|
* @param {number} props.width - The desired image width
|
|
* @param {number} props.quality - The desired image quality (ignored for now as imgproxy handles it)
|
|
*/
|
|
export default function imgproxyLoader({
|
|
src,
|
|
width,
|
|
_quality,
|
|
}: {
|
|
src: string;
|
|
width: number;
|
|
_quality?: number;
|
|
}) {
|
|
// Skip imgproxy for SVGs as they are vectors and don't benefit from resizing,
|
|
// and often cause 404s if the source is not correctly resolvable by imgproxy.
|
|
if (src.toLowerCase().endsWith('.svg')) {
|
|
return src;
|
|
}
|
|
|
|
// Check if src contains custom gravity or aspect ratio query parameters
|
|
let gravity = 'sm'; // Use smart gravity (content-aware) by default
|
|
let cleanSrc = src;
|
|
let calculatedHeight = 0;
|
|
let resizingType: 'fit' | 'fill' = 'fit';
|
|
|
|
try {
|
|
// Dummy base needed for relative URLs
|
|
const url = new URL(src, 'http://localhost');
|
|
const customGravity = url.searchParams.get('gravity');
|
|
const aspectRatio = url.searchParams.get('ar'); // e.g. "16:9"
|
|
|
|
if (customGravity) {
|
|
gravity = customGravity;
|
|
url.searchParams.delete('gravity');
|
|
}
|
|
|
|
if (aspectRatio) {
|
|
const parts = aspectRatio.split(':');
|
|
if (parts.length === 2) {
|
|
const arW = parseFloat(parts[0]);
|
|
const arH = parseFloat(parts[1]);
|
|
if (!isNaN(arW) && !isNaN(arH) && arW > 0) {
|
|
calculatedHeight = Math.round(width * (arH / arW));
|
|
resizingType = 'fill'; // Must use fill to allow imgproxy to crop
|
|
}
|
|
}
|
|
url.searchParams.delete('ar');
|
|
}
|
|
|
|
if (customGravity || aspectRatio) {
|
|
cleanSrc = src.startsWith('http') ? url.href : url.pathname + url.search;
|
|
}
|
|
} catch (e) {
|
|
// Fallback if parsing fails
|
|
}
|
|
|
|
// We use the width provided by Next.js for responsive images
|
|
// Height is calculated from aspect ratio if provided, otherwise 0 to maintain aspect ratio
|
|
return getImgproxyUrl(cleanSrc, {
|
|
width,
|
|
height: calculatedHeight,
|
|
resizing_type: resizingType,
|
|
gravity,
|
|
});
|
|
}
|