Создание механизма хранения Multer - PullRequest
0 голосов
/ 18 сентября 2018

Я устанавливаю загрузку изображений с помощью 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"
  }
]

Я не могу понять, почему он не возвращает данные для второго изображения.Любая помощь будет приветствоваться!

...