feat(blur): implement video blur annotation support

This commit is contained in:
Mahdy Arief
2026-04-11 07:39:35 +07:00
parent d5a17d396b
commit 45ee7105ef
8 changed files with 44 additions and 4 deletions
@@ -111,6 +111,17 @@ export function AnnotationOverlay({
</div>
);
case "blur":
return (
<div
className="h-full w-full bg-slate-400/10"
style={{
backdropFilter: "blur(12px)",
WebkitBackdropFilter: "blur(12px)",
boxShadow: isSelected ? "inset 0 0 0 1px rgba(255,255,255,0.2)" : "none",
}}
/>
);
default:
return null;
}
@@ -1,7 +1,7 @@
import { useRef, useState, useEffect, useMemo } from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { Trash2, Type, Image as ImageIcon, Upload, Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, ChevronDown, Info } from "lucide-react";
import { Trash2, Type, Image as ImageIcon, Upload, Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, ChevronDown, Info, SquareDashed } from "lucide-react";
import { toast } from "sonner";
import Block from '@uiw/react-color-block';
import type { AnnotationRegion, AnnotationType, ArrowDirection, FigureData } from "./types";
@@ -128,7 +128,7 @@ export function AnnotationSettingsPanel({
{/* Type Selector */}
<Tabs value={annotation.type} onValueChange={(value) => onTypeChange(value as AnnotationType)} className="mb-6">
<TabsList className="mb-4 bg-white/5 border border-white/5 p-1 w-full grid grid-cols-3 h-auto rounded-xl">
<TabsList className="mb-4 bg-white/5 border border-white/5 p-1 w-full grid grid-cols-4 h-auto rounded-xl">
<TabsTrigger value="text" className="data-[state=active]:bg-[#2563EB] data-[state=active]:text-white text-slate-400 py-2 rounded-lg transition-all gap-2">
<Type className="w-4 h-4" />
{t('annotations.text')}
@@ -143,6 +143,10 @@ export function AnnotationSettingsPanel({
</svg>
{t('annotations.arrow')}
</TabsTrigger>
<TabsTrigger value="blur" className="data-[state=active]:bg-[#2563EB] data-[state=active]:text-white text-slate-400 py-2 rounded-lg transition-all gap-2">
<SquareDashed className="w-4 h-4" />
{t('annotations.blur')}
</TabsTrigger>
</TabsList>
{/* Text Content */}
@@ -499,6 +503,18 @@ export function AnnotationSettingsPanel({
</Popover>
</div>
</TabsContent>
<TabsContent value="blur" className="mt-0 space-y-4">
<div className="p-4 bg-white/5 rounded-xl border border-white/10 flex flex-col items-center justify-center text-center">
<div className="w-12 h-12 rounded-full bg-[#2563EB]/20 flex items-center justify-center mb-3">
<SquareDashed className="w-6 h-6 text-[#2563EB]" />
</div>
<h4 className="text-sm font-medium text-slate-200 mb-1">{t('annotations.blur')}</h4>
<p className="text-xs text-slate-400 max-w-[200px]">
Resize and reposition the box on the video to blur sensitive information.
</p>
</div>
</TabsContent>
</Tabs>
<Button
@@ -399,7 +399,7 @@ export function normalizeProjectEditor(editor: Partial<ProjectEditorState>): Pro
id: region.id,
startMs,
endMs,
type: region.type === "image" || region.type === "figure" ? region.type : "text",
type: region.type === "image" || region.type === "figure" || region.type === "blur" ? region.type : "text",
content: typeof region.content === "string" ? region.content : "",
textContent: typeof region.textContent === "string" ? region.textContent : undefined,
imageContent: typeof region.imageContent === "string" ? region.imageContent : undefined,
+1 -1
View File
@@ -175,7 +175,7 @@ export function trimsToClips(trims: TrimRegion[], totalDurationMs: number): Clip
return clips;
}
export type AnnotationType = "text" | "image" | "figure";
export type AnnotationType = "text" | "image" | "figure" | "blur";
export type ArrowDirection =
| "up"
+1
View File
@@ -9,6 +9,7 @@
"text": "Text",
"image": "Image",
"arrow": "Arrow",
"blur": "Blur",
"textContent": "Text Content",
"textPlaceholder": "Enter your text...",
"fontStyle": "Font Style",
+1
View File
@@ -9,6 +9,7 @@
"text": "Texto",
"image": "Imagen",
"arrow": "Flecha",
"blur": "Desenfoque",
"textContent": "Contenido de texto",
"textPlaceholder": "Ingresa tu texto...",
"fontStyle": "Estilo de fuente",
+1
View File
@@ -9,6 +9,7 @@
"text": "文本",
"image": "图片",
"arrow": "箭头",
"blur": "模糊",
"textContent": "文本内容",
"textPlaceholder": "输入文本...",
"fontStyle": "字体样式",
+10
View File
@@ -358,6 +358,16 @@ export async function renderAnnotations(
);
}
break;
case "blur":
ctx.save();
ctx.beginPath();
ctx.rect(x, y, width, height);
ctx.clip();
ctx.filter = `blur(${20 * scaleFactor}px)`;
ctx.drawImage(ctx.canvas, 0, 0);
ctx.restore();
break;
}
}
}