This closes #1395, add new function SetLegacyDrawingHF support to set graphics in a header/footer (#2018)
This commit is contained in:
parent
0d5d1c53b2
commit
b7375bc6d4
10
picture.go
10
picture.go
|
@ -295,6 +295,16 @@ func (f *File) addSheetLegacyDrawing(sheet string, rID int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addSheetLegacyDrawingHF provides a function to add legacy drawing
|
||||||
|
// header/footer element to xl/worksheets/sheet%d.xml by given
|
||||||
|
// worksheet name and relationship index.
|
||||||
|
func (f *File) addSheetLegacyDrawingHF(sheet string, rID int) {
|
||||||
|
ws, _ := f.workSheetReader(sheet)
|
||||||
|
ws.LegacyDrawingHF = &xlsxLegacyDrawingHF{
|
||||||
|
RID: "rId" + strconv.Itoa(rID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// addSheetDrawing provides a function to add drawing element to
|
// addSheetDrawing provides a function to add drawing element to
|
||||||
// xl/worksheets/sheet%d.xml by given worksheet name and relationship index.
|
// xl/worksheets/sheet%d.xml by given worksheet name and relationship index.
|
||||||
func (f *File) addSheetDrawing(sheet string, rID int) {
|
func (f *File) addSheetDrawing(sheet string, rID int) {
|
||||||
|
|
2
sheet.go
2
sheet.go
|
@ -1239,7 +1239,7 @@ func attrValToBool(name string, attrs []xml.Attr) (val bool, err error) {
|
||||||
// |
|
// |
|
||||||
// &F | Current workbook's file name
|
// &F | Current workbook's file name
|
||||||
// |
|
// |
|
||||||
// &G | Drawing object as background (Not support currently)
|
// &G | Drawing object as background (Use SetLegacyDrawingHF)
|
||||||
// |
|
// |
|
||||||
// &H | Shadow text format
|
// &H | Shadow text format
|
||||||
// |
|
// |
|
||||||
|
|
79
vml.go
79
vml.go
|
@ -1070,3 +1070,82 @@ func extractVMLFont(font []decodeVMLFont) []RichTextRun {
|
||||||
}
|
}
|
||||||
return runs
|
return runs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLegacyDrawingHF provides a mechanism to set the graphics that
|
||||||
|
// can be referenced in the Header/Footer defitions via &G.
|
||||||
|
//
|
||||||
|
// The extension should be provided with a "." in front, e.g. ".png".
|
||||||
|
// The width/height should have units in them, e.g. "100pt".
|
||||||
|
func (f *File) SetLegacyDrawingHF(sheet string, g *HeaderFooterGraphics) error {
|
||||||
|
vmlID := f.countVMLDrawing() + 1
|
||||||
|
|
||||||
|
vml := &vmlDrawing{
|
||||||
|
XMLNSv: "urn:schemas-microsoft-com:vml",
|
||||||
|
XMLNSo: "urn:schemas-microsoft-com:office:office",
|
||||||
|
XMLNSx: "urn:schemas-microsoft-com:office:excel",
|
||||||
|
ShapeLayout: &xlsxShapeLayout{
|
||||||
|
Ext: "edit", IDmap: &xlsxIDmap{Ext: "edit", Data: vmlID},
|
||||||
|
},
|
||||||
|
ShapeType: &xlsxShapeType{
|
||||||
|
ID: "_x0000_t75",
|
||||||
|
CoordSize: "21600,21600",
|
||||||
|
Spt: 75,
|
||||||
|
PreferRelative: "t",
|
||||||
|
Path: "m@4@5l@4@11@9@11@9@5xe",
|
||||||
|
Filled: "f",
|
||||||
|
Stroked: "f",
|
||||||
|
Stroke: &xlsxStroke{JoinStyle: "miter"},
|
||||||
|
VFormulas: &vFormulas{
|
||||||
|
Formulas: []vFormula{
|
||||||
|
{Equation: "if lineDrawn pixelLineWidth 0"},
|
||||||
|
{Equation: "sum @0 1 0"},
|
||||||
|
{Equation: "sum 0 0 @1"},
|
||||||
|
{Equation: "prod @2 1 2"},
|
||||||
|
{Equation: "prod @3 21600 pixelWidth"},
|
||||||
|
{Equation: "prod @3 21600 pixelHeight"},
|
||||||
|
{Equation: "sum @0 0 1"},
|
||||||
|
{Equation: "prod @6 1 2"},
|
||||||
|
{Equation: "prod @7 21600 pixelWidth"},
|
||||||
|
{Equation: "sum @8 21600 0"},
|
||||||
|
{Equation: "prod @7 21600 pixelHeight"},
|
||||||
|
{Equation: "sum @10 21600 0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
VPath: &vPath{ExtrusionOK: "f", GradientShapeOK: "t", ConnectType: "rect"},
|
||||||
|
Lock: &oLock{Ext: "edit", AspectRatio: "t"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
style := fmt.Sprintf("position:absolute;margin-left:0;margin-top:0;width:%s;height:%s;z-index:1", g.Width, g.Height)
|
||||||
|
drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(vmlID) + ".vml"
|
||||||
|
drawingVMLRels := "xl/drawings/_rels/vmlDrawing" + strconv.Itoa(vmlID) + ".vml.rels"
|
||||||
|
|
||||||
|
mediaStr := ".." + strings.TrimPrefix(f.addMedia(g.File, g.Extension), "xl")
|
||||||
|
imageID := f.addRels(drawingVMLRels, SourceRelationshipImage, mediaStr, "")
|
||||||
|
|
||||||
|
shape := xlsxShape{
|
||||||
|
ID: "RH",
|
||||||
|
Spid: "_x0000_s1025",
|
||||||
|
Type: "#_x0000_t75",
|
||||||
|
Style: style,
|
||||||
|
}
|
||||||
|
s, _ := xml.Marshal(encodeShape{
|
||||||
|
ImageData: &vImageData{RelID: "rId" + strconv.Itoa(imageID)},
|
||||||
|
Lock: &oLock{Ext: "edit", Rotation: "t"},
|
||||||
|
})
|
||||||
|
shape.Val = string(s[13 : len(s)-14])
|
||||||
|
vml.Shape = append(vml.Shape, shape)
|
||||||
|
f.VMLDrawing[drawingVML] = vml
|
||||||
|
|
||||||
|
sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(vmlID) + ".vml"
|
||||||
|
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||||
|
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||||
|
|
||||||
|
drawingID := f.addRels(sheetRels, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
|
||||||
|
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||||
|
f.addSheetLegacyDrawingHF(sheet, drawingID)
|
||||||
|
if err := f.setContentTypePartImageExtensions(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return f.setContentTypePartVMLExtensions()
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ type vmlDrawing struct {
|
||||||
XMLNSv string `xml:"xmlns:v,attr"`
|
XMLNSv string `xml:"xmlns:v,attr"`
|
||||||
XMLNSo string `xml:"xmlns:o,attr"`
|
XMLNSo string `xml:"xmlns:o,attr"`
|
||||||
XMLNSx string `xml:"xmlns:x,attr"`
|
XMLNSx string `xml:"xmlns:x,attr"`
|
||||||
XMLNSmv string `xml:"xmlns:mv,attr"`
|
XMLNSmv string `xml:"xmlns:mv,attr,omitempty"`
|
||||||
ShapeLayout *xlsxShapeLayout `xml:"o:shapelayout"`
|
ShapeLayout *xlsxShapeLayout `xml:"o:shapelayout"`
|
||||||
ShapeType *xlsxShapeType `xml:"v:shapetype"`
|
ShapeType *xlsxShapeType `xml:"v:shapetype"`
|
||||||
Shape []xlsxShape `xml:"v:shape"`
|
Shape []xlsxShape `xml:"v:shape"`
|
||||||
|
@ -44,6 +44,7 @@ type xlsxIDmap struct {
|
||||||
type xlsxShape struct {
|
type xlsxShape struct {
|
||||||
XMLName xml.Name `xml:"v:shape"`
|
XMLName xml.Name `xml:"v:shape"`
|
||||||
ID string `xml:"id,attr"`
|
ID string `xml:"id,attr"`
|
||||||
|
Spid string `xml:"o:spid,attr,omitempty"`
|
||||||
Type string `xml:"type,attr"`
|
Type string `xml:"type,attr"`
|
||||||
Style string `xml:"style,attr"`
|
Style string `xml:"style,attr"`
|
||||||
Button string `xml:"o:button,attr,omitempty"`
|
Button string `xml:"o:button,attr,omitempty"`
|
||||||
|
@ -60,9 +61,14 @@ type xlsxShapeType struct {
|
||||||
ID string `xml:"id,attr"`
|
ID string `xml:"id,attr"`
|
||||||
CoordSize string `xml:"coordsize,attr"`
|
CoordSize string `xml:"coordsize,attr"`
|
||||||
Spt int `xml:"o:spt,attr"`
|
Spt int `xml:"o:spt,attr"`
|
||||||
|
PreferRelative string `xml:"o:preferrelative,attr,omitempty"`
|
||||||
Path string `xml:"path,attr"`
|
Path string `xml:"path,attr"`
|
||||||
|
Filled string `xml:"filled,attr,omitempty"`
|
||||||
|
Stroked string `xml:"stroked,attr,omitempty"`
|
||||||
Stroke *xlsxStroke `xml:"v:stroke"`
|
Stroke *xlsxStroke `xml:"v:stroke"`
|
||||||
|
VFormulas *vFormulas `xml:"v:formulas"`
|
||||||
VPath *vPath `xml:"v:path"`
|
VPath *vPath `xml:"v:path"`
|
||||||
|
Lock *oLock `xml:"o:lock"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxStroke directly maps the stroke element.
|
// xlsxStroke directly maps the stroke element.
|
||||||
|
@ -72,10 +78,28 @@ type xlsxStroke struct {
|
||||||
|
|
||||||
// vPath directly maps the v:path element.
|
// vPath directly maps the v:path element.
|
||||||
type vPath struct {
|
type vPath struct {
|
||||||
|
ExtrusionOK string `xml:"o:extrusionok,attr,omitempty"`
|
||||||
GradientShapeOK string `xml:"gradientshapeok,attr,omitempty"`
|
GradientShapeOK string `xml:"gradientshapeok,attr,omitempty"`
|
||||||
ConnectType string `xml:"o:connecttype,attr"`
|
ConnectType string `xml:"o:connecttype,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// oLock directly maps the o:lock element.
|
||||||
|
type oLock struct {
|
||||||
|
Ext string `xml:"v:ext,attr"`
|
||||||
|
Rotation string `xml:"rotation,attr,omitempty"`
|
||||||
|
AspectRatio string `xml:"aspectratio,attr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// vFormulas directly maps to the v:formulas element
|
||||||
|
type vFormulas struct {
|
||||||
|
Formulas []vFormula `xml:"v:f"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// vFormula directly maps to the v:f element
|
||||||
|
type vFormula struct {
|
||||||
|
Equation string `xml:"eqn,attr"`
|
||||||
|
}
|
||||||
|
|
||||||
// vFill directly maps the v:fill element. This element must be defined within a
|
// vFill directly maps the v:fill element. This element must be defined within a
|
||||||
// Shape element.
|
// Shape element.
|
||||||
type vFill struct {
|
type vFill struct {
|
||||||
|
@ -106,6 +130,13 @@ type vTextBox struct {
|
||||||
Div *xlsxDiv `xml:"div"`
|
Div *xlsxDiv `xml:"div"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// vImageData directly maps the v:imagedata element. This element must be
|
||||||
|
// defined within a Shape element.
|
||||||
|
type vImageData struct {
|
||||||
|
RelID string `xml:"o:relid,attr"`
|
||||||
|
Title string `xml:"o:title,attr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// xlsxDiv directly maps the div element.
|
// xlsxDiv directly maps the div element.
|
||||||
type xlsxDiv struct {
|
type xlsxDiv struct {
|
||||||
Style string `xml:"style,attr"`
|
Style string `xml:"style,attr"`
|
||||||
|
@ -254,7 +285,9 @@ type encodeShape struct {
|
||||||
Shadow *vShadow `xml:"v:shadow"`
|
Shadow *vShadow `xml:"v:shadow"`
|
||||||
Path *vPath `xml:"v:path"`
|
Path *vPath `xml:"v:path"`
|
||||||
TextBox *vTextBox `xml:"v:textbox"`
|
TextBox *vTextBox `xml:"v:textbox"`
|
||||||
|
ImageData *vImageData `xml:"v:imagedata"`
|
||||||
ClientData *xClientData `xml:"x:ClientData"`
|
ClientData *xClientData `xml:"x:ClientData"`
|
||||||
|
Lock *oLock `xml:"o:lock"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// formCtrlPreset defines the structure used to form control presets.
|
// formCtrlPreset defines the structure used to form control presets.
|
||||||
|
@ -301,3 +334,12 @@ type FormControl struct {
|
||||||
Type FormControlType
|
Type FormControlType
|
||||||
Format GraphicOptions
|
Format GraphicOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HeaderFooterGraphics defines the settings for an image to be
|
||||||
|
// accessible from the header/footer options.
|
||||||
|
type HeaderFooterGraphics struct {
|
||||||
|
File []byte
|
||||||
|
Extension string
|
||||||
|
Width string
|
||||||
|
Height string
|
||||||
|
}
|
||||||
|
|
32
vml_test.go
32
vml_test.go
|
@ -412,3 +412,35 @@ func TestExtractFormControl(t *testing.T) {
|
||||||
_, err := extractFormControl(string(MacintoshCyrillicCharset))
|
_, err := extractFormControl(string(MacintoshCyrillicCharset))
|
||||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetLegacyDrawingHF(t *testing.T) {
|
||||||
|
f := NewFile()
|
||||||
|
sheet := "Sheet1"
|
||||||
|
headerFooterOptions := HeaderFooterOptions{
|
||||||
|
OddHeader: "&LExcelize&R&G",
|
||||||
|
}
|
||||||
|
assert.NoError(t, f.SetHeaderFooter(sheet, &headerFooterOptions))
|
||||||
|
file, err := os.ReadFile(filepath.Join("test", "images", "excel.png"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, f.SetLegacyDrawingHF(sheet, &HeaderFooterGraphics{
|
||||||
|
Extension: ".png",
|
||||||
|
File: file,
|
||||||
|
Width: "50pt",
|
||||||
|
Height: "32pt",
|
||||||
|
}))
|
||||||
|
assert.NoError(t, f.SetCellValue(sheet, "A1", "Example"))
|
||||||
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetLegacyDrawingHF.xlsx")))
|
||||||
|
assert.NoError(t, f.Close())
|
||||||
|
|
||||||
|
// Test set legacy drawing header/footer with unsupported charset content types
|
||||||
|
f = NewFile()
|
||||||
|
f.ContentTypes = nil
|
||||||
|
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||||
|
assert.EqualError(t, f.SetLegacyDrawingHF(sheet, &HeaderFooterGraphics{
|
||||||
|
Extension: ".png",
|
||||||
|
File: file,
|
||||||
|
Width: "50pt",
|
||||||
|
Height: "32pt",
|
||||||
|
}), "XML syntax error on line 1: invalid UTF-8")
|
||||||
|
assert.NoError(t, f.Close())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue