/* Copyright 2016 Software Freedom Conservancy Inc. * Copyright 2017 Jens Georg * * 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); }