remove background

This commit is contained in:
hamid zarghami
2025-08-03 16:27:40 +03:30
parent 2b19dc5a71
commit 2059a601aa
4 changed files with 118 additions and 10 deletions
+5 -1
View File
@@ -17,7 +17,8 @@ type Props = {
isReset?: boolean,
useUploadService?: boolean,
onUploadComplete?: (urls: string[]) => void,
onUploadError?: (error: Error) => void
onUploadError?: (error: Error) => void,
onDelete?: () => void
}
const UploadBoxDraggble: FC<Props> = (props: Props) => {
@@ -100,6 +101,9 @@ const UploadBoxDraggble: FC<Props> = (props: Props) => {
if (props.onChangePreview) {
props.onChangePreview(array);
}
if (props.onDelete) {
props.onDelete()
}
}
useEffect(() => {
+3 -7
View File
@@ -112,12 +112,8 @@ const Setting: FC = () => {
const screenshotFile = await capturePersonalityScreenshot(templateName)
setIsCapturingScreenshot(false)
if (!screenshotFile) {
toast('خطا در گرفتن اسکرین‌شات', 'error')
return
}
const thumbnailUrl = await singleUpload(screenshotFile)
const thumbnailUrl = screenshotFile ? await singleUpload(screenshotFile) : undefined
if (isEditMode) {
updateTemplate({
@@ -126,7 +122,7 @@ const Setting: FC = () => {
name: templateName,
rawHtml: html,
structure: data,
thumbnailUrl: thumbnailUrl?.data?.url
thumbnailUrl: thumbnailUrl?.data?.url || undefined
}
}, {
onSuccess: (data) => {
@@ -141,7 +137,7 @@ const Setting: FC = () => {
name: templateName,
rawHtml: html,
structure: data,
thumbnailUrl: thumbnailUrl?.data?.url
thumbnailUrl: thumbnailUrl?.data?.url || undefined
}, {
onSuccess: (data) => {
toast(data?.data?.message || 'قالب با موفقیت ایجاد شد', 'success')
@@ -160,6 +160,8 @@ const SettingSideBar: FC = () => {
</div>
)
}
console.log(data[activeSection]);
return (
<div>
@@ -211,6 +213,12 @@ const SettingSideBar: FC = () => {
<UploadBoxDraggble
label={isUploading ? 'در حال آپلود...' : t('setting.upload_background')}
onChange={handleUploadBackground}
preview={data?.[activeSection]?.items?.[0]?.backgroundImage ? [data?.[activeSection]?.items?.[0]?.backgroundImage] : undefined}
onDelete={() => {
updateActiveItem({
backgroundImage: undefined
})
}}
/>
</div>
@@ -1,5 +1,59 @@
import domtoimage from "dom-to-image";
/**
* تبدیل تصاویر خارجی به data URL برای حل مشکل CORS
*/
const convertImagesToDataUrl = async (element: HTMLElement): Promise<void> => {
const images = element.querySelectorAll("img");
const promises = Array.from(images).map(async (img) => {
try {
// فقط تصاویر خارجی را پردازش کن
if (
!img.src.startsWith(window.location.origin) &&
!img.src.startsWith("data:")
) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
// ایجاد image جدید با crossOrigin
const tempImg = new Image();
tempImg.crossOrigin = "anonymous";
await new Promise((resolve, reject) => {
tempImg.onload = () => {
canvas.width = tempImg.width;
canvas.height = tempImg.height;
ctx.drawImage(tempImg, 0, 0);
try {
const dataUrl = canvas.toDataURL("image/png");
img.src = dataUrl;
resolve(void 0);
} catch (error) {
// اگر نتوانست تبدیل کند، URL اصلی را حفظ کن
console.warn("نمی‌توان تصویر را تبدیل کرد:", img.src, error);
resolve(void 0);
}
};
tempImg.onerror = () => {
console.warn("نمی‌توان تصویر را بارگذاری کرد:", img.src);
resolve(void 0);
};
tempImg.src = img.src;
});
}
}
} catch (error) {
console.warn("خطا در تبدیل تصویر:", img.src, error);
}
});
await Promise.allSettled(promises);
};
/**
* گرفتن اسکرین‌شات با dom-to-image و برگرداندن فایل برای آپلود
*/
@@ -23,8 +77,12 @@ export const captureScreenshotAsFile = async (
htmlElement.style.transform = "scale(1)";
htmlElement.style.position = "relative";
// تبدیل تصاویر خارجی به data URL
console.log("🔄 Converting external images to data URLs...");
await convertImagesToDataUrl(htmlElement);
// صبر برای render کامل
await new Promise((resolve) => setTimeout(resolve, 1000));
await new Promise((resolve) => setTimeout(resolve, 1500));
const options = {
quality: 1,
@@ -35,9 +93,51 @@ export const captureScreenshotAsFile = async (
transform: "scale(1)",
transformOrigin: "top left",
},
// تنظیمات CORS برای تصاویر خارجی
filter: (node: Node) => {
// اگر node یک img element است، crossOrigin را چک کن
if (node.nodeName === "IMG") {
const img = node as HTMLImageElement;
// تنظیم crossOrigin برای تصاویر که از دامین خارجی هستند
if (img.src && !img.src.startsWith(window.location.origin)) {
img.crossOrigin = "anonymous";
}
}
return true;
},
// امکان استفاده از تصاویر که CORS ندارند
allowTaint: true,
useCORS: true,
};
const dataUrl = await domtoimage.toPng(element, options);
let dataUrl: string;
try {
console.log("📸 Attempting screenshot with enhanced options...");
dataUrl = await domtoimage.toPng(element, options);
} catch (error) {
console.warn("⚠️ Enhanced method failed, trying fallback...", error);
// Fallback: استفاده از تنظیمات ساده‌تر
const fallbackOptions = {
quality: 0.8,
bgcolor: "#ffffff",
width: element.offsetWidth,
height: element.offsetHeight,
// حذف filter و تنظیمات پیچیده
imagePlaceholder:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
};
try {
dataUrl = await domtoimage.toPng(element, fallbackOptions);
console.log("✅ Fallback method succeeded");
} catch (fallbackError) {
console.error("❌ Both methods failed:", fallbackError);
throw fallbackError;
}
}
// بازگردانی استایل‌های اصلی
htmlElement.style.transform = originalTransform;
htmlElement.style.position = originalPosition;