使用Imagemagick的Node.js缩略图:非确定性损坏

时间:2012-11-01 12:06:33

标签: node.js imagemagick

我有一个Node.js服务器,可以动态生成并提供数据库(mongodb)中图像(640x640)的小(200x200)缩略图。我正在使用node-imagemagick模块进行缩略图。

我的代码约占95%的时间;在客户端(iOS)上大约有20个(或更少)缩略图像损坏,报告:

  

JPEG损坏的JPEG数据:数据段的过早结束

对于损坏的图像,客户端显示前50% - 75%的图像,其余部分被截断。

行为是不确定的,并且特定图像的损坏会根据请求进行更改。

我正在使用以下代码调整图像大小并输出缩略图:

im.resize({
  srcData: image.imageData.buffer,
  width: opt_width,
}, function(err, stdout) {
  var responseHeaders = {};
  responseHeaders['content-type'] = 'image/jpeg';
  responseHeaders['content-length'] = stdout.length;
  debug('Writing ', stdout.length, ' bytes.');
  response.writeHead(200, responseHeaders);
  response.write(stdout, 'binary');
  response.end();
});

这可能有什么不对吗?

注意:

  1. 问题不是错误的content-length标头。当我省略标题时,结果是一样的。
  2. 当我不调整图像大小时,全尺寸图像似乎总是很好。
  3. 在研究这个问题时,我发现了thisthis StackOverflow问题,它们都通过增加缓冲区大小来解决问题。在我的情况下,图像非常小,所以这似乎不太可能是负责任的。
  4. 我最初将stdout分配给new Buffer(stdout, 'binary')并撰写。删除它('binary'将被弃用)没有任何区别。

1 个答案:

答案 0 :(得分:1)

这个问题似乎是由node-imagemagick(0.1.2)的较旧版本引起的;升级到0.1.3是解决方案。

如果这对任何人都有帮助,这里是我用来使Node.js排队并一次处理一个客户端请求的代码。

// Set up your server like normal.
http.createServer(handleRequest);
// ...

var requestQueue = [];
var isHandlingRequest = false;  // Prevent new requests from being handled.

// If you have any endpoints that don't always call response.end(), add them here.
var urlsToHandleConcurrently = {
  '/someCometStyleThingy': true
};

function handleRequest(req, res) {
  if (req.url in urlsToHandleConcurrently) {
    handleQueuedRequest(req, res);
    return;
  }
  requestQueue.push([req, res]);  // Enqueue new requests.
  processRequestQueue();          // Check if a request in the queue can be handled.
}

function processRequestQueue() {
  // Continue if no requests are being processed and the queue is not empty.
  if (isHandlingRequest) return;
  if (requestQueue.length == 0) return;

  var op = requestQueue.shift();

  var req = op[0], res = op[1];

  // Wrap .end() on the http.ServerRequest instance to
  // unblock and process the next queued item.
  res.oldEnd = res.end;
  res.end = function(data) {
    res.oldEnd(data);
    isHandlingRequest = false;
    processRequestQueue();
  };

  // Start handling the request, while blocking the queue until res.end() is called.
  isHandlingRequest = true;
  handleQueuedRequest(req, res);
}

function handleQueuedRequest(req, res) {
  // Your regular request handling code here...
}