Обрезка GraphicsMagick в зависимости от размера исходного изображения (повторное использование потока чтения)

Я использую пакеты Meteor collection-fs для загрузки изображений и хочу вырезать миниатюру из центра каждого изображения, используя gm(readStrem).crop(). Проблема в том, что смещения x и y для crop зависят от размера исходного изображения, размеры изображений будут различаться, и я не могу использовать один и тот же файл readStream дважды.

Это ломает:

var xOff = 0;
var yOff = 0;
var thumbnailWidth = 450;
var thumbnailHeight = 600;
gm(readStream).size(function (err, dimensions) {
   if ( dimensions ) {
     xOff = (dimensions.width - thumbnailWidth) / 2;
     yOff = (dimensions.height - thumbnailHeight) / 2;
   }
   gm(readStream)
     .crop(thumbnailWidth, thumbnailHeight, xOff, yOff)
     .stream()
     .pipe(writeStream);
})

Размеры возвращаются, но второе использование readStream возвращает Error: gm().stream() or gm().write() with a non-readable stream

Я видел несколько других ответов, связанных с этим, но ни один из них не помог мне, потому что пакет заставляет меня pipe(writeStream); Я не могу просто сделать '.writeAsync()'. Я перепробовал множество других трюков, которые не сработали, в том числе:

  • клонирование потока для получения размера, а затем использование оригинала для синхронного преобразования и сохранения (в таймере)
  • вызов всего этого синхронно (глупая идея, но стоит попробовать)

Если у кого-то есть какие-либо идеи, я был бы очень признателен за ваш вклад.

Спасибо! дБ


person Daniel Bernhard    schedule 26.02.2015    source источник


Ответы (2)


Это работает и не зависит от клиента, что делает его более безопасным:

var xOff = 0;
var yOff = 0;
var thumbnailWidth = 450;
var thumbnailHeight = 600;
gm(readStream, fileObj.name()).size(
  {bufferStream: true},
  function (err, dimensions) {
    if (dimensions) {
      xOff = (dimensions.width - thumbnailWidth) / 2;
      yOff = (dimensions.height - thumbnailHeight) / 2;
    }
    this.crop(thumbnailWidth, thumbnailHeight, xOff, yOff);
    this.stream((err, stdout, stderr) => {
      stdout.pipe(writeStream);
    });
  }
);
person Menda    schedule 13.05.2016

Решение заключалось в том, чтобы определить размер файла на клиенте, добавить эти данные в fileObj перед записью, а затем во время записи вызвать функцию Crop на сервере.

var cropInfo = fileObj.cropInfo
gm(readStream)
     .crop(cropInfo.width, cropInfo.height, cropInfo.x, cropInfo.y)
     .stream()
     .pipe(writeStream);

Не совсем идеально, но работает.

person Daniel Bernhard    schedule 13.03.2015
comment
Нам нужно проверить это на стороне сервера, потому что это может нанести вред системе. - person Moe Far; 06.08.2015