-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
229 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# 图片元数据 | ||
|
||
用于从图片中提取元数据(时间、地点、相机等)信息用于展示。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package exif | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"io" | ||
"log" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
"github.com/PuerkitoBio/goquery" | ||
"github.com/movsb/taoblog/modules/utils" | ||
gold_utils "github.com/movsb/taoblog/service/modules/renderers/goldutils" | ||
) | ||
|
||
type Exif struct { | ||
fs gold_utils.WebFileSystem | ||
} | ||
|
||
func New(fs gold_utils.WebFileSystem) *Exif { | ||
return &Exif{ | ||
fs: fs, | ||
} | ||
} | ||
|
||
func (m *Exif) TransformHtml(doc *goquery.Document) error { | ||
doc.Find(`img`).Each(func(i int, s *goquery.Selection) { | ||
url := s.AttrOr(`src`, ``) | ||
if url == "" { | ||
return | ||
} | ||
fp, err := m.fs.OpenURL(url) | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
defer fp.Close() | ||
stat, err := fp.Stat() | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
info, err := extract(fp) | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
info.FileName = filepath.Base(stat.Name()) | ||
info.FileSize = utils.ByteCountIEC(stat.Size()) | ||
s.SetAttr(`data-metadata`, string(utils.DropLast1(json.Marshal(info.String())))) | ||
}) | ||
return nil | ||
} | ||
|
||
// TODO 直接传文件?否则文件大小只能读完才知道。 | ||
func extract(r io.Reader) (*Metadata, error) { | ||
cmd := exec.CommandContext(context.TODO(), `exiftool`, `-G`, `-s`, `-json`, `-`) | ||
cmd.Stdin = r | ||
output, err := cmd.Output() | ||
if err != nil { | ||
return nil, err | ||
} | ||
var md []*Metadata | ||
if err := json.Unmarshal(output, &md); err != nil { | ||
return nil, err | ||
} | ||
if len(md) <= 0 { | ||
return nil, nil | ||
} | ||
return md[0], nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package exif | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// exiftool -G -s -json test_data/exif.avif | ||
type Metadata struct { | ||
MimeType string `json:"File:MIMEType"` // 类型:image/avif | ||
FileName string `json:"File:FileName"` // 文件名字 | ||
FileSize string `json:"File:FileSize"` // 文件大小 | ||
ImageSize string `json:"Composite:ImageSize"` // 尺寸 | ||
Model string `json:"EXIF:Model"` // 设置型号 | ||
Make string `json:"EXIF:Make"` // 设置制造商 | ||
FNumber float32 `json:"EXIF:FNumber"` // 光圈数 | ||
FocalLength string `json:"EXIF:FocalLength"` // 焦距 | ||
ExposureTime string `json:"EXIF:ExposureTime"` // 曝光时间 | ||
GPSPosition string `json:"Composite:GPSPosition"` // 坐标 | ||
GPSAltitude string `json:"Composite:GPSAltitude"` // 海拔 | ||
CreateDate string `json:"EXIF:CreateDate"` // 创建日期/时间 | ||
OffsetTime string `json:"EXIF:OffsetTime"` // 时区 | ||
} | ||
|
||
func (m *Metadata) CreationDateTime() time.Time { | ||
if m.CreateDate == "" { | ||
return time.Time{} | ||
} | ||
timeZone := time.Now() | ||
if m.OffsetTime != "" { | ||
t, err := time.Parse(`-07:00`, m.OffsetTime) | ||
if err != nil { | ||
log.Println(`failed to parse timezone for exif:`, m.OffsetTime) | ||
return time.Time{} | ||
} | ||
timeZone = t | ||
} | ||
layout := `2006:01:02 15:04:05` | ||
t, err := time.ParseInLocation(layout, m.CreateDate, timeZone.Location()) | ||
if err != nil { | ||
log.Println(`failed to parse time:`, m.CreateDate) | ||
return time.Time{} | ||
} | ||
return t | ||
} | ||
|
||
func (m *Metadata) String() []string { | ||
var pairs []string | ||
|
||
add := func(value string, name string) { | ||
if value != "" { | ||
pairs = append(pairs, name, value) | ||
} | ||
} | ||
|
||
add(m.FileName, `名字`) | ||
add(m.FileSize, `大小`) | ||
add(m.ImageSize, `尺寸`) | ||
add(m.MimeType, `类型`) | ||
|
||
if t := m.CreationDateTime(); !t.IsZero() { | ||
f := t.Format(time.RFC3339) | ||
add(f, `时间`) | ||
} | ||
|
||
if m.Make != "" && m.Model != "" { | ||
add(m.Make+` / `+m.Model, `设备`) | ||
} | ||
|
||
lenInfo := []string{} | ||
if m.FNumber > 0 { | ||
lenInfo = append(lenInfo, fmt.Sprintf(`f/%v`, m.FNumber)) | ||
} | ||
if m.FocalLength != "" { | ||
lenInfo = append(lenInfo, m.FocalLength) | ||
} | ||
if m.ExposureTime != "" { | ||
lenInfo = append(lenInfo, m.ExposureTime) | ||
} | ||
add(strings.Join(lenInfo, `, `), `镜头`) | ||
|
||
add(m.GPSPosition, `位置`) | ||
add(m.GPSAltitude, `海拔`) | ||
|
||
return pairs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# README | ||
|
||
exif.avif 中的元数据是从 DJI_0759.JPG 里面通过 `exiftool -tagsFromFile DJI_0759.JPG exif.avif` 拷贝得到的。 |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters