refs #5576 feat: add symbolLink in folder when original is bigger than folder

This commit is contained in:
Javier Segarra 2023-11-20 14:56:01 +01:00
parent a5237281d6
commit 3a1520cfea
1 changed files with 186 additions and 96 deletions

View File

@ -2,132 +2,222 @@ const fs = require('fs-extra');
const path = require('path');
const gm = require('gm');
const crypto = require('crypto');
const {models} = require('vn-loopback/server/server');
const PNG = 'png';
const FORMAT = PNG;
const DEFAULT_GRAVITY = 'Center';
const DEFAULT_QUALITY = 100;
const SIZE_UNIT = 'x';
const formatWidthHeight = (width, height) => `${width}${SIZE_UNIT}${height}`;
const parseSize = value => formatWidthHeight(value.width, value.height).split(SIZE_UNIT);
module.exports = Self => {
require('../methods/image/download')(Self);
require('../methods/image/upload')(Self);
require('../methods/image/scrub')(Self);
Self.resize = async function({collectionName, srcFile, fileName, entityId}) {
const models = Self.app.models;
const collection = await models.ImageCollection.findOne(
{
fields: [
'id',
'maxWidth',
'maxHeight',
'model',
'property',
],
where: {name: collectionName},
include: {
relation: 'sizes',
scope: {
fields: ['width', 'height', 'crop'],
},
},
}
);
Self.handleFolderDestination = async fileName => {
// Insert image row
const imageName = path.parse(fileName).name;
const shasum = crypto.createHash('sha1');
shasum.update(imageName);
const hash = shasum.digest('hex');
const {name} = path.parse(fileName);
const hash = crypto.createHash('sha1').update(name).digest('hex');
const pairs = hash.match(/(..?)/g);
const imageConfig = await models.ImageConfig.findOne({fields: ['dirLevels']});
const firstPairs = pairs.slice(0, imageConfig.dirLevels).reverse();
const dstDir = firstPairs.join('/');
const {dirLevels} = await models.ImageConfig.findOne({
fields: ['dirLevels'],
});
const dstDir = pairs.slice(0, dirLevels).reverse().join('/');
await models.Image.upsertWithWhere(
{
name: imageName,
collectionFk: collectionName
return {name, dstDir};
};
Self.getCollection = async collectionName => {
const collection = await models.ImageCollection.findOne({
fields: ['id', 'maxWidth', 'maxHeight', 'model', 'property'],
where: {name: collectionName},
include: {
relation: 'sizes',
scope: {
fields: ['width', 'height', 'crop'],
},
},
});
return collection;
};
Self.getCollectionDir = async collectionName => {
const container = await models.ImageContainer.container(collectionName);
const rootPath = container.client.root;
const collectionDir = path.join(rootPath, collectionName);
return collectionDir;
};
Self.getFullSizePath = (fileName, collectionDir, dstDir) => {
const fullSizePath = path.join(collectionDir, `full/${dstDir}`);
const fullSizeOriginalPath = path.join(collectionDir, `full`);
const toFullSizePath = `${fullSizePath}/${fileName}`;
const toFullSizeOriginalPath = `${fullSizeOriginalPath}/${fileName}`;
return {
fullSizePath,
toFullSizePath,
toFullSizeOriginalPath
};
};
Self.removeLink = async(child, parent = null) => {
try {
await fs.unlink(child);
} catch (e) {
throw new Error(e);
}
try {
await fs.symlink(parent, child);
} catch (e) {
throw new Error(e);
}
};
Self.createLink = async(parent, child = null) => {
try {
const exists = await fs.exists(parent);
if (exists)
await fs.unlink(parent);
} catch (e) {
throw new Error(e);
}
try {
await fs.symlink(child, parent);
const link = await fs.readlink(parent);
console.log(link);
} catch (e) {
throw new Error(e);
}
};
Self.resize = async function({
collectionName,
srcFile,
fileName,
entityId,
}) {
const {name, dstDir} = await Self.handleFolderDestination(fileName);
try {
await models.Image.upsertWithWhere({
name,
collectionFk: collectionName,
},
{
name: imageName,
name,
collectionFk: collectionName,
updated: Date.vnNow() / 1000,
}
);
});
} catch (e) {
debugger;
throw new Error(e);
}
const collection = await Self.getCollection(collectionName);
const {maxWidth, maxHeight} = collection;
// Update entity image file name
const model = models[collection.model];
if (!model) throw new Error('No matching model found');
const entity = await model.findById(entityId);
if (entity) {
await entity.updateAttribute(
collection.property,
imageName
);
}
if (entity)
await entity.updateAttribute(collection.property, name);
// Resize
const container = await models.ImageContainer.container(
collectionName
);
const rootPath = container.client.root;
const collectionDir = path.join(rootPath, collectionName);
const collectionDir = await Self.getCollectionDir(collectionName);
// To max size
const {maxWidth, maxHeight} = collection;
const fullSizePath = path.join(collectionDir, `full/${dstDir}`);
const fullSizeOriginalPath = path.join(collectionDir, `full`);
const toFullSizePath = `${fullSizePath}/${fileName}`;
const toFullSizeOriginalPath = `${fullSizeOriginalPath}/${fileName}`;
const _fullSizePath = Self.getFullSizePath(fileName, collectionDir, dstDir);
await fs.mkdir(fullSizePath, {recursive: true});
await new Promise((resolve, reject) => {
gm(srcFile)
.resize(maxWidth, maxHeight, '>')
.setFormat('png')
.quality(100)
.write(toFullSizePath, function(err) {
if (err) reject(err);
if (!err) resolve();
});
const {fullSizePath, toFullSizePath, toFullSizeOriginalPath} = _fullSizePath;
try {
await fs.mkdir(fullSizePath, {recursive: true});
} catch (e) {
debugger;
throw new Error(e);
}
const gmInstance = gm(srcFile);
let fileWidth = null;
let fileHeight = null;
gmInstance.size(function(err, size) {
if (err) console.error(err);
[fileWidth, fileHeight] = parseSize(size);
});
try {
await fs.unlink(toFullSizeOriginalPath);
} catch (e) {}
await fs.symlink(toFullSizeOriginalPath, toFullSizePath, 'file');
// To collection sizes
for (const size of collection.sizes()) {
const {width, height} = size;
const sizePath = path.join(collectionDir, `${width}x${height}/${dstDir}`);
const toSizePath = `${sizePath}/${fileName}`;
const sizeOriginalPath = path.join(collectionDir, `${width}x${height}`);
const toSizeOriginalPath = `${sizeOriginalPath}/${fileName}`;
await fs.mkdir(sizePath, {recursive: true});
await new Promise((resolve, reject) => {
const gmInstance = gm(srcFile);
if (size.crop) {
gmInstance
.resize(width, height, '^')
.gravity('Center')
.crop(width, height);
}
if (!size.crop) gmInstance.resize(width, height, '>');
gmInstance
.setFormat('png')
.quality(100)
.write(toSizePath, function(err) {
.resize(maxWidth, maxHeight, '>')
.setFormat(PNG)
.quality(DEFAULT_QUALITY)
.write(toFullSizePath + `.${FORMAT}`, function(err, data) {
if (err) reject(err);
if (!err) resolve();
if (!err) resolve(data);
});
});
} catch (e) {
debugger;
throw new Error(e);
}
await Self.createLink(toFullSizeOriginalPath, toFullSizePath);
/* try {
await fs.unlink(toFullSizeOriginalPath);
} catch (e) {
debugger;
throw new Error(e);
}
try {
await fs.symlink(toFullSizeOriginalPath, toFullSizePath, 'file');
} catch (e) {
debugger;
throw new Error(e);
}*/
// To collection sizes
for (const size of collection.sizes()) {
const [width, height] = parseSize(size);
const sizePath = path.join(
collectionDir,
`${formatWidthHeight(width, height)}/${dstDir}`
);
try {
await fs.unlink(toSizeOriginalPath);
} catch (e) {}
await fs.symlink(toSizePath, toSizeOriginalPath);
await fs.mkdir(sizePath, {recursive: true});
} catch (e) {
debugger;
throw new Error(e);
}
const toSizePath = `${sizePath}/${fileName}`;
if (+fileWidth < +width && +fileHeight < +height) {
await new Promise((resolve, reject) => {
if (size.crop) {
gmInstance
.resize(width, height, '^')
.gravity(DEFAULT_GRAVITY)
.crop(width, height).res(function(err, data) {
if (err) reject(err);
if (!err) resolve(data);
});
} else gmInstance.resize(width, height, '>');
gmInstance
.setFormat(PNG)
.quality(DEFAULT_QUALITY)
.write(toSizePath + `.${FORMAT}`, function(err, data) {
if (err) reject(err);
if (!err) resolve(data);
});
});
}
const sizeOriginalPath = path.join(
collectionDir,
formatWidthHeight(width, height)
);
const toSizeOriginalPath = `${sizeOriginalPath}/${fileName}`;
// if (fileWidth > width && fileHeight < height)
await Self.createLink(toSizeOriginalPath, toSizePath);
}
};
};