2012-02-07 64 views
56

Tôi muốn chuyển đổi mảng byte thành hình ảnh.Byte Array để chuyển đổi hình ảnh

Đây là mã cơ sở dữ liệu của tôi từ nơi tôi nhận được mảng byte:

public void Get_Finger_print() 
{ 
    try 
    { 
     using (SqlConnection thisConnection = new SqlConnection(@"Data Source=" + System.Environment.MachineName + "\\SQLEXPRESS;Initial Catalog=Image_Scanning;Integrated Security=SSPI ")) 
     { 
      thisConnection.Open(); 
      string query = "select pic from Image_tbl";// where Name='" + name + "'"; 
      SqlCommand cmd = new SqlCommand(query, thisConnection); 
      byte[] image =(byte[]) cmd.ExecuteScalar(); 
      Image newImage = byteArrayToImage(image); 
      Picture.Image = newImage; 
      //return image; 
     } 
    } 
    catch (Exception) { } 
    //return null; 
} 

mã chuyển đổi của tôi:

public Image byteArrayToImage(byte[] byteArrayIn) 
{ 
    try 
    { 
     MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length); 
     ms.Write(byteArrayIn, 0, byteArrayIn.Length); 
     returnImage = Image.FromStream(ms,true);//Exception occurs here 
    } 
    catch { } 
    return returnImage; 
} 

Khi tôi đạt được phù hợp với nhận xét thì ngoại lệ sau đây xảy ra: Parameter is not valid.

Làm cách nào để khắc phục bất kỳ điều gì gây ra ngoại lệ này?

+0

Bạn đã kiểm tra xem các byte hình ảnh trong truy vấn của mình có hợp lệ không? Bạn có thể làm một File.WriteAllBytes ("myimage.jpg", byteArrayIn) để xác minh. – Holstebroe

Trả lời

4

thử (CẬP NHẬT)

MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length); 
ms.Position = 0; // this is important 
returnImage = Image.FromStream(ms,true); 
+0

Cảm ơn nhưng không được giải quyết vấn đề từ mã này –

+2

Nó làm cho ít ý nghĩa để viết mảng byte vào dòng bộ nhớ sau khi nó đã được khởi tạo với cùng một mảng byte. Thực ra tôi không chắc MemoryStream có cho phép ghi vượt quá độ dài được chỉ định trong hàm tạo hay không. – Holstebroe

+0

@TanzeelurRahman xem câu trả lời đã chỉnh sửa của tôi ... – Yahia

70

Bạn đang viết đến dòng bộ nhớ của bạn hai lần, cũng có thể bạn không được xử lý dòng sau khi sử dụng. Bạn cũng đang yêu cầu bộ giải mã hình ảnh áp dụng hiệu chỉnh màu được nhúng.

Hãy thử điều này thay vì:

using (var ms = new MemoryStream(byteArrayIn)) 
{ 
    return Image.FromStream(ms); 
} 
+0

Bạn cũng có thể làm cho luồng bộ nhớ không ghi được sau khi khởi tạo: MemoryStream mới (byteArrayIn, false) – Holstebroe

+0

Không có mã này không được giải quyết vấn đề của tôi –

+19

Điều này vi phạm đặc điểm kỹ thuật trong MSDN cho Hình ảnh .FromStream(), nơi nó nói "Bạn phải giữ cho luồng mở trong suốt thời gian của Ảnh." Xem thêm http://stackoverflow.com/questions/3290060/getting-an-image-object-from-a-byte-array – RenniePet

2

này được lấy cảm hứng từ câu trả lời Holstebroe, cộng với ý kiến ​​ở đây: Getting an Image object from a byte array

Bitmap newBitmap; 
using (MemoryStream memoryStream = new MemoryStream(byteArrayIn)) 
    using (Image newImage = Image.FromStream(memoryStream)) 
     newBitmap = new Bitmap(newImage); 
return newBitmap; 
55

Có lẽ tôi đang thiếu cái gì, nhưng đối với tôi đây là một-liner hoạt động tốt với một mảng byte có chứa một hình ảnh của một tập tin JPEG.

Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray)); 

EDIT:

Xem ở đây cho một phiên bản cập nhật của câu trả lời này: How to convert image in byte array

+0

Thời gian lưu ... tuyệt vời – PawanS

+0

Xin cảm ơn AAAh, Cuối cùng là câu trả lời hay. Tại sao rất nhiều câu trả lời với luồng bộ nhớ, nó gây ra cho tôi rất nhiều vấn đề. cảm ơn rất nhiều ! – Julian50

+0

Câu trả lời hay! điều này có thể được sử dụng trong một chức năng riêng biệt trong khi tất cả các đề xuất khác bằng cách sử dụng MemoryStream không thể (Luồng phải được giữ mở suốt đời của Hình ảnh) –

0

Phần lớn thời gian khi điều này xảy ra nó là dữ liệu xấu trong cột SQL. Đây là cách thích hợp để chèn vào một cột hình ảnh:

INSERT INTO [TableX] (ImgColumn) VALUES (
(SELECT * FROM OPENROWSET(BULK N'C:\....\Picture 010.png', SINGLE_BLOB) as tempimg)) 

Hầu hết mọi người làm điều đó không đúng theo cách này:

INSERT INTO [TableX] (ImgColumn) VALUES ('C:\....\Picture 010.png')) 
0

Hi cố gắng liên kết dưới đây đối với tôi cũng có cùng một vấn đề và tôi đã giải quyết cố gắng liên kết dưới đây nó sẽ giúp u enter link description here

2

Bạn chưa tuyên bố returnImage như bất kỳ loại biến :)

Điều này sẽ giúp:

public Image byteArrayToImage(byte[] byteArrayIn) 
{ 
    try 
    { 
     MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length); 
     ms.Write(byteArrayIn, 0, byteArrayIn.Length); 
     Image returnImage = Image.FromStream(ms,true); 
    } 
    catch { } 
    return returnImage; 
} 
+1

Mã hữu ích như một ý tưởng, nhưng tất nhiên sẽ không hoạt động như được viết. returnImage phải được khai báo bên ngoài phần try/catch. Ngoài ra returnImage phải được khởi tạo trong 'catch' - tôi tạo một bitmap pixel đơn: var image = new Bitmap (1, 1); MemoryStream stream = new MemoryStream(); image.Save (stream, ImageFormat.Jpeg); stream.Position = 0; – Reid

4

Tất cả các câu trả lời được trình bày giả định rằng mảng byte chứa dữ liệu trong biểu diễn định dạng tệp đã biết, như: gif, png hoặc jpg. Nhưng gần đây tôi đã gặp sự cố khi cố chuyển đổi byte[] s, chứa thông tin BGRA được linearized, hiệu quả thành các đối tượng Image. Đoạn mã sau giải quyết nó bằng cách sử dụng một đối tượng Bitmap.

using System.Drawing; 
using System.Drawing.Imaging; 
using System.Runtime.InteropServices; 
public static class Extensions 
{ 
    public static Image ImageFromRawBgraArray(
     this byte[] arr, int width, int height) 
    { 
     var output = new Bitmap(width, height); 
     var rect = new Rectangle(0, 0, width, height); 
     var bmpData = output.LockBits(rect, 
      ImageLockMode.ReadWrite, output.PixelFormat); 
     var ptr = bmpData.Scan0; 
     Marshal.Copy(arr, 0, ptr, arr.Length); 
     output.UnlockBits(bmpData); 
     return output; 
    } 
} 

Đây là một biến thể hơi khác của giải pháp được đăng trên this site.

+0

làm tài liệu tham khảo MSDN: Bitmap (Int32, Int32): "Hàm tạo này tạo Bitmap với giá trị liệt kê PixelFormat của Format32bppArgb.", Có nghĩa là byte [0] là màu xanh, byte [1] có màu xanh lá cây, byte [2] là màu đỏ, byte [3] là alpha, byte [4] có màu xanh dương, v.v. – brk

6
public Image byteArrayToImage(byte[] bytesArr) 
{ 
    MemoryStream memstr = new MemoryStream(bytesArr); 
    Image img = Image.FromStream(memstr); 
    return img; 
} 
+0

Mặc dù không phải là một ý tưởng hay, nhưng tôi đặt GC.Collect() trước luồng Bộ nhớ. Tôi đã hết bộ nhớ khi tôi tải trước toàn bộ rất nhiều tệp đồ họa lớn như các phần tử vào bộ nhớ và sau đó chuyển chúng thành hình ảnh trong khi xem. – Kayot

6

Tôi muốn lưu ý rằng có lỗi trong giải pháp được cung cấp bởi @ isaias-b.

Giải pháp đó giả định rằng stride bằng với chiều dài hàng. Nhưng nó không phải lúc nào cũng đúng. Do sự sắp xếp bộ nhớ được thực hiện bởi GDI, bước tiến có thể lớn hơn chiều dài hàng. Điều này phải được tính đến. Nếu không, hình ảnh được chuyển không hợp lệ sẽ được tạo. Các byte đệm trong mỗi hàng sẽ bị bỏ qua.

Đường sải là chiều rộng của một hàng đơn pixel (đường quét), được làm tròn lên đến ranh giới bốn byte.

Sửa code:

using System.Drawing; 
using System.Drawing.Imaging; 
using System.Runtime.InteropServices; 

public static class ImageExtensions 
{ 
    public static Image ImageFromRawBgraArray(this byte[] arr, int width, int height, PixelFormat pixelFormat) 
    { 
     var output = new Bitmap(width, height, pixelFormat); 
     var rect = new Rectangle(0, 0, width, height); 
     var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat); 

     // Row-by-row copy 
     var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat)/8; 
     var ptr = bmpData.Scan0; 
     for (var i = 0; i < height; i++) 
     { 
      Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength); 
      ptr += bmpData.Stride; 
     } 

     output.UnlockBits(bmpData); 
     return output; 
    } 
} 

Để minh họa cho những gì nó có thể dẫn đến, chúng ta hãy tạo PixelFormat.Format24bppRgb hình ảnh gradient 101x101:

var width = 101; 
var height = 101; 
var gradient = new byte[width * height * 3 /* bytes per pixel */]; 
for (int i = 0, pixel = 0; i < gradient.Length; i++, pixel = i/3) 
{ 
    var x = pixel % height; 
    var y = (pixel - x)/width; 
    gradient[i] = (byte)((x/(double)(width - 1) + y/(double)(height - 1))/2d * 255); 
} 

Nếu chúng ta sẽ sao chép toàn bộ mảng như-là để giải quyết nhọn bởi bmpData.Scan0, chúng tôi sẽ nhận được hình ảnh sau đây. Chuyển hình ảnh vì một phần của hình ảnh được ghi vào các byte đệm, được bỏ qua. Cũng chính vì vậy mà hàng cuối cùng là không đầy đủ:

stride ignored

Nhưng nếu chúng ta sẽ sao chép hàng-by-hàng chuyển con trỏ đích bằng giá trị bmpData.Stride, được ảnh hợp lệ sẽ được tạo:

stride taken into account

Stride cũng có thể là số âm:

Nếu stride dương, bitmap là từ trên xuống dưới. Nếu stride là âm, bitmap là từ dưới lên.

Nhưng tôi đã không làm việc với những hình ảnh như vậy và điều này vượt quá lưu ý của tôi.

câu trả lời liên quan: C# - RGB Buffer from Bitmap different from C++

-2

Tôi thấy điều này kẻ Convert array to image

 private void button1_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      string hasil = "D:\\coba1000.jpg"; 
      System.IO.File.WriteAllBytes(@hasil, bytestosend); 


      pictureBox1.ImageLocation = @hasil; 
     } 
     catch { } 
    } 
0

có phương pháp đơn giản như dưới đây, bạn có thể sử dụng phương pháp FromStream của hình ảnh để làm các trick, Chỉ cần nhớ để sử dụng hệ thống .Drawing;

// using image object not file 
public byte[] imageToByteArray(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; 
} 
Các vấn đề liên quan