(width: number, height: number)
| 6 | export const PLACEHOLDER_IMAGE_DOMAIN = "https://placehold.co"; |
| 7 | |
| 8 | const createCanvasImageUrl = (width: number, height: number): string => { |
| 9 | // Check if we're in a browser environment |
| 10 | if (typeof document === "undefined" || typeof window === "undefined") { |
| 11 | // Fallback for non-browser environments |
| 12 | return `${PLACEHOLDER_IMAGE_DOMAIN}/${width}x${height}`; |
| 13 | } |
| 14 | |
| 15 | const canvas = document.createElement("canvas"); |
| 16 | canvas.width = width; |
| 17 | canvas.height = height; |
| 18 | |
| 19 | const ctx = canvas.getContext("2d"); |
| 20 | if (!ctx) { |
| 21 | // Fallback if canvas context is not available |
| 22 | return `${PLACEHOLDER_IMAGE_DOMAIN}/${width}x${height}`; |
| 23 | } |
| 24 | |
| 25 | const fontSize = Math.max(12, Math.floor(width * 0.15)); |
| 26 | ctx.font = `bold ${fontSize}px Inter, Arial, Helvetica, sans-serif`; |
| 27 | ctx.fillStyle = "#888888"; |
| 28 | |
| 29 | const text = `${width} x ${height}`; |
| 30 | const textWidth = ctx.measureText(text).width; |
| 31 | const x = (width - textWidth) / 2; |
| 32 | const y = (height + fontSize) / 2; |
| 33 | |
| 34 | ctx.fillText(text, x, y); |
| 35 | |
| 36 | const image = canvas.toDataURL(); |
| 37 | const base64 = image.substring(22); |
| 38 | const byteCharacters = atob(base64); |
| 39 | const byteNumbers = new Array(byteCharacters.length); |
| 40 | for (let i = 0; i < byteCharacters.length; i++) { |
| 41 | byteNumbers[i] = byteCharacters.charCodeAt(i); |
| 42 | } |
| 43 | const byteArray = new Uint8Array(byteNumbers); |
| 44 | const file = new Blob([byteArray], { |
| 45 | type: "image/png;base64", |
| 46 | }); |
| 47 | return URL.createObjectURL(file); |
| 48 | }; |
| 49 | |
| 50 | export const getPlaceholderImage = (w: number, h = -1) => { |
| 51 | const _w = w.toFixed(0); |
nothing calls this directly
no outgoing calls
no test coverage detected