Skip to content

Commit

Permalink
add options towards supporting generic geotiff rewriting (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbonfort committed Aug 9, 2024
1 parent 4905485 commit 0921ae7
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 1,082 deletions.
157 changes: 113 additions & 44 deletions cmd/cogger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,132 @@ package main

import (
"context"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"os/signal"
"strconv"
"strings"
"syscall"

"github.com/airbusgeo/cogger"
"github.com/spf13/cobra"

"github.com/google/tiff"
_ "github.com/google/tiff/bigtiff"
)

func main() {
ctx := context.Background()
err := run(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
ctx, cncl := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer cncl()
exitCode := 0
if err := newRootCommand().ExecuteContext(ctx); err != nil {
exitCode = 1
}
os.Exit(exitCode)
}

func run(ctx context.Context) error {
outfile := flag.String("output", "out.tif", "destination file")
flag.Parse()

args := flag.Args()
if len(args) < 1 {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] file.tif [overview.tif...]\nOptions:\n", filepath.Base(os.Args[0]))
flag.PrintDefaults()
return fmt.Errorf("")
func newRootCommand() *cobra.Command {
outfile := "out.tif"
skipGhostAreas := false
keepBigtiff := false
forceBigtiff := false
keptOverviewsS := ""
keptMasksS := ""
var keptMasks []int = nil
var keptOverviews []int = nil
cmd := &cobra.Command{
Use: "cogger [main.tif] [overview.tif]...",
Short: "cogger is a tool for creating Cloud Optimized GeoTIFFs",
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, _ []string) error {
flags := cmd.Flags()
if flags.Changed("keep-masks") {
if keptMasksS == "" {
keptMasks = []int{}
} else {
ks := strings.Split(keptMasksS, ",")
keptMasks = make([]int, len(ks))
for k := range ks {
kv, err := strconv.Atoi(ks[k])
if err != nil {
return fmt.Errorf("invalid mask index %s: %w", ks[k], err)
}
keptMasks[k] = kv
}
}
}
if flags.Changed("keep-overviews") {
if keptOverviewsS == "" {
keptOverviews = []int{}
} else {
ks := strings.Split(keptOverviewsS, ",")
keptOverviews = make([]int, len(ks))
for k := range ks {
kv, err := strconv.Atoi(ks[k])
if err != nil {
return fmt.Errorf("invalid overview index %s: %w", ks[k], err)
}
keptOverviews[k] = kv
}
}
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
readers := make([]tiff.ReadAtReadSeeker, len(args))
for i, input := range args {
topFile, err := os.Open(input)
if err != nil {
return fmt.Errorf("open %s: %w", args[0], err)
}
defer topFile.Close()
readers[i] = topFile
}
out, err := os.Create(outfile)
if err != nil {
return fmt.Errorf("create %s: %w", outfile, err)
}
cfg := cogger.DefaultConfig()
if keepBigtiff {
tif0, err := tiff.Parse(readers[0], nil, nil)
if err != nil {
return fmt.Errorf("parse %s: %w", args[0], err)
}
if tif0.Version() == 0x2B {
cfg.BigTIFF = true
}
readers[0].Seek(0, io.SeekStart)
}
if forceBigtiff {
cfg.BigTIFF = true
}
if skipGhostAreas {
cfg.WithGDALGhostArea = false
}
cfg.KeptMasks = keptMasks
cfg.KeptOverviews = keptOverviews
err = cfg.Rewrite(out, readers...)
if err != nil {
return fmt.Errorf("cogger.rewrite: %w", err)
}
err = out.Close()
if err != nil {
return fmt.Errorf("close %s: %w", outfile, err)
}
return nil
},
}
flags := cmd.Flags()
flags.StringVar(&outfile, "output", outfile, "destination file")
flags.BoolVar(&skipGhostAreas, "skip-gdal-ghost-areas", skipGhostAreas, "omit writing gdal ghost areas")
flags.BoolVar(&keepBigtiff, "keep-bigtiff", keepBigtiff, "produce a bigtiff file if the input is bigtiff")
flags.BoolVar(&forceBigtiff, "force-bigtiff", forceBigtiff, "produce a bigtiff output even if the size is less than 4Gb")
flags.StringVar(&keptOverviewsS, "keep-overviews", "", "comma separated list of overview levels to keep")
flags.StringVar(&keptMasksS, "keep-masks", "", "comma separated list of mask levels to keep")
cmd.MarkFlagsMutuallyExclusive("keep-bigtiff", "force-bigtiff")
flags.SortFlags = false

totalSize := int64(0)
readers := make([]tiff.ReadAtReadSeeker, len(args))
for i, input := range args {
topFile, err := os.Open(input)
if err != nil {
return fmt.Errorf("open %s: %w", args[0], err)
}
defer topFile.Close()
st, err := topFile.Stat()
if err != nil {
return fmt.Errorf("stat %s: %w", args[0], err)
}
totalSize += st.Size()
readers[i] = topFile
}
out, err := os.Create(*outfile)
if err != nil {
return fmt.Errorf("create %s: %w", *outfile, err)
}
err = cogger.DefaultConfig().Rewrite(out, readers...)
if err != nil {
return fmt.Errorf("mucog write: %w", err)
}
err = out.Close()
if err != nil {
return fmt.Errorf("close %s: %w", *outfile, err)
}
return nil
return cmd
}
26 changes: 16 additions & 10 deletions cog.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ const (
//
// Examples for a 3-band rgb image:
//
// - [[0,1,2]] will result in tiles written in the order r1,g1,b1,r2,g2,b2...rn,gn,bn. This
// is the default.
// - [0],[1],[2]] => r1,r2...rn,g1,g2....gn,b1,b2...bn
// - [0],[2],[1]] => r1,r2...rn,b1,b2....bn,g1,g2...gn
// - [0,1],[2]] => r1,g1,r2,g2...rn,gn,b1,b2....bn
// - [[0,1,2]] will result in tiles written in the order r1,g1,b1,r2,g2,b2...rn,gn,bn. This
// is the default.
// - [0],[1],[2]] => r1,r2...rn,g1,g2....gn,b1,b2...bn
// - [0],[2],[1]] => r1,r2...rn,b1,b2....bn,g1,g2...gn
// - [0,1],[2]] => r1,g1,r2,g2...rn,gn,b1,b2....bn
//
// Examples for a 3-band rgb image with mask:
//
// - [[0,1,2,3]] will result in tiles written in the order r1,g1,b1,m1,r2,g2,b2,m2...rn,gn,bn,mn. This
// is the default.
// - [0],[1],[2],[3]] => r1,r2...rn,g1,g2...gn,b1,b2...bn,m1,m2...mn
// - [0],[3],[2],[1]] => r1,r2...rn,m1,m2...m3,b1,b2...bn,g1,g2...gn
// - [0,1],[2],[3]] => r1,g1,r2,g2...rn,gn,b1,b2....bn,m1m2...mn
// - [[0,1,2,3]] will result in tiles written in the order r1,g1,b1,m1,r2,g2,b2,m2...rn,gn,bn,mn. This
// is the default.
// - [0],[1],[2],[3]] => r1,r2...rn,g1,g2...gn,b1,b2...bn,m1,m2...mn
// - [0],[3],[2],[1]] => r1,r2...rn,m1,m2...m3,b1,b2...bn,g1,g2...gn
// - [0,1],[2],[3]] => r1,g1,r2,g2...rn,gn,b1,b2....bn,m1m2...mn
//
// For a n-band image, each band index from 0 to n-1 must appear exactly once
// in the array. If the image also has a mask, the index n must also appear exactly
Expand Down Expand Up @@ -430,6 +430,12 @@ type Config struct {

//PreloadTiles is the number of tiles to concurrently preload when writing
PreloadTiles int

//KeptOverviews if not nil represents the indices of the overviews to keep
KeptOverviews []int

//KeptMasks if not nil represents the indices of the masks to keep
KeptMasks []int
}

func DefaultConfig() Config {
Expand Down
61 changes: 59 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/airbusgeo/cogger

go 1.16
go 1.21

require (
cloud.google.com/go/storage v1.20.0
Expand All @@ -9,7 +9,7 @@ require (
github.com/argoproj/argo-workflows/v3 v3.3.9
github.com/google/tiff v0.0.0-20161109161721-4b31f3041d9a
github.com/google/uuid v1.3.0
github.com/spf13/cobra v1.5.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.8.0
github.com/tbonfort/gobs v0.0.1
go.airbusds-geo.com/gcp v0.0.8
Expand All @@ -18,3 +18,60 @@ require (
k8s.io/apimachinery v0.24.3
sigs.k8s.io/yaml v1.3.0
)

require (
cloud.google.com/go v0.100.2 // indirect
cloud.google.com/go/compute v1.3.0 // indirect
cloud.google.com/go/iam v0.1.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/airbusgeo/errs v0.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.70.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c // indirect
google.golang.org/grpc v1.44.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/client-go v0.24.3 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
)
Loading

0 comments on commit 0921ae7

Please sign in to comment.