webdevpuneet.com

Bootstrap Image Crop Before Upload — Free HTML CSS JS Snippet

Bootstrap Image Crop Before Upload · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bscrop-card">
    <div class="card-body p-4">
      <label class="form-label small fw-semibold">Choose an image</label>
      <input type="file" class="form-control mb-3" id="bscropInput" accept="image/*">

      <div class="d-none" id="bscropEditor">
        <div class="bscrop-frame" id="bscropFrame">
          <img id="bscropImg" draggable="false" alt="">
        </div>
        <label class="form-label small mt-2 mb-1">Zoom</label>
        <input type="range" class="form-range" id="bscropZoom" min="1" max="2.5" step="0.01" value="1">
        <button type="button" class="btn btn-dark btn-sm fw-bold mt-2" id="bscropSave">Save crop</button>
      </div>

      <div class="d-none mt-3" id="bscropResultWrap">
        <p class="small fw-semibold mb-1">Cropped result:</p>
        <canvas id="bscropCanvas" width="160" height="160" class="bscrop-result"></canvas>
      </div>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

A real cover-fit base scale computed from the image's actual natural dimensions, not a fixed guess
Dragging and zooming are both clamped so the crop frame can never show empty space
The crop is computed at full image resolution via natural-coordinate math, not a downscaled preview
Uses the Pointer Events API (pointerdown/move/up) so the same code handles mouse and touch dragging
Pointer capture ensures a fast drag that leaves the frame's bounds is still tracked correctly

About this UI Snippet

Bootstrap Image Crop Before Upload — HTML, CSS & JavaScript

Screenshot of the Bootstrap Image Crop Before Upload snippet rendered live

The core problem this snippet solves is mapping what's *visually* inside a fixed-size crop frame back to real pixel coordinates in the *original, full-resolution* image — those are two different coordinate systems the moment the image is scaled or panned at all. baseScale starts at whichever ratio makes the image fully cover the 220px frame (Math.max(FRAME / naturalWidth, FRAME / naturalHeight), the same "cover" math CSS's own object-fit: cover uses), and the zoom slider multiplies on top of that base rather than replacing it, so 1.0 on the slider always means "just covering the frame," not "original size."

Dragging updates offsetX/offsetY directly as real pixel positions of the image's top-left corner relative to the frame — not a CSS transform, which would make the reverse-mapping math significantly messier. clampOffsets() runs after every drag and zoom change to guarantee the frame can never show empty space around the image, by constraining each offset between FRAME - scaledSize and 0.

The actual crop happens in Save: since the frame shows a FRAME-pixel window starting at -offsetX, -offsetY in the image's *displayed* pixels, dividing those by the current scale converts them into the image's *natural* pixel coordinates — srcX = -offsetX / scale, srcY = -offsetY / scale, srcSize = FRAME / scale — which is exactly the source rectangle ctx.drawImage() needs to paint precisely what was visible on screen onto the output canvas, at full resolution rather than a blurry re-scale of an already-shrunk preview.

Step by step

How to Use

  1. 1
    Choose an image fileIt loads into a circular-adjacent square frame, automatically scaled to fully cover it.
  2. 2
    Drag inside the frameThe image pans under your cursor, clamped so it can never reveal empty space at any edge.
  3. 3
    Move the zoom sliderThe image scales up (and re-clamps its position) while staying centered on wherever you last panned to.
  4. 4
    Click "Save crop"A circular cropped result appears below, computed from the exact visible region at full image resolution.
  5. 5
    Choose a different imageThe editor resets cleanly with fresh scale and centering for the new file.

Real-world uses

Common Use Cases

Profile photo and avatar upload flows
Pairs directly with bootstrap-avatar-upload-editor for a complete photo-selection-to-final-crop pipeline.
Any upload requiring a specific aspect ratio
Ensures a user-selected image fits a fixed square (or, with square math generalized, rectangular) region cleanly before it is ever uploaded.
Learning coordinate-space conversion for canvas
A genuinely useful, complete reference for converting screen/display coordinates back into an image's natural pixel space.

Got questions?

Frequently Asked Questions

The display coordinates are natural-pixel coordinates multiplied by scale; reversing that transform to recover natural coordinates from display coordinates requires dividing by the same scale, not multiplying by it.

Yes — drawImage() always reads from the original, full-resolution <img> element regardless of how small it currently appears on screen, so the crop is never limited by the preview's displayed size the way cropping a screenshot of the frame would be.

Yes. Keep offsetX/offsetY/zoom in component state or refs (refs avoid unnecessary re-renders during a drag), and run the same clamp-and-transform math inside your pointer event handlers.

Give the frame a rectangular size instead of a square one, compute baseScale using that rectangle's width/height against the image's natural dimensions, and adjust srcSize into separate srcWidth/srcHeight values using the frame's actual aspect ratio.

Design your website