Skip to content

Commit

Permalink
✨ Feat: support png
Browse files Browse the repository at this point in the history
  • Loading branch information
soxft committed Nov 5, 2024
1 parent d3eda83 commit 231f52a
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 19 deletions.
2 changes: 2 additions & 0 deletions fg/fg.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ var Mode string
var Path string
var DateTime string
var DateTpl = "2006-01-02 15.04.05"
var Force bool

// Parse 解析命令行参数
func Parse() {
flag.StringVar(&Mode, "m", "qumagie", "操作模式: qumagie (QuMagie 备份照片处理), dir (指定文件夹批量修改 EXIF时间), dirDate (按照上级文件夹名称修改 EXIF 时间)")
flag.StringVar(&Path, "p", "", "文件夹路径")
flag.StringVar(&DateTime, "datetime", "", "日期时间")
flag.StringVar(&DateTpl, "tpl", "2006-01-02 15.04.05", "日期时间模板, 默认为 '2006-01-02 15.04.05' 请参照 Golang 时间 layout 设置, 不适用于 QuMagie 模式")
flag.BoolVar(&Force, "f", false, "强制执行, 不会检查是否已经有日期")

flag.Parse()
}
3 changes: 2 additions & 1 deletion qumagie/qumagie.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"photo_exif_do/fg"
"photo_exif_do/x_exif"
"regexp"
"time"
Expand Down Expand Up @@ -59,7 +60,7 @@ func Run(path string) {
continue
}

if err := x_exif.SetDate(filePath, t, true); err == nil {
if err := x_exif.SetDate(filePath, t, !fg.Force); err == nil {
log.Printf("[SUCC](%d) %s -> %s\n", counter, filename, t.Format("2006-01-02 15.04.05"))
x_exif.RemoveEditStr(filePath)
} else if errors.Is(err, x_exif.ErrAlreadyHasDate) || errors.Is(err, x_exif.ErrMediaTypeNotSupport) {
Expand Down
19 changes: 1 addition & 18 deletions x_exif/exif.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,6 @@ func ReadExif(path string) (string, error) {
return "", errors.New("mo DateTime from exif")
}

// setExifTag 设置exif标签
func setExifTag(rootIB *exif.IfdBuilder, ifdPath, tagName, tagValue string) error {
// fmt.Printf("setTag(): ifdPath: %v, tagName: %v, tagValue: %v",
// ifdPath, tagName, tagValue)

ifdIb, err := exif.GetOrCreateIbFromRootIb(rootIB, ifdPath)
if err != nil {
return fmt.Errorf("failed to get or create IB: %v", err)
}

if err := ifdIb.SetStandardWithName(tagName, tagValue); err != nil {
return fmt.Errorf("failed to set DateTime tag: %v", err)
}

return nil
}

// SetDate 为文件设置日期 如果已经存在则跳过
func SetDate(filePath string, t time.Time, skip bool) error {
// 检测是否已经有日期
Expand All @@ -62,7 +45,7 @@ func SetDate(filePath string, t time.Time, skip bool) error {
case ".jpg", ".jpeg":
return setJpgExif(filePath, t)
case ".png":
break
return setPngDate(filePath, t)
default:
}

Expand Down
17 changes: 17 additions & 0 deletions x_exif/jpg.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@ import (
"time"
)

// setExifTag 设置exif标签
func setExifTag(rootIB *exif.IfdBuilder, ifdPath, tagName, tagValue string) error {
// fmt.Printf("setTag(): ifdPath: %v, tagName: %v, tagValue: %v",
// ifdPath, tagName, tagValue)

ifdIb, err := exif.GetOrCreateIbFromRootIb(rootIB, ifdPath)
if err != nil {
return fmt.Errorf("failed to get or create IB: %v", err)
}

if err := ifdIb.SetStandardWithName(tagName, tagValue); err != nil {
return fmt.Errorf("failed to set DateTime tag: %v", err)
}

return nil
}

func setJpgExif(filePath string, t time.Time) error {

parser := jpeg.NewJpegMediaParser()
Expand Down
100 changes: 100 additions & 0 deletions x_exif/png.go
Original file line number Diff line number Diff line change
@@ -1 +1,101 @@
package x_exif

import (
"bytes"
"fmt"
"github.com/dsoprea/go-exif/v3"
exifcommon "github.com/dsoprea/go-exif/v3/common"
log "github.com/dsoprea/go-logging"
png "github.com/dsoprea/go-png-image-structure/v2"
riimage "github.com/dsoprea/go-utility/v2/image"
"os"
"time"
)

func setPngDate(filePath string, t time.Time) error {
praser := png.NewPngMediaParser()
intfc, err := praser.ParseFile(filePath)
if err != nil {
return fmt.Errorf("failed to parse PNG file: %v", err)
}

rootIb, err := pngConstructExifBuilder(intfc)
if err != nil {
im, err := exifcommon.NewIfdMappingWithStandard()
if err != nil {
return fmt.Errorf("failed to create new IFD mapping with standard tags: %v", err)
}
ti := exif.NewTagIndex()
if err := exif.LoadStandardTags(ti); err != nil {
return fmt.Errorf("failed to load standard tags: %v", err)
}

rootIb = exif.NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity,
exifcommon.EncodeDefaultByteOrder)
}

ts := exifcommon.ExifFullTimestampString(t)

// Set DateTime
if err := setExifTag(rootIb, "IFD0", "DateTime", ts); err != nil {
return fmt.Errorf("failed to set tag %v: %v", "DateTime", err)
}

// Set DateTimeOriginal
if err := setExifTag(rootIb, "IFD/Exif", "DateTimeOriginal", ts); err != nil {
return fmt.Errorf("failed to set tag %v: %v", "DateTimeOriginal", err)
}

cs := intfc.(*png.ChunkSlice)

err = cs.SetExif(rootIb)
log.PanicIf(err)

b := new(bytes.Buffer)

// Write to a `bytes.Buffer`.
err = cs.WriteTo(b)

// Save the file
if err := os.WriteFile(filePath, b.Bytes(), 0644); err != nil {
return fmt.Errorf("failed to write JPEG file: %v", err)
}

return nil
}

func pngConstructExifBuilder(intfc riimage.MediaContext) (rootIb *exif.IfdBuilder, err error) {

defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()

rootIfd, _, err := intfc.Exif()
if log.Is(err, exif.ErrNoExif) == true {
// No EXIF. Just create a boilerplate builder.

im := exifcommon.NewIfdMapping()

err := exifcommon.LoadStandardIfds(im)
log.PanicIf(err)

ti := exif.NewTagIndex()

rootIb :=
exif.NewIfdBuilder(
im,
ti,
exifcommon.IfdStandardIfdIdentity,
exifcommon.EncodeDefaultByteOrder)

return rootIb, nil
} else if err != nil {
log.Panic(err)
}

rootIb = exif.NewIfdBuilderFromExistingChain(rootIfd)

return rootIb, nil
}

0 comments on commit 231f52a

Please sign in to comment.