Perlin Noise Generator

Perlin Noise Generator

Likes 19 Downloads
Get Shortcut
Security Notice
Shortcuts can be dangerous and may contain malicious code. Always exercise caution when downloading shortcuts. Review the shortcut's actions before running it and watch out for weird permission requests.

Changelog

v1.0

Description

A image or text to prelin noise image generator Needs scriptable, copy an paste this into a browser then copy text into a scriptable: https://www.icloud.com/attachment/?u=https%3A%2F%2Fcvws.icloud-content.com%2FB%2FAdz9_P-lhgYJ5l5b5IeKtyDW0ieRAc2-NyDfKqpPUUfvwHWaXgFXLJDo%2F%24%7Bf%7D%3Fo%3DAtV50_11fKvwAUVyQ5Td200JtGKsFfX-g4PjieC-c1bC%26v%3D1%26x%3D3%26a%3DCAog-J2zfQyCPTxSUYfzxp-f0vbR1A-QgQe8wZLVV_cxc4wSbRCk1NmPtzMYpOTU48AzIgEAUgTW0ieRWgRXLJDoaibAGLNMMIBBZKfB8dGrwLB3kbCqa8xcddaQGwa7k28yRaOb76nxVHImf28xnW9kfZWHTCMC8J4t3YDuDWHva0ZryHlXfFMhvYWVsnNxglk%26e%3D1769735533%26fl%3D%26r%3D631B66AA-70E2-4926-8C03-E7E9AD980FAF-1%26k%3D%24%7Buk%7D%26ckc%3Dcom.apple.clouddocs%26ckz%3DiCloud.is.workflow.my.workflows%26p%3D171%26s%3DK3YNvbYDreOhcQXSKuKp54-Gnjo&uk=GDvO49hVW7Dx_8DboqTJgw&f=File-short-b1-103725.xz&sz=2816 Code: // --- LOGGER SETUP --- const startTime = Date.now(); function log(msg) { const diff = Date.now() - startTime; console.log(`[${diff}ms] ${msg}`); } log("Script started."); // --- INPUT HANDLING --- let inputImage = null; let inputString = "default"; // Default seed if (args.images.length > 0) { log("Input detected: Image provided."); inputImage = args.images[0]; } else if (args.shortcutParameter) { if (typeof args.shortcutParameter === "string") { log(`Input detected: Text seed "${args.shortcutParameter}"`); inputString = args.shortcutParameter; } else { // Handle case where image is passed as parameter log("Input detected: Image object in parameter."); inputImage = args.shortcutParameter; } } else { log("No input found. Using default seed."); } // --- CONFIGURATION --- const BLOCK_SIZE = 4; // 4 = Retro/Fast, 2 = HD/Slow const NOISE_SCALE = 0.02; // Lower = Zoomed in (bigger clouds), Higher = Zoomed out const OCTAVES = 1; // Complexity of noise (Keep to 1 for speed in JS) // If overlaying on an image, use white fog with transparency. // If standalone, use opaque colorful plasma. const IS_OVERLAY = inputImage !== null; const NOISE_ALPHA = IS_OVERLAY ? 0.5 : 1.0; // --- PERLIN NOISE IMPLEMENTATION --- // We need a permutation table (0-255) to drive the noise. // We will shuffle this table using the user's seed. log("Initializing Random Seed..."); // 1. Simple Seeded RNG (Linear Congruential Generator) let seed = 0; for (let i = 0; i < inputString.length; i++) { seed = (Math.imul(31, seed) + inputString.charCodeAt(i)) | 0; } function random() { seed = (Math.imul(1664525, seed) + 1013904223) | 0; return ((seed >>> 0) / 4294967296); } // 2. Initialize Permutation Table const PERM_SIZE = 256; const p = new Uint8Array(PERM_SIZE * 2); // Fill with 0..255 let permutation = []; for (let i = 0; i < PERM_SIZE; i++) { permutation[i] = i; } // Shuffle using our seed for (let i = PERM_SIZE - 1; i > 0; i--) { let r = Math.floor(random() * (i + 1)); [permutation[i], permutation[r]] = [permutation[r], permutation[i]]; } // Double the array to avoid overflow wrapping for (let i = 0; i < PERM_SIZE * 2; i++) { p[i] = permutation[i % PERM_SIZE]; } log("Permutation table generated."); // 3. Perlin Math Helpers function fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); } function lerp(t, a, b) { return a + t * (b - a); } function grad(hash, x, y, z) { const h = hash & 15; const u = h < 8 ? x : y; const v = h < 4 ? y : h === 12 || h === 14 ? x : z; return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v); } // 4. The Noise Function (2D) function perlin(x, y) { // Find unit cube that contains point let X = Math.floor(x) & 255; let Y = Math.floor(y) & 255; // Find relative x,y of point in cube x -= Math.floor(x); y -= Math.floor(y); // Compute fade curves let u = fade(x); let v = fade(y); // Hash coordinates of the 4 cube corners let A = p[X] + Y; let B = p[X + 1] + Y; // Add blended results from 4 corners return lerp(v, lerp(u, grad(p[A], x, y, 0), grad(p[B], x - 1, y, 0)), lerp(u, grad(p[A + 1], x, y - 1, 0), grad(p[B + 1], x - 1, y - 1, 0)) ); } // --- RENDERING --- let width, height; if (inputImage) { width = inputImage.size.width; height = inputImage.size.height; } else { width = 800; height = 800; } log(`Canvas dimensions set: ${width}x${height}`); let ctx = new DrawContext(); ctx.size = new Size(width, height); ctx.respectScreenScale = true; ctx.shouldAntialias = false; // Draw Background if (inputImage) { log("Drawing background image..."); ctx.drawImageInRect(inputImage, new Rect(0, 0, width, height)); } else { // Dark background for colorful noise ctx.setFillColor(new Color("#000000")); ctx.fillRect(new Rect(0, 0, width, height)); } // Helper: Map -1..1 to 0..255 function mapRange(val, inMin, inMax, outMin, outMax) { return (val - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; } // Helper: Float to Hex function toHex(val) { let intVal = Math.floor(Math.max(0, Math.min(255, val))); let hex = intVal.toString(16); return hex.length === 1 ? "0" + hex : hex; } log(`Starting render loop (Block Size: ${BLOCK_SIZE})...`); let totalBlocks = (width * height) / (BLOCK_SIZE * BLOCK_SIZE); let count = 0; for (let px = 0; px < width; px += BLOCK_SIZE) { for (let py = 0; py < height; py += BLOCK_SIZE) { // Calculate Noise Value (-1.0 to 1.0) // We add seed offset to x/y to ensure different text makes different clouds let noiseVal = perlin(px * NOISE_SCALE, py * NOISE_SCALE); let color; if (IS_OVERLAY) { // White Fog Effect // Map noise -1..1 to Alpha 0..1 let alphaVal = mapRange(noiseVal, -1, 1, 0, NOISE_ALPHA); // White color with variable alpha color = new Color("FFFFFF", alphaVal); } else { // Colorful Plasma Effect // Map noise to 0..255 let v = mapRange(noiseVal, -1, 1, 0, 255); // Generate pseudo-palette based on noise value // This creates bands of color let r = v; let g = (v + 85) % 255; // Offset green let b = (v + 170) % 255; // Offset blue let hex = toHex(r) + toHex(g) + toHex(b); color = new Color(hex, 1.0); } ctx.setFillColor(color); ctx.fillRect(new Rect(px, py, BLOCK_SIZE, BLOCK_SIZE)); count++; } } log(`Render complete. Processed ${count} blocks.`); // --- OUTPUT --- let finalImage = ctx.getImage(); let fm = FileManager.local(); let tempPath = fm.joinPath(fm.temporaryDirectory(), "perlin_output.png"); fm.writeImage(tempPath, finalImage); log(`Image saved to: ${tempPath}`); Script.setShortcutOutput(tempPath); if (config.runsInApp) { QuickLook.present(finalImage); } log("Script finished."); Script.complete();

Information

Version: 1.0
Released:
Last Updated:
Apps:
Permissions:
Photos
Files
Camera

Comments

Start the conversation

No comments yet. Be the first to comment!