@@ -36,6 +36,16 @@ const (
36
36
FormControlScrollBar
37
37
)
38
38
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
+
39
49
// GetComments retrieves all comments in a worksheet by given worksheet name.
40
50
func (f * File ) GetComments (sheet string ) ([]Comment , error ) {
41
51
var comments []Comment
@@ -519,6 +529,7 @@ func (f *File) addVMLObject(opts vmlOptions) error {
519
529
}
520
530
vmlID = f .countVMLDrawing () + 1
521
531
}
532
+ sheetID := f .getSheetID (opts .sheet )
522
533
drawingVML := "xl/drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
523
534
sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
524
535
sheetXMLPath , _ := f .getSheetXMLPath (opts .sheet )
@@ -534,7 +545,7 @@ func (f *File) addVMLObject(opts vmlOptions) error {
534
545
f .addSheetNameSpace (opts .sheet , SourceRelationship )
535
546
f .addSheetLegacyDrawing (opts .sheet , rID )
536
547
}
537
- if err = f .addDrawingVML (vmlID , drawingVML , prepareFormCtrlOptions (& opts )); err != nil {
548
+ if err = f .addDrawingVML (sheetID , drawingVML , prepareFormCtrlOptions (& opts )); err != nil {
538
549
return err
539
550
}
540
551
if ! opts .formCtrl {
@@ -823,7 +834,7 @@ func (f *File) addFormCtrlShape(preset formCtrlPreset, col, row int, anchor stri
823
834
// anchor value is a comma-separated list of data written out as: LeftColumn,
824
835
// LeftOffset, TopRow, TopOffset, RightColumn, RightOffset, BottomRow,
825
836
// 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 {
827
838
col , row , err := CellNameToCoordinates (opts .FormControl .Cell )
828
839
if err != nil {
829
840
return err
@@ -843,7 +854,7 @@ func (f *File) addDrawingVML(dataID int, drawingVML string, opts *vmlOptions) er
843
854
XMLNSx : "urn:schemas-microsoft-com:office:excel" ,
844
855
XMLNSmv : "http://macVmlSchemaUri" ,
845
856
ShapeLayout : & xlsxShapeLayout {
846
- Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : dataID },
857
+ Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : sheetID },
847
858
},
848
859
ShapeType : & xlsxShapeType {
849
860
ID : fmt .Sprintf ("_x0000_t%d" , vmlID ),
@@ -1071,79 +1082,138 @@ func extractVMLFont(font []decodeVMLFont) []RichTextRun {
1071
1082
return runs
1072
1083
}
1073
1084
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.
1076
1089
//
1077
1090
// 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 )
1080
1102
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
+ }
1081
1118
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
+ },
1112
1159
},
1160
+ VPath : & vPath {ExtrusionOK : "f" , GradientShapeOK : "t" , ConnectType : "rect" },
1161
+ Lock : & oLock {Ext : "edit" , AspectRatio : "t" },
1113
1162
},
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
+ }
1117
1188
}
1118
1189
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 )
1121
1197
drawingVMLRels := "xl/drawings/_rels/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml.rels"
1122
1198
1123
- mediaStr := ".." + strings .TrimPrefix (f .addMedia (g .File , g . Extension ), "xl" )
1199
+ mediaStr := ".." + strings .TrimPrefix (f .addMedia (opts .File , ext ), "xl" )
1124
1200
imageID := f .addRels (drawingVMLRels , SourceRelationshipImage , mediaStr , "" )
1125
1201
1126
1202
shape := xlsxShape {
1127
- ID : "RH" ,
1128
- Spid : "_x0000_s1025" ,
1203
+ ID : shapeID ,
1204
+ SpID : "_x0000_s1025" ,
1129
1205
Type : "#_x0000_t75" ,
1130
1206
Style : style ,
1131
1207
}
1132
- s , _ := xml .Marshal (encodeShape {
1208
+ sp , _ := xml .Marshal (encodeShape {
1133
1209
ImageData : & vImageData {RelID : "rId" + strconv .Itoa (imageID )},
1134
1210
Lock : & oLock {Ext : "edit" , Rotation : "t" },
1135
1211
})
1136
- shape .Val = string (s [13 : len (s )- 14 ])
1212
+
1213
+ shape .Val = string (sp [13 : len (sp )- 14 ])
1137
1214
vml .Shape = append (vml .Shape , shape )
1138
1215
f .VMLDrawing [drawingVML ] = vml
1139
1216
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 )
1147
1217
if err := f .setContentTypePartImageExtensions (); err != nil {
1148
1218
return err
1149
1219
}
0 commit comments