chatnimbus / image-editor.html
RED243's picture
une application quinperme de cree des image ou la modifie
7e43775 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Editor - ChatNimbus</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fabric@5.3.1/dist/fabric.min.js"></script>
<style>
#canvas-container {
width: 100%;
height: 70vh;
border: 2px dashed #ccc;
position: relative;
}
.tool-btn {
transition: all 0.2s;
}
.tool-btn:hover {
transform: scale(1.1);
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-800">Image Editor</h1>
<a href="index.html" class="flex items-center text-blue-500 hover:text-blue-700">
<i data-feather="arrow-left" class="mr-1"></i> Back to Chat
</a>
</div>
<div class="bg-white rounded-lg shadow-md p-6">
<div class="flex flex-col md:flex-row gap-6">
<!-- Tools Panel -->
<div class="w-full md:w-1/4 bg-gray-50 p-4 rounded-lg">
<div class="mb-6">
<h2 class="text-lg font-semibold mb-3">Upload Image</h2>
<input type="file" id="image-upload" accept="image/*" class="hidden">
<button onclick="document.getElementById('image-upload').click()" class="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 flex items-center justify-center">
<i data-feather="upload" class="mr-2"></i> Choose File
</button>
</div>
<div class="mb-6">
<h2 class="text-lg font-semibold mb-3">Drawing Tools</h2>
<div class="grid grid-cols-3 gap-2">
<button id="draw-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Draw">
<i data-feather="edit-3"></i>
</button>
<button id="text-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Add Text">
<i data-feather="type"></i>
</button>
<button id="shape-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Add Shape">
<i data-feather="square"></i>
</button>
<button id="eraser-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Eraser">
<i data-feather="x"></i>
</button>
<button id="crop-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Crop">
<i data-feather="crop"></i>
</button>
<button id="clear-btn" class="tool-btn bg-gray-200 p-2 rounded-lg" title="Clear All">
<i data-feather="trash-2"></i>
</button>
</div>
</div>
<div class="mb-6">
<h2 class="text-lg font-semibold mb-3">Filters</h2>
<select id="filter-select" class="w-full p-2 border rounded-lg">
<option value="none">No Filter</option>
<option value="grayscale">Grayscale</option>
<option value="sepia">Sepia</option>
<option value="invert">Invert</option>
<option value="blur">Blur</option>
</select>
</div>
<div class="mb-6">
<h2 class="text-lg font-semibold mb-3">Text Options</h2>
<input type="text" id="text-input" placeholder="Enter text" class="w-full p-2 border rounded-lg mb-2">
<div class="flex justify-between">
<input type="color" id="text-color" value="#000000" class="w-8 h-8">
<select id="font-select" class="w-3/4 p-1 border rounded-lg">
<option value="Arial">Arial</option>
<option value="Times New Roman">Times New Roman</option>
<option value="Courier New">Courier New</option>
<option value="Georgia">Georgia</option>
</select>
</div>
</div>
<div class="mb-6">
<h2 class="text-lg font-semibold mb-3">Brush Options</h2>
<div class="flex items-center mb-2">
<span class="mr-2">Size:</span>
<input type="range" id="brush-size" min="1" max="50" value="5" class="flex-1">
</div>
<div class="flex items-center">
<span class="mr-2">Color:</span>
<input type="color" id="brush-color" value="#000000" class="w-8 h-8">
</div>
</div>
<div>
<button id="save-btn" class="w-full bg-green-500 text-white py-2 px-4 rounded-lg hover:bg-green-600 flex items-center justify-center">
<i data-feather="save" class="mr-2"></i> Save Image
</button>
</div>
</div>
<!-- Canvas Area -->
<div class="w-full md:w-3/4">
<div id="canvas-container">
<canvas id="canvas"></canvas>
</div>
<div class="mt-4 flex justify-center gap-4">
<button id="undo-btn" class="bg-gray-200 py-2 px-4 rounded-lg hover:bg-gray-300 flex items-center">
<i data-feather="rotate-ccw" class="mr-2"></i> Undo
</button>
<button id="redo-btn" class="bg-gray-200 py-2 px-4 rounded-lg hover:bg-gray-300 flex items-center">
<i data-feather="rotate-cw" class="mr-2"></i> Redo
</button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
// Initialize Fabric.js canvas
const canvas = new fabric.Canvas('canvas', {
width: document.getElementById('canvas-container').offsetWidth - 4,
height: document.getElementById('canvas-container').offsetHeight - 4,
backgroundColor: '#ffffff'
});
// Upload image
document.getElementById('image-upload').addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(event) {
fabric.Image.fromURL(event.target.result, function(img) {
canvas.clear();
canvas.add(img);
canvas.renderAll();
});
};
reader.readAsDataURL(file);
});
// Drawing tools
document.getElementById('draw-btn').addEventListener('click', function() {
canvas.isDrawingMode = true;
});
document.getElementById('text-btn').addEventListener('click', function() {
const text = new fabric.IText('Double click to edit', {
left: 100,
top: 100,
fontFamily: document.getElementById('font-select').value,
fill: document.getElementById('text-color').value
});
canvas.add(text);
canvas.setActiveObject(text);
canvas.renderAll();
});
document.getElementById('shape-btn').addEventListener('click', function() {
const rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'transparent',
stroke: document.getElementById('brush-color').value,
strokeWidth: document.getElementById('brush-size').value,
width: 200,
height: 100
});
canvas.add(rect);
canvas.renderAll();
});
document.getElementById('eraser-btn').addEventListener('click', function() {
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = '#ffffff';
});
document.getElementById('clear-btn').addEventListener('click', function() {
if (confirm('Are you sure you want to clear the canvas?')) {
canvas.clear();
}
});
// Brush settings
document.getElementById('brush-size').addEventListener('input', function() {
canvas.freeDrawingBrush.width = parseInt(this.value);
});
document.getElementById('brush-color').addEventListener('input', function() {
canvas.freeDrawingBrush.color = this.value;
});
// Text settings
document.getElementById('text-color').addEventListener('input', function() {
const activeObject = canvas.getActiveObject();
if (activeObject && activeObject.type === 'i-text') {
activeObject.set('fill', this.value);
canvas.renderAll();
}
});
document.getElementById('font-select').addEventListener('change', function() {
const activeObject = canvas.getActiveObject();
if (activeObject && activeObject.type === 'i-text') {
activeObject.set('fontFamily', this.value);
canvas.renderAll();
}
});
// Filters
document.getElementById('filter-select').addEventListener('change', function() {
const objects = canvas.getObjects();
objects.forEach(obj => {
if (obj.type === 'image') {
obj.filters = [];
switch(this.value) {
case 'grayscale':
obj.filters.push(new fabric.Image.filters.Grayscale());
break;
case 'sepia':
obj.filters.push(new fabric.Image.filters.Sepia());
break;
case 'invert':
obj.filters.push(new fabric.Image.filters.Invert());
break;
case 'blur':
obj.filters.push(new fabric.Image.filters.Blur({
blur: 0.2
}));
break;
}
obj.applyFilters();
canvas.renderAll();
}
});
});
// Save image
document.getElementById('save-btn').addEventListener('click', function() {
const link = document.createElement('a');
link.download = 'edited-image.png';
link.href = canvas.toDataURL({
format: 'png',
quality: 1
});
link.click();
});
// Undo/Redo
const history = [];
let historyIndex = -1;
canvas.on('object:modified', saveState);
canvas.on('object:added', saveState);
function saveState() {
if (historyIndex < history.length - 1) {
history.splice(historyIndex + 1);
}
history.push(JSON.stringify(canvas));
historyIndex = history.length - 1;
}
document.getElementById('undo-btn').addEventListener('click', function() {
if (historyIndex <= 0) return;
historyIndex--;
canvas.loadFromJSON(history[historyIndex], function() {
canvas.renderAll();
});
});
document.getElementById('redo-btn').addEventListener('click', function() {
if (historyIndex >= history.length - 1) return;
historyIndex++;
canvas.loadFromJSON(history[historyIndex], function() {
canvas.renderAll();
});
});
// Window resize
window.addEventListener('resize', function() {
canvas.setWidth(document.getElementById('canvas-container').offsetWidth - 4);
canvas.setHeight(document.getElementById('canvas-container').offsetHeight - 4);
canvas.renderAll();
});
});
</script>
</body>
</html>