Skip to content

Commit

Permalink
feat(imago): add suport for cropping with aspect ratio
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Mar 1, 2024
1 parent ad59ce3 commit 2b3db06
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
16 changes: 16 additions & 0 deletions packages/imago/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,22 @@ export interface TextLayer extends CompLayer {

export interface CropSpec extends ProcSpec {
op: "crop";
/**
* Target aspect ratio. Only used if {@link CropSpec.size} is given as
* single numeric value (pixels or percentage). If the aspect ratio is >1,
* the general aspect of the cropped image will remain principally the same,
* i.e. a portait image will remain portait (but cropped), ditto for
* landscape. If the given aspect raatio is <1, the aspect of the image will
* be flipped/swapped, i.e. a portait aspect becomes landscape and vice
* versa.
*
* @example
* ```js
* // crop image to 3:2 aspect ratio
* { op: "crop", size: 100, unit: "%", aspect: 3/2 }
* ```
*/
aspect?: number;
border?: Size | Sides;
gravity?: Gravity;
origin?: Gravity;
Expand Down
15 changes: 12 additions & 3 deletions packages/imago/src/ops/crop.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { isNumber } from "@thi.ng/checks";
import { illegalArgs } from "@thi.ng/errors";
import type { CropSpec, Processor } from "../api.js";
import type { CropSpec, Dim, Processor } from "../api.js";
import {
computeMargins,
computeSize,
computeSizeWithAspect,
gravityPosition,
positionOrGravity,
} from "../units.js";

export const cropProc: Processor = async (spec, input, ctx) => {
const { border, gravity, pos, size, ref, unit } = <CropSpec>spec;
const { aspect, border, gravity, pos, size, ref, unit } = <CropSpec>spec;
if (border == null && size == null)
illegalArgs("require `border` or `size` option");
if (border != null) {
Expand All @@ -24,7 +26,14 @@ export const cropProc: Processor = async (spec, input, ctx) => {
true,
];
}
const $size = computeSize(size!, ctx.size, ref, unit);
let $size: Dim;
if (aspect != undefined) {
if (!isNumber(size))
illegalArgs("size must be numeric if aspect is used");
$size = computeSizeWithAspect(size, ctx.size, aspect, unit);
} else {
$size = computeSize(size!, ctx.size, ref, unit);
}
let left = 0,
top = 0;
if (pos) {
Expand Down
24 changes: 24 additions & 0 deletions packages/imago/src/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,30 @@ export const computeSize = (
return res;
};

export const computeSizeWithAspect = (
size: number,
[w, h]: Dim,
aspect: number,
unit: SizeUnit = "px",
clamp = true
): Dim => {
const origAspect = w / h;
const min = Math.min(w, h);
const max = Math.max(w, h);
let res: Dim;
if (unit === "%") {
size = (size / 100) * max;
}
if (clamp) {
size = Math.min(size, max);
if (size / aspect > min) size = min * aspect;
}
res = origAspect > 1 ? [size, size / aspect] : [size / aspect, size];
res[0] = round(res[0]);
res[1] = round(res[1]);
return res;
};

export const computeMargins = (
size: Size | Sides,
curr: Dim,
Expand Down

0 comments on commit 2b3db06

Please sign in to comment.