2012-04-04 5 views
8

Một người bạn và tôi đã dành phần tốt hơn của đêm qua gần như xé tóc ra để cố gắng làm việc với một số hình ảnh trong ứng dụng tàu điện ngầm. Chúng tôi đã đưa hình ảnh vào ứng dụng với sự quyến rũ chia sẻ, và sau đó tôi muốn làm một số công việc khác với họ, cắt xén các hình ảnh và lưu chúng trở lại vào thư mục appdata. Điều này tỏ ra rất bực mình.Xử lý ảnh WinRT

Câu hỏi của tôi, vào cuối tất cả điều này, sẽ là "Cách thích hợp để làm điều này, mà không cảm thấy như tôi đang đập cùng nhau một loạt các mảnh ghép hình ghép không khớp?"

Khi chia sẻ nhiều hình ảnh với ứng dụng, chúng sẽ xuất hiện dưới dạng danh sách Windows.Storage.StorageFile s. Dưới đây là một số mã được sử dụng để xử lý điều đó.

var storageItems = await _shareOperation.Data.GetStorageItemsAsync(); 

foreach (StorageFile item in storageItems) 
{ 
    var stream = await item.OpenReadAsync(); 
    var properties = await item.Properties.GetImagePropertiesAsync(); 

    var image = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height); 
    image.SetSource(stream); 

    images.Add(image); 
} 

Một số tìm kiếm trực tuyến cho biết bạn có thể truy cập dữ liệu pixel trong hình ảnh. This question bao gồm một câu trả lời hữu ích đầy đủ các phương pháp mở rộng để lưu hình ảnh vào một tệp, vì vậy chúng tôi đã sử dụng chúng.

Vấn đề của chúng tôi là điều tồi tệ nhất khi tôi thử mở lại tệp sau. Tôi đã làm điều gì đó tương tự như trước:

var files = await ApplicationData.Current.LocalFolder.GetFilesAsync(); 

foreach (var file in files) 
{ 
    var fileStream = await file.OpenReadAsync(); 
    var properties = await file.Properties.GetImagePropertiesAsync(); 
    var bitmap = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height); 
    bitmap.SetSource(fileStream); 

    System.IO.Stream stream = bitmap.PixelBuffer.AsStream(); 

Đây là vấn đề. Luồng này kéo dài bao lâu, nếu tôi muốn các byte ra khỏi nó?

// CRASH! Length isn't supported on an IRandomAccessStream. 
    var pixels = new byte[fileStream.Length]; 

Ok thử lại.

var pixels = new byte[stream.Length]; 

Điều này hoạt động, ngoại trừ ... nếu hình ảnh được nén, luồng ngắn hơn mong đợi, vì vậy bạn sẽ thoát khỏi ngoại lệ. Bây giờ giả vờ là một bitmap không nén.

await _stream.ReadAsync(pixels, 0, pixels.Length); 

Cũng đoán xem. Mặc dù tôi đã nói bitmap.SetSource(fileStream); để đọc dữ liệu, mảng byte của tôi vẫn đầy zeroes. Tôi không biết tại sao. Nếu tôi vượt qua điều này bitmap vào giao diện người dùng của tôi thông qua nhóm dữ liệu mẫu, hình ảnh sẽ hiển thị tốt. Vì vậy, nó đã rõ ràng có dữ liệu pixel trong bitmap đó một nơi nào đó, nhưng tôi không thể đọc nó ra khỏi bitmap.PixelBuffer? Tại sao không?

Cuối cùng, đây là những gì đã kết thúc thực sự hiệu quả.

var decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, fileStream); 
    var data = await decoder.GetPixelDataAsync(); 
    var bytes = data.DetachPixelData(); 

    /* process my data, finally */ 

} // end of that foreach I started a while ago 

Vì vậy, bây giờ tôi có dữ liệu hình ảnh, nhưng tôi vẫn có một vấn đề lớn. Để làm bất cứ điều gì với nó, tôi phải đưa ra giả định về định dạng của nó. Tôi không biết liệu nó là rgba, rgb, abgr, bgra, bất kể chúng có thể là gì. Nếu tôi đoán sai quá trình xử lý của tôi không thành công. Tôi đã có hàng chục thử nghiệm chạy nhổ ra zero byte và hình ảnh bị hỏng, lộn ngược hình ảnh (???), màu sắc sai, vv Tôi đã có thể mong đợi để tìm thấy một số thông tin này trong properties mà tôi nhận được từ gọi await file.Properties.GetImagePropertiesAsync();, nhưng không may mắn. Điều đó chỉ chứa chiều rộng và chiều cao của hình ảnh, cộng với một số thứ vô dụng khác. Tài liệu tối thiểu here.

Vì vậy, tại sao quá trình này lại gây đau đớn? Điều này chỉ phản ánh sự non nớt của các thư viện ngay bây giờ, và tôi có thể mong đợi nó trở nên tốt hơn không? Hoặc là đã có một số cách tiêu chuẩn để làm điều này? Tôi muốn nó dễ dàng như trong System.Drawing. Điều đó cung cấp cho bạn tất cả dữ liệu bạn cần và vui lòng tải bất kỳ loại hình ảnh nào một cách chính xác mà không làm bạn tự xử lý luồng.

+0

"Tôi không biết liệu đó có phải là rgba, rgb, abgr, bgra hay không.". Trên thực tế bạn biết chính xác nó là gì bởi sự lựa chọn của bạn về định dạng. Làm việc nó một lần và cho PNG và bạn có thể áp dụng logic cho tất cả các PNG. – jheriko

+0

... mọi người cũng thực hiện các thư viện hình ảnh khá kém, mặc dù BitmapEncoder/BitmapDecoder khá đẹp. stb_image.c thực hiện công việc tốt hơn nhiều trong hầu hết các trường hợp và trên hầu hết các nền tảng so với bất kỳ thư viện gốc nào có sẵn bởi vì nó cung cấp một giao diện tối thiểu và chính xác. (byte, kích thước, định dạng, không có chrome và boilerplate). – jheriko

Trả lời

2
  1. Từ những gì tôi đã thấy - khi bạn định tải WriteableBitmap bằng luồng - bạn không cần phải kiểm tra kích thước hình ảnh - chỉ cần thực hiện WriteableBitmap (1,1) mới, sau đó gọi SetSource() .
  2. Bạn không chắc chắn lý do tại sao bạn đang suy nghĩ var pixel = new byte [fileStream.Length]; sẽ hoạt động, vì fileStream có các byte ảnh nén và không phải là mảng pixel.
  3. Bạn có thể cần phải tìm cách đầu dòng để có được những mảng pixel:

    var pixelStream = pixelBuffer.AsStream(); 
    var bytes = new byte[this.pixelStream.Length]; 
    this.pixelStream.Seek(0, SeekOrigin.Begin); 
    this.pixelStream.Read(bytes, 0, Bytes.Length); 
    
  4. tôi đã bắt đầu làm việc trên một cổng WinRT của WriteableBitmapEx - có thể nó có thể giúp bạn: http://bit.ly/WriteableBitmapExWinRT. Tôi đã không thử nghiệm nó tốt và nó được dựa trên một phiên bản cũ của WBX, nhưng nó là khá đầy đủ về hỗ trợ tính năng. Có thể chậm hơn một chút so với khả năng.

+0

Ah, vì vậy tôi không cần bộ giải mã, tôi chỉ cần tìm cách bắt đầu. Cảm ơn! Tôi sẽ cho một phát bắn. Và tôi sẽ kiểm tra thư viện của bạn! – Tesserex

+0

Tìm kiếm luồng không hoạt động, vẫn có tất cả byte không. Lấy làm tiếc. – Tesserex

+0

Có lẽ bạn cần đợi hình ảnh tải trước khi có thể truy cập bộ đệm pixel? Tôi sẽ bắt đầu bằng cách đợi Task.Delay (1000) trước khi truy cập PixelBuffer. Nếu điều đó giúp - có thể có một sự kiện chờ đợi như bitmap.Loaded. –