u
This commit is contained in:
@@ -146,7 +146,7 @@ Backend mapping:
|
|||||||
| `updateBySku` | `(googleAuthId, sku, { name })` | same shape as `getBySku` |
|
| `updateBySku` | `(googleAuthId, sku, { name })` | same shape as `getBySku` |
|
||||||
| `addImage` | `(googleAuthId, sku, imageBuffer)` | image result (see below) |
|
| `addImage` | `(googleAuthId, sku, imageBuffer)` | image result (see below) |
|
||||||
|
|
||||||
`addImage` accepts a full-size AVIF `Buffer`, scales to max 1000×1000 (`pic.binary`) and 200×200 (`pic.thumbbinary`) via `sharp`, computes `hash` / `thumbhash`, links `articlepic`. Auth like `getBySku`. Errors: `Article not found`, `Not authorized`.
|
`addImage` accepts a full-size AVIF `Buffer`. Full image: if already AVIF and ≤1000×1000, stored as-is; otherwise scaled to max 1000×1000 (`pic.binary`). Thumb always scaled to max 200×200 (`pic.thumbbinary`) via `sharp`. Computes `hash` / `thumbhash`, links `articlepic`. Auth like `getBySku`. Errors: `Article not found`, `Not authorized`.
|
||||||
|
|
||||||
`addImage` returns:
|
`addImage` returns:
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ Backend mapping:
|
|||||||
{
|
{
|
||||||
picId,
|
picId,
|
||||||
sort,
|
sort,
|
||||||
full: { w, h, size }, // scaled AVIF, max 1000×1000 (fit inside)
|
full: { w, h, size }, // AVIF, max 1000×1000 (stored as-is when already AVIF and within bounds)
|
||||||
thumb: { w, h }, // scaled AVIF, max 200×200 (fit inside)
|
thumb: { w, h }, // scaled AVIF, max 200×200 (fit inside)
|
||||||
hash, // SHA-256 hex of full image bytes
|
hash, // SHA-256 hex of full image bytes
|
||||||
thumbHash, // base64 thumbhash of thumb preview
|
thumbHash, // base64 thumbhash of thumb preview
|
||||||
|
|||||||
@@ -10,16 +10,37 @@ export default async function processAvifImage(inputBuffer) {
|
|||||||
? inputBuffer
|
? inputBuffer
|
||||||
: Buffer.from(inputBuffer);
|
: Buffer.from(inputBuffer);
|
||||||
|
|
||||||
|
const meta = await sharp(input).metadata();
|
||||||
|
const w = meta.width ?? 0;
|
||||||
|
const h = meta.height ?? 0;
|
||||||
|
const isAvif =
|
||||||
|
meta.format === 'avif' ||
|
||||||
|
(meta.format === 'heif' && meta.compression === 'av1');
|
||||||
|
const useOriginalFull =
|
||||||
|
isAvif && w > 0 && h > 0 && w <= FULL_MAX && h <= FULL_MAX;
|
||||||
|
|
||||||
|
if (!useOriginalFull) {
|
||||||
|
console.log(
|
||||||
|
`processAvifImage: converting full image (format=${meta.format ?? 'unknown'}, ${w}×${h}, avif=${isAvif})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const thumbPipeline = sharp(input)
|
||||||
|
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
||||||
|
|
||||||
const [full, thumb, thumbRgba] = await Promise.all([
|
const [full, thumb, thumbRgba] = await Promise.all([
|
||||||
sharp(input)
|
useOriginalFull
|
||||||
|
? Promise.resolve({
|
||||||
|
info: { width: w, height: h },
|
||||||
|
data: input,
|
||||||
|
})
|
||||||
|
: sharp(input)
|
||||||
.resize(FULL_MAX, FULL_MAX, { fit: 'inside', withoutEnlargement: true })
|
.resize(FULL_MAX, FULL_MAX, { fit: 'inside', withoutEnlargement: true })
|
||||||
.avif({ effort: 4 })
|
.avif({ effort: 4 })
|
||||||
.toBuffer({ resolveWithObject: true }),
|
.toBuffer({ resolveWithObject: true }),
|
||||||
sharp(input)
|
thumbPipeline.clone().avif({ effort: 4 }).toBuffer({ resolveWithObject: true }),
|
||||||
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true })
|
thumbPipeline
|
||||||
.avif({ effort: 4 })
|
.clone()
|
||||||
.toBuffer({ resolveWithObject: true }),
|
|
||||||
sharp(input)
|
|
||||||
.resize(100, 100, { fit: 'inside', withoutEnlargement: true })
|
.resize(100, 100, { fit: 'inside', withoutEnlargement: true })
|
||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.raw()
|
.raw()
|
||||||
|
|||||||
Reference in New Issue
Block a user