Ошибка нехватки памяти при загрузке растрового изображения - PullRequest
5 голосов
/ 25 июня 2010

Я работаю с изображениями большого размера (например, 16000x9440 px) и вырезаю некоторые области для других целей.Я получаю исключение «Недостаточно памяти» при создании нового экземпляра растрового изображения:

using (FileStream fileStream = new FileStream(mapFileResized, FileMode.Open))
{
    byte[] data = new byte[fileStream.Length];
    fileStream.Read(data, 0, data.Length);
    using (MemoryStream memoryStream = new MemoryStream(data))
    {
        using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
        {
            tile = new Bitmap(tileWidth, tileHeight, PixelFormat.Format24bppRgb);
            tile.SetResolution(src.HorizontalResolution, src.VerticalResolution);
            tile.MakeTransparent();
            using (Graphics grRect = Graphics.FromImage(tile))
            {
                grRect.CompositingQuality = CompositingQuality.HighQuality;
                grRect.SmoothingMode = SmoothingMode.HighQuality;
                grRect.DrawImage(
                        src,
                        new RectangleF(0, 0, tileWidth, tileHeight),
                        rTile,
                        GraphicsUnit.Pixel
                );
            }
        }
    }
}

Когда я использую изображения небольшого размера (например, 8000x4720 px), тогда все работает нормально.

Как мне работать с изображениями большого размера?

Плитка PS Битовая карта расположена в блоке finally.

С уважением, Алекс.

Ответы [ 3 ]

6 голосов
/ 25 июня 2010

Вы используете около гигабайта оперативной памяти, не очень удивительно, что вам не хватает памяти.

Предполагая, что вы используете формат файла 32bpp с 16000x9440 пикселей, вы получаете размер файла примерно:

16000 *9440* (32/8) = ~ 576 МБ

byte[] data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
using (MemoryStream memoryStream = new MemoryStream(data))
{
  [... snip ...]
}

Вы загружаете весь файл в поток памяти, для этого требуется 576 МБ.

[... snip ...]
    using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
    {
        [... snip ...]
    }
[... snip ...]

Вы загружаете все содержимое потока в растровое изображение, для этого требуется как минимум еще 576 МБ (в зависимости от того, сколько памяти требуется растровому изображению на пиксель, должно быть не менее 4, вероятно, больше). В этот момент в памяти дважды появляется изображение, которое серьезно мешает таким большим изображениям.

Вы можете уменьшить объем занимаемой памяти, избавившись от потока памяти и загрузив растровое изображение непосредственно из потока файлов.

Другим решением было бы загрузить только часть растрового изображения и загрузить другие части по требованию (так же, как карты Google), но я не могу помочь вам с этим решением, может потребоваться чтение растрового изображения вручную.

3 голосов
/ 25 июня 2010

Не полный ответ на ваш вопрос, но вам, вероятно, лучше использовать такую ​​библиотеку, как ImageMagick.NET

2 голосов
/ 25 июня 2010

MemoryStream реализовано с использованием массива байтов, в котором хранятся данные. Если вы прочитали больше данных, чем может вместить массив, выделяется новый массив двойного размера, и байты копируются из одного массива в другой.

Поскольку вы, очевидно, знаете, сколько данных вам понадобится, вы можете заранее выделить правильный размер и таким образом избежать изменения размера.

Однако, как только вы достигнете определенного размера, вам не хватит памяти. .NET налагает ограничение в 2 ГБ для одного объекта ( даже для 64-битных ), поэтому внутренний массив в MemoryStream никогда не сможет расти дальше этого уровня. Если ваше изображение больше этого, вы получите исключение нехватки памяти.

...