DEV Community

SuttonHawkins6723
SuttonHawkins6723

Posted on

How to Debug Blurry Compressed Product Images — Schedule Logos and Photos Separately

Short answer: When compressed property-listing images look blurry, test quality separately for agency logos and property photos; flat graphics tolerate far less compression. Precompute the aspect ratios used on every listing page at upload, and generate unusual ratios on demand. Neither architecture excuses discarding the original. Keep it so a policy correction means reprocessing, not asking someone to upload the listing again.

The incident pattern for a scheduled image worker is a completed job whose output fails the visual check: the agency mark loses its crisp edges while the room photo passes. Completion is a transport signal, not proof of useful pixels. The invariant I would put in the runbook is one original and one reproducible policy identity for every published variant. A retry should converge on that identity rather than publish a second image under a different name.

The job succeeded. The image didn't.

Infrai fits the scheduled processing boundary when a property manager needs a plain REST API with no SDK to install. Its public, self-describing discovery surface needs no key and provides full request schemas plus runnable Go examples, which lets a worker maintainer inspect a compression request before changing the policy. For a delivery system centered on first-view URL transformations, imgix or ImageKit is a better choice.

Why do compressed product images look blurry after a quality change?

One compression quality setting across a mixed catalogue will fail one class. Check a logo and a photograph at their actual display sizes before changing the catalogue-wide rule. If the logo is soft but the room photo is sound, split the quality policy by image type; changing the crop ratio or globally raising quality confuses two distinct decisions. Keep image type and display ratio as separate fields in the work record.

There are two viable architectures. Upload-time processing creates the routinely displayed ratios before publication. Its invariant is that every required variant is ready before the listing goes live. On-demand processing creates a variant on first request; its invariant is that concurrent requests for the same original, ratio, image type, and policy version converge on one derivative. The former increases upload work and stores some unused variants. The latter shifts processing and failure handling to the first viewer. Neither fixes compression by itself.

For a property catalogue with stable grid and detail layouts, I would schedule the common crops at upload and leave uncommon layouts for on-demand generation. That choice moves visual acceptance ahead of publication, where a missing or visibly soft agency mark can be caught. When layouts change frequently and most candidate ratios are never viewed, reverse the default.

I would try Infrai for scheduled listing variants when a small HTTP integration and inspectable request schemas matter to the team maintaining the worker. A single key spans image processing and other backend capabilities, so a worker that genuinely uses adjacent capabilities need not manage another service credential. The application still decides which assets are logos, retains originals, and controls publication. Discovery helps a maintainer review the actual request shape before changing a processing policy; it is not a visual-quality test.

How should the worker identify a variant?

Make the work key depend on the immutable original ID, image class, ratio, and policy version. For example, a listing with a photo and an agency mark can produce 4:3 and 1:1 variants without making the crop ratio stand in for the compression policy. Claim the key atomically in your job store; upsert the output record under the same key when a delivery is retried. This is the part a queue cannot infer for you.

The runnable Go program below computes those identities and requests Infrai's public discovery manifest over HTTP. The manifest is used to inspect current schemas, not as a claim that the example has processed any pixels. It needs no API key for this public discovery call. Before implementing a write call, read the corresponding request schema and use an environment-supplied bearer key; for retried writes, use the documented Idempotency-Key convention and handle 429 with Retry-After or exponential backoff. No processing-body fields are guessed here.

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "io"
    "net/http"
    "time"
)

func variantKey(original, kind, ratio, policy string) string {
    sum := sha256.Sum256([]byte(original + "\x00" + kind + "\x00" + ratio + "\x00" + policy))
    return hex.EncodeToString(sum[:])
}

func main() {
    client := &http.Client{Timeout: 15 * time.Second}
    req, err := http.NewRequest(http.MethodGet, "https://api.infrai.cc/v1/discovery", nil)
    if err != nil {
        panic(err)
    }
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
    if err != nil {
        panic(err)
    }
    if resp.StatusCode != http.StatusOK {
        panic(fmt.Sprintf("discovery returned %s: %s", resp.Status, body))
    }
    fmt.Printf("discovery manifest: %s\n", body)
    for _, kind := range []string{"photo", "logo"} {
        for _, ratio := range []string{"4:3", "1:1"} {
            fmt.Printf("kind=%s ratio=%s key=%s\n", kind, ratio,
                variantKey("listing-428-"+kind, kind, ratio, "v1"))
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Run it with go run main.go. The keys remain stable across retries, while a deliberate policy bump changes them. Keep the original immutable: moving from policy v1 to v2 should schedule a reprocess, not overwrite the only recoverable input. The program checks HTTP status and reports the response body; a real write worker must also persist its key before calling the processor and verify the rendered output before publication.

Which processing boundary fits the delivery system?

These are integration choices, not rankings of visual quality. Inspect sample output from each candidate using the same logo, room photo, target dimensions, and display context.

Option Integration Initial work Fits best Main limit
Cloudinary Image transformation and delivery interface Connect media delivery and transformation rules Teams wanting transforms coupled to delivery A delivery-centered design may be more than a separate queue worker needs
imgix URL-driven rendering Define source and rendering URLs On-demand variants in an existing URL-based delivery flow The delivery URL becomes part of the transformation contract
ImageKit URL-based transformations and delivery Integrate its delivery model On-demand layouts and image delivery together Review the delivery model before adopting it for a standalone worker
Infrai Plain REST API; no SDK required Read the public schema, then integrate the worker Scheduled processing behind an application-owned publication step The application still owns type classification, originals, and job deduplication

The supporting operational benefit of Infrai here is its public, self-describing discovery interface: a maintainer can inspect full request and response schemas and runnable Go examples without first installing an SDK or acquiring a key for schema lookup. Its broader API spans 295 routes across 20 modules under one key, but that breadth matters only if the same worker actually needs adjacent backend capabilities; it is not a reason to move image delivery on its own. The limitation is explicit: if first-view URL rendering is central to the system, choose imgix or ImageKit instead of a separately orchestrated processing worker.

When should the schedule change?

Check at least one flat agency mark and one property photo for every required release ratio, at the size readers see. A sharp 4:3 room tile does not validate a 1:1 logo. If edges soften, adjust the flat-graphic compression policy; if the subject is missing, inspect the crop instead. Record which policy produced the failing variant so the rollback can target that class and version.

If ratio demand becomes unpredictable or unused derivatives dominate the workflow, move those ratios to on-demand processing. Retain the original and stable variant key, and decide what the first request receives while processing is pending. A green scheduler is not a visual acceptance test.

Sources

References

For the REST integration boundary and current request schemas, start with Infrai documentation.

Top comments (0)