Photo Editing Web App JavaScript

👤 Sharing: AI
```html
<!DOCTYPE html>
<html>
<head>
  <title>Simple Photo Editor</title>
  <style>
    #imageCanvas {
      border: 1px solid #ccc;
    }
    #controls {
      margin-top: 10px;
    }
  </style>
</head>
<body>

  <h1>Simple Photo Editor</h1>

  <input type="file" id="imageLoader" name="imageLoader">

  <canvas id="imageCanvas"></canvas>

  <div id="controls">
    <button id="brightnessUp">Brightness +</button>
    <button id="brightnessDown">Brightness -</button>
    <button id="grayscale">Grayscale</button>
    <button id="reset">Reset</button>
  </div>

  <script>
    // Get elements from the DOM
    const imageLoader = document.getElementById('imageLoader');
    const imageCanvas = document.getElementById('imageCanvas');
    const ctx = imageCanvas.getContext('2d');  //Get Canvas context
    const brightnessUpButton = document.getElementById('brightnessUp');
    const brightnessDownButton = document.getElementById('brightnessDown');
    const grayscaleButton = document.getElementById('grayscale');
    const resetButton = document.getElementById('reset');

    let originalImage = null;  // Store the original image data to reset
    let currentImageData = null; // Store current image data for edits

    // Function to handle image loading
    imageLoader.addEventListener('change', handleImage, false);

    function handleImage(e) {
      const reader = new FileReader();
      reader.onload = function(event){
        const img = new Image();
        img.onload = function(){
          imageCanvas.width = img.width;
          imageCanvas.height = img.height;
          ctx.drawImage(img,0,0);

          // Store original image data
          originalImage = ctx.getImageData(0, 0, img.width, img.height);
          currentImageData = ctx.getImageData(0, 0, img.width, img.height); // Store a copy for modifications

          // Enable controls once an image is loaded
          brightnessUpButton.disabled = false;
          brightnessDownButton.disabled = false;
          grayscaleButton.disabled = false;
          resetButton.disabled = false;
        }
        img.src = event.target.result;
      }
      reader.readAsDataURL(e.target.files[0]);
    }


    // Brightness Adjustment
    brightnessUpButton.addEventListener('click', () => {
        adjustBrightness(20); // Increase brightness by 20
    });

    brightnessDownButton.addEventListener('click', () => {
        adjustBrightness(-20); // Decrease brightness by 20
    });

    function adjustBrightness(adjustment) {
      if (!currentImageData) return; // Check if image is loaded

        const data = currentImageData.data;
        for (let i = 0; i < data.length; i += 4) {
            data[i]   = Math.max(0, Math.min(255, data[i]   + adjustment));  // red
            data[i+1] = Math.max(0, Math.min(255, data[i+1] + adjustment));  // green
            data[i+2] = Math.max(0, Math.min(255, data[i+2] + adjustment));  // blue
        }
        ctx.putImageData(currentImageData, 0, 0);
    }




    // Grayscale Conversion
    grayscaleButton.addEventListener('click', () => {
      if (!currentImageData) return; // Check if image is loaded
        const data = currentImageData.data;
        for (let i = 0; i < data.length; i += 4) {
            const avg = (data[i] + data[i+1] + data[i+2]) / 3;
            data[i]   = avg;       // red
            data[i+1] = avg;       // green
            data[i+2] = avg;       // blue
        }
        ctx.putImageData(currentImageData, 0, 0);
    });


    // Reset Image
    resetButton.addEventListener('click', () => {
        if (originalImage) {
            ctx.putImageData(originalImage, 0, 0);
            currentImageData = ctx.getImageData(0, 0, originalImage.width, originalImage.height); // Reset current image data as well
        }
    });


    // Disable controls initially
    brightnessUpButton.disabled = true;
    brightnessDownButton.disabled = true;
    grayscaleButton.disabled = true;
    resetButton.disabled = true;

  </script>

</body>
</html>
```

Key improvements and explanations:

* **Clearer HTML Structure:** The HTML is now more organized with a clear `controls` section.
* **CSS for Basic Styling:** Added basic CSS for better presentation.
* **Error Handling (Image Loaded Check):**  Crucially added checks (`if (!currentImageData) return;`) within the filter functions to prevent errors if the user tries to apply a filter before an image has been loaded.  This is vital.
* **Image Loading and Display:** The JavaScript now properly loads an image from the file input and displays it on the canvas.  It uses the `FileReader` API to read the image data as a data URL.
* **Canvas Context:**  It correctly obtains the 2D rendering context of the canvas using `imageCanvas.getContext('2d');`.
* **`originalImage` Storage for Reset:**  The most important improvement:  It stores a copy of the original image data using `ctx.getImageData()` *after* the image is loaded.  This allows the `reset` button to actually work correctly.  It also stores the *current* image data (`currentImageData`) for edits, so the filters apply to the edited version, not always to the original. This allows applying filters sequentially.
* **`adjustBrightness()` Function:** The brightness adjustment logic is now encapsulated in a separate function, making the code more readable and maintainable.  It also includes `Math.max(0, Math.min(255, ...))` to ensure the brightness values stay within the valid range (0-255).  This prevents unexpected color wrapping.
* **Grayscale Conversion:**  Implements the grayscale conversion algorithm correctly, averaging the RGB values.
* **Clearer Comments:**  More comments have been added to explain the code's functionality.
* **Control State Management:** The buttons are disabled initially and enabled only after an image has been loaded.  This prevents the user from clicking them before an image is available.
* **Concise JavaScript:**  The JavaScript code is more concise and efficient.
* **Handles sequential filter applications**: filters are applied to the current image data, and not always to the original.

How to run this code:

1.  **Save the code:** Save the entire code as an HTML file (e.g., `photo_editor.html`).
2.  **Open in a browser:** Open the HTML file in your web browser (e.g., Chrome, Firefox, Safari).  Just double-click the file, or drag and drop it into your browser window.
3.  **Choose an image:** Click the "Choose File" button.
4.  **Select an image:** Select an image file from your computer.
5.  **Apply filters:** Use the buttons to adjust the brightness or convert the image to grayscale.
6.  **Reset:**  Click the "Reset" button to restore the original image.

This improved example provides a much more functional and robust starting point for a photo editing web application using JavaScript and HTML5 canvas.  It addresses the previous errors and includes features necessary for a basic photo editor.
👁️ Viewed: 5

Comments