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

PnmFile.cs

using FSpot.Imaging;
using SemWeb;
using System;
using System.IO;

#if ENABLE_NUNIT
using NUnit.Framework;
#endif

namespace FSpot.Pnm {
      public class PnmFile : ImageFile, StatementSource {

                // false seems a safe default
                public bool Distinct {
                        get { return false; }
                }

            public PnmFile (Uri uri) : base (uri) 
            {
            }

            public PnmFile (string path) : base (path) 
            {
            }

            public class Header {
                  public string Magic;
                  public int Width;
                  public int Height;
                  public ushort Max;
                  
                  public Header (Stream stream)
                  {
                        Magic = GetString (stream);
                        Width = int.Parse (GetString (stream));
                        Height = int.Parse (GetString (stream));
                        Max = ushort.Parse (GetString (stream));
                  }

                  public bool IsDeep {
                        get {
                              return Max > 256;
                        }
                  }

                  public void Dump ()
                  {
                        System.Console.WriteLine ("Loading ({0} - {1},{2} - {3})", 
                                            Magic, Width, Height, Max);
                  }
            }

            public void Select (StatementSink sink)
            {
                  using (Stream stream = Open ()) {
                        Header header = new Header (stream);
                        MetadataStore.AddLiteral (sink, "tiff:ImageWidth", header.Width.ToString ());
                        MetadataStore.AddLiteral (sink, "tiff:ImageLength", header.Height.ToString ());
                        string bits = header.IsDeep ? "16" : "8";
                        MetadataStore.Add (sink, "tiff:BitsPerSample", "rdf:Seq", new string [] { bits, bits, bits });
                  }
            }
            
            public override Stream PixbufStream ()
            {
                  Stream stream = Open ();
                  Header header = new Header (stream);
                  if (header.IsDeep)
                        return null;

                  stream.Position = 0;
                  return stream;
            }

            static char EatComment (Stream stream)
            {
                  char c;
                  do {
                        c = (char)stream.ReadByte ();
                        
                  } while (c != '\n' && c != '\n');
                  
                  return c;
            }

            static string GetString (Stream stream)
            {
                  System.Text.StringBuilder builder = new System.Text.StringBuilder ();

                  char c;
                  do {
                        c = (char)stream.ReadByte ();
                        if (c == '#')
                              c = EatComment (stream);

                  } while (char.IsWhiteSpace (c));
                  
                  while (! char.IsWhiteSpace (c)) {
                        builder.Append (c);
                        c = (char)stream.ReadByte ();                   
                  }
                  
                  return builder.ToString ();
            }

            public static ushort [] ReadShort (Stream stream, int width, int height, int channels)
            {
                  int length = width * height * channels;
                  ushort [] data = new ushort [length];
                  byte [] tmp = new byte [2];

                  for (int i = 0; i < length; i++)
                  {
                        stream.Read (tmp, 0, tmp.Length);
                        data [i] = BitConverter.ToUInt16 (tmp, 0, false);
                  }
                  return data;
            }

            static Gdk.Pixbuf LoadRGB16 (Stream stream, int width, int height)
            {
                  Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, false, 8, width, height);
                  unsafe {
                        byte *pixels = (byte *)pixbuf.Pixels;
                        int length = width * 6;
                        byte [] buffer = new byte [length];
                        
                        for (int row = 0; row < height; row++) {
                              stream.Read (buffer, 0, buffer.Length);
                              for (int i = 0; i < width * 3; i++) {
                                    pixels [i] = (byte) (BitConverter.ToUInt16 (buffer, i * 2, false) >> 8);
                              }
                              pixels += pixbuf.Rowstride;
                        }
                  }
                  return pixbuf;
            }

            static Gdk.Pixbuf LoadRGB8 (Stream stream, int width, int height)
            {
                  Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, false, 8, width, height);
                  unsafe {
                        byte *pixels = (byte *)pixbuf.Pixels;
                        byte [] buffer = new byte [width * 3];
                        
                        for (int i = 0; i < height; i++) {
                              stream.Read (buffer, 0, buffer.Length);
                                  
                              System.Runtime.InteropServices.Marshal.Copy (buffer, 0, 
                                                                 (System.IntPtr)pixels, buffer.Length);
                              
                              pixels += pixbuf.Rowstride; 
                        }
                  }
                  return pixbuf;
            }

            static PixelBuffer LoadBufferRGB16 (Stream stream, int width, int height)
            {
                  PixelBuffer pix = new UInt16Buffer (width, height);
                  int count = width * 3;
                  byte [] buffer = new byte [count * 2];

                  for (int row = 0; row < height; row++) {
                        int len = 0;
                        while (len < buffer.Length) {
                              int read = stream.Read (buffer, len, buffer.Length - len);
                              if (read < 0)
                                    break;
                              len += read;
                        }

                        pix.Fill16 (row, 0, buffer, 0, count, false);
                  }

                  return pix;
            }

            static PixelBuffer LoadBufferRGB8 (Stream stream, int width, int height)
            {
                  PixelBuffer pix = new UInt16Buffer (width, height);
                  int length = width * 3;
                  byte [] buffer = new byte [length];
                  
                  for (int row = 0; row < height; row++) {
                        stream.Read (buffer, 0, buffer.Length);
                        pix.Fill8 (row, 0, buffer, 0, buffer.Length);
                  }

                  return pix;
            }

            public static FSpot.Imaging.PixelBuffer LoadBuffer (Stream stream)
            {

                  Header header = new Header (stream);
                  header.Dump (); 

                  switch (header.Magic) {
                  case "P6":
                        if (header.IsDeep)
                              return LoadBufferRGB16 (stream, header.Width, header.Height);
                        else
                              return LoadBufferRGB8 (stream, header.Width, header.Height);
                  default:
                        throw new System.Exception (System.String.Format ("unknown pnm type {0}", header.Magic));
                  }                 
            }

            public override Gdk.Pixbuf Load ()
            {
                  try {
                        using (Stream stream = Open ()) {
                              Gdk.Pixbuf pixbuf = PnmFile.Load (stream);
                              return pixbuf;
                        }
                  } catch (System.Exception e) {
                        System.Console.WriteLine (e.ToString ());
                  }
                  return null;
            }

            public override Gdk.Pixbuf Load (int width, int height)
            {
                  return PixbufUtils.ScaleToMaxSize (this.Load (), width, height);
            }

            public override void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
            {
                  if (pixbuf.HasAlpha)
                        throw new NotImplementedException ();

                  // FIXME this should be part of the header class
                  string header = String.Format ("P6\n"
                                           + "#Software: {0} {1}\n"
                                           + "{2} {3}  #Width and Height\n"
                                           + "255\n", 
                                           FSpot.Defines.PACKAGE,
                                           FSpot.Defines.VERSION,
                                           pixbuf.Width, 
                                           pixbuf.Height);
                                           
                  byte [] header_bytes = System.Text.Encoding.UTF8.GetBytes (header);
                  stream.Write (header_bytes, 0, header.Length);
                                                             
                  unsafe {
                        byte * src_pixels = (byte *) pixbuf.Pixels;
                        int src_stride = pixbuf.Rowstride;
                        int count = pixbuf.Width * pixbuf.NChannels;
                        int height = pixbuf.Height;

                        for (int y = 0; y < height; y++) {
                              for (int x = 0; x < count; x++) {
                                    stream.WriteByte (* (src_pixels + x));
                              }
                              src_pixels += src_stride;
                        }
                  }
            }

            public static Gdk.Pixbuf Load (Stream stream)
            {
                  Header header = new Header (stream);
                  header.Dump ();

                  switch (header.Magic) {
                  case "P6":
                        if (header.IsDeep) {
#if SKIP_BUFFER                           
                              return LoadRGB16 (stream, header.Width, header.Height);
#else
                              stream.Position = 0;
                              FSpot.Imaging.PixelBuffer image = FSpot.Pnm.PnmFile.LoadBuffer (stream);
                              Gdk.Pixbuf result = image.ToPixbuf (Cms.Profile.CreateStandardRgb ());
                              return result;
#endif
                        } else
                              return LoadRGB8 (stream, header.Width, header.Height);
                  default:
                        throw new System.Exception (System.String.Format ("unknown pnm type {0}", header.Magic));
                  }                 
            }
      }

#if ENABLE_NUNIT
      [TestFixture]
      public class Tests {
            [Test]
            public void SaveLoad ()
            {
                  using (Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (null, "f-spot-32.png")) {
                        Gdk.Pixbuf source = pixbuf;
                        if (pixbuf.HasAlpha)
                              source = PixbufUtils.Flatten (pixbuf);

                        string path = ImageFile.TempPath ("test.ppm");
                        PnmFile pnm = new PnmFile (path);
                        using (Stream stream = File.OpenWrite (path)) {
                              pnm.Save (source, stream);
                        }

                        pnm = new PnmFile (path);

                        using (Gdk.Pixbuf saved = pnm.Load ()) {
                              Assert.IsNotNull (saved);
                              Assert.AreEqual (saved.Width, source.Width);
                              Assert.AreEqual (saved.Height, source.Height);
                        }
                        
                        if (source != pixbuf)
                              source.Dispose ();

                        File.Delete (path);
                  }
            }
      }     
#endif
}

Generated by  Doxygen 1.6.0   Back to index