Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi bands images #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
17 changes: 15 additions & 2 deletions vips/label.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,44 @@ int text(VipsImage **out, const char *text, const char *font, int width,
}

int label(VipsImage *in, VipsImage **out, LabelOptions *o) {
double ones[3] = {1, 1, 1};
int input_bands = vips_image_get_bands(in);
double *ones = (double *)malloc(sizeof(double) * input_bands);
for (int i = 0; i < input_bands; i++) {
ones[i] = 1.0;
}

VipsImage *base = vips_image_new();
VipsImage **t = (VipsImage **)vips_object_local_array(VIPS_OBJECT(base), 9);

if (vips_text(&t[0], o->Text, "font", o->Font, "width", o->Width, "height",
o->Height, "align", o->Align, NULL) ||
vips_linear1(t[0], &t[1], o->Opacity, 0.0, NULL) ||
vips_cast(t[1], &t[2], VIPS_FORMAT_UCHAR, NULL) ||
vips_embed(t[2], &t[3], o->OffsetX, o->OffsetY, t[2]->Xsize + o->OffsetX,
t[2]->Ysize + o->OffsetY, NULL)) {
g_object_unref(base);
free(ones);
return 1;
}

if (vips_black(&t[4], 1, 1, NULL) ||
vips_linear(t[4], &t[5], ones, o->Color, 3, NULL) ||
vips_linear(t[4], &t[5], ones, o->Color, input_bands, NULL) ||
vips_cast(t[5], &t[6], VIPS_FORMAT_UCHAR, NULL) ||
vips_copy(t[6], &t[7], "interpretation", in->Type, NULL) ||
vips_embed(t[7], &t[8], 0, 0, in->Xsize, in->Ysize, "extend",
VIPS_EXTEND_COPY, NULL)) {
g_object_unref(base);
free(ones);
return 1;
}

if (vips_ifthenelse(t[3], t[8], in, out, "blend", TRUE, NULL)) {
g_object_unref(base);
free(ones);
return 1;
}

g_object_unref(base);
free(ones);
return 0;
}