Commit f11990d2 authored by fisherdaddy's avatar fisherdaddy

feature: 新增图像背景移除工具

parent 3db13667
...@@ -26,7 +26,7 @@ const SubtitleGenerator = lazy(() => import('./components/SubtitleGenerator')); ...@@ -26,7 +26,7 @@ const SubtitleGenerator = lazy(() => import('./components/SubtitleGenerator'));
const ImageCompressor = lazy(() => import('./components/ImageCompressor')); const ImageCompressor = lazy(() => import('./components/ImageCompressor'));
const ImageWatermark = lazy(() => import('./components/ImageWatermark')); const ImageWatermark = lazy(() => import('./components/ImageWatermark'));
const TextBehindImage = lazy(() => import('./components/TextBehindImage')); const TextBehindImage = lazy(() => import('./components/TextBehindImage'));
const BackgroundRemover = lazy(() => import('./components/BackgroundRemover'));
function App() { function App() {
return ( return (
<div className="app-container"> <div className="app-container">
...@@ -57,7 +57,8 @@ function App() { ...@@ -57,7 +57,8 @@ function App() {
<Route path="/subtitle-to-image" element={<SubtitleGenerator />} /> <Route path="/subtitle-to-image" element={<SubtitleGenerator />} />
<Route path="/image-compressor" element={<ImageCompressor />} /> <Route path="/image-compressor" element={<ImageCompressor />} />
<Route path="/image-watermark" element={<ImageWatermark />} /> <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 />} /> <Route path="*" element={<NotFound />} />
</Routes> </Routes>
......
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
...@@ -150,6 +150,18 @@ const UploadButton = styled.div` ...@@ -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() { function ImageWatermark() {
const { t } = useTranslation(); const { t } = useTranslation();
const [image, setImage] = useState(null); const [image, setImage] = useState(null);
...@@ -347,6 +359,11 @@ function ImageWatermark() { ...@@ -347,6 +359,11 @@ function ImageWatermark() {
/> />
{t('tools.imageWatermark.dropOrClick')} {t('tools.imageWatermark.dropOrClick')}
</UploadButton> </UploadButton>
{/* 添加隐私提示 */}
<PrivacyNote>
{t('tools.imageWatermark.privacyNote')}
</PrivacyNote>
</Section> </Section>
<Section> <Section>
......
...@@ -16,6 +16,8 @@ const SubtitleMaker = () => { ...@@ -16,6 +16,8 @@ const SubtitleMaker = () => {
strokeColor: '#000000' strokeColor: '#000000'
}); });
const fileInputRef = useRef(null);
// 预设的字幕颜色选项 - 只保留最常用的几个 // 预设的字幕颜色选项 - 只保留最常用的几个
const presetColors = [ const presetColors = [
{ name: t('tools.subtitleGenerator.presetColors.classicYellow'), value: '#FFE135' }, { name: t('tools.subtitleGenerator.presetColors.classicYellow'), value: '#FFE135' },
...@@ -138,7 +140,15 @@ useEffect(() => { ...@@ -138,7 +140,15 @@ useEffect(() => {
<Container> <Container>
<SettingsPanel> <SettingsPanel>
<h3>{t('tools.subtitleGenerator.uploadImage')}</h3> <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 && ( {imageSrc && (
<> <>
...@@ -322,33 +332,25 @@ const PreviewImage = styled.img` ...@@ -322,33 +332,25 @@ const PreviewImage = styled.img`
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`; `;
const FileInput = styled.input` const UploadButton = styled.div`
width: 100%; border: 2px dashed rgba(99, 102, 241, 0.2);
padding: 0.5rem; border-radius: 12px;
border: 1px solid #e5e7eb; padding: 2rem;
border-radius: 8px; text-align: center;
font-size: 0.9rem;
margin-bottom: 1rem;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.5);
&::-webkit-file-upload-button { &:hover {
background: linear-gradient(135deg, #6366F1 0%, #4F46E5 100%); border-color: rgba(99, 102, 241, 0.4);
color: white; background: rgba(99, 102, 241, 0.05);
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);
}
} }
`; `;
const HiddenFileInput = styled.input`
display: none;
`;
const SettingGroup = styled.div` const SettingGroup = styled.div`
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
......
...@@ -241,6 +241,18 @@ const GroupTitle = styled.h3` ...@@ -241,6 +241,18 @@ const GroupTitle = styled.h3`
font-weight: 600; 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() { function TextBehindImage() {
const { t } = useTranslation(); const { t } = useTranslation();
const [selectedImage, setSelectedImage] = useState(null); const [selectedImage, setSelectedImage] = useState(null);
...@@ -465,6 +477,11 @@ function TextBehindImage() { ...@@ -465,6 +477,11 @@ function TextBehindImage() {
/> />
{t('tools.textBehindImage.uploadPrompt')} {t('tools.textBehindImage.uploadPrompt')}
</ImageUploadArea> </ImageUploadArea>
{/* 添加隐私提示 */}
<PrivacyNote>
{t('tools.textBehindImage.privacyNote')}
</PrivacyNote>
</SettingsGroup> </SettingsGroup>
{textSets.map(textSet => ( {textSets.map(textSet => (
......
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
"title": "Subtitle Generator", "title": "Subtitle Generator",
"description": "Quickly generate multi-line subtitle images with customizable styles", "description": "Quickly generate multi-line subtitle images with customizable styles",
"uploadImage": "Upload Background Image", "uploadImage": "Upload Background Image",
"dragOrClick": "Drag and drop or click to upload",
"removeImage": "Remove Image", "removeImage": "Remove Image",
"globalSettings": "Global Settings", "globalSettings": "Global Settings",
"fontColor": "Font Color", "fontColor": "Font Color",
...@@ -184,11 +185,17 @@ ...@@ -184,11 +185,17 @@
"bottomRight": "Bottom Right" "bottomRight": "Bottom Right"
}, },
"download": "Download Image", "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": { "imageBackgroundRemover": {
"title": "Image Background Remover", "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": { "textBehindImage": {
"title": "Text Behind Image", "title": "Text Behind Image",
...@@ -208,6 +215,7 @@ ...@@ -208,6 +215,7 @@
"positionY": "Vertical Position", "positionY": "Vertical Position",
"download": "Download Image", "download": "Download Image",
"processing": "Processing...", "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."
} }
} }
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
"title": "字幕生成ツール", "title": "字幕生成ツール",
"description": "複数行の字幕画像を素早く生成、スタイルのカスタマイズも可能", "description": "複数行の字幕画像を素早く生成、スタイルのカスタマイズも可能",
"uploadImage": "背景画像をアップロード", "uploadImage": "背景画像をアップロード",
"dropOrClick": "ドラッグまたはクリックして画像をアップロード",
"removeImage": "画像を削除", "removeImage": "画像を削除",
"globalSettings": "グローバル設定", "globalSettings": "グローバル設定",
"fontColor": "フォントカラー", "fontColor": "フォントカラー",
...@@ -184,11 +185,17 @@ ...@@ -184,11 +185,17 @@
"bottomRight": "右下" "bottomRight": "右下"
}, },
"download": "画像をダウンロード", "download": "画像をダウンロード",
"noImage": "画像をアップロードしてください" "noImage": "画像をアップロードしてください",
"privacyNote": "この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
}, },
"imageBackgroundRemover": { "imageBackgroundRemover": {
"title": "画像背景の削除", "title": "画像背景削除",
"description": "画像の背景を削除" "description": "画像の背景を削除",
"uploadPrompt": "クリックまたはドラッグして画像をアップロード",
"processing": "処理中...",
"noImage": "まず画像をアップロードしてください",
"download": "画像をダウンロード",
"privacyNote": "この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
}, },
"textBehindImage": { "textBehindImage": {
"title": "画像の後ろの文字", "title": "画像の後ろの文字",
...@@ -208,6 +215,7 @@ ...@@ -208,6 +215,7 @@
"positionY": "垂直位置", "positionY": "垂直位置",
"download": "画像をダウンロード", "download": "画像をダウンロード",
"processing": "処理中...", "processing": "処理中...",
"noImage": "最初に画像をアップロードしてください" "noImage": "最初に画像をアップロードしてください",
"privacyNote": "この機能は完全にブラウザ内で実行され、プライバシーの漏洩リスクはありません。安心してご利用ください。"
} }
} }
...@@ -118,6 +118,7 @@ ...@@ -118,6 +118,7 @@
"title": "자막 생성기", "title": "자막 생성기",
"description": "여러 줄의 자막 이미지를 빠르게 생성, 스타일 커스터마이징 지원", "description": "여러 줄의 자막 이미지를 빠르게 생성, 스타일 커스터마이징 지원",
"uploadImage": "배경 이미지 업로드", "uploadImage": "배경 이미지 업로드",
"dropOrClick": "드래그하거나 클릭하여 이미지 업로드",
"removeImage": "이미지 제거", "removeImage": "이미지 제거",
"globalSettings": "전역 설정", "globalSettings": "전역 설정",
"fontColor": "글자 색상", "fontColor": "글자 색상",
...@@ -185,11 +186,17 @@ ...@@ -185,11 +186,17 @@
"bottomRight": "오른쪽 아래" "bottomRight": "오른쪽 아래"
}, },
"download": "이미지 다운로드", "download": "이미지 다운로드",
"noImage": "이미지를 업로드하세요" "noImage": "이미지를 업로드하세요",
"privacyNote": "이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
}, },
"imageBackgroundRemover": { "imageBackgroundRemover": {
"title": "이미지 배경 제거", "title": "이미지 배경 제거",
"description": "이미지 배경 제거" "description": "이미지의 배경을 제거",
"uploadPrompt": "클릭 또는 드래그하여 이미지를 업로드하세요",
"processing": "처리 중...",
"noImage": "먼저 이미지를 업로드하세요",
"download": "이미지 다운로드",
"privacyNote": "이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
}, },
"textBehindImage": { "textBehindImage": {
"title": "이미지 뒤의 텍스트", "title": "이미지 뒤의 텍스트",
...@@ -209,6 +216,7 @@ ...@@ -209,6 +216,7 @@
"positionY": "수직 위치", "positionY": "수직 위치",
"download": "이미지 다운로드", "download": "이미지 다운로드",
"processing": "처리 중...", "processing": "처리 중...",
"noImage": "먼저 이미지를 업로드하세요" "noImage": "먼저 이미지를 업로드하세요",
"privacyNote": "이 기능은 완전히 브라우저 내에서 실행되며, 개인정보 유출 위험이 없습니다. 안심하고 사용하세요."
} }
} }
...@@ -116,6 +116,7 @@ ...@@ -116,6 +116,7 @@
"title": "字幕拼接", "title": "字幕拼接",
"description": "快速生成多行字幕图片,支持自定义样式", "description": "快速生成多行字幕图片,支持自定义样式",
"uploadImage": "上传背景图片", "uploadImage": "上传背景图片",
"dropOrClick": "拖拽或点击上传图片",
"removeImage": "移除图片", "removeImage": "移除图片",
"globalSettings": "全局设置", "globalSettings": "全局设置",
"fontColor": "字体颜色", "fontColor": "字体颜色",
...@@ -183,11 +184,17 @@ ...@@ -183,11 +184,17 @@
"bottomRight": "右下角" "bottomRight": "右下角"
}, },
"download": "下载图片", "download": "下载图片",
"noImage": "请上传图片" "noImage": "请上传图片",
"privacyNote": "本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
}, },
"imageBackgroundRemover": { "imageBackgroundRemover": {
"title": "图片背景去除", "title": "图片背景去除",
"description": "去除图片背景" "description": "去除图片背景",
"uploadPrompt": "点击或拖拽上传图片",
"processing": "正在处理...",
"noImage": "请先上传图片",
"download": "下载图片",
"privacyNote": "本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
}, },
"textBehindImage": { "textBehindImage": {
"title": "文字穿越图片", "title": "文字穿越图片",
...@@ -207,6 +214,7 @@ ...@@ -207,6 +214,7 @@
"positionY": "垂直位置", "positionY": "垂直位置",
"download": "下载图片", "download": "下载图片",
"processing": "正在处理...", "processing": "正在处理...",
"noImage": "请先上传图片" "noImage": "请先上传图片",
"privacyNote": "本功能完全在浏览器本地执行,无隐私数据泄露风险,请放心使用。"
} }
} }
...@@ -10,7 +10,7 @@ const tools = [ ...@@ -10,7 +10,7 @@ const tools = [
{ id: 'subtitleGenerator', icon: '/assets/icon/subtitle2image.png', path: '/subtitle-to-image' }, { id: 'subtitleGenerator', icon: '/assets/icon/subtitle2image.png', path: '/subtitle-to-image' },
{ id: 'imageCompressor', icon: '/assets/icon/image-compressor.png', path: '/image-compressor' }, { id: 'imageCompressor', icon: '/assets/icon/image-compressor.png', path: '/image-compressor' },
{ id: 'imageWatermark', icon: '/assets/icon/image-watermark.png', path: '/image-watermark' }, { 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: 'textBehindImage', icon: '/assets/icon/text-behind-image.png', path: '/text-behind-image' },
{ id: 'latex2image', icon: '/assets/icon/latex2image.png', path: '/latex-to-image' }, { id: 'latex2image', icon: '/assets/icon/latex2image.png', path: '/latex-to-image' },
......
...@@ -11,7 +11,7 @@ const tools = [ ...@@ -11,7 +11,7 @@ const tools = [
{ id: 'subtitleGenerator', icon: '/assets/icon/subtitle2image.png', path: '/subtitle-to-image' }, { id: 'subtitleGenerator', icon: '/assets/icon/subtitle2image.png', path: '/subtitle-to-image' },
{ id: 'imageCompressor', icon: '/assets/icon/image-compressor.png', path: '/image-compressor' }, { id: 'imageCompressor', icon: '/assets/icon/image-compressor.png', path: '/image-compressor' },
{ id: 'imageWatermark', icon: '/assets/icon/image-watermark.png', path: '/image-watermark' }, { 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: 'textBehindImage', icon: '/assets/icon/text-behind-image.png', path: '/text-behind-image' },
]; ];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment