static gboolean dt_iop_zonesystem_bar_motion_notify (GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; const int inset = DT_ZONESYSTEM_INSET; int width = widget->allocation.width - 2*inset, height = widget->allocation.height - 2*inset; /* record mouse position within control */ g->mouse_x = CLAMP(event->x - inset, 0, width); g->mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); g->zone_under_mouse = (g->mouse_x/width) / (1.0/(p->size-1)); if (g->is_dragging) { /* calculate zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1}; _iop_zonesystem_calculate_zonemap (p,zonemap); if ( (g->mouse_x/width) > zonemap[g->current_zone-1] && (g->mouse_x/width) < zonemap[g->current_zone+1] ) { p->zone[g->current_zone] = (g->mouse_x/width); dt_dev_add_history_item(darktable.develop, self, TRUE); } } else g->hilite_zone = (g->mouse_y<(height/2.0))?TRUE:FALSE; gtk_widget_queue_draw (self->widget); gtk_widget_queue_draw (g->preview); return TRUE; }
static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; /* calculate zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; _iop_zonesystem_calculate_zonemap(p, zonemap); /* record mouse position within control */ g->mouse_x = CLAMP(event->x - inset, 0, width); g->mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); if(g->is_dragging) { if((g->mouse_x / width) > zonemap[g->current_zone - 1] && (g->mouse_x / width) < zonemap[g->current_zone + 1]) { p->zone[g->current_zone] = (g->mouse_x / width); dt_dev_add_history_item(darktable.develop, self, TRUE); } } else { /* decide which zone the mouse is over */ if(g->mouse_y >= height * (1.0 - DT_ZONESYSTEM_REFERENCE_SPLIT)) { g->zone_under_mouse = (g->mouse_x / width) / (1.0 / (p->size - 1)); g->mouse_over_output_zones = TRUE; } else { float xpos = g->mouse_x / width; for(int z = 0; z < p->size - 1; z++) { if(xpos >= zonemap[z] && xpos < zonemap[z + 1]) { g->zone_under_mouse = z; break; } } g->mouse_over_output_zones = FALSE; } g->hilite_zone = (g->mouse_y < height) ? TRUE : FALSE; } gtk_widget_queue_draw(self->widget); gtk_widget_queue_draw(g->preview); return TRUE; }
int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { dt_iop_zonesystem_data_t *data = (dt_iop_zonesystem_data_t *)piece->data; dt_iop_zonesystem_global_data_t *gd = (dt_iop_zonesystem_global_data_t *)self->data; cl_mem dev_zmo, dev_zms = NULL; cl_int err = -999; const int devid = piece->pipe->devid; const int width = roi_in->width; const int height = roi_in->height; /* calculate zonemap */ const int size = data->params.size; float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; float zonemap_offset[ROUNDUP(MAX_ZONE_SYSTEM_SIZE, 16)] = { -1 }; float zonemap_scale[ROUNDUP(MAX_ZONE_SYSTEM_SIZE, 16)] = { -1 }; _iop_zonesystem_calculate_zonemap(&(data->params), zonemap); /* precompute scale and offset */ for(int k = 0; k < size - 1; k++) zonemap_scale[k] = (zonemap[k + 1] - zonemap[k]) * (size - 1); for(int k = 0; k < size - 1; k++) zonemap_offset[k] = 100.0f * ((k + 1) * zonemap[k] - k * zonemap[k + 1]); dev_zmo = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * ROUNDUP(MAX_ZONE_SYSTEM_SIZE, 16), zonemap_offset); if(dev_zmo == NULL) goto error; dev_zms = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * ROUNDUP(MAX_ZONE_SYSTEM_SIZE, 16), zonemap_scale); if(dev_zms == NULL) goto error; size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 }; dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 0, sizeof(cl_mem), (void *)&dev_in); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 1, sizeof(cl_mem), (void *)&dev_out); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 2, sizeof(int), (void *)&width); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 3, sizeof(int), (void *)&height); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 4, sizeof(int), (void *)&size); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 5, sizeof(cl_mem), (void *)&dev_zmo); dt_opencl_set_kernel_arg(devid, gd->kernel_zonesystem, 6, sizeof(cl_mem), (void *)&dev_zms); err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_zonesystem, sizes); if(err != CL_SUCCESS) goto error; dt_opencl_release_mem_object(dev_zmo); dt_opencl_release_mem_object(dev_zms); return TRUE; error: if(dev_zmo != NULL) dt_opencl_release_mem_object(dev_zmo); if(dev_zms != NULL) dt_opencl_release_mem_object(dev_zms); dt_print(DT_DEBUG_OPENCL, "[opencl_zonesystem] couldn't enqueue kernel! %d\n", err); return FALSE; }
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)p1; dt_iop_zonesystem_data_t *d = (dt_iop_zonesystem_data_t *)piece->data; d->params = *p; d->rzscale = (d->params.size - 1) / 100.0f; /* calculate zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; _iop_zonesystem_calculate_zonemap(&(d->params), zonemap); const int size = d->params.size; // precompute scale and offset for(int k = 0; k < size - 1; k++) d->zonemap_scale[k] = (zonemap[k + 1] - zonemap[k]) * (size - 1); for(int k = 0; k < size - 1; k++) d->zonemap_offset[k] = 100.0f * ((k + 1) * zonemap[k] - k * zonemap[k + 1]); }
static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2*inset;/*, height = allocation.height - 2*inset;*/ /* calculate zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1}; _iop_zonesystem_calculate_zonemap(p,zonemap); /* translate mouse into zone index */ int k = _iop_zonesystem_zone_index_from_lightness (g->mouse_x/width,zonemap,p->size); float zw = zonemap[k+1]-zonemap[k]; if ((g->mouse_x/width)>zonemap[k]+(zw/2)) k++; if (event->button == 1) { if (p->zone[k]==-1) { p->zone[k] = zonemap[k]; dt_dev_add_history_item(darktable.develop, self, TRUE); } g->is_dragging = TRUE; g->current_zone = k; } else if (event->button == 3) { /* clear the controlpoint */ p->zone[k] = -1; dt_dev_add_history_item(darktable.develop, self, TRUE); } return TRUE; }
static gboolean dt_iop_zonesystem_preview_expose (GtkWidget *widget, GdkEventExpose *event, dt_iop_module_t *self) { const int inset = 2; int width = widget->allocation.width, height = widget->allocation.height; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* clear background */ GtkStateType state = gtk_widget_get_state(self->expander); GtkStyle *style = gtk_widget_get_style(self->expander); cairo_set_source_rgb (cr, style->bg[state].red/65535.0, style->bg[state].green/65535.0, style->bg[state].blue/65535.0); cairo_paint (cr); width -= 2*inset; height -= 2*inset; cairo_translate(cr, inset, inset); dt_pthread_mutex_lock(&g->lock); if( g->preview_buffer && self->enabled) { /* calculate the zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1}; _iop_zonesystem_calculate_zonemap (p,zonemap); /* let's generate a pixbuf from pixel zone buffer */ guchar *image = g_malloc ((g->preview_width*g->preview_height)*4); for (int k=0; k<g->preview_width*g->preview_height; k++) { int zone = 255*CLIP (((1.0/(p->size-1))*g->preview_buffer[k])); image[4*k+2] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone; image[4*k+1] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone; image[4*k+0] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?0:zone; } dt_pthread_mutex_unlock(&g->lock); const int wd = g->preview_width, ht = g->preview_height; const float scale = fminf(width/(float)wd, height/(float)ht); const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data (image, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width/2.0, height/2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f*wd, -.5f*ht); cairo_rectangle(cr, 1, 1, wd-2, ht-2); cairo_set_source_surface (cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD); cairo_fill_preserve(cr); cairo_surface_destroy (surface); cairo_set_line_width(cr, 1.0); cairo_set_source_rgb(cr, .1, .1, .1); cairo_stroke(cr); g_free(image); } else dt_pthread_mutex_unlock(&g->lock); cairo_destroy(cr); cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface (cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
static gboolean dt_iop_zonesystem_bar_expose (GtkWidget *widget, GdkEventExpose *event, dt_iop_module_t *self) { dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; const int inset = DT_ZONESYSTEM_INSET; int width = widget->allocation.width, height = widget->allocation.height; cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* clear background */ cairo_set_source_rgb (cr, .15, .15, .15); cairo_paint(cr); /* translate and scale */ width-=2*inset; height-=2*inset; cairo_save(cr); cairo_translate(cr, inset, inset); cairo_scale(cr,width,height); /* render the bars */ float zonemap[MAX_ZONE_SYSTEM_SIZE]= {0}; _iop_zonesystem_calculate_zonemap (p, zonemap); float s=(1./(p->size-2)); cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); for(int i=0; i<p->size-1; i++) { /* draw the reference zone */ float z=s*i; cairo_rectangle (cr,(1./(p->size-1))*i,0,(1./(p->size-1)),DT_ZONESYSTEM_REFERENCE_SPLIT-DT_ZONESYSTEM_BAR_SPLIT_WIDTH); cairo_set_source_rgb (cr, z, z, z); cairo_fill (cr); /* draw zone mappings */ cairo_rectangle (cr, zonemap[i],DT_ZONESYSTEM_REFERENCE_SPLIT+DT_ZONESYSTEM_BAR_SPLIT_WIDTH, (zonemap[i+1]-zonemap[i]),1.0-DT_ZONESYSTEM_REFERENCE_SPLIT); cairo_set_source_rgb (cr, z, z, z); cairo_fill (cr); } cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); cairo_restore (cr); /* render zonebar control lines */ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); cairo_set_line_width (cr, 1.); cairo_rectangle (cr,inset,inset,width,height); cairo_set_source_rgb (cr, .1,.1,.1); cairo_stroke (cr); cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); /* render control points handles */ cairo_set_source_rgb (cr, 0.6, 0.6, 0.6); cairo_set_line_width (cr, 1.); const float arrw = 7.0f; for (int k=1; k<p->size-1; k++) { float nzw=zonemap[k+1]-zonemap[k]; float pzw=zonemap[k]-zonemap[k-1]; if ( ( ((g->mouse_x/width) > (zonemap[k]-(pzw/2.0))) && ((g->mouse_x/width) < (zonemap[k]+(nzw/2.0))) ) || p->zone[k] != -1) { gboolean is_under_mouse = ((width*zonemap[k]) - arrw*.5f < g->mouse_x && (width*zonemap[k]) + arrw*.5f > g->mouse_x); cairo_move_to(cr, inset+(width*zonemap[k]), height+(2*inset)-1); cairo_rel_line_to(cr, -arrw*.5f, 0); cairo_rel_line_to(cr, arrw*.5f, -arrw); cairo_rel_line_to(cr, arrw*.5f, arrw); cairo_close_path(cr); if ( is_under_mouse ) cairo_fill(cr); else cairo_stroke(cr); } } /* push mem surface into widget */ cairo_destroy (cr); cairo_t *cr_pixmap = gdk_cairo_create (gtk_widget_get_window (widget)); cairo_set_source_surface (cr_pixmap, cst, 0, 0); cairo_paint (cr_pixmap); cairo_destroy (cr_pixmap); cairo_surface_destroy (cst); return TRUE; }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { float *in; float *out; dt_iop_zonesystem_gui_data_t *g = NULL; dt_iop_zonesystem_data_t *data = (dt_iop_zonesystem_data_t*)piece->data; guchar *buffer = NULL; if( self->dev->gui_attached && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW ) { g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_pthread_mutex_lock(&g->lock); if(g->preview_buffer) g_free (g->preview_buffer); buffer = g->preview_buffer = g_malloc (roi_in->width*roi_in->height); g->preview_width=roi_out->width; g->preview_height=roi_out->height; } /* calculate zonemap */ const int size = data->size; float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1}; _iop_zonesystem_calculate_zonemap (data, zonemap); const int ch = piece->colors; /* if gui and have buffer lets gaussblur and fill buffer with zone indexes */ if( self->dev->gui_attached && g && buffer) { /* setup gaussian kernel */ const int radius = 8; const int rad = MIN(radius, ceilf(radius * roi_in->scale / piece->iscale)); const int wd = 2*rad+1; float mat[wd*wd]; float *m; const float sigma2 = (2.5*2.5)*(radius*roi_in->scale/piece->iscale)*(radius*roi_in->scale/piece->iscale); float weight = 0.0f; memset(mat, 0, wd*wd*sizeof(float)); m = mat; for(int l=-rad; l<=rad; l++) for(int k=-rad; k<=rad; k++,m++) weight += *m = expf(- (l*l + k*k)/(2.f*sigma2)); m = mat; for(int l=-rad; l<=rad; l++) for(int k=-rad; k<=rad; k++,m++) *m /= weight; /* gauss blur the L channel */ #ifdef _OPENMP #pragma omp parallel for default(none) private(in, out, m) shared(mat, ivoid, ovoid, roi_out, roi_in) schedule(static) #endif for(int j=rad; j<roi_out->height-rad; j++) { in = ((float *)ivoid) + ch*(j*roi_in->width + rad); out = ((float *)ovoid) + ch*(j*roi_out->width + rad); for(int i=rad; i<roi_out->width-rad; i++) { for(int c=0; c<3; c++) out[c] = 0.0f; float sum = 0.0; m = mat; for(int l=-rad; l<=rad; l++) { float *inrow = in + ch*(l*roi_in->width-rad); for(int k=-rad; k<=rad; k++,inrow+=ch,m++) sum += *m * inrow[0]; } out[0] = sum; out += ch; in += ch; } } /* create zonemap preview */ // in = (float *)ivoid; out = (float *)ovoid; #ifdef _OPENMP #pragma omp parallel for default(none) shared(roi_out,out,buffer,g,zonemap) schedule(static) #endif for (int k=0; k<roi_out->width*roi_out->height; k++) { buffer[k] = _iop_zonesystem_zone_index_from_lightness (out[ch*k]/100.0f, zonemap, size); } dt_pthread_mutex_unlock(&g->lock); } /* process the image */ in = (float *)ivoid; out = (float *)ovoid; const float rzscale = (size-1)/100.0f; float zonemap_offset[MAX_ZONE_SYSTEM_SIZE]= {-1}; float zonemap_scale[MAX_ZONE_SYSTEM_SIZE]= {-1}; // precompute scale and offset for (int k=0; k < size-1; k++) zonemap_scale[k] = (zonemap[k+1]-zonemap[k])*(size-1); for (int k=0; k < size-1; k++) zonemap_offset[k] = 100.0f * ((k+1)*zonemap[k] - k*zonemap[k+1]) ; #ifdef _OPENMP #pragma omp parallel for default(none) shared(roi_out, in, out, zonemap_scale,zonemap_offset) schedule(static) #endif for (int j=0; j<roi_out->height; j++) for (int i=0; i<roi_out->width; i++) { /* remap lightness into zonemap and apply lightness */ const float *inp = in + ch*(j*roi_out->width+i); float *outp = out + ch*(j*roi_out->width+i); const int rz = CLAMPS(inp[0]*rzscale, 0, size-2); // zone index const float zs = ((rz > 0) ? (zonemap_offset[rz]/inp[0]) : 0) + zonemap_scale[rz]; _mm_stream_ps(outp,_mm_mul_ps(_mm_load_ps(inp),_mm_set1_ps(zs))); } _mm_sfence(); if(piece->pipe->mask_display) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height); }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { float *in; float *out; dt_iop_zonesystem_gui_data_t *g = NULL; dt_iop_zonesystem_data_t *data = (dt_iop_zonesystem_data_t*)piece->data; const int width = roi_out->width; const int height = roi_out->height; guchar *in_buffer = NULL, *out_buffer = NULL; if( self->dev->gui_attached && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW ) { g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_pthread_mutex_lock(&g->lock); if(g->in_preview_buffer) g_free (g->in_preview_buffer); if(g->out_preview_buffer) g_free (g->out_preview_buffer); in_buffer = g->in_preview_buffer = g_malloc ((size_t)width*height); out_buffer = g->out_preview_buffer = g_malloc ((size_t)width*height); g->preview_width = width; g->preview_height = height; dt_pthread_mutex_unlock(&g->lock); } /* calculate zonemap */ const int size = data->size; float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1}; _iop_zonesystem_calculate_zonemap (data, zonemap); const int ch = piece->colors; /* process the image */ in = (float *)ivoid; out = (float *)ovoid; const float rzscale = (size-1)/100.0f; float zonemap_offset[MAX_ZONE_SYSTEM_SIZE]= {-1}; float zonemap_scale[MAX_ZONE_SYSTEM_SIZE]= {-1}; // precompute scale and offset for (int k=0; k < size-1; k++) zonemap_scale[k] = (zonemap[k+1]-zonemap[k])*(size-1); for (int k=0; k < size-1; k++) zonemap_offset[k] = 100.0f * ((k+1)*zonemap[k] - k*zonemap[k+1]) ; #ifdef _OPENMP #pragma omp parallel for default(none) shared(in, out, zonemap_scale,zonemap_offset) schedule(static) #endif for (int j=0; j<height; j++) for (int i=0; i<width; i++) { /* remap lightness into zonemap and apply lightness */ const float *inp = in + ch*((size_t)j*width+i); float *outp = out + ch*((size_t)j*width+i); const int rz = CLAMPS(inp[0]*rzscale, 0, size-2); // zone index const float zs = ((rz > 0) ? (zonemap_offset[rz]/inp[0]) : 0) + zonemap_scale[rz]; _mm_stream_ps(outp,_mm_mul_ps(_mm_load_ps(inp),_mm_set1_ps(zs))); } _mm_sfence(); if(piece->pipe->mask_display) dt_iop_alpha_copy(ivoid, ovoid, width, height); /* if gui and have buffer lets gaussblur and fill buffer with zone indexes */ if( self->dev->gui_attached && g && in_buffer && out_buffer) { float Lmax[] = { 100.0f }; float Lmin[] = { 0.0f }; /* setup gaussian kernel */ const int radius = 8; const float sigma = 2.5*(radius*roi_in->scale/piece->iscale); dt_gaussian_t *gauss = dt_gaussian_init(width, height, 1, Lmax, Lmin, sigma, DT_IOP_GAUSSIAN_ZERO); float *tmp = g_malloc((size_t)width*height*sizeof(float)); if(gauss && tmp) { #ifdef _OPENMP #pragma omp parallel for default(none) shared(ivoid, tmp) schedule(static) #endif for(size_t k=0; k<(size_t)width*height; k++) tmp[k] = ((float *)ivoid)[ch*k]; dt_gaussian_blur(gauss, tmp, tmp); /* create zonemap preview for input */ dt_pthread_mutex_lock(&g->lock); #ifdef _OPENMP #pragma omp parallel for default(none) shared(tmp,in_buffer) schedule(static) #endif for (size_t k=0; k<(size_t)width*height; k++) { in_buffer[k] = CLAMPS(tmp[k]*(size-1)/100.0f, 0, size-2); } dt_pthread_mutex_unlock(&g->lock); #ifdef _OPENMP #pragma omp parallel for default(none) shared(ovoid, tmp) schedule(static) #endif for(size_t k=0; k<(size_t)width*height; k++) tmp[k] = ((float *)ovoid)[ch*k]; dt_gaussian_blur(gauss, tmp, tmp); /* create zonemap preview for output */ dt_pthread_mutex_lock(&g->lock); #ifdef _OPENMP #pragma omp parallel for default(none) shared(tmp,out_buffer) schedule(static) #endif for (size_t k=0; k<(size_t)width*height; k++) { out_buffer[k] = CLAMPS(tmp[k]*(size-1)/100.0f, 0, size-2); } dt_pthread_mutex_unlock(&g->lock); } if (tmp) g_free(tmp); if (gauss) dt_gaussian_free(gauss); } }
static gboolean dt_iop_zonesystem_preview_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self) { const int inset = DT_PIXEL_APPLY_DPI(2); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* clear background */ GtkStyleContext *context = gtk_widget_get_style_context(self->expander); gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); dt_pthread_mutex_lock(&g->lock); if(g->in_preview_buffer && g->out_preview_buffer && self->enabled) { /* calculate the zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; _iop_zonesystem_calculate_zonemap(p, zonemap); /* let's generate a pixbuf from pixel zone buffer */ guchar *image = g_malloc_n((size_t)4 * g->preview_width * g->preview_height, sizeof(guchar)); guchar *buffer = g->mouse_over_output_zones ? g->out_preview_buffer : g->in_preview_buffer; for(int k = 0; k < g->preview_width * g->preview_height; k++) { int zone = 255 * CLIP(((1.0 / (p->size - 1)) * buffer[k])); image[4 * k + 2] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 255 : zone; image[4 * k + 1] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 255 : zone; image[4 * k + 0] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 0 : zone; } dt_pthread_mutex_unlock(&g->lock); const int wd = g->preview_width, ht = g->preview_height; const float scale = fminf(width / (float)wd, height / (float)ht); const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data(image, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f * wd, -.5f * ht); cairo_rectangle(cr, DT_PIXEL_APPLY_DPI(1), DT_PIXEL_APPLY_DPI(1), wd - DT_PIXEL_APPLY_DPI(2), ht - DT_PIXEL_APPLY_DPI(2)); cairo_set_source_surface(cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD); cairo_fill_preserve(cr); cairo_surface_destroy(surface); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_stroke(cr); g_free(image); } else { dt_pthread_mutex_unlock(&g->lock); // draw a big, subdued dt logo if(g->image) { GdkRGBA *color; gtk_style_context_get(context, gtk_widget_get_state_flags(self->expander), "background-color", &color, NULL); cairo_set_source_surface(cr, g->image, (width - g->image_width) * 0.5, (height - g->image_height) * 0.5); cairo_rectangle(cr, 0, 0, width, height); cairo_set_operator(cr, CAIRO_OPERATOR_HSL_LUMINOSITY); cairo_fill_preserve(cr); cairo_set_operator(cr, CAIRO_OPERATOR_DARKEN); cairo_set_source_rgb(cr, color->red + 0.02, color->green + 0.02, color->blue + 0.02); cairo_fill_preserve(cr); cairo_set_operator(cr, CAIRO_OPERATOR_LIGHTEN); cairo_set_source_rgb(cr, color->red - 0.02, color->green - 0.02, color->blue - 0.02); cairo_fill(cr); gdk_rgba_free(color); } } cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }