【问题标题】:"Echoing" an image in Node.js在 Node.js 中“回显”图像
【发布时间】:2016-05-04 19:52:47
【问题描述】:

我有一个功能齐全的 PHP 应用程序,我正在尝试制作它的 Node.js 版本。它处理服务图像图块。当它准备好显示图像时:

// Stream out the image
echo self::$tile;

如何在 Node.js 中做类似的事情?我知道这是一个广泛的问题,但我认为我最大的问题是我不了解 PHP 如何“回显”图像。


详情:

我正在使用 AWS 来获取图像。 AWS 调用返回一个缓冲区。此时,在 Javascript 中,我将图像保留为缓冲区。

该站点使用平铺图像填充地图,因此有多个调用将图像放置在页面上的特定位置。我正在使用 express 来处理请求。

app.get(/^\/omb\/1.0.0\/(.+)\/(.+)\/(.+)\/(.+)\.[a-zA-Z]*$/, function(req, res){
    var MosaicStreamer = require('./models/MosaicStreamer.js'); 
    var ms = new MosaicStreamer; 
    var configs = {library: req.params[0], zoom: req.params[1], column: req.params[2], row: req.params[3]}; 
    ms.handleTile(configs); 
});

handleTile 抓取图像并最终将我带到现在的位置。使用以下方法抓取图像:

var aws = new AWS.S3(); 
var params = {
    Bucket: this.bucket,  
    Key: this.tileDirectory + this.filepath, 
    Range: 'bytes=' + (this.toffset + 4) + "-" + (this.tsize + this.toffset + 4)
};
var ts = this; 
aws.getObject(params, function(err, data){
    if(ts.tile == null){
       ts.tile = data.Body; //S3 get object 
    }
}

【问题讨论】:

  • 我们能看到创建self::$title的代码吗?或者,我们可以看看self::$title 是如何被使用的吗?它是base64编码的图像吗?您是否将其结果直接烘焙到浏览器响应中并修改标头,这是 BLOB 吗?回答完这些问题后,我们可以提供建议。
  • @Ohgodwhy,好吧,我会尽力而为!我将编辑问题
  • 当您使用echo 时,PHP 所做的是将输出(在本例中为二进制内容)写入输出缓冲区,该缓冲区通过 Web 服务器连接到请求资源的浏览器。在 node.js 中通过将二进制数据写入请求的“响应流”来完成相同的概念。由于您可能已经通过多种方式实现了请求处理,因此我们需要更详细地了解您正在使用的堆栈(例如 express、api、http 模块等),最好使用一些示例代码。
  • @RogierSpieker 在帖子中添加了一些细节。我正在使用express。所以从你的意思来看,我猜我需要在路由中做一些事情来处理图像?
  • 您是否在 AWS 实例中使用 S3 存储桶?

标签: javascript php node.js image echo


【解决方案1】:

我认为您想要做的是获取一个给定的 URL,该 URL 非常接近 S3 存储桶中文件夹/文件的命名约定。因此,假设您已经建立了与 S3 的客户端连接,您可以使用readFile 方法。第二个参数是imageStream,您可以将其传入response。一旦流从 S3 结束,它将自动从客户端结束 res,将图像直接输出到客户端(如您所愿)。

一些伪代码:

app.get(/^\/omb\/1.0.0\/(.+)\/(.+)\/(.+)\/(.+)\.[a-zA-Z]*$/, function(req, res){
    var MosaicStreamer = require('./models/MosaicStreamer.js'); 
    var ms = new MosaicStreamer; 
    var configs = {library: req.params[0], zoom: req.params[1], column: req.params[2], row: req.params[3]}; 
    return ms.handleTile(configs, res); 
    //return the handleTile function, add 2nd argument and pass res through
});

handleTile 函数内部,您可以调用 S3

function handleTile(configs, res){
    client.readFile('filename', function(error, imageStream){
        imageStream.pipe(res);
    });
}

现在请求这样的图像:

<img src="/path/to/my/file/that/matches/regexp/expression"/>

它将从 S3 存储桶请求该图像并将资源直接流式传输回客户端。

【讨论】:

  • 我一直在使用aws-sdk 发出获取请求。 var aws = new AWS.S3(); var params = { Bucket: this.bucket, Key: this.tileDirectory + this.filepath, Range: 'bytes=' + (this.toffset + 4) + "-" + (this.tsize + this.toffset + 4) }; var ts = this; aws.getObject(params, function(err, data){ if(ts.tile == null){ ts.tile = data.Body; //S3 get object }}; client 会假设我以另一种方式做吗?还有其他方法吗?
  • @tibsar 我用client 但你用aws 作为你的变量,没什么大不了的。在这种情况下,getObject() 上的函数回调的第二个参数是您的流,因此您可以将其直接通过管道传递到您的 express 函数内部带有 data.pipe(res) 的响应。
  • 好的,我想我明白你在说什么了。打算试试看。
  • 原来我仍然很困惑。所以你是说按照aws.readFile(ts.tile, function(error, imageStream){ . . . 的方式做一些事情?
  • @tibsar 我认为您应该可以在 getObject 函数中执行 data.pipe(res)。请注意,在这种情况下,getObjectreadFile 不应一起使用,因为它们的用途非常相似。它们只是接受不同的参数。
【解决方案2】:

要成功渲染图像,您必须实现三个步骤:

  1. 检索图像数据(例如作为通过fs.readFile 读取的缓冲区)或流(例如通过fs.createReadStream

  2. Set 带有参数(req, res) 的 Web 请求处理程序中的相应标头;像

res.writeHead(200, {'Content-Type': 'image/png'});

  1. Write 文件。如果您将文件放在缓冲区中,则使用

    res.end(buf, 'binary');

    如果你有一个流通过

    read_stream.pipe(res)

整个代码可能看起来像(假设您想从当前目录提供文件image.jpg):

'use strict';
var fs = require('fs');
var http = require('http');

http.createServer(function(req, res) {
    fs.readFile('image.jpg', function(err, buf) {
        if (err) {
            res.writeHead(500);
            res.end('Cannot access file.');
            return;
        }

        res.writeHead(200, {'Content-Type': 'image/jpeg'});
        res.end(buf, 'binary');
    });
}).listen(8002, '');

使用流,一个非常简单的版本(注意:没有错误处理,错误处理可能会变得更复杂,这取决于您希望如何处理读取文件时发生的错误)

'use strict';
var fs = require('fs');
var http = require('http');

http.createServer(function(req, res) {
    var stream = fs.createReadStream('image.jpg');
    // Error handling omitted here
    res.writeHead(200, {'Content-Type': 'image/jpeg'});
    stream.pipe(res);
}).listen(8003, '');

使用缓冲区的代码更容易编写,但这意味着您的服务器必须将整个文件保存在内存中 - 例如,您将无法提供320 Gigapixel image 文件。您也只有在拥有整个文件后才开始发送数据。

使用流可以在您获得文件后立即发送,因此速度会更快一些。如果您从文件或本地快速服务器读取速度差异可能可以忽略不计。此外,您只需要一点点内存。另一方面,错误处理更复杂。

【讨论】:

  • 所以我的图像在缓冲区中。我需要在写之前阅读它吗?
  • 是的,这是第 1 步。我添加了一个从文件系统读取文件的示例代码。当然,如果您的图像源不是文件系统而是数据库或远程服务器,则读取部分(步骤 1)看起来会有所不同。
  • 使用流和其他方式有什么区别?
  • 所以我试了一下,它看起来像是到达http.createServer(function(req, res){,但永远不会到达fs.readFile(ts.tile, function(err, data){。它只是挂起,没有抛出任何错误。知道为什么它不会进入函数吗?
  • @tibsar ts.tile 是什么?如果这不是直接在文件系统上的图像路径,它只会转储并且不会提供任何错误,因为 OP 提供了伪代码。
猜你喜欢
  • 2021-11-28
  • 2013-07-19
  • 1970-01-01
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多