mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-11-11 17:23:37 +01:00
Add visual workflow builder, fix critical bugs, and add Arabic i18n support
This commit is contained in:
1 parent
36ebb3b429
commit
5d8b83e105
118 files changed
+14151
-2357
No files matched your search
@@ -0,0 +1,312 @@
|
||||
import type { ScanSettings } from '../types/scanner-effect-type.js';
|
||||
import type { AdjustColorsSettings } from '../types/adjust-colors-type.js';
|
||||
|
||||
export function applyGreyscale(imageData: ImageData): void {
|
||||
const data = imageData.data;
|
||||
for (let j = 0; j < data.length; j += 4) {
|
||||
const grey = Math.round(
|
||||
0.299 * data[j] + 0.587 * data[j + 1] + 0.114 * data[j + 2]
|
||||
);
|
||||
data[j] = grey;
|
||||
data[j + 1] = grey;
|
||||
data[j + 2] = grey;
|
||||
}
|
||||
}
|
||||
|
||||
export function applyInvertColors(imageData: ImageData): void {
|
||||
const data = imageData.data;
|
||||
for (let j = 0; j < data.length; j += 4) {
|
||||
data[j] = 255 - data[j];
|
||||
data[j + 1] = 255 - data[j + 1];
|
||||
data[j + 2] = 255 - data[j + 2];
|
||||
}
|
||||
}
|
||||
|
||||
export function rgbToHsl(
|
||||
r: number,
|
||||
g: number,
|
||||
b: number
|
||||
): [number, number, number] {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
const l = (max + min) / 2;
|
||||
let h = 0;
|
||||
let s = 0;
|
||||
|
||||
if (max !== min) {
|
||||
const d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
||||
else if (max === g) h = ((b - r) / d + 2) / 6;
|
||||
else h = ((r - g) / d + 4) / 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
}
|
||||
|
||||
export function hslToRgb(
|
||||
h: number,
|
||||
s: number,
|
||||
l: number
|
||||
): [number, number, number] {
|
||||
if (s === 0) {
|
||||
const v = Math.round(l * 255);
|
||||
return [v, v, v];
|
||||
}
|
||||
|
||||
const hue2rgb = (p: number, q: number, t: number): number => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
return [
|
||||
Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
|
||||
Math.round(hue2rgb(p, q, h) * 255),
|
||||
Math.round(hue2rgb(p, q, h - 1 / 3) * 255),
|
||||
];
|
||||
}
|
||||
|
||||
export function applyScannerEffect(
|
||||
sourceData: ImageData,
|
||||
canvas: HTMLCanvasElement,
|
||||
settings: ScanSettings,
|
||||
rotationAngle: number,
|
||||
scale: number = 1
|
||||
): void {
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
const w = sourceData.width;
|
||||
const h = sourceData.height;
|
||||
|
||||
const scaledBlur = settings.blur * scale;
|
||||
const scaledNoise = settings.noise * scale;
|
||||
|
||||
const workCanvas = document.createElement('canvas');
|
||||
workCanvas.width = w;
|
||||
workCanvas.height = h;
|
||||
const workCtx = workCanvas.getContext('2d')!;
|
||||
|
||||
if (scaledBlur > 0) {
|
||||
workCtx.filter = `blur(${scaledBlur}px)`;
|
||||
}
|
||||
|
||||
workCtx.putImageData(sourceData, 0, 0);
|
||||
if (scaledBlur > 0) {
|
||||
const tempCanvas = document.createElement('canvas');
|
||||
tempCanvas.width = w;
|
||||
tempCanvas.height = h;
|
||||
const tempCtx = tempCanvas.getContext('2d')!;
|
||||
tempCtx.filter = `blur(${scaledBlur}px)`;
|
||||
tempCtx.drawImage(workCanvas, 0, 0);
|
||||
workCtx.filter = 'none';
|
||||
workCtx.clearRect(0, 0, w, h);
|
||||
workCtx.drawImage(tempCanvas, 0, 0);
|
||||
}
|
||||
|
||||
const imageData = workCtx.getImageData(0, 0, w, h);
|
||||
const data = imageData.data;
|
||||
|
||||
const contrastFactor =
|
||||
settings.contrast !== 0
|
||||
? (259 * (settings.contrast + 255)) / (255 * (259 - settings.contrast))
|
||||
: 1;
|
||||
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
let r = data[i];
|
||||
let g = data[i + 1];
|
||||
let b = data[i + 2];
|
||||
|
||||
if (settings.grayscale) {
|
||||
const grey = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
r = grey;
|
||||
g = grey;
|
||||
b = grey;
|
||||
}
|
||||
|
||||
if (settings.brightness !== 0) {
|
||||
r += settings.brightness;
|
||||
g += settings.brightness;
|
||||
b += settings.brightness;
|
||||
}
|
||||
|
||||
if (settings.contrast !== 0) {
|
||||
r = contrastFactor * (r - 128) + 128;
|
||||
g = contrastFactor * (g - 128) + 128;
|
||||
b = contrastFactor * (b - 128) + 128;
|
||||
}
|
||||
|
||||
if (settings.yellowish > 0) {
|
||||
const intensity = settings.yellowish / 50;
|
||||
r += 20 * intensity;
|
||||
g += 12 * intensity;
|
||||
b -= 15 * intensity;
|
||||
}
|
||||
|
||||
if (scaledNoise > 0) {
|
||||
const n = (Math.random() - 0.5) * scaledNoise;
|
||||
r += n;
|
||||
g += n;
|
||||
b += n;
|
||||
}
|
||||
|
||||
data[i] = Math.max(0, Math.min(255, r));
|
||||
data[i + 1] = Math.max(0, Math.min(255, g));
|
||||
data[i + 2] = Math.max(0, Math.min(255, b));
|
||||
}
|
||||
|
||||
workCtx.putImageData(imageData, 0, 0);
|
||||
|
||||
if (settings.border) {
|
||||
const borderSize = Math.max(w, h) * 0.02;
|
||||
const gradient1 = workCtx.createLinearGradient(0, 0, borderSize, 0);
|
||||
gradient1.addColorStop(0, 'rgba(0,0,0,0.3)');
|
||||
gradient1.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
workCtx.fillStyle = gradient1;
|
||||
workCtx.fillRect(0, 0, borderSize, h);
|
||||
|
||||
const gradient2 = workCtx.createLinearGradient(w, 0, w - borderSize, 0);
|
||||
gradient2.addColorStop(0, 'rgba(0,0,0,0.3)');
|
||||
gradient2.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
workCtx.fillStyle = gradient2;
|
||||
workCtx.fillRect(w - borderSize, 0, borderSize, h);
|
||||
|
||||
const gradient3 = workCtx.createLinearGradient(0, 0, 0, borderSize);
|
||||
gradient3.addColorStop(0, 'rgba(0,0,0,0.3)');
|
||||
gradient3.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
workCtx.fillStyle = gradient3;
|
||||
workCtx.fillRect(0, 0, w, borderSize);
|
||||
|
||||
const gradient4 = workCtx.createLinearGradient(0, h, 0, h - borderSize);
|
||||
gradient4.addColorStop(0, 'rgba(0,0,0,0.3)');
|
||||
gradient4.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
workCtx.fillStyle = gradient4;
|
||||
workCtx.fillRect(0, h - borderSize, w, borderSize);
|
||||
}
|
||||
|
||||
if (rotationAngle !== 0) {
|
||||
const rad = (rotationAngle * Math.PI) / 180;
|
||||
const cos = Math.abs(Math.cos(rad));
|
||||
const sin = Math.abs(Math.sin(rad));
|
||||
const newW = Math.ceil(w * cos + h * sin);
|
||||
const newH = Math.ceil(w * sin + h * cos);
|
||||
|
||||
canvas.width = newW;
|
||||
canvas.height = newH;
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillRect(0, 0, newW, newH);
|
||||
ctx.translate(newW / 2, newH / 2);
|
||||
ctx.rotate(rad);
|
||||
ctx.drawImage(workCanvas, -w / 2, -h / 2);
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
} else {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
ctx.drawImage(workCanvas, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export function applyColorAdjustments(
|
||||
sourceData: ImageData,
|
||||
canvas: HTMLCanvasElement,
|
||||
settings: AdjustColorsSettings
|
||||
): void {
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
const w = sourceData.width;
|
||||
const h = sourceData.height;
|
||||
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
|
||||
const imageData = new ImageData(new Uint8ClampedArray(sourceData.data), w, h);
|
||||
const data = imageData.data;
|
||||
|
||||
const contrastFactor =
|
||||
settings.contrast !== 0
|
||||
? (259 * (settings.contrast + 255)) / (255 * (259 - settings.contrast))
|
||||
: 1;
|
||||
|
||||
const gammaCorrection = settings.gamma !== 1.0 ? 1 / settings.gamma : 1;
|
||||
const sepiaAmount = settings.sepia / 100;
|
||||
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
let r = data[i];
|
||||
let g = data[i + 1];
|
||||
let b = data[i + 2];
|
||||
|
||||
if (settings.brightness !== 0) {
|
||||
const adj = settings.brightness * 2.55;
|
||||
r += adj;
|
||||
g += adj;
|
||||
b += adj;
|
||||
}
|
||||
|
||||
if (settings.contrast !== 0) {
|
||||
r = contrastFactor * (r - 128) + 128;
|
||||
g = contrastFactor * (g - 128) + 128;
|
||||
b = contrastFactor * (b - 128) + 128;
|
||||
}
|
||||
|
||||
if (settings.saturation !== 0 || settings.hueShift !== 0) {
|
||||
const [hue, sat, lig] = rgbToHsl(
|
||||
Math.max(0, Math.min(255, r)),
|
||||
Math.max(0, Math.min(255, g)),
|
||||
Math.max(0, Math.min(255, b))
|
||||
);
|
||||
|
||||
let newHue = hue;
|
||||
if (settings.hueShift !== 0) {
|
||||
newHue = (hue + settings.hueShift / 360) % 1;
|
||||
if (newHue < 0) newHue += 1;
|
||||
}
|
||||
|
||||
let newSat = sat;
|
||||
if (settings.saturation !== 0) {
|
||||
const satAdj = settings.saturation / 100;
|
||||
newSat = satAdj > 0 ? sat + (1 - sat) * satAdj : sat * (1 + satAdj);
|
||||
newSat = Math.max(0, Math.min(1, newSat));
|
||||
}
|
||||
|
||||
[r, g, b] = hslToRgb(newHue, newSat, lig);
|
||||
}
|
||||
|
||||
if (settings.temperature !== 0) {
|
||||
const t = settings.temperature / 50;
|
||||
r += 30 * t;
|
||||
b -= 30 * t;
|
||||
}
|
||||
|
||||
if (settings.tint !== 0) {
|
||||
const t = settings.tint / 50;
|
||||
g += 30 * t;
|
||||
}
|
||||
|
||||
if (settings.gamma !== 1.0) {
|
||||
r = Math.pow(Math.max(0, Math.min(255, r)) / 255, gammaCorrection) * 255;
|
||||
g = Math.pow(Math.max(0, Math.min(255, g)) / 255, gammaCorrection) * 255;
|
||||
b = Math.pow(Math.max(0, Math.min(255, b)) / 255, gammaCorrection) * 255;
|
||||
}
|
||||
|
||||
if (settings.sepia > 0) {
|
||||
const sr = 0.393 * r + 0.769 * g + 0.189 * b;
|
||||
const sg = 0.349 * r + 0.686 * g + 0.168 * b;
|
||||
const sb = 0.272 * r + 0.534 * g + 0.131 * b;
|
||||
r = r + (sr - r) * sepiaAmount;
|
||||
g = g + (sg - g) * sepiaAmount;
|
||||
b = b + (sb - b) * sepiaAmount;
|
||||
}
|
||||
|
||||
data[i] = Math.max(0, Math.min(255, r));
|
||||
data[i + 1] = Math.max(0, Math.min(255, g));
|
||||
data[i + 2] = Math.max(0, Math.min(255, b));
|
||||
}
|
||||
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
}
|
||||
Reference in new issue
Block a user