Commit 5a565319 authored by Lucas Beeler's avatar Lucas Beeler

Adjustment palette now includes histogram slider controls (#615) that are...

Adjustment palette now includes histogram slider controls (#615) that are automatically set by auto-enhance (#681).
parent ec535051
......@@ -49,7 +49,8 @@ SRC_FILES = \
LibraryWindow.vala \
CameraTable.vala \
DirectWindow.vala \
Properties.vala
Properties.vala \
CustomComponents.vala
VAPI_FILES = \
libexif.vapi \
......
......@@ -70,7 +70,16 @@ public struct RGBAnalyticPixel {
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 bool equals(ref RGBAnalyticPixel rhs) {
return ((red == rhs.red) && (green == rhs.green) && (blue == rhs.blue));
}
public uint hash_code() {
return (((uint)(red * 255.0f)) << 16) + (((uint)(green * 255.0f)) << 8) +
((uint)(blue * 255.0f));
}
}
public struct HSVAnalyticPixel {
......@@ -199,6 +208,16 @@ public struct HSVAnalyticPixel {
return result;
}
public bool equals(ref HSVAnalyticPixel rhs) {
return ((hue == rhs.hue) && (saturation == rhs.saturation) &&
(light_value == rhs.light_value));
}
public uint hash_code() {
return (((uint)(hue * 255.0f)) << 16) + (((uint)(saturation * 255.0f)) << 8) +
((uint)(light_value * 255.0f));
}
}
public enum RGBTransformationKind {
......@@ -585,7 +604,7 @@ public class RGBTransformationFactory {
class RGBHistogram {
private const uchar MARKED_BACKGROUND = 30;
private const uchar MARKED_FOREGROUND = 210;
private const uchar UNMARKED_BACKGROUND = 40;
private const uchar UNMARKED_BACKGROUND = 120;
public const int GRAPHIC_WIDTH = 256;
public const int GRAPHIC_HEIGHT = 100;
......@@ -896,6 +915,45 @@ public abstract class IntensityTransformation {
public abstract string to_string();
}
public class NormalizationInstance {
private uchar black_point = 0;
private uchar white_point = 255;
public NormalizationInstance() {
}
public NormalizationInstance.from_extrema(int user_black_point,
int user_white_point) {
assert((user_black_point >= 0) && (user_black_point <= 255));
assert((user_white_point >= 0) && (user_white_point <= 255));
black_point = (uchar) user_black_point;
white_point = (uchar) user_white_point;
}
public bool is_identity() {
return ((black_point == 0) && (white_point == 255));
}
public int get_black_point() {
return black_point;
}
public int get_white_point() {
return white_point;
}
public void set_black_point(int user_black_point) {
assert((user_black_point >= 0) && (user_black_point <= 255));
black_point = (uchar) user_black_point;
}
public void set_white_point(int user_white_point) {
assert((user_white_point >= 0) && (user_white_point <= 255));
white_point = (uchar) user_white_point;
}
}
public class NormalizationTransformation : IntensityTransformation {
private float[] remap_table = null;
private const float LOW_DISCARD_MASS = 0.02f;
......@@ -921,6 +979,17 @@ public class NormalizationTransformation : IntensityTransformation {
build_remap_table();
}
public NormalizationTransformation.from_extrema(int black_point, int white_point) {
assert((black_point >= 0) && (black_point <= 255));
assert((white_point >= 0) && (white_point <= 255));
assert(black_point < white_point);
low_kink = black_point;
high_kink = white_point;
build_remap_table();
}
public NormalizationTransformation.from_string(string encoded_transformation) {
encoded_transformation.canon("0123456789. ", ' ');
encoded_transformation.chug();
......@@ -971,42 +1040,14 @@ public class NormalizationTransformation : IntensityTransformation {
public override string to_string() {
return "{ %d, %d }".printf(low_kink, high_kink);
}
}
public class EnhancementFactory {
private const int CURRENT_VERSION = 1;
private const int MIN_SUPPORTED_VERSION = 1;
public static int get_current_version() {
return CURRENT_VERSION;
}
public static bool is_encoding_version_supported(int encoding_version) {
if (encoding_version < MIN_SUPPORTED_VERSION)
return false;
if (encoding_version > CURRENT_VERSION)
return false;
return true;
public int get_white_point() {
return high_kink;
}
public static IntensityTransformation? create_from_encoding(int encoding_version,
string encoded_transformation) {
switch (encoding_version) {
case 1:
return new NormalizationTransformation.from_string(encoded_transformation);
default:
warning("enhancement factory: unsupported transformation encoding version");
return null;
}
}
public static IntensityTransformation create_current(Gdk.Pixbuf target) {
IntensityHistogram histogram = new IntensityHistogram(target);
return new NormalizationTransformation(histogram);
public int get_black_point() {
return low_kink;
}
}
This diff is collapsed.
......@@ -331,7 +331,7 @@ public abstract class EditingTool {
activated();
}
// Like activate(), this should always be called from an overriding subclass.
public virtual void deactivate() {
// multiple deactivates are tolerated
......@@ -1273,14 +1273,12 @@ public class AdjustTool : EditingTool {
new Gtk.Button.with_label("Reset");
public Gtk.Button cancel_button =
new Gtk.Button.from_stock(Gtk.STOCK_CANCEL);
public Gtk.Image histogram_image_tray = new Gtk.Image();
public RGBHistogramManipulator histogram_manipulator =
new RGBHistogramManipulator();
public AdjustToolWindow(Gtk.Window container) {
base(container);
histogram_image_tray.set_size_request(RGBHistogram.GRAPHIC_WIDTH,
RGBHistogram.GRAPHIC_HEIGHT);
Gtk.Table slider_organizer = new Gtk.Table(4, 2, false);
slider_organizer.set_row_spacings(12);
slider_organizer.set_col_spacings(12);
......@@ -1317,19 +1315,15 @@ public class AdjustTool : EditingTool {
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.Frame histogram_tray_wrapper = new Gtk.Frame(null);
histogram_tray_wrapper.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
histogram_tray_wrapper.add(histogram_image_tray);
Gtk.VBox pane_layouter = new Gtk.VBox(false, 8);
pane_layouter.add(histogram_tray_wrapper);
pane_layouter.add(histogram_manipulator);
pane_layouter.add(slider_organizer);
pane_layouter.add(button_layouter);
......@@ -1345,42 +1339,18 @@ public class AdjustTool : EditingTool {
private AdjustToolWindow adjust_tool_window = null;
private bool suppress_effect_redraw = false;
private Gdk.Pixbuf draw_to_pixbuf = null;
private Gdk.Pixbuf virgin_pixbuf = null;
public override void activate(PhotoCanvas canvas) {
adjust_tool_window = new AdjustToolWindow(canvas.get_container());
float exposure_param =
canvas.get_photo().get_color_adjustment(
RGBTransformationKind.EXPOSURE);
adjust_tool_window.exposure_slider.set_value(exposure_param);
float saturation_param =
canvas.get_photo().get_color_adjustment(
RGBTransformationKind.SATURATION);
adjust_tool_window.saturation_slider.set_value(saturation_param);
float tint_param =
canvas.get_photo().get_color_adjustment(
RGBTransformationKind.TINT);
adjust_tool_window.tint_slider.set_value(tint_param);
float temperature_param =
canvas.get_photo().get_color_adjustment(
RGBTransformationKind.TEMPERATURE);
adjust_tool_window.temperature_slider.set_value(temperature_param);
sync_control_state(canvas.get_photo());
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;
bind_handlers();
canvas.resized_scaled_pixbuf += on_canvas_resize;
draw_to_pixbuf = canvas.get_scaled_pixbuf().copy();
adjust_tool_window.histogram_image_tray.set_from_pixbuf(
new RGBHistogram(draw_to_pixbuf).get_graphic());
virgin_pixbuf = draw_to_pixbuf.copy();
base.activate(canvas);
}
......@@ -1396,6 +1366,7 @@ public class AdjustTool : EditingTool {
}
draw_to_pixbuf = null;
virgin_pixbuf = null;
base.deactivate();
}
......@@ -1429,7 +1400,21 @@ public class AdjustTool : EditingTool {
tint_transform);
RGBTransformation.transform_existing_pixbuf(composite_transform,
canvas.get_scaled_pixbuf(), draw_to_pixbuf);
virgin_pixbuf, draw_to_pixbuf);
int left_constraint =
adjust_tool_window.histogram_manipulator.get_left_nub_position();
int right_constraint =
adjust_tool_window.histogram_manipulator.get_right_nub_position();
adjust_tool_window.histogram_manipulator.update_histogram(draw_to_pixbuf);
if ((left_constraint > 0) || (right_constraint < 255)) {
IntensityTransformation constraint_transform =
new NormalizationTransformation.from_extrema(left_constraint, right_constraint);
IntensityTransformation.transform_pixbuf(constraint_transform, draw_to_pixbuf);
}
}
canvas.paint_pixbuf(draw_to_pixbuf);
......@@ -1438,8 +1423,7 @@ public class AdjustTool : EditingTool {
public override Gdk.Pixbuf? get_display_pixbuf(TransformablePhoto photo) {
return photo.get_pixbuf(TransformablePhoto.SCREEN, TransformablePhoto.Exception.ADJUST);
}
private void on_cancel() {
notify_cancel();
}
......@@ -1451,11 +1435,12 @@ public class AdjustTool : EditingTool {
adjust_tool_window.saturation_slider.set_value(0.0);
adjust_tool_window.temperature_slider.set_value(0.0);
adjust_tool_window.tint_slider.set_value(0.0);
adjust_tool_window.histogram_manipulator.set_left_nub_position(0);
adjust_tool_window.histogram_manipulator.set_right_nub_position(255);
suppress_effect_redraw = false;
canvas.repaint();
adjust_tool_window.histogram_image_tray.set_from_pixbuf(
new RGBHistogram(draw_to_pixbuf).get_graphic());
}
private void on_apply() {
......@@ -1480,7 +1465,7 @@ public class AdjustTool : EditingTool {
current_instance.kind = RGBTransformationKind.SATURATION;
current_instance.parameter = saturation_param;
adjustments.add(current_instance);
adjust_tool_window.exposure_slider.set_value(0.0);
float tint_param =
(float) adjust_tool_window.tint_slider.get_value();
current_instance.kind = RGBTransformationKind.TINT;
......@@ -1493,8 +1478,12 @@ public class AdjustTool : EditingTool {
current_instance.parameter = temperature_param;
adjustments.add(current_instance);
canvas.get_photo().set_color_adjustments(adjustments);
NormalizationInstance normalization_inst = new NormalizationInstance.from_extrema(
adjust_tool_window.histogram_manipulator.get_left_nub_position(),
adjust_tool_window.histogram_manipulator.get_right_nub_position());
canvas.get_photo().set_color_adjustments(adjustments, normalization_inst);
notify_apply();
AppWindow.get_instance().set_normal_cursor();
......@@ -1502,12 +1491,84 @@ public class AdjustTool : EditingTool {
private void on_adjustment() {
canvas.repaint();
adjust_tool_window.histogram_image_tray.set_from_pixbuf(
new RGBHistogram(draw_to_pixbuf).get_graphic());
}
private void on_histogram_constraint() {
canvas.repaint();
}
private void on_canvas_resize() {
draw_to_pixbuf = canvas.get_scaled_pixbuf().copy();
}
private void bind_handlers() {
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;
adjust_tool_window.histogram_manipulator.nub_position_changed +=
on_histogram_constraint;
}
private void sync_control_state(TransformablePhoto photo) {
float exposure_param =
photo.get_color_adjustment(RGBTransformationKind.EXPOSURE);
adjust_tool_window.exposure_slider.set_value(exposure_param);
float saturation_param =
photo.get_color_adjustment(RGBTransformationKind.SATURATION);
adjust_tool_window.saturation_slider.set_value(saturation_param);
float tint_param =
photo.get_color_adjustment(RGBTransformationKind.TINT);
adjust_tool_window.tint_slider.set_value(tint_param);
float temperature_param =
photo.get_color_adjustment(RGBTransformationKind.TEMPERATURE);
adjust_tool_window.temperature_slider.set_value(temperature_param);
NormalizationInstance normalization_inst =
photo.get_normalization();
adjust_tool_window.histogram_manipulator.set_left_nub_position(
normalization_inst.get_black_point());
adjust_tool_window.histogram_manipulator.set_right_nub_position(
normalization_inst.get_white_point());
}
private void set_adjustment_slider(Gtk.HScale slider, int val) {
slider.value_changed -= on_adjustment;
slider.set_value(val);
slider.value_changed += on_adjustment;
}
public void set_exposure_adjustment(int exposure) {
set_adjustment_slider(adjust_tool_window.exposure_slider, exposure);
}
public void set_saturation_adjustment(int saturation) {
set_adjustment_slider(adjust_tool_window.saturation_slider, saturation);
}
public void set_temperature_adjustment(int temp) {
set_adjustment_slider(adjust_tool_window.temperature_slider, temp);
}
public void set_tint_adjustment(int tint) {
set_adjustment_slider(adjust_tool_window.tint_slider, tint);
}
public void set_histogram_left_nub(int position) {
adjust_tool_window.histogram_manipulator.set_left_nub_position(position);
}
public void set_histogram_right_nub(int position) {
adjust_tool_window.histogram_manipulator.set_right_nub_position(position);
}
public void force_repaint() {
canvas.repaint();
}
}
......@@ -107,7 +107,6 @@ public abstract class TransformablePhoto: PhotoBase {
CROP = 1 << 1,
REDEYE = 1 << 2,
ADJUST = 1 << 3,
ENHANCE = 1 << 4,
ALL = 0xFFFFFFFF
}
......@@ -395,23 +394,13 @@ public abstract class TransformablePhoto: PhotoBase {
}
public bool has_transformations() {
// trivial check -- if the photo has been reoriented, then it has transformations
if (row.orientation != row.original_orientation)
return true;
// if execution reaches this point, we didn't return above, so perform a more
// complicated series of tests
if (row.transformations == null)
return false;
if ((row.transformations.size == 1) &&
(row.transformations.contains("enhancement")) &&
(!is_enhancement_enabled()))
return false;
// if we haven't returned by this point, then we have transformations other
// than disabled enhancement, so return true
return true;
else
return true;
}
public void remove_all_transformations() {
......@@ -519,8 +508,36 @@ public abstract class TransformablePhoto: PhotoBase {
return 0.0f;
}
}
public NormalizationInstance get_normalization() {
NormalizationInstance identity = new NormalizationInstance();
KeyValueMap map = get_transformation("adjustments");
if (map == null)
return identity;
string encoded_transformation = map.get_string("normalization", "-");
if (encoded_transformation == "-")
return identity;
encoded_transformation.canon("0123456789. ", ' ');
encoded_transformation.chug();
encoded_transformation.chomp();
int black_point_i = 0;
int white_point_i = 0;;
int num_captured = encoded_transformation.scanf("%d %d", &black_point_i,
&white_point_i);
assert(num_captured == 2);
NormalizationInstance user_transformation =
new NormalizationInstance.from_extrema(black_point_i,
white_point_i);
return user_transformation;
}
public void set_color_adjustments(Gee.ArrayList<RGBTransformationInstance?> adjustments) {
public void set_color_adjustments(Gee.ArrayList<RGBTransformationInstance?> adjustments,
NormalizationInstance? normalization_inst = null) {
KeyValueMap map = get_transformation("adjustments");
if (map == null)
map = new KeyValueMap("adjustments");
......@@ -549,6 +566,12 @@ public abstract class TransformablePhoto: PhotoBase {
}
}
if (normalization_inst != null) {
string encoded_normalization = "{ %d, %d }".printf(
normalization_inst.get_black_point(), normalization_inst.get_white_point());
map.set_string("normalization", encoded_normalization);
}
if (set_transformation(map))
notify_altered(Alteration.IMAGE);
}
......@@ -608,82 +631,6 @@ public abstract class TransformablePhoto: PhotoBase {
notify_altered(Alteration.IMAGE);
}
public void set_enhancement_enabled() {
KeyValueMap map = get_transformation("enhancement");
if (map == null) {
map = new KeyValueMap("enhancement");
}
if (!map.has_key("encoded_transformation")) {
Gdk.Pixbuf histogram_pixbuf = null;
try {
histogram_pixbuf = get_pixbuf(1024, Exception.ALL, Gdk.InterpType.HYPER);
} catch (Error e) {
error("pixbuf generation failed");
}
IntensityTransformation transform =
EnhancementFactory.create_current(histogram_pixbuf);
map.set_int("version", EnhancementFactory.get_current_version());
map.set_string("encoded_transformation", transform.to_string());
}
map.set_bool("enhanced", true);
if (set_transformation(map))
notify_altered(Alteration.IMAGE);
}
public void set_enhancement_disabled() {
KeyValueMap map = get_transformation("enhancement");
if (map == null) {
map = new KeyValueMap("enhancement");
}
map.set_bool("enhanced", false);
if (set_transformation(map))
notify_altered(Alteration.IMAGE);
}
private IntensityTransformation get_enhancement_transformation() {
assert(is_enhancement_enabled());
KeyValueMap map = get_transformation("enhancement");
assert(map != null);
assert(map.has_key("encoded_transformation"));
string encoded_transformation = map.get_string("encoded_transformation", "");
assert(encoded_transformation != "");
int version = map.get_int("version", 0);
return EnhancementFactory.create_from_encoding(version, encoded_transformation);
}
public bool is_enhancement_enabled() {
KeyValueMap map = get_transformation("enhancement");
/* if there's no enhancement group in the map, then enhancement is
disabled */
if (map == null)
return false;
/* if there is an enhancement group in the map, but the "enhanced" key
has value false, then enhancement is disabled */
if (!map.get_bool("enhanced", true))
return false;
/* if enhanced is set to true in the map, but the encoding version used
is unsupported, then enhancement is disabled */
if (!EnhancementFactory.is_encoding_version_supported(map.get_int("version", 0)))
return false;
/* otherwise, enhancement is enabled */
return true;
}
// Pixbuf generation
// Returns a raw, untransformed, unrotated, unscaled pixbuf from the source
......@@ -782,8 +729,7 @@ public abstract class TransformablePhoto: PhotoBase {
Timer timer = new Timer();
Timer total_timer = new Timer();
double load_and_decode_time = 0.0, pixbuf_copy_time = 0.0, redeye_time = 0.0,
adjustment_time = 0.0, crop_time = 0.0, orientation_time = 0.0, scale_time = 0.0,
enhance_time = 0.0;
adjustment_time = 0.0, crop_time = 0.0, orientation_time = 0.0, scale_time = 0.0;
total_timer.start();
#endif
......@@ -875,24 +821,18 @@ public abstract class TransformablePhoto: PhotoBase {
RGBTransformation composite_transform = get_composite_transformation();
if (!composite_transform.is_identity())
RGBTransformation.transform_pixbuf(composite_transform, pixbuf);
#if MEASURE_PIPELINE
adjustment_time = timer.elapsed();
#endif
}
// auto-enhancement
if ((exceptions & Exception.ENHANCE) == 0) {
#if MEASURE_PIPELINE
timer.start();
#endif
if (is_enhancement_enabled()) {
IntensityTransformation adaptive_transform =
get_enhancement_transformation();
IntensityTransformation.transform_pixbuf(adaptive_transform, pixbuf);
}
NormalizationInstance normalization_inst = get_normalization();
if (!normalization_inst.is_identity()) {
IntensityTransformation normalization_xform =
new NormalizationTransformation.from_extrema(
normalization_inst.get_black_point(),
normalization_inst.get_white_point());
IntensityTransformation.transform_pixbuf(normalization_xform,
pixbuf);
}
#if MEASURE_PIPELINE
enhance_time = timer.elapsed();
adjustment_time = timer.elapsed();
#endif
}
......@@ -910,9 +850,9 @@ public abstract class TransformablePhoto: PhotoBase {
#if MEASURE_PIPELINE
double total_time = total_timer.elapsed();
debug("PIPELINE: load_and_decode=%lf pixbuf_copy=%lf redeye=%lf crop=%lf scale=%lf adjustment=%lf enhancement=%lf orientation=%lf total=%lf",
debug("PIPELINE: load_and_decode=%lf pixbuf_copy=%lf redeye=%lf crop=%lf scale=%lf adjustment=%lf orientation=%lf total=%lf",
load_and_decode_time, pixbuf_copy_time, redeye_time, crop_time, scale_time, adjustment_time,
enhance_time, orientation_time, total_time);
orientation_time, total_time);
#endif
return pixbuf;
......
......@@ -32,7 +32,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
private Gtk.ToggleToolButton crop_button = null;
private Gtk.ToggleToolButton redeye_button = null;
private Gtk.ToggleToolButton adjust_button = null;
private Gtk.ToggleToolButton enhance_button = null;
private Gtk.ToolButton enhance_button = null;
private Gtk.ToolButton prev_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_BACK);
private Gtk.ToolButton next_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_FORWARD);
private EditingTool current_tool = null;
......@@ -43,7 +43,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
TransformablePhoto new_photo, out bool ok) {
ok = true;
}
public EditingHostPage(string name) {
base(name);
......@@ -78,10 +78,10 @@ public abstract class EditingHostPage : SinglePhotoPage {
toolbar.insert(adjust_button, -1);
// ehance tool
enhance_button = new Gtk.ToggleToolButton.from_stock(Resources.ENHANCE);
enhance_button = new Gtk.ToolButton.from_stock(Resources.ENHANCE);
enhance_button.set_label("Enhance");
enhance_button.set_tooltip_text("Automatically improve the photo's appearance");
enhance_button.toggled += on_enhance_toggled;
enhance_button.clicked += on_enhance_clicked;
toolbar.insert(enhance_button, -1);
// separator to force next/prev buttons to right side of toolbar
......@@ -201,12 +201,6 @@ public abstract class EditingHostPage : SinglePhotoPage {
private void update_ui() {
bool multiple = controller.get_count() > 1;
/* disconnect the on_enhance_toggled signal before calling set_active on the
button to avoid having on_enhance_toggled invoked twice */
enhance_button.toggled -= on_enhance_toggled;
enhance_button.set_active(photo.is_enhancement_enabled());
enhance_button.toggled += on_enhance_toggled;
prev_button.sensitive = multiple;
next_button.sensitive = multiple;
......@@ -611,16 +605,67 @@ public abstract class EditingHostPage : SinglePhotoPage {
adjust_button.set_active(false);
}
private void on_enhance_toggled() {
if (current_tool != null)
deactivate_tool();
private void on_enhance_clicked() {
AppWindow.get_instance().set_busy_cursor();
if (enhance_button.get_active()) {
photo.set_enhancement_enabled();
Gdk.Pixbuf pixbuf = null;
try {
pixbuf = photo.get_pixbuf(1024, TransformablePhoto.Exception.ALL);
} catch (Error e) {
error("PhotoPage: on_enhance_clicked: couldn't obtain pixbuf to build " +
"transform histogram");
}
/* zero out any existing color transformations as these may conflict with
auto-enhancement */
Gee.ArrayList<RGBTransformationInstance?> adjustments =
new Gee.ArrayList<RGBTransformationInstance?>();
RGBTransformationInstance current_instance = {0};
current_instance.kind = RGBTransformationKind.EXPOSURE;
current_instance.parameter = 0.0f;
adjustments.add(current_instance);
current_instance.kind = RGBTransformationKind.SATURATION;
current_instance.parameter = 0.0f;
adjustments.add(current_instance);
current_instance.kind = RGBTransformationKind.TINT;
current_instance.parameter = 0.0f;
adjustments.add(current_instance);
current_instance.kind = RGBTransformationKind.TEMPERATURE;
current_instance.parameter = 0.0f;
adjustments.add(current_instance);
/* create a new normalization transformation representing the
auto-enhancement */
NormalizationTransformation trans = new NormalizationTransformation(
new IntensityHistogram(pixbuf));
int black_point = trans.get_black_point();
int white_point = trans.get_white_point();