2016-08-31 5 views
0

Я новичок в RxJS и пробую эту (казалось бы) простую задачу, но я просто не могу понять это.Изменение размера изображений с помощью RxJS и узла

Я хочу:
1. Прочитайте изображение из файла
2. Преобразовать этот образ на несколько более мелких изображений
3. Сохраните все изображения в файл

Я преобразованный fs.readFile и фс .writeFile для наблюдаемых.

const readFile$ = Rx.Observable.bindNodeCallback(fs.readFile); 
const writeFile$ = Rx.Observable.bindNodeCallback(fs.writeFile); 

Я изготовил трубопровод изображений.

var pictureSizes = [ 
    {width: 100, size: 'thumbnail', suffix: '_t'}, 
    {width: 300, size: 'small', suffix: '_s'}, 
    {width: 600, size: 'medium', suffix: '_m'}, 
    {width: 1000, size: 'large', suffix: '_l'} 
]; 

И я сделал resizeImage $ функцию с использованием графики магии

function resizeImage$(picture, data) { 
    return Rx.Observable.create(observer => { 
     gm(data) 
     .resize(picture.width) 
     .toBuffer('jpg', function(err, buffer) { 
      if (err) { 
      console.log(err); 
      observer.error(err); 
      } else { 
      observer.next(buffer); 
      observer.complete(); 
      } 
     }); 
    }) 
} 

Я думаю (надеюсь) выше нормально. Я не могу понять, как связать своих операторов.

readFile$('./largeimage.jpg') 
    .mergeMap(data => pictureSizes.map(picture => resizeImage$(picture, data))) 
    .flatMap(picture => writeFile$('./testImages/resized.jpg', picture)) 
    .subscribe(
    (x) => console.log('Next', x), 
    (e) => console.log('Error', e), 
    (c) => console.log('Complete',c) 
) 

Это выше поврежденные данные в файл jpeg. (И перезаписывает этот файл, потому что я не могу понять, как получить pictureSizes.suffix во имя выводимого файла.

Все, что помогает! Спасибо.

UPDATE

Я получил его на работу , но я знаю, что эта причудливая множественная подписка - это ужасный анти-шаблон. Основная подписка завершается до изменения размера изображения. У меня такое чувство, что это проблема с горячей/холодной, но я понятия не имею, как это исправить. код ..

const pictureSizes = [ 
    {width: 100, size: 'thumbnail', suffix: '_t'}, 
    {width: 300, size: 'small', suffix: '_s'}, 
    {width: 600, size: 'medium', suffix: '_m'}, 
    {width: 1000, size: 'large', suffix: '_l'} 
]; 

const image = 'truck.jpg'; 

function resizeImage$(binary, pictureSize) { 
    return new Rx.Observable(observer => { 
     gm(binary) 
     .resize(pictureSize.width) 
     .toBuffer('jpg', function(err, buffer) { 
      console.log('BUFFER'); 
      if (err) { 
      console.log(err); 
      observer.error(err); 
      } else { 
      observer.next({binary: buffer, pictureSize: pictureSize}); 
      observer.complete('done'); 
      } 
     }); 
    }).subscribe(
    (resizedImage) => { 
     console.log(resizedImage); 
     const binary = resizedImage.binary; 
     const pictureSize = resizedImage.pictureSize; 
     const fileName = image.split('.')[0]; 
     const fileExtension = image.split('.')[1]; 
     fs.writeFile(`./testImages/${fileName}${pictureSize.suffix}.${fileExtension}`, binary); 
    }) 
} 
    var readFile$ = new Rx.Observable.bindNodeCallback(fs.readFile); 
    readFile$(`./${image}`) 
    .zip(Rx.Observable.of(pictureSizes), (binary, sizes) => 
     Rx.Observable.of({ binary: binary, sizes: sizes })) 
    .mergeMap(x => x.value.sizes.map(pictureSize => 
     resizeImage$(x.value.binary, pictureSize))) 
    .subscribe() 
+1

Вы говорите, что то, что вы работаете для применения суффикса файла, за исключением? В качестве теста, если вы закомментируете все «pictureSizes» за исключением одного, получите правильный, не поврежденный выходной файл? – cartant

+0

Нет, извините, я не понял ... Суффикс файла - дополнительная проблема. Конечный файл поврежден только одним объектом pictureSize. –

ответ

0

Основываясь на вашем примере я думаю, что вы можете еще больше упростить ответ:

var pictureSizes = [ 
    {width: 100, size: 'thumbnail', suffix: '_t'}, 
    {width: 300, size: 'small', suffix: '_s'}, 
    {width: 600, size: 'medium', suffix: '_m'}, 
    {width: 1000, size: 'large', suffix: '_l'} 
]; 

const scaler$ = Rx.Observable.bindNodeCallback((binary, size, callback) => { 
    gm(binary) 
    .resize(size.width) 
    .toBuffer('jpg', callback); 
}); 

const readFile$ = Rx.Observable.bindNodeCallback(fs.readFile); 
const writeFile$ = Rx.Observable.bindNodeCallback(fs.writeFile); 

function scaleImage$(sizes) { 
    const scales = Rx.Observable.from(sizes); 

    return source => 
    source.flatMap(binary => 
     scales.flatMap(
     size => scaler$(binary, size), 
     (pictureSize, binary) => ({pictureSize, binary}) 
    ) 
    ); 
} 

function resize(imagePath, sizes) { 
    return readFile$(imagePath) 
    .let(scaleImage$(sizes)) 
    .flatMap(result => { 
     const {pictureSize, binary} = result; 
     const [name, ext] = image.split('.'); 
     return writeFile$(`./resized/${name}${pictureSize.suffix}.${ext}`, binary); 
    }); 
} 

Использование:

resize(imagePath, pictureSizes) 
    .subscribe(); 
+0

Ничего себе! Это займет секунду, чтобы обернуть вокруг себя голову. Два вопроса. Две функции используют «размеры» в качестве аргумента, но я не вижу, чтобы это было определено. Это «pictureSizes»? И два, с RxJS 5, могу ли я заменить mergeMap для вашей FlatMap? –

+0

Оказывается, что я использовал неправильное имя переменной, да, 'размеры' являются' pictureSizes'. И да, вы можете заменить это, я думаю, что псевдоним «mergeMap» все еще существует. Я считаю, что проект RxJS 5 возвращается к имени «flatMap», поэтому «mergeMap» может стать устаревшим в какой-то момент в будущем. – paulpdaniels

+0

Это работало блестяще. Это сделало гораздо больше смысла, чем беспорядок, который я сделал. Я все еще пытаюсь понять источник currying source => source.flatMap wizardry. Мне кажется, что как только я смогу это понять, мое программирование значительно улучшится. Спасибо за ваше время и отличную работу! –

0

В случае, если кто-то заинтересован, у меня есть ответ. Если кто-то захочет реорганизовать его дальше, сделайте это.

Остальные вопросы ... 1. Должен ли файл записи выполняться как наблюдаемый, чтобы ловить ошибки?
2. Я не уверен, почему mergeAll был нужен.

var pictureSizes = [ 
    {width: 100, size: 'thumbnail', suffix: '_t'}, 
    {width: 300, size: 'small', suffix: '_s'}, 
    {width: 600, size: 'medium', suffix: '_m'}, 
    {width: 1000, size: 'large', suffix: '_l'} 
]; 

function scaleImage$(binary, pictureSize) { 
    return new Rx.Observable(observer => { 
     gm(binary) 
     .resize(pictureSize.width) 
     .toBuffer('jpg', function(err, buffer) { 
      if (err) { 
      observer.error(err); 
      } else { 
      observer.next({ binary: buffer, pictureSize: pictureSize }); 
      observer.complete(); 
      } 
     }); 
    }) 
} 

function writeFile(binary, pictureSize, image) { 
    const fileName = image.split('.')[0]; 
    const fileExtension = image.split('.')[1]; 
    fs.writeFile(`./resized/${fileName}${pictureSize.suffix}.${fileExtension}`, binary); 
} 

function resizeImage(imagePath) { 
    var readFile$ = new Rx.Observable.bindNodeCallback(fs.readFile); 
    readFile$(imagePath) 
    .combineLatest(Rx.Observable.of(pictureSizes),(binary,y) => y.map(pictureSize => Object.assign({}, {binary, pictureSize}))) 
    .mergeMap(arr => arr.map(obj => scaleImage$(obj.binary, obj.pictureSize))) 
    .mergeAll() 
    .subscribe((obj) => writeFile(obj.binary, obj.pictureSize, image)) 

} 

И если вы хотите, синхронное поведение (масштаб изображения 1 -> записи изображения 1 -> масштаб изображения 2 ...), используйте concatMap и concatAll.