1

I'm looking for a reactive way to resize images which are stored in GridFS.

There is an article here but unfortunately it uses Casbah which is not non-bloking.

And also there is a good library for image resizing. Although it supports async operations, I couldn't find a way to resize an image chunk-by-chunk. Maybe it's not possible at all. Then I'm OK but would you please help me to understand how can I convert an Enumerator (which I get from GridFS) to a simple stream which is usable by scrimage (image resizer lib).

4

2 に答える 2

3

私が最初に始めなければならないこと (そして、私はいつもそうしていることに気づきました) は、そもそもなぜ GridFS を使用しているのかを考えることです。

これは、前に述べたように、GridFS は MongoDB がファイルを格納する方法であり、したがってそれを使用するという一般的な誤解から来ています。したがって、この投稿を検討している、またはこの投稿を読んでいる人には、次の 2 つのリンクにあるドキュメントを読むことをお勧めします。

http://docs.mongodb.org/manual/faq/developers/#when-should-i-use-gridfs

http://docs.mongodb.org/manual/core/gridfs/

要約すると、GridFS の唯一の目的は、16MBのBSON ドキュメント制限を超えるコンテンツを格納できるようにすることです。基本的に、ドキュメントは小さな (16 MB 未満) の部分にチャンクされ、特別なコレクションに挿入されます。これにより、必要なすべてのドキュメントを取得するための簡素化されたインターフェイスを使用して、読み取りと書き込みの両方でサイズ制限を簡単に処理できます。

追加情報は、GridFS はMongoDB の魔法ではないということです。サーバーは、保存されている情報が単なる別のドキュメントであること以外は何も知りません。したがって、GridFS はドライバー仕様の実装です。つまり、読み取りと書き込みのたびに、複数のドキュメント リクエストがネットワーク上で発生します。

ここで重要なのは、コンテンツが16MB 未満の場合は、通常のドキュメント フィールドにデータとして挿入するだけのほうがよいということです (バイナリはもちろん base64 でエンコードする必要があります)。ワイヤー。

画像が 16MB 未満であるこの実装の場合、単一のドキュメントが返されます。これには、String を含むフィールドがあり、(base64 から) ストリーミング解析してコンテンツを返すのは簡単です。または、基本的に変換に関するものは何でも、追加の呼び出しが MongoDB サーバーに返されて「チャンク」が増えることを心配する必要はありません。

データ ソースとして 200MB の高解像度 Photoshop ドキュメントが本当に必要な場合は、ぜひ GridFS を使用してください。その場合、それはおそらくあなたが望むものです。

GridFS を袋に入れません。それは本当に良い考えです。それを使用しているほとんどの人が、それが設計された目的のために使用していないというだけです.

PSストリーミング変換を行う際の実際の問題は、これを行うために、画像に関するいくつかのメタデータが必要になることです(通常、ファイルコンテンツ全体にアクセスできるようになるまで、ライブラリメソッドからは利用できません)。したがって、目標を達成するために、とにかくカスタム情報を保存することになります。

于 2014-02-11T08:51:01.763 に答える
0

私の理解では、MongoDB/ReactiveMongo はドキュメント全体の「ストリーム」でクエリに応答するため、バイナリ データを GridFS に格納したり、GridFS から取得したりすることは常に意味があります。(潜在的に巨大な) バイナリ データを 1 つのドキュメントに格納しても、データを実際にストリーミングすることはできません。代わりに、バイナリ データが最初に完全にメモリに読み込まれますが、これはリソースの制限によりお勧めできません。

元の質問に戻りますが、ここでの主な問題は、基本的に、(Iteratee が書き込む可能性のある) OutputStream を、画像処理ライブラリが必要とする 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);

}
于 2014-02-12T09:51:17.403 に答える