diff options
Diffstat (limited to 'src/_transformation.c')
-rw-r--r-- | src/_transformation.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/_transformation.c b/src/_transformation.c new file mode 100644 index 0000000..7c5a7b0 --- /dev/null +++ b/src/_transformation.c @@ -0,0 +1,180 @@ +/* Copyright 2016 Software Freedom Conservancy Inc. + * Copyright 2017 Jens Georg <mail@jensge.org> + * + * This software is licensed under the GNU LGPL (version 2.1 or later). + * See the COPYING file in this distribution. + */ + +#include "shotwell-graphics-processor.h" + +static inline void _pixel_transformer_apply_transformations (PixelTransformer* self, RGBAnalyticPixel* p, RGBAnalyticPixel* result) { + PixelFormat current_format = PIXEL_FORMAT_RGB; + RGBAnalyticPixel p_rgb = {p->red, p->green, p->blue }; + HSVAnalyticPixel p_hsv = {0.0f, 0.0f, 0.0f}; + gint i = 0; + + for (i = 0; i < self->optimized_slots_used; i++) { + PixelTransformation* trans = NULL; + PixelFormat preferred_format; + + trans = self->optimized_transformations[i]; + preferred_format = pixel_transformation_get_preferred_format (trans); + if (preferred_format == PIXEL_FORMAT_RGB) { + RGBAnalyticPixel _tmp14_ = {0}; + if (current_format == PIXEL_FORMAT_HSV) { + hsv_analytic_pixel_to_rgb (&p_hsv, &p_rgb); + current_format = PIXEL_FORMAT_RGB; + } + pixel_transformation_transform_pixel_rgb (trans, &p_rgb, &_tmp14_); + p_rgb.red =_tmp14_.red; + p_rgb.green =_tmp14_.green; + p_rgb.blue =_tmp14_.blue; + } else { + HSVAnalyticPixel _tmp19_ = {0}; + if (current_format == PIXEL_FORMAT_RGB) { + rgb_analytic_pixel_to_hsv (&p_rgb, &p_hsv); + current_format = PIXEL_FORMAT_HSV; + } + pixel_transformation_transform_pixel_hsv (trans, &p_hsv, &_tmp19_); + p_hsv.hue = _tmp19_.hue; + p_hsv.saturation = _tmp19_.saturation; + p_hsv.light_value = _tmp19_.light_value; + } + } + + if (current_format == PIXEL_FORMAT_HSV) { + hsv_analytic_pixel_to_rgb (&p_hsv, &p_rgb); + } + + result->red = p_rgb.red; + result->green = p_rgb.green; + result->blue = p_rgb.blue; +} + +void pixel_transformer_apply_transformations (PixelTransformer* self, RGBAnalyticPixel* p, RGBAnalyticPixel* result) { + _pixel_transformer_apply_transformations (self, p, result); +} + +void pixel_transformer_apply_transformation (PixelTransformer* self, + guint row, + gint rowstride, + gint rowbytes, + gint n_channels, + guchar* source_pixels, int source_pixels_length1, + guchar* dest_pixels, int dest_pixels_length1) { + guint row_start_index = row * rowstride; + guint row_end_index = row_start_index + rowbytes; + guint i = 0; + + for (i = row_start_index; i < row_end_index; i += n_channels) { + RGBAnalyticPixel current_pixel = { rgb_lookup_table[source_pixels[i]], + rgb_lookup_table[source_pixels[i+1]], + rgb_lookup_table[source_pixels[i+2]] }; + RGBAnalyticPixel transformed_pixel = { 0.0f, 0.0f, 0.0f }; + _pixel_transformer_apply_transformations (self, ¤t_pixel, &transformed_pixel); + dest_pixels[i] = (guchar) (transformed_pixel.red * 255.0f); + dest_pixels[i+1] = (guchar) (transformed_pixel.green * 255.0f); + dest_pixels[i+2] = (guchar) (transformed_pixel.blue * 255.0f); + } +} + +void hsv_analytic_pixel_to_rgb (HSVAnalyticPixel *self, RGBAnalyticPixel* result) { + if (self->saturation == 0.0f) { + result->red = self->light_value; + result->green = self->light_value; + result->blue = self->light_value; + + return; + } + + float hue_denorm = self->hue * 360.0f; + if (hue_denorm == 360.0f) + hue_denorm = 0.0f; + + float hue_hexant = hue_denorm / 60.0f; + int hexant_i_part = (int) hue_hexant; + float hexant_f_part = hue_hexant - ((float) hexant_i_part); + + float p = self->light_value * (1.0f - self->saturation); + float q = self->light_value * (1.0f - (self->saturation * hexant_f_part)); + float t = self->light_value * (1.0f - (self->saturation * (1.0f - hexant_f_part))); + + switch (hexant_i_part) { + case 0: + result->red = self->light_value; result->green = t; result->blue = p; + break; + case 1: + result->red = q; result->green = self->light_value; result->blue = p; + break; + case 2: + result->red = p; result->green = self->light_value; result->blue = t; + break; + case 3: + result->red = p; result->green = q; result->blue = self->light_value; + break; + case 4: + result->red = t; result->green = p; result->blue = self->light_value; + break; + case 5: + result->red = self->light_value; result->green = p; result->blue = q; + break; + default: + g_assert_not_reached(); + } +} + +void hsv_analytic_pixel_init_from_rgb (HSVAnalyticPixel *self, RGBAnalyticPixel* p) { + gfloat max_component = MAX(MAX(p->red, p->green), p->blue); + gfloat min_component = MIN(MIN(p->red, p->green), p->blue); + + self->light_value = max_component; + gfloat delta = max_component - min_component; + self->saturation = (max_component != 0.0f) ? ((delta) / max_component) : 0.0f; + if (self->saturation == 0.0f) { + self->hue = 0.0f; + + return; + } + + if (p->red == max_component) { + self->hue = (p->green - p->blue) / delta; + } else if (p->green == max_component) { + self->hue = 2.0f + ((p->blue - p->red) / delta); + } else if (p->blue == max_component) { + self->hue = 4.0f + ((p->red - p->green) / delta); + } + + self->hue *= 60.0f; + if (self->hue < 0.0f) { + self->hue += 360.0f; + } + + self->hue /= 360.0f; + self->hue = CLAMP(self->hue, 0.0f, 1.0f); + self->saturation = CLAMP(self->saturation, 0.0f, 1.0f); + self->light_value = CLAMP(self->light_value, 0.0f, 1.0f); +} + +void rgb_transformation_real_transform_pixel_rgb (PixelTransformation* base, RGBAnalyticPixel* p, RGBAnalyticPixel* result) { + RGBTransformation *self = RGB_TRANSFORMATION(base); + result->red = CLAMP(p->red * self->matrix_entries[0] + + p->green * self->matrix_entries[1] + + p->blue * self->matrix_entries[2] + + self->matrix_entries[3], 0.0f, 1.0f); + result->green = CLAMP(p->red * self->matrix_entries[4] + + p->green * self->matrix_entries[5] + + p->blue * self->matrix_entries[6] + + self->matrix_entries[7], 0.0f, 1.0f); + result->blue = CLAMP(p->red * self->matrix_entries[8] + + p->green * self->matrix_entries[9] + + p->blue * self->matrix_entries[10] + + self->matrix_entries[11], 0.0f, 1.0f); +} + + +void hsv_transformation_real_transform_pixel_hsv (PixelTransformation* base, HSVAnalyticPixel* pixel, HSVAnalyticPixel* result) { + HSVTransformation *self = HSV_TRANSFORMATION(base); + result->hue = pixel->hue; + result->saturation = pixel->saturation; + result->light_value = CLAMP(self->remap_table[(int) (pixel->light_value * 255.0f)], 0.0f, 1.0f); +} |