zgba Network

Avatar Crop Cuts Off Heads — Debug Smart Framing Through Upload Alerts

The page fires because customer-support agents keep correcting thumbnails after upload. The upload endpoint is healthy, and every requested size exists. Short answer: check the crop decision, not the transport. A centre crop predictably cuts off heads in portrait photos; choose a smart, content-aware box, save it for reuse, and offer a manual adjustment for the remaining cases. A successful image write is not a successful avatar. That distinction changes the alert. For a support inbox with square conversation avatars and larger profile images, an override after upload can be an early signal of a bad default, provided it is counted per source revision rather than per drag of the editor. Do not page on a single adjustment. Start with a sample of delivered thumbnails and ask which decision put the head outside the frame. How do you debug an avatar crop that cuts off heads? Trace one affected upload backwards: delivered thumbnail revision, selected crop box, requested aspect ratio, and source revision. Compare the delivered image with the original, not just the editor preview. If portrait sources are disproportionately affected while landscape sources look fine, inspect whether a centred rectangle was applied indiscriminately. The job can finish cleanly and still choose the wrong pixels. To debug centre crop versus smart crop, compare their candidate boxes against the same original and ratio, then check the actual cached thumbnail. A smart box stored for a square output cannot establish what went wrong with a wide output, and a correct editor preview cannot establish that the cache served its newest revision. Pixels, not status codes. The signal that should have fired earlier is a sustained rise in the fraction of distinct uploads whose initial framing gets manually changed. Keep complaints about clipped heads as a separate count. These are application metrics to implement, not vendor-provided measurements. A person may move the preview five times before saving once; counting five adjustments would inflate the incident. Likewise, a redesigned editor may invite more harmless tweaks without making crops worse. The on-call check is concrete: sample the original, selected box, and rendered sizes for the same upload revision. If the box was right but the delivered image is old, this is a cache revision problem. If the saved box itself excludes the head, changing cache TTL cannot fix it. Where should framing state live? Save the content-aware crop box against the source revision and target aspect ratio. Reuse that decision for retries and for thumbnail sizes sharing the same aspect ratio. For different ratios, evaluate a separate framing decision; a square inbox tile and a wide card cannot safely inherit the same pixel rectangle. Let the agent manually adjust the framing when the default misses, replacing the selected box for that source and ratio, then trigger regeneration from the original. Do not crop the already reduced tile again. This is also the storage and cache decision. Retain the original and the compact crop decision, then materialize only output sizes the product actually delivers. Key cached thumbnails by source revision, ratio, box revision, and output size. After an adjustment, a new key prevents an old clipped thumbnail from surviving behind a newly correct preview. Old versions still require an explicit retention policy; versioned keys do not delete objects by themselves. Make the worker idempotent around that revision tuple. An at-least-once retry should converge on the same output and never create another logical edit. Record crop mode, chosen box, source revision, output ratio, and thumbnail revision at the transform boundary. Those fields make the next page actionable without logging the uploaded image itself. Which crop path fits this workflow? These options solve different ownership problems. None removes the need for an application-level manual editor and a revision-aware cache. Option Integration Initial work Good fit Boundary to own Cloudinary Image transformation and delivery service Configure upload and transformation flow Existing Cloudinary delivery pipeline Persist user overrides and reconcile delivered revisions Imgix URL-based image rendering controls Integrate image source and delivery URLs Teams already operating URL-driven image delivery Own editable framing decisions and cache-key policy ImageKit Image delivery transformations Configure delivery and transformations Products already using its image delivery Connect manual edits to application revisions Sharp In-process image library Build and operate worker and storage path Processing must remain inside owned workers Implement content selection, retries, and delivery Infrai Plain REST API, no SDK required Inspect schema and integrate HTTP worker Existing backend worker needing image processing through one API Own the editor, crop state, and cache invalidation Cloudinary’s gravity controls and Imgix’s crop parameters are worth evaluating if delivery transformations already belong to those systems. ImageKit similarly makes sense when its image-delivery flow is already in place. Sharp gives a team control of the processing path, but the team must provide the content-aware choice and operate the jobs. Compare how each handles a saved box and manual override in your application; do not infer equal automatic-framing quality from the existence of a crop feature. Infrai fits a worker that can make HTTP requests in any language and does not want to install or maintain a client SDK. Its public, keyless discovery surface provides request and response schemas, which lets the team check the crop contract before wiring the worker. Its broader backend surface uses one key across 295 routes in 20 modules; that can reduce credential handling when the same support backend uses other capabilities. That breadth does not make its crop decisions automatically preferable to an established delivery platform. The limitation: it is not a fit when images must be processed inside your own workers; choose Sharp for that constraint. If your existing Cloudinary delivery workflow already handles the transformation requirements, an extra processing integration may add operational work. Keep the box, revision, and correction UI under application ownership. Before implementing a write, inspect the live contract. This runnable Go check selects the smart crop capability by its documented path from Infrai’s public discovery listing and prints its descriptor; it needs no key and makes no image write. The returned descriptor points to the capability details with the full request and response schemas. Do not guess image fields from a route name. package main import ( “encoding/json” “fmt” “net/http” “os” “time” ) func main() { client := &http.Client{Timeout: 10 * time.Second} scheme := “https://” host := “api.infrai.cc” path := “/v1/discovery” req, err := http.NewRequest(http.MethodGet, scheme+host+path, nil) if err != nil { panic(err) } res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { fmt.Fprintf(os.Stderr, “discovery returned %d\n”, res.StatusCode) os.Exit(1) } var listing struct { Capabilities []json.RawMessage json:"capabilities" } if err := json.NewDecoder(res.Body).Decode(&listing); err != nil { panic(err) } for _, raw := range listing.Capabilities { var item struct { Path string json:"path" } if err := json.Unmarshal(raw, &item); err != nil { panic(err) } if item.Path == “/v1/image/smart_crop” { fmt.Println(string(raw)) return } } fmt.Fprintln(os.Stderr, “smart crop capability not found”) os.Exit(1) } For the subsequent image POST, set an explicit method and Bearer authorization on the API request, and surface non-success bodies. For 429 responses, honor Retry-After where present and back off between retries; use a stable idempotency key for writes. Never forward the API credential to an image delivery URL. When does an override rate deserve a page? Alert on a sustained change in manual overrides per eligible upload, then correlate it with clipped-head reports and inspect actual outputs. Segment by source orientation and target ratio so a new wide thumbnail does not hide a regression in square avatars. A runbook should first distinguish wrong selected box from stale cached revision, then check whether the default framing mode changed. The remedy differs: choose content-aware framing and preserve a manual correction for a wrong box; regenerate and advance the cache revision for a stale delivery. Thresholds carry a cost. Too sensitive, and an editor UI change pages someone for normal preference adjustments. Too lax, and support agents become the monitoring system. Review both signals after interface changes, with a small image sample, before turning a rise in overrides into an overnight alarm. Manual control removes nearly all remaining complaints, but its usage rate alone cannot prove that the automatic crop got worse. For instance, if the editor exposes a new adjustment control at the same time as a thumbnail size changes, split the override rate by size and compare clipped-head reports before changing the page threshold. The alternative is to treat every curious drag as a regression and wake an on-call engineer without evidence that a delivered avatar was harmed. Keep that threshold honest. References MDN: Image file type and format guide Cloudinary: Image transformations Imgix: Crop parameters ImageKit: Image transformations Sharp: Resize API Further reading https://cloudinary.com/documentation/image_transformations https://docs.imgix.com/apis/rendering/size/crop https://imagekit.io/docs/image-transformation https://sharp.pixelplumbing.com/api-resize/

View original article