2009-02-20 3 views
11

Я пытаюсь написать небольшое приложение для просмотра изображений. Однако с .NET существуют ограничения на системную память.Как использовать большие растровые изображения в .NET?

При попытке загрузить большие растровые изображения (9000 x 9000 px или больше, 24-бит), я получаю Исключение System.OutOfMemoryException. Это на ПК с Windows 2000 с 2 ГБ оперативной памяти (из которых 1,3 ГБ используется). Это также занимает много времени, чтобы попытаться загрузить файлы.

Следующий код создает эту ошибку:

Image image = new Bitmap(filename); 
using (Graphics gfx = this.CreateGraphics()) 
{ 
    gfx.DrawImage(image, new Point(0, 0)); 
} 

Как делает этот код:

Stream stream = (Stream)File.OpenRead(filename); 
Image image = Image.FromStream(stream, false, false); 
using (Graphics gfx = this.CreateGraphics()) 
{ 
    gfx.DrawImage(image, new Rectangle(0, 0, 100, 100), 4000, 4000, 100, 100, GraphicsUnit.Pixel); 
} 

Кроме того, это достаточно, чтобы сделать только это:

Bitmap bitmap = new Bitmap(filename); 
IntPtr handle = bitmap.GetHbitmap(); 

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

http://bytes.com/groups/net-c/279493-drawing-large-bitmaps

Я знаю из других приложений (Internet Explorer, MS Paint и т.д.), что можно открывать большие изображения, и довольно быстро. Мой вопрос: Как использовать большие растровые изображения с .NET?

Есть ли все равно, чтобы передать их или загрузить их без памяти?

ответ

8

Это вопрос из двух частей.Первый вопрос заключается в том, как вы можете загружать большие изображения без исчерпания памяти (1), а второй - для повышения производительности загрузки (2).

(1) Конспект приложения, такого как Photoshop, где вы можете работать с огромными изображениями, потребляющими гигабиты в файловой системе. Сохранение всего изображения в памяти и до сих пор достаточное количество свободной памяти для выполнения операций (фильтры, обработка изображений и т. Д. Или даже просто добавление слоев) было бы невозможно в большинстве систем (даже 8 ГБ x64 систем).

Именно поэтому приложения, подобные этому, используют концепцию файлов подкачки. Внутри я предполагаю, что Photoshop использует собственный формат файла, подходящий для их дизайна приложения и построенный для поддержки частичных нагрузок от swap, позволяя им загружать части файла в память для его обработки.

(2) Performande можно улучшить (довольно много), написав пользовательские загрузчики для каждого формата файла. Это требует, чтобы вы прочитали заголовки файлов и структуру форматов файлов, с которыми хотите работать. Как только вы получили руку от нее, это не ****, но это не так просто, как вызов метода.

Например, вы можете google для FastBitmap, чтобы увидеть примеры того, как вы можете быстро загрузить файл растрового изображения (BMP), включив в него декодирование заголовка растрового изображения. Это включало PInvoke и дать вам некоторое представление о том, что вы против вам нужно будет определить растровые structues такие как

 [StructLayout(LayoutKind.Sequential, Pack = 1)] 
     public struct BITMAPFILEHEADER 
     { 
      public Int16 bfType; 
      public Int32 bfSize; 
      public Int16 bfReserved1; 
      public Int16 bfReserved2; 
      public Int32 bfOffBits; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct BITMAPINFO 
     { 
      public BITMAPINFOHEADER bmiHeader; 
      public RGBQUAD bmiColors; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct BITMAPINFOHEADER 
     { 
      public uint biSize; 
      public int biWidth; 
      public int biHeight; 
      public ushort biPlanes; 
      public ushort biBitCount; 
      public BitmapCompression biCompression; 
      public uint biSizeImage; 
      public int biXPelsPerMeter; 
      public int biYPelsPerMeter; 
      public uint biClrUsed; 
      public uint biClrImportant; 
     } 

Возможно работать с созданием DIB (http://www.herdsoft.com/ti/davincie/imex3j8i.htm) и странности, как данные хранятся «вверх ногами «в растровом изображении, которое вам нужно учесть, или вы увидите зеркальное изображение, когда и откройте его :-)

Теперь это только для растровых изображений. Предположим, вы хотели сделать PNG, тогда вам нужно будет делать похожие вещи, но декодировать заголовок PNG, который в своей простейшей форме не так уж и трудный, но если вы хотите получить полную поддержку спецификации PNG, то вам нужно развлечься:)

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

string[] chunks = 
new string[] {"?PNG", "IHDR","PLTE","IDAT","IEND","tRNS", 
"cHRM","gAMA","iCCP","sBIT","sRGB","tEXt","zTXt","iTXt", 
"bKGD","hIST","pHYs","sPLT","tIME"}; 

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

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

Короткий ответ заключается в том, что возможности обработки изображений в BCL не так горячие. Средний ответ заключался бы в том, чтобы попытаться найти, если кто-то написал библиотеку изображений, которая могла бы вам помочь, и длинный ответ заключался бы в том, чтобы вытащить рукава и самостоятельно написать ядро ​​вашего приложения.

Поскольку вы знаете меня в реальной жизни вы знаете, где меня найти;)

0

насчет:

Image image = new Bitmap(filename); 
using (Graphics gfx = Graphics.FromImage(image)) 
{  
// Stuff 
} 
+0

Я не думаю, что это будет работать на 32-битной системе, основанной на ограничениях. – WiiMaxx

0

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

0

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

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

Возможно, имеются доступные библиотеки замены, которые работают с этими проблемами со стандартными загрузчиками?

0

Значит, вы говорите, что это не загрузка растрового изображения, а рендеринг, который вызывает нехватку памяти?

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

3

Для полноценного ответа я бы использовал Reflector, чтобы посмотреть исходный код Paint.NET (http://www.getpaint.net/); усовершенствованная программа редактирования графики, написанная на C#.

(как указано в комментарии, Paint.NET использовался с открытым исходным кодом, но теперь он закрыт).

+0

Paint.net - это программа с закрытым исходным кодом с конца 2007 года (http: //blog.getpaint.net/2007/12/04/freeware-authors-beware-of-% E2% 80% 9Cbackspaceware% E2% 80% 9D /) – zihotki

+0

Это очень плохо. Я отредактировал, чтобы отразить ваш комментарий. – ine

0

Одно только меня поразило. Вы рисуете все изображение, а не только видимую часть? Вы не должны нарисовать большую часть изображения, чем вы показываете в своем приложении, используйте параметры x, y, width и heigth, чтобы ограничить рисованную область.

Смежные вопросы