Я устанавливаю загрузку изображений с помощью Express и Multer.Мой обработчик маршрутизатора получит formData с несколькими файлами: я хочу обработать их в нескольких разрешениях и сохранить их в папках с именем своего разрешения:
media
├── w350
│ ├── image1.jpg
│ └── image2.jpg
├── w600
│ ├── image1.jpg
│ └── image2.jpg
└── w1200
├── image1.jpg
└── image2.jpg
Для обработки изображений ранее в промежуточном программном обеспечении, которое у меня естьиспользовать собственный механизм хранения, поэтому я начал с этого механизма, чтобы написать свой собственный: https://github.com/gladchinda/advanced-multer-node-sourcecode/blob/master/helpers/AvatarStorage.js
Моя реализация такова.
var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var Jimp = require('jimp');
var mkdirp = require('mkdirp');
var concat = require('concat-stream');
var streamifier = require('streamifier');
// create a multer storage engine
var CustomStorage = function(options) {
function CustomStorage() {
return; // Should be empty
}
CustomStorage.prototype._createOutputStream = function(filepath, cb, options) {
var output = fs.createWriteStream(filepath);
output.on('error', cb);
output.on('finish', function() {
cb(null, {
destination: options.uploadPath,
baseUrl: options.uploadPath,
filename: path.basename(filepath),
storage: options.storage,
});
});
return output;
};
// this processes the Jimp image buffer
CustomStorage.prototype._processImage = function(image, cb, options) {
var self = this;
var batch = [];
var mime = Jimp.MIME_PNG;
var clone = image.clone();
// Set image resolutions
options.sizes.map((item) => {
var outputStream;
var image = null;
var filepath = options.fileName.split('.');
options.uploadPath = path.join(options.folder, 'w' + item.width);
// Create path if not exist
if (options.storage == 'local') {
!fs.existsSync(options.uploadPath) && mkdirp.sync(options.uploadPath);
}
filepath = path.join(options.uploadPath, options.fileName);
outputStream = self._createOutputStream(filepath, cb, options);
image = clone.clone().resize(item.width, item.height);
var image = {
stream: outputStream,
image: image,
};
batch.push(image);
});
batch.forEach((item) => {
item.image.getBuffer(mime, function(err, buffer) {
if (options.storage == 'local') {
streamifier.createReadStream(buffer).pipe(item.stream);
}
});
});
};
CustomStorage.prototype._handleFile = function(req, file, cb) {
let that = this;
let options = {
sizes: [
{
width: 300,
height: 150,
},
{
width: 600,
height: 300,
},
{
width: 1200,
height: 600,
},
],
storage: 'local',
output: 'jpg',
fileName: file.originalname,
fieldName: file.fieldname,
folder: 'media/images'
};
var fileManipulate = concat(function(imageData) {
Jimp.read(imageData)
.then(function(image) {
that._processImage(image, cb, options);
})
.catch(cb);
});
file.stream.pipe(fileManipulate);
};
return new CustomStorage(options);
};
module.exports = CustomStorage;
Не требует никаких опций, поэтому в вашем роутере вы можете вызвать его с помощью:
import CustomStorage from './CustomStorage';
var storage = CustomStorage();
var upload = multer({ storage: storage });
router.put('/:id', upload.any(), function(req, res, next) {
console.log('req.files: ', JSON.stringify(req.files, undefined, 2));
});
При загрузке двух изображений это должно возвращать что-то вроде:
req.files: [
{
"originalname": "fantastic-photo.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "media/images/Projects/w1200",
"baseUrl": "media/images/Projects/w1200",
"filename": "374827017056551892885227324803010320001537184436993.jpg",
"storage": "local",
"fieldname": "projects_img"
},
{
"originalname": "fantastic-photo.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "media/images/Projects/w1200",
"baseUrl": "media/images/Projects/w1200",
"filename": "374827017056551892885227324803010320001537184436993.jpg",
"storage": "local",
"fieldname": "projects_img"
}
]
Но вместо этого он возвращает только первое изображение:
req.files: [
{
"originalname": "fantastic-photo.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "media/images/Projects/w1200",
"baseUrl": "media/images/Projects/w1200",
"filename": "374827017056551892885227324803010320001537184436993.jpg",
"storage": "local",
"fieldname": "projects_img"
},
{
"fieldname": "projects_img2"
}
]
Я не могу понять, почему он не возвращает данные для второго изображения.Любая помощь будет приветствоваться!