2010-12-05 9 views
4

J'essaie de combiner un ensemble d'images PNG 8 bits dans une image PNG plus grande en C#. Curieusement, cela semble être particulièrement difficile. Comme Graphics ne prend pas en charge les couleurs indexées, vous ne pouvez pas l'utiliser. J'ai donc essayé de créer un bitmap non indexé (en utilisant Graphics) et de le convertir en bitmap couleur indexé. La conversion est correcte, mais je n'arrive pas à comprendre comment définir la palette de l'image de sortie. Il a par défaut une palette prédéfinie qui a peu à voir avec ce que je cherche.Meilleure façon de combiner plusieurs images PNG8 dans .NET

Alors:

est-il un moyen de contrôler la palette bitmap? Ou existe-t-il une autre méthode (System.Windows.Media.Imaging.WriteableBitmap, par exemple) qui peut supporter cela? Re: WriteableBitmap: Je n'arrive pas à trouver des exemples en ligne sur la manière de combiner des PNG dans ce contexte, ou même si cela a du sens de l'essayer.

+0

Bien que se référant spécifiquement aux GIFs, le principal principal de la table de couleurs s'applique probablement ... http://support.microsoft.com/kb/319061 seulement expérimenté avec le code un peu en faisant quelque chose de très semblable. –

Répondre

0

Il se trouve que je suis en mesure de construire un bitmap non indexé et convertir à l'aide PngBitmapEncoder comme ceci:

byte[] ConvertTo8bpp(Bitmap sourceBitmap) 
    { 
     // generate a custom palette for the bitmap (I already had a list of colors 
     // from a previous operation 
     Dictionary<System.Drawing.Color, byte> colorDict = new Dictionary<System.Drawing.Color, byte>(); // lookup table for conversion to indexed color 
     List<System.Windows.Media.Color> colorList = new List<System.Windows.Media.Color>(); // list for palette creation 
     byte index = 0; 
     unchecked 
     { 
      foreach (var cc in ColorsFromPreviousOperation) 
      { 
       colorDict[cc] = index++; 
       colorList.Add(cc.ToMediaColor()); 
      } 
     } 
     System.Windows.Media.Imaging.BitmapPalette bmpPal = new System.Windows.Media.Imaging.BitmapPalette(colorList); 

     // create the byte array of raw image data 
     int width = sourceBitmap.Width; 
     int height = sourceBitmap.Height; 
     int stride = sourceBitmap.Width; 
     byte[] imageData = new byte[width * height]; 

     for (int x = 0; x < width; ++x) 
      for (int y = 0; y < height; ++y) 
      { 
       var pixelColor = sourceBitmap.GetPixel(x, y); 
       imageData[x + (stride * y)] = colorDict[pixelColor]; 
      } 

     // generate the image source 
     var bsource = BitmapSource.Create(width, height, 96, 96, PixelFormats.Indexed8, bmpPal, imageData, stride); 

     // encode the image 
     PngBitmapEncoder encoder = new PngBitmapEncoder(); 
     encoder.Interlace = PngInterlaceOption.Off; 
     encoder.Frames.Add(BitmapFrame.Create(bsource)); 

     MemoryStream outputStream = new MemoryStream(); 
     encoder.Save(outputStream); 

     return outputStream.ToArray(); 
    } 

plus la méthode d'extension d'aide:

public static System.Windows.Media.Color ToMediaColor(this System.Drawing.Color color) 
    { 
     return new System.Windows.Media.Color() 
     { 
      A = color.A, 
      R = color.R, 
      G = color.G, 
      B = color.B 
     }; 
    } 

Note pour le prudent : le PngBitmapEncoder semble réellement réduire le nombre de bpp de 8 à 4 quand il le peut. Lorsque je teste avec 6 couleurs, par exemple, le PNG de sortie est seulement de 4 bits. Lorsque j'utilise une image plus riche en couleurs, c'est en 8 bits. On dirait une fonctionnalité jusqu'ici ... bien que ce serait bien si j'avais un contrôle explicite dessus.

0

Avis de non-responsabilité, je travaille pour Atalasoft.

Notre produit, DotImage Photo, est gratuit et peut le faire.

Pour lire un PNG

AtalaImage img = new AtalaImage("image.png"); 

Pour convertir à 24 BPP

img = img.GetChangedPixelFormat(newPixelFormat); 

Créer une image de la taille que vous voulez

AtalaImage img2 = new AtalaImage(width, height, color); 

utilisation OverlayCommand superposer img sur img2

OverlayCommand cmd = new OverlayCommand(img); 
cmd.Apply(img2, point); 

Pour enregistrer

img2.Save("new.png", new PngEncoder(), null); 

Si vous avez besoin d'aide soit commentaire sur cette réponse ou faire une entrée du forum.

Questions connexes