Untitled

 avatar
unknown
plain_text
a year ago
4.7 kB
3
Indexable
import React, { useState, useRef } from 'react';
import { AlertCircle } from 'lucide-react';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';

const ImageProcessor = () => {
  const [originalImage, setOriginalImage] = useState(null);
  const [processedImage, setProcessedImage] = useState(null);
  const [scaleFactor, setScaleFactor] = useState(0.5);
  const [error, setError] = useState(null);
  const canvasRef = useRef(null);

  const handleImageUpload = (event) => {
    const file = event.target.files[0];
    const reader = new FileReader();

    reader.onload = (e) => {
      const img = new Image();
      img.onload = () => {
        setOriginalImage(img);
        setProcessedImage(null);
        setError(null);
      };
      img.src = e.target.result;
    };

    reader.readAsDataURL(file);
  };

  const processImage = () => {
    if (!originalImage) {
      setError("Please upload an image first.");
      return;
    }

    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');

    // Set canvas size to match original image
    canvas.width = originalImage.width;
    canvas.height = originalImage.height;

    // Draw original image
    ctx.drawImage(originalImage, 0, 0);

    // Get image data
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;

    // Calculate dimensions for downscaled image
    const pixelSize = Math.ceil(1 / scaleFactor);
    const scaledWidth = Math.floor(canvas.width / pixelSize);
    const scaledHeight = Math.floor(canvas.height / pixelSize);

    // Create a temporary canvas for the downscaled image
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = scaledWidth;
    tempCanvas.height = scaledHeight;
    const tempCtx = tempCanvas.getContext('2d');
    tempCtx.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight);

    // Get the downscaled image data
    const scaledImageData = tempCtx.getImageData(0, 0, scaledWidth, scaledHeight);
    const scaledData = scaledImageData.data;

    // Process the image with large pixel effect
    for (let y = 0; y < canvas.height; y++) {
      for (let x = 0; x < canvas.width; x++) {
        const srcX = Math.floor(x / pixelSize);
        const srcY = Math.floor(y / pixelSize);
        const srcIndex = (srcY * scaledWidth + srcX) * 4;
        const destIndex = (y * canvas.width + x) * 4;

        data[destIndex] = scaledData[srcIndex];
        data[destIndex + 1] = scaledData[srcIndex + 1];
        data[destIndex + 2] = scaledData[srcIndex + 2];
        data[destIndex + 3] = scaledData[srcIndex + 3];
      }
    }

    // Put the processed image data back on the canvas
    ctx.putImageData(imageData, 0, 0);

    // Set processed image
    setProcessedImage(canvas.toDataURL());
  };

  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">Image Processor (Large Pixel Effect)</h1>
      
      <div className="mb-4">
        <input 
          type="file" 
          accept="image/*" 
          onChange={handleImageUpload} 
          className="mb-2"
        />
        <div className="flex items-center">
          <label htmlFor="scaleFactor" className="mr-2">Scale Factor:</label>
          <input
            type="number"
            id="scaleFactor"
            min="0.1"
            max="1"
            step="0.1"
            value={scaleFactor}
            onChange={(e) => setScaleFactor(parseFloat(e.target.value))}
            className="border rounded px-2 py-1 w-20"
          />
        </div>
      </div>

      <button 
        onClick={processImage}
        className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
      >
        Process Image
      </button>

      {error && (
        <Alert variant="destructive" className="mt-4">
          <AlertCircle className="h-4 w-4" />
          <AlertTitle>Error</AlertTitle>
          <AlertDescription>{error}</AlertDescription>
        </Alert>
      )}

      <div className="mt-4 flex flex-wrap">
        {originalImage && (
          <div className="mr-4 mb-4">
            <h2 className="text-lg font-semibold mb-2">Original Image</h2>
            <img src={originalImage.src} alt="Original" className="max-w-full h-auto" />
          </div>
        )}
        {processedImage && (
          <div>
            <h2 className="text-lg font-semibold mb-2">Processed Image (Large Pixel Effect)</h2>
            <img src={processedImage} alt="Processed" className="max-w-full h-auto" />
          </div>
        )}
      </div>

      <canvas ref={canvasRef} style={{ display: 'none' }} />
    </div>
  );
};

export default ImageProcessor;
Editor is loading...
Leave a Comment