Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai-box
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
青山
ai-box
Commits
f11990d2
Commit
f11990d2
authored
Nov 14, 2024
by
fisherdaddy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feature: 新增图像背景移除工具
parent
3db13667
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
376 additions
and
40 deletions
+376
-40
App.jsx
src/App.jsx
+3
-2
BackgroundRemover.jsx
src/components/BackgroundRemover.jsx
+267
-0
ImageWatermark.jsx
src/components/ImageWatermark.jsx
+17
-0
SubtitleGenerator.jsx
src/components/SubtitleGenerator.jsx
+25
-23
TextBehindImage.jsx
src/components/TextBehindImage.jsx
+17
-0
tools.json
src/locales/en/tools.json
+11
-3
tools.json
src/locales/ja/tools.json
+12
-4
tools.json
src/locales/ko/tools.json
+11
-3
tools.json
src/locales/zh/tools.json
+11
-3
Home.jsx
src/pages/Home.jsx
+1
-1
ImageTools.jsx
src/pages/ImageTools.jsx
+1
-1
No files found.
src/App.jsx
View file @
f11990d2
...
...
@@ -26,7 +26,7 @@ const SubtitleGenerator = lazy(() => import('./components/SubtitleGenerator'));
const
ImageCompressor
=
lazy
(()
=>
import
(
'./components/ImageCompressor'
));
const
ImageWatermark
=
lazy
(()
=>
import
(
'./components/ImageWatermark'
));
const
TextBehindImage
=
lazy
(()
=>
import
(
'./components/TextBehindImage'
));
const
BackgroundRemover
=
lazy
(()
=>
import
(
'./components/BackgroundRemover'
));
function
App
()
{
return
(
<
div
className=
"app-container"
>
...
...
@@ -57,7 +57,8 @@ function App() {
<
Route
path=
"/subtitle-to-image"
element=
{
<
SubtitleGenerator
/>
}
/>
<
Route
path=
"/image-compressor"
element=
{
<
ImageCompressor
/>
}
/>
<
Route
path=
"/image-watermark"
element=
{
<
ImageWatermark
/>
}
/>
<
Route
path=
"/text-behind-image"
element=
{
<
TextBehindImage
/>
}
/>
<
Route
path=
"/text-behind-image"
element=
{
<
TextBehindImage
/>
}
/>
<
Route
path=
"/background-remover"
element=
{
<
BackgroundRemover
/>
}
/>
<
Route
path=
"*"
element=
{
<
NotFound
/>
}
/>
</
Routes
>
...
...
src/components/BackgroundRemover.jsx
0 → 100644
View file @
f11990d2
import
React
,
{
useState
,
useRef
}
from
'react'
;
import
{
removeBackground
}
from
"@imgly/background-removal"
;
import
styled
from
'styled-components'
;
import
{
useTranslation
}
from
'../js/i18n'
;
import
SEO
from
'./SEO'
;
// Reuse container style
const
Container
=
styled
.
div
`
min-height: 100vh;
background: linear-gradient(135deg, #f5f7ff 0%, #ffffff 100%);
padding: 2rem;
position: relative;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
linear-gradient(90deg, rgba(99, 102, 241, 0.05) 1px, transparent 1px),
linear-gradient(rgba(99, 102, 241, 0.05) 1px, transparent 1px);
background-size: 20px 20px;
pointer-events: none;
}
`
;
const
ContentWrapper
=
styled
.
div
`
display: flex;
gap: 2rem;
max-width: 1400px;
margin: 0 auto;
position: relative;
z-index: 1;
height: calc(100vh - 6rem);
@media (max-width: 768px) {
flex-direction: column;
height: auto;
}
`
;
const
Title
=
styled
.
h2
`
font-size: 1.8rem;
margin-bottom: 1.5rem;
background: linear-gradient(135deg, #6366F1 0%, #4F46E5 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 700;
letter-spacing: -0.02em;
`
;
const
PreviewArea
=
styled
.
div
`
flex: 2;
display: flex;
flex-direction: column;
gap: 1rem;
background: white;
border-radius: 16px;
padding: 1.5rem;
box-shadow: 0 8px 32px rgba(99, 102, 241, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
height: 100%;
overflow: hidden;
position: relative;
.preview-content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
}
.upload-prompt {
color: #666;
font-size: 1.2rem;
}
`
;
const
ControlPanel
=
styled
.
div
`
flex: 1;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 1.5rem;
box-shadow: 0 8px 32px rgba(99, 102, 241, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
flex-direction: column;
gap: 1rem;
`
;
const
ImageUploadArea
=
styled
.
div
`
border: 2px dashed #6366F1;
border-radius: 8px;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background: rgba(99, 102, 241, 0.05);
}
`
;
const
DownloadButton
=
styled
.
button
`
position: absolute;
top: 1.5rem;
right: 1.5rem;
z-index: 10;
background: linear-gradient(135deg, #6366F1 0%, #4F46E5 100%);
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
&:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
`
;
// 添加提示语样式
const
PrivacyNote
=
styled
.
div
`
background: rgba(99, 102, 241, 0.1);
border-left: 4px solid #6366F1;
padding: 1rem;
margin-top: 1rem;
border-radius: 0 8px 8px 0;
color: #4F46E5;
font-size: 0.9rem;
line-height: 1.5;
`
;
function
BackgroundRemover
()
{
const
{
t
}
=
useTranslation
();
const
[
selectedImage
,
setSelectedImage
]
=
useState
(
null
);
const
[
removedBgImage
,
setRemovedBgImage
]
=
useState
(
null
);
const
[
isProcessing
,
setIsProcessing
]
=
useState
(
false
);
const
fileInputRef
=
useRef
(
null
);
const
handleImageUpload
=
async
(
e
)
=>
{
const
file
=
e
.
target
.
files
?.[
0
];
if
(
file
)
{
try
{
setIsProcessing
(
true
);
const
imageUrl
=
URL
.
createObjectURL
(
file
);
setSelectedImage
(
imageUrl
);
// Remove background
const
imageBlob
=
await
removeBackground
(
imageUrl
);
const
removedBgUrl
=
URL
.
createObjectURL
(
imageBlob
);
setRemovedBgImage
(
removedBgUrl
);
}
catch
(
error
)
{
console
.
error
(
'Error processing image:'
,
error
);
}
finally
{
setIsProcessing
(
false
);
}
}
};
const
handleDownload
=
()
=>
{
if
(
removedBgImage
)
{
const
link
=
document
.
createElement
(
'a'
);
link
.
href
=
removedBgImage
;
link
.
download
=
'removed-background.png'
;
document
.
body
.
appendChild
(
link
);
link
.
click
();
document
.
body
.
removeChild
(
link
);
}
};
return
(
<>
<
SEO
title=
{
t
(
'tools.imageBackgroundRemover.title'
)
}
description=
{
t
(
'tools.imageBackgroundRemover.description'
)
}
/>
<
Container
>
<
ContentWrapper
>
<
ControlPanel
>
<
Title
>
{
t
(
'tools.imageBackgroundRemover.title'
)
}
</
Title
>
<
ImageUploadArea
onClick=
{
()
=>
fileInputRef
.
current
.
click
()
}
>
<
input
type=
"file"
ref=
{
fileInputRef
}
style=
{
{
display
:
'none'
}
}
accept=
"image/*"
onChange=
{
handleImageUpload
}
/>
{
t
(
'tools.imageBackgroundRemover.uploadPrompt'
)
}
</
ImageUploadArea
>
{
/* 添加提示语 */
}
<
PrivacyNote
>
{
t
(
'tools.imageBackgroundRemover.privacyNote'
)
}
</
PrivacyNote
>
</
ControlPanel
>
<
PreviewArea
>
{
removedBgImage
&&
(
<
DownloadButton
onClick=
{
handleDownload
}
>
{
t
(
'tools.imageBackgroundRemover.download'
)
}
</
DownloadButton
>
)
}
<
div
className=
"preview-content"
>
{
isProcessing
?
(
<
div
className=
"loading-container"
>
<
span
>
{
t
(
'tools.imageBackgroundRemover.processing'
)
}
</
span
>
</
div
>
)
:
removedBgImage
?
(
<
div
style=
{
{
position
:
'relative'
,
width
:
'100%'
,
height
:
'100%'
,
display
:
'flex'
,
justifyContent
:
'center'
,
alignItems
:
'center'
}
}
>
<
img
src=
{
removedBgImage
}
alt=
"Processed"
style=
{
{
maxWidth
:
'100%'
,
maxHeight
:
'100%'
,
objectFit
:
'contain'
}
}
/>
</
div
>
)
:
(
<
div
className=
"upload-prompt"
>
{
t
(
'tools.imageBackgroundRemover.noImage'
)
}
</
div
>
)
}
</
div
>
</
PreviewArea
>
</
ContentWrapper
>
</
Container
>
</>
);
}
export
default
BackgroundRemover
;
\ No newline at end of file
src/components/ImageWatermark.jsx
View file @
f11990d2
...
...
@@ -150,6 +150,18 @@ const UploadButton = styled.div`
}
`
;
// 添加隐私提示样式
const
PrivacyNote
=
styled
.
div
`
background: rgba(99, 102, 241, 0.1);
border-left: 4px solid #6366F1;
padding: 1rem;
margin-top: 0.5rem;
border-radius: 0 8px 8px 0;
color: #4F46E5;
font-size: 0.9rem;
line-height: 1.5;
`
;
function
ImageWatermark
()
{
const
{
t
}
=
useTranslation
();
const
[
image
,
setImage
]
=
useState
(
null
);
...
...
@@ -347,6 +359,11 @@ function ImageWatermark() {
/>
{
t
(
'tools.imageWatermark.dropOrClick'
)
}
</
UploadButton
>
{
/* 添加隐私提示 */
}
<
PrivacyNote
>
{
t
(
'tools.imageWatermark.privacyNote'
)
}
</
PrivacyNote
>
</
Section
>
<
Section
>
...
...
src/components/SubtitleGenerator.jsx
View file @
f11990d2
...
...
@@ -16,6 +16,8 @@ const SubtitleMaker = () => {
strokeColor
:
'#000000'
});
const
fileInputRef
=
useRef
(
null
);
// 预设的字幕颜色选项 - 只保留最常用的几个
const
presetColors
=
[
{
name
:
t
(
'tools.subtitleGenerator.presetColors.classicYellow'
),
value
:
'#FFE135'
},
...
...
@@ -138,7 +140,15 @@ useEffect(() => {
<
Container
>
<
SettingsPanel
>
<
h3
>
{
t
(
'tools.subtitleGenerator.uploadImage'
)
}
</
h3
>
<
FileInput
type=
"file"
accept=
"image/*"
onChange=
{
handleImageUpload
}
/>
<
UploadButton
onClick=
{
()
=>
fileInputRef
.
current
.
click
()
}
>
<
HiddenFileInput
ref=
{
fileInputRef
}
type=
"file"
accept=
"image/*"
onChange=
{
handleImageUpload
}
/>
{
t
(
'tools.subtitleGenerator.dropOrClick'
)
}
</
UploadButton
>
{
imageSrc
&&
(
<>
...
...
@@ -322,33 +332,25 @@ const PreviewImage = styled.img`
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`
;
const
FileInput
=
styled
.
input
`
width: 100%;
padding: 0.5rem;
border: 1px solid #e5e7eb;
border-radius: 8px;
font-size: 0.9rem;
margin-bottom: 1rem;
const
UploadButton
=
styled
.
div
`
border: 2px dashed rgba(99, 102, 241, 0.2);
border-radius: 12px;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.5);
&::-webkit-file-upload-button {
background: linear-gradient(135deg, #6366F1 0%, #4F46E5 100%);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
margin-right: 1rem;
font-weight: 500;
transition: all 0.3s ease;
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
&:hover {
border-color: rgba(99, 102, 241, 0.4);
background: rgba(99, 102, 241, 0.05);
}
`
;
const
HiddenFileInput
=
styled
.
input
`
display: none;
`
;
const
SettingGroup
=
styled
.
div
`
margin-bottom: 1.5rem;
...
...
src/components/TextBehindImage.jsx
View file @
f11990d2
...
...
@@ -241,6 +241,18 @@ const GroupTitle = styled.h3`
font-weight: 600;
`
;
// 添加隐私提示样式
const
PrivacyNote
=
styled
.
div
`
background: rgba(99, 102, 241, 0.1);
border-left: 4px solid #6366F1;
padding: 1rem;
margin-top: 0.5rem;
border-radius: 0 8px 8px 0;
color: #4F46E5;
font-size: 0.9rem;
line-height: 1.5;
`
;
function
TextBehindImage
()
{
const
{
t
}
=
useTranslation
();
const
[
selectedImage
,
setSelectedImage
]
=
useState
(
null
);
...
...
@@ -465,6 +477,11 @@ function TextBehindImage() {
/>
{
t
(
'tools.textBehindImage.uploadPrompt'
)
}
</
ImageUploadArea
>
{
/* 添加隐私提示 */
}
<
PrivacyNote
>
{
t
(
'tools.textBehindImage.privacyNote'
)
}
</
PrivacyNote
>
</
SettingsGroup
>
{
textSets
.
map
(
textSet
=>
(
...
...
src/locales/en/tools.json
View file @
f11990d2
...
...
@@ -117,6 +117,7 @@
"title"
:
"Subtitle Generator"
,
"description"
:
"Quickly generate multi-line subtitle images with customizable styles"
,
"uploadImage"
:
"Upload Background Image"
,
"dragOrClick"
:
"Drag and drop or click to upload"
,
"removeImage"
:
"Remove Image"
,
"globalSettings"
:
"Global Settings"
,
"fontColor"
:
"Font Color"
,
...
...
@@ -184,11 +185,17 @@
"bottomRight"
:
"Bottom Right"
},
"download"
:
"Download Image"
,
"noImage"
:
"Please upload an image"
"noImage"
:
"Please upload an image"
,
"privacyNote"
:
"This feature runs entirely in your browser with no risk of privacy data leakage. Feel free to use it."
},
"imageBackgroundRemover"
:
{
"title"
:
"Image Background Remover"
,
"description"
:
"Remove image background"
"description"
:
"Remove the background of images"
,
"uploadPrompt"
:
"Click or drag to upload an image"
,
"processing"
:
"Processing..."
,
"noImage"
:
"Please upload an image first"
,
"download"
:
"Download Image"
,
"privacyNote"
:
"This feature runs entirely in your browser with no risk of privacy data leakage. Feel free to use it."
},
"textBehindImage"
:
{
"title"
:
"Text Behind Image"
,
...
...
@@ -208,6 +215,7 @@
"positionY"
:
"Vertical Position"
,
"download"
:
"Download Image"
,
"processing"
:
"Processing..."
,
"noImage"
:
"Please upload an image first"
"noImage"
:
"Please upload an image first"
,
"privacyNote"
:
"This feature runs entirely in your browser with no risk of privacy data leakage. Feel free to use it."
}
}
src/locales/ja/tools.json
View file @
f11990d2
...
...
@@ -117,6 +117,7 @@
"title"
:
"字幕生成ツール"
,
"description"
:
"複数行の字幕画像を素早く生成、スタイルのカスタマイズも可能"
,
"uploadImage"
:
"背景画像をアップロード"
,
"dropOrClick"
:
"ドラッグまたはクリックして画像をアップロード"
,
"removeImage"
:
"画像を削除"
,
"globalSettings"
:
"グローバル設定"
,
"fontColor"
:
"フォントカラー"
,
...
...
@@ -184,11 +185,17 @@
"bottomRight"
:
"右下"
},
"download"
:
"画像をダウンロード"
,
"noImage"
:
"画像をアップロードしてください"
"noImage"
:
"画像をアップロードしてください"
,
"privacyNote"
:
"この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
},
"imageBackgroundRemover"
:
{
"title"
:
"画像背景の削除"
,
"description"
:
"画像の背景を削除"
"title"
:
"画像背景削除"
,
"description"
:
"画像の背景を削除"
,
"uploadPrompt"
:
"クリックまたはドラッグして画像をアップロード"
,
"processing"
:
"処理中..."
,
"noImage"
:
"まず画像をアップロードしてください"
,
"download"
:
"画像をダウンロード"
,
"privacyNote"
:
"この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
},
"textBehindImage"
:
{
"title"
:
"画像の後ろの文字"
,
...
...
@@ -208,6 +215,7 @@
"positionY"
:
"垂直位置"
,
"download"
:
"画像をダウンロード"
,
"processing"
:
"処理中..."
,
"noImage"
:
"最初に画像をアップロードしてください"
"noImage"
:
"最初に画像をアップロードしてください"
,
"privacyNote"
:
"この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
}
}
src/locales/ko/tools.json
View file @
f11990d2
...
...
@@ -118,6 +118,7 @@
"title"
:
"자막 생성기"
,
"description"
:
"여러 줄의 자막 이미지를 빠르게 생성, 스타일 커스터마이징 지원"
,
"uploadImage"
:
"배경 이미지 업로드"
,
"dropOrClick"
:
"드래그하거나 클릭하여 이미지 업로드"
,
"removeImage"
:
"이미지 제거"
,
"globalSettings"
:
"전역 설정"
,
"fontColor"
:
"글자 색상"
,
...
...
@@ -185,11 +186,17 @@
"bottomRight"
:
"오른쪽 아래"
},
"download"
:
"이미지 다운로드"
,
"noImage"
:
"이미지를 업로드하세요"
"noImage"
:
"이미지를 업로드하세요"
,
"privacyNote"
:
"이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
},
"imageBackgroundRemover"
:
{
"title"
:
"이미지 배경 제거"
,
"description"
:
"이미지 배경 제거"
"description"
:
"이미지의 배경을 제거"
,
"uploadPrompt"
:
"클릭 또는 드래그하여 이미지를 업로드하세요"
,
"processing"
:
"처리 중..."
,
"noImage"
:
"먼저 이미지를 업로드하세요"
,
"download"
:
"이미지 다운로드"
,
"privacyNote"
:
"이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
},
"textBehindImage"
:
{
"title"
:
"이미지 뒤의 텍스트"
,
...
...
@@ -209,6 +216,7 @@
"positionY"
:
"수직 위치"
,
"download"
:
"이미지 다운로드"
,
"processing"
:
"처리 중..."
,
"noImage"
:
"먼저 이미지를 업로드하세요"
"noImage"
:
"먼저 이미지를 업로드하세요"
,
"privacyNote"
:
"이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
}
}
src/locales/zh/tools.json
View file @
f11990d2
...
...
@@ -116,6 +116,7 @@
"title"
:
"字幕拼接"
,
"description"
:
"快速生成多行字幕图片,支持自定义样式"
,
"uploadImage"
:
"上传背景图片"
,
"dropOrClick"
:
"拖拽或点击上传图片"
,
"removeImage"
:
"移除图片"
,
"globalSettings"
:
"全局设置"
,
"fontColor"
:
"字体颜色"
,
...
...
@@ -183,11 +184,17 @@
"bottomRight"
:
"右下角"
},
"download"
:
"下载图片"
,
"noImage"
:
"请上传图片"
"noImage"
:
"请上传图片"
,
"privacyNote"
:
"本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
},
"imageBackgroundRemover"
:
{
"title"
:
"图片背景去除"
,
"description"
:
"去除图片背景"
"description"
:
"去除图片背景"
,
"uploadPrompt"
:
"点击或拖拽上传图片"
,
"processing"
:
"正在处理..."
,
"noImage"
:
"请先上传图片"
,
"download"
:
"下载图片"
,
"privacyNote"
:
"本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
},
"textBehindImage"
:
{
"title"
:
"文字穿越图片"
,
...
...
@@ -207,6 +214,7 @@
"positionY"
:
"垂直位置"
,
"download"
:
"下载图片"
,
"processing"
:
"正在处理..."
,
"noImage"
:
"请先上传图片"
"noImage"
:
"请先上传图片"
,
"privacyNote"
:
"本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
}
}
src/pages/Home.jsx
View file @
f11990d2
...
...
@@ -10,7 +10,7 @@ const tools = [
{
id
:
'subtitleGenerator'
,
icon
:
'/assets/icon/subtitle2image.png'
,
path
:
'/subtitle-to-image'
},
{
id
:
'imageCompressor'
,
icon
:
'/assets/icon/image-compressor.png'
,
path
:
'/image-compressor'
},
{
id
:
'imageWatermark'
,
icon
:
'/assets/icon/image-watermark.png'
,
path
:
'/image-watermark'
},
{
id
:
'imageBackgroundRemover'
,
icon
:
'/assets/icon/image-background-remover.png'
,
path
:
'
https://huggingface.co/spaces/briaai/BRIA-RMBG-2.0'
,
external
:
true
},
{
id
:
'imageBackgroundRemover'
,
icon
:
'/assets/icon/image-background-remover.png'
,
path
:
'
/background-remover'
},
{
id
:
'textBehindImage'
,
icon
:
'/assets/icon/text-behind-image.png'
,
path
:
'/text-behind-image'
},
{
id
:
'latex2image'
,
icon
:
'/assets/icon/latex2image.png'
,
path
:
'/latex-to-image'
},
...
...
src/pages/ImageTools.jsx
View file @
f11990d2
...
...
@@ -11,7 +11,7 @@ const tools = [
{
id
:
'subtitleGenerator'
,
icon
:
'/assets/icon/subtitle2image.png'
,
path
:
'/subtitle-to-image'
},
{
id
:
'imageCompressor'
,
icon
:
'/assets/icon/image-compressor.png'
,
path
:
'/image-compressor'
},
{
id
:
'imageWatermark'
,
icon
:
'/assets/icon/image-watermark.png'
,
path
:
'/image-watermark'
},
{
id
:
'imageBackgroundRemover'
,
icon
:
'/assets/icon/image-background-remover.png'
,
path
:
'
https://huggingface.co/spaces/briaai/BRIA-RMBG-2.0'
,
external
:
true
},
{
id
:
'imageBackgroundRemover'
,
icon
:
'/assets/icon/image-background-remover.png'
,
path
:
'
/background-remover'
},
{
id
:
'textBehindImage'
,
icon
:
'/assets/icon/text-behind-image.png'
,
path
:
'/text-behind-image'
},
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment