javascript 102 lines · 3 tabs

Resize and Compress Uploaded Images with Sharp Before Saving to Disk

Shared by codesnips Sep 2026
3 tabs
const sharp = require('sharp');

const DEFAULTS = {
  maxWidth: 1600,
  maxHeight: 1600,
  format: 'webp',
  quality: 80
};

async function processImage(buffer, options = {}) {
  const opts = { ...DEFAULTS, ...options };

  const pipeline = sharp(buffer, { failOn: 'truncated' });
  const metadata = await pipeline.metadata();
  if (!metadata.format) {
    throw new Error('Unsupported or unreadable image');
  }

  const output = await pipeline
    .rotate() // apply EXIF orientation, then strip it
    .resize(opts.maxWidth, opts.maxHeight, {
      fit: 'inside',
      withoutEnlargement: true
    })
    .toFormat(opts.format, { quality: opts.quality })
    .toBuffer({ resolveWithObject: true });

  return {
    buffer: output.data,
    width: output.info.width,
    height: output.info.height,
    format: opts.format,
    bytes: output.info.size
  };
}

module.exports = { processImage };
3 files · javascript Explain with highlit

This snippet shows how an Express upload endpoint accepts a raw image, normalizes it, and writes a compressed, resized version to disk instead of storing the original bytes untouched. Storing whatever a client sends is a common source of bloat and abuse: a 12 MP phone photo can be 8 MB when a 1600px WebP at quality 80 would be a few hundred kilobytes. The transformation happens server-side so the stored asset is predictable regardless of what device or format the client used.

In imageProcessor.js, the work is centralized in processImage, which wraps the sharp library. The pipeline calls .rotate() first so EXIF orientation is baked in — otherwise portrait photos from phones render sideways. .resize() uses fit: 'inside' with withoutEnlargement: true, which shrinks oversized images to fit a bounding box but never upscales a small one, avoiding blurry blow-ups. It then re-encodes to a single canonical format (webp) with a fixed quality, and sharp metadata is read up front to reject non-images early. Returning both the buffer and its dimensions lets the caller persist useful metadata without re-parsing.

upload.js configures multer with memoryStorage so the file arrives as an in-memory Buffer rather than a temp file on disk. This matters because sharp reads a buffer directly, so the original is never persisted — only the processed output is. A fileFilter blocks obvious non-image MIME types, and limits.fileSize caps the request to prevent a single upload from exhausting memory; the two together form a cheap first line of defense before any expensive decoding runs.

uploadRoutes.js ties it together: the multer middleware populates req.file, processImage produces the optimized buffer, a collision-resistant name is built with crypto.randomUUID, and fs.writeFile commits it. Errors from sharp on a corrupt or truncated file surface as a 422 rather than a 500, and multer's LIMIT_FILE_SIZE is mapped to 413. The trade-off is CPU and event-loop time spent decoding on the request path; for high volume this belongs in a background job, but for typical avatar or attachment flows doing it inline keeps the design simple and the stored files consistently small.


Related snips

ruby
class SignupForm
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :account_name, :string
  attribute :email, :string

Shallow Controller, Deep Params: Form Object Pattern

rails activemodel form-object
by codesnips 3 tabs
ruby
# BAD: N+1 query problem
@users = User.all
@users.each do |user|
  puts user.posts.count  # Fires query for each user!
end

ActiveRecord query optimization and N+1 prevention

ruby rails activerecord
by Sarah Mitchell 3 tabs
typescript
import { randomBytes, createHash } from "crypto";
import jwt from "jsonwebtoken";
import { RefreshTokenStore } from "./store";

const ACCESS_SECRET = process.env.ACCESS_SECRET!;
const ACCESS_TTL = "15m";

JWT access + refresh token rotation (conceptual)

security node jwt
by codesnips 3 tabs
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Form Validation Example</title>
  <style>

HTML forms with validation and accessibility

html forms validation
by Alex Chang 1 tab
sql
-- EXPLAIN ANALYZE (actual execution statistics)
EXPLAIN ANALYZE
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at >= '2024-01-01'

Advanced query optimization techniques

database optimization query-performance
by Maria Garcia 2 tabs
python
import cv2

image = cv2.imread('receipt.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresholded = cv2.adaptiveThreshold(

OpenCV image preprocessing for OCR and vision pipelines

opencv image-processing computer-vision
by Dr. Elena Vasquez 1 tab

Share this code

Here's the card — post it anywhere.

Resize and Compress Uploaded Images with Sharp Before Saving to Disk — share card
Link copied