Copying geo data from one image to another.

2009-06-30

In my last post I created a panorama by stitching a number of photographs together with DoubleTake. One problem with creating synthetic images is they lack the geo data I embed in the rest of the photographs from my GPS’ track log. I figured the always excellent exiftool could accomplish copying the data so it would be visible in Lightroom but I wasn’t entirely sure how. After some trial-and-error this worked:

$ exiftool -tagsfromfile Z09023676.dng -@ geotags.txt marmotpass.tiff

where geotags.txt is a list of all the tags to copy from the source image Z09023676.dng to the destination image marmotpass.tiff:

-EXIF:DateTimeOriginal
-EXIF:CreateDate
-EXIF:ModifyDate
-EXIF:TimeZoneOffset
-XMP:DateTimeOriginal
-XMP:DateTimeDigitized
-XMP:ModifyDate
-EXIF:GPSSatellites
-EXIF:GPSLatitude
-EXIF:GPSLongitude
-EXIF:GPSLatitudeRef
-EXIF:GPSLongitudeRef
-EXIF:GPSMapDatum
-EXIF:GPSDateStamp
-EXIF:GPSTimeStamp
-EXIF:GPSAltitude
-EXIF:GPSAltitudeRef
-XMP:GPSLatitude
-XMP:GPSLongitude
-XMP:GPSDateTime
-XMP:GPSAltitude
-XMP:GPSAltitudeRef
-XMP:CountryCode
-XMP:Country
-XMP:State
-XMP:City
-XMP:Location
-IPTC:Country-PrimaryLocationCode
-IPTC:Country-PrimaryLocationName
-IPTC:Province-State
-IPTC:City

If you forgot to turn on the GPS for some portion of the shoot (hmmm) but happened to shoot from the same location at another time, remove the date and time related fields and apply the same approach.

Categories : development   photography
Tags :     

You do not have appropriate access privileges

2008-12-29

It used to be Mac upgrades were straight forward and safe, but no longer. I’m continually experiencing some problem or another, though fortunately most are pretty easy to remedy — here’s another and my most recent.

I have an extensive backup strategy which includes backing up to two different external drives. When I upgraded to 10.5.6 I had no issues with Time Machine on the first of the drives but when I got to work today I was greeted with this lovely and informative message:

not authorized

You do not have appropriate access privileges to save file “.0022xxxxxxxx” in folder “Island”.

It’s an easy fix, open iTerm or Terminal and follow along:

$ cd /Volumes/{volume name}
$ sudo chown $USER {file name}
Categories : development   general
Tags :     

Python thread dumps.

2008-12-17

For some time I’ve wanted the equivalent of Java’s ability to dump the stack trace of all currently running threads in Python as a means for debugging some hung processes. I finally found a solution and wired it up to the services’ http console:

import sys
import traceback
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
 
def stacktraces():
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# ThreadID: %s" % threadId)
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
 
    return highlight("\n".join(code), PythonLexer(), HtmlFormatter(
      full=False,
      # style="native",
      noclasses=True,
    ))

The magic happens with sys._current_frames() which returns exactly what I wanted. The only outstanding issue is how to get the thread’s name to display in addition to the ident.

I’ll probably hook this up as a signal handler as well so headless applications can have the same functionality.

Categories : development

Using Python’s “with” statement.

2008-12-02

I happened upon a post whereby the author has:

a number of functions that all do very different things, but they all create and close a “context” [code example] I’d rather avoid the code duplication, and the danger of forgetting that try/finally block and the close().

The author’s implementation was rather clever: using decorators to magically add the context, invoke the function passing the context instance as a keyword and then destroying the context after the function invocation. However, as the poster suggests, it’s kinda kludgy and not explicit — thereby violating one of the tenets of The Zen of Python.

But, what’s interesting, in some ways he basically invented the with statement introduced in Python 2.5 without knowing it. I really like with because it solves the often needed sequence of open-call-close rather abstractly and in quite a Pythonic way. My with solution shell:

from __future__ import with_statement # needed in 2.5, not in 2.6+
 
import logging
import traceback
logging.basicConfig(level=logging.INFO)
 
class Context(object):
    def __init__(self, i):
        self.i = i
        logging.info("(%d) initializing", self.i)
 
    def __enter__(self):
        logging.info("(%d) entering", self.i)
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        logging.error("(%d) exiting", self.i)
        if exc_type:
            s = traceback.format_exception(exc_type, exc_val, exc_tb)
            logging.error("".join(s))
            return True
 
def g():
    for i in range (4):
        with Context(i) as ctx:
            if i == 2:
                # for demonstration purposes let's raise
                raise ValueError(i)
 
g()

The two magic methods required to participant in context management are:

  • __enter__: invoked when entering the context
  • __exit__: invoked when leaving the context; if the exception arguments are non-None an exception was raised — return True to suppress, False to re-raise

Running the code yields:

$ python b.py 
INFO:root:(0) initializing
INFO:root:(0) entering
ERROR:root:(0) exiting
INFO:root:(1) initializing
INFO:root:(1) entering
ERROR:root:(1) exiting
INFO:root:(2) initializing
INFO:root:(2) entering
ERROR:root:(2) exiting
ERROR:root:Traceback (most recent call last):
  File "b.py", line 26, in g
    raise ValueError(i)
ValueError: 2
 
INFO:root:(3) initializing
INFO:root:(3) entering
ERROR:root:(3) exiting

Summit, sunset, Pierre.

2008-10-28

My silence of late is attributable to having spent the better part of last week at eBay attending the Next-Generation Distributed Systems Summit. I was fortunate, in time and invitation, to attend, meet some really amazing technologists and learn a Tremendous amount (thanks Little Bear). I’m still consolidating my final notes and thoughts on the Summit so expect another post soon.

In the interim, enjoy some sunset photos from my travels with Pierre.

From time to time I’m reminded not everyone is up to speed on the travel-with-animals story: my daughter sends an animal along with me anytime I venture out on the “big boat” — I photograph our adventures and share the love.

pierre at ebay

Thank you eBay, and in particular Randy, for hosting such an outstanding event.

pierre with rainier

Pierre poses with Mt Rainier in the background.

pierre with sun

pierre sitting on the deck with the sun

Pierre basking in the setting sun.

pierre at stanfordpierre with the stanford S

I found a bit of time to stop by one of our country’s more beautiful and influential universities: Stanford.

pierre on benchsun, water, swirl

lots of sky

sun, water, mountains

I love being out on the boat at sunset — I think it beats sunrise.