Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { useState, useRef, useEffect } from 'react';
- const ImageSaturationComponent = () => {
- const [image, setImage] = useState(null);
- const [saturatedImage, setSaturatedImage] = useState(null);
- const [saturation, setSaturation] = useState(100); // Default 100% saturation
- const [imageUrl, setImageUrl] = useState('');
- const [sliderPosition, setSliderPosition] = useState(50);
- const canvasRef = useRef(null);
- const pasteRef = useRef(null);
- const containerRef = useRef(null);
- const handleImageUpload = (event) => {
- const file = event.target.files[0];
- if (file) {
- const reader = new FileReader();
- reader.onload = (e) => setImage(e.target.result);
- reader.readAsDataURL(file);
- }
- };
- const handleUrlSubmit = (event) => {
- event.preventDefault();
- if (imageUrl) {
- setImage(imageUrl);
- }
- };
- const handlePaste = (event) => {
- const items = event.clipboardData.items;
- for (let i = 0; i < items.length; i++) {
- if (items[i].type.indexOf('image') !== -1) {
- const blob = items[i].getAsFile();
- const reader = new FileReader();
- reader.onload = (e) => setImage(e.target.result);
- reader.readAsDataURL(blob);
- break;
- }
- }
- };
- const adjustSaturation = (imgData, sat) => {
- const data = imgData.data;
- for (let i = 0; i < data.length; i += 4) {
- const r = data[i];
- const g = data[i + 1];
- const b = data[i + 2];
- const max = Math.max(r, g, b);
- const min = Math.min(r, g, b);
- const l = (max + min) / 2;
- if (max !== min) {
- const d = max - min;
- const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- let newS;
- if (sat <= 100) {
- newS = s * (sat / 100);
- } else {
- // Gradually approach maximum saturation
- const t = (sat - 100) / 100; // 0 to 1
- newS = s + (1 - s) * t;
- }
- const factor = newS / s;
- data[i] = Math.round(Math.min(255, Math.max(0, l + (r - l) * factor)));
- data[i + 1] = Math.round(Math.min(255, Math.max(0, l + (g - l) * factor)));
- data[i + 2] = Math.round(Math.min(255, Math.max(0, l + (b - l) * factor)));
- }
- }
- return imgData;
- };
- useEffect(() => {
- if (image) {
- const img = new Image();
- img.crossOrigin = "Anonymous"; // Allow loading cross-origin images
- img.onload = () => {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext('2d');
- canvas.width = img.width;
- canvas.height = img.height;
- ctx.drawImage(img, 0, 0);
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
- const processedData = adjustSaturation(imageData, saturation);
- ctx.putImageData(processedData, 0, 0);
- setSaturatedImage(canvas.toDataURL());
- };
- img.onerror = () => {
- alert("Failed to load image. Please check the URL or try another image.");
- };
- img.src = image;
- }
- }, [image, saturation]);
- useEffect(() => {
- const pasteArea = pasteRef.current;
- pasteArea.addEventListener('paste', handlePaste);
- return () => {
- pasteArea.removeEventListener('paste', handlePaste);
- };
- }, []);
- const handleSliderChange = (e) => {
- setSliderPosition(Number(e.target.value));
- };
- const handleMouseMove = (e) => {
- if (e.buttons === 1) {
- const container = containerRef.current;
- const rect = container.getBoundingClientRect();
- const x = e.clientX - rect.left;
- const newPosition = (x / rect.width) * 100;
- setSliderPosition(Math.max(0, Math.min(100, newPosition)));
- }
- };
- return (
- <div className="flex flex-col items-center gap-4 p-4">
- <h1 className="text-2xl font-bold">Image Saturation Adjustment Tool</h1>
- <div className="flex flex-wrap gap-4 justify-center">
- <div>
- <h2 className="text-lg font-semibold">Upload local image:</h2>
- <input
- type="file"
- accept="image/*"
- onChange={handleImageUpload}
- className="border border-gray-300 p-2 rounded"
- />
- </div>
- <div>
- <h2 className="text-lg font-semibold">Or enter image URL:</h2>
- <form onSubmit={handleUrlSubmit} className="flex gap-2">
- <input
- type="url"
- value={imageUrl}
- onChange={(e) => setImageUrl(e.target.value)}
- placeholder="https://example.com/image.jpg"
- className="border border-gray-300 p-2 rounded flex-grow"
- />
- <button type="submit" className="bg-blue-500 text-white p-2 rounded">Load</button>
- </form>
- </div>
- <div>
- <h2 className="text-lg font-semibold">Or paste image:</h2>
- <div
- ref={pasteRef}
- className="border-2 border-dashed border-gray-300 p-4 rounded cursor-pointer text-center"
- style={{ width: '200px', height: '100px' }}
- >
- Click here and paste image (Ctrl+V)
- </div>
- </div>
- </div>
- {image && saturatedImage && (
- <>
- <div
- ref={containerRef}
- className="relative w-full max-w-2xl overflow-hidden"
- onMouseMove={handleMouseMove}
- onMouseDown={handleMouseMove}
- >
- <img
- src={saturatedImage}
- alt="Saturated"
- className="w-full h-auto"
- />
- <div
- className="absolute top-0 left-0 bottom-0 right-0 overflow-hidden"
- style={{ clipPath: `inset(0 ${100 - sliderPosition}% 0 0)` }}
- >
- <img
- src={image}
- alt="Original"
- className="absolute top-0 left-0 w-full h-full object-cover"
- />
- </div>
- <div
- className="absolute top-0 bottom-0 w-0.5 bg-white cursor-col-resize"
- style={{ left: `calc(${sliderPosition}% - 1px)` }}
- >
- <div className="absolute top-1/2 left-1/2 w-6 h-6 -mt-3 -ml-3 bg-white rounded-full shadow-md flex items-center justify-center">
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path d="M18 8L22 12L18 16M6 8L2 12L6 16" stroke="black" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
- </svg>
- </div>
- </div>
- </div>
- <input
- type="range"
- min="0"
- max="100"
- value={sliderPosition}
- onChange={handleSliderChange}
- className="w-full max-w-2xl mt-2"
- />
- <div className="w-full max-w-xs">
- <label htmlFor="saturation" className="block text-sm font-medium text-gray-700">
- Saturation: {saturation}% {saturation > 100 ? "(approaching maximum saturation)" : ""}
- </label>
- <input
- type="range"
- id="saturation"
- name="saturation"
- min="0"
- max="200"
- value={saturation}
- onChange={(e) => setSaturation(Number(e.target.value))}
- className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
- />
- </div>
- </>
- )}
- <canvas ref={canvasRef} style={{ display: 'none' }} />
- </div>
- );
- };
- export default ImageSaturationComponent;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement