diff --git a/.ci/build-examples.sh b/.ci/build-examples.sh new file mode 100755 index 0000000..c7a8756 --- /dev/null +++ b/.ci/build-examples.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd $PWD +go get github.com/go-ole/go-ole/oleutil@v1.3.0 +go mod tidy + +:> build_errors +find $PWD -maxdepth 2 -mindepth 1 -not -path '*/\.*' -type d -exec sh -c "cd {}; echo building {}; go build -tags=test main.go" 2>>build_log \; +grep -v "^go: " build_log | grep -v main.go > build_errors +if [[ $(wc -l build_errors | awk '{print $1}') == "0" ]]; then + exit 0 +fi +echo BUILD ERRORS: +cat build_errors +echo END OF BUILD ERRORS. +exit 1 diff --git a/.ci/validate-examples.sh b/.ci/validate-examples.sh index 319af4e..61b7c9b 100755 --- a/.ci/validate-examples.sh +++ b/.ci/validate-examples.sh @@ -1,13 +1,13 @@ #!/bin/bash :> errors -output=$(find ../_examples -maxdepth 2 -mindepth 2 ! -name "metered" ! -name "offline" ! -name "metered-non-persistent-cache" ! -name "usage-logs" -print0 | xargs -0 -I{} sh -c "cd {}; echo running {}; ./main") +output=$(find .. -maxdepth 2 -mindepth 2 -not -path '*/\.*' -type d ! -name "metered" ! -name "offline" ! -name "metered-non-persistent-cache" ! -name "usage-logs" -print0 | xargs -0 -I{} sh -c "cd {}; echo running {}; ./main") if [ $? -ne 0 ]; then echo $output >> errors fi export PATH=$PATH:$HOME/dotnet -find ../_examples -name "*.docx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} docx \; -find ../_examples -name "*.xlsx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} xlsx \; -find ../_examples -name "*.pptx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} pptx \; +find .. -name "*.docx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} docx \; +find .. -name "*.xlsx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} xlsx \; +find .. -name "*.pptx" $(printf "! -name %s " $(cat skip_files)) -exec ./dotnet_run.sh {} pptx \; echo Errors: $(wc -l errors) if [[ $(wc -l errors | awk '{print $1}') == "0" ]]; then exit 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb78014..a59bb22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: UniOffice CI +name: UniOffice Examples CI on: push: @@ -34,7 +34,7 @@ jobs: wget https://download.visualstudio.microsoft.com/download/pr/4e3b04aa-c015-4e06-a42e-05f9f3c54ed2/74d1bb68e330eea13ecfc47f7cf9aeb7/dotnet-sdk-8.0.404-linux-x64.tar.gz tar -xf dotnet-sdk-8.0.404-linux-x64.tar.gz - - name: test + - name: Test and validate examples run: | export REPO=$PWD cd $REPO/.ci @@ -44,7 +44,7 @@ jobs: cd $REPO/.ci/openxml-validator $HOME/dotnet/dotnet build --configuration Release cd $REPO - ./build_examples.sh + ./.ci/build-examples.sh cd $REPO/.ci ./validate-examples.sh if [ $? -ne 0 ] diff --git a/document/comment-list/main.go b/document/comment-list/main.go index 40ee4db..a184881 100644 --- a/document/comment-list/main.go +++ b/document/comment-list/main.go @@ -25,14 +25,7 @@ func init() { } func main() { - if len(os.Args) < 2 { - fmt.Printf("Syntax: go run main.go input.docx\n") - os.Exit(1) - } - - inputPath := os.Args[1] - - doc, err := document.Open(inputPath) + doc, err := document.Open("sample.docx") if err != nil { log.Fatalf("error opening document: %s", err) } diff --git a/document/comment-list/sample.docx b/document/comment-list/sample.docx new file mode 100644 index 0000000..3be86cf Binary files /dev/null and b/document/comment-list/sample.docx differ diff --git a/document/comment-remove/main.go b/document/comment-remove/main.go index e601b25..dc7d713 100644 --- a/document/comment-remove/main.go +++ b/document/comment-remove/main.go @@ -10,7 +10,6 @@ import ( "fmt" "log" "os" - "strconv" "github.com/unidoc/unioffice/v2/common/license" "github.com/unidoc/unioffice/v2/document" @@ -26,18 +25,7 @@ func init() { } func main() { - if len(os.Args) < 3 { - fmt.Printf("Syntax: go run main.go input.docx comment_id\n") - os.Exit(1) - } - - inputPath := os.Args[1] - commentId, err := strconv.Atoi(os.Args[2]) - if err != nil { - log.Fatalf("error parsing comment id: %s", err) - } - - doc, err := document.Open(inputPath) + doc, err := document.Open("sample.docx") if err != nil { log.Fatalf("error opening document: %s", err) } @@ -45,9 +33,10 @@ func main() { listComments(doc) - if sucess := doc.RemoveComment(int64(commentId)); !sucess { - fmt.Println("Failed removing comment") + commentId := int64(2) + if ok := doc.RemoveComment(commentId); !ok { + fmt.Println("Failed removing comment") return } diff --git a/document/comment-remove/sample.docx b/document/comment-remove/sample.docx new file mode 100644 index 0000000..3be86cf Binary files /dev/null and b/document/comment-remove/sample.docx differ diff --git a/document/node-remove/main.go b/document/node-remove/main.go index 0aec7d7..2e17b15 100644 --- a/document/node-remove/main.go +++ b/document/node-remove/main.go @@ -4,7 +4,6 @@ package main import ( - "fmt" "log" "os" @@ -20,16 +19,7 @@ func init() { } func main() { - args := os.Args - if len(args) < 2 { - fmt.Printf("Usage %s go run main.go input.docx output.docx", os.Args[0]) - return - } - - inputPath := args[1] - outputPath := args[2] - - doc, err := document.Open(inputPath) + doc, err := document.Open("sample.docx") if err != nil { log.Fatalf("error opening document: %s", err) } @@ -46,7 +36,7 @@ func main() { } } - err = doc.SaveToFile(outputPath) + err = doc.SaveToFile("output.docx") if err != nil { panic(err) } diff --git a/document/template-with-header/letter_template.docx b/document/template-with-header/letter_template.docx index 2a8fb75..72f1e49 100755 Binary files a/document/template-with-header/letter_template.docx and b/document/template-with-header/letter_template.docx differ diff --git a/document/use-template/use-template.docx b/document/use-template/use-template.docx new file mode 100644 index 0000000..0f51a2b Binary files /dev/null and b/document/use-template/use-template.docx differ diff --git a/license/usage-logs/grocery_list.docx b/license/usage-logs/grocery_list.docx index 4f436f7..5ed04a6 100644 Binary files a/license/usage-logs/grocery_list.docx and b/license/usage-logs/grocery_list.docx differ diff --git a/license/usage-logs/updated_list.docx b/license/usage-logs/updated_list.docx index 7e0ff0c..c9d8731 100644 Binary files a/license/usage-logs/updated_list.docx and b/license/usage-logs/updated_list.docx differ diff --git a/presentation/copy-reorder-slide/main.go b/presentation/copy-reorder-slide/main.go index dca5f3c..464633d 100644 --- a/presentation/copy-reorder-slide/main.go +++ b/presentation/copy-reorder-slide/main.go @@ -43,7 +43,7 @@ func main() { } // move inserted slide to the very beginning of presentation, it becomes slide 0 - err = pptTo.MoveSlide(4, 0) + err = pptTo.MoveSlide(len(pptTo.Slides())-1, 1) if err != nil { fmt.Println("error moving slide ", err) os.Exit(1) diff --git a/presentation/use-template-sales/main.go b/presentation/use-template-sales/main.go new file mode 100644 index 0000000..4de91dc --- /dev/null +++ b/presentation/use-template-sales/main.go @@ -0,0 +1,157 @@ +// Copyright 2025 FoxyUtils ehf. All rights reserved. +package main + +import ( + "fmt" + "log" + "os" + + "encoding/json" + + "github.com/unidoc/unioffice/v2/common/license" + "github.com/unidoc/unioffice/v2/schema/soo/pml" + + "github.com/unidoc/unioffice/v2/presentation" +) + +type SaleInfo struct { + Area string + Sale string + Customers int + Manager string +} + +type Data struct { + Year int + ID string + SaleData []SaleInfo +} + +func init() { + // Make sure to load your metered License API key prior to using the library. + // If you need a key, you can sign up and create a free one at https://cloud.unidoc.io + err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`)) + if err != nil { + panic(err) + } +} + +func main() { + jsonData := []byte(` + { + "year":2020, + "id":"JI23SA", + "SaleData":[ + { + "area": "Michigan", + "sale": "10 million", + "customers": 10000, + "manager": "Henry" + }, + { + "area": "Cincinnati", + "sale": "2 million", + "customers": 490, + "manager": "John Green" + }, + { + "area": "Washington", + "sale": "150 million", + "customers": 100000, + "manager": "Smith Johnson" + } + ] + } + `) + + ppt, err := presentation.OpenTemplate("template.pptx") + if err != nil { + log.Fatalf("unable to open template: %s", err) + } + defer ppt.Close() + + for i, layout := range ppt.SlideLayouts() { + fmt.Println(i, " LL ", layout.Name(), "/", layout.Type()) + } + + var res Data + err = json.Unmarshal(jsonData, &res) + if err != nil { + log.Fatalf("error unmarshalling JSON: %s", err) + } + saleData := res.SaleData + + for _, data := range saleData { // Iterate through the sale data + // Remove any existing slides + for _, s := range ppt.Slides() { + err := ppt.RemoveSlide(s) + if err != nil { + log.Fatalf("error removing slide: %s", err) + } + } + + l, err := ppt.GetLayoutByName("Title and Caption") + if err != nil { + log.Fatalf("error retrieving layout: %s", err) + } + + sld, err := ppt.AddDefaultSlideWithLayout(l) + if err != nil { + log.Fatalf("error adding slide: %s", err) + } + + ph, err := sld.GetPlaceholder(pml.ST_PlaceholderTypeTitle) + if err != nil { + log.Fatalf("error getting placeholder type title: %s", err) + } + + ph.SetText(fmt.Sprintf("Sale Data For: %s", data.Area)) + + ph, err = sld.GetPlaceholder(pml.ST_PlaceholderTypeBody) + if err != nil { + log.Fatalf("error getting placeholder type body: %s", err) + } + + ph.SetText("Created with github.com/unidoc/unioffice/") + + tac, err := ppt.GetLayoutByName("Title and Content") + if err != nil { + log.Fatalf("error retrieving layout: %s", err) + } + + sld, err = ppt.AddDefaultSlideWithLayout(tac) + if err != nil { + log.Fatalf("error adding slide: %s", err) + } + + ph, err = sld.GetPlaceholder(pml.ST_PlaceholderTypeTitle) + if err != nil { + log.Fatalf("error getting placeholder type title: %s", err) + } + + ph.SetText(fmt.Sprintf("Data for %s, Managed by %s", data.Area, data.Manager)) + + ph, err = sld.GetPlaceholderByIndex(1) + if err != nil { + log.Fatalf("error getting placeholder by index: %s", err) + } + + ph.ClearAll() + + para := ph.AddParagraph() + run := para.AddRun() + run.SetText(fmt.Sprintf("Here is the number of sales in %s: $%s", data.Area, data.Sale)) + + para = ph.AddParagraph() + run = para.AddRun() + run.SetText(fmt.Sprintf("Number of Customers: %d", data.Customers)) + + para = ph.AddParagraph() + run = para.AddRun() + run.SetText(fmt.Sprintf("Manager: %s", data.Manager)) + + if err := ppt.SaveToFile(fmt.Sprintf("%s.pptx", data.Area)); err != nil { + log.Fatalf("error saving presentation: %s", err) + } + } +} diff --git a/presentation/use-template-sales/template.pptx b/presentation/use-template-sales/template.pptx new file mode 100644 index 0000000..10831af Binary files /dev/null and b/presentation/use-template-sales/template.pptx differ diff --git a/spreadsheet/line-chart-from-csv/main.go b/spreadsheet/line-chart-from-csv/main.go index 90a9d16..11a6741 100644 --- a/spreadsheet/line-chart-from-csv/main.go +++ b/spreadsheet/line-chart-from-csv/main.go @@ -23,16 +23,7 @@ func init() { } func main() { - args := os.Args - if len(args) < 2 { - fmt.Printf("Usage %s go run main.go input.csv output.xlsx", os.Args[0]) - return - } - - inputPath := args[1] - outputPath := args[2] - - sliceData, err := readCsv(inputPath) + sliceData, err := readCsv("example-data.csv") if err != nil { log.Fatalf("error reading csv: %s", err) } @@ -99,7 +90,7 @@ func main() { log.Fatalf("error validating sheet: %s", err) } - if err := ss.SaveToFile(outputPath); err != nil { + if err := ss.SaveToFile("output.xlsx"); err != nil { log.Fatalf("error saving: %s", err) } } diff --git a/spreadsheet/line-chart-from-csv/output.xlsx b/spreadsheet/line-chart-from-csv/output.xlsx index 293e935..6be4b80 100644 Binary files a/spreadsheet/line-chart-from-csv/output.xlsx and b/spreadsheet/line-chart-from-csv/output.xlsx differ diff --git a/spreadsheet/multiple-charts-from-csv/charts-from-csv.xlsx b/spreadsheet/multiple-charts-from-csv/charts-from-csv.xlsx index 50cfbe9..9f805ec 100644 Binary files a/spreadsheet/multiple-charts-from-csv/charts-from-csv.xlsx and b/spreadsheet/multiple-charts-from-csv/charts-from-csv.xlsx differ