web-dev-qa-db-fra.com

Conversion d'octets en images

Je veux convertir un tableau d'octets en une image.

Ceci est mon code de base de données d'où j'obtiens le tableau d'octets:

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

Mon code de conversion:

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

Lorsque j'atteins la ligne avec un commentaire, l'exception suivante se produit: Parameter is not valid.

Comment puis-je réparer ce qui cause cette exception?

84
Tanzeel ur Rahman

Vous écrivez deux fois dans votre flux de mémoire, vous ne supprimez pas non plus le flux après utilisation. Vous demandez également au décodeur d'image d'appliquer la correction de couleur intégrée.

Essayez ceci à la place:

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

Peut-être me manque-t-il quelque chose, mais pour moi, cette ligne unique fonctionne bien avec un tableau d'octets contenant une image d'un fichier JPEG.

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

MODIFIER:

Voir ici pour une version mise à jour de cette réponse: Comment convertir une image en tableau d'octets

76
RenniePet
    public Image byteArrayToImage(byte[] bytesArr)
    {
        using (MemoryStream memstr = new MemoryStream(bytesArr))
        {
            Image img = Image.FromStream(memstr);
            return img;
        }
    }
11
Ali Gh

J'aimerais noter qu'il y a un bogue dans la solution fournie par @ isaias-b.

Cette solution suppose que stride est égal à la longueur de la ligne. Mais ce n'est pas toujours vrai. En raison des alignements de mémoire effectués par GDI, le pas peut être supérieur à la longueur de la ligne. Ceci doit être pris en compte. Sinon, une image décalée non valide sera générée. Les octets de remplissage de chaque ligne seront ignorés.

La foulée est la largeur d'une seule ligne de pixels (une ligne de balayage), arrondie à une limite de quatre octets.

Code fixe:

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

Pour illustrer ce à quoi cela peut conduire, générons PixelFormat.Format24bppRgb image en dégradé 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);
}

Si nous copions le tableau entier tel quel à l'adresse indiquée par bmpData.Scan0, nous obtiendrons l'image suivante. Décalage d'image car une partie de l'image a été écrite en octets de remplissage, ce qui a été ignoré. C'est aussi pourquoi la dernière ligne est incomplète:

stride ignored

Mais si nous copions le pointeur de destination décalé ligne par ligne selon la valeur bmpData.Stride, une image valide sera générée:

stride taken into account

Stride peut aussi être négatif:

Si le pas est positif, le bitmap est de haut en bas. Si la foulée est négative, l'image bitmap est ascendante.

Mais je n'ai pas travaillé avec de telles images et c'est au-delà de ma note.

Réponse associée: C # - Tampon RGB de Bitmap différent de C++

8
lorond

il existe une approche simple comme ci-dessous, vous pouvez utiliser la méthode FromStream d'une image pour faire l'affaire, rappelez-vous simplement d'utiliser 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;
}
6
Ali

Toutes les réponses présentées supposent que le tableau d'octets contient des données dans une représentation de format de fichier connue, telle que: gif, png ou jpg. Mais j'ai récemment eu un problème en essayant de convertir efficacement byte[]s, contenant des informations BGRA linéarisées, en objets Image. Le code suivant le résout en utilisant un objet 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;
    }
}

Ceci est une légère variante d'une solution qui a été postée sur ce site .

5
isaias-b

essayez (UPDATE)

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

Ceci est inspiré par la réponse de Holstebroe, plus les commentaires ici: Obtenir un objet Image à partir d'un tableau d'octets

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

Vous n'avez pas déclaré returnImage en tant que variable :)

Cela devrait aider:

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

La plupart du temps, lorsque cela se produit, il s'agit de mauvaises données dans la colonne SQL. C’est la bonne façon d’insérer dans une colonne d’image:

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

La plupart des gens le font mal de cette façon:

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