Allow vignetting to become really strong for artistic purposes.
Also allows to change the center of vignetting.
This commit is contained in:
@@ -685,6 +685,10 @@ TP_SHARPENING_USM;Unsharp Mask
|
||||
TP_VIGNETTING_AMOUNT;Amount
|
||||
TP_VIGNETTING_LABEL;Vignetting Correction
|
||||
TP_VIGNETTING_RADIUS;Radius
|
||||
TP_VIGNETTING_STRENGTH;Strength
|
||||
TP_VIGNETTING_CENTER_X;Center X
|
||||
TP_VIGNETTING_CENTER_Y;Center Y
|
||||
TP_VIGNETTING_CENTER;Center
|
||||
TP_WBALANCE_AUTO;Auto
|
||||
TP_WBALANCE_CAMERA;Camera
|
||||
TP_WBALANCE_CUSTOM;Custom
|
||||
|
@@ -223,25 +223,42 @@ void ImProcFunctions::transform (Image16* original, Image16* transformed, int cx
|
||||
transformSep (original, transformed, cx, cy, sx, sy, oW, oH);
|
||||
}
|
||||
|
||||
void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul)
|
||||
{
|
||||
// vignette center is a point with coordinates between -1 and +1
|
||||
double x = vignetting.centerX / 100.0;
|
||||
double y = vignetting.centerY / 100.0;
|
||||
|
||||
// calculate vignette center in pixels
|
||||
w2 = (double) oW / 2.0 - 0.5 + x * oW;
|
||||
h2 = (double) oH / 2.0 - 0.5 + y * oH;
|
||||
|
||||
// max vignette radius in pixels
|
||||
maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
|
||||
|
||||
// vignette variables with applied strength
|
||||
v = 1.0 - vignetting.strength * vignetting.amount * 3.0 / 400.0;
|
||||
b = 1.0 + vignetting.radius * 7.0 / 100.0;
|
||||
mul = (1.0-v) / tanh(b);
|
||||
}
|
||||
|
||||
void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH) {
|
||||
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
|
||||
double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
|
||||
|
||||
double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
|
||||
double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
|
||||
|
||||
double mul = (1.0-v) / tanh(b);
|
||||
double vig_w2;
|
||||
double vig_h2;
|
||||
double maxRadius;
|
||||
double v;
|
||||
double b;
|
||||
double mul;
|
||||
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
|
||||
|
||||
#pragma omp parallel for if (multiThread)
|
||||
for (int y=0; y<transformed->height; y++) {
|
||||
double y_d = (double) (y + cy) - h2 ;
|
||||
double vig_y_d = (double) (y + cy) - vig_h2 ;
|
||||
int val;
|
||||
for (int x=0; x<transformed->width; x++) {
|
||||
double x_d = (double) (x + cx) - w2 ;
|
||||
double r = sqrt(x_d*x_d + y_d*y_d);
|
||||
double vig_x_d = (double) (x + cx) - vig_w2 ;
|
||||
double r = sqrt(vig_x_d*vig_x_d + vig_y_d*vig_y_d);
|
||||
double vign = v + mul * tanh (b*(maxRadius-r) / maxRadius);
|
||||
val = original->r[y][x] / vign;
|
||||
transformed->r[y][x] = CLIP(val);
|
||||
@@ -255,9 +272,16 @@ void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int c
|
||||
|
||||
#include "cubint.cc"
|
||||
void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
double vig_w2;
|
||||
double vig_h2;
|
||||
double maxRadius;
|
||||
double v;
|
||||
double b;
|
||||
double mul;
|
||||
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
|
||||
|
||||
// auxiliary variables for distortion correction
|
||||
double a = params->distortion.amount;
|
||||
@@ -266,11 +290,6 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
|
||||
double cost = cos(params->rotate.degree * 3.14/180.0);
|
||||
double sint = sin(params->rotate.degree * 3.14/180.0);
|
||||
|
||||
// auxiliary variables for vignetting
|
||||
double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
|
||||
double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
|
||||
double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
|
||||
double mul = (1.0-v) / tanh(b);
|
||||
bool dovign = params->vignetting.amount != 0;
|
||||
|
||||
// auxiliary variables for vertical perspective correction
|
||||
@@ -293,6 +312,8 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
|
||||
for (int x=0; x<transformed->width; x++) {
|
||||
double x_d = ascale * (x + cx - w2); // centering x coord & scale
|
||||
double y_d = ascale * (y + cy - h2); // centering y coord & scale
|
||||
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
|
||||
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
|
||||
|
||||
// horizontal perspective transformation
|
||||
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
|
||||
@@ -308,11 +329,14 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
|
||||
|
||||
// distortion correction
|
||||
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius;
|
||||
double r2 = sqrt(Dx*Dx + Dy*Dy);
|
||||
double s = 1.0 - a + a * r ;
|
||||
Dx *= s;
|
||||
Dy *= s;
|
||||
|
||||
double vig_Dx = vig_x_d * cost - vig_y_d * sint;
|
||||
double vig_Dy = vig_x_d * sint + vig_y_d * cost;
|
||||
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
|
||||
|
||||
// de-center
|
||||
Dx += w2;
|
||||
Dy += h2;
|
||||
@@ -357,8 +381,16 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
|
||||
#include "cubintch.cc"
|
||||
void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
|
||||
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
|
||||
double vig_w2;
|
||||
double vig_h2;
|
||||
double maxRadius;
|
||||
double v;
|
||||
double b;
|
||||
double mul;
|
||||
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
|
||||
|
||||
// auxiliary variables for c/a correction
|
||||
double cdist[3];
|
||||
@@ -381,11 +413,6 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
|
||||
double cost = cos(params->rotate.degree * 3.14/180.0);
|
||||
double sint = sin(params->rotate.degree * 3.14/180.0);
|
||||
|
||||
// auxiliary variables for vignetting
|
||||
double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
|
||||
double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
|
||||
double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
|
||||
double mul = (1.0-v) / tanh(b);
|
||||
bool dovign = params->vignetting.amount != 0;
|
||||
|
||||
// auxiliary variables for vertical perspective correction
|
||||
@@ -408,6 +435,8 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
|
||||
for (int x=0; x<transformed->width; x++) {
|
||||
double x_d = ascale * (x + cx - w2); // centering x coord & scale
|
||||
double y_d = ascale * (y + cy - h2); // centering y coord & scale
|
||||
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
|
||||
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
|
||||
|
||||
// horizontal perspective transformation
|
||||
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
|
||||
@@ -423,9 +452,12 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
|
||||
|
||||
// distortion correction
|
||||
double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius;
|
||||
double r2 = sqrt(Dxc*Dxc + Dyc*Dyc);
|
||||
double s = 1.0 - a + a * r ;
|
||||
|
||||
double vig_Dx = vig_x_d * cost - vig_y_d * sint;
|
||||
double vig_Dy = vig_x_d * sint + vig_y_d * cost;
|
||||
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
|
||||
|
||||
for (int c=0; c<3; c++) {
|
||||
|
||||
double Dx = Dxc * (s + cdist[c]);
|
||||
@@ -468,8 +500,16 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
|
||||
|
||||
void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
|
||||
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
double w2 = (double) oW / 2.0 - 0.5;
|
||||
double h2 = (double) oH / 2.0 - 0.5;
|
||||
|
||||
double vig_w2;
|
||||
double vig_h2;
|
||||
double maxRadius;
|
||||
double v;
|
||||
double b;
|
||||
double mul;
|
||||
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
|
||||
|
||||
// auxiliary variables for distortion correction
|
||||
double a = params->distortion.amount;
|
||||
@@ -478,11 +518,6 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
|
||||
double cost = cos(params->rotate.degree * 3.14/180.0);
|
||||
double sint = sin(params->rotate.degree * 3.14/180.0);
|
||||
|
||||
// auxiliary variables for vignetting
|
||||
double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
|
||||
double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
|
||||
double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
|
||||
double mul = (1.0-v) / tanh(b);
|
||||
bool dovign = params->vignetting.amount != 0;
|
||||
|
||||
// auxiliary variables for vertical perspective correction
|
||||
@@ -505,6 +540,8 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
|
||||
for (int x=0; x<transformed->width; x++) {
|
||||
double y_d = ascale * (y + cy - h2); // centering y coord & scale
|
||||
double x_d = ascale * (x + cx - w2); // centering x coord & scale
|
||||
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
|
||||
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
|
||||
|
||||
// horizontal perspective transformation
|
||||
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
|
||||
@@ -520,11 +557,14 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
|
||||
|
||||
// distortion correction
|
||||
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius;
|
||||
double r2 = sqrt(Dx*Dx + Dy*Dy);
|
||||
double s = 1.0 - a + a * r ;
|
||||
Dx *= s;
|
||||
Dy *= s;
|
||||
|
||||
double vig_Dx = vig_x_d * cost - vig_y_d * sint;
|
||||
double vig_Dy = vig_x_d * sint + vig_y_d * cost;
|
||||
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
|
||||
|
||||
// de-center
|
||||
Dx += w2;
|
||||
Dy += h2;
|
||||
|
@@ -147,6 +147,9 @@ void ProcParams::setDefaults () {
|
||||
|
||||
vignetting.amount = 0;
|
||||
vignetting.radius = 50;
|
||||
vignetting.strength = 1;
|
||||
vignetting.centerX = 0;
|
||||
vignetting.centerY = 0;
|
||||
|
||||
chmixer.red[0] = 100;
|
||||
chmixer.red[1] = 0;
|
||||
@@ -326,6 +329,9 @@ int ProcParams::save (Glib::ustring fname) const {
|
||||
// save vignetting correction
|
||||
keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount);
|
||||
keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius);
|
||||
keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength);
|
||||
keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX);
|
||||
keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY);
|
||||
|
||||
// save highlight recovery settings
|
||||
keyFile.set_boolean ("HLRecovery", "Enabled", hlrecovery.enabled);
|
||||
@@ -580,6 +586,9 @@ if (keyFile.has_group ("CACorrection")) {
|
||||
if (keyFile.has_group ("Vignetting Correction")) {
|
||||
if (keyFile.has_key ("Vignetting Correction", "Amount")) vignetting.amount = keyFile.get_integer ("Vignetting Correction", "Amount");
|
||||
if (keyFile.has_key ("Vignetting Correction", "Radius")) vignetting.radius = keyFile.get_integer ("Vignetting Correction", "Radius");
|
||||
if (keyFile.has_key ("Vignetting Correction", "Strength")) vignetting.strength = keyFile.get_integer ("Vignetting Correction", "Strength");
|
||||
if (keyFile.has_key ("Vignetting Correction", "CenterX")) vignetting.centerX = keyFile.get_integer ("Vignetting Correction", "CenterX");
|
||||
if (keyFile.has_key ("Vignetting Correction", "CenterY")) vignetting.centerY = keyFile.get_integer ("Vignetting Correction", "CenterY");
|
||||
}
|
||||
|
||||
// load highlight recovery settings
|
||||
@@ -775,6 +784,9 @@ bool ProcParams::operator== (const ProcParams& other) {
|
||||
&& cacorrection.blue == other.cacorrection.blue
|
||||
&& vignetting.amount == other.vignetting.amount
|
||||
&& vignetting.radius == other.vignetting.radius
|
||||
&& vignetting.strength == other.vignetting.strength
|
||||
&& vignetting.centerX == other.vignetting.centerX
|
||||
&& vignetting.centerY == other.vignetting.centerY
|
||||
&& !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int))
|
||||
&& !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int))
|
||||
&& !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int))
|
||||
|
@@ -249,6 +249,9 @@ class VignettingParams {
|
||||
public:
|
||||
int amount;
|
||||
int radius;
|
||||
int strength;
|
||||
int centerX;
|
||||
int centerY;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -107,6 +107,9 @@ void ParamsEdited::set (bool v) {
|
||||
cacorrection.blue = v;
|
||||
vignetting.amount = v;
|
||||
vignetting.radius = v;
|
||||
vignetting.strength = v;
|
||||
vignetting.centerX = v;
|
||||
vignetting.centerY = v;
|
||||
chmixer.red[0] = v;
|
||||
chmixer.red[1] = v;
|
||||
chmixer.red[2] = v;
|
||||
@@ -234,6 +237,9 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
|
||||
cacorrection.blue = cacorrection.blue && p.cacorrection.blue == other.cacorrection.blue;
|
||||
vignetting.amount = vignetting.amount && p.vignetting.amount == other.vignetting.amount;
|
||||
vignetting.radius = vignetting.radius && p.vignetting.radius == other.vignetting.radius;
|
||||
vignetting.strength = vignetting.strength && p.vignetting.strength == other.vignetting.strength;
|
||||
vignetting.centerX = vignetting.centerX && p.vignetting.centerX == other.vignetting.centerX;
|
||||
vignetting.centerY = vignetting.centerY && p.vignetting.centerY == other.vignetting.centerY;
|
||||
chmixer.red[0] = chmixer.red[0] && p.chmixer.red[0] == other.chmixer.red[0];
|
||||
chmixer.red[1] = chmixer.red[1] && p.chmixer.red[1] == other.chmixer.red[1];
|
||||
chmixer.red[2] = chmixer.red[2] && p.chmixer.red[2] == other.chmixer.red[2];
|
||||
@@ -352,6 +358,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
|
||||
if (cacorrection.blue) toEdit.cacorrection.blue = options.baBehav[ADDSET_CA] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue;
|
||||
if (vignetting.amount) toEdit.vignetting.amount = options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount;
|
||||
if (vignetting.radius) toEdit.vignetting.radius = mods.vignetting.radius;
|
||||
if (vignetting.strength) toEdit.vignetting.strength = mods.vignetting.strength;
|
||||
if (vignetting.centerX) toEdit.vignetting.centerX = mods.vignetting.centerX;
|
||||
if (vignetting.centerY) toEdit.vignetting.centerY = mods.vignetting.centerY;
|
||||
if (chmixer.red[0]) toEdit.chmixer.red[0] = mods.chmixer.red[0];
|
||||
if (chmixer.red[1]) toEdit.chmixer.red[1] = mods.chmixer.red[1];
|
||||
if (chmixer.red[2]) toEdit.chmixer.red[2] = mods.chmixer.red[2];
|
||||
|
@@ -191,6 +191,9 @@ class VignettingParamsEdited {
|
||||
public:
|
||||
bool amount;
|
||||
bool radius;
|
||||
bool strength;
|
||||
bool centerX;
|
||||
bool centerY;
|
||||
};
|
||||
|
||||
class ChannelMixerParamsEdited {
|
||||
|
@@ -30,8 +30,20 @@ Vignetting::Vignetting () : vigAdd(false) {
|
||||
radius = Gtk::manage (new Adjuster (M("TP_VIGNETTING_RADIUS"), 0, 100, 1, 50));
|
||||
radius->setAdjusterListener (this);
|
||||
|
||||
strength = Gtk::manage (new Adjuster (M("TP_VIGNETTING_STRENGTH"), 1, 100, 1, 1));
|
||||
strength->setAdjusterListener (this);
|
||||
|
||||
centerX = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_X"), -100, 100, 1, 0));
|
||||
centerX->setAdjusterListener (this);
|
||||
|
||||
centerY = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_Y"), -100, 100, 1, 0));
|
||||
centerY->setAdjusterListener (this);
|
||||
|
||||
pack_start (*amount);
|
||||
pack_start (*radius);
|
||||
pack_start (*strength);
|
||||
pack_start (*centerX);
|
||||
pack_start (*centerY);
|
||||
|
||||
show_all();
|
||||
}
|
||||
@@ -45,6 +57,9 @@ void Vignetting::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
||||
|
||||
amount->setValue (pp->vignetting.amount);
|
||||
radius->setValue (pp->vignetting.radius);
|
||||
strength->setValue (pp->vignetting.strength);
|
||||
centerX->setValue (pp->vignetting.centerX);
|
||||
centerY->setValue (pp->vignetting.centerY);
|
||||
|
||||
enableListener ();
|
||||
}
|
||||
@@ -53,6 +68,9 @@ void Vignetting::write (ProcParams* pp, ParamsEdited* pedited) {
|
||||
|
||||
pp->vignetting.amount = (int)amount->getValue ();
|
||||
pp->vignetting.radius = (int)radius->getValue ();
|
||||
pp->vignetting.strength = (int)strength->getValue ();
|
||||
pp->vignetting.centerX = (int)centerX->getValue ();
|
||||
pp->vignetting.centerY = (int)centerY->getValue ();
|
||||
|
||||
if (pedited)
|
||||
pedited->vignetting.amount = amount->getEditedState ();
|
||||
@@ -62,6 +80,9 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p
|
||||
|
||||
amount->setDefault (defParams->vignetting.amount);
|
||||
radius->setDefault (defParams->vignetting.radius);
|
||||
strength->setDefault (defParams->vignetting.strength);
|
||||
centerX->setDefault (defParams->vignetting.centerX);
|
||||
centerY->setDefault (defParams->vignetting.centerY);
|
||||
|
||||
if (pedited)
|
||||
amount->setDefaultEditedState (pedited->vignetting.amount ? Edited : UnEdited);
|
||||
@@ -72,7 +93,7 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p
|
||||
void Vignetting::adjusterChanged (Adjuster* a, double newval) {
|
||||
|
||||
if (listener)
|
||||
listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), (int)amount->getValue(), (int)radius->getValue()));
|
||||
listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%5\n%2=%6\n%3=%7\n%4=%8 %9", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), M("TP_VIGNETTING_STRENGTH"), M("TP_VIGNETTING_CENTER"), (int)amount->getValue(), (int)radius->getValue(), (int)strength->getValue(), (int)centerX->getValue(), (int)centerY->getValue()));
|
||||
}
|
||||
|
||||
void Vignetting::setAdjusterBehavior (bool bvadd) {
|
||||
|
@@ -28,6 +28,9 @@ class Vignetting : public Gtk::VBox, public AdjusterListener, public ToolPanel {
|
||||
protected:
|
||||
Adjuster* amount;
|
||||
Adjuster* radius;
|
||||
Adjuster* strength;
|
||||
Adjuster* centerX;
|
||||
Adjuster* centerY;
|
||||
bool vigAdd;
|
||||
|
||||
public:
|
||||
|
Reference in New Issue
Block a user