使用 GraphicsMagick 操作 GridFS 文件并将其存储为新文件
Manipulate GridFS file with GraphicsMagick and store it as new file
我正在尝试通过 gridfs-stream
(https://github.com/aheckmann/gridfs-stream) 读取 GridFS 文件,使用 gm
将其旋转 90° 并将其存储为新的 GridFS 文件。
我的结果看起来非常 'unstylish'...所以我请求帮助优化这个小代码片段...
此代码的第二件事:我需要一种 'switch'。此代码对图像进行旋转操作。但我需要传递一个参数来进行旋转、调整大小或其他操作。我该如何整合它?
import Grid from 'gridfs-stream'
import { MongoInternals } from 'meteor/mongo'
const id = '12345'
const gfs = Grid(
MongoInternals.defaultRemoteCollectionDriver().mongo.db,
MongoInternals.NpmModule
)
const readStream = gfs.createReadStream({ _id: id })
readStream.on('error', function (err) {
console.error('Could not read stream', err)
throw Meteor.Error(err)
})
gm(readStream)
.rotate('#ffffff', 90)
.stream(function (err, stdout, stderr) {
if (err) {
console.error('Could not write stream')
throw Meteor.Error(err)
}
const writeStream = gfs.createWriteStream()
const newFileId = writeStream.id
writeStream.on('finish',
function () {
console.log('New file created with ID ' + newFileId)
}
)
stdout.pipe(writeStream)
})
我没有设置项目来测试它,但它看起来不错。
复杂的流式传输往往看起来很难看。除了尽量让它失控之外,你无能为力。但是让我们看看在添加额外功能的同时我们可以做些什么来美化。
由于您是在顶层创建读取流,我认为将写入流也放在顶层会更简洁。您可以将它们组合在一个对象中。
粗箭头函数往往看起来更简洁,所以我将它们放入匿名函数中。请注意,粗箭头没有 this
绑定。因此,如果您需要访问流的 this
,则需要恢复使用 function
关键字。
使用 rs
和 ws
表示 readstream
和 writestream
是非常常见的约定。所以我认为在适当的地方使用它是一个安全的缩写。
为了增加使用多个选项的能力,我们制作了一个包装函数,它接受我们的输入流和选项以及 returns 输出流。一个插件,你可以说。
通过使我们的函数调用将对象解构为参数,我们可以按名称分配它们。更容易判断发生了什么。
我们使用 Object.keys
来获取选项名称数组。然后使用名称逐步执行我们的选项,通过 spread
将参数数组输入 gm
方法来应用每个选项。
gm readme 表示如果没有回调,它将 return 一个流以方便。好的。 :) 我们将 return 整个流链,准备好通过管道传输到我们想要的任何输出。
import Grid from 'gridfs-stream'
import gm from 'gm'
import { MongoInternals } from 'meteor/mongo'
const id = '12345'
const gfs = Grid(
MongoInternals.defaultRemoteCollectionDriver().mongo.db,
MongoInternals.NpmModule
)
const gfsStreams = {
read: _id =>
gfs.createReadStream({ _id })
.on('error', err => {
console.error('Could not read stream', err)
throw Meteor.Error(err)
}),
write: () => {
const ws = gfs.createWriteStream()
const newFileId = ws.id
ws.on('finish', () =>
console.log('New file created with ID ' + newFileId)
)
.on('error' => {
console.error('Could not write stream')
throw Meteor.Error(err)
})
return ws
}
}
const transformedStream = gmTransform({
filestream: gfsStreams.read(id),
gmOptions: {
magnify: [],
rotate: ['ffffff', 90],
blur: [7, 3]
crop: [300, 300, 150, 130]
},
output: stdout
})
stdout.pipe(transformedStream)
function gmTrasform ({filestream, gmOptions}){
let gmStream = gm(filestream)
.on('error', {
console.error('Could not transform image')
throw Meteor.Error(err)
})
Object.keys(gmOptions)
.forEach(opt => {
gmStream = gmStream[opt](...gmOptions[i])
})
return gmStream.stream()
.pipe(gfsStreams.write())
}
我正在尝试通过 gridfs-stream
(https://github.com/aheckmann/gridfs-stream) 读取 GridFS 文件,使用 gm
将其旋转 90° 并将其存储为新的 GridFS 文件。
我的结果看起来非常 'unstylish'...所以我请求帮助优化这个小代码片段...
此代码的第二件事:我需要一种 'switch'。此代码对图像进行旋转操作。但我需要传递一个参数来进行旋转、调整大小或其他操作。我该如何整合它?
import Grid from 'gridfs-stream'
import { MongoInternals } from 'meteor/mongo'
const id = '12345'
const gfs = Grid(
MongoInternals.defaultRemoteCollectionDriver().mongo.db,
MongoInternals.NpmModule
)
const readStream = gfs.createReadStream({ _id: id })
readStream.on('error', function (err) {
console.error('Could not read stream', err)
throw Meteor.Error(err)
})
gm(readStream)
.rotate('#ffffff', 90)
.stream(function (err, stdout, stderr) {
if (err) {
console.error('Could not write stream')
throw Meteor.Error(err)
}
const writeStream = gfs.createWriteStream()
const newFileId = writeStream.id
writeStream.on('finish',
function () {
console.log('New file created with ID ' + newFileId)
}
)
stdout.pipe(writeStream)
})
我没有设置项目来测试它,但它看起来不错。
复杂的流式传输往往看起来很难看。除了尽量让它失控之外,你无能为力。但是让我们看看在添加额外功能的同时我们可以做些什么来美化。
由于您是在顶层创建读取流,我认为将写入流也放在顶层会更简洁。您可以将它们组合在一个对象中。
粗箭头函数往往看起来更简洁,所以我将它们放入匿名函数中。请注意,粗箭头没有
this
绑定。因此,如果您需要访问流的this
,则需要恢复使用function
关键字。使用
rs
和ws
表示readstream
和writestream
是非常常见的约定。所以我认为在适当的地方使用它是一个安全的缩写。为了增加使用多个选项的能力,我们制作了一个包装函数,它接受我们的输入流和选项以及 returns 输出流。一个插件,你可以说。
通过使我们的函数调用将对象解构为参数,我们可以按名称分配它们。更容易判断发生了什么。
我们使用
Object.keys
来获取选项名称数组。然后使用名称逐步执行我们的选项,通过spread
将参数数组输入gm
方法来应用每个选项。gm readme 表示如果没有回调,它将 return 一个流以方便。好的。 :) 我们将 return 整个流链,准备好通过管道传输到我们想要的任何输出。
import Grid from 'gridfs-stream'
import gm from 'gm'
import { MongoInternals } from 'meteor/mongo'
const id = '12345'
const gfs = Grid(
MongoInternals.defaultRemoteCollectionDriver().mongo.db,
MongoInternals.NpmModule
)
const gfsStreams = {
read: _id =>
gfs.createReadStream({ _id })
.on('error', err => {
console.error('Could not read stream', err)
throw Meteor.Error(err)
}),
write: () => {
const ws = gfs.createWriteStream()
const newFileId = ws.id
ws.on('finish', () =>
console.log('New file created with ID ' + newFileId)
)
.on('error' => {
console.error('Could not write stream')
throw Meteor.Error(err)
})
return ws
}
}
const transformedStream = gmTransform({
filestream: gfsStreams.read(id),
gmOptions: {
magnify: [],
rotate: ['ffffff', 90],
blur: [7, 3]
crop: [300, 300, 150, 130]
},
output: stdout
})
stdout.pipe(transformedStream)
function gmTrasform ({filestream, gmOptions}){
let gmStream = gm(filestream)
.on('error', {
console.error('Could not transform image')
throw Meteor.Error(err)
})
Object.keys(gmOptions)
.forEach(opt => {
gmStream = gmStream[opt](...gmOptions[i])
})
return gmStream.stream()
.pipe(gfsStreams.write())
}