Commit d13e7a3b authored by Lucas Beeler's avatar Lucas Beeler

#78: added adjust control manipulating exposure, saturation, temperature and tint

parent 176c2ef7
......@@ -44,6 +44,7 @@ SRC_FILES = \
Resources.vala \
Debug.vala \
Sidebar.vala \
ColorTransformation.vala \
EditingTools.vala
VAPI_FILES = \
......
/* Copyright 2009 Yorba Foundation
*
* This software is licensed under the GNU LGPL (version 2.1 or later).
* See the COPYING file in this distribution.
*/
public struct AnalyticPixel {
public float red;
public float green;
public float blue;
public AnalyticPixel() {
red = 0.0f;
green = 0.0f;
blue = 0.0f;
}
public AnalyticPixel.from_components(float red, float green,
float blue) {
this.red = red.clamp(0.0f, 1.0f);
this.green = green.clamp(0.0f, 1.0f);
this.blue = blue.clamp(0.0f, 1.0f);
}
public AnalyticPixel.from_quantized_components(uchar red_quantized,
uchar green_quantized, uchar blue_quantized) {
this.red = ((float) red_quantized) / 255.0f;
this.green = ((float) green_quantized) / 255.0f;
this.blue = ((float) blue_quantized) / 255.0f;
}
public uchar quantized_red() {
return (uchar)(red * 255.0f);
}
public uchar quantized_green() {
return (uchar)(green * 255.0f);
}
public uchar quantized_blue() {
return (uchar)(blue * 255.0f);
}
public static AnalyticPixel get_pixbuf_pixel(owned Gdk.Pixbuf pixbuf,
int x, int y) {
assert((x >= 0) && (x < pixbuf.width));
assert((y >= 0) && (y < pixbuf.height));
int px_start_byte_offset = (y * pixbuf.rowstride) + (x *
pixbuf.n_channels);
unowned uchar[] pixel_data = pixbuf.get_pixels();
return AnalyticPixel.from_quantized_components(
pixel_data[px_start_byte_offset],
pixel_data[px_start_byte_offset + 1],
pixel_data[px_start_byte_offset + 2]);
}
public static void set_pixbuf_pixel(owned Gdk.Pixbuf pixbuf,
AnalyticPixel pixel, int x, int y) {
assert((x >= 0) && (x < pixbuf.width));
assert((y >= 0) && (y < pixbuf.height));
int px_start_byte_offset = (y * pixbuf.rowstride) + (x *
pixbuf.n_channels);
unowned uchar[] pixel_data = pixbuf.get_pixels();
pixel_data[px_start_byte_offset] = pixel.quantized_red();
pixel_data[px_start_byte_offset + 1] = pixel.quantized_green();
pixel_data[px_start_byte_offset + 2] = pixel.quantized_blue();
}
}
public enum ColorTransformationKind {
EXPOSURE,
SATURATION,
TINT,
TEMPERATURE
}
public struct ColorTransformationInstance {
public ColorTransformationKind kind;
public float parameter;
}
public class ColorTransformation {
/* matrix entries are stored in row-major; by default, the matrix formed
by matrix_entries is the 4x4 identity matrix */
protected float[] matrix_entries = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
protected bool identity = true;
public ColorTransformation() {
}
public bool is_identity() {
return identity;
}
public AnalyticPixel transform_pixel(AnalyticPixel pixel) {
float red_out = (pixel.red * matrix_entries[0]) +
(pixel.green * matrix_entries[1]) +
(pixel.blue * matrix_entries[2]) +
matrix_entries[3];
red_out = red_out.clamp(0.0f, 1.0f);
float green_out = (pixel.red * matrix_entries[4]) +
(pixel.green * matrix_entries[5]) +
(pixel.blue * matrix_entries[6]) +
matrix_entries[7];
green_out = green_out.clamp(0.0f, 1.0f);
float blue_out = (pixel.red * matrix_entries[8]) +
(pixel.green * matrix_entries[9]) +
(pixel.blue * matrix_entries[10]) +
matrix_entries[11];
blue_out = blue_out.clamp(0.0f, 1.0f);
return AnalyticPixel.from_components(red_out, green_out, blue_out);
}
public ColorTransformation compose_against(ColorTransformation transform) {
ColorTransformation result = new ColorTransformation();
/* row 0 */
result.matrix_entries[0] =
(matrix_entries[0] * transform.matrix_entries[0]) +
(matrix_entries[1] * transform.matrix_entries[4]) +
(matrix_entries[2] * transform.matrix_entries[8]) +
(matrix_entries[3] * transform.matrix_entries[12]);
result.matrix_entries[1] =
(matrix_entries[0] * transform.matrix_entries[1]) +
(matrix_entries[1] * transform.matrix_entries[5]) +
(matrix_entries[2] * transform.matrix_entries[9]) +
(matrix_entries[3] * transform.matrix_entries[13]);
result.matrix_entries[2] =
(matrix_entries[0] * transform.matrix_entries[2]) +
(matrix_entries[1] * transform.matrix_entries[6]) +
(matrix_entries[2] * transform.matrix_entries[10]) +
(matrix_entries[3] * transform.matrix_entries[14]);
result.matrix_entries[3] =
(matrix_entries[0] * transform.matrix_entries[3]) +
(matrix_entries[1] * transform.matrix_entries[7]) +
(matrix_entries[2] * transform.matrix_entries[11]) +
(matrix_entries[3] * transform.matrix_entries[15]);
/* row 1 */
result.matrix_entries[4] =
(matrix_entries[4] * transform.matrix_entries[0]) +
(matrix_entries[5] * transform.matrix_entries[4]) +
(matrix_entries[6] * transform.matrix_entries[8]) +
(matrix_entries[7] * transform.matrix_entries[12]);
result.matrix_entries[5] =
(matrix_entries[4] * transform.matrix_entries[1]) +
(matrix_entries[5] * transform.matrix_entries[5]) +
(matrix_entries[6] * transform.matrix_entries[9]) +
(matrix_entries[7] * transform.matrix_entries[13]);
result.matrix_entries[6] =
(matrix_entries[4] * transform.matrix_entries[2]) +
(matrix_entries[5] * transform.matrix_entries[6]) +
(matrix_entries[6] * transform.matrix_entries[10]) +
(matrix_entries[7] * transform.matrix_entries[14]);
result.matrix_entries[7] =
(matrix_entries[4] * transform.matrix_entries[3]) +
(matrix_entries[5] * transform.matrix_entries[7]) +
(matrix_entries[6] * transform.matrix_entries[11]) +
(matrix_entries[7] * transform.matrix_entries[15]);
/* row 2 */
result.matrix_entries[8] =
(matrix_entries[8] * transform.matrix_entries[0]) +
(matrix_entries[9] * transform.matrix_entries[4]) +
(matrix_entries[10] * transform.matrix_entries[8]) +
(matrix_entries[11] * transform.matrix_entries[12]);
result.matrix_entries[9] =
(matrix_entries[8] * transform.matrix_entries[1]) +
(matrix_entries[9] * transform.matrix_entries[5]) +
(matrix_entries[10] * transform.matrix_entries[9]) +
(matrix_entries[11] * transform.matrix_entries[13]);
result.matrix_entries[10] =
(matrix_entries[8] * transform.matrix_entries[2]) +
(matrix_entries[9] * transform.matrix_entries[6]) +
(matrix_entries[10] * transform.matrix_entries[10]) +
(matrix_entries[11] * transform.matrix_entries[14]);
result.matrix_entries[11] =
(matrix_entries[8] * transform.matrix_entries[3]) +
(matrix_entries[9] * transform.matrix_entries[7]) +
(matrix_entries[10] * transform.matrix_entries[11]) +
(matrix_entries[11] * transform.matrix_entries[15]);
/* row 3 */
result.matrix_entries[12] =
(matrix_entries[12] * transform.matrix_entries[0]) +
(matrix_entries[13] * transform.matrix_entries[4]) +
(matrix_entries[14] * transform.matrix_entries[8]) +
(matrix_entries[15] * transform.matrix_entries[12]);
result.matrix_entries[13] =
(matrix_entries[12] * transform.matrix_entries[1]) +
(matrix_entries[13] * transform.matrix_entries[5]) +
(matrix_entries[14] * transform.matrix_entries[9]) +
(matrix_entries[15] * transform.matrix_entries[13]);
result.matrix_entries[14] =
(matrix_entries[12] * transform.matrix_entries[2]) +
(matrix_entries[13] * transform.matrix_entries[6]) +
(matrix_entries[14] * transform.matrix_entries[10]) +
(matrix_entries[15] * transform.matrix_entries[14]);
result.matrix_entries[15] =
(matrix_entries[12] * transform.matrix_entries[3]) +
(matrix_entries[13] * transform.matrix_entries[7]) +
(matrix_entries[14] * transform.matrix_entries[11]) +
(matrix_entries[15] * transform.matrix_entries[15]);
if (!identity) {
result.identity = false;
}
if (!transform.identity) {
result.identity = false;
}
return result;
}
public static void transform_pixbuf(ColorTransformation transform,
owned Gdk.Pixbuf pixbuf) {
for (int j = 0; j < pixbuf.height; j++) {
for (int i = 0; i < pixbuf.width; i++) {
AnalyticPixel pixel_ij =
AnalyticPixel.get_pixbuf_pixel(pixbuf, i, j);
AnalyticPixel pixel_ij_transformed =
transform.transform_pixel(pixel_ij);
AnalyticPixel.set_pixbuf_pixel(pixbuf, pixel_ij_transformed,
i, j);
}
}
}
public static void transform_existing_pixbuf(ColorTransformation transform,
owned Gdk.Pixbuf in_pixbuf, owned Gdk.Pixbuf out_pixbuf) {
assert((in_pixbuf.width == out_pixbuf.width) && (in_pixbuf.height ==
out_pixbuf.height));
for (int j = 0; j < in_pixbuf.height; j++) {
for (int i = 0; i < in_pixbuf.width; i++) {
AnalyticPixel pixel_ij =
AnalyticPixel.get_pixbuf_pixel(in_pixbuf, i, j);
AnalyticPixel pixel_ij_transformed =
transform.transform_pixel(pixel_ij);
AnalyticPixel.set_pixbuf_pixel(out_pixbuf, pixel_ij_transformed,
i, j);
}
}
}
}
public class ExposureTransformation : ColorTransformation {
private const float EPSILON = 0.08f;
private const float PARAMETER_SCALE = (1.0f / 32.0f);
public const float MIN_PARAMETER = -16.0f;
public const float MAX_PARAMETER = 16.0f;
public ExposureTransformation(float parameter) {
base();
assert((parameter >= MIN_PARAMETER) && (parameter <= MAX_PARAMETER));
if (parameter != 0.0f) {
parameter *= PARAMETER_SCALE;
if (parameter < 0.0f)
parameter = 1.0f / (-parameter + 1.0f);
else
parameter += 1.0f;
matrix_entries[0] = parameter;
matrix_entries[5] = parameter;
matrix_entries[10] = parameter;
matrix_entries[3] = parameter * EPSILON;
matrix_entries[7] = parameter * EPSILON;
matrix_entries[11] = parameter * EPSILON;
identity = false;
}
}
}
public class SaturationTransformation : ColorTransformation {
private enum WeightKind { NTSC, LINEAR, FLAT }
private const float NTSC_WEIGHT_RED = 0.299f;
private const float NTSC_WEIGHT_GREEN = 0.587f;
private const float NTSC_WEIGHT_BLUE = 0.114f;
private const float LINEAR_WEIGHT_RED = 0.3086f;
private const float LINEAR_WEIGHT_GREEN = 0.6094f;
private const float LINEAR_WEIGHT_BLUE = 0.0820f;
private const float FLAT_WEIGHT_RED = 0.333f;
private const float FLAT_WEIGHT_GREEN = 0.333f;
private const float FLAT_WEIGHT_BLUE = 0.333f;
public const float MIN_PARAMETER = -16.0f;
public const float MAX_PARAMETER = 16.0f;
private WeightKind weight_kind = WeightKind.FLAT;
public SaturationTransformation(float parameter) {
base();
assert((parameter >= MIN_PARAMETER) && (parameter <= MAX_PARAMETER));
if (parameter != 0.0f) {
float adjusted_param = parameter / MAX_PARAMETER;
adjusted_param += 1.0f;
float red_weight = 0.0f;
float green_weight = 0.0f;
float blue_weight = 0.0f;
if (weight_kind == WeightKind.NTSC) {
red_weight = NTSC_WEIGHT_RED;
green_weight = NTSC_WEIGHT_GREEN;
blue_weight = NTSC_WEIGHT_BLUE;
} else if (weight_kind == WeightKind.LINEAR) {
red_weight = LINEAR_WEIGHT_RED;
green_weight = LINEAR_WEIGHT_GREEN;
blue_weight = LINEAR_WEIGHT_BLUE;
} else if (weight_kind == WeightKind.FLAT) {
red_weight = FLAT_WEIGHT_RED;
green_weight = FLAT_WEIGHT_GREEN;
blue_weight = FLAT_WEIGHT_BLUE;
} else {
error("unrecognized weight kind.\n");
}
matrix_entries[0] = ((1.0f - adjusted_param) * red_weight) +
adjusted_param;
matrix_entries[1] = (1.0f - adjusted_param) * red_weight;
matrix_entries[2] = (1.0f - adjusted_param) * red_weight;
matrix_entries[4] = (1.0f - adjusted_param) * green_weight;
matrix_entries[5] = ((1.0f - adjusted_param) * green_weight) +
adjusted_param;
matrix_entries[6] = (1.0f - adjusted_param) * green_weight;
matrix_entries[8] = (1.0f - adjusted_param) * blue_weight;
matrix_entries[9] = (1.0f - adjusted_param) * blue_weight;
matrix_entries[10] = ((1.0f - adjusted_param) * blue_weight) +
adjusted_param;
identity = false;
}
}
}
public class TemperatureTransformation : ColorTransformation {
private const float INTENSITY_FACTOR = 0.33;
public const float MIN_PARAMETER = -16.0f;
public const float MAX_PARAMETER = 16.0f;
public TemperatureTransformation(float parameter) {
base();
assert((parameter >= MIN_PARAMETER) && (parameter <= MAX_PARAMETER));
if (parameter != 0.0f) {
float adjusted_param = parameter / MAX_PARAMETER;
adjusted_param *= INTENSITY_FACTOR;
matrix_entries[11] -= adjusted_param;
matrix_entries[7] += (adjusted_param / 2);
matrix_entries[3] += (adjusted_param / 2);
identity = false;
}
}
}
public class TintTransformation : ColorTransformation {
private const float INTENSITY_FACTOR = 0.25;
public const float MIN_PARAMETER = -16.0f;
public const float MAX_PARAMETER = 16.0f;
public TintTransformation(float parameter) {
base();
assert((parameter >= MIN_PARAMETER) && (parameter <= MAX_PARAMETER));
if (parameter != 0.0f) {
float adjusted_param = parameter / MAX_PARAMETER;
adjusted_param *= INTENSITY_FACTOR;
matrix_entries[11] -= (adjusted_param / 2);
matrix_entries[7] += adjusted_param;
matrix_entries[3] -= (adjusted_param / 2);
identity = false;
}
}
}
public class ColorTransformationFactory {
private static ColorTransformationFactory instance = null;
public ColorTransformationFactory() {
}
public static ColorTransformationFactory get_instance() {
if (instance == null)
instance = new ColorTransformationFactory();
return instance;
}
public ColorTransformation from_parameter(ColorTransformationKind kind,
float parameter) {
switch (kind) {
case ColorTransformationKind.EXPOSURE:
return new ExposureTransformation((float) parameter);
case ColorTransformationKind.SATURATION:
return new SaturationTransformation((float) parameter);
case ColorTransformationKind.TINT:
return new TintTransformation((float) parameter);
case ColorTransformationKind.TEMPERATURE:
return new TemperatureTransformation((float) parameter);
default:
error("unrecognized ColorTransformationKind enumeration value");
break;
}
return new ColorTransformation();
}
}
......@@ -579,7 +579,7 @@ public class PhotoTable : DatabaseTable {
return true;
}
private string? get_raw_transformations(PhotoID photo_id) {
Sqlite.Statement stmt;
if (!select_by_id(photo_id.id, "transformations", out stmt))
......@@ -588,7 +588,7 @@ public class PhotoTable : DatabaseTable {
string trans = stmt.column_text(0);
if (trans != null && trans.length == 0)
return null;
return trans;
}
......@@ -608,7 +608,7 @@ public class PhotoTable : DatabaseTable {
return false;
}
return true;
}
......
......@@ -450,7 +450,6 @@ public class CropTool : EditingTool {
crop_tool_window = new CropToolWindow(canvas.get_container());
crop_tool_window.apply_button.clicked += on_crop_apply;
crop_tool_window.cancel_button.clicked += notify_cancel;
crop_tool_window.show_all();
// obtain crop dimensions and paint against the uncropped photo
Dimensions uncropped_dim = canvas.get_photo().get_uncropped_dimensions();
......@@ -1045,7 +1044,7 @@ public class RedeyeTool : EditingTool {
private Gdk.Cursor cached_arrow_cursor;
private Gdk.Cursor cached_grab_cursor;
private Gdk.Rectangle old_scaled_pixbuf_position;
private RedeyeInstance new_interaction_instance(PhotoCanvas canvas) {
Gdk.Rectangle photo_bounds = canvas.get_scaled_pixbuf_position();
Gdk.Point photo_center = {0};
......@@ -1158,11 +1157,10 @@ public class RedeyeTool : EditingTool {
redeye_tool_window.slider.change_value += on_size_slider_adjust;
redeye_tool_window.apply_button.clicked += on_apply;
redeye_tool_window.close_button.clicked += notify_cancel;
redeye_tool_window.show_all();
cached_arrow_cursor = new Gdk.Cursor(Gdk.CursorType.ARROW);
cached_grab_cursor = new Gdk.Cursor(Gdk.CursorType.FLEUR);
base.activate(canvas);
}
......@@ -1253,3 +1251,254 @@ public class RedeyeTool : EditingTool {
}
}
public class AdjustTool : EditingTool {
const int SLIDER_MIN_VALUE = -16;
const int SLIDER_MAX_VALUE = 16;
const int SLIDER_WIDTH = 160;
private class AdjustToolWindow : EditingToolWindow {
public Gtk.HScale exposure_slider = new Gtk.HScale.with_range(
SLIDER_MIN_VALUE, SLIDER_MAX_VALUE, 1.0);
public Gtk.HScale saturation_slider = new Gtk.HScale.with_range(
SLIDER_MIN_VALUE, SLIDER_MAX_VALUE, 1.0);
public Gtk.HScale tint_slider = new Gtk.HScale.with_range(
SLIDER_MIN_VALUE, SLIDER_MAX_VALUE, 1.0);
public Gtk.HScale temperature_slider = new Gtk.HScale.with_range(
SLIDER_MIN_VALUE, SLIDER_MAX_VALUE, 1.0);
public Gtk.Button apply_button =
new Gtk.Button.from_stock(Gtk.STOCK_APPLY);
public Gtk.Button reset_button =
new Gtk.Button.with_label("Reset");
public Gtk.Button cancel_button =
new Gtk.Button.from_stock(Gtk.STOCK_CANCEL);
public AdjustToolWindow(Gtk.Window container) {
base(container);
Gtk.Table slider_organizer = new Gtk.Table(4, 2, false);
slider_organizer.set_row_spacings(12);
slider_organizer.set_col_spacings(12);
Gtk.Label exposure_label = new Gtk.Label.with_mnemonic("Exposure:");
exposure_label.set_alignment(0.0f, 0.5f);
slider_organizer.attach_defaults(exposure_label, 0, 1, 0, 1);
slider_organizer.attach_defaults(exposure_slider, 1, 2, 0, 1);
exposure_slider.set_size_request(SLIDER_WIDTH, -1);
exposure_slider.set_draw_value(false);
exposure_slider.set_update_policy(Gtk.UpdateType.DISCONTINUOUS);
Gtk.Label saturation_label = new Gtk.Label.with_mnemonic("Saturation:");
saturation_label.set_alignment(0.0f, 0.5f);
slider_organizer.attach_defaults(saturation_label, 0, 1, 1, 2);
slider_organizer.attach_defaults(saturation_slider, 1, 2, 1, 2);
saturation_slider.set_size_request(SLIDER_WIDTH, -1);
saturation_slider.set_draw_value(false);
saturation_slider.set_update_policy(Gtk.UpdateType.DISCONTINUOUS);
Gtk.Label tint_label = new Gtk.Label.with_mnemonic("Tint:");
tint_label.set_alignment(0.0f, 0.5f);
slider_organizer.attach_defaults(tint_label, 0, 1, 2, 3);
slider_organizer.attach_defaults(tint_slider, 1, 2, 2, 3);
tint_slider.set_size_request(SLIDER_WIDTH, -1);
tint_slider.set_draw_value(false);
tint_slider.set_update_policy(Gtk.UpdateType.DISCONTINUOUS);
Gtk.Label temperature_label =
new Gtk.Label.with_mnemonic("Temperature:");
temperature_label.set_alignment(0.0f, 0.5f);
slider_organizer.attach_defaults(temperature_label, 0, 1, 3, 4);
slider_organizer.attach_defaults(temperature_slider, 1, 2, 3, 4);
temperature_slider.set_size_request(SLIDER_WIDTH, -1);
temperature_slider.set_draw_value(false);
temperature_slider.set_update_policy(Gtk.UpdateType.DISCONTINUOUS);
Gtk.HBox button_layouter = new Gtk.HBox(false, 8);
button_layouter.set_homogeneous(true);
button_layouter.pack_start(cancel_button, true, true, 1);
button_layouter.pack_start(reset_button, true, true, 1);
button_layouter.pack_start(apply_button, true, true, 1);
Gtk.VBox pane_layouter = new Gtk.VBox(false, 8);
pane_layouter.add(slider_organizer);
pane_layouter.add(button_layouter);
exposure_slider.set_value(0.0);
saturation_slider.set_value(0.0);
tint_slider.set_value(0.0);
temperature_slider.set_value(0.0);
add(pane_layouter);
}
}
private AdjustToolWindow adjust_tool_window = null;
private bool suppress_effect_redraw = false;
private Gdk.Pixbuf draw_to_pixbuf = null;
public override void activate(PhotoCanvas canvas) {
adjust_tool_window = new AdjustToolWindow(canvas.get_container());
float exposure_param =
canvas.get_photo().get_adjustment_parameter(
ColorTransformationKind.EXPOSURE);
adjust_tool_window.exposure_slider.set_value(exposure_param);
float saturation_param =
canvas.get_photo().get_adjustment_parameter(
ColorTransformationKind.SATURATION);
adjust_tool_window.saturation_slider.set_value(saturation_param);
float tint_param =
canvas.get_photo().get_adjustment_parameter(
ColorTransformationKind.TINT);
adjust_tool_window.tint_slider.set_value(tint_param);
float temperature_param =
canvas.get_photo().get_adjustment_parameter(
ColorTransformationKind.TEMPERATURE);
adjust_tool_window.temperature_slider.set_value(temperature_param);
adjust_tool_window.apply_button.clicked += on_apply;
adjust_tool_window.reset_button.clicked += on_reset;
adjust_tool_window.cancel_button.clicked += on_cancel;
adjust_tool_window.exposure_slider.value_changed += on_adjustment;
adjust_tool_window.saturation_slider.value_changed +=
on_adjustment;
adjust_tool_window.tint_slider.value_changed += on_adjustment;
adjust_tool_window.temperature_slider.value_changed +=
on_adjustment;
canvas.resized_scaled_pixbuf += on_canvas_resize;
draw_to_pixbuf = canvas.get_scaled_pixbuf().copy();
base.activate(canvas);
}
public override EditingToolWindow? get_tool_window() {
return adjust_tool_window;
}
public override void deactivate() {
if (adjust_tool_window != null) {
adjust_tool_window.hide();
adjust_tool_window = null;
}
draw_to_pixbuf = null;
base.deactivate();
}
public override void paint(Gdk.GC gc, Gdk.Drawable drawable) {
if (!suppress_effect_redraw) {
ColorTransformation tint_transform =
ColorTransformationFactory.get_instance().from_parameter(
ColorTransformationKind.TINT,
(float) adjust_tool_window.tint_slider.get_value());
ColorTransformation temperature_transform =
ColorTransformationFactory.get_instance().from_parameter(
ColorTransformationKind.TEMPERATURE,
(float) adjust_tool_window.temperature_slider.get_value());
ColorTransformation saturation_transform =
ColorTransformationFactory.get_instance().from_parameter(
ColorTransformationKind.SATURATION,
(float) adjust_tool_window.saturation_slider.get_value());
ColorTransformation exposure_transform =
ColorTransformationFactory.get_instance().from_parameter(
ColorTransformationKind.EXPOSURE,
(float) adjust_tool_window.exposure_slider.get_value());
ColorTransformation composite_transform = ((
exposure_transform.compose_against(
saturation_transform)).compose_against(
temperature_transform)).compose_against(
tint_transform);
ColorTransformation.transform_existing_pixbuf(composite_transform,
canvas.get_scaled_pixbuf(), draw_to_pixbuf);
}
canvas.paint_pixbuf(draw_to_pixbuf);
}
public override Gdk.Pixbuf? get_unscaled_pixbuf(Photo photo) {
return photo.get_pixbuf(Photo.EXCEPTION_ADJUST);
}
private void on_cancel() {
notify_cancel();
}
private void on_reset() {
suppress_effect_redraw = true;
adjust_tool_window.exposure_slider.set_value