Logo Search packages:      
Sourcecode: f-spot version File versions

Histogram.cs

/* 
 *  
 */

using System;

namespace FSpot {
      public class Histogram {
            public Histogram (Gdk.Pixbuf src)
            {
                    FillValues (src);
            }
            
            public Histogram () {}
            
            // FIXME these should be properties
            public byte [] Color = new byte [] {0x00, 0x00, 0x00, 0xff};

            public void FillValues (Gdk.Pixbuf src)

            {
                  values = new int [256, 3];

                  if (src.BitsPerSample != 8)
                        throw new System.Exception ("Invalid bits per sample");
                                    
                  unsafe {
                        byte * srcb = (byte *)src.Pixels;
                        byte * pixels = srcb;
                        bool alpha = src.HasAlpha;
                        int rowstride = src.Rowstride;
                        int width = src.Width;
                        int height = src.Height;

                        // FIXME array bounds checks slow this down a lot
                        // so we use a pointer.  It is sad but I want fastness
                        fixed (int * v = &values [0,0]) {
                              for (int j = 0; j < height; j++) {
                                    for (int i = 0; i < width; i++) {
                                          v [*(srcb++) * 3 + 0]++;
                                          v [*(srcb++) * 3 + 1]++;
                                          v [*(srcb++) * 3 + 2]++;
                                          
                                          if (alpha)
                                                srcb++;
                                          
                                    }
                                    srcb =  ((byte *) pixels) + j * rowstride;
                              }
                        }
                  }
                  if (pixbuf != null) {
                        Draw (pixbuf);
                  }
            }
            
            public int Count (int channel)
            {
                  int count = 0;
                  for (int i = 0; i < values.GetLength (0); i++) {
                        count += values [i, channel];
                  }

                  return count;
            }

            public void GetHighLow (int channel, out int high, out int low)
            {
                  double total = Count (channel);
                  double current = 0.0;
                  double percentage;
                  double next_percentage;
                  
                  low = 0;
                  high = 0;
                  
                  for (int i = 0; i < values.GetLength (0) - 1; i++) {
                        current += values [i, channel];
                        percentage = current / total;
                        next_percentage = (current + values [i + 1, channel]) / total;
                        if (Math.Abs (percentage - 0.006) < Math.Abs (next_percentage - 0.006)) {
                              low = i + 1;
                              break;
                        }
                  }

                  for (int i = values.GetLength (0) - 1; i > 0; i--) {
                        current += values [i, channel];
                        percentage = current / total;
                        next_percentage = (current + values [i - 1, channel]) / total;
                        if (Math.Abs (percentage - 0.006) < Math.Abs (next_percentage - 0.006)) {
                              high = i - 1;
                              break;
                        }
                  }
            }

            private void Draw (Gdk.Pixbuf image) 
            {
                  int max = 0;
                  for (int i = 0; i < values.GetLength (0); i++) {
                        for (int j = 0; j < values.GetLength (1); j++) {
                              max = System.Math.Max (max, values [i, j]);
                        }
                  }
                  unsafe {
                        int height = image.Height;
                        int rowstride = image.Rowstride;
                        int r = 0;
                        int b = 0;
                        int g = 0;
                        
                        for (int i = 0; i < image.Width; i++) {
                              byte * pixels = (byte *)image.Pixels + i * 4;
                              
                              if (max > 0) {
                                    r = values [i, 0] * height / max;
                                    g = values [i, 1] * height / max;
                                    b = values [i, 2] * height / max;
                              } else 
                                    r = g = b = 0;

                              int top = Math.Max (r, Math.Max (g, b));

                              int j = 0;
                              for (; j < height - top; j++) {
                                    pixels [0] = Color [0];
                                    pixels [1] = Color [1];
                                    pixels [2] = Color [2];
                                    pixels [3] = Color [3];
                                    pixels += rowstride;
                              }
                              for (; j < height; j++) {
                                    pixels [0] = (byte) ((j >= height - r) ? 0xff : 0x00);
                                    pixels [1] = (byte) ((j >= height - g) ? 0xff : 0x00);
                                    pixels [2] = (byte) ((j >= height - b) ? 0xff : 0x00);
                                    pixels [3] = 0xff;
                                    pixels += rowstride;
                              }

                        }
                  }
            }     

            public Gdk.Pixbuf GeneratePixbuf ()
            {
                  int height = 128;
                  pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, values.GetLength (0), height);
                  this.Draw (pixbuf);
                  return pixbuf;
            }
                                         
            private int [,] values = new int [256, 3];
            public int [,] Values {
                  get {
                        return values;
                  }
            }
            
            private Gdk.Pixbuf pixbuf;
            public Gdk.Pixbuf Pixbuf {
                  get {
                        return pixbuf;
                  }
            }
            
#if FSPOT_HISTOGRAM_MAIN
            public static void Main (string [] args) 
            {
                  Gtk.Application.Init ();
                  Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (args [0]);
                  System.Console.WriteLine ("loaded {0}", args [0]);
                  Histogram hist = new Histogram (pixbuf);
                  System.Console.WriteLine ("loaded histgram", args [0]);
                  
                  Gtk.Window win = new Gtk.Window ("display");
                  Gtk.Image image = new Gtk.Image ();
                  Gdk.Pixbuf img = hist.GeneratePixbuf ();
                  image.Pixbuf = img;
                  win.Add (image);
                  win.ShowAll ();
                  Gtk.Application.Run ();

            }
#endif
      }
}

Generated by  Doxygen 1.6.0   Back to index