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  }