Skip to content

Commit

Permalink
Adds Recomb for ImageRef (#377)
Browse files Browse the repository at this point in the history
* Add recombination functionality to image processing

A new function add img.Recomb support has been added to the ImageRef structure

* Add tests on ImageRef_Recomb

* Trigger CI

---------

Co-authored-by: Benny <benny.think@gmail.com>
  • Loading branch information
n0vad3v and BennyThink authored Nov 10, 2023
1 parent 1e5b2cf commit dbf5fb2
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 0 deletions.
4 changes: 4 additions & 0 deletions vips/conversion.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ int flip_image(VipsImage *in, VipsImage **out, int direction) {
return vips_flip(in, out, direction, NULL);
}

int recomb_image(VipsImage *in, VipsImage **out, VipsImage *m) {
return vips_recomb(in, out, m, NULL);
}

int extract_image_area(VipsImage *in, VipsImage **out, int left, int top,
int width, int height) {
return vips_extract_area(in, out, left, top, width, height, NULL);
Expand Down
12 changes: 12 additions & 0 deletions vips/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,18 @@ func vipsFlip(in *C.VipsImage, direction Direction) (*C.VipsImage, error) {
return out, nil
}

// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-recomb
func vipsRecomb(in *C.VipsImage, m *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("recomb")
var out *C.VipsImage

if err := C.recomb_image(in, &out, m); err != 0 {
return nil, handleImageError(out)
}

return out, nil
}

// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-extract-area
func vipsExtractArea(in *C.VipsImage, left, top, width, height int) (*C.VipsImage, error) {
incOpCounter("extractArea")
Expand Down
2 changes: 2 additions & 0 deletions vips/conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ int embed_multi_page_image_background(VipsImage *in, VipsImage **out, int left,

int flip_image(VipsImage *in, VipsImage **out, int direction);

int recomb_image(VipsImage *in, VipsImage **out, VipsImage *m);

int extract_image_area(VipsImage *in, VipsImage **out, int left, int top,
int width, int height);
int extract_area_multi_page(VipsImage *in, VipsImage **out, int left, int top,
Expand Down
49 changes: 49 additions & 0 deletions vips/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,55 @@ func (r *ImageRef) Flip(direction Direction) error {
return nil
}

// Recomb recombines the image bands using the matrix provided
func (r *ImageRef) Recomb(matrix [][]float64) error {
numBands := r.Bands()
// Ensure the provided matrix is 3x3
if len(matrix) != 3 || len(matrix[0]) != 3 || len(matrix[1]) != 3 || len(matrix[2]) != 3 {
return errors.New("Invalid recombination matrix")
}
// If the image is RGBA, expand the matrix to 4x4
if numBands == 4 {
matrix = append(matrix, []float64{0, 0, 0, 1})
for i := 0; i < 3; i++ {
matrix[i] = append(matrix[i], 0)
}
} else if numBands != 3 {
return errors.New("Unsupported number of bands")
}

// Flatten the matrix
var matrixValues []float64
for _, row := range matrix {
for _, value := range row {
matrixValues = append(matrixValues, value)
}
}

// Convert the Go slice to a C array and get its size
matrixPtr := unsafe.Pointer(&matrixValues[0])
matrixSize := C.size_t(len(matrixValues) * 8) // 8 bytes for each float64

// Create a VipsImage from the matrix in memory
matrixImage := C.vips_image_new_from_memory(matrixPtr, matrixSize, C.int(numBands), C.int(numBands), 1, C.VIPS_FORMAT_DOUBLE)

// Check for any Vips errors
errMsg := C.GoString(C.vips_error_buffer())
if errMsg != "" {
C.vips_error_clear()
return errors.New("Vips error: " + errMsg)
}

// Recombine the image using the matrix
out, err := vipsRecomb(r.image, matrixImage)
if err != nil {
return err
}

r.setImage(out)
return nil
}

// Rotate rotates the image by multiples of 90 degrees. To rotate by arbitrary angles use Similarity.
func (r *ImageRef) Rotate(angle Angle) error {
width := r.Width()
Expand Down
32 changes: 32 additions & 0 deletions vips/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,38 @@ func TestImageRef_CompositeMulti(t *testing.T) {
require.NoError(t, err)
}

func TestImageRef_Recomb(t *testing.T) {
Startup(nil)

image, err := NewImageFromFile(resources + "png-24bit.png")
require.NoError(t, err)

matrix := [][]float64{
{0.3588, 0.7044, 0.1368},
{0.2990, 0.5870, 0.1140},
{0.2392, 0.4696, 0.0912},
}

err = image.Recomb(matrix)
require.NoError(t, err)
}

func TestImageRef_Recomb_Error(t *testing.T) {
Startup(nil)

image, err := NewImageFromFile(resources + "png-24bit.png")
require.NoError(t, err)

matrix := [][]float64{
{0.3588, 0.7044, 0.1368, 0},
{0.2990, 0.5870, 0.1140, 0},
{0.2392, 0.4696, 0.0912, 0},
}

err = image.Recomb(matrix)
require.Error(t, err)
}

func TestCopy(t *testing.T) {
Startup(nil)

Expand Down

0 comments on commit dbf5fb2

Please sign in to comment.