merge: resolve conflict with main branch in README.md

This commit is contained in:
SnapOtter
2026-05-08 17:32:16 +08:00
150 changed files with 32270 additions and 101 deletions
@@ -26,6 +26,7 @@ const OUTPUT_FORMATS: { value: OutputFormat; label: string }[] = [
{ value: "jpeg", label: "JPEG" },
{ value: "webp", label: "WebP" },
{ value: "avif", label: "AVIF" },
{ value: "jxl", label: "JXL" },
];
const BG_PRESETS = [
@@ -4,8 +4,38 @@ import { ProgressCard } from "@/components/common/progress-card";
import { useToolProcessor } from "@/hooks/use-tool-processor";
import { useFileStore } from "@/stores/file-store";
const OUTPUT_FORMATS = ["jpg", "png", "webp", "avif", "tiff", "gif", "heic", "heif"] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif"];
const OUTPUT_FORMATS = [
"jpg",
"png",
"webp",
"avif",
"tiff",
"gif",
"heic",
"heif",
"jxl",
"bmp",
"ico",
"jp2",
"qoi",
] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif", "jxl", "jp2"];
const FORMAT_LABELS: Record<string, string> = {
jpg: "JPG",
png: "PNG",
webp: "WebP",
avif: "AVIF",
tiff: "TIFF",
gif: "GIF",
heic: "HEIC",
heif: "HEIF",
jxl: "JXL",
bmp: "BMP",
ico: "ICO",
jp2: "JP2",
qoi: "QOI",
};
export interface ConvertControlsProps {
settings?: Record<string, unknown>;
@@ -54,7 +84,7 @@ export function ConvertControls({ settings: initialSettings, onChange }: Convert
>
{OUTPUT_FORMATS.map((f) => (
<option key={f} value={f}>
{f.toUpperCase()}
{FORMAT_LABELS[f] ?? f.toUpperCase()}
</option>
))}
</select>
@@ -6,8 +6,18 @@ import { generateId } from "@/lib/utils";
import { useFileStore } from "@/stores/file-store";
import type { EraserCanvasRef } from "./eraser-canvas";
const OUTPUT_FORMATS = ["png", "jpg", "webp", "avif", "tiff", "gif", "heic", "heif"] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif"];
const OUTPUT_FORMATS = [
"png",
"jpg",
"webp",
"avif",
"tiff",
"gif",
"heic",
"heif",
"jxl",
] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif", "jxl"];
interface EraseObjectSettingsProps {
eraserRef: React.RefObject<EraserCanvasRef | null>;
@@ -10,6 +10,7 @@ const OUTPUT_FORMATS = [
{ value: "png", label: "PNG" },
{ value: "webp", label: "WebP" },
{ value: "avif", label: "AVIF" },
{ value: "jxl", label: "JXL" },
] as const;
export function ImageToBase64Settings() {
@@ -69,7 +70,11 @@ export function ImageToBase64Settings() {
};
const hasFiles = files.length > 0;
const showQuality = outputFormat === "jpeg" || outputFormat === "webp" || outputFormat === "avif";
const showQuality =
outputFormat === "jpeg" ||
outputFormat === "webp" ||
outputFormat === "avif" ||
outputFormat === "jxl";
return (
<div className="space-y-4">
@@ -13,7 +13,7 @@ const TIERS: { id: Tier; label: string; desc: string }[] = [
{ id: "maximum", label: "Maximum", desc: "Best AI model, slowest" },
];
const LOSSY_FORMATS = new Set(["jpeg", "webp", "avif"]);
const LOSSY_FORMATS = new Set(["jpeg", "webp", "avif", "jxl"]);
export interface NoiseRemovalControlsProps {
settings?: Record<string, unknown>;
@@ -28,9 +28,9 @@ export function NoiseRemovalControls({
const [strength, setStrength] = useState(50);
const [detailPreservation, setDetailPreservation] = useState(50);
const [colorNoise, setColorNoise] = useState(30);
const [outputFormat, setOutputFormat] = useState<"original" | "png" | "jpeg" | "webp" | "avif">(
"original",
);
const [outputFormat, setOutputFormat] = useState<
"original" | "png" | "jpeg" | "webp" | "avif" | "jxl"
>("original");
const [quality, setQuality] = useState(90);
// One-time init from pipeline settings
@@ -44,7 +44,9 @@ export function NoiseRemovalControls({
setDetailPreservation(Number(initialSettings.detailPreservation));
if (initialSettings.colorNoise != null) setColorNoise(Number(initialSettings.colorNoise));
if (initialSettings.format != null)
setOutputFormat(initialSettings.format as "original" | "png" | "jpeg" | "webp" | "avif");
setOutputFormat(
initialSettings.format as "original" | "png" | "jpeg" | "webp" | "avif" | "jxl",
);
if (initialSettings.quality != null) setQuality(Number(initialSettings.quality));
}, [initialSettings]);
@@ -164,8 +166,8 @@ export function NoiseRemovalControls({
{/* Output format */}
<div>
<p className="text-xs text-muted-foreground mb-1">Output Format</p>
<div className="grid grid-cols-5 gap-1">
{(["original", "png", "jpeg", "webp", "avif"] as const).map((f) => (
<div className="grid grid-cols-3 gap-1">
{(["original", "png", "jpeg", "webp", "avif", "jxl"] as const).map((f) => (
<button
key={f}
type="button"
@@ -5,7 +5,7 @@ import { useToolProcessor } from "@/hooks/use-tool-processor";
import { formatHeaders } from "@/lib/api";
import { useFileStore } from "@/stores/file-store";
type WebFormat = "webp" | "jpeg" | "avif" | "png";
type WebFormat = "webp" | "jpeg" | "avif" | "png" | "jxl";
interface PreviewState {
loading: boolean;
@@ -19,6 +19,7 @@ const FORMAT_LABELS: Record<WebFormat, string> = {
jpeg: "JPEG",
avif: "AVIF",
png: "PNG",
jxl: "JXL",
};
function formatSize(bytes: number): string {
@@ -200,8 +201,8 @@ export function OptimizeForWebSettings() {
{/* Format selector */}
<div>
<p className="text-sm font-medium text-muted-foreground">Output Format</p>
<div className="grid grid-cols-4 gap-1 mt-1">
{(["webp", "jpeg", "avif", "png"] as const).map((f) => (
<div className="grid grid-cols-5 gap-1 mt-1">
{(["webp", "jpeg", "avif", "png", "jxl"] as const).map((f) => (
<button
key={f}
type="button"
@@ -11,6 +11,7 @@ const FORMAT_OPTIONS = [
{ value: "gif", label: "GIF" },
{ value: "heic", label: "HEIC" },
{ value: "heif", label: "HEIF" },
{ value: "jxl", label: "JXL" },
];
const DPI_PRESETS = [
@@ -33,7 +34,7 @@ const COLOR_MODE_OPTIONS = [
{ value: "bw", label: "B&W" },
] as const;
const LOSSY_FORMATS = ["jpg", "webp", "avif", "heic", "heif"];
const LOSSY_FORMATS = ["jpg", "webp", "avif", "heic", "heif", "jxl"];
export function PdfToImageSettings() {
const store = usePdfToImageStore();
@@ -4,7 +4,7 @@ import { ProgressCard } from "@/components/common/progress-card";
import { useToolProcessor } from "@/hooks/use-tool-processor";
import { useFileStore } from "@/stores/file-store";
const LOSSY_FORMATS = new Set(["jpeg", "webp", "avif"]);
const LOSSY_FORMATS = new Set(["jpeg", "webp", "avif", "jxl"]);
export interface RedEyeRemovalControlsProps {
settings?: Record<string, unknown>;
@@ -17,9 +17,9 @@ export function RedEyeRemovalControls({
}: RedEyeRemovalControlsProps) {
const [sensitivity, setSensitivity] = useState(50);
const [strength, setStrength] = useState(70);
const [outputFormat, setOutputFormat] = useState<"original" | "png" | "jpeg" | "webp" | "avif">(
"original",
);
const [outputFormat, setOutputFormat] = useState<
"original" | "png" | "jpeg" | "webp" | "avif" | "jxl"
>("original");
const [quality, setQuality] = useState(90);
// One-time init from pipeline settings
@@ -30,7 +30,9 @@ export function RedEyeRemovalControls({
if (initialSettings.sensitivity != null) setSensitivity(Number(initialSettings.sensitivity));
if (initialSettings.strength != null) setStrength(Number(initialSettings.strength));
if (initialSettings.format != null)
setOutputFormat(initialSettings.format as "original" | "png" | "jpeg" | "webp" | "avif");
setOutputFormat(
initialSettings.format as "original" | "png" | "jpeg" | "webp" | "avif" | "jxl",
);
if (initialSettings.quality != null) setQuality(Number(initialSettings.quality));
}, [initialSettings]);
@@ -101,8 +103,8 @@ export function RedEyeRemovalControls({
{/* Output format */}
<div>
<p className="text-xs text-muted-foreground mb-1">Output Format</p>
<div className="grid grid-cols-5 gap-1">
{(["original", "png", "jpeg", "webp", "avif"] as const).map((f) => (
<div className="grid grid-cols-3 gap-1">
{(["original", "png", "jpeg", "webp", "avif", "jxl"] as const).map((f) => (
<button
key={f}
type="button"
@@ -29,9 +29,10 @@ const OUTPUT_FORMATS = [
{ value: "jpg", label: "JPG" },
{ value: "webp", label: "WebP" },
{ value: "avif", label: "AVIF" },
{ value: "jxl", label: "JXL" },
] as const;
const LOSSY_FORMATS = new Set(["jpg", "webp", "avif"]);
const LOSSY_FORMATS = new Set(["jpg", "webp", "avif", "jxl"]);
export function SplitSettings() {
const { files, processing: fileStoreProcessing } = useFileStore();
@@ -6,7 +6,7 @@ import { useFileStore } from "@/stores/file-store";
type Direction = "horizontal" | "vertical" | "grid";
type ResizeMode = "fit" | "original" | "stretch" | "crop";
type Alignment = "start" | "center" | "end";
type OutputFormat = "png" | "jpeg" | "webp" | "avif";
type OutputFormat = "png" | "jpeg" | "webp" | "avif" | "jxl";
export function StitchSettings() {
const { files, processing, error, setProcessing, setError, setProcessedUrl, setSizes, setJobId } =
@@ -227,7 +227,7 @@ export function StitchSettings() {
<div>
<p className="text-xs text-muted-foreground">Format</p>
<div className="grid grid-cols-3 gap-1 mt-1">
{(["png", "jpeg", "webp", "avif"] as const).map((f) => (
{(["png", "jpeg", "webp", "avif", "jxl"] as const).map((f) => (
<button
type="button"
key={f}
@@ -240,7 +240,7 @@ export function StitchSettings() {
</div>
</div>
{(format === "jpeg" || format === "webp" || format === "avif") && (
{(format === "jpeg" || format === "webp" || format === "avif" || format === "jxl") && (
<div>
<div className="flex justify-between items-center">
<label htmlFor="stitch-quality" className="text-xs text-muted-foreground">
@@ -4,12 +4,12 @@ import { ProgressCard } from "@/components/common/progress-card";
import { useToolProcessor } from "@/hooks/use-tool-processor";
import { useFileStore } from "@/stores/file-store";
type OutputFormat = "png" | "jpg" | "webp" | "avif" | "tiff" | "gif" | "heif";
type OutputFormat = "png" | "jpg" | "webp" | "avif" | "tiff" | "gif" | "heif" | "jxl";
type SizingMode = "scale" | "custom";
type BgMode = "transparent" | "color";
const FORMATS: OutputFormat[] = ["png", "jpg", "webp", "avif", "tiff", "gif", "heif"];
const LOSSY_FORMATS: OutputFormat[] = ["jpg", "webp", "avif", "heif"];
const FORMATS: OutputFormat[] = ["png", "jpg", "webp", "avif", "tiff", "gif", "heif", "jxl"];
const LOSSY_FORMATS: OutputFormat[] = ["jpg", "webp", "avif", "heif", "jxl"];
const NO_TRANSPARENCY_FORMATS: OutputFormat[] = ["jpg", "tiff"];
const SCALE_PRESETS = [0.5, 1, 2, 3, 4];
@@ -10,8 +10,18 @@ const MODEL_OPTIONS = [
{ value: "auto", label: "Balanced" },
{ value: "realesrgan", label: "Best" },
] as const;
const OUTPUT_FORMATS = ["png", "jpg", "webp", "avif", "tiff", "gif", "heic", "heif"] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif"];
const OUTPUT_FORMATS = [
"png",
"jpg",
"webp",
"avif",
"tiff",
"gif",
"heic",
"heif",
"jxl",
] as const;
const LOSSY_FORMATS = ["jpg", "jpeg", "webp", "avif", "heic", "heif", "jxl"];
export interface UpscaleControlsProps {
settings?: Record<string, unknown>;