fix(web): гистограмма пересчитывается при правках
Гистограмма считалась по базовому превью один раз и не менялась при движении ползунков и кривой. Теперь по уменьшенной копии фото накапливается сэмпл пикселей, а сама гистограмма пересчитывается с применением текущих правок, так что график реагирует на манипуляции сразу.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { photosApi } from '$lib/api';
|
||||
import Icon from './Icon.svelte';
|
||||
import { edit } from '$lib/stores/edit.svelte';
|
||||
import { applyLight } from '$lib/light-wasm';
|
||||
import {
|
||||
CHANNEL_COLORS,
|
||||
CHANNEL_LABELS,
|
||||
@@ -53,21 +54,22 @@
|
||||
};
|
||||
});
|
||||
|
||||
// Гистограмма каналов считается по базовому превью фото.
|
||||
// Гистограмма каналов считается по базовому превью фото и пересчитывается
|
||||
// с учётом текущих правок, поэтому реагирует на движение ползунков и кривой.
|
||||
type Histogram = { red: number[]; green: number[]; blue: number[] };
|
||||
let histogram = $state<Histogram | null>(null);
|
||||
let sample = $state<Uint8ClampedArray | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
const url = photo.preview_url;
|
||||
if (!url) {
|
||||
histogram = null;
|
||||
sample = null;
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
if (cancelled) return;
|
||||
histogram = computeHistogram(img);
|
||||
sample = sampleImage(img);
|
||||
};
|
||||
img.src = url;
|
||||
return () => {
|
||||
@@ -75,8 +77,8 @@
|
||||
};
|
||||
});
|
||||
|
||||
/** Считает гистограмму каналов по уменьшенной копии фото. */
|
||||
function computeHistogram(img: HTMLImageElement): Histogram | null {
|
||||
/** Уменьшенная копия фото: пиксели для расчёта гистограммы. */
|
||||
function sampleImage(img: HTMLImageElement): Uint8ClampedArray | null {
|
||||
const width = 256;
|
||||
const height = Math.max(1, Math.round((img.naturalHeight / img.naturalWidth) * width));
|
||||
const canvas = document.createElement('canvas');
|
||||
@@ -85,7 +87,15 @@
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return null;
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const data = ctx.getImageData(0, 0, width, height).data;
|
||||
return new Uint8ClampedArray(ctx.getImageData(0, 0, width, height).data);
|
||||
}
|
||||
|
||||
/** Гистограмма с учётом текущих правок. */
|
||||
const histogram = $derived.by<Histogram | null>(() => {
|
||||
const pixels = sample;
|
||||
if (!pixels) return null;
|
||||
const data = new Uint8ClampedArray(pixels);
|
||||
applyLight(data, params.light);
|
||||
const r = new Array<number>(256).fill(0);
|
||||
const g = new Array<number>(256).fill(0);
|
||||
const b = new Array<number>(256).fill(0);
|
||||
@@ -101,7 +111,7 @@
|
||||
if (!max) return null;
|
||||
const norm = (values: number[]) => values.map((v) => v / max);
|
||||
return { red: norm(r), green: norm(g), blue: norm(b) };
|
||||
}
|
||||
});
|
||||
|
||||
/** Каналы, которые показываем на графике: у мастер-канала — все три. */
|
||||
const visibleChannels = $derived<CurveChannel[]>(
|
||||
|
||||
Reference in New Issue
Block a user