feat: edit image

This commit is contained in:
Ibrahima G. Coulibaly
2025-07-09 04:34:43 +01:00
parent 1250c8f4c3
commit 90e0389156
7 changed files with 522 additions and 63 deletions

View File

@@ -0,0 +1,127 @@
import React, { useCallback, useState } from 'react';
import { Box } from '@mui/material';
import ToolImageInput from '@components/input/ToolImageInput';
import ToolContent from '@components/ToolContent';
import { ToolComponentProps } from '@tools/defineTool';
// Import the image editor with proper typing
import FilerobotImageEditor, {
FilerobotImageEditorConfig
} from 'react-filerobot-image-editor';
export default function ImageEditor({ title }: ToolComponentProps) {
const [input, setInput] = useState<File | null>(null);
const [isEditorOpen, setIsEditorOpen] = useState(false);
const [imageUrl, setImageUrl] = useState<string | null>(null);
// Handle file input change
const handleInputChange = useCallback((file: File | null) => {
setInput(file);
if (file) {
// Create object URL for the image editor
const url = URL.createObjectURL(file);
setImageUrl(url);
setIsEditorOpen(true);
} else {
setImageUrl(null);
}
}, []);
const onCloseEditor = (reason: string) => {
if (reason === 'close-button-clicked') {
setIsEditorOpen(false);
setImageUrl(null);
}
};
// Handle save from image editor
const handleSave: FilerobotImageEditorConfig['onSave'] = (
editedImageObject,
designState
) => {
console.log('Image saved:', editedImageObject, designState);
if (editedImageObject && editedImageObject.imageBase64) {
// Convert base64 to blob
const base64Data = editedImageObject.imageBase64.split(',')[1];
const byteCharacters = atob(base64Data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: editedImageObject.mimeType });
const editedFile = new File(
[blob],
editedImageObject.fullName ?? 'edited.png',
{
type: editedImageObject.mimeType
}
);
// Create a temporary download link
const url = URL.createObjectURL(editedFile);
const a = document.createElement('a');
a.href = url;
a.download = editedFile.name; // This will be the name of the downloaded file
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// Release the blob URL
URL.revokeObjectURL(url);
}
};
const getDefaultImageName = () => {
if (!input) return;
const originalName = input?.name || 'edited-image';
const nameWithoutExt = originalName.replace(/\.[^/.]+$/, '');
const editedFileName = `${nameWithoutExt}-edited`;
return editedFileName;
};
return (
<ToolContent
title={title}
initialValues={{}}
getGroups={null}
input={input}
inputComponent={
isEditorOpen ? (
imageUrl && (
<Box style={{ width: '100%', height: '70vh' }}>
<FilerobotImageEditor
source={imageUrl}
onSave={handleSave}
onClose={onCloseEditor}
annotationsCommon={{
fill: 'blue'
}}
defaultSavedImageName={getDefaultImageName()}
Rotate={{ angle: 90, componentType: 'slider' }}
savingPixelRatio={1}
previewPixelRatio={1}
/>
</Box>
)
) : (
<ToolImageInput
value={input}
onChange={handleInputChange}
accept={['image/*']}
title="Upload Image to Edit"
/>
)
}
toolInfo={{
title: 'Image Editor',
description:
'A powerful image editing tool that provides professional-grade features including cropping, rotating, color adjustments, text annotations, drawing tools, and watermarking. Edit your images directly in your browser without the need for external software.'
}}
compute={() => {}}
/>
);
}

View File

@@ -0,0 +1,28 @@
import { defineTool } from '@tools/defineTool';
import { lazy } from 'react';
export const tool = defineTool('image-generic', {
name: 'Image Editor',
path: 'editor',
icon: 'mdi:image-edit',
description:
'Advanced image editor with tools for cropping, rotating, annotating, adjusting colors, and adding watermarks. Edit your images with professional-grade tools directly in your browser.',
shortDescription: 'Edit images with advanced tools and features',
keywords: [
'image',
'editor',
'edit',
'crop',
'rotate',
'annotate',
'adjust',
'watermark',
'text',
'drawing',
'filters',
'brightness',
'contrast',
'saturation'
],
component: lazy(() => import('./index'))
});

View File

@@ -9,7 +9,9 @@ import { tool as imageToText } from './image-to-text/meta';
import { tool as qrCodeGenerator } from './qr-code/meta';
import { tool as rotateImage } from './rotate/meta';
import { tool as convertToJpg } from './convert-to-jpg/meta';
import { tool as imageEditor } from './editor/meta';
export const imageGenericTools = [
imageEditor,
resizeImage,
compressImage,
removeBackground,