@@ -36,6 +36,16 @@ const (
3636 FormControlScrollBar
3737)
3838
39+ // HeaderFooterImagePositionType is the type of header and footer image position.
40+ type HeaderFooterImagePositionType byte
41+
42+ // Worksheet header and footer image position types enumeration.
43+ const (
44+ HeaderFooterImagePositionLeft HeaderFooterImagePositionType = iota
45+ HeaderFooterImagePositionCenter
46+ HeaderFooterImagePositionRight
47+ )
48+
3949// GetComments retrieves all comments in a worksheet by given worksheet name.
4050func (f * File ) GetComments (sheet string ) ([]Comment , error ) {
4151 var comments []Comment
@@ -519,6 +529,7 @@ func (f *File) addVMLObject(opts vmlOptions) error {
519529 }
520530 vmlID = f .countVMLDrawing () + 1
521531 }
532+ sheetID := f .getSheetID (opts .sheet )
522533 drawingVML := "xl/drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
523534 sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
524535 sheetXMLPath , _ := f .getSheetXMLPath (opts .sheet )
@@ -534,7 +545,7 @@ func (f *File) addVMLObject(opts vmlOptions) error {
534545 f .addSheetNameSpace (opts .sheet , SourceRelationship )
535546 f .addSheetLegacyDrawing (opts .sheet , rID )
536547 }
537- if err = f .addDrawingVML (vmlID , drawingVML , prepareFormCtrlOptions (& opts )); err != nil {
548+ if err = f .addDrawingVML (sheetID , drawingVML , prepareFormCtrlOptions (& opts )); err != nil {
538549 return err
539550 }
540551 if ! opts .formCtrl {
@@ -823,7 +834,7 @@ func (f *File) addFormCtrlShape(preset formCtrlPreset, col, row int, anchor stri
823834// anchor value is a comma-separated list of data written out as: LeftColumn,
824835// LeftOffset, TopRow, TopOffset, RightColumn, RightOffset, BottomRow,
825836// BottomOffset.
826- func (f * File ) addDrawingVML (dataID int , drawingVML string , opts * vmlOptions ) error {
837+ func (f * File ) addDrawingVML (sheetID int , drawingVML string , opts * vmlOptions ) error {
827838 col , row , err := CellNameToCoordinates (opts .FormControl .Cell )
828839 if err != nil {
829840 return err
@@ -843,7 +854,7 @@ func (f *File) addDrawingVML(dataID int, drawingVML string, opts *vmlOptions) er
843854 XMLNSx : "urn:schemas-microsoft-com:office:excel" ,
844855 XMLNSmv : "http://macVmlSchemaUri" ,
845856 ShapeLayout : & xlsxShapeLayout {
846- Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : dataID },
857+ Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : sheetID },
847858 },
848859 ShapeType : & xlsxShapeType {
849860 ID : fmt .Sprintf ("_x0000_t%d" , vmlID ),
@@ -1071,79 +1082,138 @@ func extractVMLFont(font []decodeVMLFont) []RichTextRun {
10711082 return runs
10721083}
10731084
1074- // SetLegacyDrawingHF provides a mechanism to set the graphics that
1075- // can be referenced in the Header/Footer defitions via &G.
1085+ // AddHeaderFooterImage provides a mechanism to set the graphics that can be
1086+ // referenced in the header and footer definitions via &G, file base name,
1087+ // extension name and file bytes, supported image types: EMF, EMZ, GIF, JPEG,
1088+ // JPG, PNG, SVG, TIF, TIFF, WMF, and WMZ.
10761089//
10771090// The extension should be provided with a "." in front, e.g. ".png".
1078- // The width/height should have units in them, e.g. "100pt".
1079- func (f * File ) SetLegacyDrawingHF (sheet string , g * HeaderFooterGraphics ) error {
1091+ // The width and height should have units in them, e.g. "100pt".
1092+ func (f * File ) AddHeaderFooterImage (sheet string , opts * HeaderFooterImageOptions ) error {
1093+ ws , err := f .workSheetReader (sheet )
1094+ if err != nil {
1095+ return err
1096+ }
1097+ ext , ok := supportedImageTypes [strings .ToLower (opts .Extension )]
1098+ if ! ok {
1099+ return ErrImgExt
1100+ }
1101+ sheetID := f .getSheetID (sheet )
10801102 vmlID := f .countVMLDrawing () + 1
1103+ drawingVML := "xl/drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
1104+ sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
1105+ sheetXMLPath , _ := f .getSheetXMLPath (sheet )
1106+ sheetRels := "xl/worksheets/_rels/" + strings .TrimPrefix (sheetXMLPath , "xl/worksheets/" ) + ".rels"
1107+ if ws .LegacyDrawingHF != nil {
1108+ // The worksheet already has a VML relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
1109+ sheetRelationshipsDrawingVML = f .getSheetRelationshipsTargetByID (sheet , ws .LegacyDrawingHF .RID )
1110+ vmlID , _ = strconv .Atoi (strings .TrimSuffix (strings .TrimPrefix (sheetRelationshipsDrawingVML , "../drawings/vmlDrawing" ), ".vml" ))
1111+ drawingVML = strings .ReplaceAll (sheetRelationshipsDrawingVML , ".." , "xl" )
1112+ } else {
1113+ // Add first VML drawing for given sheet.
1114+ rID := f .addRels (sheetRels , SourceRelationshipDrawingVML , sheetRelationshipsDrawingVML , "" )
1115+ f .addSheetNameSpace (sheet , SourceRelationship )
1116+ f .addSheetLegacyDrawingHF (sheet , rID )
1117+ }
10811118
1082- vml := & vmlDrawing {
1083- XMLNSv : "urn:schemas-microsoft-com:vml" ,
1084- XMLNSo : "urn:schemas-microsoft-com:office:office" ,
1085- XMLNSx : "urn:schemas-microsoft-com:office:excel" ,
1086- ShapeLayout : & xlsxShapeLayout {
1087- Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : vmlID },
1088- },
1089- ShapeType : & xlsxShapeType {
1090- ID : "_x0000_t75" ,
1091- CoordSize : "21600,21600" ,
1092- Spt : 75 ,
1093- PreferRelative : "t" ,
1094- Path : "m@4@5l@4@11@9@11@9@5xe" ,
1095- Filled : "f" ,
1096- Stroked : "f" ,
1097- Stroke : & xlsxStroke {JoinStyle : "miter" },
1098- VFormulas : & vFormulas {
1099- Formulas : []vFormula {
1100- {Equation : "if lineDrawn pixelLineWidth 0" },
1101- {Equation : "sum @0 1 0" },
1102- {Equation : "sum 0 0 @1" },
1103- {Equation : "prod @2 1 2" },
1104- {Equation : "prod @3 21600 pixelWidth" },
1105- {Equation : "prod @3 21600 pixelHeight" },
1106- {Equation : "sum @0 0 1" },
1107- {Equation : "prod @6 1 2" },
1108- {Equation : "prod @7 21600 pixelWidth" },
1109- {Equation : "sum @8 21600 0" },
1110- {Equation : "prod @7 21600 pixelHeight" },
1111- {Equation : "sum @10 21600 0" },
1119+ shapeID := map [HeaderFooterImagePositionType ]string {
1120+ HeaderFooterImagePositionLeft : "L" ,
1121+ HeaderFooterImagePositionCenter : "C" ,
1122+ HeaderFooterImagePositionRight : "R" ,
1123+ }[opts .Position ] +
1124+ map [bool ]string {false : "H" , true : "F" }[opts .IsFooter ] +
1125+ map [bool ]string {false : "" , true : "FIRST" }[opts .FirstPage ]
1126+ vml := f .VMLDrawing [drawingVML ]
1127+ if vml == nil {
1128+ vml = & vmlDrawing {
1129+ XMLNSv : "urn:schemas-microsoft-com:vml" ,
1130+ XMLNSo : "urn:schemas-microsoft-com:office:office" ,
1131+ XMLNSx : "urn:schemas-microsoft-com:office:excel" ,
1132+ ShapeLayout : & xlsxShapeLayout {
1133+ Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : sheetID },
1134+ },
1135+ ShapeType : & xlsxShapeType {
1136+ ID : "_x0000_t75" ,
1137+ CoordSize : "21600,21600" ,
1138+ Spt : 75 ,
1139+ PreferRelative : "t" ,
1140+ Path : "m@4@5l@4@11@9@11@9@5xe" ,
1141+ Filled : "f" ,
1142+ Stroked : "f" ,
1143+ Stroke : & xlsxStroke {JoinStyle : "miter" },
1144+ VFormulas : & vFormulas {
1145+ Formulas : []vFormula {
1146+ {Equation : "if lineDrawn pixelLineWidth 0" },
1147+ {Equation : "sum @0 1 0" },
1148+ {Equation : "sum 0 0 @1" },
1149+ {Equation : "prod @2 1 2" },
1150+ {Equation : "prod @3 21600 pixelWidth" },
1151+ {Equation : "prod @3 21600 pixelHeight" },
1152+ {Equation : "sum @0 0 1" },
1153+ {Equation : "prod @6 1 2" },
1154+ {Equation : "prod @7 21600 pixelWidth" },
1155+ {Equation : "sum @8 21600 0" },
1156+ {Equation : "prod @7 21600 pixelHeight" },
1157+ {Equation : "sum @10 21600 0" },
1158+ },
11121159 },
1160+ VPath : & vPath {ExtrusionOK : "f" , GradientShapeOK : "t" , ConnectType : "rect" },
1161+ Lock : & oLock {Ext : "edit" , AspectRatio : "t" },
11131162 },
1114- VPath : & vPath {ExtrusionOK : "f" , GradientShapeOK : "t" , ConnectType : "rect" },
1115- Lock : & oLock {Ext : "edit" , AspectRatio : "t" },
1116- },
1163+ }
1164+ // Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
1165+ d , err := f .decodeVMLDrawingReader (drawingVML )
1166+ if err != nil {
1167+ return err
1168+ }
1169+ if d != nil {
1170+ vml .ShapeType .ID = d .ShapeType .ID
1171+ vml .ShapeType .CoordSize = d .ShapeType .CoordSize
1172+ vml .ShapeType .Spt = d .ShapeType .Spt
1173+ vml .ShapeType .PreferRelative = d .ShapeType .PreferRelative
1174+ vml .ShapeType .Path = d .ShapeType .Path
1175+ vml .ShapeType .Filled = d .ShapeType .Filled
1176+ vml .ShapeType .Stroked = d .ShapeType .Stroked
1177+ for _ , v := range d .Shape {
1178+ s := xlsxShape {
1179+ ID : v .ID ,
1180+ SpID : v .SpID ,
1181+ Type : v .Type ,
1182+ Style : v .Style ,
1183+ Val : v .Val ,
1184+ }
1185+ vml .Shape = append (vml .Shape , s )
1186+ }
1187+ }
11171188 }
11181189
1119- style := fmt .Sprintf ("position:absolute;margin-left:0;margin-top:0;width:%s;height:%s;z-index:1" , g .Width , g .Height )
1120- drawingVML := "xl/drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
1190+ for idx , shape := range vml .Shape {
1191+ if shape .ID == shapeID {
1192+ vml .Shape = append (vml .Shape [:idx ], vml .Shape [idx + 1 :]... )
1193+ }
1194+ }
1195+
1196+ style := fmt .Sprintf ("position:absolute;margin-left:0;margin-top:0;width:%s;height:%s;z-index:1" , opts .Width , opts .Height )
11211197 drawingVMLRels := "xl/drawings/_rels/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml.rels"
11221198
1123- mediaStr := ".." + strings .TrimPrefix (f .addMedia (g .File , g . Extension ), "xl" )
1199+ mediaStr := ".." + strings .TrimPrefix (f .addMedia (opts .File , ext ), "xl" )
11241200 imageID := f .addRels (drawingVMLRels , SourceRelationshipImage , mediaStr , "" )
11251201
11261202 shape := xlsxShape {
1127- ID : "RH" ,
1128- Spid : "_x0000_s1025" ,
1203+ ID : shapeID ,
1204+ SpID : "_x0000_s1025" ,
11291205 Type : "#_x0000_t75" ,
11301206 Style : style ,
11311207 }
1132- s , _ := xml .Marshal (encodeShape {
1208+ sp , _ := xml .Marshal (encodeShape {
11331209 ImageData : & vImageData {RelID : "rId" + strconv .Itoa (imageID )},
11341210 Lock : & oLock {Ext : "edit" , Rotation : "t" },
11351211 })
1136- shape .Val = string (s [13 : len (s )- 14 ])
1212+
1213+ shape .Val = string (sp [13 : len (sp )- 14 ])
11371214 vml .Shape = append (vml .Shape , shape )
11381215 f .VMLDrawing [drawingVML ] = vml
11391216
1140- sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
1141- sheetXMLPath , _ := f .getSheetXMLPath (sheet )
1142- sheetRels := "xl/worksheets/_rels/" + strings .TrimPrefix (sheetXMLPath , "xl/worksheets/" ) + ".rels"
1143-
1144- drawingID := f .addRels (sheetRels , SourceRelationshipDrawingVML , sheetRelationshipsDrawingVML , "" )
1145- f .addSheetNameSpace (sheet , SourceRelationship )
1146- f .addSheetLegacyDrawingHF (sheet , drawingID )
11471217 if err := f .setContentTypePartImageExtensions (); err != nil {
11481218 return err
11491219 }
0 commit comments