u
This commit is contained in:
@@ -32,7 +32,7 @@ Adds a child article to a parent article (creates and attaches with auto-generat
|
|||||||
|
|
||||||
*Source: `src/store/article/addImage.js`*
|
*Source: `src/store/article/addImage.js`*
|
||||||
|
|
||||||
Adds an image to an article by its SKU, processing it into AVIF variants.
|
Adds an image to an article by its SKU, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
@@ -45,13 +45,13 @@ Adds an image to an article by its SKU, processing it into AVIF variants.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, fullHash: string, thumbHash: string}>` — The added image info.
|
`Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, smallThumb: {w: number, h: number}, fullHash: string, thumbHash: string}>` — The added image info.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const result = await store.article.addImage(42, 'SKU-1', imageBuffer);
|
const result = await store.article.addImage(42, 'SKU-1', imageBuffer);
|
||||||
// => { picId, sort, full: { w, h, size }, thumb: { w, h }, fullHash, thumbHash }
|
// => { picId, sort, full: { w, h, size }, thumb: { w, h }, smallThumb: { w, h }, fullHash, thumbHash }
|
||||||
```
|
```
|
||||||
|
|
||||||
## `article.attachChild`
|
## `article.attachChild`
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ This document is auto-generated from the JSDoc comments in `src/store` by runnin
|
|||||||
|
|
||||||
*Source: `src/store/brand/addImage.js`*
|
*Source: `src/store/brand/addImage.js`*
|
||||||
|
|
||||||
Adds an image to a brand, processing it into AVIF full and thumb variants.
|
Adds an image to a brand, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Adds an image to a brand, processing it into AVIF full and thumb variants.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array<object>}>`
|
`Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number, pics: Array<object>}>`
|
||||||
|
|
||||||
## `brand.create`
|
## `brand.create`
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ This document is auto-generated from the JSDoc comments in `src/store` by runnin
|
|||||||
|
|
||||||
*Source: `src/store/category/addImage.js`*
|
*Source: `src/store/category/addImage.js`*
|
||||||
|
|
||||||
Adds an image to a category, processing it into AVIF full and thumb variants.
|
Adds an image to a category, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Adds an image to a category, processing it into AVIF full and thumb variants.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>` — The added image info.
|
`Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number}>` — The added image info.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
|
|||||||
6
API.md
6
API.md
@@ -74,7 +74,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `list(googleAuthId: number, tx?: object): Promise<Array<object>>`
|
- `list(googleAuthId: number, tx?: object): Promise<Array<object>>`
|
||||||
- `update(id: number, input: {iso639: string, name: string, taxrate: number, reducedtaxrate: number}, tx?: object): Promise<{id: number, rootCategoryId: number, languageId: number, taxrateId: number, reducedtaxrateId: number, taxfreerateId: number}>`
|
- `update(id: number, input: {iso639: string, name: string, taxrate: number, reducedtaxrate: number}, tx?: object): Promise<{id: number, rootCategoryId: number, languageId: number, taxrateId: number, reducedtaxrateId: number, taxfreerateId: number}>`
|
||||||
- [category](API.category.md)
|
- [category](API.category.md)
|
||||||
- `addImage(googleAuthId: number, categoryId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>`
|
- `addImage(googleAuthId: number, categoryId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number}>`
|
||||||
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string}, tx?: object): Promise<{id: number, parentId: number, sort: number, name: string, slug: string}>`
|
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string}, tx?: object): Promise<{id: number, parentId: number, sort: number, name: string, slug: string}>`
|
||||||
- `delete(input: {googleAuthId: number, id: number, recursive?: boolean}, tx?: object): Promise<void>`
|
- `delete(input: {googleAuthId: number, id: number, recursive?: boolean}, tx?: object): Promise<void>`
|
||||||
- `deleteImage(googleAuthId: number, categoryId: number, tx?: object): Promise<{id: number, thumbW: null, thumbH: null, thumbHash: null}>`
|
- `deleteImage(googleAuthId: number, categoryId: number, tx?: object): Promise<{id: number, thumbW: null, thumbH: null, thumbHash: null}>`
|
||||||
@@ -86,7 +86,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `rename(input: {googleAuthId: number, id: number, name: string}, tx?: object): Promise<{id: number, name: string, slug: string}>`
|
- `rename(input: {googleAuthId: number, id: number, name: string}, tx?: object): Promise<{id: number, name: string, slug: string}>`
|
||||||
- [article](API.article.md)
|
- [article](API.article.md)
|
||||||
- `addChild(googleAuthId: number, parentSku: string, options: {attach?: boolean, attributeValueId?: number, value?: string, name?: string, unitamount?: number, weight?: number, track_stock?: boolean|number}, tx?: object): Promise<object>`
|
- `addChild(googleAuthId: number, parentSku: string, options: {attach?: boolean, attributeValueId?: number, value?: string, name?: string, unitamount?: number, weight?: number, track_stock?: boolean|number}, tx?: object): Promise<object>`
|
||||||
- `addImage(googleAuthId: number, sku: string, image: Buffer, tx?: object): Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, fullHash: string, thumbHash: string}>`
|
- `addImage(googleAuthId: number, sku: string, image: Buffer, tx?: object): Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, smallThumb: {w: number, h: number}, fullHash: string, thumbHash: string}>`
|
||||||
- `attachChild(googleAuthId: number, parentSku: string, options: {sku: string, childSku?: string, attributeValueId?: number, value?: string, reparent?: boolean, unitamount?: number, weight?: number, track_stock?: boolean|number}, tx?: object): Promise<{article: object, children: Array<object>}>`
|
- `attachChild(googleAuthId: number, parentSku: string, options: {sku: string, childSku?: string, attributeValueId?: number, value?: string, reparent?: boolean, unitamount?: number, weight?: number, track_stock?: boolean|number}, tx?: object): Promise<{article: object, children: Array<object>}>`
|
||||||
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string, desc?: string, seo?: string, track_stock?: boolean|number}, tx?: object): Promise<{id: number, parentId: number, name: string, sku: string, track_stock: boolean}>`
|
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string, desc?: string, seo?: string, track_stock?: boolean|number}, tx?: object): Promise<{id: number, parentId: number, name: string, sku: string, track_stock: boolean}>`
|
||||||
- `delete(googleAuthId: number, sku: string, optionsOrTx?: object|*, maybeTx?: object): Promise<void>`
|
- `delete(googleAuthId: number, sku: string, optionsOrTx?: object|*, maybeTx?: object): Promise<void>`
|
||||||
@@ -129,7 +129,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `list(googleAuthId: number, options?: {frontendOnly?: boolean, maskWriteonly?: boolean}, tx?: object): Promise<Array<{key: string, value: string, frontend: boolean, writeonly: boolean}>>`
|
- `list(googleAuthId: number, options?: {frontendOnly?: boolean, maskWriteonly?: boolean}, tx?: object): Promise<Array<{key: string, value: string, frontend: boolean, writeonly: boolean}>>`
|
||||||
- `set(googleAuthId: number, input: {key: string, value: string, frontend?: boolean, writeonly?: boolean}, tx?: object): Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}>`
|
- `set(googleAuthId: number, input: {key: string, value: string, frontend?: boolean, writeonly?: boolean}, tx?: object): Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}>`
|
||||||
- [brand](API.brand.md)
|
- [brand](API.brand.md)
|
||||||
- `addImage(googleAuthId: number, brandId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array<object>}>`
|
- `addImage(googleAuthId: number, brandId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number, pics: Array<object>}>`
|
||||||
- `create(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
- `create(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
||||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||||
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number}, tx?: object): Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>, total: number, offset: number, limit: number}>`
|
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number}, tx?: object): Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>, total: number, offset: number, limit: number}>`
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ async function runTests() {
|
|||||||
assert(existsSync(join(storageDir, 'fullbinary')), 'fullbinary dir should exist');
|
assert(existsSync(join(storageDir, 'fullbinary')), 'fullbinary dir should exist');
|
||||||
assert(existsSync(join(storageDir, 'thumbbinary')), 'thumbbinary dir should exist');
|
assert(existsSync(join(storageDir, 'thumbbinary')), 'thumbbinary dir should exist');
|
||||||
|
|
||||||
// Verify sqlite tables do NOT contain blob columns
|
// Large file and image blobs stay on disk; the 40px small-thumb stays inline in pic.
|
||||||
const fileTableInfo = provider.db.pragma('table_info("file")');
|
const fileTableInfo = provider.db.pragma('table_info("file")');
|
||||||
const fileColNames = fileTableInfo.map((c) => c.name);
|
const fileColNames = fileTableInfo.map((c) => c.name);
|
||||||
console.log('file table columns:', fileColNames);
|
console.log('file table columns:', fileColNames);
|
||||||
@@ -40,6 +40,9 @@ async function runTests() {
|
|||||||
console.log('pic table columns:', picColNames);
|
console.log('pic table columns:', picColNames);
|
||||||
assert(!picColNames.includes('fullbinary'), 'pic table should NOT have fullbinary column');
|
assert(!picColNames.includes('fullbinary'), 'pic table should NOT have fullbinary column');
|
||||||
assert(!picColNames.includes('thumbbinary'), 'pic table should NOT have thumbbinary column');
|
assert(!picColNames.includes('thumbbinary'), 'pic table should NOT have thumbbinary column');
|
||||||
|
assert(picColNames.includes('smallthumbw'), 'pic table should have smallthumbw column');
|
||||||
|
assert(picColNames.includes('smallthumbh'), 'pic table should have smallthumbh column');
|
||||||
|
assert(picColNames.includes('smallthumbbinary'), 'pic table should have smallthumbbinary column');
|
||||||
|
|
||||||
// Setup base data: google_auth, company, unit, article, manifest
|
// Setup base data: google_auth, company, unit, article, manifest
|
||||||
const googleAuthId = await store.google_auth.add('test@example.com');
|
const googleAuthId = await store.google_auth.add('test@example.com');
|
||||||
@@ -199,6 +202,18 @@ async function runTests() {
|
|||||||
|
|
||||||
const picResult = await store.article.addImage(googleAuthId, article.sku, sampleImage);
|
const picResult = await store.article.addImage(googleAuthId, article.sku, sampleImage);
|
||||||
const fullHash = picResult.fullHash;
|
const fullHash = picResult.fullHash;
|
||||||
|
assert.equal(picResult.smallThumb.w, 40);
|
||||||
|
assert.equal(picResult.smallThumb.h, 27);
|
||||||
|
const smallThumbRow = provider.db.prepare(
|
||||||
|
'SELECT smallthumbw, smallthumbh, smallthumbbinary FROM pic WHERE hash = ?',
|
||||||
|
).get(fullHash);
|
||||||
|
assert.equal(smallThumbRow.smallthumbw, 40);
|
||||||
|
assert.equal(smallThumbRow.smallthumbh, 27);
|
||||||
|
assert(Buffer.isBuffer(smallThumbRow.smallthumbbinary), 'Small thumb AVIF must be stored in the pic row');
|
||||||
|
const smallThumbMetadata = await sharp(smallThumbRow.smallthumbbinary).metadata();
|
||||||
|
assert.equal(smallThumbMetadata.format, 'heif');
|
||||||
|
assert.equal(smallThumbMetadata.width, 40);
|
||||||
|
assert.equal(smallThumbMetadata.height, 27);
|
||||||
console.log('Article pic added with hash:', fullHash);
|
console.log('Article pic added with hash:', fullHash);
|
||||||
|
|
||||||
const fullPath = join(storageDir, 'fullbinary', fullHash + '.avif');
|
const fullPath = join(storageDir, 'fullbinary', fullHash + '.avif');
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
export const CREATE = `
|
export const CREATE = `
|
||||||
INSERT INTO pic (
|
INSERT INTO pic (
|
||||||
w, h, size, hash, thumbw, thumbh, thumbhash, source, fullbinary, thumbbinary
|
w, h, size, hash, thumbw, thumbh, thumbhash,
|
||||||
|
smallthumbw, smallthumbh, smallthumbbinary,
|
||||||
|
source, fullbinary, thumbbinary
|
||||||
)
|
)
|
||||||
OUTPUT INSERTED.id
|
OUTPUT INSERTED.id
|
||||||
VALUES (
|
VALUES (
|
||||||
@w, @h, @size, @hash, @thumbw, @thumbh, @thumbhash, @source, @fullbinary, @thumbbinary
|
@w, @h, @size, @hash, @thumbw, @thumbh, @thumbhash,
|
||||||
|
@smallthumbw, @smallthumbh, @smallthumbbinary,
|
||||||
|
@source, @fullbinary, @thumbbinary
|
||||||
)
|
)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -95,9 +95,12 @@ BEGIN
|
|||||||
thumbw INT NOT NULL,
|
thumbw INT NOT NULL,
|
||||||
thumbh INT NOT NULL,
|
thumbh INT NOT NULL,
|
||||||
thumbhash NVARCHAR(64) NOT NULL,
|
thumbhash NVARCHAR(64) NOT NULL,
|
||||||
|
smallthumbw INT NOT NULL,
|
||||||
|
smallthumbh INT NOT NULL,
|
||||||
source NVARCHAR(MAX) NOT NULL,
|
source NVARCHAR(MAX) NOT NULL,
|
||||||
fullbinary VARBINARY(MAX) NOT NULL,
|
fullbinary VARBINARY(MAX) NOT NULL,
|
||||||
thumbbinary VARBINARY(MAX) NOT NULL,
|
thumbbinary VARBINARY(MAX) NOT NULL,
|
||||||
|
smallthumbbinary VARBINARY(MAX) NOT NULL,
|
||||||
CONSTRAINT UQ_pic_hash UNIQUE (hash)
|
CONSTRAINT UQ_pic_hash UNIQUE (hash)
|
||||||
);
|
);
|
||||||
END
|
END
|
||||||
@@ -1220,4 +1223,3 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_SHIPPING,
|
INIT_SHIPPING,
|
||||||
INIT_PACKAGE,
|
INIT_PACKAGE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ export const {
|
|||||||
|
|
||||||
export const CREATE = `
|
export const CREATE = `
|
||||||
INSERT INTO pic (
|
INSERT INTO pic (
|
||||||
w, h, size, hash, thumbw, thumbh, thumbhash, source
|
w, h, size, hash, thumbw, thumbh, thumbhash,
|
||||||
|
smallthumbw, smallthumbh, smallthumbbinary, source
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
@w, @h, @size, @hash, @thumbw, @thumbh, @thumbhash, @source
|
@w, @h, @size, @hash, @thumbw, @thumbh, @thumbhash,
|
||||||
|
@smallthumbw, @smallthumbh, @smallthumbbinary, @source
|
||||||
)
|
)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ CREATE TABLE IF NOT EXISTS pic (
|
|||||||
thumbw INTEGER NOT NULL,
|
thumbw INTEGER NOT NULL,
|
||||||
thumbh INTEGER NOT NULL,
|
thumbh INTEGER NOT NULL,
|
||||||
thumbhash TEXT NOT NULL,
|
thumbhash TEXT NOT NULL,
|
||||||
|
smallthumbw INTEGER NOT NULL,
|
||||||
|
smallthumbh INTEGER NOT NULL,
|
||||||
|
smallthumbbinary BLOB NOT NULL,
|
||||||
source TEXT NOT NULL
|
source TEXT NOT NULL
|
||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -22,17 +22,17 @@ export default function addImage(provider) {
|
|||||||
const addArticlePicSql = isSqlite ? SQLITE_ADD_ARTICLEPIC : MSSQL_ADD_ARTICLEPIC;
|
const addArticlePicSql = isSqlite ? SQLITE_ADD_ARTICLEPIC : MSSQL_ADD_ARTICLEPIC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an image to an article by its SKU, processing it into AVIF variants.
|
* Adds an image to an article by its SKU, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {string} sku - The article SKU.
|
* @param {string} sku - The article SKU.
|
||||||
* @param {Buffer} image - The source image buffer.
|
* @param {Buffer} image - The source image buffer.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, fullHash: string, thumbHash: string}>} The added image info.
|
* @returns {Promise<{picId: number, sort: number, full: {w: number, h: number, size: number}, thumb: {w: number, h: number}, smallThumb: {w: number, h: number}, fullHash: string, thumbHash: string}>} The added image info.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const result = await store.article.addImage(42, 'SKU-1', imageBuffer);
|
* const result = await store.article.addImage(42, 'SKU-1', imageBuffer);
|
||||||
* // => { picId, sort, full: { w, h, size }, thumb: { w, h }, fullHash, thumbHash }
|
* // => { picId, sort, full: { w, h, size }, thumb: { w, h }, smallThumb: { w, h }, fullHash, thumbHash }
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, sku, image, tx) => {
|
return async (googleAuthId, sku, image, tx) => {
|
||||||
const runAdd = async (runner) => {
|
const runAdd = async (runner) => {
|
||||||
@@ -71,6 +71,9 @@ export default function addImage(provider) {
|
|||||||
thumbw: processed.thumb.w,
|
thumbw: processed.thumb.w,
|
||||||
thumbh: processed.thumb.h,
|
thumbh: processed.thumb.h,
|
||||||
thumbhash: processed.thumb.hash,
|
thumbhash: processed.thumb.hash,
|
||||||
|
smallthumbw: processed.smallThumb.w,
|
||||||
|
smallthumbh: processed.smallThumb.h,
|
||||||
|
smallthumbbinary: processed.smallThumb.buffer,
|
||||||
source: '',
|
source: '',
|
||||||
fullbinary: processed.full.buffer,
|
fullbinary: processed.full.buffer,
|
||||||
thumbbinary: processed.thumb.buffer,
|
thumbbinary: processed.thumb.buffer,
|
||||||
@@ -107,6 +110,10 @@ export default function addImage(provider) {
|
|||||||
w: processed.thumb.w,
|
w: processed.thumb.w,
|
||||||
h: processed.thumb.h,
|
h: processed.thumb.h,
|
||||||
},
|
},
|
||||||
|
smallThumb: {
|
||||||
|
w: processed.smallThumb.w,
|
||||||
|
h: processed.smallThumb.h,
|
||||||
|
},
|
||||||
fullHash,
|
fullHash,
|
||||||
thumbHash: processed.thumb.hash,
|
thumbHash: processed.thumb.hash,
|
||||||
};
|
};
|
||||||
@@ -121,4 +128,3 @@ export default function addImage(provider) {
|
|||||||
return runAdd(makeRunner(provider));
|
return runAdd(makeRunner(provider));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ export default function addImage(provider) {
|
|||||||
const addBrandPicSql = isSqlite ? SQLITE_ADD_BRANDPIC : MSSQL_ADD_BRANDPIC;
|
const addBrandPicSql = isSqlite ? SQLITE_ADD_BRANDPIC : MSSQL_ADD_BRANDPIC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an image to a brand, processing it into AVIF full and thumb variants.
|
* Adds an image to a brand, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {number} brandId - The id of the brand.
|
* @param {number} brandId - The id of the brand.
|
||||||
* @param {Buffer} image - The source image buffer.
|
* @param {Buffer} image - The source image buffer.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array<object>}>}
|
* @returns {Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number, pics: Array<object>}>}
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, brandId, image, tx) => {
|
return async (googleAuthId, brandId, image, tx) => {
|
||||||
const runAdd = async (runner) => {
|
const runAdd = async (runner) => {
|
||||||
@@ -69,6 +69,9 @@ export default function addImage(provider) {
|
|||||||
thumbw: processed.thumb.w,
|
thumbw: processed.thumb.w,
|
||||||
thumbh: processed.thumb.h,
|
thumbh: processed.thumb.h,
|
||||||
thumbhash: processed.thumb.hash,
|
thumbhash: processed.thumb.hash,
|
||||||
|
smallthumbw: processed.smallThumb.w,
|
||||||
|
smallthumbh: processed.smallThumb.h,
|
||||||
|
smallthumbbinary: processed.smallThumb.buffer,
|
||||||
source: '',
|
source: '',
|
||||||
fullbinary: processed.full.buffer,
|
fullbinary: processed.full.buffer,
|
||||||
thumbbinary: processed.thumb.buffer,
|
thumbbinary: processed.thumb.buffer,
|
||||||
@@ -88,6 +91,8 @@ export default function addImage(provider) {
|
|||||||
thumbW: processed.thumb.w,
|
thumbW: processed.thumb.w,
|
||||||
thumbH: processed.thumb.h,
|
thumbH: processed.thumb.h,
|
||||||
thumbHash: processed.thumb.hash,
|
thumbHash: processed.thumb.hash,
|
||||||
|
smallThumbW: processed.smallThumb.w,
|
||||||
|
smallThumbH: processed.smallThumb.h,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -96,6 +101,8 @@ export default function addImage(provider) {
|
|||||||
thumbW: processed.thumb.w,
|
thumbW: processed.thumb.w,
|
||||||
thumbH: processed.thumb.h,
|
thumbH: processed.thumb.h,
|
||||||
thumbHash: processed.thumb.hash,
|
thumbHash: processed.thumb.hash,
|
||||||
|
smallThumbW: processed.smallThumb.w,
|
||||||
|
smallThumbH: processed.smallThumb.h,
|
||||||
pics: [picObj],
|
pics: [picObj],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ export default function addImage(provider) {
|
|||||||
const addCategoryPicSql = isSqlite ? SQLITE_ADD_CATEGORYPIC : MSSQL_ADD_CATEGORYPIC;
|
const addCategoryPicSql = isSqlite ? SQLITE_ADD_CATEGORYPIC : MSSQL_ADD_CATEGORYPIC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an image to a category, processing it into AVIF full and thumb variants.
|
* Adds an image to a category, processing full, thumb, and 40px-edge small-thumb AVIF variants.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {number} categoryId - The id of the category.
|
* @param {number} categoryId - The id of the category.
|
||||||
* @param {Buffer} image - The source image buffer.
|
* @param {Buffer} image - The source image buffer.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>} The added image info.
|
* @returns {Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number}>} The added image info.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const result = await store.category.addImage(42, 5, imageBuffer);
|
* const result = await store.category.addImage(42, 5, imageBuffer);
|
||||||
@@ -71,6 +71,9 @@ export default function addImage(provider) {
|
|||||||
thumbw: processed.thumb.w,
|
thumbw: processed.thumb.w,
|
||||||
thumbh: processed.thumb.h,
|
thumbh: processed.thumb.h,
|
||||||
thumbhash: processed.thumb.hash,
|
thumbhash: processed.thumb.hash,
|
||||||
|
smallthumbw: processed.smallThumb.w,
|
||||||
|
smallthumbh: processed.smallThumb.h,
|
||||||
|
smallthumbbinary: processed.smallThumb.buffer,
|
||||||
source: '',
|
source: '',
|
||||||
fullbinary: processed.full.buffer,
|
fullbinary: processed.full.buffer,
|
||||||
thumbbinary: processed.thumb.buffer,
|
thumbbinary: processed.thumb.buffer,
|
||||||
@@ -98,6 +101,8 @@ export default function addImage(provider) {
|
|||||||
thumbW: processed.thumb.w,
|
thumbW: processed.thumb.w,
|
||||||
thumbH: processed.thumb.h,
|
thumbH: processed.thumb.h,
|
||||||
thumbHash: processed.thumb.hash,
|
thumbHash: processed.thumb.hash,
|
||||||
|
smallThumbW: processed.smallThumb.w,
|
||||||
|
smallThumbH: processed.smallThumb.h,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { rgbaToThumbHash } from 'thumbhash';
|
|||||||
|
|
||||||
const FULL_MAX = 1000;
|
const FULL_MAX = 1000;
|
||||||
const THUMB_MAX = 200;
|
const THUMB_MAX = 200;
|
||||||
|
const SMALL_THUMB_MAX = 40;
|
||||||
|
|
||||||
export default async function processAvifImage(inputBuffer) {
|
export default async function processAvifImage(inputBuffer) {
|
||||||
const input = Buffer.isBuffer(inputBuffer)
|
const input = Buffer.isBuffer(inputBuffer)
|
||||||
@@ -26,8 +27,10 @@ export default async function processAvifImage(inputBuffer) {
|
|||||||
|
|
||||||
const thumbPipeline = sharp(input)
|
const thumbPipeline = sharp(input)
|
||||||
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
||||||
|
const smallThumbPipeline = sharp(input)
|
||||||
|
.resize(SMALL_THUMB_MAX, SMALL_THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
||||||
|
|
||||||
const [full, thumb, thumbRgba] = await Promise.all([
|
const [full, thumb, thumbRgba, smallThumb] = await Promise.all([
|
||||||
useOriginalFull
|
useOriginalFull
|
||||||
? Promise.resolve({
|
? Promise.resolve({
|
||||||
info: { width: w, height: h },
|
info: { width: w, height: h },
|
||||||
@@ -44,6 +47,9 @@ export default async function processAvifImage(inputBuffer) {
|
|||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.raw()
|
.raw()
|
||||||
.toBuffer({ resolveWithObject: true }),
|
.toBuffer({ resolveWithObject: true }),
|
||||||
|
smallThumbPipeline
|
||||||
|
.avif({ effort: 2 })
|
||||||
|
.toBuffer({ resolveWithObject: true }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const thumbHashBytes = rgbaToThumbHash(
|
const thumbHashBytes = rgbaToThumbHash(
|
||||||
@@ -66,5 +72,10 @@ export default async function processAvifImage(inputBuffer) {
|
|||||||
buffer: thumb.data,
|
buffer: thumb.data,
|
||||||
hash: Buffer.from(thumbHashBytes).toString('base64'),
|
hash: Buffer.from(thumbHashBytes).toString('base64'),
|
||||||
},
|
},
|
||||||
|
smallThumb: {
|
||||||
|
w: smallThumb.info.width,
|
||||||
|
h: smallThumb.info.height,
|
||||||
|
buffer: smallThumb.data,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user