我需要从上传的照片中创建4个图片尺寸:大,中,小和超小。它大部分都使用下面的代码工作,但是大中型尺寸需要在左下方放置一个水印,而不是较小的两个尺寸。
对于带水印的图像,我似乎需要复制文件流并为每个文件保存一个单独的实例。速度和效率在这里很重要,所以我想确保我做到最好。
GM节点模块真的缺乏文档。有关更多信息,他们会链接到GraphicsMagick网站,如果您尝试使用GM模块执行此操作,则无法提供帮助。这真的令人沮丧。
基本上,我可以帮助找出如何在两个较大尺寸上进行水印,然后我也想知道下面的代码是否尽可能高效。在本地计算机上创建4种尺寸时似乎有点慢。
var fileName = req.files.photo.name,
fileBaseName = fileName.substr(0, fileName.lastIndexOf('.')),
uploadRoot = SiteConfig.root + '/upload/',
photosRoot = SiteConfig.root + '/photos/',
publicRoot = SiteConfig.root + '/public/';
require('fs').rename(
req.files.photo.path,
uploadRoot + fileName,
function(error)
{
if (error)
{
res.send({ error: 'upload error' });
return;
}
var ImageSizes = {
large: {
width: 990,
height: 990
},
medium: {
width: 550,
height: 550
},
small: {
width: 145,
height: 145
},
xsmall: {
width: 55,
height: 55
}
};
var GM = require('gm'),
fileStream = require('fs').createReadStream(photosRoot + fileName);
var lgPath = photosRoot + fileBaseName + '_lg.jpg',
mdPath = photosRoot + fileBaseName + '_md.jpg',
smPath = photosRoot + fileBaseName + '_sm.jpg',
xsPath = photosRoot + fileBaseName + '_xs.jpg';
// I'm guessing the second parameter is to set the format
GM(fileStream, 'img.jpg')
.size(
{
bufferStream: true
},
function(err, size)
{
console.log(size.width);
console.log(size.height);
if (size.width > ImageSizes.large.width || size.height > ImageSizes.large.height)
this.resize(ImageSizes.large.width, ImageSizes.large.height);
// Auto-orient based on EXIF data then remove EXIF data
this
.autoOrient()
.noProfile()
.quality(70)
.write(
lgPath,
function (err)
{
if (!err)
{
console.log('write large done');
this
.resize(ImageSizes.medium.width, ImageSizes.medium.height)
// watermark code - i want to continue using the file stream instead of a file path
//.subCommand('composite')
//.gravity('Center')
//.in('-compose', 'Over', watermarkFilePath, baseFilePath)
.quality(70)
.write(
mdPath,
function (err)
{
if (!err)
{
console.log('write medium done');
this
.resize(ImageSizes.small.width, ImageSizes.small.height)
.crop(ImageSizes.small.width, ImageSizes.small.height)
.quality(70)
.write(
smPath,
function (err)
{
if (!err)
{
console.log('write small done');
this
.resize(ImageSizes.xsmall.width, ImageSizes.xsmall.height)
.quality(70)
.write(
xsPath,
function (err)
{
if (!err)
console.log('write xsmall done');
else
console.log('write xsmall error');
}
);
}
else
console.log('write small error');
}
);
}
else
console.log('write medium error');
}
);
}
else
console.log('write large error');
}
);
}
);
}
);
答案 0 :(得分:1)
(注意这不是真正的代码,只是关于真实代码可能看起来像什么的想法)
让我觉得你想做这样的事情:
server.on('incomingImage', function (image, res) {
async.each(imageOptions, function (imageOptions, done) {
image
.pipe(resize(imageOptions))
.pipe(fs.createWriteStream(baseDir + image.path + imageOptions.path))
.on('end', done);
}, function (err) {
if (err) {
res.send(500);
} else {
res.send(204);
}
});
});
也就是说,当图像进入时,为每个图像选项创建一个通过流和文件写入流的大小调整,然后通过所有调整大小的流将图像传输到文件写入流,一旦所有文件都有写完了,回复。
通过并行处理流,您可以最大限度地减少服务器因IO而必须等待的任何时间(这是node.js背后的基本思想)。
您正在将文件写入磁盘,然后依次处理每个映像选项并将其写入磁盘,然后再开始从磁盘读取文件。
这样写入时间x 1 +读取时间x 5 +处理时间x 5 +写入时间x 5
相反,它应该是最大处理时间+最大写入时间,这要短得多。
由于gm
模块没有提供良好的流接口,因此存在一些复杂情况。您可能想看看是否有更好的模块。
还有关于流的主题:
https://github.com/substack/stream-handbook http://nodeschool.io/#stream-adventure
和async