From 95b7d58c3fae2733cbd2bf7cdf5a7690f7652333 Mon Sep 17 00:00:00 2001 From: Pericles Telemachou Date: Fri, 22 Sep 2023 14:06:15 +1000 Subject: [PATCH] Split `Nearblack` into `Nearblack` and `NearblackInto` functions, add tests, add missing `Close()`s --- godal.go | 44 +++++++++++++++++++------ godal_test.go | 89 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 110 insertions(+), 23 deletions(-) diff --git a/godal.go b/godal.go index 39daced..698d877 100644 --- a/godal.go +++ b/godal.go @@ -3849,7 +3849,12 @@ func (ds *Dataset) Grid(destPath string, switches []string, opts ...GridOption) return &Dataset{majorObject{C.GDALMajorObjectH(dsRet)}}, nil } -// NearBlack runs the library version of GDALNearblack. +// `Nearblack` and `NearblackInto` run the library version of GDALNearblack. The difference between them is: +// - Nearblack: Takes a `destPath` (string) as its first arg, the produced dataset will be output to this "file" +// and returned from the function +// - NearblackInto: Instead takes a `srcDs` (Dataset) as its first arg, the produced dataset will be stored in +// the `Dataset` this method was called from +// // See the nearblack doc page to determine the valid flags/opts that can be set in switches. // // Example switches : @@ -3862,7 +3867,7 @@ func (ds *Dataset) Grid(destPath string, switches []string, opts ...GridOption) // // NOTE: Some switches are NOT compatible with this binding, as a `nullptr` is passed to a later call to // `GDALNearblackOptionsNew()` (as the 2nd argument). Those switches are: "-o", "-q", "-quiet" -func (ds *Dataset) Nearblack(destPath string, destDs *Dataset, switches []string, opts ...NearblackOption) (*Dataset, error) { +func (ds *Dataset) Nearblack(destPath string, switches []string, opts ...NearblackOption) (*Dataset, error) { nearBlackOpts := nearBlackOpts{} for _, opt := range opts { opt.setNearblackOpt(&nearBlackOpts) @@ -3872,20 +3877,39 @@ func (ds *Dataset) Nearblack(destPath string, destDs *Dataset, switches []string defer cswitches.free() dest := unsafe.Pointer(C.CString(destPath)) + defer C.free(dest) + cgc := createCGOContext(nil, nearBlackOpts.errorHandler) - defer C.free(unsafe.Pointer(dest)) - var dsRet C.GDALDatasetH - if destDs != nil { - dsRet = C.godalNearblack(cgc.cPointer(), (*C.char)(dest), destDs.handle(), ds.handle(), cswitches.cPointer()) - } else { - dsRet = C.godalNearblack(cgc.cPointer(), (*C.char)(dest), nil, ds.handle(), cswitches.cPointer()) + ret, err := C.godalNearblack(cgc.cPointer(), (*C.char)(dest), nil, ds.handle(), cswitches.cPointer()) + if err = cgc.close(); err != nil { + return nil, err + } + + return &Dataset{majorObject{C.GDALMajorObjectH(ret)}}, nil +} + +func (ds *Dataset) NearblackInto(srcDs *Dataset, switches []string, opts ...NearblackOption) error { + nearBlackOpts := nearBlackOpts{} + for _, opt := range opts { + opt.setNearblackOpt(&nearBlackOpts) + } + + cswitches := sliceToCStringArray(switches) + defer cswitches.free() + + cgc := createCGOContext(nil, nearBlackOpts.errorHandler) + + var srcDsHandle C.GDALDatasetH = nil + if srcDs != nil { + srcDsHandle = srcDs.handle() } + _ = C.godalNearblack(cgc.cPointer(), nil, ds.handle(), srcDsHandle, cswitches.cPointer()) if err := cgc.close(); err != nil { - return nil, err + return err } - return &Dataset{majorObject{C.GDALMajorObjectH(dsRet)}}, nil + return nil } type cgoContext struct { diff --git a/godal_test.go b/godal_test.go index 18831b0..e9f8bfd 100644 --- a/godal_test.go +++ b/godal_test.go @@ -4314,7 +4314,7 @@ func TestNearblackBlack(t *testing.T) { // 2. Put the Dataset generated above, through the `Nearblack` function, to set pixels near BLACK to BLACK argsNbString := "-near 10 -nb 0" fname2 := "/vsimem/test1.tiff" - nbDs, err := gridDs.Nearblack(fname2, nil, strings.Split(argsNbString, " ")) + nbDs, err := gridDs.Nearblack(fname2, strings.Split(argsNbString, " ")) if err != nil { t.Error(err) return @@ -4343,11 +4343,13 @@ func TestNearblackWhite(t *testing.T) { t.Error(err) return } + defer vrtDs.Close() geom, err := NewGeometryFromWKT("POLYGON((0 0 255, 0 1 255, 1 1 0, 1 0 0))", nil) if err != nil { t.Error(err) return } + defer geom.Close() _, err = vrtDs.CreateLayer("grid", nil, GTPolygon) if err != nil { t.Error(err) @@ -4384,7 +4386,7 @@ func TestNearblackWhite(t *testing.T) { // 2. Put the Dataset generated above, through the `Nearblack` function, to set pixels near WHITE to WHITE argsNbString := "-near 10 -nb 0 -white" fname2 := "/vsimem/test1.tiff" - nbDs, err := gridDs.Nearblack(fname2, nil, strings.Split(argsNbString, " ")) + nbDs, err := gridDs.Nearblack(fname2, strings.Split(argsNbString, " ")) if err != nil { t.Error(err) return @@ -4402,7 +4404,34 @@ func TestNearblackWhite(t *testing.T) { } } -func TestNearblackReplaceSrcDs(t *testing.T) { +func TestNearblackInvalidSwitch(t *testing.T) { + // 1. Create a linearly interpolated image that goes from white -> black, using `Grid()` + var ( + outXSize = 256 + outYSize = 256 + ) + fname := "/vsimem/test.tiff" + vrtDs, err := Create(Memory, fname, 1, Byte, outXSize, outYSize) + if err != nil { + t.Error(err) + return + } + defer func() { _ = VSIUnlink(fname) }() + defer vrtDs.Close() + + // 2. Put the Dataset generated above, through the `Nearblack` + fname2 := "/vsimem/test1.tiff" + + _, err = vrtDs.Nearblack(fname2, []string{"-invalidswitch"}) + assert.Error(t, err) + ehc := eh() + _, err = vrtDs.Nearblack(fname2, []string{"-invalidswitch"}, ErrLogger(ehc.ErrorHandler)) + assert.Error(t, err) + + defer func() { _ = VSIUnlink(fname2) }() +} + +func TestNearblackBlackInto(t *testing.T) { // 1. Create an image, linearly interpolated, from black (on the left) to white (on the right), using `Grid()` var ( outXSize = 256 @@ -4413,11 +4442,13 @@ func TestNearblackReplaceSrcDs(t *testing.T) { t.Error(err) return } + defer vrtDs.Close() geom, err := NewGeometryFromWKT("POLYGON((0 0 0, 0 1 0, 1 1 255, 1 0 255))", nil) if err != nil { t.Error(err) return } + defer geom.Close() _, err = vrtDs.CreateLayer("grid", nil, GTPolygon) if err != nil { t.Error(err) @@ -4452,16 +4483,20 @@ func TestNearblackReplaceSrcDs(t *testing.T) { gridDs.Read(0, 0, originalColors, outXSize, outYSize) // 2. Put the Dataset generated above, through the `Nearblack` function, to set pixels near BLACK to BLACK + nbDs, err := Create(Memory, "nbDs", 1, Byte, outXSize, outYSize) + if err != nil { + t.Error(err) + return + } + defer nbDs.Close() argsNbString := "-near 10 -nb 0" - fname2 := "/vsimem/test1.tiff" - _, err = gridDs.Nearblack(fname2, gridDs, strings.Split(argsNbString, " ")) + err = nbDs.NearblackInto(gridDs, strings.Split(argsNbString, " ")) if err != nil { t.Error(err) return } - defer func() { _ = VSIUnlink(fname2) }() nearblackColors := make([]byte, outXSize*outYSize) - gridDs.Read(0, 0, nearblackColors, outXSize, outYSize) + nbDs.Read(0, 0, nearblackColors, outXSize, outYSize) // 3. Test on all rows that pixels where abs(0 - pixelValue) <= 10, are set to black (0) for i := 0; i < outYSize; i++ { @@ -4471,7 +4506,7 @@ func TestNearblackReplaceSrcDs(t *testing.T) { } } -func TestNearblackInvalidSwitch(t *testing.T) { +func TestNearblackIntoInvalidSwitch(t *testing.T) { // 1. Create a linearly interpolated image that goes from white -> black, using `Grid()` var ( outXSize = 256 @@ -4487,14 +4522,42 @@ func TestNearblackInvalidSwitch(t *testing.T) { defer vrtDs.Close() // 2. Put the Dataset generated above, through the `Nearblack` - nbDs := &Dataset{} - fname2 := "/vsimem/test1.tiff" - defer func() { _ = VSIUnlink(fname2) }() + nbDs, err := Create(Memory, "nbDs", 1, Byte, outXSize, outYSize) + if err != nil { + t.Error(err) + return + } defer nbDs.Close() + err = nbDs.NearblackInto(vrtDs, []string{"-invalidswitch"}) + assert.Error(t, err) ehc := eh() - _, err = vrtDs.Nearblack(fname2, nbDs, []string{"-invalidswitch"}, ErrLogger(ehc.ErrorHandler)) + err = nbDs.NearblackInto(vrtDs, []string{"-invalidswitch"}, ErrLogger(ehc.ErrorHandler)) assert.Error(t, err) +} - _, err = vrtDs.Nearblack(fname2, nbDs, []string{"-invalidswitch"}) +func TestNearblackIntoNoSrcDs(t *testing.T) { + // 1. Create a linearly interpolated image that goes from white -> black, using `Grid()` + var ( + outXSize = 256 + outYSize = 256 + ) + fname := "/vsimem/test.tiff" + vrtDs, err := Create(Memory, fname, 1, Byte, outXSize, outYSize) + if err != nil { + t.Error(err) + return + } + defer func() { _ = VSIUnlink(fname) }() + defer vrtDs.Close() + + // 2. Put the Dataset generated above, through the `Nearblack` + nbDs, err := Create(Memory, "nbDs", 1, Byte, outXSize, outYSize) + if err != nil { + t.Error(err) + return + } + defer nbDs.Close() + ehc := eh() + err = nbDs.NearblackInto(nil, []string{}, ErrLogger(ehc.ErrorHandler)) assert.Error(t, err) }