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

JpegFile.cs

#define USE_TIFF
using System;
using System.IO;
using FSpot.Xmp;
using FSpot.Tiff;

#if ENABLE_NUNIT
using NUnit.Framework;
#endif

namespace FSpot {
      public interface IThumbnailContainer {
            Gdk.Pixbuf GetEmbeddedThumbnail ();
      }

      public class JpegFile : ImageFile, IThumbnailContainer, SemWeb.StatementSource {
            private Exif.ExifData exif_data;
            private XmpFile xmp;
            private JpegHeader header;
            private FSpot.Tiff.Header exif_header;

                // False seems a safe default
                public bool Distinct {
                        get { return false; }
                }
            
            public JpegFile (Uri uri) : base (uri)
            {
                  try {
                        // Console.WriteLine ("approximate quality = {0}", Header.GuessQuality ());
                  } catch (Exception e) {
                        System.Console.WriteLine (e);
                  }
            }
            
            public JpegFile (string path) : base (path) 
            {
            }

            public JpegHeader Header {
                  get {
                        if (header == null) {
                              using (Stream stream = this.Open ()) {
                                    header = new JpegHeader (stream, true);
                              }
                        }
                        return header;
                  }
            }

            public FSpot.Tiff.Header ExifHeader {
                  get {
                        if (exif_header == null) {
                              exif_header = Header.GetExifHeader ();
                        }
                        return exif_header;
                  }
            }

            public void Select (SemWeb.StatementSink sink)
            {
                  Header.Select (sink);
            }

            public override Cms.Profile GetProfile ()
            {
                  return Header.GetProfile ();
            }

            public override string Description {
                  get {
#if USE_TIFF
                        try {
                              SubdirectoryEntry sub = (SubdirectoryEntry) ExifHeader.Directory.Lookup (TagId.ExifIfdPointer);
                              if (sub != null) {
                                    DirectoryEntry entry = sub.Directory [0].Lookup (TagId.UserComment);
                                    if (entry != null)
                                          return entry.ValueAsString [0];
                              }
                        } catch (System.Exception e) {
                              Console.WriteLine (e);
                        }
                        return null;
#else
                        try {
                              Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);
                              Exif.ExifEntry entry = exif_content.Lookup (Exif.Tag.UserComment);
                              
                              if (entry == null)
                                    return null;
                              
                              UserComment comment = new UserComment (entry.Data, entry.ByteOrder == Exif.ByteOrder.Intel);
                              return comment.Value;
                        } catch (Exception e) {
                              // errors here shouldn't be fatal
                              return null;
                        }
#endif                        
                  }
            }

            public void SetDescription (string value)
            {
                  Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);                
                  Exif.ExifEntry entry = exif_content.GetEntry (Exif.Tag.UserComment);

                  UserComment comment = new UserComment (value);
                  byte [] data = comment.GetBytes (entry.ByteOrder == Exif.ByteOrder.Intel);
                  entry.SetData (data);
            }
            
            public void SetXmp (XmpFile xmp)
            {
                  this.xmp = xmp;
            }

            private void UpdateMeta ()
            {
                  Exif.ExifContent image_content = this.ExifData.GetContents (Exif.Ifd.Zero);
                  image_content.GetEntry (Exif.Tag.Software).SetData (FSpot.Defines.PACKAGE + " version " + FSpot.Defines.VERSION);

                  // set the write time in the datetime tag
                  image_content.GetEntry (Exif.Tag.DateTime).Reset ();
            }

            private void SaveMetaData (System.IO.Stream input, System.IO.Stream output)
            {
                  JpegHeader header = new JpegHeader (input);
                  UpdateMeta ();
                  
                  // Console.WriteLine ("updated metadata");
                  header.SetExif (this.ExifData);
                  // Console.WriteLine ("set exif");
                  if (xmp != null)
                        header.SetXmp (xmp);
                  // Console.WriteLine ("set xmp");
                  header.Save (output);
                  // Console.WriteLine ("saved");
            }
            
            public void SaveMetaData (string path)
            {
                  UpdateMeta ();

                  //Get file permissions... (mkstemp does not keep permissions or ownership)
                  Mono.Unix.Native.Stat stat;
                  int stat_err = Mono.Unix.Native.Syscall.stat (path, out stat);

                  string  temp_path = path;
                  using (System.IO.FileStream stream = System.IO.File.OpenRead (path)) {
                        using (System.IO.Stream output = FSpot.Unix.MakeSafeTemp (ref temp_path)) {
                              SaveMetaData (stream, output);
                        }
                  }

                  File.SetAttributes (temp_path, File.GetAttributes (path));

                  if (FSpot.Unix.Rename (temp_path, path) < 0) {
                        System.IO.File.Delete (temp_path);
                        throw new System.Exception (System.String.Format ("Unable to rename {0} to {1}",
                                                              temp_path, path));
                  }

                  //Set file permissions and gid...
                  if (stat_err == 0) 
                        try {
                              Mono.Unix.Native.Syscall.chmod (path, stat.st_mode |
                                                            Mono.Unix.Native.FilePermissions.S_IRUSR | 
                                                            Mono.Unix.Native.FilePermissions.S_IWUSR);
                              Mono.Unix.Native.Syscall.chown(path, Mono.Unix.Native.Syscall.getuid (), stat.st_gid);
                        } catch (Exception) {}
            }

            public void SetThumbnail (Gdk.Pixbuf source)
            {
                  // Then create the thumbnail
                  // The DCF spec says thumbnails should be 160x120 always
                  Gdk.Pixbuf thumbnail = PixbufUtils.ScaleToAspect (source, 160, 120);
                  byte [] thumb_data = PixbufUtils.Save (thumbnail, "jpeg", null, null);
                  
                  // System.Console.WriteLine ("saving thumbnail");                       

                  // now update the exif data
                  ExifData.Data = thumb_data;
            }

            public void SetDimensions (int width, int height)
            {
                  Exif.ExifEntry e;
                  Exif.ExifContent thumb_content;
                  
                  // update the thumbnail related image fields if they exist.
                  thumb_content = this.ExifData.GetContents (Exif.Ifd.One);
                  e = thumb_content.Lookup (Exif.Tag.RelatedImageWidth);
                  if (e != null)
                        e.SetData ((uint)width);

                  e = thumb_content.Lookup (Exif.Tag.RelatedImageHeight);
                  if (e != null)
                        e.SetData ((uint)height);
                  
                  Exif.ExifContent image_content;
                  image_content = this.ExifData.GetContents (Exif.Ifd.Zero);
                  image_content.GetEntry (Exif.Tag.Orientation).SetData ((ushort)PixbufOrientation.TopLeft);
                  //image_content.GetEntry (Exif.Tag.ImageWidth).SetData ((uint)pixbuf.Width);
                  //image_content.GetEntry (Exif.Tag.ImageHeight).SetData ((uint)pixbuf.Height);
                  image_content.GetEntry (Exif.Tag.PixelXDimension).SetData ((uint)width);
                  image_content.GetEntry (Exif.Tag.PixelYDimension).SetData ((uint)height);
            }

            public override void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
            {

                  // Console.WriteLine ("starting save");
                  // First save the imagedata
                  int quality = Header.GuessQuality ();
                  quality = quality == 0 ? 75 : quality;
                  byte [] image_data = PixbufUtils.Save (pixbuf, "jpeg", new string [] {"quality" }, new string [] { quality.ToString () });
                  System.IO.MemoryStream buffer = new System.IO.MemoryStream ();
                  buffer.Write (image_data, 0, image_data.Length);
                  buffer.Position = 0;
                  
                  // Console.WriteLine ("setting thumbnail");
                  SetThumbnail (pixbuf);
                  SetDimensions (pixbuf.Width, pixbuf.Height);
                  pixbuf.Dispose ();
                  
                  // Console.WriteLine ("saving metatdata");
                  SaveMetaData (buffer, stream);
                  // Console.WriteLine ("done");
                  buffer.Close ();
            }
            
            public Gdk.Pixbuf GetEmbeddedThumbnail ()
            {
                  if (this.ExifData.Data.Length > 0) {
                        MemoryStream mem = new MemoryStream (this.ExifData.Data);
                        Gdk.Pixbuf thumb = new Gdk.Pixbuf (mem);
                        Gdk.Pixbuf rotated = PixbufUtils.TransformOrientation (thumb, this.Orientation);
                        
                        if (rotated != thumb)
                              thumb.Dispose ();
                        
                        mem.Close ();
                        return rotated;
                  }
                  return null;
            }
            
            public Exif.ExifData ExifData {
                  get {
                        if (exif_data == null) {
                              exif_data = Header.Exif;

                              if (exif_data == null || exif_data.Handle.Handle == System.IntPtr.Zero)
                                    exif_data = new Exif.ExifData ();
                        }
                        // System.Console.WriteLine ("loading exif data");
                        return exif_data;
                  }
                  set {
                        this.exif_data = value;
                  }
            }

            public override PixbufOrientation GetOrientation () 
            {
                  PixbufOrientation orientation = PixbufOrientation.TopLeft;
#if USE_TIFF
                  try {
                        DirectoryEntry e = ExifHeader.Directory.Lookup (TagId.Orientation);
                        orientation = (PixbufOrientation)e.ValueAsLong [0];
                  } catch {
                        System.Console.WriteLine ("error checking orientation");
                  }
#else                                    
                  Exif.ExifEntry e = this.ExifData.GetContents (Exif.Ifd.Zero).Lookup (Exif.Tag.Orientation);
                  
                  if (e != null) {
                        ushort [] value = e.GetDataUShort ();
                        orientation = (PixbufOrientation) value [0];
                  }
#endif                  
                  if (orientation < PixbufOrientation.TopLeft || orientation > PixbufOrientation.LeftBottom)
                        orientation = PixbufOrientation.TopLeft;

                  return orientation;
            }
            
            public void SetOrientation (PixbufOrientation orientation)
            {
                  Exif.ExifEntry e = this.ExifData.GetContents (Exif.Ifd.Zero).GetEntry (Exif.Tag.Orientation);
                  // System.Console.WriteLine ("Saving orientation as {0}", orientation);
                  e.SetData ((ushort)orientation);
                   
                  e = this.ExifData.GetContents (Exif.Ifd.One).Lookup (Exif.Tag.Orientation);
                  if (e != null)
                        e.SetData ((ushort)orientation);
            }
            
            public void SetDateTimeOriginal (DateTime time)
            {
                  Exif.ExifEntry e = ExifData.LookupFirst (Exif.Tag.DateTimeOriginal);
                  if (e != null)
                        e.SetData (time);
                  else {
                        Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);
                        Exif.ExifEntry entry = exif_content.GetEntry (Exif.Tag.DateTimeOriginal);
                        entry.SetData (time);
                  }           
            }

            public override System.DateTime Date {
                  get {
                        System.DateTime time;
                        try {
#if USE_TIFF
                              SubdirectoryEntry sub = (SubdirectoryEntry) ExifHeader.Directory.Lookup (TagId.ExifIfdPointer);
                              DirectoryEntry e;
                              
                              if (sub != null) {
                                    e = sub.Directory [0].Lookup (TagId.DateTimeOriginal);
                                    
                                    if (e != null)
                                          return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
                              }
                              
                              e = ExifHeader.Directory.Lookup (TagId.DateTime);
                              
                              if (e != null)
                                    return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
                              
                              return base.Date;
#else
                              string time_str = "";                     
                              time_str = ExifData.LookupFirstValue (Exif.Tag.DateTimeOriginal);
                              
                              if (time_str == null || time_str == "") 
                                    time_str = ExifData.LookupFirstValue (Exif.Tag.DateTime);
                              
                              time = Exif.ExifUtil.DateTimeFromString (time_str).ToUniversalTime (); 
#endif
                        } catch (System.Exception e) {
                              Console.WriteLine (e);
                              time = base.Date;
                        }
                        return time;
                  }
            }

#if ENABLE_NUNIT
            [TestFixture]
            public class Tests {
                  public Tests ()
                  {
                        Gnome.Vfs.Vfs.Initialize ();
                        Gtk.Application.Init ();
                  }
                  
#if false
                  [Test]
                  public void TestLoad ()
                  {
                        JpegFile jimg = new JpegFile ("/home/lewing/start.swe.jpeg");
                        Assert.AreEqual (PixbufOrientation.TopLeft, jimg.Orientation);
                  }
#endif
                  [Test]
                  public void TestSave ()
                  {
                        string desc = "this is an example description";
                        string desc2 = "\x00a9 Novell Inc.";
                        PixbufOrientation orient = PixbufOrientation.TopRight;
                        Gdk.Pixbuf test = new Gdk.Pixbuf (null, "f-spot-32.png");
                        string path = ImageFile.TempPath ("joe.jpg");
                        
                        PixbufUtils.SaveJpeg (test, path, 75, new Exif.ExifData ());
                        JpegFile jimg = new JpegFile (path);
                        jimg.SetDescription (desc);
                        jimg.SetOrientation (orient);
                        jimg.SaveMetaData (path);
                        JpegFile mod = new JpegFile (path);
                        Assert.AreEqual (mod.Orientation, orient);
                        Assert.AreEqual (mod.Description, desc);
                        jimg.SetDescription (desc2);
                        jimg.SaveMetaData (path);
                        mod = new JpegFile (path);
                        Assert.AreEqual (mod.Description, desc2);
                        
                        File.Delete (path);
                  }
            }
#endif
      }
}

Generated by  Doxygen 1.6.0   Back to index