我正在寻找一种反应方式来调整存储在GridFS中的图像。
有一篇文章here,但遗憾的是它使用的Casbah不是非笨蛋。
还有good library用于调整图像大小。虽然它支持异步操作,但我找不到一种方法来重新调整图像块的大小。也许根本不可能。然后我很好,但是请你帮我理解如何将Enumerator(我从GridFS获得)转换为scrimage(image resizer lib)可用的简单流。
答案 0 :(得分:3)
我必须首先开始(我发现我一直这样做)是首先考虑你为什么要使用GridFS。
正如我之前所说,这来自于一个常见的误解,即GridFS是MongoDB存储文件的方式,因此这就是你所使用的。所以我建议任何人考虑,甚至阅读这篇文章,以便阅读以下两个链接上的文件:
http://docs.mongodb.org/manual/faq/developers/#when-should-i-use-gridfs
http://docs.mongodb.org/manual/core/gridfs/
总结是,GridFS的唯一目的是能够存储更大的内容 16MB BSON文档限制。实质上,文档将 chunked 分成更小(超过16MB)的部分并插入到特殊集合中。这有助于使用简化的界面处理读取和写入的大小限制,以获取所需的所有文档。
额外信息是GridFS 不 MongoDB魔法。 服务器不知道存储的信息,只是它只是另一个文档。因此,GridFS是驱动程序规范实现,这意味着每次读取和写入都会通过网络产生多个文档请求。
现在真正的问题是,当您的内容低于16MB 时,您最好只将其作为数据插入普通文档字段(二进制文件当然需要进行base64编码),并且你所有的读写都是通过电线以一次性进行的。
对于这个实现案例,你的图像小于16MB,你会得到一个单独的文档,带有一个包含字符串的字段,这对于解析流来说很简单(来自base64)和返回内容。或者基本上是转换上的任何内容,因为您不必担心返回到MongoDB服务器的其他调用以获得更多“块”。
如果您真的需要200MB High Res Photoshop文档作为您的数据源,那么请继续使用GridFS。在这种情况下,这可能就是你想要的。
没有装袋GridFS,这是一个非常好的主意。只是大多数使用它的人并没有将它用于它的设计目标。
P.S进行任何流式转换的真正问题是,为了做到这一点,你需要几个关于图像的元数据(通常不能从库方法获得,直到可以访问整个文件内容)。因此,无论如何,您都要存储自定义信息,以实现目标。
答案 1 :(得分:0)
根据我的理解,存储和从GridFS中获取二进制数据总是有意义的,因为MongoDB / ReactiveMongo使用整个文档的“流”来回答查询。将(潜在的巨大的)二进制数据存储在一个文档中不允许真正流式传输数据。相反,二进制数据首先被完全读入存储器,由于资源限制,这不是一个好主意。
回到原来的问题,这里的主要问题基本上是如何将OutputStream(Iteratee可能写入的)连接到图像处理库所需的InputStream。有关详细信息,请参阅http://ostermiller.org/convert_java_outputstream_inputstream.html。
以下代码应该有希望解释这个概念:
import java.io._
import java.util.Arrays
import scala.concurrent._
import ExecutionContext.Implicits.global
import play.api.libs.iteratee._
object StreamingDemo extends App {
// this enumerator will come from GridFS in your scenario
val enumerator = Enumerator[Array[Byte]](Array(1, 2), Array(3), Array(4, 5, 6)) andThen Enumerator.eof
val in = new PipedInputStream();
val out = new PipedOutputStream(in);
def putDataOnOutputStream(out: OutputStream) = {
// as we have a Future here writing to the OutputStream is done in a separate thread as needed with piping
enumerator.apply(Iteratee.foreach { elem =>
println("write...");
out.write(elem)
out.flush()
}).onComplete { _ =>
out.close()
}
}
def processDataFromInputStream(in: InputStream) = {
var res: Int = in.read
while (res != -1) {
println("read: " + res);
res = in.read
}
in.close()
}
putDataOnOutputStream(out)
processDataFromInputStream(in);
}