Skip to content

Commit

Permalink
Desaturation
Browse files Browse the repository at this point in the history
  • Loading branch information
mtgrosser committed Feb 6, 2024
1 parent 6a91d6c commit 8d184e9
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Rsze 1.5.0 (Feb 6, 2024)

* Image desaturation (grayscale)

## Rszr 1.4.0 (Jan 11, 2024)

* Fix `load_data` (@mantas)
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ image.contrast(0.5)

# gamma
image.gamma(1.1)

# convert to grayscale (automatic mode)
image.desaturate

# convert to grayscale with mode
image.desaturate(:lightness)
image.desaturate(:luminosity)
image.desaturate(:average)
```

### Image auto orientation
Expand Down
67 changes: 58 additions & 9 deletions ext/rszr/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,54 @@ static VALUE rszr_image__sharpen_bang(VALUE self, VALUE rb_radius)
}


static void rszr_desaturate_pixel(rszr_raw_pixel * pixel, int mode)
{
uint8_t grey;
if (mode == 2 || (mode == 0 && (pixel->blue > pixel->red && pixel->blue > pixel->green))) {
// lightness
grey = (pixel->blue + (pixel->red > pixel->green ? pixel->green : pixel->red)) / 2;
} else if (mode == 1 || mode == 0) {
// luminosity
grey = 0.21 * pixel->red + 0.72 * pixel->green + 0.07 * pixel->blue;
} else {
// average
grey = (pixel->red + pixel->green + pixel->blue) / 3;
}
pixel->red = grey;
pixel->green = grey;
pixel->blue = grey;
}

static VALUE rszr_image__desaturate_bang(VALUE self, VALUE rb_mode)
{
rszr_image_handle * handle;
rszr_raw_pixel * pixels;
uint64_t size;
int mode;

mode = NUM2INT(rb_mode);

Data_Get_Struct(self, rszr_image_handle, handle);

imlib_context_set_image(handle->image);

pixels = (rszr_raw_pixel *) imlib_image_get_data();
if (pixels == NULL) {
rb_raise(eRszrTransformationError, "error desaturating image");
return Qnil;
}

size = imlib_image_get_width() * imlib_image_get_height();
for (uint64_t i = 0; i < size; i++) {
rszr_desaturate_pixel(&pixels[i], mode);
}

imlib_image_put_back_data((uint32_t *) pixels);

return self;
}


static Imlib_Image rszr_create_cropped_scaled_image(const Imlib_Image image, VALUE rb_src_x, VALUE rb_src_y, VALUE rb_src_w, VALUE rb_src_h, VALUE rb_dst_w, VALUE rb_dst_h)
{
Imlib_Image resized_image;
Expand Down Expand Up @@ -688,15 +736,16 @@ void Init_rszr_image()
rb_define_protected_method(cImage, "_format", rszr_image__format_get, 0);
rb_define_protected_method(cImage, "_format=", rszr_image__format_set, 1);

rb_define_private_method(cImage, "_initialize", rszr_image__initialize, 2);
rb_define_private_method(cImage, "_resize", rszr_image__resize, 7);
rb_define_private_method(cImage, "_crop", rszr_image__crop, 5);
rb_define_private_method(cImage, "_turn!", rszr_image__turn_bang, 1);
rb_define_private_method(cImage, "_rotate", rszr_image__rotate, 2);
rb_define_private_method(cImage, "_sharpen!", rszr_image__sharpen_bang, 1);
rb_define_private_method(cImage, "_pixel", rszr_image__pixel_get, 2);
rb_define_private_method(cImage, "_blend", rszr_image__blend, 11);
rb_define_private_method(cImage, "_rectangle!", rszr_image__rectangle_bang, 5);
rb_define_private_method(cImage, "_initialize", rszr_image__initialize, 2);
rb_define_private_method(cImage, "_resize", rszr_image__resize, 7);
rb_define_private_method(cImage, "_crop", rszr_image__crop, 5);
rb_define_private_method(cImage, "_turn!", rszr_image__turn_bang, 1);
rb_define_private_method(cImage, "_rotate", rszr_image__rotate, 2);
rb_define_private_method(cImage, "_sharpen!", rszr_image__sharpen_bang, 1);
rb_define_private_method(cImage, "_desaturate!", rszr_image__desaturate_bang, 1);
rb_define_private_method(cImage, "_pixel", rszr_image__pixel_get, 2);
rb_define_private_method(cImage, "_blend", rszr_image__blend, 11);
rb_define_private_method(cImage, "_rectangle!", rszr_image__rectangle_bang, 5);

rb_define_private_method(cImage, "_save", rszr_image__save, 4);
}
Expand Down
4 changes: 4 additions & 0 deletions ext/rszr/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ typedef struct {
Imlib_Image image;
} rszr_image_handle;

typedef struct {
uint8_t blue, green, red, alpha; //alpha, red, green, blue;
} rszr_raw_pixel;

extern VALUE cImage;

void Init_rszr_image();
Expand Down
11 changes: 11 additions & 0 deletions lib/rszr/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Rszr
class Image
GRAVITIES = [true, :center, :n, :nw, :w, :sw, :s, :se, :e, :ne].freeze
BLENDING_MODES = %i[copy add subtract reshade].freeze
DESATURATION_MODES = %i[dynamic luminosity lightness average].freeze

extend Identification
include Buffered
Expand Down Expand Up @@ -119,6 +120,16 @@ def blur!(radius)
_sharpen!(-radius)
end

def desaturate!(mode = :dynamic)
_mode = DESATURATION_MODES.index(mode)
raise ArgumentError, 'illegal mode' unless _mode
_desaturate!(_mode);
end

def desaturate(*args, **opts)
dup.desaturate!(*args, **opts)
end

def filter(filter_expr)
dup.filter!(filter_expr)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rszr/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Rszr
VERSION = '1.4.0'
VERSION = '1.5.0'
end
10 changes: 10 additions & 0 deletions spec/rszr_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,16 @@
it 'filters' do
expect(@image.filter('bump_map( map=tint(red=50,tint=200), blue=10 );').dimensions).to eq(@image.dimensions)
end

%i[dynamic luminosity lightness average].each do |mode|
it "desaturates in mode #{mode}" do
@image.desaturate!(mode)
pixel = @image[500, 500]
expect(pixel.red).to eq(pixel.green)
expect(pixel.blue).to eq(pixel.red)
end
end

end

end

0 comments on commit 8d184e9

Please sign in to comment.