Chuyển đổi một bitmap thành một mảng byte


233

Sử dụng C #, là có một cách tốt hơn để chuyển đổi Windows Bitmapđể một byte[]hơn tiết kiệm vào một tập tin tạm thời và đọc kết quả bằng cách sử dụng FileStream?

Câu trả lời:


418

Có một vài cách.

ImageConverter

public static byte[] ImageToByte(Image img)
{
    ImageConverter converter = new ImageConverter();
    return (byte[])converter.ConvertTo(img, typeof(byte[]));
}

Điều này là thuận tiện vì nó không đòi hỏi nhiều mã.

Luồng bộ nhớ

public static byte[] ImageToByte2(Image img)
{
    using (var stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

Cái này tương đương với những gì bạn đang làm, ngoại trừ tập tin được lưu vào bộ nhớ thay vì vào đĩa. Mặc dù có nhiều mã hơn, bạn có tùy chọn ImageFormat và nó có thể dễ dàng sửa đổi giữa việc lưu vào bộ nhớ hoặc đĩa.

Nguồn: http://www.vcskicks.com/image-to-byte.php


2
Bạn cũng có thể sử dụng bitmap.Lockbits và Marshal.Copy cho một bản sao nhanh đơn giản mà không cần bất kỳ dòng bộ nhớ trung gian nào, v.v.
deegee

4
Xin lưu ý rằng ImageConverterphương thức này sẽ lưu hình ảnh dưới dạng Png, dẫn đến các tệp HUGE.
skolima

8
bạn không cần phải đóng luồng khi sử dụng 'bằng cách sử dụng'
LastTribunal

2
Ai đó có thể cho tôi thêm một chút thông tin về cách cấu trúc của mảng này không? Có bắt đầu bằng x = 0 và quay vòng qua mọi y và sau đó tăng x? Và sau đó lưu trữ nó như thế này: [0,0,1,1,1,1,0,0,1,1]?
Raymond Timmermans

1
ImageConverterkhông phải là .net tiêu chuẩn bạn có thể sử dụngMemoryStream
Alexandre

95

Một MemoryStream có thể hữu ích cho việc này. Bạn có thể đặt nó trong một phương thức mở rộng:

public static class ImageExtensions
{
    public static byte[] ToByteArray(this Image image, ImageFormat format)
    {
        using(MemoryStream ms = new MemoryStream())
        {
            image.Save(ms, format);
            return ms.ToArray();
        }
    }
}

Bạn chỉ có thể sử dụng nó như:

var image = new Bitmap(10, 10);
// Draw your image
byte[] arr = image.ToByteArray(ImageFormat.Bmp);

Tôi không đồng ý một phần với câu trả lời của uy tín liên quan đến ImageConverter. Không sử dụng ImageConverter. Không có gì sai về mặt kỹ thuật với nó, nhưng đơn giản là việc nó sử dụng quyền anh / unboxing từ đối tượng cho tôi biết đó là mã từ các vị trí tối cũ của khung .NET và nó không lý tưởng để sử dụng với xử lý hình ảnh (nó quá mức cần thiết để chuyển đổi thành byte [] ít nhất), đặc biệt là khi bạn xem xét những điều sau đây.

Tôi đã xem ImageConvertermã được sử dụng bởi khung .Net và bên trong nó sử dụng mã gần giống với mã tôi đã cung cấp ở trên. Nó tạo ra một cái mới MemoryStream, lưu Bitmapở bất kỳ định dạng nào khi bạn cung cấp và trả về mảng. Bỏ qua chi phí phụ của việc tạo một ImageConverterlớp bằng cách sử dụngMemoryStream


Đáng yêu. Điều đó sẽ làm! Mặc dù vậy, tôi sẽ muốn loại bỏ MemoryStream - quan tâm đến việc cập nhật?
Jeremy McGee

Tôi đã cập nhật câu trả lời của mình với một số cuộc thảo luận về lý do tại sao không sử dụng ImageConverter, như câu trả lời được chọn của bạn cho thấy, cũng như việc thêm xử lý.
Christopher Currens

Sử dụng tốt một phương pháp mở rộng, tôi thích nó!
Anh chàng Pascalou

3
+1 để xem xét ImageConverter và báo cáo kết quả nghiên cứu của bạn. Nhưng tôi không nghĩ những gì bạn đã phát hiện ra đảm bảo tuyên bố "Không sử dụng ImageConverter." Nó chắc chắn cung cấp các dịch vụ hữu ích theo cách khác, từ mảng byte sang Hình ảnh, ví dụ như đặt độ phân giải hình ảnh (dpi). Và "chi phí phụ của việc tạo lớp ImageConverter" có lẽ không đáng kể và chỉ cần được thực hiện một lần bất kể bạn sử dụng bao nhiêu lần.
RenniePet

1
Tôi thấy ImageConverter cũng hữu ích ở chỗ nó có thể tự động xác định loại hình ảnh - ví dụ: nếu bạn có một mảng byte của hình ảnh, nhưng không biết định dạng - bạn có thể thử đọc các tiêu đề và nhận gợi ý từ đó, nhưng, tốt, ... sử dụng (Image img = (Image) myImgConverter.ConvertFrom (byteImage)) và sau đó kiểm tra img.PixelFormat, v.v ... chỉ đơn giản hơn .. - tất nhiên tùy thuộc vào những gì bạn muốn làm
hello_earth

45

Bạn cũng có thể chỉ Marshal.Copy dữ liệu bitmap. Không có bộ nhớ trung gian, vv và một bản sao bộ nhớ nhanh. Điều này sẽ hoạt động trên cả bitmap 24 bit và 32 bit.

public static byte[] BitmapToByteArray(Bitmap bitmap)
{

    BitmapData bmpdata = null;

    try
    {
        bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        int numbytes = bmpdata.Stride * bitmap.Height;
        byte[] bytedata = new byte[numbytes];
        IntPtr ptr = bmpdata.Scan0;

        Marshal.Copy(ptr, bytedata, 0, numbytes);

        return bytedata;
    }
    finally
    {
        if (bmpdata != null)
            bitmap.UnlockBits(bmpdata);
    }

}

.


1
Xin chào, tôi đã sử dụng phương thức này, nhưng tôi không thể chuyển đổi mảng byte này trở lại hình ảnh một lần nữa. Bitmap bitmap1 = Bitmap mới (MemoryStream mới (mảng)); nó ném một ngoại lệ của các tham số không hợp lệ. Có lỗi gì không?
Howard

1
Xin chào, phần bình luận quá nhỏ để tôi có thể đăng toàn bộ mã sạch. Cách đơn giản nhất là ghim mảng: GCHandle handle = GCHandle.Alloc (bufferarray, GCHandleType.Pinned); lấy con trỏ tới mảng IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayEuity (bufferarray, 0); sau đó tạo một bitmap mới bằng cách sử dụng IntPtr: bitmap = Bitmap mới (chiều rộng, chiều cao, (chiều rộng * 4), PixelFormat.Format32bppArgb, iptr); nhưng bạn sẽ phải sử dụng các tham số tạo bitmap thích hợp cho định dạng bitmap của mình. Hãy chắc chắn để dọn sạch: iptr = IntPtr.Zero; xử lý. ();
deegee

3
Lỗi là gì? Nhiều lập trình viên bao gồm cả bản thân tôi đang sử dụng kiểu mã này và nó hoạt động tốt.
deegee

4
@ mini-me - Tôi khuyên bạn nên tìm kiếm bước tiến bitmap so với chiều rộng bitmap là gì. Đây không phải là một lỗi trong mã của tôi, đây là cách Windows xử lý ảnh bitmap. Stride có thể bao gồm dữ liệu bổ sung ở cuối mỗi dòng (chiều rộng) để có mỗi đầu dòng và bắt đầu trên ranh giới 32 bit để căn chỉnh bộ nhớ và hiệu suất.
deegee

3
Nó không phải là một lỗi. msdn.microsoft.com/en-us/l
Library / từ

16

Lưu hình ảnh vào MemoryStream và sau đó lấy mảng byte.

http://msdn.microsoft.com/en-us/l Library / ms142148.aspx

  Byte[] data;

  using (var memoryStream = new MemoryStream())
  {
    image.Save(memoryStream, ImageFormat.Bmp);

    data = memoryStream.ToArray();
  }

Không có phương thức Save trên Image.
Prescott Chartier

@PrescottChartier Ví dụ trên giả sử bạn đang làm việc từ một loại có nguồn gốc từ System.Drawing.Image (xem: docs.microsoft.com/en-us/dotnet/api/iêu )
Chris Baxter

Yup và tôi nhận được System.Drawing.Image does not exist. Vì vậy, không, không hoạt động :(
Prescott Chartier

Bạn có thể thấy những gì tôi đang cố gắng thực hiện ở đây: stackoverflow.com/questions/55084620/ Kẻ
Prescott Chartier

10

Sử dụng MemoryStreamthay vì a FileStream, như thế này:

MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();

Bạn có thể muốn ToArray, không GetBuffer.
vcsjones

GetBuffer trả về một mảng byte không dấu (mảng byte)
Jeff Reddy

4
Nó có thể có dữ liệu phụ không phải là một phần của hình ảnh. Từ tài liệu: Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method.Vì vậy, bây giờ mảng byte từ GetBuffersẽ trả về hình ảnh cộng với các byte không được sử dụng, điều này có thể sẽ dẫn đến hình ảnh bị hỏng.
vcsjones

1
Tốt để biết. Cảm ơn các bình luận vcs!
Jeff Reddy

Cách tiếp cận này lưu hình ảnh dưới dạng jpeg với cài đặt nén mặc định, sẽ giới thiệu các thành phần nén có thể làm giảm rõ rệt hình ảnh của bạn.
Richard Ev

8

Hãy thử như sau:

MemoryStream stream = new MemoryStream();
Bitmap bitmap = new Bitmap();
bitmap.Save(stream, ImageFormat.Jpeg);

byte[] byteArray = stream.GetBuffer();

Hãy chắc chắn rằng bạn đang sử dụng:

System.Drawing & using System.Drawing.Imaging;

1
Cách tiếp cận này lưu hình ảnh dưới dạng jpeg với cài đặt nén mặc định, sẽ giới thiệu các thành phần nén có thể làm giảm rõ rệt hình ảnh của bạn.
Richard Ev

Một lần nữa, không có phương thức Save trên bitmap.
Prescott Chartier

7

Tôi tin rằng bạn có thể chỉ cần làm:

ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));

6
MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();

5

Đơn giản hơn:

return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))

-3

Rất đơn giản sử dụng điều này chỉ trong một dòng:

byte[] imgdata = File.ReadAllBytes(@"C:\download.png");

op nói anh ấy không quan tâm đến lựa chọn này
Mauro Sampietro
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.