252 votes

Convertir un bitmap en un tableau d'octets

En utilisant C#, existe-t-il un meilleur moyen de convertir un fichier Windows Bitmap à un byte[] que de sauvegarder dans un fichier temporaire et de lire le résultat à l'aide d'une FileStream ?

462voto

prestomanifesto Points 4135

Il y a plusieurs façons.

ImageConverter

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

Celle-ci est pratique car elle ne nécessite pas beaucoup de code.

Flux de mémoire

public static byte[] ImageToByte2(Image img)
{
    byte[] byteArray = new byte[0];
    using (MemoryStream stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        stream.Close();

        byteArray = stream.ToArray();
    }
    return byteArray;
}

Celle-ci est équivalente à ce que vous faites, sauf que le fichier est enregistré en mémoire au lieu d'être sur le disque. Bien qu'il y ait plus de code, vous avez l'option ImageFormat et il peut être facilement modifié entre l'enregistrement en mémoire ou sur le disque.

Source : http://www.vcskicks.com/image-to-byte.php

2 votes

Vous pouvez également utiliser bitmap.Lockbits et Marshal.Copy pour une simple copie rapide sans flux de mémoire intermédiaire, etc.

7 votes

Veuillez noter que le ImageConverter enregistre l'image au format Png, ce qui donne lieu à des fichiers volumineux.

8 votes

vous n'avez pas besoin de fermer le flux lorsque vous utilisez 'using'.

103voto

A MemoryStream peut être utile pour cela. Vous pourriez le mettre dans une méthode d'extension :

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

Tu pourrais l'utiliser comme ça :

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

Je suis partiellement en désaccord avec la réponse de prestomanifto concernant l'ImageConverter. N'utilisez pas ImageConverter. Techniquement, il n'y a rien de mal à cela, mais le simple fait qu'il utilise le boxing/unboxing de l'objet m'indique qu'il s'agit d'un code provenant des vieux endroits sombres du cadre .NET et qu'il n'est pas idéal à utiliser avec le traitement d'images (c'est trop pour la conversion en byte[] au moins), surtout si l'on considère ce qui suit.

J'ai jeté un coup d'œil à la ImageConverter utilisé par le cadre .Net, et en interne, il utilise un code presque identique à celui que j'ai fourni ci-dessus. Il crée un nouveau MemoryStream , sauve le Bitmap dans le format dans lequel il était lorsque vous l'avez fourni, et retourne le tableau. Il n'est pas nécessaire de créer un tableau ImageConverter en utilisant MemoryStream

0 votes

Charmant. Ca va le faire ! Je suppose que vous voulez vous débarrasser du MemoryStream, cependant - vous voulez bien mettre à jour ?

0 votes

J'ai mis à jour ma réponse avec une discussion sur les raisons de ne pas utiliser ImageConverter, comme votre réponse choisie le suggère, ainsi que l'ajout de l'élimination.

0 votes

Belle utilisation d'une méthode d'extension, j'aime ça !

52voto

deegee Points 390

Vous pouvez également vous contenter de Marshal.Copy pour les données bitmap. Pas de flux de mémoire intermédiaire, etc. et une copie mémoire rapide. Cela devrait fonctionner sur les bitmaps 24 bits et 32 bits.

public static byte[] BitmapToByteArray(Bitmap bitmap)
{

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

    bitmap.UnlockBits(bmpdata);

    return bytedata;

}

.

1 votes

Bonjour, j'ai utilisé cette méthode, mais je ne peux pas reconvertir ce tableau d'octets en image. Bitmap bitmap1 = new Bitmap(new MemoryStream(array)) ; il jette une exception de paramètres invalides. Y a-t-il une erreur ?

1 votes

Bonjour, la section des commentaires est trop petite pour que je puisse poster un code complet et propre. Le moyen le plus simple est d'épingler le tableau : GCHandle handle = GCHandle.Alloc(bufferarray, GCHandleType.Pinned) ; récupérer le pointeur vers le tableau IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement(bufferarray, 0) ; puis créer un nouveau bitmap en utilisant l'IntPtr : bitmap = new Bitmap(width, height, (width * 4), PixelFormat.Format32bppArgb, iptr) ; mais vous devrez utiliser les paramètres de création de bitmap appropriés pour votre format de bitmap. Assurez-vous de nettoyer : iptr = IntPtr.Zero ; handle.Free() ;

0 votes

Mais votre fonction a un bug, c'est dommage.

18voto

Chris Baxter Points 8085

Sauvegarder l'image dans un MemoryStream, puis récupérer le tableau d'octets.

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

  Byte[] data;

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

    data = memoryStream.ToArray();
  }

0 votes

Il n'y a pas de méthode de sauvegarde sur l'image.

0 votes

@PrescottChartier L'exemple ci-dessus suppose que vous travaillez à partir d'un type dérivé de System.Drawing.Image (voir : docs.microsoft.com/fr/us/dotnet/api/ )

0 votes

Yup et je reçois System.Drawing.Image does not exist . Donc non, ça ne marche pas :(

12voto

Jeff Reddy Points 2110

Utilisez un MemoryStream au lieu d'un FileStream comme ceci :

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

0 votes

Vous voulez probablement ToArray pas GetBuffer .

0 votes

GetBuffer renvoie un tableau d'octets non signés (tableau d'octets).

4 votes

Il peut contenir des données de remplissage qui ne font pas partie de l'image. Dans la documentation : 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. Donc maintenant le tableau d'octets de GetBuffer retournera l'image plus les octets inutilisés, ce qui aura probablement pour résultat une image corrompue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X