Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { useState } from 'react';
- const ColorPaletteAnalyzer = () => {
- const [isProcessing, setIsProcessing] = useState(false);
- const [palette, setPalette] = useState([]);
- const [imagePreview, setImagePreview] = useState(null);
- const colorDifference = (rgb1, rgb2) => {
- const rDiff = rgb1.r - rgb2.r;
- const gDiff = rgb1.g - rgb2.g;
- const bDiff = rgb1.b - rgb2.b;
- return Math.sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);
- };
- const rgbToHex = (r, g, b) => {
- const toHex = (c) => {
- const hex = c.toString(16);
- return hex.length === 1 ? '0' + hex : hex;
- };
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
- };
- const clusterColors = (colors, threshold = 30) => {
- const clusters = [];
- colors.forEach(color => {
- let foundCluster = false;
- for (const cluster of clusters) {
- if (colorDifference(cluster.center, color) < threshold) {
- cluster.colors.push(color);
- const len = cluster.colors.length;
- cluster.center = {
- r: Math.round(cluster.colors.reduce((sum, c) => sum + c.r, 0) / len),
- g: Math.round(cluster.colors.reduce((sum, c) => sum + c.g, 0) / len),
- b: Math.round(cluster.colors.reduce((sum, c) => sum + c.b, 0) / len)
- };
- foundCluster = true;
- break;
- }
- }
- if (!foundCluster) {
- clusters.push({
- center: { ...color },
- colors: [color]
- });
- }
- });
- return clusters.map(cluster => ({
- ...cluster.center,
- count: cluster.colors.length
- }));
- };
- const processImage = (file) => {
- setIsProcessing(true);
- setPalette([]);
- setImagePreview(URL.createObjectURL(file));
- const img = new Image();
- const reader = new FileReader();
- reader.onload = (e) => {
- img.onload = () => {
- const canvas = document.createElement('canvas');
- const ctx = canvas.getContext('2d');
- const maxSize = 300;
- let width = img.width;
- let height = img.height;
- if (width > maxSize || height > maxSize) {
- const ratio = Math.min(maxSize / width, maxSize / height);
- width *= ratio;
- height *= ratio;
- }
- canvas.width = width;
- canvas.height = height;
- ctx.drawImage(img, 0, 0, width, height);
- const imageData = ctx.getImageData(0, 0, width, height).data;
- const colors = [];
- for (let i = 0; i < imageData.length; i += 16) {
- colors.push({
- r: imageData[i],
- g: imageData[i + 1],
- b: imageData[i + 2],
- });
- }
- const clusteredColors = clusterColors(colors)
- .sort((a, b) => b.count - a.count)
- .slice(0, 5)
- .map(color => ({
- rgb: `rgb(${color.r}, ${color.g}, ${color.b})`,
- hex: rgbToHex(color.r, color.g, color.b)
- }));
- setPalette(clusteredColors);
- setIsProcessing(false);
- };
- img.src = e.target.result;
- };
- reader.readAsDataURL(file);
- };
- return (
- <div className="container mx-auto p-6">
- {/* Input Section */}
- <div className="mb-8">
- <label className="block text-sm font-medium mb-2">Upload Image</label>
- <input
- type="file"
- accept="image/*"
- onChange={(e) => processImage(e.target.files[0])}
- className="block w-full text-sm text-slate-500
- file:mr-4 file:py-2 file:px-4
- file:rounded-full file:border-0
- file:text-sm file:font-semibold
- file:bg-violet-50 file:text-violet-700
- hover:file:bg-violet-100"
- />
- </div>
- {/* Content Section */}
- <div className="grid grid-cols-2 gap-8">
- {/* Left Column - Image Preview */}
- <div className="w-full">
- {imagePreview && (
- <div className="rounded-lg overflow-hidden shadow-lg bg-gray-50">
- <img
- src={imagePreview}
- alt="Uploaded preview"
- className="w-full h-auto object-contain max-h-[calc(100vh-300px)]"
- />
- </div>
- )}
- </div>
- {/* Right Column - Color Palette */}
- <div className="w-full">
- {isProcessing && (
- <div className="flex items-center justify-center py-4">
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-violet-700"></div>
- </div>
- )}
- {palette.length > 0 && (
- <div className="space-y-6">
- <h2 className="text-lg font-semibold">Color Palette</h2>
- <div className="grid grid-cols-1 gap-4">
- {palette.map((color, index) => (
- <div key={index} className="flex items-center space-x-4 p-4 bg-white rounded-lg shadow">
- <div
- className="w-16 h-16 rounded shadow-sm"
- style={{ backgroundColor: color.rgb }}
- />
- <div>
- <div className="font-mono text-sm">{color.hex}</div>
- <div className="font-mono text-sm text-gray-600">{color.rgb}</div>
- </div>
- </div>
- ))}
- </div>
- </div>
- )}
- </div>
- </div>
- </div>
- );
- };
- export default ColorPaletteAnalyzer;
Advertisement
Add Comment
Please, Sign In to add comment