Cách nhanh nhất để chuyển đổi Hình ảnh sang mảng Byte


106

Tôi đang tạo ứng dụng chia sẻ Máy tính Từ xa, trong đó tôi chụp một hình ảnh của Máy tính để bàn và Nén nó và gửi nó đến người nhận. Để nén hình ảnh, tôi cần chuyển nó thành byte [].

Hiện tại tôi đang sử dụng cái này:

public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
    MemoryStream ms = new MemoryStream();
    imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
    return  ms.ToArray();
}

public Image byteArrayToImage(byte[] byteArrayIn)
{
     MemoryStream ms = new MemoryStream(byteArrayIn);
     Image returnImage = Image.FromStream(ms);
     return returnImage;
}

Nhưng tôi không thích nó vì tôi phải lưu nó trong ImageFormat và điều đó cũng có thể sử dụng tài nguyên (Làm chậm) cũng như tạo ra các kết quả nén khác nhau. Tôi đã đọc cách sử dụng Marshal. Sao chép và ghi nhớ nhưng tôi không thể hiểu họ.

Vậy có phương pháp nào khác để đạt được mục tiêu này không?


cả MemoryStream và Image đều có phương pháp loại bỏ, hãy đảm bảo rằng bạn đang loại bỏ chúng vì điều này có thể gây ra MemoryLeaks.
abc123

3
@ abc123: Bạn không cần phải vứt bỏ a MemoryStream; đó là một tài nguyên được quản lý hoàn toàn, trừ khi bạn đang sử dụng nó để loại bỏ. Trong cả hai trường hợp này, sẽ không thích hợp để loại bỏ tài nguyên.
Jon Skeet

1
@JonSkeet thú vị, bạn đã thực hiện một điểm chuẩn về điều đó chưa? để xem tốc độ .net giải phóng đối tượng? Tôi biết rằng có một đối số tương tự cho DataTable nhưng có một sự khác biệt đáng chú ý về tốc độ mà GarbageCollector thu thập bộ nhớ được cấp phát khi sử dụng loại bỏ.
abc123

@ abc123: Tôi thực sự sẽ không mong đợi điều đó - việc loại bỏ luồng không ảnh hưởng gì đến mảng và MemoryStream không có trình hoàn thiện (không giống như DataTable, kế thừa từ MarshalByValueComponent).
Jon Skeet

2
bất kỳ giải pháp cuối cùng với mã nguồn đầy đủ?
Kiquenet

Câu trả lời:


39

Vậy có phương pháp nào khác để đạt được mục tiêu này không?

Không. Để chuyển đổi hình ảnh sang mảng byte, bạn phải chỉ định định dạng hình ảnh - cũng giống như bạn phải chỉ định mã hóa khi chuyển đổi văn bản thành mảng byte.

Nếu bạn lo lắng về các đồ tạo tác nén, hãy chọn định dạng không mất dữ liệu. Nếu bạn lo lắng về tài nguyên CPU, hãy chọn một định dạng không cần nén - ví dụ: chỉ là các pixel ARGB thô. Nhưng tất nhiên điều đó sẽ dẫn đến một mảng byte lớn hơn.

Lưu ý rằng nếu bạn chọn một định dạng mà không bao gồm nén, không có điểm nào trong sau đó nén mảng byte sau đó - đó là gần như chắc chắn không có tác dụng có lợi.


12
thay vì 'chọn định dạng không mất dữ liệu', bạn có thể chọn cách imageIn.RawFormatcố gắng lưu các byte hình ảnh thô mà không cần mã hóa lại.
Chris F Carroll

52

Có một thuộc tính RawFormat của tham số Image trả về định dạng tệp của hình ảnh. Bạn có thể thử những cách sau:

// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
{
    using(var ms = new MemoryStream())
    {
        image.Save(ms, image.RawFormat);
        return ms.ToArray();
    }
}

9
Tôi khuyên bạn nên hoặc xử lý MemoryStream hoặc quấn cơ thể của phương pháp này trong một tuyên bố sử dụng () {}
Neil.Allen

@ Neil.Allen Tôi là người mới ở đây, bạn có thể vui lòng cho biết tại sao không?
Khalil Khalaf

3
@FirstStep Vì hãy tự dọn dẹp sau khi chính mình :)
Sinaesthetic

@Sinaesthetic Tôi thấy. Và quy trình là đặt bất kỳ hàm nào tôi muốn thực thi, trong using () {}?
Khalil Khalaf

2
@FirstStep Không hoàn toàn. Chính xác hơn: Nếu bạn sử dụng một đối tượng đã triển khai IDisposable, thì bạn nên chắc chắn gọi Dispose () khi bạn hoàn thành việc với nó để nó sẽ dọn dẹp mọi tài nguyên mà nó đã buộc. Câu lệnh using () {} chỉ gọi nó cho bạn khi đối tượng đi ra khỏi phạm vi của câu lệnh đó. Vì vậy, bạn có thể làm myObject.Dispose()hoặc using(myObject){}- cả hai đều làm điều tương tự, nhưng về cơ bản câu lệnh using tạo ra một phạm vi sẽ dọn dẹp cho bạn.
Sinaesthetic

14

Tôi không chắc liệu bạn có thu được lợi nhuận lớn hay không vì những lý do mà Jon Skeet đã chỉ ra. Tuy nhiên, bạn có thể thử và chuẩn phương thức TypeConvert.ConvertTo và xem nó như thế nào so với phương pháp hiện tại của bạn.

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));

Không thể truyền đối tượng kiểu 'System.Byte []' sang kiểu 'System.Drawing.Image'.
user123

14
public static byte[] ReadImageFile(string imageLocation)
    {
        byte[] imageData = null;
        FileInfo fileInfo = new FileInfo(imageLocation);
        long imageFileLength = fileInfo.Length;
        FileStream fs = new FileStream(imageLocation, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fs);
        imageData = br.ReadBytes((int)imageFileLength);
        return imageData;
    }

5
Chào mừng bạn đến với stackoverflow.com, bạn có thể thêm một chút chi tiết giải thích tại sao mẫu mã trên lại hữu ích. Nó dành cho những người dùng SO khác, những người có thể không hiểu nó hoàn toàn ... stackoverflow.com/help/how-to-answer
Mack

Điều này dành cho các tệp thành byte, nhưng OP muốn một đối tượng vẽ được chuyển đổi thành byte. Các đối tượng vẽ có thể được lưu trữ trong cơ sở dữ liệu, không nhất thiết phải là hệ thống tệp, dưới dạng một mảng byte và do đó phải được chuyển đổi qua lại ... nhưng không phải dưới dạng tệp trong FileStream để được chuyển đổi thành byte - trừ khi có lẽ, trong quá trình tải lên ban đầu.
vapcguy

Điều này đã giúp tôi khi tôi đang tìm cách thực hiện việc này với các tệp. Tốt để có xung quanh như liên quan của nó.
Justin

5
public static class HelperExtensions
{
    //Convert Image to byte[] array:
    public static byte[] ToByteArray(this Image imageIn)
    {
        var ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        return ms.ToArray();
    }

    //Convert byte[] array to Image:
    public static Image ToImage(this byte[] byteArrayIn)
    {
        var ms = new MemoryStream(byteArrayIn);
        var returnImage = Image.FromStream(ms);
        return returnImage;
    }
}

2

Cách nhanh nhất mà tôi có thể tìm ra là:

var myArray = (byte[]) new ImageConverter().ConvertTo(InputImg, typeof(byte[]));

Hi vọng sẽ hữu ích


Hãy cẩn thận với điều này, đặc biệt nếu sử dụng WPF nơi bạn có System.Windows.Controls.Imagecác đối tượng. Nếu bạn muốn chuyển một trong những giá trị đó thành byte và bạn chuyển nó vào dòng này dưới dạng InputImg, điều này sẽ không hoạt động. Nó mong đợi một System.Drawing.Imageđối tượng.
vapcguy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.