Пример #1
0
func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
	// this needs to be commented out when regenerating regress expected vals
	if v := regressExpected[w.picName][field]; v != tag.String() {
		w.t.Errorf("pic %v:  expected '%v' got '%v'", w.picName, v, tag.String())
	}
	return nil
}
Пример #2
0
func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
	// this needs to be commented out when regenerating regress expected vals
	pic := regressExpected[w.picName]
	if pic == nil {
		w.t.Errorf("   regression data not found")
		return nil
	}

	exp, ok := pic[field]
	if !ok {
		w.t.Errorf("   regression data does not have field %v", field)
		return nil
	}

	s := tag.String()
	if tag.Count == 1 && s != "\"\"" {
		s = fmt.Sprintf("[%s]", s)
	}
	got := tag.String()

	if exp != got {
		fmt.Println("s: ", s)
		fmt.Printf("len(s)=%v\n", len(s))
		w.t.Errorf("   field %v bad tag: expected '%s', got '%s'", field, exp, got)
	}
	return nil
}
Пример #3
0
func (w *regresswalk) Walk(name FieldName, tag *tiff.Tag) error {
	if strings.HasPrefix(string(name), UnknownPrefix) {
		fmt.Fprintf(w.wr, "\t\t\"%v\": `%v`,\n", name, tag.String())
	} else {
		fmt.Fprintf(w.wr, "\t\t%v: `%v`,\n", name, tag.String())
	}
	return nil
}
Пример #4
0
func tagFormatString(tag *tiff.Tag) string {
	switch tag.Format() {
	case tiff.IntVal:
		return "int"
	case tiff.RatVal:
		return "rat"
	case tiff.FloatVal:
		return "float"
	case tiff.StringVal:
		return "string"
	}
	return ""
}
Пример #5
0
func parse3Rat2(tag *tiff.Tag) ([3]float64, error) {
	v := [3]float64{}
	for i := range v {
		num, den, err := tag.Rat2(i)
		if err != nil {
			return v, err
		}
		v[i] = ratFloat(num, den)
		if tag.Count < uint32(i+2) {
			break
		}
	}
	return v, nil
}
Пример #6
0
// Get values written as big.Rat returns the result in a more sensible formatting.
func FormatGPS(t *tiff.Tag) float32 {

	Dec := make([]float32, 3)
	for count := 0; count < 3; count++ {

		Numer, Denom, _ := t.Rat2(count)
		// Add error checking somewhere?

		Dec[count] = float32(Numer) / float32(Denom)
	}

	DecGPS := float32(Dec[0]) + float32(Dec[1]/60) + float32(Dec[2]/3600)
	return DecGPS
	//DecGPS := Hours + Minutes/float32(60) + Seconds/float32(3600)
}
Пример #7
0
// Walk implements exif.Walker interface and initializes the Photograph
// from the EXIF data.
func (p *Photograph) Walk(field exif.FieldName, tag *tiff.Tag) error {
	logging.Log.Info("%v: %v", field, tag)
	p.ExifMap[field] = tag
	if "DateTime" == field {
		const timeFormat = "2006:01:02 15:04:05"
		s, err := tag.StringVal()
		if err != nil {
			return err
		}
		p.Time, err = time.Parse(timeFormat, s)
		if err != nil {
			return err
		}
	}
	return nil
}
Пример #8
0
func tagDegrees(tag *tiff.Tag) (float64, error) {
	switch tag.Format() {
	case tiff.RatVal:
		// The usual case, according to the Exif spec
		// (http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf,
		// sec 4.6.6, p. 52 et seq.)
		v, err := parse3Rat2(tag)
		if err != nil {
			return 0.0, err
		}
		return v[0] + v[1]/60 + v[2]/3600.0, nil
	case tiff.StringVal:
		// Encountered this weird case with a panorama picture taken with a HTC phone
		s, err := tag.StringVal()
		if err != nil {
			return 0.0, err
		}
		return parseTagDegreesString(s)
	default:
		// don't know how to parse value, give up
		return 0.0, fmt.Errorf("Malformed EXIF Tag Degrees")
	}
}
Пример #9
0
func storeImage(rw http.ResponseWriter, req *http.Request) {
	// Appengine
	var c appengine.Context
	// Google Cloud Storage authentication
	var cc gcscontext.Context
	// Google Cloud Storage bucket name
	var bucketName string = ""
	// Google Cloud Storage client
	var client *storage.Client
	// Google Cloud Storage bucket
	var bucketHandle *storage.BucketHandle
	// User uploaded image file name
	var fileName string = uuid.New()
	// Transform user uploaded image to a thumbnail file name
	var fileNameThumbnail string = uuid.New()
	// User uploaded image file type
	var contentType string = ""
	// User uploaded image file raw data
	var b []byte
	// Google Cloud Storage file writer
	var wc *storage.Writer = nil
	// Error
	var err error = nil
	// Result, 0: success, 1: failed
	var r int = http.StatusCreated

	// Set response in the end
	defer func() {
		// Return status. WriteHeader() must be called before call to Write
		if r == http.StatusCreated {
			// Changing the header after a call to WriteHeader (or Write) has no effect.
			// rw.Header().Set("Location", req.URL.String()+"/"+cKey.Encode())
			rw.Header().Set("Location", "http://"+bucketName+".storage.googleapis.com/"+fileName)
			rw.Header().Set("X-Thumbnail", "http://"+bucketName+".storage.googleapis.com/"+fileNameThumbnail)
			rw.WriteHeader(r)
		} else {
			http.Error(rw, http.StatusText(r), r)
		}
	}()

	// To log information in Google APP Engine console
	c = appengine.NewContext(req)

	// Get data from body
	b, err = ioutil.ReadAll(req.Body)
	if err != nil {
		c.Errorf("%s in reading body", err)
		r = http.StatusInternalServerError
		return
	}
	c.Infof("Body length %d bytes, read %d bytes", req.ContentLength, len(b))

	// Determine filename extension from content type
	contentType = req.Header["Content-Type"][0]
	switch contentType {
	case "image/jpeg":
		fileName += ".jpg"
		fileNameThumbnail += ".jpg"
	default:
		c.Errorf("Unknown or unsupported content type '%s'. Valid: image/jpeg", contentType)
		r = http.StatusBadRequest
		return
	}
	c.Infof("Content type %s is received, %s is detected.", contentType, http.DetectContentType(b))

	// Prepare Google Cloud Storage authentication
	cc = gcsappengine.NewContext(req)
	if client, err = storage.NewClient(cc); err != nil {
		c.Errorf("%s in initializing a GCS client", err)
		r = http.StatusInternalServerError
		return
	}
	defer client.Close()

	// Get default bucket
	if bucketName, err = gcsfile.DefaultBucketName(cc); err != nil {
		c.Errorf("%s in getting default GCS bucket name", err)
		r = http.StatusInternalServerError
		return
	}
	bucketHandle = client.Bucket(bucketName)
	c.Infof("APP Engine Version: %s", gcsappengine.VersionID(cc))
	c.Infof("Using bucket name: %s", bucketName)

	// Change default object ACLs
	if err = bucketHandle.DefaultObjectACL().Set(cc, storage.AllUsers, storage.RoleReader); err != nil {
		c.Errorf("%v in saving default object ACL rule for bucket %q", err, bucketName)
		r = http.StatusInternalServerError
		return
	}

	// Store rotated image in Google Cloud Storage
	var in *bytes.Reader = bytes.NewReader(b)
	var x *exif.Exif = nil
	var orientation *tiff.Tag = nil
	var beforeImage image.Image
	var afterImage *image.NRGBA = nil

	// Read EXIF
	if _, err = in.Seek(0, 0); err != nil {
		c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err)
		return
	}
	if x, err = exif.Decode(in); err != nil {
		c.Errorf("%s in decoding JPEG image", err)
		return
	}

	// Get Orientation
	if orientation, err = x.Get(exif.Orientation); err != nil {
		c.Warningf("%s in getting orientation from EXIF", err)
		return
	}
	c.Debugf("Orientation %s", orientation.String())

	// Open image
	if _, err = in.Seek(0, 0); err != nil {
		c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err)
		return
	}
	if beforeImage, err = imaging.Decode(in); err != nil {
		c.Errorf("%s in opening image %s", err)
		return
	}

	switch orientation.String() {
	case "1":
		afterImage = beforeImage.(*image.NRGBA)
	case "2":
		afterImage = imaging.FlipH(beforeImage)
	case "3":
		afterImage = imaging.Rotate180(beforeImage)
	case "4":
		afterImage = imaging.FlipV(beforeImage)
	case "5":
		afterImage = imaging.Transverse(beforeImage)
	case "6":
		afterImage = imaging.Rotate270(beforeImage)
	case "7":
		afterImage = imaging.Transpose(beforeImage)
	case "8":
		afterImage = imaging.Rotate90(beforeImage)
	}

	// Save rotated image
	wc = bucketHandle.Object(fileName).NewWriter(cc)
	wc.ContentType = contentType
	if err = imaging.Encode(wc, afterImage, imaging.JPEG); err != nil {
		c.Errorf("%s in saving rotated image", err)
		return
	}
	if err = wc.Close(); err != nil {
		c.Errorf("CreateFile: unable to close bucket %q, file %q: %v", bucketName, fileName, err)
		r = 1
		return
	}
	wc = nil

	// Make thumbnail
	if afterImage.Rect.Dx() > afterImage.Rect.Dy() {
		afterImage = imaging.Resize(afterImage, 1920, 0, imaging.Lanczos)
	} else {
		afterImage = imaging.Resize(afterImage, 0, 1920, imaging.Lanczos)
	}

	// Save thumbnail
	wc = bucketHandle.Object(fileNameThumbnail).NewWriter(cc)
	wc.ContentType = contentType
	if imaging.Encode(wc, afterImage, imaging.JPEG); err != nil {
		c.Errorf("%s in saving image thumbnail", err)
		return
	}
	if err = wc.Close(); err != nil {
		c.Errorf("CreateFileThumbnail: unable to close bucket %q, file %q: %v", bucketName, fileNameThumbnail, err)
		r = 1
		return
	}

	c.Infof("/%v/%v, /%v/%v created", bucketName, fileName, bucketName, fileNameThumbnail)
}
Пример #10
0
func (_ Walker) Walk(name exif.FieldName, tag *tiff.Tag) error {
	data, _ := tag.MarshalJSON()
	fmt.Printf("    %v: %v\n", name, string(data))
	return nil
}
Пример #11
0
func (tw *tagsWalker) Walk(name exif.FieldName, tag *tiff.Tag) error {
	tw.v[string(name)] = tag.String()
	return nil
}
Пример #12
0
// Implements the Walk function to be a Walker
func (ew *ExifHandler) Walk(name exif.FieldName, tag *tiff.Tag) error {
	ew.tags[string(name)] = tag.String()
	return nil
}