strip_metadata.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package processing
  2. import (
  3. "bytes"
  4. "github.com/trimmer-io/go-xmp/xmp"
  5. "github.com/imgproxy/imgproxy/v3/imagedata"
  6. "github.com/imgproxy/imgproxy/v3/imagemeta/iptc"
  7. "github.com/imgproxy/imgproxy/v3/imagemeta/photoshop"
  8. "github.com/imgproxy/imgproxy/v3/options"
  9. "github.com/imgproxy/imgproxy/v3/vips"
  10. )
  11. func stripPS3(img *vips.Image) []byte {
  12. ps3Data, err := img.GetBlob("iptc-data")
  13. if err != nil || len(ps3Data) == 0 {
  14. return nil
  15. }
  16. ps3Map := make(photoshop.PhotoshopMap)
  17. photoshop.Parse(ps3Data, ps3Map)
  18. iptcData, found := ps3Map[photoshop.IptcKey]
  19. if !found {
  20. return nil
  21. }
  22. iptcMap := make(iptc.IptcMap)
  23. err = iptc.Parse(iptcData, iptcMap)
  24. if err != nil {
  25. return nil
  26. }
  27. for key := range iptcMap {
  28. if key.RecordID == 2 && key.TagID != 80 && key.TagID != 110 && key.TagID != 116 {
  29. delete(iptcMap, key)
  30. }
  31. }
  32. if len(iptcMap) == 0 {
  33. return nil
  34. }
  35. ps3Map = photoshop.PhotoshopMap{
  36. photoshop.IptcKey: iptcMap.Dump(),
  37. }
  38. return ps3Map.Dump()
  39. }
  40. func stripXMP(img *vips.Image) []byte {
  41. xmpData, err := img.GetBlob("xmp-data")
  42. if err != nil || len(xmpData) == 0 {
  43. return nil
  44. }
  45. xmpDoc, err := xmp.Read(bytes.NewReader(xmpData))
  46. if err != nil {
  47. return nil
  48. }
  49. namespaces := xmpDoc.Namespaces()
  50. filteredNs := namespaces[:0]
  51. for _, ns := range namespaces {
  52. if ns.Name == "dc" || ns.Name == "xmpRights" || ns.Name == "cc" {
  53. filteredNs = append(filteredNs, ns)
  54. }
  55. }
  56. xmpDoc.FilterNamespaces(filteredNs)
  57. nodes := xmpDoc.Nodes()
  58. for _, n := range nodes {
  59. if n.Name() == "dc" {
  60. filteredNodes := n.Nodes[:0]
  61. for _, nn := range n.Nodes {
  62. name := nn.Name()
  63. if name == "rights" || name == "contributor" || name == "creator" || name == "publisher" {
  64. filteredNodes = append(filteredNodes, nn)
  65. }
  66. }
  67. n.Nodes = filteredNodes
  68. filteredAttrs := n.Attr[:0]
  69. for _, a := range n.Attr {
  70. name := a.Name.Local
  71. if name == "dc:rights" || name == "dc:contributor" || name == "dc:creator" || name == "dc:publisher" {
  72. filteredAttrs = append(filteredAttrs, a)
  73. }
  74. }
  75. n.Attr = filteredAttrs
  76. }
  77. }
  78. if len(xmpDoc.Nodes()) == 0 {
  79. return nil
  80. }
  81. xmpData, err = xmp.Marshal(xmpDoc)
  82. if err != nil {
  83. return nil
  84. }
  85. return xmpData
  86. }
  87. func stripMetadata(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error {
  88. if !po.StripMetadata {
  89. return nil
  90. }
  91. var ps3Data, xmpData []byte
  92. if po.KeepCopyright {
  93. ps3Data = stripPS3(img)
  94. xmpData = stripXMP(img)
  95. }
  96. if err := img.Strip(po.KeepCopyright); err != nil {
  97. return err
  98. }
  99. if po.KeepCopyright {
  100. if len(ps3Data) > 0 {
  101. img.SetBlob("iptc-data", ps3Data)
  102. }
  103. if len(xmpData) > 0 {
  104. img.SetBlob("xmp-data", xmpData)
  105. }
  106. }
  107. return nil
  108. }