<div id="root"></div>
body {
  height: 100vh;
  margin: 0;
}
View Compiled
import React from 'https://esm.sh/react@18.2.0'
import ReactDOM from 'https://esm.sh/react-dom@18.2.0'

const App = () => {
  const [image, setImage] = React.useState('https://raw.githubusercontent.com/readmedata/data/main/%E1%84%92%E1%85%A1%E1%84%83%E1%85%AE%E1%84%85%E1%85%B5-%E1%84%89%E1%85%A6%E1%86%AF%E1%84%8F%E1%85%A1.jpeg');
  const [resolution, setResolution] = React.useState(0.5);

  function handleChange(e) {
  setResolution(Number(e.target.value))
}
  
  React.useEffect(() => {
    compressImage(resolution, image, setImage)
  },[resolution]);
  
  return(
    <div style={{display:'flex', flexDirection:'column'}}>
      <Input resolution={resolution} setResolution={setResolution} handleChange={handleChange}/>
      <img src={image} width="300px" height="300px"/>
    </div>
  );
}

function compressImage(resolution, image, setImage) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'anonymous';
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    img.src = image;

    img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0, img.width, img.height);

      canvas.toBlob(
        (blob) => {
          if (blob) {
            setImage(URL.createObjectURL(blob));
            URL.revokeObjectURL(URL.createObjectURL(blob));
            resolve();
          } else {
            reject(new Error('Failed to compress image'));
          }
        },
        'image/jpeg',
        resolution
      );
    };
  });
}

function Input({resolution,setResolution, handleChange}) {
  const maxResolution = 0.64
  const minResolution = 0.12
  
  return(
    <div style={{display: 'flex', flexDirection:'column'}}>
      <div>
      <input
      type="number"
      value={resolution.toFixed(2)}
      onChange={handleChange}
      style={{width:"70px"}}
      readOnly/>&emsp;&emsp;
      <button onClick={() => {
    if(resolution >= maxResolution) return;
      setResolution(prev => prev + 0.02)}}>+</button>
      <button onClick={() => {
    if(resolution <= minResolution) return;
    setResolution(prev => prev - 0.02)}}
        >-</button>
        <div>화질: {resolution.toFixed(2)}&emsp; 최대: {maxResolution}
        </div>
       </div>
    </div>
  )
}

ReactDOM.render(<App />,
document.getElementById("root"))
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.