2010-02-19 4 views
5

Avant, lorsque j'utilisais win32, j'utilisais FreeImage pour charger et sauvegarder des bitmaps de profondeur supérieure à 8 bits. Toutes les images avec lesquelles je travaille, puisque je fais de l'imagerie médicale, et avant que qui que ce soit, oui, mes clients et moi avons dépensé beaucoup d'argent sur des moniteurs à contraste élevé et à luminosité élevée avec 11 ou 12 bits de dynamique . En fait, si vous êtes curieux, requirements by the ACR for running mammography incluue un moniteur avec au moins 10 bits de gamme dynamique.Comment puis-je sauvegarder/charger une image 16 bits dans .net x64?

Je viens commuté à x64 pour les frais généraux de mémoire et d'obtenir tout mon développement sur une plate-forme et le mode compilation. Je préfère ne pas revenir à win32, et mes clients sont là avec moi (et vraiment forçant le changement). FreeImage ne compile pas sur les fenêtres de 64 bits; il a une directive _asm dans le code que le compilateur ne peut pas gérer.

Je pensais que je vais essayer le support natif .NET dans les classes Microsoft. Longue histoire courte: Ils ne fonctionnent pas, et échouent avec des messages d'erreur très limités. Je suppose que c'est parce que Microsoft ne supporte toujours pas la classe Format16bppGrayScale.

Peut-être qu'il y a un problème dans mon code. Voici mon code écrit:

Bitmap theBitmap = new Bitmap(inImage.XSize, inImage.YSize, PixelFormat.Format16bppGrayScale); 

//have to go with lockbits 
Rectangle rect = new Rectangle(0, 0, theBitmap.Width, theBitmap.Height); 
System.Drawing.Imaging.BitmapData bmpData = 
    theBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
    PixelFormat.Format16bppGrayScale); 
IntPtr ptr = bmpData.Scan0; 
int theByteSize = theBitmap.Width * theBitmap.Height *2; 
byte[] theByteBuffer = new byte[theByteSize]; 
System.Buffer.BlockCopy(inImage.Data, 0, theByteBuffer, 0, theByteSize); 
System.Runtime.InteropServices.Marshal.Copy(theByteBuffer, 0, ptr, theByteSize); 
theBitmap.UnlockBits(bmpData); 

theBitmap.Save(inDirectory + "\\" + inName); 
theBitmap.Dispose(); 

Ce code provoque le plantage du programme avec

An unhandled exception of type 
'System.Runtime.InteropServices.ExternalException' occurred in 
System.Drawing.dll 

Additional information: A generic error occurred in GDI+. 

Intéressant, surtout que je ne veux plus jamais dessiner cette image à l'écran comme celui-ci (même si ce serait bien!) , mais je veux juste utiliser la fonctionnalité de sauvegarde/chargement. L'image ne s'écrit sur le disque (même si le programme se bloque), et le code de lecture suivante bloque également le programme:

Bitmap theBitmap = new Bitmap(theCompleteName, false); 
ushort[] theData = new ushort[theBitmap.Width * theBitmap.Height]; 
int x, y; 

switch (theBitmap.PixelFormat) 
{ 
    case PixelFormat.Format16bppGrayScale: 
     //have to go with lockbits 
     {   
      Rectangle rect = new Rectangle(0, 0, theBitmap.Width, theBitmap.Height); 
      System.Drawing.Imaging.BitmapData bmpData = 
       theBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, 
       PixelFormat.Format16bppGrayScale); 
      IntPtr ptr = bmpData.Scan0;//scanline approach left over from FreeImage 

      for (y = 0; y < theBitmap.Height; ++y){ 
       byte[] scanline = new byte[theBitmap.Width*2]; 
       System.Runtime.InteropServices.Marshal.Copy(ptr, scanline, y * theBitmap.Width * 2, theBitmap.Width * 2); 
       System.Buffer.BlockCopy(scanline, 0, theData, y * theBitmap.Width * 2, theBitmap.Width * 2); 
      } 
      theBitmap.UnlockBits(bmpData); 
     } 
     break; 
    //for colors, just take the red and call it a day 


    case PixelFormat.Format24bppRgb: 
    case PixelFormat.Format32bppArgb://really stupid reading code, always works 
     for (y = 0; y < theBitmap.Height; ++y) { 
      for (x = 0; x < theBitmap.Width; ++x) { 
       theData[y * theBitmap.Width + x] = (byte)(theBitmap.GetPixel(x, y).R); 
      } 
     } 
     break; 
} 
theNewImage = new ImageContainer(theData, theBitmap.Width, theBitmap.Height, inName, inAssessmentID); 
theBitmap.Dispose();//not needed, anymore 

Ce code provoque le plantage du programme avec l'erreur:

An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll 

Additional information: Parameter is not valid. 

Ces résultats dis-moi que Microsoft n'a toujours pas corrigé la partie Format16bppGrayScale de l'énumération PixelFormat. C'est une honte.

Que puis-je utiliser pour charger et enregistrer 16 bits des images en niveaux de gris sur 64 bits avec .NET?

(EDIT: Je dois ajouter que, bien que je puisse sauvegarder des images DICOM, j'ai besoin de faire des expériences sur des données non-patient pour vérifier que les algorithmes sont sains, etc ... DICOM nécessite un ensemble d'UID et autres champs qui sont trop exigeants pour ce dont j'ai besoin, j'ai juste besoin d'images, et pas de données patient, pour le moment).

Répondre

3

FreeImage pouvez être compilé en x64. En suivant les instructions here, vous pouvez contourner la directive _asm. Il y a aussi une DLL 64 bits compilée en bas de la page.

La dernière version (3.15.1) contient déjà ce correctif. J'ai pris la distribution source à essayer (je suis curieux d'utiliser FreeImage dans mon propre projet) et la plate-forme x64 compile bien tout de suite.

+0

Vous avez raison-- à partir de maintenant, le projet freeimage compile pour x64. Merci de l'avoir signalé! – mmr

0

Je ne réponds pas vraiment à votre question mais j'ai déjà utilisé le composant ImageDraw vendu par Neodnyamic et je le recommanderais sans hésiter (et j'utiliserais) à nouveau. Ce n'est pas gratuit mais ça vaut bien un petit investissement.

+0

hrm. Il semble que ImageDraw utilise GDI +, ce qui signifie qu'il devrait avoir exactement les mêmes erreurs que ce que je reçois maintenant, n'est-ce pas? – mmr

+0

Téléchargez l'essai et découvrez-le.De mémoire le composant a été acheté en raison des problèmes avec GDI +. – Kane

Questions connexes