2009-02-20 13 views
11

Tôi đang cố gắng viết một ứng dụng xem hình ảnh có trọng lượng nhẹ. Tuy nhiên, có những giới hạn bộ nhớ hệ thống với .NET.Làm cách nào để sử dụng các bitmap lớn trong .NET?

Khi cố gắng tải các ảnh bitmap lớn (9000 x 9000 px hoặc lớn hơn, 24-bit), tôi nhận được một System.OutOfMemoryException. Đây là trên một máy tính Windows 2000 với 2GB RAM (trong đó 1,3GB được sử dụng hết). Nó cũng mất rất nhiều thời gian để thử tải các tập tin.

Các mã sau đây tạo ra lỗi này:

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

Như làm mã này:

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); 
} 

Ngoài ra, nó là đủ để làm điều này:

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

Mã sau được dự định để sử dụng với GDI. Trong khi nghiên cứu điều này, tôi phát hiện ra rằng đây thực tế là một vấn đề bộ nhớ trong đó .NET cố gắng phân bổ gấp đôi số lượng cần thiết trong một khối bộ nhớ liền kề duy nhất.

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

Tôi biết từ các ứng dụng khác (Internet Explorer, MS Paint vv) mà nó IS có thể mở hình ảnh lớn, và khá nhanh chóng. Câu hỏi của tôi là, làm cách nào để sử dụng các bitmap lớn với .NET?

Có cách nào để truyền phát hoặc tải bộ nhớ không?

Trả lời

8

Đây là câu hỏi gồm hai phần.Câu hỏi đầu tiên là làm thế nào bạn có thể tải hình ảnh lớn mà không cần hết bộ nhớ (1), thứ hai là cải thiện hiệu năng tải (2).

(1) Concider một ứng dụng như Photoshop, nơi bạn có khả năng làm việc với hình ảnh khổng lồ tiêu thụ gigabites trên hệ thống tập tin. Giữ toàn bộ hình ảnh trong bộ nhớ và vẫn còn đủ bộ nhớ trống để thực hiện các thao tác (bộ lọc, xử lý hình ảnh và vân vân, hoặc thậm chí chỉ thêm lớp) sẽ không thể thực hiện trên hầu hết các hệ thống (thậm chí hệ thống 8gb x64).

Đó là lý do tại sao các ứng dụng như thế này sử dụng khái niệm về tệp hoán đổi. Trong nội bộ, tôi giả định rằng photoshop sử dụng định dạng tệp độc quyền, phù hợp với thiết kế ứng dụng của họ và được xây dựng để hỗ trợ tải một phần từ trao đổi, cho phép họ tải các phần của tệp vào bộ nhớ để xử lý nó.

(2) Performande có thể được cải thiện (khá nhiều) bằng cách viết trình tải tùy chỉnh cho từng định dạng tệp. Điều này đòi hỏi bạn phải đọc lên các tiêu đề tập tin và cấu trúc của các định dạng tệp mà bạn muốn làm việc. Một khi bạn đã nhận được bàn tay của nó nó không **** mà **** cứng, nhưng nó không phải là tầm thường như làm một cuộc gọi phương thức.

Ví dụ bạn có thể google cho FastBitmap để xem các ví dụ về cách bạn có thể tải một tệp bitmap (BMP) rất nhanh, nó bao gồm giải mã tiêu đề bitmap. Đây tham gia pinvoke và cung cấp cho bạn một số ý tưởng về những gì bạn đang lên chống lại bạn sẽ cần phải xác định structues bitmap như

 [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; 
     } 

Có thể làm việc với việc tạo ra một DIB (http://www.herdsoft.com/ti/davincie/imex3j8i.htm) và oddities như các dữ liệu được lưu trữ "lộn ngược "trong một bitmap mà bạn cần phải đưa vào tài khoản hoặc bạn sẽ thấy một hình ảnh phản chiếu khi bạn mở nó :-)

Bây giờ, đó là chỉ cho bitmap. Giả sử bạn muốn làm PNG thì bạn cần phải làm những thứ tương tự nhưng giải mã tiêu đề PNG, mà ở dạng đơn giản nhất của nó không khó, nhưng nếu bạn muốn nhận hỗ trợ đặc tả PNG đầy đủ thì bạn đang ở trong một chuyến đi thú vị:)

PNG là khác nhau để nói một bitmap vì nó sử dụng một định dạng dựa trên đoạn mà nó có "tiêu đề" bạn có thể loacate để tìm các dữ liệu khác nhau. Ví dụ về một số khối tôi đã sử dụng trong khi chơi với định dạng là

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

Bạn cũng sẽ phải tìm hiểu về checksums Adler32 cho các tập tin PNG. Vì vậy, mỗi định dạng tệp bạn muốn làm sẽ thêm một tập hợp các thách thức khác. Tôi thực sự muốn tôi có thể cung cấp đầy đủ các ví dụ mã nguồn đầy đủ hơn trong câu trả lời của tôi nhưng đó là một chủ đề phức tạp, và thành thật mà nói tôi đã không thực hiện hoán đổi để tôi không thể đưa ra quá nhiều lời khuyên chắc chắn về cái đó.

Câu trả lời ngắn gọn là khả năng xử lý hình ảnh trong BCL không phải là nóng. Câu trả lời trung bình sẽ là thử và tìm xem liệu ai đó đã viết một thư viện hình ảnh có thể giúp bạn và câu trả lời dài sẽ là kéo tay áo của bạn lên và viết cốt lõi của ứng dụng của bạn cho mình.

Vì bạn biết tôi trong cuộc sống thực, bạn biết nơi để tìm tôi;)

0

gì về:

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

tôi không nghĩ rằng điều này sẽ làm việc trên một hệ thống 32 bit dựa trên các hạn chế – WiiMaxx

0

chỉ là một sửa chữa nhanh chóng, tôi đã có cùng một vấn đề, tôi đã tạo ra một trường hợp thứ hai bitmap và thông qua bitmap trong constructor.

0

Bạn có thể tạo một bitmap mới, trống, có cùng kích thước và độ sâu màu không? Nếu đó là trường hợp, bạn ít nhất biết rằng môi trường của bạn có thể xử lý hình ảnh. Sau đó, vấn đề nằm trong hệ thống phụ tải hình ảnh, như tất nhiên liên kết của bạn chỉ ra có thể là trường hợp.

Tôi đoán bạn có thể viết trình tải bitmap của riêng bạn, nhưng đó là rất nhiều công việc cho các định dạng không tầm thường, vì vậy tôi sẽ không đề xuất nó.

Có thể có các thư viện thay thế có sẵn hoạt động xung quanh những vấn đề này với trình tải tiêu chuẩn?

0

Vì vậy, bạn đang nói rằng nó không phải là tải bitmap nhưng kết xuất gây ra một bộ nhớ?

Nếu vậy, bạn có thể sử dụng Bitmap.LockBits để lấy tổng số điểm ảnh và tự viết lại hình ảnh cơ bản không?

3

Để có câu trả lời thực sự toàn diện, tôi sẽ sử dụng Reflector để xem mã nguồn của Paint.NET (http://www.getpaint.net/); một chương trình chỉnh sửa đồ họa tiên tiến được viết bằng C#.

(như được chỉ ra trong nhận xét, Paint.NET đã từng là mã nguồn mở nhưng giờ đã đóng nguồn).

+0

Paint.net là một chương trình nguồn đóng từ cuối năm 2007 (http: //blog.getpaint.net/2007/12/04/phần mềm miễn phí-tác giả-beware-of-% E2% 80% 9Cbackspaceware% E2% 80% 9D /) – zihotki

+0

Đó là quá xấu. Tôi đã chỉnh sửa để phản ánh nhận xét của bạn. – ine

0

Một điều vừa xảy ra với tôi. Bạn có vẽ toàn bộ hình ảnh và không chỉ phần hiển thị? Bạn không nên vẽ một phần lớn hình ảnh hơn so với hiển thị trong ứng dụng của mình, sử dụng tham số x, y, width và heigth để hạn chế vùng được vẽ.