More writing for the main posts

This commit is contained in:
2024-12-09 22:18:13 -05:00
parent b608a25146
commit 0983558659
16 changed files with 155 additions and 125 deletions

View File

@ -44,20 +44,6 @@ const PaletteBar: React.FC<PaletteBarProps> = ({height, palette, children}) => {
)
}
const colorSwatchPainter = (palette: number[], color: number) =>
(width: number, height: number) => {
const [r, g, b] = colorFromPalette(palette, color);
const image = new ImageData(width, height);
for (let i = 0; i < image.data.length; i += 4) {
image.data[i] = r * 0xff;
image.data[i + 1] = g * 0xff;
image.data[i + 2] = b * 0xff;
image.data[i + 3] = 0xff;
}
return image;
}
type ColorEditorProps = {
title: string;
palette: number[];

View File

@ -1,9 +1,13 @@
import {ChaosGameFinalProps} from "../2-transforms/chaosGameFinal";
// hidden-start
import {Props as ChaosGameFinalProps} from "../2-transforms/chaosGameFinal";
import {randomBiUnit} from "../src/randomBiUnit";
import {randomChoice} from "../src/randomChoice";
import {camera, histIndex} from "../src/camera";
import {colorFromPalette, paintColor} from "./paintColor";
const quality = 15;
const step = 100_000;
// hidden-end
export type TransformColor = {
color: number;
colorSpeed: number;
@ -13,23 +17,21 @@ function mixColor(color1: number, color2: number, colorSpeed: number) {
return color1 * (1 - colorSpeed) + color2 * colorSpeed;
}
export type ChaosGameColorProps = ChaosGameFinalProps & {
type Props = ChaosGameFinalProps & {
palette: number[];
colors: TransformColor[];
finalColor: TransformColor;
}
export function* chaosGameColor({width, height, transforms, final, palette, colors, finalColor, quality, step}: ChaosGameColorProps) {
let iterations = (quality ?? 1) * width * height;
step = step ?? 10_000;
export function* chaosGameColor({width, height, transforms, final, palette, colors, finalColor}: Props) {
let currentColor = Math.random();
const red = Array(width * height).fill(0);
const green = Array(width * height).fill(0);
const blue = Array(width * height).fill(0);
const alpha = Array(width * height).fill(0);
const red = Array<number>(width * height).fill(0);
const green = Array<number>(width * height).fill(0);
const blue = Array<number>(width * height).fill(0);
const alpha = Array<number>(width * height).fill(0);
let [x, y] = [randomBiUnit(), randomBiUnit()];
const iterations = width * height * quality;
for (let i = 0; i < iterations; i++) {
const [transformIndex, transform] = randomChoice(transforms);
[x, y] = transform(x, y);

View File

@ -1,17 +1,19 @@
// hidden-start
import {randomBiUnit} from "../src/randomBiUnit";
import {randomChoice} from "../src/randomChoice";
import {ChaosGameFinalProps} from "../2-transforms/chaosGameFinal";
import {Props as ChaosGameFinalProps} from "../2-transforms/chaosGameFinal";
import {camera, histIndex} from "../src/camera";
// hidden-end
export type ChaosGameHistogramProps = ChaosGameFinalProps & {
paint: (width: number, histogram: Uint32Array) => ImageData;
}
export function* chaosGameHistogram({width, height, transforms, final, quality, step, paint}: ChaosGameHistogramProps) {
let iterations = (quality ?? 1) * width * height;
step = step ?? 10_000;
const histogram = new Uint32Array(width * height);
const quality = 10;
const step = 100_000;
// hidden-end
export type Props = ChaosGameFinalProps & {
paint: (width: number, height: number, histogram: number[]) => ImageData;
}
export function* chaosGameHistogram({width, height, transforms, final, paint}: Props) {
let iterations = quality * width * height;
const histogram = Array<number>(width * height).fill(0);
let [x, y] = [randomBiUnit(), randomBiUnit()];
@ -22,13 +24,18 @@ export function* chaosGameHistogram({width, height, transforms, final, quality,
if (i > 20) {
const [pixelX, pixelY] = camera(finalX, finalY, width);
const pixelIndex = histIndex(pixelX, pixelY, width, 1);
histogram[pixelIndex] += 1;
const hIndex = histIndex(pixelX, pixelY, width, 1);
if (hIndex < 0 || hIndex >= histogram.length) {
continue;
}
histogram[hIndex] += 1;
}
if (i % step === 0)
yield paint(width, histogram);
yield paint(width, height, histogram);
}
yield paint(width, histogram);
yield paint(width, height, histogram);
}

View File

@ -18,6 +18,10 @@ Can we do something more intelligent with that information?
## Image histograms
:::note
This post covers sections 4 and 5 of the Fractal Flame Algorithm paper
:::
To start with, it's worth demonstrating how much work is actually "wasted."
We'll render the reference image again, but this time, set each pixel's transparency
based on how many times we encounter it in the chaos game:

View File

@ -1,17 +1,17 @@
export function paintLinear(width: number, histogram: Uint32Array): ImageData {
const image = new ImageData(width, histogram.length / width);
export function paintLinear(width: number, height: number, histogram: number[]): ImageData {
const image = new ImageData(width, height);
let countMax = 0;
let valueMax = 0;
for (let value of histogram) {
countMax = Math.max(countMax, value);
valueMax = Math.max(valueMax, value);
}
for (let i = 0; i < histogram.length; i++) {
const pixelIndex = i * 4;
image.data[pixelIndex] = 0; // red
image.data[pixelIndex + 1] = 0; // green
image.data[pixelIndex + 2] = 0; // blue
image.data[pixelIndex + 3] = Number(histogram[i]) / countMax * 0xff;
image.data[pixelIndex] = 0;
image.data[pixelIndex + 1] = 0;
image.data[pixelIndex + 2] = 0;
image.data[pixelIndex + 3] = histogram[i] / valueMax * 0xff;
}
return image;

View File

@ -1,5 +1,5 @@
export function paintLogarithmic(width: number, histogram: Uint32Array): ImageData {
const image = new ImageData(width, histogram.length / width);
export function paintLogarithmic(width: number, height: number, histogram: number[]): ImageData {
const image = new ImageData(width, height);
const histogramLog = new Array<number>();
histogram.forEach(value => histogramLog.push(Math.log(value)));