github.com/boki/go-xmp@v1.0.1/models/tiff/model.go (about) 1 // Copyright (c) 2017-2018 Alexander Eichhorn 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 // Package tiff implements metadata for TIFF and JPEG image files as defined 16 // by XMP Specification Part 1. 17 package tiff 18 19 import ( 20 "fmt" 21 "strings" 22 23 "trimmer.io/go-xmp/models/dc" 24 "trimmer.io/go-xmp/models/xmp_base" 25 "trimmer.io/go-xmp/xmp" 26 ) 27 28 var ( 29 NsTiff = xmp.NewNamespace("tiff", "http://ns.adobe.com/tiff/1.0/", NewModel) 30 ) 31 32 func init() { 33 xmp.Register(NsTiff, xmp.ImageMetadata) 34 } 35 36 func NewModel(name string) xmp.Model { 37 return &TiffInfo{} 38 } 39 40 func MakeModel(d *xmp.Document) (*TiffInfo, error) { 41 m, err := d.MakeModel(NsTiff) 42 if err != nil { 43 return nil, err 44 } 45 x, _ := m.(*TiffInfo) 46 return x, nil 47 } 48 49 func FindModel(d *xmp.Document) *TiffInfo { 50 if m := d.FindModel(NsTiff); m != nil { 51 return m.(*TiffInfo) 52 } 53 return nil 54 } 55 56 type TiffInfo struct { 57 Artist xmp.StringList `xmp:"dc:creator"` 58 BitsPerSample xmp.IntList `xmp:"tiff:BitsPerSample"` // 3 components 59 Compression CompressionType `xmp:"tiff:Compression"` 60 DateTime xmp.Date `xmp:"xmp:ModifyDate"` 61 ImageLength int `xmp:"tiff:ImageLength"` 62 ImageWidth int `xmp:"tiff:ImageWidth"` // A. Tags relating to image data structure 63 Make string `xmp:"tiff:Make"` 64 Model string `xmp:"tiff:Model"` 65 Software string `xmp:"xmp:CreatorTool"` 66 ImageDescription xmp.AltString `xmp:"dc:description"` 67 Copyright xmp.AltString `xmp:"dc:rights"` 68 Orientation OrientationType `xmp:"tiff:Orientation"` 69 PhotometricInterpretation ColorModel `xmp:"tiff:PhotometricInterpretation"` 70 PlanarConfiguration PlanarType `xmp:"tiff:PlanarConfiguration"` 71 PrimaryChromaticities xmp.RationalArray `xmp:"tiff:PrimaryChromaticities"` // 6 components 72 ReferenceBlackWhite xmp.RationalArray `xmp:"tiff:ReferenceBlackWhite"` // 6 components 73 ResolutionUnit ResolutionUnit `xmp:"tiff:ResolutionUnit"` // 2 = inches, 3 = centimeters 74 SamplesPerPixel int `xmp:"tiff:SamplesPerPixel"` 75 TransferFunction xmp.IntList `xmp:"tiff:TransferFunction"` // C. Tags relating to image data characteristics 76 WhitePoint xmp.RationalArray `xmp:"tiff:WhitePoint"` 77 XResolution xmp.Rational `xmp:"tiff:XResolution"` 78 YCbCrCoefficients xmp.RationalArray `xmp:"tiff:YCbCrCoefficients"` // 3 components 79 YCbCrPositioning YCbCrPosition `xmp:"tiff:YCbCrPositioning"` 80 YCbCrSubSampling YCbCrSubSampling `xmp:"tiff:YCbCrSubSampling"` 81 YResolution xmp.Rational `xmp:"tiff:YResolution"` 82 NativeDigest string `xmp:"tiff:NativeDigest,omit"` // ignore according to spec 83 84 // be resilient to broken writers: read tags erroneously 85 // mapped to the wrong XMP properties, but do not output them 86 // when writing ourselves 87 X_Artist string `xmp:"tiff:Artist,omit"` 88 X_DateTime xmp.Date `xmp:"tiff:DateTime,omit"` 89 X_Software string `xmp:"tiff:Software,omit"` 90 X_ImageDescription xmp.AltString `xmp:"tiff:ImageDescription,omit"` 91 X_Copyright xmp.AltString `xmp:"tiff:Copyright,omit"` 92 } 93 94 func (x TiffInfo) Can(nsName string) bool { 95 return NsTiff.GetName() == nsName 96 } 97 98 func (x TiffInfo) Namespaces() xmp.NamespaceList { 99 return []*xmp.Namespace{NsTiff} 100 } 101 102 func (x *TiffInfo) SyncModel(d *xmp.Document) error { 103 return nil 104 } 105 106 func (x *TiffInfo) SyncFromXMP(d *xmp.Document) error { 107 if m := dc.FindModel(d); m != nil { 108 x.Artist = m.Creator 109 x.ImageDescription = m.Description 110 x.Copyright = m.Rights 111 } 112 if m := xmpbase.FindModel(d); m != nil { 113 x.DateTime = m.ModifyDate 114 if m.CreatorTool != "" { 115 x.Software = m.CreatorTool.String() 116 } 117 } 118 return nil 119 } 120 121 // also remap X_* attributes to the correct standard positions, but don't overwrite 122 func (x TiffInfo) SyncToXMP(d *xmp.Document) error { 123 m, err := dc.MakeModel(d) 124 if err != nil { 125 return err 126 } 127 if len(m.Creator) == 0 && len(x.Artist) > 0 { 128 m.Creator = x.Artist 129 } 130 if len(m.Creator) == 0 && len(x.X_Artist) > 0 { 131 m.Creator = strings.Split(x.X_Artist, ",") 132 } 133 if len(m.Description) == 0 { 134 m.Description = x.ImageDescription 135 } 136 if len(m.Description) == 0 { 137 m.Description = x.X_ImageDescription 138 } 139 if len(m.Rights) == 0 { 140 m.Rights = x.Copyright 141 } 142 if len(m.Rights) == 0 { 143 m.Rights = x.X_Copyright 144 } 145 146 // XMP base 147 base, err := xmpbase.MakeModel(d) 148 if err != nil { 149 return err 150 } 151 if base.ModifyDate.IsZero() { 152 base.ModifyDate = x.DateTime 153 } 154 if base.ModifyDate.IsZero() { 155 base.ModifyDate = x.X_DateTime 156 } 157 if base.CreatorTool.IsZero() && x.Software != "" { 158 base.CreatorTool = xmp.AgentName(x.Software) 159 } 160 return nil 161 } 162 163 func (x *TiffInfo) CanTag(tag string) bool { 164 _, err := xmp.GetNativeField(x, tag) 165 return err == nil 166 } 167 168 func (x *TiffInfo) GetTag(tag string) (string, error) { 169 if v, err := xmp.GetNativeField(x, tag); err != nil { 170 return "", fmt.Errorf("%s: %v", NsTiff.GetName(), err) 171 } else { 172 return v, nil 173 } 174 } 175 176 func (x *TiffInfo) SetTag(tag, value string) error { 177 if err := xmp.SetNativeField(x, tag, value); err != nil { 178 return fmt.Errorf("%s: %v", NsTiff.GetName(), err) 179 } 180 return nil 181 }