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/small-views-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@imgproxy/imgproxy-js-core": minor
---

Add [avifo](https://docs.imgproxy.net/latest/usage/processing#avif-options) option support
32 changes: 32 additions & 0 deletions src/options/avifOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { AvifOptions, AvifOptionsPartial } from "../types/avifOptions";
import { guardIsUndef, guardIsValidVal } from "../utils";

const correctOptions = {
auto: true,
on: true,
off: true,
};

const getOpt = (options: AvifOptionsPartial): AvifOptions | undefined =>
options.avif_options || options.avifo;

const test = (options: AvifOptionsPartial): boolean => Boolean(getOpt(options));

const build = (options: AvifOptionsPartial): string => {
const avifOptions = getOpt(options);
let subsample: string;

guardIsUndef(avifOptions, "avif_options");

if (typeof avifOptions === "string") {
subsample = avifOptions;
} else {
subsample = avifOptions.subsample;
}

guardIsValidVal(correctOptions, subsample, "avif_options");

return `avifo:${subsample}`;
};

export { test, build };
1 change: 1 addition & 0 deletions src/options/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * as adjust from "./adjust";
export * as autoquality from "./autoquality";
export * as autoRotate from "./autoRotate";
export * as avifOptions from "./avifOptions";
export * as background from "./background";
export * as backgroundAlpha from "./backgroundAlpha";
export * as blur from "./blur";
Expand Down
39 changes: 39 additions & 0 deletions src/types/avifOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Available AVIF subsample values:
* - `"auto"` - (default) use subsampling when the image is saved with quality less than 90
* - `"on"` - always apply subsampling
* - `"off"` - never apply subsampling
*/
type AvifSubsampleOptions = "auto" | "on" | "off";

/**
* *AVIF options*. **PRO feature**
*
* Allows redefining AVIF saving options.
*
* @default "auto"
*
* @see {@link https://docs.imgproxy.net/generating_the_url?id=avif-options | AVIF options imgproxy docs}
*/
type AvifOptions =
| AvifSubsampleOptions
| {
/**
* Controls when chroma subsampling is used. Default: `"auto"`
*/
subsample: AvifSubsampleOptions;
};

/**
* *AVIF options option*. **PRO feature**
*
* To describe the AVIF options option, you can use the keyword `avif_options` or `avifo`.
*
* @see https://docs.imgproxy.net/generating_the_url?id=avif-options
*/
interface AvifOptionsPartial {
avif_options?: AvifOptions;
avifo?: AvifOptions;
}

export { AvifOptions, AvifOptionsPartial };
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AdjustOptionsPartial } from "./adjust";
import type { AutoqualityOptionsPartial } from "./autoquality";
import type { AutoRotateOptionsPartial } from "./autoRotate";
import type { AvifOptionsPartial } from "./avifOptions";
import type { BackgroundOptionsPartial } from "./background";
import type { BackgroundAlphaOptionsPartial } from "./backgroundAlpha";
import type { BlurDetectionsOptionsPartial } from "./blurDetections";
Expand Down Expand Up @@ -80,6 +81,7 @@ import type { WildOptionsPartial } from "../typesShared/wildOptions";
export type Options = AdjustOptionsPartial &
AutoqualityOptionsPartial &
AutoRotateOptionsPartial &
AvifOptionsPartial &
BackgroundOptionsPartial &
BackgroundAlphaOptionsPartial &
BlurDetectionsOptionsPartial &
Expand Down
71 changes: 71 additions & 0 deletions tests/optionsBasic/avifOptions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { describe, expect, it } from "vitest";
import { test, build } from "../../src/options/avifOptions";

describe("avifOptions", () => {
describe("test", () => {
it("should return true if avif_options option is defined", () => {
expect(test({ avif_options: "auto" })).toEqual(true);
});

it("should return true if avifo option is defined", () => {
expect(test({ avifo: "on" })).toEqual(true);
});

it("should return false if avif_options option is undefined", () => {
expect(test({})).toEqual(false);
});
});

describe("build", () => {
it("should throw an error if avif_options is undefined", () => {
expect(() => build({})).toThrow("avif_options option is undefined");
});

it("should throw an error if avif_options is invalid", () => {
// @ts-expect-error: Let's ignore an error (check for users with vanilla js).
expect(() => build({ avif_options: "invalid" })).toThrow(
"avif_options option is invalid. Valid values are: auto, on, off"
);
});

it("should throw an error if avif_options is a number", () => {
// @ts-expect-error: Let's ignore an error (check for users with vanilla js).
expect(() => build({ avif_options: 1 })).toThrow(
"avif_options option is invalid. Valid values are: auto, on, off"
);
});

it("should return avifo:auto if avif_options is auto", () => {
expect(build({ avif_options: "auto" })).toEqual("avifo:auto");
});

it("should return avifo:on if avifo option is on", () => {
expect(build({ avifo: "on" })).toEqual("avifo:on");
});

it("should return avifo:off if avif_options is off", () => {
expect(build({ avif_options: "off" })).toEqual("avifo:off");
});

it("should support object notation with subsample property", () => {
expect(build({ avif_options: { subsample: "auto" } })).toEqual(
"avifo:auto"
);

expect(build({ avif_options: { subsample: "on" } })).toEqual("avifo:on");

expect(build({ avif_options: { subsample: "off" } })).toEqual(
"avifo:off"
);
});

it("should throw an error if subsample is invalid in object notation", () => {
expect(() =>
// @ts-expect-error: Let's ignore an error (check for users with vanilla js).
build({ avif_options: { subsample: "invalid" } })
).toThrow(
"avif_options option is invalid. Valid values are: auto, on, off"
);
});
});
});