Index the dimensions of images.

This commit is contained in:
Brad Fitzpatrick 2012-11-07 23:54:00 +01:00
parent a41269e78e
commit 3057358cfc
5 changed files with 81 additions and 7 deletions

View File

@ -586,10 +586,10 @@ func (x *Index) EdgesTo(ref *blobref.BlobRef, opts *search.EdgesToOpts) (edges [
}
for _, parentRef := range permanodeParents {
edges = append(edges, &search.Edge{
From: parentRef,
FromType: "permanode",
To: ref,
})
From: parentRef,
FromType: "permanode",
To: ref,
})
}
return edges, nil
}

BIN
pkg/index/indextest/testdata/dude.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -18,6 +18,7 @@ package indextest
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
@ -253,6 +254,30 @@ func Index(t *testing.T, initIdx func() *index.Index) {
t.Logf("add-attribute claim %q points to member permanode %q", memberRef, pnChild)
memberRefTime := id.lastTime()
// TODO(bradfitz): add EXIF tests here, once that stuff is ready.
if false {
for i := 1; i <= 8; i++ {
fileBase := fmt.Sprintf("f%d-exif.jpg", i)
fileName := filepath.Join(findGoPathPackage("camlistore.org"), "pkg", "images", "testdata", fileBase)
contents, err := ioutil.ReadFile(fileName)
if err != nil {
t.Fatal(err)
}
id.UploadFile(fileBase, string(contents))
}
}
// Upload a basic image.
var jpegFileRef *blobref.BlobRef
{
fileName := filepath.Join(findGoPathPackage("camlistore.org"), "pkg", "index", "indextest", "testdata", "dude.jpg")
contents, err := ioutil.ReadFile(fileName)
if err != nil {
t.Fatal(err)
}
jpegFileRef, _ = id.UploadFile("dude.jpg", string(contents))
}
lastPermanodeMutation := id.lastTime()
id.dumpIndex(t)
@ -261,6 +286,11 @@ func Index(t *testing.T, initIdx func() *index.Index) {
t.Fatalf("%q = %q, want %q", key, g, e)
}
key = "imagesize|" + jpegFileRef.String()
if g, e := id.Get(key), "50|100"; g != e {
t.Errorf("JPEG dude.jpg key %q = %q; want %q", key, g, e)
}
key = "have:" + pn.String()
pnSizeStr := id.Get(key)
if pnSizeStr == "" {
@ -519,8 +549,8 @@ func EdgesTo(t *testing.T, initIdx func() *index.Index) {
t.Fatalf("num edges = %d; want 1", len(edges))
}
wantEdge := &search.Edge{
From: pn1,
To: pn2,
From: pn1,
To: pn2,
FromType: "permanode",
}
if got, want := edges[0].String(), wantEdge.String(); got != want {

View File

@ -216,4 +216,16 @@ var (
{"name", typeStr}, // the name, if static.
},
}
// Width and height after any EXIF rotation.
keyImageSize = &keyType{
"imagesize",
[]part{
{"fileref", typeBlobRef}, // blobref of "file" schema blob
},
[]part{
{"width", typeStr},
{"height", typeStr},
},
}
)

View File

@ -21,7 +21,12 @@ import (
"crypto/sha1"
"errors"
"fmt"
"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"io"
"io/ioutil"
"log"
"strings"
@ -121,7 +126,34 @@ func (ix *Index) populateFile(blobRef *blobref.BlobRef, ss *schema.Superset, bm
return nil
}
mime, reader := magic.MimeTypeFromReader(fr)
size, err := io.Copy(sha1, reader)
var copyDest io.Writer = sha1
var withCopyErr func(error) // or nil
if strings.HasPrefix(mime, "image/") {
pr, pw := io.Pipe()
copyDest = io.MultiWriter(copyDest, pw)
confc := make(chan *image.Config, 1)
go func() {
conf, _, err := image.DecodeConfig(pr)
defer io.Copy(ioutil.Discard, pr)
if err == nil {
confc <- &conf
} else {
confc <- nil
}
}()
withCopyErr = func(err error) {
pw.CloseWithError(err)
if conf := <-confc; conf != nil {
bm.Set(keyImageSize.Key(blobRef), keyImageSize.Val(fmt.Sprint(conf.Width), fmt.Sprint(conf.Height)))
}
}
}
size, err := io.Copy(copyDest, reader)
if f := withCopyErr; f != nil {
f(err)
}
if err != nil {
// TODO: job scheduling system to retry this spaced
// out max n times. Right now our options are