Files
llink/js/desktop/src/lib/avatar-image.ts
T
Arjun PatelGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
4facc6b371 feat: avatars for humans (#273)
* implement avatar backend functionality

* add avatar endpoints

* typo

* implement client side avatar upload and handling

* fixes

* Update go/internal/handler/handler.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update js/desktop/src/lib/avatar-image.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* bug in order

* remove unused component

* fix invalid migration

* fix syntax errors

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-06-11 15:30:21 -07:00

37 lines
1.3 KiB
TypeScript

/**
* Center-crop an image source to a square and downscale it to a JPEG suitable
* for an avatar. Avatars never render larger than ~80px, so 512px is generous
* headroom while keeping the upload to a few tens of KB regardless of input.
*
* Pass `mirror` when capturing from a (mirrored) webcam preview so the saved
* image matches what the user saw.
*/
export async function toAvatarBlob(
source: ImageBitmap,
{ size = 512, mirror = false }: { size?: number; mirror?: boolean } = {},
): Promise<Blob> {
if (!Number.isInteger(size) || size <= 0) {
throw new Error('Avatar size must be a positive integer');
}
const side = Math.min(source.width, source.height);
if (side === 0) {
// A not-yet-decoded <video> or a corrupt image yields a zero-size source;
// cropping it would silently produce a blank avatar, so fail instead.
throw new Error('Image source has zero dimensions');
}
const sx = (source.width - side) / 2;
const sy = (source.height - side) / 2;
const canvas = new OffscreenCanvas(size, size);
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Failed to acquire 2D canvas context');
if (mirror) {
ctx.translate(size, 0);
ctx.scale(-1, 1);
}
ctx.drawImage(source, sx, sy, side, side, 0, 0, size, size);
return canvas.convertToBlob({ type: 'image/jpeg', quality: 0.82 });
}