Created
September 26, 2025 11:32
-
-
Save keevitaja/3a7a83fa2d97c60cedd427b21939ae5f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| /* Barnsley fern → PNG (Node.js + pngjs) | |
| * Usage: node fern.js [width] [height] [iterations] [outfile] | |
| */ | |
| const fs = require("fs"); | |
| const { PNG } = require("pngjs"); | |
| const width = parseInt(process.argv[2] || "2000", 10); | |
| const height = parseInt(process.argv[3] || "3000", 10); | |
| const iters = parseInt(process.argv[4] || "3000000", 10); | |
| const out = process.argv[5] || "fern.png"; | |
| // Barnsley fern koordinaadid (mahu kaardistamiseks) | |
| const XMIN = -2.1820, XMAX = 2.6558; | |
| const YMIN = 0.0, YMAX = 9.9983; | |
| // Kaardistus maailmast pikslitesse (säilitab proportsiooni) | |
| const sx = (width - 1) / (XMAX - XMIN); | |
| const sy = (height - 1) / (YMAX - YMIN); | |
| // Histogrammi puhvrid toonide jaoks | |
| const counts = new Uint32Array(width * height); | |
| // Algpunkt | |
| let x = 0, y = 0; | |
| // IFS transformatsioonid ja nende tõenäosused | |
| for (let i = 0; i < iters; i++) { | |
| const r = Math.random() * 100; | |
| let xn, yn; | |
| if (r < 1) { | |
| // Tüvi | |
| xn = 0; | |
| yn = 0.16 * y; | |
| } else if (r < 86) { | |
| // Suur haru | |
| xn = 0.85 * x + 0.04 * y; | |
| yn = -0.04 * x + 0.85 * y + 1.6; | |
| } else if (r < 93) { | |
| // Väike haru 1 | |
| xn = 0.20 * x - 0.26 * y; | |
| yn = 0.23 * x + 0.22 * y + 1.6; | |
| } else { | |
| // Väike haru 2 | |
| xn = -0.15 * x + 0.28 * y; | |
| yn = 0.26 * x + 0.24 * y + 0.44; | |
| } | |
| x = xn; y = yn; | |
| // Kaardista pikslisse (Y telg ekraanil alla) | |
| const px = Math.round((x - XMIN) * sx); | |
| const py = height - 1 - Math.round((y - YMIN) * sy); | |
| if (px >= 0 && px < width && py >= 0 && py < height) { | |
| counts[py * width + px]++; | |
| } | |
| } | |
| // Leia max loendus normaliseerimiseks (kasuta log-skaalat detailide esiletõstmiseks) | |
| let maxCount = 0; | |
| for (let i = 0; i < counts.length; i++) { | |
| if (counts[i] > maxCount) maxCount = counts[i]; | |
| } | |
| // Värvi PNG: must taust, roheline leht (logaritmiline intensiivsus) | |
| const png = new PNG({ width, height }); | |
| for (let i = 0; i < counts.length; i++) { | |
| const c = counts[i]; | |
| const idx = i << 2; // *4 | |
| if (c === 0) { | |
| // taust (must) | |
| png.data[idx + 0] = 0; | |
| png.data[idx + 1] = 0; | |
| png.data[idx + 2] = 0; | |
| png.data[idx + 3] = 255; | |
| } else { | |
| // log-normaliseerimine | |
| const v = Math.log(1 + c) / Math.log(1 + maxCount); // 0..1 | |
| const g = Math.min(255, Math.floor(255 * v)); | |
| // pehme roheline; soovi korral muuda RGB-d | |
| png.data[idx + 0] = Math.floor(g * 0.2); // R | |
| png.data[idx + 1] = g; // G | |
| png.data[idx + 2] = Math.floor(g * 0.3); // B | |
| png.data[idx + 3] = 255; // A | |
| } | |
| } | |
| // Kirjuta fail | |
| png | |
| .pack() | |
| .pipe(fs.createWriteStream(out)) | |
| .on("finish", () => { | |
| console.log(`OK: ${out} (${width}×${height}, ${iters.toLocaleString()} iteratsiooni)`); | |
| }) | |
| .on("error", (e) => { | |
| console.error("Kirjutamise viga:", e); | |
| process.exit(1); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment