Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/full-plums-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"unpic": minor
---

feat(ipx): improve ipx provider typing and test coverage
48 changes: 48 additions & 0 deletions src/providers/ipx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ Deno.test("ipx extract", async (t) => {
format: "webp",
});
});

await t.step("should extract crop with URL-encoded underscores", () => {
const url = `${baseURL}/crop_100%5F50%5F300%5F200,f_auto/images/test.jpg`;
const result = extract(url);
assertEquals(result?.src, "/images/test.jpg");
assertEquals(result?.operations.crop, "100_50_300_200");
});

await t.step("should extract fit and position", () => {
const url =
`${baseURL}/s_800x600,fit_cover,position_top,f_auto/images/test.jpg`;
const result = extract(url);
assertEquals(result?.operations.fit, "cover");
assertEquals(result?.operations.position, "top");
});
});

Deno.test("ipx generate", async (t) => {
Expand Down Expand Up @@ -139,3 +154,36 @@ Deno.test("ipx transform", async (t) => {
);
});
});

Deno.test("ipx generate with extended operations", async (t) => {
await t.step("should generate URL with crop", () => {
const result = generate(
img,
{ width: 800, height: 600, crop: "100_50_300_200" },
{ baseURL },
);
assertEquals(result.includes("crop_100%5F50%5F300%5F200"), true);
assertEquals(result.includes("s_800x600"), true);
});

await t.step("should generate URL with fit and position", () => {
const result = generate(
img,
{ width: 800, height: 600, fit: "cover", position: "top" },
{ baseURL },
);
assertEquals(result.includes("fit_cover"), true);
assertEquals(result.includes("position_top"), true);
});

await t.step("should generate URL with effects", () => {
const result = generate(
img,
{ width: 300, rotate: 90, blur: 5, grayscale: true },
{ baseURL },
);
assertEquals(result.includes("rotate_90"), true);
assertEquals(result.includes("blur_5"), true);
assertEquals(result.includes("grayscale_true"), true);
});
});
72 changes: 72 additions & 0 deletions src/providers/ipx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,78 @@ export interface IPXOperations extends Operations {
* Output format of the image.
*/
f?: ImageFormat | "auto";

/**
* Resize fit mode. Only applies when both width and height are specified.
*/
fit?: "contain" | "cover" | "fill" | "inside" | "outside";

/**
* Position/gravity for resize. Only applies when both width and height are specified.
* @example "top"
*/
position?: string;

/**
* Alias for position.
*/
pos?: string;

/**
* Extract/crop a region of the image.
* Format: "left_top_width_height"
* @example "100_50_300_200"
*/
extract?: string;

/**
* Alias for extract.
*/
crop?: string;

/**
* Rotation angle in degrees.
* @example 90
*/
rotate?: number;

/**
* Flip image vertically.
*/
flip?: boolean;

/**
* Flip image horizontally.
*/
flop?: boolean;

/**
* Blur sigma value.
* @example 5
*/
blur?: number;

/**
* Sharpen sigma value.
* @example 30
*/
sharpen?: number;

/**
* Convert to grayscale.
*/
grayscale?: boolean;

/**
* Background color (hex without #).
* @example "ff0000"
*/
background?: string;

/**
* Alias for background.
*/
b?: string;
}

export interface IPXOptions {
Expand Down