Le moyen le plus rapide de convertir une image en tableau d'octets

106

Je crée une application de partage de bureau à distance dans laquelle je capture une image du bureau, je la compresse et je l'envoie au récepteur. Pour compresser l'image, je dois la convertir en octet [].

Actuellement j'utilise ceci:

public byte[] imageToByteArray(System.Drawing.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;
}

Mais je ne l'aime pas car je dois l'enregistrer dans un ImageFormat et cela peut également utiliser des ressources (ralentir) et produire des résultats de compression différents.J'ai lu sur l'utilisation de Marshal.Copy et memcpy mais je suis incapable de les comprendre.

Existe-t-il donc une autre méthode pour atteindre cet objectif?

user2529551
la source
MemoryStream et Image ont tous deux une méthode de mise au rebut, assurez-vous de les éliminer car cela peut provoquer des MemoryLeaks.
abc123 le
3
@ abc123: Vous n'avez pas besoin de disposer d'un MemoryStream; c'est une ressource entièrement gérée, sauf si vous l'utilisez dans la communication à distance. Dans ces deux cas, il serait inapproprié de disposer de la ressource.
Jon Skeet
1
@JonSkeet intéressant, avez-vous fait un benchmark à ce sujet? pour voir la vitesse à laquelle .net libère l'objet? Je sais qu'il existe un argument similaire pour DataTable et pourtant il y a une différence notable dans la vitesse à laquelle le GarbageCollector collecte la mémoire allouée quand une disposition est utilisée.
abc123
@ abc123: Je ne m'attendrais vraiment pas à ce qu'il y en ait un - la suppression du flux ne fait rien au tableau, et MemoryStream n'a pas de finaliseur (contrairement à DataTable, qui en hérite de MarshalByValueComponent).
Jon Skeet
2
une solution finale avec le code source complet?
Kiquenet

Réponses:

39

Existe-t-il donc une autre méthode pour atteindre cet objectif?

Non. Pour convertir une image en tableau d'octets, vous devez spécifier un format d'image - tout comme vous devez spécifier un encodage lorsque vous convertissez du texte en tableau d'octets.

Si vous vous inquiétez des artefacts de compression, choisissez un format sans perte. Si vous êtes préoccupé par les ressources du processeur, choisissez un format qui ne gêne pas la compression - uniquement des pixels ARVB bruts, par exemple. Mais bien sûr, cela conduira à un plus grand tableau d'octets.

Notez que si vous choisissez un format qui ne comprend la compression, il n'y a pas de point dans la compression puis le tableau d'octets après - il est presque certain d'avoir aucun effet bénéfique.

Jon Skeet
la source
12
au lieu de «choisir un format sans perte», vous pouvez choisir les imageIn.RawFormattentatives de sauvegarde des octets de l'image brute sans réencodage supplémentaire.
Chris F Carroll
52

Il existe une propriété RawFormat du paramètre Image qui renvoie le format de fichier de l'image. Vous pouvez essayer ce qui suit:

// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
{
    using(var ms = new MemoryStream())
    {
        image.Save(ms, image.RawFormat);
        return ms.ToArray();
    }
}
Triton
la source
9
Je recommanderais de supprimer le MemoryStream ou d'encapsuler le corps de cette méthode dans une instruction using () {}
Neil.Allen
@ Neil.Allen Je suis nouveau ici, pouvez-vous dire pourquoi?
Khalil Khalaf
3
@FirstStep Parce que nettoyez après vous :)
Sinaesthetic
@Sinaesthetic je vois. Et la routine est de mettre la fonction que je veux exécuter, dans un using () {}?
Khalil Khalaf
2
@FirstStep Pas tout à fait. Plus précisément: si vous utilisez un objet qui a implémenté IDisposable, vous devez vous assurer d'appeler Dispose () lorsque vous en avez terminé avec lui afin qu'il nettoie toutes les ressources qu'il a bloquées. L'instruction using () {} l'appelle simplement pour vous lorsque l'objet sort du champ d'application de cette instruction. Vous pouvez donc faire myObject.Dispose()ou using(myObject){}- les deux font la même chose, mais l'instruction using crée essentiellement une portée qui nettoiera pour vous.
Sinaesthetic
14

Je ne sais pas si vous allez obtenir des gains énormes pour les raisons évoquées par Jon Skeet. Cependant, vous pouvez essayer de comparer la méthode TypeConvert.ConvertTo et voir comment elle se compare à l'utilisation de votre méthode actuelle.

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));
clavierP
la source
Impossible de convertir un objet de type «System.Byte []» en type «System.Drawing.Image».
user123
14
public static byte[] ReadImageFile(string imageLocation)
    {
        byte[] imageData = null;
        FileInfo fileInfo = new FileInfo(imageLocation);
        long imageFileLength = fileInfo.Length;
        FileStream fs = new FileStream(imageLocation, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fs);
        imageData = br.ReadBytes((int)imageFileLength);
        return imageData;
    }
bhadresh
la source
5
Bienvenue sur stackoverflow.com, pourriez-vous ajouter un petit détail expliquant pourquoi l'exemple de code ci-dessus est utile. C'est pour les autres utilisateurs de SO qui peuvent ne pas le comprendre entièrement ... stackoverflow.com/help/how-to-answer
Mack
C'est pour les fichiers en octets, mais l'OP voulait un objet de dessin converti en octets. Les objets de dessin peuvent être stockés dans des bases de données, pas nécessairement le système de fichiers, sous forme de tableau d'octets, et doivent donc être transformés d'avant en arrière ... mais pas en tant que fichiers dans un FileStream à convertir en octets - à moins que peut-être, pendant le téléchargement initial.
vapcguy
Cela m'a aidé car je cherchais à faire cela avec des fichiers. Bon à avoir autour de lui.
Justin
5
public static class HelperExtensions
{
    //Convert Image to byte[] array:
    public static byte[] ToByteArray(this Image imageIn)
    {
        var ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        return ms.ToArray();
    }

    //Convert byte[] array to Image:
    public static Image ToImage(this byte[] byteArrayIn)
    {
        var ms = new MemoryStream(byteArrayIn);
        var returnImage = Image.FromStream(ms);
        return returnImage;
    }
}
Ahmad Aghazadeh
la source
2

Le moyen le plus rapide pour le savoir est le suivant:

var myArray = (byte[]) new ImageConverter().ConvertTo(InputImg, typeof(byte[]));

J'espère être utile

alireza amini
la source
Soyez prudent avec cela, surtout si vous utilisez WPF où vous auriez des System.Windows.Controls.Imageobjets. Si vous voulez convertir l'un de ceux-ci en octets et que vous le passez à cette ligne en tant que InputImg, cela ne fonctionnera pas. Il attend un System.Drawing.Imageobjet.
vapcguy