Guest User

Untitled

a guest
Dec 12th, 2024
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 5.51 KB | Source Code | 0 0
  1. import React, { useState } from 'react';
  2.  
  3. const ColorPaletteAnalyzer = () => {
  4.   const [isProcessing, setIsProcessing] = useState(false);
  5.   const [palette, setPalette] = useState([]);
  6.   const [imagePreview, setImagePreview] = useState(null);
  7.  
  8.   const colorDifference = (rgb1, rgb2) => {
  9.     const rDiff = rgb1.r - rgb2.r;
  10.     const gDiff = rgb1.g - rgb2.g;
  11.     const bDiff = rgb1.b - rgb2.b;
  12.     return Math.sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);
  13.   };
  14.  
  15.   const rgbToHex = (r, g, b) => {
  16.     const toHex = (c) => {
  17.       const hex = c.toString(16);
  18.       return hex.length === 1 ? '0' + hex : hex;
  19.     };
  20.     return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
  21.   };
  22.  
  23.   const clusterColors = (colors, threshold = 30) => {
  24.     const clusters = [];
  25.  
  26.     colors.forEach(color => {
  27.       let foundCluster = false;
  28.       for (const cluster of clusters) {
  29.         if (colorDifference(cluster.center, color) < threshold) {
  30.           cluster.colors.push(color);
  31.           const len = cluster.colors.length;
  32.           cluster.center = {
  33.             r: Math.round(cluster.colors.reduce((sum, c) => sum + c.r, 0) / len),
  34.             g: Math.round(cluster.colors.reduce((sum, c) => sum + c.g, 0) / len),
  35.             b: Math.round(cluster.colors.reduce((sum, c) => sum + c.b, 0) / len)
  36.           };
  37.           foundCluster = true;
  38.           break;
  39.         }
  40.       }
  41.  
  42.       if (!foundCluster) {
  43.         clusters.push({
  44.           center: { ...color },
  45.           colors: [color]
  46.         });
  47.       }
  48.     });
  49.  
  50.     return clusters.map(cluster => ({
  51.       ...cluster.center,
  52.       count: cluster.colors.length
  53.     }));
  54.   };
  55.  
  56.   const processImage = (file) => {
  57.     setIsProcessing(true);
  58.     setPalette([]);
  59.     setImagePreview(URL.createObjectURL(file));
  60.  
  61.     const img = new Image();
  62.     const reader = new FileReader();
  63.  
  64.     reader.onload = (e) => {
  65.       img.onload = () => {
  66.         const canvas = document.createElement('canvas');
  67.         const ctx = canvas.getContext('2d');
  68.        
  69.         const maxSize = 300;
  70.         let width = img.width;
  71.         let height = img.height;
  72.        
  73.         if (width > maxSize || height > maxSize) {
  74.           const ratio = Math.min(maxSize / width, maxSize / height);
  75.           width *= ratio;
  76.           height *= ratio;
  77.         }
  78.  
  79.         canvas.width = width;
  80.         canvas.height = height;
  81.         ctx.drawImage(img, 0, 0, width, height);
  82.  
  83.         const imageData = ctx.getImageData(0, 0, width, height).data;
  84.         const colors = [];
  85.  
  86.         for (let i = 0; i < imageData.length; i += 16) {
  87.           colors.push({
  88.             r: imageData[i],
  89.             g: imageData[i + 1],
  90.             b: imageData[i + 2],
  91.           });
  92.         }
  93.  
  94.         const clusteredColors = clusterColors(colors)
  95.           .sort((a, b) => b.count - a.count)
  96.           .slice(0, 5)
  97.           .map(color => ({
  98.             rgb: `rgb(${color.r}, ${color.g}, ${color.b})`,
  99.             hex: rgbToHex(color.r, color.g, color.b)
  100.           }));
  101.  
  102.         setPalette(clusteredColors);
  103.         setIsProcessing(false);
  104.       };
  105.  
  106.       img.src = e.target.result;
  107.     };
  108.  
  109.     reader.readAsDataURL(file);
  110.   };
  111.  
  112.   return (
  113.     <div className="container mx-auto p-6">
  114.       {/* Input Section */}
  115.       <div className="mb-8">
  116.         <label className="block text-sm font-medium mb-2">Upload Image</label>
  117.         <input
  118.           type="file"
  119.           accept="image/*"
  120.           onChange={(e) => processImage(e.target.files[0])}
  121.           className="block w-full text-sm text-slate-500
  122.            file:mr-4 file:py-2 file:px-4
  123.            file:rounded-full file:border-0
  124.            file:text-sm file:font-semibold
  125.            file:bg-violet-50 file:text-violet-700
  126.            hover:file:bg-violet-100"
  127.         />
  128.       </div>
  129.  
  130.       {/* Content Section */}
  131.       <div className="grid grid-cols-2 gap-8">
  132.         {/* Left Column - Image Preview */}
  133.         <div className="w-full">
  134.           {imagePreview && (
  135.             <div className="rounded-lg overflow-hidden shadow-lg bg-gray-50">
  136.               <img
  137.                 src={imagePreview}
  138.                 alt="Uploaded preview"
  139.                 className="w-full h-auto object-contain max-h-[calc(100vh-300px)]"
  140.               />
  141.             </div>
  142.           )}
  143.         </div>
  144.  
  145.         {/* Right Column - Color Palette */}
  146.         <div className="w-full">
  147.           {isProcessing && (
  148.             <div className="flex items-center justify-center py-4">
  149.               <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-violet-700"></div>
  150.             </div>
  151.           )}
  152.  
  153.           {palette.length > 0 && (
  154.             <div className="space-y-6">
  155.               <h2 className="text-lg font-semibold">Color Palette</h2>
  156.               <div className="grid grid-cols-1 gap-4">
  157.                 {palette.map((color, index) => (
  158.                   <div key={index} className="flex items-center space-x-4 p-4 bg-white rounded-lg shadow">
  159.                     <div
  160.                       className="w-16 h-16 rounded shadow-sm"
  161.                       style={{ backgroundColor: color.rgb }}
  162.                     />
  163.                     <div>
  164.                       <div className="font-mono text-sm">{color.hex}</div>
  165.                       <div className="font-mono text-sm text-gray-600">{color.rgb}</div>
  166.                     </div>
  167.                   </div>
  168.                 ))}
  169.               </div>
  170.             </div>
  171.           )}
  172.         </div>
  173.       </div>
  174.     </div>
  175.   );
  176. };
  177.  
  178. export default ColorPaletteAnalyzer;
Advertisement
Add Comment
Please, Sign In to add comment