Skip to content

image centering #6

@macrozone

Description

@macrozone

idea from chatgpt:

import OpenAI from "openai";
import { z } from "zod";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const CropSchema = z.object({
  focalPoint: z.object({ x: z.number(), y: z.number() }) // normalized [0..1]
    .describe("Where to center the crop, e.g. main face/action."),
  regions: z.array(z.object({
    label: z.string(),
    confidence: z.number(),
    box: z.object({ x: z.number(), y: z.number(), w: z.number(), h: z.number() }) // normalized [0..1]
  })).max(5)
});

export async function getSmartCropHints(imageUrl: string) {
  const resp = await client.responses.create({
    model: "gpt-4o-mini",
    input: [
      {
        role: "user",
        content: [
          { type: "input_text", text:
            "Find the most interesting subject(s) to preserve in a crop. " +
            "Return a normalized focalPoint and up to 5 bounding boxes with labels. " +
            "Prefer faces, people, logos, text, hands/tools, or strong action. " +
            "If multiple, choose the one that best represents the photo." },
          { type: "input_image", image_url: imageUrl }
        ]
      }
    ],
    // Structured output (JSON Schema) — validated locally with Zod:
    response_format: { type: "json_schema", json_schema: { name: "CropHints", schema: CropSchema } }
  });

  const data = CropSchema.parse(resp.output[0].content[0].json);
  return data;
}

// Example: compute a crop rect (in pixels) for a target aspect ratio
export function computeCropRect(
  imgW: number, imgH: number,
  focal: {x:number;y:number},  // normalized
  aspect: number                // e.g. 1.0 for square, 16/9, 4/5, etc.
) {
  // pick max size that fits image and keeps aspect, centered on focal point
  let cropW = imgW, cropH = Math.round(imgW / aspect);
  if (cropH > imgH) { cropH = imgH; cropW = Math.round(imgH * aspect); }

  let cx = Math.round(focal.x * imgW);
  let cy = Math.round(focal.y * imgH);

  let x = Math.round(cx - cropW / 2);
  let y = Math.round(cy - cropH / 2);

  // clamp to image bounds
  x = Math.max(0, Math.min(x, imgW - cropW));
  y = Math.max(0, Math.min(y, imgH - cropH));

  return { x, y, w: cropW, h: cropH };
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions