none
大きな画像の作成と編集 RRS feed

  • 質問

  • photoshopなどのようにメモリに全てを確保できないほどの大きな画像の作成と編集をしたいと思っています。
    方法としては画像本体をハードディスクの方において、編集した情報だけを書き込もうと思っています。
    モニタに表示する際は、縮小された画像を表示するために、分割したブロックを縮小した情報を得る事の繰り返しで作ろうと思ってます。
    さらに使うメモリの量はユーザーの方でコントロールしたいと思ってます。
    それとできるなら、画像を分割する処理をしてもdrawlineや塗りつぶしなどの関数も自分で作らないで済む方がいいです。(これは無理でも大丈夫です。)
    そういった場合どうすればいいのでしょうか?
    2009年11月28日 18:33

回答

  • 外池と申します。

    すでにみなさんが回等されていることのまとめになりますが、

    1)画像本体生データをファイル上に置いてバイナリ形式でランダムアクセスする。(任意の場所の任意のバイト数のデータを読み書きできるようにする。)

    2)その画像(またはその一部)を表示のために縮小した(なんらかの方法でピクセル数を少なくした)画像を用意しこれはメモリ上に置く。

    3)表示された画像上の位置と元画像の位置を関連づける機能を備える。 表示されている画像に対して編集の操作が行われれば、この関連付けを用いて上述1)の機能で生データにアクセスするデータの位置を決定する。

    こんな感じになろうかと思います。2)の画像データが用意できていれば、それを表示することはGDIなりGDI+なりで簡単にできると思うのですが、難しいのは1)だと思います。真正直に1)だけを実装して、3)の操作の度にファイルにアクセスしに行っては、おそらく遅くてやってられないと想像します。1)と3)を連動させたなんらかのキャッシュ機能を独自に実装しないといけないと思います。

    写真が趣味なものでphotoshop以外にもラスターデータの画像処理ソフトをいじった経験がありますが、このキャッシュ機能の良し悪しで操作の快適さが大きく左右されるので、相当に上手くやる必要がある(ノウハウが必要)と思います。


    (ホームページを再開しました)
    2009年11月30日 4:27

すべての返信

  • 使用言語というか、環境というか何を想定されているのでしょうか?
    また、大きなというのはどのぐらいのサイズでしょうか?

    私の場合、HTMLのCSS Spriteのための画像作成に.NET Frameworkを使用していますが、15,000pxの画像も問題なく作成できています。
    作成した画像を保存する際にも考慮が必要です。GIFやBMPやJPEG辺りですと最大サイズが65,536 x 65,536だったと思います。PNGは4Gpxかな。

    あとはもっと根本的なこととして、ラスターイメージではなくベクタイメージを採用すれば、サイズは関係なくなります。PhotoshopでなくIllustratorの守備範囲です。
    2009年11月28日 23:57
  • 扱えないとしている画像のサイズ、あるいはアプリケーションでのメモリの利用状況次第でしょうか。
    今回の画像以外にもメモリでデータを持っているものが多数いるのであれば、15,000px * 15,000px でも持てないかもしれません。

    試しに、Windows XP (x86) で 15,000px * 15,000px で Bitmap を 24bpp で作り、Graphics.FromImage を経て、DrawLine したところ、600MB はメモリを使っていそうでした。

    # 巨大な画像の場合、綺麗に連続した空き領域が必要なので、状況によっては仮想メモリ空間での空き領域断片化していて、確保できないこともある。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2009年11月29日 0:50
    モデレータ
  • >佐祐理さん
    使用言語はc#でもc++でもよいです。win32apiを使っても大丈夫です。
    photoshopでテストする限り1500pixel/inchの20インチ×インチでも問題なく使えるため、最低これくらいを扱えるようにしたいです。
    >佐祐理さんの言うとおりBMPだと保存できませんでした。こういう制限があることは知りませんでした。pngやフォトショップ形式だと保存して開くこともできました。
    ベクターイメージは考えていません。あくまでラスターイメージーで扱う事を考えています。

    >Azuleanさん
    そうですね。確かに連続したメモリ量がないとエラーがでます。ですので、ですのでこちらで扱うメモリの量をアバウトでも良いので決めたいと思っています。

    自分で調べて今ネックなのがファイルの一部だけを読む方法が見つからないことです。filemappingですと最初から途中までは読めるのですが、途中から途中までを読むことができないみたいですし、ファイルストリームでも同じみたいです。
    ファイルを分割して保存を考えたのですが、他のソフトとの連携を考えますとなしの方向でお願いします。理由は一枚の大きな画像を開く際に、これを分割するには、やはりファイルを途中から読めないといけないと思うためです。

    面倒な質問とは思いますがよろしくお願いします。

    2009年11月29日 12:20
  • 自分で調べて今ネックなのがファイルの一部だけを読む方法が見つからないことです。
    ファイルのバイナリとして途中から途中を読み込むことはできますが、System.Drawing.Bitmap クラスとして部分的に読み出すことはできません。
    .NET Framework が利用している GDI+ が、そういう設計で作られているためです。
    GDI+ ベースで考えると、部分的な読み書きは難しいでしょう。
    (Bitmap ファイルなら自力で読み書きできなくはないでしょうが、JPEG や PNG との変換を考えると難しい)


    Photoshop は .NET Framework や GDI+ を使っているわけではなく、独自のライブラリで処理しているのではないでしょうか。(詳細は調べていません)
    # 「最低」と表現していますが、ハードルが高いのではないかと思いますが…。

    WPF 側のクラス群がそのあたりをうまくフォローしているかどうかは試していないので回答できる状態にありません。

    # 他に可能性があるとすれば、サードパーティ製ライブラリを買うとか。

    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2009年11月29日 12:56
    モデレータ
  • filemappingもストリームも4GBを超える大きなファイルを扱うことは可能です。できなかったのだとするとアイキどうどうさんの操作手順に何か問題があったのだと思います。

    Photoshopで扱えないのは、やはりそのサイズではラスターイメージの需要がほとんどないからなのでは。

    最初の質問にはdrawlineとありましたが、これはまさしくベクターです。
    ご存じとはお思いますが、drawlineをラスターイメージ上に展開してしまうと、1dotずつの情報に分解され復元できません。ベクターイメージでしたらdrawlineの情報は残るため、後から解像度を変更することも可能です。

    最終アウトプットはどのようなものなのでしょうか? それがラスターイメージだとして、途中の作業ではベクターイメージの選択肢はないのでしょうか?
    2009年11月30日 0:12
  • 外池と申します。

    すでにみなさんが回等されていることのまとめになりますが、

    1)画像本体生データをファイル上に置いてバイナリ形式でランダムアクセスする。(任意の場所の任意のバイト数のデータを読み書きできるようにする。)

    2)その画像(またはその一部)を表示のために縮小した(なんらかの方法でピクセル数を少なくした)画像を用意しこれはメモリ上に置く。

    3)表示された画像上の位置と元画像の位置を関連づける機能を備える。 表示されている画像に対して編集の操作が行われれば、この関連付けを用いて上述1)の機能で生データにアクセスするデータの位置を決定する。

    こんな感じになろうかと思います。2)の画像データが用意できていれば、それを表示することはGDIなりGDI+なりで簡単にできると思うのですが、難しいのは1)だと思います。真正直に1)だけを実装して、3)の操作の度にファイルにアクセスしに行っては、おそらく遅くてやってられないと想像します。1)と3)を連動させたなんらかのキャッシュ機能を独自に実装しないといけないと思います。

    写真が趣味なものでphotoshop以外にもラスターデータの画像処理ソフトをいじった経験がありますが、このキャッシュ機能の良し悪しで操作の快適さが大きく左右されるので、相当に上手くやる必要がある(ノウハウが必要)と思います。


    (ホームページを再開しました)
    2009年11月30日 4:27
  • 皆さん返信ありがとうございます。
    >Azuleanさん
    >JPEG や PNG との変換を考えると難しい
    そうですか。分割でやろうとすると自作しないといけないみたいですね。結構手間がかかるとは思いますが、やってみようと思います。
    ただ、しばらくは分割で保存して印刷などをするときは他のソフトに頼る事になると思います。

    >佐祐理さん
    >filemappingもストリームも4GBを超える大きなファイルを扱うことは可能です。できなかったのだとするとアイキどうどうさんの操作手順に何か問題があったのだと思います。
    filemappingでやった際はエラーは出ませんでした。ただDIBsectionに全てを適用させるとエラーが出ましたけど。それと
    >確かに連続したメモリ量がないとエラーがでます
    というのは、.NETのbitmapで行った場合です。
    ただfilemappingが上手くいかないと申し上げたのはCreateFileMappingをした際にメモリを多く消費したせいです。てっきり私はMapViewOfFileするまではメモリ上には何も確保しないと思っていました。MapViewOfFileでメモリにデータをのせて、メモリの消費量を自分の方でコントロールできるものと思っていました。(関係ないかもしれませんが、私のPCのメモリは4Gで3Gの適用をしています)

    ベクタはオプションとしてはありますが、目的のためにはラスタでないといけないので主幹部分にベクタを入れるのは避けないです。
    ソフトの目的は画像の編集と作成です。イメージを伝えるのは苦手ですが、分かりやすく単純にいうとphotoshopとペインターを合わせた感じだと思っていただければよいと思います。

    >外池さん
    ありがとうございます。そんな感じです。スピードは初めのうちは多少遅くても大丈夫です。


    今あまり時間がとれないのですが、これからちょっとやってプログラムを組んでみようと思います。バイナリで途中からデータにアクセスする方法などに関して質問してもよいのでしょうか?
    もしよければ、ヒントだけでもいただけると嬉しいです。たぶんアクセスする方法は複数あると思いますのでメモリとの相性などで試してみたいのでよろしくお願いします。
    2009年11月30日 16:51
  • 外池です。

    バイナリファイルを扱うAPIを挙げればよろしいのでしょうか? .Net Frameworkであれば、一番原始的なものはFileStreamオブジェクトを使う方法かと思います。Seekメソッドでファイル上の任意の位置に移動して、そこで読み書きしたいバイト数を指定しながらReadやWriteメソッドを使ってやります。Win32 APIも同等のものがあると思います。


    (ホームページを再開しました)
    2009年12月1日 2:53