mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
346 lines
13 KiB
Go
346 lines
13 KiB
Go
// Copyright 2017 Baliance. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by the terms of the Affero GNU General
|
|
// Public License version 3.0 as published by the Free Software Foundation and
|
|
// appearing in the file LICENSE included in the packaging of this file. A
|
|
// commercial license can be purchased by contacting sales@baliance.com.
|
|
|
|
package presentation
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"baliance.com/gooxml"
|
|
"baliance.com/gooxml/measurement"
|
|
"baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml"
|
|
|
|
"baliance.com/gooxml/common"
|
|
dml "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml"
|
|
"baliance.com/gooxml/schema/schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
|
pml "baliance.com/gooxml/schema/schemas.openxmlformats.org/presentationml"
|
|
"baliance.com/gooxml/zippkg"
|
|
)
|
|
|
|
// Presentation is the a presentation base document.
|
|
type Presentation struct {
|
|
common.DocBase
|
|
x *pml.Presentation
|
|
prels common.Relationships
|
|
slides []*pml.Sld
|
|
slideRels []common.Relationships
|
|
masters []*pml.SldMaster
|
|
masterRels []common.Relationships
|
|
layouts []*pml.SldLayout
|
|
layoutRels []common.Relationships
|
|
themes []*dml.Theme
|
|
}
|
|
|
|
// New initializes and reurns a new presentation
|
|
func New() *Presentation {
|
|
p := &Presentation{x: pml.NewPresentation()}
|
|
|
|
p.x.SldIdLst = pml.NewCT_SlideIdList()
|
|
p.x.ConformanceAttr = sharedTypes.ST_ConformanceClassTransitional
|
|
p.AppProperties = common.NewAppProperties()
|
|
p.CoreProperties = common.NewCoreProperties()
|
|
p.ContentTypes = common.NewContentTypes()
|
|
|
|
p.ContentTypes.AddOverride("/ppt/presentation.xml", "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
|
|
|
|
p.Rels = common.NewRelationships()
|
|
|
|
p.Rels.AddRelationship("docProps/core.xml", "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties")
|
|
p.Rels.AddRelationship("docProps/app.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties")
|
|
p.Rels.AddRelationship("ppt/presentation.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
|
|
|
|
p.prels = common.NewRelationships()
|
|
|
|
p.x.SldMasterIdLst = pml.NewCT_SlideMasterIdList()
|
|
m := pml.NewSldMaster()
|
|
m.ClrMap.Bg1Attr = drawingml.ST_ColorSchemeIndexLt1
|
|
m.ClrMap.Bg2Attr = drawingml.ST_ColorSchemeIndexLt2
|
|
m.ClrMap.Tx1Attr = drawingml.ST_ColorSchemeIndexDk1
|
|
m.ClrMap.Tx2Attr = drawingml.ST_ColorSchemeIndexDk2
|
|
m.ClrMap.Accent1Attr = drawingml.ST_ColorSchemeIndexAccent1
|
|
m.ClrMap.Accent2Attr = drawingml.ST_ColorSchemeIndexAccent2
|
|
m.ClrMap.Accent3Attr = drawingml.ST_ColorSchemeIndexAccent3
|
|
m.ClrMap.Accent4Attr = drawingml.ST_ColorSchemeIndexAccent4
|
|
m.ClrMap.Accent5Attr = drawingml.ST_ColorSchemeIndexAccent5
|
|
m.ClrMap.Accent6Attr = drawingml.ST_ColorSchemeIndexAccent6
|
|
m.ClrMap.HlinkAttr = drawingml.ST_ColorSchemeIndexHlink
|
|
m.ClrMap.FolHlinkAttr = drawingml.ST_ColorSchemeIndexFolHlink
|
|
|
|
p.masters = append(p.masters, m)
|
|
|
|
p.ContentTypes.AddOverride("/ppt/slideMasters/slideMaster1.xml", common.SlideMasterContentType)
|
|
mrelID := p.prels.AddRelationship("slideMasters/slideMaster1.xml", common.SlideMasterRelationshipType)
|
|
smid := pml.NewCT_SlideMasterIdListEntry()
|
|
smid.IdAttr = gooxml.Uint32(2147483648)
|
|
smid.RIdAttr = mrelID.ID()
|
|
p.x.SldMasterIdLst.SldMasterId = append(p.x.SldMasterIdLst.SldMasterId, smid)
|
|
mrel := common.NewRelationships()
|
|
p.masterRels = append(p.masterRels, mrel)
|
|
|
|
ls := pml.NewSldLayout()
|
|
lrid := mrel.AddRelationship("../slideLayouts/slideLayout1.xml", common.SlideLayoutType)
|
|
p.ContentTypes.AddOverride("/ppt/slideLayouts/slideLayout1.xml", common.SlideLayoutContentType)
|
|
mrel.AddRelationship("../theme/theme1.xml", common.ThemeType)
|
|
p.layouts = append(p.layouts, ls)
|
|
|
|
m.SldLayoutIdLst = pml.NewCT_SlideLayoutIdList()
|
|
lid := pml.NewCT_SlideLayoutIdListEntry()
|
|
lid.IdAttr = gooxml.Uint32(2147483649)
|
|
lid.RIdAttr = lrid.ID()
|
|
m.SldLayoutIdLst.SldLayoutId = append(m.SldLayoutIdLst.SldLayoutId, lid)
|
|
|
|
lrel := common.NewRelationships()
|
|
p.layoutRels = append(p.layoutRels, lrel)
|
|
lrel.AddRelationship("../slideMasters/slideMaster1.xml", common.SlideMasterRelationshipType)
|
|
p.x.NotesSz.CxAttr = 6858000
|
|
p.x.NotesSz.CyAttr = 9144000
|
|
|
|
thm := dml.NewTheme()
|
|
|
|
thm.NameAttr = gooxml.String("gooxml Theme")
|
|
thm.ThemeElements.ClrScheme.NameAttr = "Office"
|
|
thm.ThemeElements.ClrScheme.Dk1.SysClr = dml.NewCT_SystemColor()
|
|
thm.ThemeElements.ClrScheme.Dk1.SysClr.LastClrAttr = gooxml.String("000000")
|
|
thm.ThemeElements.ClrScheme.Dk1.SysClr.ValAttr = dml.ST_SystemColorValWindowText
|
|
|
|
thm.ThemeElements.ClrScheme.Lt1.SysClr = dml.NewCT_SystemColor()
|
|
thm.ThemeElements.ClrScheme.Lt1.SysClr.LastClrAttr = gooxml.String("ffffff")
|
|
thm.ThemeElements.ClrScheme.Lt1.SysClr.ValAttr = dml.ST_SystemColorValWindow
|
|
|
|
thm.ThemeElements.ClrScheme.Dk2.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Dk2.SrgbClr.ValAttr = "44546a"
|
|
|
|
thm.ThemeElements.ClrScheme.Lt2.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Lt2.SrgbClr.ValAttr = "e7e7e6"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent1.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent1.SrgbClr.ValAttr = "4472c4"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent2.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent2.SrgbClr.ValAttr = "ed7d31"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent3.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent3.SrgbClr.ValAttr = "a5a5a5"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent4.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent4.SrgbClr.ValAttr = "ffc000"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent5.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent5.SrgbClr.ValAttr = "5b9bd5"
|
|
|
|
thm.ThemeElements.ClrScheme.Accent6.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Accent6.SrgbClr.ValAttr = "70ad47"
|
|
|
|
thm.ThemeElements.ClrScheme.Hlink.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.Hlink.SrgbClr.ValAttr = "0563c1"
|
|
|
|
thm.ThemeElements.ClrScheme.FolHlink.SrgbClr = dml.NewCT_SRgbColor()
|
|
thm.ThemeElements.ClrScheme.FolHlink.SrgbClr.ValAttr = "954f72"
|
|
|
|
thm.ThemeElements.FontScheme.NameAttr = "Office"
|
|
thm.ThemeElements.FontScheme.MajorFont.Latin.TypefaceAttr = "Calibri Light"
|
|
thm.ThemeElements.FontScheme.MinorFont.Latin.TypefaceAttr = "Calibri"
|
|
|
|
thm.ThemeElements.FmtScheme.NameAttr = gooxml.String("Office")
|
|
// fills
|
|
fp := dml.NewEG_FillProperties()
|
|
thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties, fp)
|
|
fp.SolidFill = &dml.CT_SolidColorFillProperties{
|
|
SchemeClr: &dml.CT_SchemeColor{ValAttr: dml.ST_SchemeColorValPhClr},
|
|
}
|
|
|
|
// rot fill 0
|
|
fp = dml.NewEG_FillProperties()
|
|
thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties, fp)
|
|
// add it twice so OSX word doesn't choke
|
|
thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.FillStyleLst.EG_FillProperties, fp)
|
|
fp.GradFill = &dml.CT_GradientFillProperties{RotWithShapeAttr: gooxml.Bool(true),
|
|
GsLst: &dml.CT_GradientStopList{},
|
|
Lin: &dml.CT_LinearShadeProperties{}}
|
|
fp.GradFill.Lin.AngAttr = gooxml.Int32(5400000)
|
|
fp.GradFill.Lin.ScaledAttr = gooxml.Bool(false)
|
|
|
|
gs := dml.NewCT_GradientStop()
|
|
gs.PosAttr.ST_PositiveFixedPercentageDecimal = gooxml.Int32(0)
|
|
gs.SchemeClr = &dml.CT_SchemeColor{ValAttr: dml.ST_SchemeColorValPhClr}
|
|
fp.GradFill.GsLst.Gs = append(fp.GradFill.GsLst.Gs, gs)
|
|
|
|
gs = dml.NewCT_GradientStop()
|
|
gs.PosAttr.ST_PositiveFixedPercentageDecimal = gooxml.Int32(50000)
|
|
gs.SchemeClr = &dml.CT_SchemeColor{ValAttr: dml.ST_SchemeColorValPhClr}
|
|
fp.GradFill.GsLst.Gs = append(fp.GradFill.GsLst.Gs, gs)
|
|
|
|
thm.ThemeElements.FmtScheme.LnStyleLst = dml.NewCT_LineStyleList()
|
|
for i := 0; i < 3; i++ {
|
|
lp := dml.NewCT_LineProperties()
|
|
lp.WAttr = gooxml.Int32(int32(6350 * (i + 1)))
|
|
lp.CapAttr = dml.ST_LineCapFlat
|
|
lp.CmpdAttr = dml.ST_CompoundLineSng
|
|
lp.AlgnAttr = dml.ST_PenAlignmentCtr
|
|
thm.ThemeElements.FmtScheme.LnStyleLst.Ln = append(thm.ThemeElements.FmtScheme.LnStyleLst.Ln, lp)
|
|
}
|
|
|
|
thm.ThemeElements.FmtScheme.EffectStyleLst = dml.NewCT_EffectStyleList()
|
|
for i := 0; i < 3; i++ {
|
|
ef := dml.NewCT_EffectStyleItem()
|
|
ef.EffectLst = dml.NewCT_EffectList()
|
|
thm.ThemeElements.FmtScheme.EffectStyleLst.EffectStyle = append(thm.ThemeElements.FmtScheme.EffectStyleLst.EffectStyle, ef)
|
|
}
|
|
|
|
sf := dml.NewEG_FillProperties()
|
|
sf.SolidFill = &dml.CT_SolidColorFillProperties{
|
|
SchemeClr: &dml.CT_SchemeColor{ValAttr: dml.ST_SchemeColorValPhClr},
|
|
}
|
|
thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties,
|
|
sf)
|
|
thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties,
|
|
sf)
|
|
thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties = append(thm.ThemeElements.FmtScheme.BgFillStyleLst.EG_FillProperties,
|
|
fp)
|
|
|
|
p.themes = append(p.themes, thm)
|
|
p.ContentTypes.AddOverride("/ppt/theme/theme1.xml", common.ThemeContentType)
|
|
p.prels.AddRelationship("theme/theme1.xml", common.ThemeType)
|
|
return p
|
|
}
|
|
|
|
// X returns the inner wrapped XML type.
|
|
func (p *Presentation) X() *pml.Presentation {
|
|
return p.x
|
|
}
|
|
|
|
func (p *Presentation) AddSlide() Slide {
|
|
sd := pml.NewCT_SlideIdListEntry()
|
|
sd.IdAttr = 256
|
|
p.x.SldIdLst.SldId = append(p.x.SldIdLst.SldId, sd)
|
|
|
|
slide := pml.NewSld()
|
|
slide.CSld.SpTree.NvGrpSpPr.CNvPr.IdAttr = 1
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm = dml.NewCT_GroupTransform2D()
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Off = dml.NewCT_Point2D()
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Off.XAttr.ST_CoordinateUnqualified = gooxml.Int64(0)
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Off.YAttr.ST_CoordinateUnqualified = gooxml.Int64(0)
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Ext = dml.NewCT_PositiveSize2D()
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Ext.CxAttr = int64(0 * measurement.Point)
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.Ext.CyAttr = int64(0 * measurement.Point)
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.ChOff = slide.CSld.SpTree.GrpSpPr.Xfrm.Off
|
|
slide.CSld.SpTree.GrpSpPr.Xfrm.ChExt = slide.CSld.SpTree.GrpSpPr.Xfrm.Ext
|
|
|
|
c := pml.NewCT_GroupShapeChoice()
|
|
slide.CSld.SpTree.Choice = append(slide.CSld.SpTree.Choice, c)
|
|
sp := pml.NewCT_Shape()
|
|
c.Sp = append(c.Sp, sp)
|
|
|
|
sp.NvSpPr.NvPr.Ph = pml.NewCT_Placeholder()
|
|
sp.NvSpPr.NvPr.Ph.TypeAttr = pml.ST_PlaceholderTypeCtrTitle
|
|
|
|
sp.TxBody = drawingml.NewCT_TextBody()
|
|
para := drawingml.NewCT_TextParagraph()
|
|
sp.TxBody.P = append(sp.TxBody.P, para)
|
|
|
|
run := drawingml.NewEG_TextRun()
|
|
para.EG_TextRun = append(para.EG_TextRun, run)
|
|
run.R = drawingml.NewCT_RegularTextRun()
|
|
run.R.T = "testing 123"
|
|
|
|
p.slides = append(p.slides, slide)
|
|
fn := fmt.Sprintf("slides/slide%d.xml", len(p.slides))
|
|
srelID := p.prels.AddRelationship(fn, common.SlideType)
|
|
sd.RIdAttr = srelID.ID()
|
|
|
|
p.ContentTypes.AddOverride(fmt.Sprintf("/ppt/slides/slide%d.xml", len(p.slides)), common.SlideContentType)
|
|
|
|
srel := common.NewRelationships()
|
|
p.slideRels = append(p.slideRels, srel)
|
|
srel.AddRelationship("../slideLayouts/slideLayout1.xml", common.SlideLayoutType)
|
|
|
|
return Slide{sd, slide}
|
|
}
|
|
|
|
// Save writes the presentation out to a writer in the Zip package format
|
|
func (p *Presentation) Save(w io.Writer) error {
|
|
z := zip.NewWriter(w)
|
|
defer z.Close()
|
|
if err := zippkg.MarshalXML(z, "[Content_Types].xml", p.ContentTypes.X()); err != nil {
|
|
return err
|
|
}
|
|
if err := zippkg.MarshalXML(z, "_rels/.rels", p.Rels.X()); err != nil {
|
|
return err
|
|
}
|
|
if err := zippkg.MarshalXML(z, "docProps/app.xml", p.AppProperties.X()); err != nil {
|
|
return err
|
|
}
|
|
if err := zippkg.MarshalXML(z, "docProps/core.xml", p.CoreProperties.X()); err != nil {
|
|
return err
|
|
}
|
|
if err := zippkg.MarshalXML(z, "ppt/presentation.xml", p.x); err != nil {
|
|
return err
|
|
}
|
|
if err := zippkg.MarshalXML(z, "ppt/_rels/presentation.xml.rels", p.prels.X()); err != nil {
|
|
return err
|
|
}
|
|
for i, slide := range p.slides {
|
|
spath := fmt.Sprintf("ppt/slides/slide%d.xml", i+1)
|
|
zippkg.MarshalXML(z, spath, slide)
|
|
rpath := zippkg.RelationsPathFor(spath)
|
|
zippkg.MarshalXML(z, rpath, p.slideRels[i].X())
|
|
}
|
|
for i, m := range p.masters {
|
|
mpath := fmt.Sprintf("ppt/slideMasters/slideMaster%d.xml", i+1)
|
|
zippkg.MarshalXML(z, mpath, m)
|
|
rpath := zippkg.RelationsPathFor(mpath)
|
|
zippkg.MarshalXML(z, rpath, p.masterRels[i].X())
|
|
}
|
|
for i, l := range p.layouts {
|
|
mpath := fmt.Sprintf("ppt/slideLayouts/slideLayout%d.xml", i+1)
|
|
zippkg.MarshalXML(z, mpath, l)
|
|
rpath := zippkg.RelationsPathFor(mpath)
|
|
zippkg.MarshalXML(z, rpath, p.layoutRels[i].X())
|
|
}
|
|
for i, l := range p.themes {
|
|
tpath := fmt.Sprintf("ppt/theme/theme%d.xml", i+1)
|
|
zippkg.MarshalXML(z, tpath, l)
|
|
}
|
|
p.WriteExtraFiles(z)
|
|
return nil
|
|
}
|
|
|
|
// SaveToFile writes the Presentation out to a file.
|
|
func (p *Presentation) SaveToFile(path string) error {
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
return p.Save(f)
|
|
}
|
|
|
|
func (p *Presentation) Validate() error {
|
|
if err := p.x.Validate(); err != nil {
|
|
return err
|
|
}
|
|
for i, s := range p.slides {
|
|
if err := s.ValidateWithPath(fmt.Sprintf("Slide[%d]", i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for i, sm := range p.masters {
|
|
if err := sm.ValidateWithPath(fmt.Sprintf("SlideMaster[%d]", i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for i, sl := range p.layouts {
|
|
if err := sl.ValidateWithPath(fmt.Sprintf("SlideMAter[%d]", i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|