DEV Community

ChrysostomHayes8537
ChrysostomHayes8537

Posted on

Print-on-Demand Artwork Intake — 4 Metadata Checks Before Raster Conversion

A print-on-demand healthtech workflow should reject unsuitable artwork during metadata intake, before raster conversion starts. Short answer: validate dimensions and format first, keep the original asset identifier beside every derivative, and make retention and failure handling explicit before production.

That sounds obvious until a clinic uploads a phone photo with an unusual color profile, a transparent PNG with a huge canvas, or a square illustration that cannot cover the selected poster size. A converter can produce a file and still produce the wrong product.

I treat the metadata response as an admission decision, not as decoration. The result I want is visible to the operator: accepted, rejected with a reason, or waiting for a human review. I don't need a clever dashboard to see that distinction.

What should a print-on-demand artwork metadata check prove before conversion?

Start with representative source files and target dimensions. For a healthtech poster, my fixture set would include a JPEG photograph, a transparent PNG illustration, a high-resolution TIFF supplied by design, and one intentionally unacceptable file. Record width, height, format, color information, and the source asset ID in the test expectation. Then test the target outputs: a 3000 x 4500 poster, a square card, and the smallest thumbnail the storefront displays.

The rule is not “the API returned 200.” The rule is “this source can produce the requested artifact without a silent crop or an accidental upscale.” A 1200-pixel image may be fine for a web preview and unacceptable for a large print. Keep those policies in your application so a vendor response cannot quietly redefine production quality.

One short rule: reject early.

A useful record has three identities: the immutable source ID, the validation decision, and the derivative ID created by conversion. Never overwrite the source object with the converted file. If a nurse asks why a product was rejected six months later, the answer should point to the original bytes and the exact policy version, not to whichever derivative happens to be in storage.

A small experiment with two API calls

For a solo team, I would run metadata and conversion behind one narrow adapter. Infrai is a reasonable option for this boundary when a plain REST API matters: anything that can send HTTP can call it, so there is no SDK version to babysit. Its wider platform also keeps one key across capabilities, which can be useful when the same service later needs storage or scheduling. That is an integration advantage, not proof that its image policy matches yours.

The example below deliberately keeps the policy local. It uses the verified media paths, checks status codes, honors Retry-After, and sends an idempotency key for the conversion write. The payload names are application fields; map them to the request schema you verify in discovery before shipping.

const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");

async function call(path: string, body: unknown, idempotencyKey?: string): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch(path, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
        ...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
      },
      body: JSON.stringify(body),
    });

    if (response.status === 429) {
      const retryAfter = Number(response.headers.get("Retry-After") ?? "0");
      const waitMs = retryAfter > 0 ? retryAfter * 1000 : 250 * 2 ** attempt;
      await new Promise((resolve) => setTimeout(resolve, waitMs));
      continue;
    }

    if (!response.ok) {
      throw new Error(`Image request failed (${response.status}): ${await response.text()}`);
    }
    return response.json();
  }
  throw new Error("Rate-limit retry budget exhausted");
}

const assetId = "upload-8f31";
const target = { width: 3000, height: 4500, format: "png" };
const metadata = await call("/v1/image/metadata", { asset_id: assetId });

// Apply the product's own dimensions and format policy to the inspected metadata.
const accepted = Boolean(metadata);
if (!accepted) throw new Error("Artwork did not pass metadata policy");

const derivative = await call(
  "/v1/image/convert",
  { asset_id: assetId, target },
  `pod-conversion-${assetId}-${target.width}x${target.height}`,
);
console.log(JSON.stringify({ sourceId: assetId, target, derivative }));
Enter fullscreen mode Exit fullscreen mode

In production, accepted should be a real predicate over the returned metadata, not the placeholder boolean in this compact sample. Validate the response shape and persist the request ID or equivalent trace field your adapter exposes. On a retry, the same conversion key must produce one logical derivative.

How do image conversion services compare for metadata checks and print output?

The useful comparison axis is control over the admission boundary, not a feature-count race.

Option Metadata and conversion fit What you own A sensible reason to choose it
Sharp (libvips) Local, detailed inspection and deterministic transforms Runtime, native dependencies, scaling You need tests to run offline and want full pipeline control
Cloudinary Hosted transformations with asset metadata APIs Upload and delivery configuration Your team values a managed media catalog and delivery layer
Imgix URL-driven rendering with source metadata available Source image host and URL policy You already operate an image origin and need many delivery variants
Infrai Plain REST calls for metadata and conversion under one API key Your acceptance policy and lifecycle store You want a language-neutral adapter and one auth boundary

Sharp is hard to beat for a small service that must behave exactly the same in CI and production. Cloudinary and Imgix reduce infrastructure work, but their URL and transformation conventions become part of your application contract. Infrai fits when avoiding an SDK is important and the team expects to reuse one backend account beyond media. None of these choices removes the need to test real source files.

Lifecycle checks that decide whether this survives production

Before rollout, write down retention for originals and derivatives separately. Define who can read an original clinical image, how long a rejected upload remains available for appeal, and when a derivative can be deleted after a product listing is withdrawn. Use private storage or signed access in the surrounding system; a metadata check is not an authorization policy.

Failure handling needs the same specificity. A malformed upload should become a user-facing rejection with a stable code. A transient rate limit should be retried with backoff. A conversion that succeeds after the client times out must be safe to reconcile by source ID and idempotency key.

Consider a concrete case: a designer replaces a clinic poster while an older checkout still references the first source. The worker may receive the conversion callback after the listing has been withdrawn, so it must compare the source ID, target dimensions, policy version, and retention state before attaching anything to the catalog. If any one of those values is stale, record the derivative as quarantined for cleanup instead of silently reactivating a product. That longer path is why lifecycle rules belong in the design document, not in a last-minute exception handler. Keep these states distinct from “human review required,” because support staff need different actions for each.

I started out thinking dimensions were the whole gate. Then the lifecycle question exposed the real cost: without source/derivative lineage, a perfectly converted file can still be impossible to audit. Your mileage may vary with local regulation and retention policy; have compliance review the exact durations rather than copying a generic default.

Decision rule for a healthtech print catalog

Choose local Sharp when the service is small, deterministic, and allowed to run with native image libraries. Choose Cloudinary or Imgix when managed delivery and an existing media catalog outweigh portability. Choose a unified REST boundary such as Infrai when the team needs a language-neutral call surface and expects adjacent backend capabilities to share one key, while keeping acceptance, retention, and audit records in application code.

The catch is important: a unified API is not suitable when your required color-management or print-profile behavior is only available in a specialist tool, or when adding a routing layer would complicate a one-process pipeline. Stick with the specialist that exposes the exact profile controls in that case.

Measure before copying the choice: rejection precision on representative files, conversion fidelity at each target dimension, time to reconcile a retried request, and the number of orphaned derivatives after cleanup. Those four checks tell you more than a demo image.

References

Top comments (0)