Bayt dizisinden görüntüye dönüştürme


103

Bir bayt dizisini bir görüntüye dönüştürmek istiyorum.

Bu, bayt dizisini aldığım veritabanı kodum:

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;
}

Dönüşüm kodum:

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;
}

Yorum içeren satıra ulaştığımda şu istisna oluşuyor: Parameter is not valid.

Bu istisnaya neden olan şeyi nasıl düzeltebilirim?


Sorgunuzdaki resim baytlarının geçerli olup olmadığını kontrol ettiniz mi? Doğrulamak için bir File.WriteAllBytes ("myimage.jpg", byteArrayIn) yapabilirsiniz.
Holstebroe

Yanıtlar:


110

Bellek akışınıza iki kez yazıyorsunuz, ayrıca kullanımdan sonra akışı elden çıkarmıyorsunuz. Ayrıca görüntü kod çözücüsünden katıştırılmış renk düzeltmesi uygulamasını da istiyorsunuz.

Bunun yerine şunu deneyin:

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

Ayrıca, başlatmadan sonra bellek akışını açıkça yazılamaz hale de getirebilirsiniz: new MemoryStream (byteArrayIn, false)
Holstebroe

28
Bu, Image.FromStream () için MSDN'de "Görüntünün ömrü boyunca akışı açık tutmanız gerekir" ifadesini ihlal eder. Ayrıca bkz. Stackoverflow.com/questions/3290060/…
RenniePet

81

Belki bir şeyi kaçırıyorum, ama benim için bu tek satırlık bir JPEG dosyasının görüntüsünü içeren bir bayt dizisi ile iyi çalışıyor.

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

DÜZENLE:

Bu cevabın güncellenmiş bir versiyonu için buraya bakın: Bayt dizisinde görüntü nasıl dönüştürülür


AAAh teşekkürler, Nihayet iyi bir cevap. Neden hafıza akışı ile bu kadar çok cevap, bana çok fazla soruna neden oluyor. çok teşekkürler !
Julian50

İyi cevap! bu ayrı bir işlevde kullanılabilir, ancak MemoryStream kullanan diğer tüm teklifler kullanılamaz (Akış, Resmin ömrü boyunca açık tutulmalıdır)
A_L

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

Normalde iyi bir fikir olmasa da, Bellek akışının önüne bir GC.Collect () koyuyorum. Bir sürü büyük grafik dosyasını önyükleme olarak belleğe yüklediğimde ve daha sonra bunları görüntüleme sırasında görüntülere dönüştürdüğümde belleğim bitiyordu.
Kayot

9

@ İsaias-b tarafından sağlanan çözümde bir hata olduğunu belirtmek isterim.

Bu çözüm, stridebunun satır uzunluğuna eşit olduğunu varsayar . Ancak bu her zaman doğru değildir. GDI tarafından gerçekleştirilen bellek hizalamaları nedeniyle, adım satır uzunluğundan daha büyük olabilir. Bu dikkate alınmalıdır. Aksi takdirde geçersiz kaydırılmış görüntü oluşturulacaktır. Her satırdaki doldurma baytları göz ardı edilecektir.

Adım, dört baytlık bir sınıra yuvarlanmış tek bir piksel sırasının (bir tarama çizgisi) genişliğidir.

Sabit kod:

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;
    }
}

Neye yol açabileceğini göstermek için PixelFormat.Format24bppRgb101x101 gradyan görüntüsü oluşturalım:

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);
}

Dizinin tamamını işaret ettiği adrese olduğu gibi kopyalayacaksak bmpData.Scan0, aşağıdaki görüntüyü alacağız. Görüntünün bir kısmı doldurma baytlarına yazıldığı için görüntü kayması yok sayıldı. Ayrıca son satırın eksik olmasının nedeni de budur:

uzun adım yok sayıldı

Ancak, satır satır değişen hedef işaretçisini bmpData.Stridedeğere göre kopyalayacaksak , geçerli görüntü oluşturulacaktır:

dikkate alınan adım

Adım ayrıca olumsuz olabilir:

Adım pozitifse, bit eşlem yukarıdan aşağıya doğrudur. Adım negatifse, bit eşlem aşağıdan yukarıya doğrudur.

Ancak bu tür görüntülerle çalışmadım ve bu notumun ötesinde.

İlgili cevap: C # - C ++ 'dan farklı Bitmap'ten RGB Arabelleği


6

Sunulan tüm yanıtlar, bayt dizisinin gif, png veya jpg gibi bilinen bir dosya biçimi gösteriminde veri içerdiğini varsayar. Ancak son zamanlarda byte[]doğrusallaştırılmış BGRA bilgilerini içeren URL'leri verimli bir şekilde Imagenesnelere dönüştürmeye çalışırken bir sorun yaşadım . Aşağıdaki kod, bir Bitmapnesne kullanarak çözer .

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;
    }
}

Bu, bu sitede yayınlanan bir çözümün biraz varyasyonudur .


referans olarak MSDN: Bitmap (Int32, Int32): "Bu yapıcı, Format32bppArgb PixelFormat numaralandırma değerine sahip bir Bitmap oluşturur.", yani bayt [0] mavi, bayt [1] yeşil, bayt [2] kırmızıdır , bayt [3] alfa, bayt [4] mavi, vb.
brk

1
İhtiyaç duyulan tüm "leri" eklediğiniz için TEŞEKKÜR EDERİZ. Çoğu insan bunu unutur ve hepsini bulmak acı verir.
Casey Crookston

6

Aşağıdaki gibi basit bir yaklaşım FromStreamvar, hile yapmak için bir görüntünün yöntemini kullanabilirsiniz , Sadece kullanmayı unutmayın System.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;
}

5

deneyin (GÜNCELLEME)

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

2
Bayt dizisini, aynı bayt dizisi ile başlatıldıktan sonra bellek akışına yazmak çok az mantıklıdır. Aslında MemoryStream'in yapıcıda belirtilen uzunluğun ötesinde yazmaya izin verdiğinden emin değilim.
Holstebroe

2

ReturnImage'ı herhangi bir değişken olarak tanımlamadınız :)

Bu yardımcı olmalı:

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
Kod bir fikir olarak yararlıdır, ancak elbette yazıldığı gibi çalışmayacaktır. returnImage, dene / yakala bölümünün dışında bildirilmelidir. Ayrıca returnImage'ın 'catch'de somutlaştırılması gerekir - Tek bir piksel bitmap oluşturuyorum: var image = new Bitmap (1, 1); MemoryStream akışı = new MemoryStream (); image.Save (stream, ImageFormat.Jpeg); stream.Position = 0;
Reid

2

Bu, Holstebroe'in cevabından ve buradaki yorumlardan ilham almıştır: Bir bayt dizisinden bir Image nesnesi alma

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

1

Tek astar:

Image bmp = (Bitmap)((new ImageConverter()).ConvertFrom(imageBytes));

0

Bunun olduğu çoğu zaman SQL sütunundaki bozuk verilerdir. Bu, bir görüntü sütununa eklemenin uygun yoludur:

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

Çoğu insan bunu şu şekilde yanlış yapar:

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

0

İlk Bu Paketi Yükleyin:

Yükleme Paketi SixLabors.ImageSharp -Version 1.0.0-beta0007

[SixLabors.ImageSharp] [1] [1]: https://www.nuget.org/packages/SixLabors.ImageSharp

Ardından, Byte Dizisini Görüntüye Çevirmek İçin Aşağıdaki Kodu kullanın:

Image<Rgba32> image = Image.Load(byteArray); 

ImageFormat'ı Almak İçin Aşağıdaki Kodu Kullanın:

IImageFormat format = Image.DetectFormat(byteArray);

Kodun Altındaki Görüntüyü Değiştirmek İçin:

image.Mutate(x => x.Resize(new Size(1280, 960)));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.