.NET GDI +图像大小 - 文件编解码器限制

时间:2010-05-28 20:49:29

标签: .net gdi+ codec

可以使用.NET提供的图像文件编解码器编码的图像大小是否有限制?

我正在尝试编码图像> 4GB大小,但它根本不起作用(或无法正常工作,即写出不可读的文件)与.bmp,.jpg,.png或.tif编码器。

当我将图像尺寸降低到< 2GB它适用于.jpg,但不适用于.bmp,.tif或.png。

我的下一次尝试是尝试libtiff,因为我知道tiff文件适用于大图像。

大图像有什么好的文件格式?或者我只是达到文件格式限制?

(所有这些都是在64位操作系统(WinXP 64)上完成的,带有8 GB RAM,并使用x64架构进行编译。)

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内存区域,但这仅限于&lt; 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();

3 个答案:

答案 0 :(得分:2)

您遇到的问题很可能是.NET Framework中的以下限制:GC堆中允许的最大对象大小为2GB,即使在64位OS /版本上也是如此。

部分参考文献:linklinklink

根据您的需要,使用像TIFF这样的相对简单(未压缩)的格式,可能可以部分生成您的图像并在之后合并这些部分。只是一个想法..

答案 1 :(得分: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年代或更早版本中创建的其他图像格式中找到类似的限制。当磁盘只有数十兆字节时,多GB的文件大小限制不被视为问题。

答案 2 :(得分:1)

所以你的目标是将它们编码为jpeg?我确信只有一种方法可以只输入你编码的部分,然后处理并继续下一部分。如果您打开原始文件并自行解析,我相信有开源jpeg编码器可以帮助创建这些部分。这应该允许您对非常大的文件进行编码,但是您将始终需要克服操作系统和文件系统障碍。