2017-05-11 2 views
2

Quel est le but de ImageLockMode dans Bitmap.LockBits? Pour ReadOnly le documentation que seuls les EtatsBut de ImageLockMode dans Bitmap.LockBits (avec du code)

ReadOnly: Indique qu'une partie de l'image est verrouillée pour la lecture.

Mais le code suivant prouve que cela n'est pas vrai. Je sais que la question a déjà été posée, cette fois-ci j'essaie avec un code réel car je ne trouve pas de réponse ailleurs.

Si je cours le code suivant, il se comporte exactement comme expliqué dans la réponse.

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

namespace LockBits_Trials 
{ 
    class Program 
    { 
     static readonly Random rnd = new Random(42); 
     static void Main(string[] args) 
     { 
     Bitmap bmp_fromFile = new Bitmap("example.png"); 
     Bitmap bmp_fromCtor = new Bitmap(100, 100, PixelFormat.Format24bppRgb); 
     marshalCopy(bmp_fromFile, "result_marshalCopy_fromFile.png"); 
     marshalCopy(bmp_fromCtor, "result_marshalCopy_fromCtor.png"); 
     usePointer(bmp_fromFile, "result_usePointer_fromFile.png"); 
     usePointer(bmp_fromCtor, "result_usePointer_fromCtor.png"); 
     } 

     private static unsafe void usePointer(Bitmap bmp, string filename) 
     { 
     ImageLockMode mode = ImageLockMode.ReadOnly; 
     //code from turgay at http://csharpexamples.com/fast-image-processing-c/ 
     if (bmp.PixelFormat != PixelFormat.Format24bppRgb) 
      throw new Exception(); 
     BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), mode, bmp.PixelFormat); 
     int bytesPerPixel = 3; int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; 
     byte* ptrFirstPixel = (byte*)bitmapData.Scan0; 
     for (int y = 0; y < heightInPixels; y++) { 
      byte* currentLine = ptrFirstPixel + (y * bitmapData.Stride); 
      for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { 
       currentLine[x] = (byte)rnd.Next(0, 255); 
       currentLine[x + 1] = (byte)rnd.Next(0, 255); 
       currentLine[x + 2] = (byte)rnd.Next(0, 255); 
      } 
     } 
     bmp.UnlockBits(bitmapData); 
     bmp.Save(filename, ImageFormat.Png); 
     } 

     private static unsafe void marshalCopy(Bitmap bmp, string filename) 
     { 
     ImageLockMode mode = ImageLockMode.ReadOnly; 
     if (bmp.PixelFormat != PixelFormat.Format24bppRgb) 
      throw new Exception(); 
     BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), mode, bmp.PixelFormat); 
     IntPtr ptrFirstPixel = bitmapData.Scan0; 
     int totalBytes = bitmapData.Stride * bitmapData.Height; 
     byte[] newData = new byte[totalBytes]; 
     for (int i = 0; i < totalBytes; i++) 
      newData[i] = (byte)rnd.Next(0, 255); 
     Marshal.Copy(newData, 0, ptrFirstPixel, newData.Length); 
     bmp.UnlockBits(bitmapData); 
     bmp.Save(filename, ImageFormat.Png); 
     } 
    } 
} 

Les images result_marshalCopy_fromFile.png et result_usePointer_fromFile.png contiennent tous deux l'image d'origine, donc rien a été écrasé (et pas exception levée!). Les deux autres images contiennent le bruit aléatoire qui leur a été écrit pendant leur verrouillage.

Je n'ai pas effectué de test supplémentaire pour confirmer le comportement de l'accès en écriture parallèle, car je ne le fais pas de toute façon.

Ce n'est pas un double, mais fortement liée: Does Bitmap.LockBits “pin” a bitmap into memory?

+0

Vous n'êtes pas assez difficile, pas de codec pour rester heureux. Vous devrez rendre sa vie plus difficile en demandant intentionnellement un format de pixel qui ne correspond pas au format de pixel de l'image bitmap. –

+0

@Hans Passant Je ne comprends pas? –

Répondre

1

Comme vous l'avez observé, une fois que vous avez eu accès au pointeur de données brutes, il n'y a rien pour vous empêcher d'écrire à cette mémoire, quelle que soit la Type de verrou demandé. Le type de verrou n'est vraiment utile que dans deux cas:

1) Si plusieurs bits de demande de code se verrouillent simultanément, un seul verrou d'écriture peut être émis à la fois, alors que les verrous en lecture peuvent être partagés. Ceci, bien sûr, dépend du code qui acquiert les verrous en les utilisant de manière appropriée.

2) Tous les verrous ne sont pas directement sauvegardés par la mémoire Bitmap. Dans votre exemple, c'est parce que vous avez créé une mémoire Bitmap et ensuite demandé un verrou dans le même format de pixel. Cependant, une image bitmap peut représenter d'autres objets GDI +, tels que des pixels appartenant à un contexte de périphérique. En outre, si vous demandez un format de pixel autre que celui de la source, vous devrez peut-être le convertir. Dans l'un ou l'autre de ces cas, lorsqu'un verrou de lecture est demandé, GDI + peut avoir à tirer une copie du bitmap de la vraie source et à vous le donner dans le format de pixel requis. Si vous deviez modifier cette copie, elle ne serait pas réécrite dans le contexte source. Si vous avez demandé un verrou en écriture, GDI + sait qu'il faut recopier les pixels sur la source une fois que vous avez libéré le verrou.

+0

Merci pour la réponse détaillée. Je viens de faire un test qui confirme ce que vous dites et édite ma question en conséquence. Si vous pouviez jeter un oeil sur le code pour les erreurs? Ce serait génial. –