Sunday, February 12, 2006

One of the most popular search hits for my blog is "Managed XMP Parser".  A while back (actually it was 1 year ago today...whoa, freaky), I blogged about extracting the XMP data out of my pictures after screwing up the upload into Flickr.  I ended up writing my own code to pull out the XMP data.  I mentioned making it available, but it was relatively straightforward, so I never got around to posting it.

In the last week, I've gotten lots of requests for the code, so here it is, uglyness and all.  One interesting thing about my approach is that I do not rely on any particular file format.  I simply look for the XMP markers and pull out the XML in-between.  This means it will work on ANY file with embedded XMP.

All the usual disclaimers apply.  I don't claim this is the best way, but it works.  I've just plucked it out of my little date fixing app I built.  At the end, you'll have an XPathNavigator and a namespace manager setup to run XPath queries.  There's probably some sweet stuff the 2.0 can help us out with, but I haven't updated it.  Enjoy:

MemoryStream xmpStream = new MemoryStream();

byte[] beginPattern = Encoding.ASCII.GetBytes("<?xpacket begin");

int beginIndex=0;

bool beginFound = false;

byte[] beginStopPattern = Encoding.ASCII.GetBytes(">\n");

int beginStopIndex = 0;

bool xmlStartFound = false;

byte[] endPattern = Encoding.ASCII.GetBytes("<?xpacket end");

int endIndex=0;

bool endFound = false;

bool backedUp = false;

using (Stream stream = new FileStream(path, FileMode.Open)) {

      int data;

      while ((data = stream.ReadByte()) != -1) {

            byte b = (byte)data;

            if (!beginFound) {

                  if (b == beginPattern[beginIndex]) {

                        beginIndex++;

                        if (beginIndex >= beginPattern.Length) {

                              beginFound = true;

                        }

                  }

                  else {

                        if (beginIndex != 0) {

                              beginIndex = 0;

                              stream.Seek(-1, SeekOrigin.Current);

                        }

                  }

            }

            else if (!xmlStartFound) {

                  if (b == beginStopPattern[beginStopIndex]) {

                        beginStopIndex++;

                        if (beginStopIndex >= beginStopPattern.Length) {

                              xmlStartFound = true;

                        }

                  }

                  else {

                        if (beginStopIndex != 0) {

                              beginStopIndex = 0;

                              stream.Seek(-1, SeekOrigin.Current);

                        }

                  }

            }

            else if (!endFound) {

                  //load up the memorystream

                  if (backedUp) {

                        backedUp = false;

                  }

                  else {

                        xmpStream.WriteByte(b);

                  }

                  if (b == endPattern[endIndex]) {

                        endIndex++;

                        if (endIndex >= endPattern.Length) {

                              endFound = true;

                              xmpStream.SetLength(xmpStream.Length-endPattern.Length);

                              break;

                        }

                  }

                  else {

                        if (endIndex != 0) {

                              endIndex = 0;

                              stream.Seek(-1, SeekOrigin.Current);

                              backedUp = true;

                        }

                  }

            }

      }

}

if (!endFound) {

      Console.WriteLine("No XMP data found");

      break;

}

//load up the xmp

xmpStream.Position = 0;

XPathDocument xmpDocument = new XPathDocument(xmpStream);

XPathNavigator xmpNav = xmpDocument.CreateNavigator();

XmlNamespaceManager nsManager = new XmlNamespaceManager(xmpNav.NameTable);

nsManager.AddNamespace("x", "adobe:ns:meta/");

nsManager.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");

nsManager.AddNamespace("iX", "http://ns.adobe.com/iX/1.0/");

nsManager.AddNamespace("crs", "http://ns.adobe.com/camera-raw-settings/1.0/");

nsManager.AddNamespace("exif", "http://ns.adobe.com/exif/1.0/");

nsManager.AddNamespace("aux", "http://ns.adobe.com/exif/1.0/aux/");

nsManager.AddNamespace("pdf", "http://ns.adobe.com/pdf/1.3/");

nsManager.AddNamespace("photoshop", "http://ns.adobe.com/photoshop/1.0/");

nsManager.AddNamespace("tiff", "http://ns.adobe.com/tiff/1.0/");

nsManager.AddNamespace("xap", "http://ns.adobe.com/xap/1.0/");

nsManager.AddNamespace("xapMM", "http://ns.adobe.com/xap/1.0/mm/");

nsManager.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");

XPathExpression dateExpr = xmpNav.Compile("string(/x:xmpmeta/rdf:RDF/rdf:Description/exif:DateTimeOriginal)");

dateExpr.SetContext(nsManager);

string dateTimeStr = (string)xmpNav.Evaluate(dateExpr);

DateTime date = XmlConvert.ToDateTime(dateTimeStr);

 

 

posted on Sunday, February 12, 2006 2:48:18 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Thursday, February 09, 2006

Well, my new TV arrived yesterday afternoon, so after work, church, and getting Jenna to sleep, I finally got to hook it up.  The first thing I did was fire up the XBox360.  The dashboard just about knocked me across the room.  It is breathtakingly beautiful.  I fired up Halo 2 to check for video lag (for which I had to send my previous set back if you recall).  I was pleased to find minimal lag "out of the box".  A quick jaunt through the menus revealed "game mode", which eliminated the lag altogether (or at least to a point indistiguishable from my previous lag-free CRT set).

So I'm really looking forward to the HD Olympics coverage this year.  I hope it doesn't suck like it did 2 years ago for the summer games.  We'll see.

All said and done, I couldn't be more pleased.  We see what little annoyances I can find in a week.  I'm pretty picky.

(pictures coming)

posted on Thursday, February 09, 2006 7:54:29 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Wednesday, February 01, 2006

I've had the itch for a new TV for a while now.  Mine is what I would call a "first-gen" HD set.  It's a 40" rear-projection CRT capable of 1080i scan rates.  As a CRT, it is subject to all the CRT problems:

  • Non-linear geometry problems across all 3 tubes - This could be summarized with "convergence issues", but causes lots of different visible anomalies.
  • Focus issues across three projectors
  • Blue gun "bleed"
  • "hot spots" of different color temperature across the screen.
  • Heavy as heck
  • etc.

Beyond that, as a first-gen set, it has some problems like not dealing with different aspect ratios cleanly, no digital inputs, etc.  In addition, it's getting old and is having some electronic problems.

Back in October, I ordered one of the new 1080p Sampsung DLP sets.  It was beautiful, but I sent it back for several reasons:

  • The DLP rainbow effect was very bothersome to me
  • The "video lag" made playing Halo 2 virtually impossible

I was very dissapointed to send it back, and I've been scared to get another one, for fear of the same dissapointments.  But I think I'm finally ready to get another one.  It's Sony's new 1080p SXRD set. It's based on Sony's implementation of LCOS (Liquid Crystal on Semiconductor).  It's a three-chip solution (separate chips for red, green, and blue), so it won't be able to do ClearType, and will have some convergence to deal with, but at that resolution, ClearType won't be necessary and any convergence problems will be linear and shouldn't be a big deal.  In addition, I have read lots of reviews that indicate there is no video lag with the xbox360.  I'd like to get personal experience with this, so I may cart my 360 to a store and try it out myself.

Anyone have any experience with Sony's SXRD sets?  Any advice?  I think the only thing I don't like about it is those crazy speakers sticking out the side.  All my audio runs through my sound system, so they'll just be there taking up space.

posted on Wednesday, February 01, 2006 12:05:35 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]