agentsclimarketplace

Image resizing service

Skill almasumdev/awesome-mobile-backend-agent-skills/.github/skills/media/image-resizing-service

Agent skills for the backend-for-mobile layer: APIs, auth, push, sync, and BaaS integrations.

Install
npx -y skills add almasumdev/awesome-mobile-backend-agent-skills --skill image-resizing-service

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Serve right-sized image variants to mobile via URL-based transforms and a CDN. Use when designing the image delivery path for a mobile app.

SKILL.md

5.3 KB, as published. Nobody here has run it

Image Resizing Service

Instructions

Mobile screens need many sizes: thumbnails, feed cards, full-screen, Retina. Shipping originals is wasteful and slow. A resizing service plus a CDN in front gives you bandwidth savings and good cache hit rates.

1. Two Models

A. Pre-generated variants (batch). At upload time, a worker produces a fixed set of sizes and formats. Clients request specific variant URLs.

Pros: low runtime cost, deterministic storage, easy to cache. Cons: you pay for every size whether it is requested or not; adding a new size requires a backfill.

B. On-demand transforms (URL-based). A single origin; clients append transform params; the edge transforms and caches.

Pros: flexible, no backfill. Cons: first-request latency; requires a transform service (self-hosted imgproxy, thumbor, or managed imgix/Cloudinary/Cloudflare Images).

Most mobile apps benefit from a hybrid: pre-generate the handful of sizes used by the primary screens; enable on-demand for long-tail needs.

2. URL Transforms

Design the URL so the client can ask for exactly what the device needs:

https://cdn.example.com/img/med_01HX7.../w=750,h=750,fit=cover,format=auto,q=80
  • w, h in CSS pixels (client multiplies by device scale).
  • fit: cover, contain, fill, inside.
  • format=auto lets the edge pick AVIF / WebP / JPEG based on Accept.
  • q: quality, default 80; lower for thumbnails.
  • dpr (device pixel ratio) optional alternative to pre-multiplied w/h.

Allowlist permitted combinations -- attackers will otherwise request every size + format to blow up your cache.

3. Format Selection

  • AVIF: best compression; slower decode; ship when device supports it.
  • WebP: near-universal on modern mobile; excellent default.
  • JPEG: fallback; always the floor.
  • HEIC from iOS uploads: transcode to JPEG/WebP for delivery unless the client specifically requests HEIC.

Prefer format=auto and let the edge pick based on Accept headers:

Accept: image/avif,image/webp,image/*;q=0.8

4. Service Implementation

Using imgproxy (Go) behind a CDN:

Client -> CDN -> imgproxy -> object storage
                 cache hit -> serve directly

imgproxy URL example (signed):

https://cdn.example.com/signature/rs:fill:750:750:1/q:80/format:webp/plain/s3://uploads/med_01HX7/original.jpg

Self-hosted alternative (Python/FastAPI + libvips):

from fastapi import FastAPI, Response
import pyvips

app = FastAPI()

@app.get("/img/{key:path}")
def img(key: str, w: int = 0, h: int = 0, q: int = 80, format: str = "webp"):
    im = pyvips.Image.thumbnail(f"s3://uploads/{key}", w or h, height=h or None)
    buf = im.write_to_buffer(f".{format}[Q={q}]")
    return Response(buf, media_type=f"image/{format}",
                    headers={"Cache-Control": "public, max-age=31536000, immutable"})

Always process in a streaming, memory-bounded way; libvips is the right default for that. Restrict output dimensions (e.g., max 4096x4096) and decoded pixels to prevent DoS via huge inputs.

5. Cache Strategy

  • Immutable URLs (include a content hash or upload id) -> set Cache-Control: public, max-age=31536000, immutable.
  • CDN cache key includes the full transform path.
  • Purge rarely; if a user replaces an image, issue a new id rather than mutating.

6. Client Patterns

iOS (SDWebImage / Nuke):

let url = imageURL(mediaId: id, width: view.bounds.width, fit: .cover)
imageView.nuke.load(url)

Android (Coil):

imageView.load(imageUrl(id, widthPx = view.width, fit = "cover")) {
  crossfade(true)
  placeholder(R.drawable.ph)
}

The helper imageUrl(...) computes device-scaled pixel dimensions and appends transform params. Keep that logic in one place.

7. Placeholders and LQIP

For feed and list views, ship a tiny placeholder (BlurHash string, or a 16x16 WebP) in the JSON payload. The client renders that instantly while the full image streams:

{
  "id": "med_01HX7...",
  "w": 3024, "h": 4032,
  "blurhash": "LEHV6nWB2yk8pyo0adR*.7kCMdnj"
}

8. Privacy

  • Strip EXIF metadata (location, device) on upload or at transform time.
  • Private media: sign URLs with a short TTL; do not make buckets public.

9. Cost

  • Cache hit rate > 95% is achievable with stable URLs + long max-age.
  • Watch egress: mobile image traffic often dominates a backend's total bandwidth bill.
  • Compute cost goes up with format=auto + AVIF; measure before broadly enabling.

10. Observability

Track cache hit rate by variant, p95 transform latency on miss, bytes delivered per platform, and format distribution over time. Alert when miss latency degrades -- usually a bad transform service config.

Checklist

  • URL transform grammar defined and documented.
  • Allowlist of valid size / format combinations.
  • format=auto wired to Accept header negotiation.
  • Immutable URLs with long Cache-Control and CDN in front.
  • Max input/output pixel limits enforced to prevent DoS.
  • EXIF stripped; private media served through signed URLs.
  • BlurHash or tiny LQIP shipped in JSON payloads for smooth loading.
  • Cache hit rate, miss latency, egress dashboards.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.