1import { Image } from "https://deno.land/x/imagescript@1.2.15/mod.ts";
2
3function encodeURL(url: string): string {
10
11 const {
12 w, // Width of the output image
13 h, // Height of the output image
14 fit, // Fit mode for resizing: 'cover' or 'contain'
15 background, // Background color for 'contain' mode or transparent areas
16 withoutEnlargement, // Whether to prevent enlarging the image
17 format = 'base64' // URL format: 'base64' or 'plain'
18 } = Object.fromEntries(params);
22
23 if (!inputUrl) {
24 const exampleUrl = "https://example.com/image.jpg";
25 const encodedExampleUrl = encodeURL(exampleUrl);
26 const baseUrl = `${url.protocol}//${url.host}/`;
27 const exampleBase64 = `${baseUrl}${encodedExampleUrl}?format=base64`;
28 const examplePlain = `${baseUrl}${exampleUrl}?format=plain`;
29 return new Response(`Error: No image URL provided. Please include a URL in the path and specify the format using the 'format' parameter.
30
31Example usage:
442. w (integer, optional):
45 - Values: Any positive integer
46 - Specifies the desired width of the output image in pixels
47 - If omitted, the original image width is used
48 - Example: w=300
49
503. h (integer, optional):
51 - Values: Any positive integer
52 - Specifies the desired height of the output image in pixels
53 - If omitted, the original image height is used
54 - Example: h=200
55
564. fit (string, optional):
57 - Values: 'cover' (default) or 'contain'
58 - Determines how the image should be resized to fit the specified dimensions
59 - 'cover': The image will fill the specified dimensions while maintaining its aspect ratio, potentially cropping the image
60 - 'contain': The image will be resized to fit within the specified dimensions while maintaining its aspect ratio, potentially adding letterboxing
61 - Example: fit=contain
62
696. withoutEnlargement (string, optional):
70 - Values: 'true' or 'false' (default)
71 - When set to 'true', prevents the image from being enlarged if the requested dimensions are larger than the original image
72 - Example: withoutEnlargement=true
73
74Usage notes:
75- The image URL should be provided in the path of the request URL
76- At least one of 'w' or 'h' should be provided to resize the image
77- If only one of 'w' or 'h' is provided, the other dimension will be calculated to maintain the aspect ratio
78- The 'background' parameter is only used when 'fit' is set to 'contain' or when the image has transparent areas
79- All parameters are optional. If not provided, default values or original image properties will be used`,
80 { status: 400 });
81 }
82
83 let imageUrl;
84 try {
85 if (format === 'base64') {
86 imageUrl = decodeURIComponent(atob(inputUrl));
87 } else if (format === 'plain') {
88 imageUrl = decodeURIComponent(inputUrl);
89 } else {
90 throw new Error('Invalid format specified. Use "base64" or "plain".');
91 }
92 console.log('Processed URL:', imageUrl);
93 } catch (error) {
94 return new Response(`Error processing URL: ${error.message}. Please ensure the URL is correctly formatted and the format is specified correctly.`, { status: 400 });
96
97 try {
98 console.log('Fetching image from:', imageUrl);
99 const response = await fetch(imageUrl);
100 if (!response.ok) {
101 throw new Error(`HTTP error! status: ${response.status}`);
103 const arrayBuffer = await response.arrayBuffer();
104
105 let image = await Image.decode(new Uint8Array(arrayBuffer));
106
107 const targetWidth = w ? parseInt(w) : image.width;
108 const targetHeight = h ? parseInt(h) : image.height;
109
110 if (withoutEnlargement === "true" && (targetWidth > image.width || targetHeight > image.height)) {
111 // Don't enlarge the image
112 } else {
113 if (fit === "contain") {
114 image = image.contain(targetWidth, targetHeight);
115 } else {
116 // Default to 'cover'
117 image = image.cover(targetWidth, targetHeight);
118 }
119 }
121 if (background) {
122 try {
123 const bgColor = Image.rgbaToColor(...JSON.parse(background));
124 const bgImage = new Image(image.width, image.height);
125 bgImage.fill(bgColor);
126 image = bgImage.composite(image);
127 } catch (error) {
128 console.error('Error applying background:', error);
131 }
132
133 const encodedImage = await image.encode();
134
135 return new Response(encodedImage, {
136 status: 200,
137 headers: {
138 "Content-Type": "image/png",
139 "Cache-Control": "max-age=86400"
140 }
141 });
142 } catch (error) {
143 console.error('Error processing image:', error);
144 let errorMessage = `Error processing image: ${error.message}. `;
145 if (error.message.includes('HTTP error')) {
146 errorMessage += 'The image could not be fetched from the provided URL. Please check if the URL is correct and accessible.';
147 } else if (error.message.includes('decode')) {
148 errorMessage += 'The image could not be decoded. Please ensure the URL points to a valid image file.';
149 } else if (error.message.includes('client error (Connect)')) {
150 errorMessage += 'There was a network error while trying to fetch the image. This might be due to network restrictions or the image server being unreachable.';
151 } else {
152 errorMessage += 'An unexpected error occurred while processing the image. Please try again or contact support if the issue persists.';
153 }
154 return new Response(errorMessage, { status: 500 });