static gboolean masks_form_is_in_roi(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { // we get the area for the form int fl, ft, fw, fh; if(!dt_masks_get_area(self, piece, form, &fw, &fh, &fl, &ft)) return FALSE; // is the form outside of the roi? fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale; if(ft >= roi_out->y + roi_out->height || ft + fh <= roi_out->y || fl >= roi_out->x + roi_out->width || fl + fw <= roi_out->x) return FALSE; return TRUE; }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_spots_params_t *d = (dt_iop_spots_params_t *)piece->data; dt_develop_blend_params_t *bp = self->blend_params; const int ch = piece->colors; const float *in = (float *)i; float *out = (float *)o; // we don't modify most of the image: #ifdef _OPENMP #pragma omp parallel for schedule(static) default(none) shared(out,in,roi_in,roi_out) #endif for (int k=0; k<roi_out->height; k++) { float *outb = out + ch*k*roi_out->width; const float *inb = in + ch*roi_in->width*(k+roi_out->y-roi_in->y) + ch*(roi_out->x-roi_in->x); memcpy(outb, inb, sizeof(float)*roi_out->width*ch); } // iterate through all forms dt_masks_form_t *grp = dt_masks_get_from_id(self->dev,bp->mask_id); int pos=0; if (grp && (grp->type & DT_MASKS_GROUP)) { GList *forms = g_list_first(grp->points); while(forms) { dt_masks_point_group_t *grpt = (dt_masks_point_group_t *)forms->data; //we get the spot dt_masks_form_t *form = dt_masks_get_from_id(self->dev,grpt->formid); if (!form) { forms = g_list_next(forms); pos++; continue; } //we get the area for the form int fl,ft,fw,fh; if (!dt_masks_get_area(self,piece,form,&fw,&fh,&fl,&ft)) { forms = g_list_next(forms); pos++; continue; } //if the form is outside the roi, we just skip it fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale; if (ft>=roi_out->y+roi_out->height || ft+fh<=roi_out->y || fl>=roi_out->x+roi_out->width || fl+fw<=roi_out->x) { forms = g_list_next(forms); pos++; continue; } if (d->clone_algo[pos] == 1 && (form->type & DT_MASKS_CIRCLE)) { dt_masks_point_circle_t *circle = (dt_masks_point_circle_t *)g_list_nth_data(form->points,0); // convert from world space: const int rad = circle->radius* MIN(piece->buf_in.width, piece->buf_in.height)*roi_in->scale; const int posx = (circle->center[0] * piece->buf_in.width)*roi_in->scale - rad; const int posy = (circle->center[1] * piece->buf_in.height)*roi_in->scale - rad; const int posx_source = (form->source[0]*piece->buf_in.width)*roi_in->scale - rad; const int posy_source = (form->source[1]*piece->buf_in.height)*roi_in->scale - rad; const int dx = posx-posx_source; const int dy = posy-posy_source; fw = fh = 2*rad; // convert from world space: float filter[2*rad + 1]; if(rad > 0) { for(int k=-rad; k<=rad; k++) { const float kk = 1.0f - fabsf(k/(float)rad); filter[rad + k] = kk*kk*(3.0f - 2.0f*kk); } } else { filter[0] = 1.0f; } for (int yy=posy ; yy<posy+fh; yy++) { //we test if we are inside roi_out if (yy<roi_out->y || yy>=roi_out->y+roi_out->height) continue; //we test if the source point is inside roi_in if (yy-dy<roi_in->y || yy-dy>=roi_in->y+roi_in->height) continue; for (int xx=posx ; xx<posx+fw; xx++) { //we test if we are inside roi_out if (xx<roi_out->x || xx>=roi_out->x+roi_out->width) continue; //we test if the source point is inside roi_in if (xx-dx<roi_in->x || xx-dx>=roi_in->x+roi_in->width) continue; const float f = filter[xx-posx+1]*filter[yy-posy+1]; for(int c=0; c<ch; c++) out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] = out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] * (1.0f-f) + in[4*(roi_in->width*(yy-posy+posy_source-roi_in->y) + xx-posx+posx_source-roi_in->x) + c] * f; } } } else { //we get the mask float *mask; int posx,posy,width,height; dt_masks_get_mask(self,piece,form,&mask,&width,&height,&posx,&posy); int fts = posy*roi_in->scale, fhs = height*roi_in->scale, fls = posx*roi_in->scale, fws = width*roi_in->scale; //now we search the delta with the source int dx,dy; dx=dy=0; if (form->type & DT_MASKS_PATH) { dt_masks_point_path_t *pt = (dt_masks_point_path_t *)g_list_nth_data(form->points,0); dx = pt->corner[0]*roi_in->scale*piece->buf_in.width - form->source[0]*roi_in->scale*piece->buf_in.width; dy = pt->corner[1]*roi_in->scale*piece->buf_in.height - form->source[1]*roi_in->scale*piece->buf_in.height; } else if (form->type & DT_MASKS_CIRCLE) { dt_masks_point_circle_t *pt = (dt_masks_point_circle_t *)g_list_nth_data(form->points,0); dx = pt->center[0]*roi_in->scale*piece->buf_in.width - form->source[0]*roi_in->scale*piece->buf_in.width; dy = pt->center[1]*roi_in->scale*piece->buf_in.height - form->source[1]*roi_in->scale*piece->buf_in.height; } if (dx!=0 || dy!=0) { //now we do the pixel clone for (int yy=fts+1 ; yy<fts+fhs-1; yy++) { //we test if we are inside roi_out if (yy<roi_out->y || yy>=roi_out->y+roi_out->height) continue; //we test if the source point is inside roi_in if (yy-dy<roi_in->y || yy-dy>=roi_in->y+roi_in->height) continue; for (int xx=fls+1 ; xx<fls+fws-1; xx++) { //we test if we are inside roi_out if (xx<roi_out->x || xx>=roi_out->x+roi_out->width) continue; //we test if the source point is inside roi_in if (xx-dx<roi_in->x || xx-dx>=roi_in->x+roi_in->width) continue; float f = mask[((int)((yy-fts)/roi_in->scale))*width + (int)((xx-fls)/roi_in->scale)]; //we can add the opacity here for(int c=0; c<ch; c++) out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] = out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] * (1.0f-f) + in[4*(roi_in->width*(yy-dy-roi_in->y) + xx-dx-roi_in->x) + c] * f; } } } free(mask); } pos++; forms = g_list_next(forms); } } }
void modify_roi_in(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in) { *roi_in = *roi_out; int roir = roi_in->width+roi_in->x; int roib = roi_in->height+roi_in->y; int roix = roi_in->x; int roiy = roi_in->y; //dt_iop_spots_params_t *d = (dt_iop_spots_params_t *)piece->data; dt_develop_blend_params_t *bp = self->blend_params; // We iterate through all spots or polygons dt_masks_form_t *grp = dt_masks_get_from_id(darktable.develop,bp->mask_id); if (grp && (grp->type & DT_MASKS_GROUP)) { GList *forms = g_list_first(grp->points); while(forms) { dt_masks_point_group_t *grpt = (dt_masks_point_group_t *)forms->data; //we get the spot dt_masks_form_t *form = dt_masks_get_from_id(self->dev,grpt->formid); if (form) { //we get the area for the form int fl,ft,fw,fh; if (!dt_masks_get_area(self,piece,form,&fw,&fh,&fl,&ft)) { forms = g_list_next(forms); continue; } //if the form is outside the roi, we just skip it fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale; if (ft>=roi_out->y+roi_out->height || ft+fh<=roi_out->y || fl>=roi_out->x+roi_out->width || fl+fw<=roi_out->x) { forms = g_list_next(forms); continue; } //we get the area for the source if (!dt_masks_get_source_area(self,piece,form,&fw,&fh,&fl,&ft)) { forms = g_list_next(forms); continue; } fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale; //we enlarge the roi if needed roiy = fminf(ft,roiy); roix = fminf(fl,roix); roir = fmaxf(fl+fw,roir); roib = fmaxf(ft+fh,roib); } forms = g_list_next(forms); } } //now we set the values roi_in->x = CLAMP(roix, 0, piece->pipe->iwidth*roi_in->scale-1); roi_in->y = CLAMP(roiy, 0, piece->pipe->iheight*roi_in->scale-1); roi_in->width = CLAMP(roir-roi_in->x, 1, piece->pipe->iwidth*roi_in->scale-roi_in->x); roi_in->height = CLAMP(roib-roi_in->y, 1, piece->pipe->iheight*roi_in->scale-roi_in->y); }