2011-11-23 19 views
9

Tôi hiện đang xử lý các ảnh rất lớn, được tạo cơ bản bằng cách ghép nhiều hình ảnh nhỏ hơn (ví dụ: ảnh toàn cảnh hoặc phần mềm mosaic ảnh). Để tránh các ngoại lệ ngoài bộ nhớ (trong bộ nhớ chỉ là "bản đồ" về cách sắp xếp các hình ảnh nhỏ hơn), tôi đã viết một số mã lưu các hình ảnh này theo từng dòng dưới dạng bitmap sử dụng BinaryWriter và LockBits. Càng xa càng tốt.C# lưu các bitmap rất lớn dưới dạng jpegs (hoặc bất kỳ định dạng nén nào khác)

Vấn đề là bây giờ tôi cũng muốn lưu những hình ảnh này dưới dạng Jpegs (hoặc PNG). Vì tôi khá mới với C# Tôi chỉ có thể nghĩ đến hai cách cho bây giờ:

1) Tương tự như quy trình lưu bitmap. Tạo ra một số tiêu đề jpeg và lưu các dòng hình ảnh lớn theo dòng, nén chúng bằng cách nào đó trước đây. Tôi không có ý tưởng làm thế nào để thực hiện nén mặc dù.

2) Truyền trực tuyến bitmap đã lưu vào bộ nhớ và lưu nó dưới dạng jpeg được mã hóa.

Kể từ khi tiếp cận thứ hai có vẻ dễ dàng hơn, tôi đã cố gắng một cái gì đó như thế này:

FileStream fsr = 
    new FileStream("input.bmp", FileMode.Open, FileAccess.Read); 
FileStream fsw = 
    new FileStream("output.jpg", FileMode.CreateNew, FileAccess.Write); 

EncoderParameters encoderParameters = new EncoderParameters(1); 
encoderParameters.Param[0] = 
    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L); 

Bitmap bmp = new Bitmap(fsr); 
bmp.Save(fsw, GetEncoder(ImageFormat.Jpeg), encoderParameters); 
bmp.Dispose(); 

Vấn đề bây giờ là tiết kiệm-phương pháp cố gắng hoàn toàn tải bitmap vào bộ nhớ đầu tiên, gây ra một out-of-bộ nhớ ngoại lệ.

Tôi sẽ rất vui vì bất kỳ đề xuất nào về cách giải quyết hoặc phá vỡ vấn đề này!

+1

OutOfMemoryException trong ngày và tuổi này? Làm thế nào lớn là bitmap của bạn? – zmbq

+2

có, bạn có thể gặp vấn đề về bộ nhớ một cách dễ dàng, tôi đã thay đổi kích thước khoảng 10 nghìn hình ảnh và thường xuyên chạy vào 'OutOfMemoryException', mặc dù tôi đã xử lý đúng cách. – DarthVader

+1

OOM từ một Bitmap là rất đáng ngờ. Lớp này sẽ ném ngoại lệ bộ nhớ cho bất kỳ thứ gì sai, bao gồm các tham số xấu, v.v. –

Trả lời

0

Tôi nghi ngờ bạn không thể làm điều này trong .NET, nhưng bạn luôn có thể gọi vào thư viện C để thực hiện việc nâng hạng nặng. Tôi đã không sử dụng nó bản thân mình, nhưng tôi đề nghị bạn nhìn vào thư viện GraphicsMagick. Đó là một thư viện C với giấy phép cho phép sử dụng cả nguồn mở và thương mại và có vẻ như nó có thể làm những gì bạn cần.

+0

Cảm ơn bạn, tôi sẽ xem xét nó. Nhưng tôi thực sự muốn tránh các thư viện phụ. – mgulde

+0

Tôi đã kiểm tra thư viện GraphicsMagick nhưng không thể tìm thấy bất cứ điều gì về cách viết jpegs (hoặc pngs) theo khối. – mgulde

1

Lưu ý rằng nén JPEG có một số nhược điểm không tầm thường quan trọng:

1) JPEG là lossy, do đó bạn sẽ không thể tái sinh cùng một hình ảnh. Điều này có thể được chấp nhận hoàn toàn, nhưng nếu bạn cần tái tạo chính xác hình ảnh nguồn, thì PNG là cách để đi.

2) JPEG được căn chỉnh trên ranh giới 8 pixel. Nếu bạn cùng nhau tạo hình ảnh có kích thước không nhiều 8, chiều rộng hoặc chiều cao, bạn sẽ nhận được một số đồ tạo tác mạnh mẽ tại ranh giới hình ảnh

Xem xét trường hợp sử dụng của bạn, tôi muốn giới thiệu cho các ảnh không ghép lại với nhau và sử dụng thuật toán nén tiêu chuẩn, chẳng hạn như PNG hoặc Zlib, trên mỗi hình ảnh nhỏ hơn. Bạn vẫn có thể lưu trữ các luồng nén được tạo thành một tệp duy nhất. Ưu điểm là bạn có thể trực tiếp "nhảy" ở vị trí của hình ảnh nhỏ mà bạn muốn trích xuất, điều này sẽ tiết kiệm được * rất nhiều * bộ nhớ.

Điểm bất lợi là bạn không thể "xem trước trực quan" tất cả các hình ảnh nhỏ thành một hình ảnh lớn (bạn sẽ cần phải tạo một chương trình để sử dụng).

+0

Trước hết, cảm ơn rất nhiều. Thay đổi mã để lưu hình ảnh lớn không theo chiều dọc nhưng trong các khối 8x8px sẽ không có vấn đề gì. Ngoài ra mất thông tin nhẹ do tiết kiệm nó như jpeg không quan trọng. Vấn đề của tôi bây giờ là, rằng tôi hoàn toàn không có đầu mối về cách viết một tệp jpeg (hoặc png, cho rằng vấn đề) theo thứ tự. – mgulde

+0

Nếu bạn muốn gắn bó với phương pháp "hình ảnh lớn", tôi muốn khuyên bạn nên lưu nó trong các băng tần 8 dòng. Sau đó, bạn sẽ nhận được trong bộ nhớ một bitmap của Width x 8 pixel, mà sẽ làm giảm yêu cầu bộ nhớ so với hình ảnh đầy đủ. – Cyan

+0

Tôi vừa sửa đổi mã và giờ đang lưu hình ảnh trong các băng gồm 8 dòng. Nhưng vẫn còn có vấn đề mà tôi không biết làm thế nào để lưu nó như là một jpeg: Đối với bmps tôi đã viết một tiêu đề và sau đó chỉ cần streamed các giá trị byte ARGB từng người một. Tôi sẽ cần một số chức năng, mà có thể viết một tiêu đề jpeg và sau đó - đây là những gì tôi coi là một phần phức tạp - mã hóa các ban nhạc vào định dạng jpeg và nối chúng vào tập tin hiện có chunk bởi chunk. Phương pháp "Lưu" – mgulde

0

(vì tiêu đề cho biết "hoặc bất kỳ định dạng nén nào khác")

Định dạng TIFF có khái niệm về gạch và sọc. Cả hai có thể được sử dụng để tránh có tất cả các hình ảnh lớn trong bộ nhớ bất cứ lúc nào. Có lẽ gạch sẽ có ích cho bạn kể từ khi bạn đang khâu hình ảnh nhỏ.

Bạn có thể thử LibTiff.Net (miễn phí, thân thiện với thương mại, nguồn mở, chỉ được viết bằng C#) cho tác vụ.

Có một bài viết Basic introduction to the capabilities of the library với thông tin về hình ảnh dải và ngói theo định hướng IO (trong phần thứ hai của bài viết).

Tuyên bố từ chối trách nhiệm: Tôi làm việc cho công ty.

+0

Cảm ơn, tôi sẽ thử nó. Bạn có biết nếu có bất kỳ điều tương tự cho jpegs, pngs, aso, quá? Thông thường, tôi sẽ luôn luôn đi cho jpegs. – mgulde

+0

Theo như tôi biết, không có gì giống như thế này cho JPEG. Thật không may, tôi không biết nếu có bất cứ điều gì như thế này cho PNGs. – Bobrovsky