6

.NET から入手できる画像ファイル コーデックを使用してエンコードできる画像のサイズに制限はありますか?

サイズが 4GB を超える画像をエンコードしようとしていますが、.bmp、.jpg、.png、または .tif エンコーダーでは機能しません (または正しく機能しない、つまり、読み取り不能なファイルを書き出す)。

画像サイズを < 2GB に下げると、.jpg では機能しますが、.bmp、.tif、または .png では機能しません。

私の次の試みは、libtiff を試すことです。なぜなら、tiff ファイルは大きな画像用であることを知っているからです。

大きな画像に適したファイル形式は何ですか? または、ファイル形式の制限に達しているだけですか?

(これらはすべて、8 GB の RAM を搭載し、x64 アーキテクチャを使用してコンパイルされた 64 ビット オペレーティング システム (WinXP 64) で実行されています。)

Random r = new Random((int)DateTime.Now.Ticks);

int width = 64000;
int height = 64000;
int stride = (width % 4) > 0 ? width + (width % 4) : width;
UIntPtr dataSize = new UIntPtr((ulong)stride * (ulong)height);
IntPtr p = Program.VirtualAlloc(IntPtr.Zero, dataSize, Program.AllocationType.COMMIT | Program.AllocationType.RESERVE, Program.MemoryProtection.READWRITE);

Bitmap bmp = new Bitmap(width, height, stride, PixelFormat.Format8bppIndexed, p);
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);

ColorPalette cp = bmp.Palette;
for (int i = 0; i < cp.Entries.Length; i++)
{
  cp.Entries[i] = Color.FromArgb(i, i, i);
}
bmp.Palette = cp;

unsafe
{
  for (int y = 0; y < bd.Height; y++)
  {
    byte* row = (byte*)bd.Scan0.ToPointer() + (y * bd.Stride);
    for (int x = 0; x < bd.Width; x++)
    {
      *(row + x) = (byte)r.Next(256);
    }
  }
}

bmp.UnlockBits(bd);
bmp.Save(@"c:\test.jpg", ImageFormat.Jpeg);
bmp.Dispose();

Program.VirtualFree(p, UIntPtr.Zero, 0x8000);

固定された GC メモリ領域も使用してみましたが、これは 2GB 未満に制限されています。

Random r = new Random((int)DateTime.Now.Ticks);

int bytesPerPixel = 4;
int width = 4000;
int height = 4000;         
int padding = 4 - ((width * bytesPerPixel) % 4);
padding = (padding == 4 ? 0 : padding);
int stride = (width * bytesPerPixel) + padding;
UInt32[] pixels = new UInt32[width * height];
GCHandle gchPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);
using (Bitmap bmp = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, gchPixels.AddrOfPinnedObject()))
{
    for (int y = 0; y < height; y++)
    {
        int row = (y * width);
        for (int x = 0; x < width; x++)
        {
            pixels[row + x] = (uint)r.Next();
        }
    }

    bmp.Save(@"c:\test.jpg", ImageFormat.Jpeg);
}
gchPixels.Free();
4

3 に答える 3

2

直面している問題は、.NET Frameworkで次の制限がある可能性が非常に高いです。GCヒープで許可される最大オブジェクトサイズは、64ビットOS/ビルドでも2GBです。

いくつかの参照:リンクリンクリンク

必要に応じて、TIFFのような比較的単純な(非圧縮の)形式を使用すると、画像をパーツで生成し、後でパーツをマージすることができる場合があります。ただのアイデア..

于 2010-05-28T21:24:59.027 に答える
1

それであなたの目標はそれらをjpegにエンコードすることですか?エンコードしているセクションだけをプルして、破棄して次のセクションに進む方法があると確信しています。ファイルを生で開いて自分で解析すると、セクションの作成に役立つオープンソースのjpegエンコーダーがそこにあると確信しています。これにより、非常に大きなファイルをエンコードできるようになりますが、OSとファイルシステムのハードルを常に克服する必要があります。

于 2010-09-07T16:55:49.787 に答える
1

TIFF仕様セクション2から: http: //partners.adobe.com/public/developer/en/tiff/TIFF6.pdfのTIFF構造:

TIFFは画像ファイル形式です。このドキュメントでは、ファイルは8ビットバイトのシーケンスとして定義されており、バイトには0からNまでの番号が付けられています。可能な最大のTIFFファイルの長さは2**32バイトです。

残念ながら、多くのTIFFライターとリーダーは、実装に符号付き整数を使用し、実際のサイズを2**31に減らします。これは、Cristopheが述べたように、画像全体をメモリに保持しようとするドライバーによる頻繁な試みによって悪化します。

80年代以前に作成された他の画像形式でも、同様の制限が発生する可能性があります。ディスクが数十メガバイトしかない場合、数ギガバイトのファイルサイズ制限は問題とは見なされませんでした。

于 2010-06-06T23:04:12.720 に答える