3

データベース(mongodb)内の画像(640x640)から小さな(200x200)サムネイルを動的に生成して提供するNode.jsサーバーがあります。サムネイル作成にnode-imagemagickモジュールを使用しています。

私のコードはおよそ95%の時間で機能します。クライアント(iOS)では、サムネイル画像の約20分の1(またはそれ以下)が破損しています。

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. これを調査したところ、これこのStackOverflowの質問が見つかりました。どちらも、バッファサイズを増やすことで問題を解決しました。私の場合、画像は非常に小さいので、これが原因である可能性は低いようです。
  4. 私はもともとに割り当てstdoutて、new Buffer(stdout, 'binary')それを書いていました。それを削除しても('binary'非推奨になります)、違いはありません。
4

1 に答える 1

1

この問題は、 node-imagemagick(0.1.2)の少し古いバージョンが原因であると思われます。0.1.3へのアップグレードが解決策でした。

これが誰かに役立つ場合に備えて、Node.jsをキューに入れ、クライアント要求を一度に1つずつ処理するために使用したコードを次に示します。

// 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...
}
于 2012-11-02T07:07:42.920 に答える