From 346ac03cd171e4cd71456f8dd2f0ca87036d2444 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Wed, 9 Oct 2013 22:00:24 -0700 Subject: [PATCH] goexif: merge upstream and document process. This commit contains changes following the process documented in the new file README.camlistore. Because we've used such and ad-hoc process managing this directory in the past, we will need a followup commit that manually merges changes that failed during 'git am'. This change passes 'make presubmit' and a quick examination by running 'devcam server' 'devcam put'ing some CR2 files and visiting /ui/. camlistored logs some messages like: 2013/10/13 13:55:11 filename "RAW_CANON_50D.CR2" exif = 2008-09-17 15:13:40 +0000 UTC, 2013/10/13 13:55:11 filename "RAW_CANON_5DMARK2_PREPROD.CR2" exif = 2008-10-29 20:05:00 +0000 UTC, And thumbnails are properly rotated in the web ui. commit 6034d9ed8d1fd31a8b7e80ffe4acc2c47b3ffd25 Author: Bill Thiede Date: Sun Sep 15 15:10:39 2013 -0700 Add support for TIFF based images, like CR2. This adds detection for TIFF images and skips the steps of removing JPEG and EXIF headers from the data before calling tiff.Decode. commit 2cc61b08a74f782b8665442ee5977649d3109971 Author: mewmew Date: Sat Jan 26 22:38:20 2013 +0100 tiff: Fix bug in convertVals, where floatVals was allocated more than once. commit 8206b5bee50e1d6d7e3b6b385e4ef0ef6e029137 Author: Robert Carlsen Date: Wed Jan 23 15:08:48 2013 -0600 vetted fix from Fatal to Fatalf commit 4347b209f9f0396dd2cca9dbf25cb7f519148ec4 Author: Robert Carlsen Date: Thu Jan 10 20:07:05 2013 -0600 analytics Change-Id: If13a7dbacd35ee2a49315bacf2d7cfc7795c0cc2 --- .../camlistore/goexif/README.camlistore | 82 +++++++++++++++++++ .../github.com/camlistore/goexif/README.md | 1 + .../github.com/camlistore/goexif/exif/exif.go | 56 +++++++++++-- .../camlistore/goexif/exif/exif_test.go | 2 +- .../github.com/camlistore/goexif/tiff/tag.go | 4 +- 5 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 third_party/github.com/camlistore/goexif/README.camlistore diff --git a/third_party/github.com/camlistore/goexif/README.camlistore b/third_party/github.com/camlistore/goexif/README.camlistore new file mode 100644 index 000000000..eb1efc3be --- /dev/null +++ b/third_party/github.com/camlistore/goexif/README.camlistore @@ -0,0 +1,82 @@ +Changing code under third_party/github.com/camlistore/goexif +============================================================ + +These instructions assume you have a github.com account. + +Sync github.com/rwcarlsen/goexif -> github.com/camlistore/goexif +---------------------------------------------------------------- +1. Issue a pull request at https://github.com/camlistore/goexif/pulls, set + the base fork to camlistore/goexif go1 branch, and the head fork as + rwcarlsen/goexif go1 branch. Follow the normal github workflow until + someone on the camlistore project merges in the changes. + +Sync github.com/camlistore/goexif -> camlistore.org/third_party/github.com/camlistore/goexif +-------------------------------------------------------------------------------------------- +1. Once someone on the camlistore team merges in the latest from upstream, + checkout a local copy: + + $ git clone https://github.com/camlistore/goexif + $ cd goexif + +2. Make a patch to apply to the camlistore.org copy. You'll need to know the + git rev of github.com/camlistore/goexif that was last merged to + camlistore.org/third_party, for this example we'll use 030a4566: + + # Create individual patches that have been applied upstream. + $ git format-patch -o /tmp/patches 030a4566 + $ cd /path/to/camlistore.org/third_party/github.com/camlistore/goexif + # Create new branch to temporarily apply each upstream change. + $ git checkout -b patches_individual + # Apply patches. + $ git am --directory=third_party/github.com/camlistore/goexif /tmp/patches/* + + # If something fails to apply try: + $ git apply --reject + $ edit edit edit + $ git add + $ git am --resolved + + # If it is a patch camlistore already had, because we created it and + # pushed it upstream, you can skip it with: + $ git am --skip + + # Now create a new branch to squash all the changes into one. Keeping a + # record of upstream commits in the default commit message of a single + # commit. + $ git checkout -b patches_squashed master + $ git merge --squash patches_individual + + # Verify no new files have been added that require import path updating: + $ cd /path/to/camlistore.org/third_party/ + $ ./rewrite-imports.sh -l + # If any rewrites are required, run: + $ ./rewrite-imports.sh -w + + # Now create a commit that will be sent for review. + $ git commit -v + + # Enter your commit message on the first line per usual. + # You should see summaries of all the changes merged in the commit + # message. Leave these, they will be useful next sync as we'll know what + # commits were sync'd. Send the change for review. + $ ./misc/review + +Sync camlistore.org/third_party/github.com/camlistore/goexif -> github.com/camlistore/goexif +---------------------------------------------------------------------------------------------- +1. TODO(wathiede): this should follow a similar process as 'Sync + github.com/camlistore/goexif -> + camlistore.org/third_party/github.com/camlistore/goexif' Basically use + format-patch to generate a patch for each change we've made in + camlistore.org's repo and apply to a fork of github.com/camlistore/goexif. + Maybe skip the 'merge --squash' step, and keep each change in the log of + github.com/camlistore/goexif. + +Sync github.com/camlistore/goexif -> github.com/rwcarlsen/goexif +-------------------------------------------------------------------- +1. This should follow the standard github pull-request workflow. Issue a + pull request at https://github.com/request/goexif/pulls, set the base fork + to rwcarlsen/goexif go1 branch, and the head fork as camlistore/goexif go1 + branch. + +2. Address any feedback during review and rwcarlsen will merge changes to + github.com/rwcarlsen/goexif as appropriate. diff --git a/third_party/github.com/camlistore/goexif/README.md b/third_party/github.com/camlistore/goexif/README.md index 3b55e5e6c..2694d76ca 100644 --- a/third_party/github.com/camlistore/goexif/README.md +++ b/third_party/github.com/camlistore/goexif/README.md @@ -57,3 +57,4 @@ func main() { ``` +[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/5e166f74cdb82b999ccd84e3c4dc4348 "githalytics.com")](http://githalytics.com/rwcarlsen/goexif) diff --git a/third_party/github.com/camlistore/goexif/exif/exif.go b/third_party/github.com/camlistore/goexif/exif/exif.go index 0c99812e8..ab3722239 100644 --- a/third_party/github.com/camlistore/goexif/exif/exif.go +++ b/third_party/github.com/camlistore/goexif/exif/exif.go @@ -58,15 +58,61 @@ type Exif struct { // Decode parses EXIF-encoded data from r and returns a queryable Exif object. func Decode(r io.Reader) (*Exif, error) { - sec, err := newAppSec(0xE1, r) + // EXIF data in JPEG is stored in the APP1 marker. EXIF data uses the TIFF + // format to store data. + // If we're parsing a TIFF image, we don't need to strip away any data. + // If we're parsing a JPEG image, we need to strip away the JPEG APP1 + // marker and also the EXIF header. + header := make([]byte, 4) + n, err := r.Read(header) + if n < len(header) { + return nil, errors.New("exif: short read on header") + } if err != nil { return nil, err } - er, err := sec.exifReader() - if err != nil { - return nil, err + + var isTiff bool + switch string(header) { + case "II*\x00": + // TIFF - Little endian (Intel) + isTiff = true + case "MM\x00*": + // TIFF - Big endian (Motorola) + isTiff = true + default: + // Not TIFF, assume JPEG } - tif, err := tiff.Decode(er) + + // Put the header bytes back into the reader. + r = io.MultiReader(bytes.NewReader(header), r) + var ( + er *bytes.Reader + tif *tiff.Tiff + ) + + if isTiff { + // Functions below need the IFDs from the TIFF data to be stored in a + // *bytes.Reader. We use TeeReader to get a copy of the bytes as a + // side-effect of tiff.Decode() doing its work. + b := &bytes.Buffer{} + tr := io.TeeReader(r, b) + tif, err = tiff.Decode(tr) + er = bytes.NewReader(b.Bytes()) + } else { + // Strip away JPEG APP1 header. + sec, err := newAppSec(0xE1, r) + if err != nil { + return nil, err + } + // Strip away EXIF header. + er, err = sec.exifReader() + if err != nil { + return nil, err + } + tif, err = tiff.Decode(er) + } + if err != nil { return nil, errors.New("exif: decode failed: " + err.Error()) } diff --git a/third_party/github.com/camlistore/goexif/exif/exif_test.go b/third_party/github.com/camlistore/goexif/exif/exif_test.go index e887bba4a..888020275 100644 --- a/third_party/github.com/camlistore/goexif/exif/exif_test.go +++ b/third_party/github.com/camlistore/goexif/exif/exif_test.go @@ -19,7 +19,7 @@ func TestDecode(t *testing.T) { t.Fatal(err) } if x == nil { - t.Fatal("No error and yet %v was not decoded\n", name) + t.Fatalf("No error and yet %v was not decoded\n", name) } val, err := x.Get("Model") diff --git a/third_party/github.com/camlistore/goexif/tiff/tag.go b/third_party/github.com/camlistore/goexif/tiff/tag.go index d41c2dae0..b2e87f2c6 100644 --- a/third_party/github.com/camlistore/goexif/tiff/tag.go +++ b/third_party/github.com/camlistore/goexif/tiff/tag.go @@ -186,16 +186,16 @@ func (t *Tag) convertVals() { t.ratVals[i] = []int64{int64(n), int64(d)} } case 11: // float32 + t.floatVals = make([]float64, int(t.Ncomp)) for i := 0; i < int(t.Ncomp); i++ { - t.floatVals = make([]float64, int(t.Ncomp)) var v float32 err := binary.Read(r, t.order, &v) panicOn(err) t.floatVals[i] = float64(v) } case 12: // float64 (double) + t.floatVals = make([]float64, int(t.Ncomp)) for i := 0; i < int(t.Ncomp); i++ { - t.floatVals = make([]float64, int(t.Ncomp)) var u float64 err := binary.Read(r, t.order, &u) panicOn(err)