Skip to content

Commit 19aa5c5

Browse files
committed
Add support for exif canonical_names option
1 parent 887dd39 commit 19aa5c5

4 files changed

Lines changed: 96 additions & 8 deletions

File tree

.changeset/exif-canonical-names.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@imgproxy/imgproxy-js-core": minor
3+
---
4+
5+
Add support for the `canonical_names` parameter of the `exif` image-info option. The `exif` option now also accepts an object `{ enabled, canonical_names }`; when `canonical_names` is `1`, `"t"`, or `true`, imgproxy returns EXIF field names in a canonical form (e.g. `DateTimeOriginal`) instead of the human-readable form. The existing boolean-style input is still supported.

src/optionsImageInfo/exif.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,27 @@ const getOpt = (options: ExifImageInfoOptionsPartial): Exif | undefined => {
1212
const test = (options: ExifImageInfoOptionsPartial): boolean =>
1313
getOpt(options) !== undefined;
1414

15+
const isExifObject = (
16+
value: Exclude<Exif, undefined>
17+
): value is Exclude<Exif, 1 | 0 | "t" | "f" | boolean | string> =>
18+
typeof value === "object" && value !== null;
19+
1520
const build = (options: ExifImageInfoOptionsPartial): string => {
1621
const exifOpts = getOpt(options);
1722
guardIsUndef(exifOpts, "EXIF");
18-
return `exif:${normalizeBoolean(exifOpts)}`;
23+
24+
if (!isExifObject(exifOpts)) {
25+
return `exif:${normalizeBoolean(exifOpts)}`;
26+
}
27+
28+
const { enabled, canonical_names } = exifOpts;
29+
const enabledPart = enabled !== undefined ? normalizeBoolean(enabled) : "t";
30+
31+
if (canonical_names === undefined) {
32+
return `exif:${enabledPart}`;
33+
}
34+
35+
return `exif:${enabledPart}:${normalizeBoolean(canonical_names)}`;
1936
};
2037

2138
export { test, build };

src/typesImageInfo/exif.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,36 @@
1+
/**
2+
* Boolean-like values for EXIF option fields.
3+
*
4+
* @note Only `1`, `"t"`, or `true` are recognized as truthy values.
5+
* Any other value (including `"true"` or `"1"` as strings) will be treated as false.
6+
*/
7+
type ExifBooleanValue = 1 | 0 | "t" | "f" | boolean | string;
8+
9+
/**
10+
* *EXIF option (object form)*
11+
*
12+
* @param {ExifBooleanValue} enabled - When set to `1`, `"t"` or `true`,
13+
* imgproxy will return the image’s EXIF metadata. Default: `true`.
14+
* @param {ExifBooleanValue} canonical_names - When set to `1`, `"t"` or `true`,
15+
* imgproxy will return the EXIF metadata field names in a canonical form
16+
* (e.g. `DateTimeOriginal`) instead of a human-readable form
17+
* (e.g. `Date and Time (Original)`). Default: `false`.
18+
*/
19+
interface ExifObject {
20+
enabled?: ExifBooleanValue;
21+
canonical_names?: ExifBooleanValue;
22+
}
23+
124
/**
225
* *EXIF option*
326
*
4-
* When set to `1`, `"t"` or `true`, imgproxy will return the image’s EXIF metadata.
27+
* When `enabled` is set to `1`, `"t"` or `true`, imgproxy will return the image’s EXIF metadata.
28+
* When `canonical_names` is set to `1`, `"t"` or `true`, imgproxy will return the EXIF
29+
* metadata field names in a canonical form (e.g. `DateTimeOriginal`) instead of a
30+
* human-readable form (e.g. `Date and Time (Original)`).
31+
*
32+
* Accepts a plain boolean-like value (controls `enabled` only) or an object
33+
* `{ enabled, canonical_names }`.
534
*
635
* @note If any value other than `1`, `"t"`, or `true` is passed, it will be recognized as `false`.
736
*
@@ -16,22 +45,22 @@
1645
* }
1746
* }
1847
*
19-
* @default true
48+
* @default true:false
2049
*
2150
*
22-
* @see {@link https://docs.imgproxy.net/getting_the_image_info?id=exif | EXIF imgproxy docs}
51+
* @see {@link https://docs.imgproxy.net/usage/getting_info#exif | EXIF imgproxy docs}
2352
*/
24-
type Exif = 1 | "t" | true | false | string;
53+
type Exif = ExifBooleanValue | ExifObject;
2554

2655
/**
2756
* *EXIF option*
2857
*
2958
* To describe the EXIF option, you can use the keyword `exif`.
3059
*
31-
* @see https://docs.imgproxy.net/getting_the_image_info?id=exif
60+
* @see https://docs.imgproxy.net/usage/getting_info#exif
3261
*/
3362
interface ExifImageInfoOptionsPartial {
3463
exif?: Exif;
3564
}
3665

37-
export { Exif, ExifImageInfoOptionsPartial };
66+
export { Exif, ExifObject, ExifBooleanValue, ExifImageInfoOptionsPartial };

tests/optionsImageInfo/exif.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ describe("EXIF", () => {
1111
expect(test({ exif: false })).toEqual(true);
1212
});
1313

14+
it("should return true if EXIF option is an object", () => {
15+
expect(test({ exif: { enabled: true } })).toEqual(true);
16+
});
17+
1418
it("should return false if EXIF option is undefined", () => {
1519
expect(test({})).toEqual(false);
1620
});
@@ -38,12 +42,45 @@ describe("EXIF", () => {
3842
});
3943

4044
it("should return 'f' if EXIF option is 0", () => {
41-
// @ts-expect-error: Let's ignore an error.
4245
expect(build({ exif: 0 })).toEqual("exif:f");
4346
});
4447

4548
it("should return 'f' if EXIF option is string (except 't')", () => {
4649
expect(build({ exif: "true" })).toEqual("exif:f");
4750
});
51+
52+
it("should return 'exif:t' if EXIF option is an object with enabled=true", () => {
53+
expect(build({ exif: { enabled: true } })).toEqual("exif:t");
54+
});
55+
56+
it("should return 'exif:f' if EXIF option is an object with enabled=false", () => {
57+
expect(build({ exif: { enabled: false } })).toEqual("exif:f");
58+
});
59+
60+
it("should default enabled to 't' if only canonical_names is passed", () => {
61+
expect(build({ exif: { canonical_names: true } })).toEqual("exif:t:t");
62+
});
63+
64+
it("should return 'exif:t:t' if both fields are true", () => {
65+
expect(build({ exif: { enabled: true, canonical_names: true } })).toEqual(
66+
"exif:t:t"
67+
);
68+
});
69+
70+
it("should return 'exif:f:t' if enabled=false and canonical_names=true", () => {
71+
expect(
72+
build({ exif: { enabled: false, canonical_names: true } })
73+
).toEqual("exif:f:t");
74+
});
75+
76+
it("should return 'exif:t:f' if enabled=true and canonical_names=false", () => {
77+
expect(
78+
build({ exif: { enabled: true, canonical_names: false } })
79+
).toEqual("exif:t:f");
80+
});
81+
82+
it("should return 'exif:t' for an empty object", () => {
83+
expect(build({ exif: {} })).toEqual("exif:t");
84+
});
4885
});
4986
});

0 commit comments

Comments
 (0)