mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
fix code
This commit is contained in:
parent
4c5e127c88
commit
7b0f88d110
@ -3,17 +3,7 @@ package cn.hutool.swing.img;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.swing.img.color.ColorUtil;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
@ -34,7 +24,6 @@ public class GraphicsUtil {
|
||||
*/
|
||||
public static Graphics2D createGraphics(final BufferedImage image, final Color color) {
|
||||
final Graphics2D g = image.createGraphics();
|
||||
|
||||
if (null != color) {
|
||||
// 填充背景
|
||||
g.setColor(color);
|
||||
@ -99,9 +88,7 @@ public class GraphicsUtil {
|
||||
*/
|
||||
public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final int width, final int height) {
|
||||
// 抗锯齿
|
||||
if (g instanceof Graphics2D) {
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
enableAntialias(g);
|
||||
// 创建字体
|
||||
g.setFont(font);
|
||||
|
||||
@ -168,9 +155,7 @@ public class GraphicsUtil {
|
||||
*/
|
||||
public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final Point point) {
|
||||
// 抗锯齿
|
||||
if (g instanceof Graphics2D) {
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
enableAntialias(g);
|
||||
|
||||
g.setFont(font);
|
||||
g.setColor(ObjUtil.defaultIfNull(color, Color.BLACK));
|
||||
@ -182,8 +167,8 @@ public class GraphicsUtil {
|
||||
/**
|
||||
* 绘制图片
|
||||
*
|
||||
* @param g 画笔
|
||||
* @param img 要绘制的图片
|
||||
* @param g 画笔
|
||||
* @param img 要绘制的图片
|
||||
* @param point 绘制的位置,基于左上角
|
||||
* @return 画笔对象
|
||||
*/
|
||||
@ -208,12 +193,27 @@ public class GraphicsUtil {
|
||||
/**
|
||||
* 设置画笔透明度
|
||||
*
|
||||
* @param g 画笔
|
||||
* @param g 画笔
|
||||
* @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
|
||||
* @return 画笔
|
||||
*/
|
||||
public static Graphics2D setAlpha(final Graphics2D g, final float alpha){
|
||||
public static Graphics2D setAlpha(final Graphics2D g, final float alpha) {
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开抗锯齿和文本抗锯齿
|
||||
*
|
||||
* @param g {@link Graphics}
|
||||
*/
|
||||
private static void enableAntialias(final Graphics g) {
|
||||
if (g instanceof Graphics2D) {
|
||||
((Graphics2D) g).setRenderingHints(
|
||||
RenderingHintsBuilder.of()
|
||||
.setAntialiasing(RenderingHintsBuilder.Antialias.ON)
|
||||
.setTextAntialias(RenderingHintsBuilder.TextAntialias.ON).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -706,11 +706,10 @@ public class Img implements Serializable {
|
||||
* 结果类型设定见{@link #setTargetImageType(String)}
|
||||
*
|
||||
* @param out 写出到的目标流
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public boolean write(final OutputStream out) throws IORuntimeException {
|
||||
return write(ImgUtil.getImageOutputStream(out));
|
||||
public void write(final OutputStream out) throws IORuntimeException {
|
||||
write(ImgUtil.getImageOutputStream(out));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -718,27 +717,25 @@ public class Img implements Serializable {
|
||||
* 结果类型设定见{@link #setTargetImageType(String)}
|
||||
*
|
||||
* @param targetImageStream 写出到的目标流
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public boolean write(final ImageOutputStream targetImageStream) throws IORuntimeException {
|
||||
public void write(final ImageOutputStream targetImageStream) throws IORuntimeException {
|
||||
Assert.notBlank(this.targetImageType, "Target image type is blank !");
|
||||
Assert.notNull(targetImageStream, "Target output stream is null !");
|
||||
|
||||
final Image targetImage = (null == this.targetImage) ? this.srcImage : this.targetImage;
|
||||
Assert.notNull(targetImage, "Target image is null !");
|
||||
|
||||
return ImgUtil.write(targetImage, this.targetImageType, targetImageStream, this.quality, this.backgroundColor);
|
||||
ImgUtil.write(targetImage, this.targetImageType, targetImageStream, this.quality, this.backgroundColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为目标文件扩展名对应的格式
|
||||
*
|
||||
* @param targetFile 目标文件
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public boolean write(final File targetFile) throws IORuntimeException {
|
||||
public void write(final File targetFile) throws IORuntimeException {
|
||||
final String formatName = FileNameUtil.extName(targetFile);
|
||||
if (StrUtil.isNotBlank(formatName)) {
|
||||
this.targetImageType = formatName;
|
||||
@ -752,7 +749,7 @@ public class Img implements Serializable {
|
||||
ImageOutputStream out = null;
|
||||
try {
|
||||
out = ImgUtil.getImageOutputStream(targetFile);
|
||||
return write(out);
|
||||
write(out);
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.math.NumberUtil;
|
||||
import cn.hutool.core.net.url.URLUtil;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
@ -502,6 +501,7 @@ public class ImgUtil {
|
||||
Assert.notNull(destImageFile);
|
||||
Assert.isFalse(srcImageFile.equals(destImageFile), "Src file is equals to dest file!");
|
||||
|
||||
// 通过扩展名检查图片类型,相同类型直接复制
|
||||
final String srcExtName = FileNameUtil.extName(srcImageFile);
|
||||
final String destExtName = FileNameUtil.extName(destImageFile);
|
||||
if (StrUtil.equalsIgnoreCase(srcExtName, destExtName)) {
|
||||
@ -1430,15 +1430,8 @@ public class ImgUtil {
|
||||
|
||||
// 创建图片
|
||||
final BufferedImage image = new BufferedImage(width, height, imageType);
|
||||
final Graphics g = image.getGraphics();
|
||||
if (null != backgroundColor) {
|
||||
// 先用背景色填充整张图片,也就是背景
|
||||
g.setColor(backgroundColor);
|
||||
g.fillRect(0, 0, width, height);
|
||||
}
|
||||
g.setColor(ObjUtil.defaultIfNull(fontColor, Color.BLACK));
|
||||
g.setFont(font);// 设置画笔字体
|
||||
g.drawString(str, 0, font.getSize());// 画出字符串
|
||||
final Graphics g = GraphicsUtil.createGraphics(image, backgroundColor);
|
||||
GraphicsUtil.drawString(g, str, font, fontColor, new Point(0, font.getSize()));
|
||||
g.dispose();
|
||||
|
||||
return image;
|
||||
@ -1535,6 +1528,19 @@ public class ImgUtil {
|
||||
write(image, imageType, getImageOutputStream(out));
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为目标文件扩展名对应的格式
|
||||
*
|
||||
* @param image {@link Image}
|
||||
* @param targetFile 目标文件
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static void write(final Image image, final File targetFile) throws IORuntimeException {
|
||||
final String imageType = FileNameUtil.extName(targetFile);
|
||||
ImgWriter.of(image, imageType).write(targetFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为指定格式:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG<br>
|
||||
* 此方法并不关闭流
|
||||
@ -1542,12 +1548,11 @@ public class ImgUtil {
|
||||
* @param image {@link Image}
|
||||
* @param imageType 图片类型(图片扩展名)
|
||||
* @param destImageStream 写出到的目标流
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public static boolean write(final Image image, final String imageType, final ImageOutputStream destImageStream) throws IORuntimeException {
|
||||
return write(image, imageType, destImageStream, 1);
|
||||
public static void write(final Image image, final String imageType, final ImageOutputStream destImageStream) throws IORuntimeException {
|
||||
write(image, imageType, destImageStream, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1557,110 +1562,57 @@ public class ImgUtil {
|
||||
* @param imageType 图片类型(图片扩展名)
|
||||
* @param targetImageStream 写出到的目标流
|
||||
* @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static boolean write(final Image image, final String imageType, final ImageOutputStream targetImageStream,
|
||||
final float quality) throws IORuntimeException {
|
||||
return write(image, imageType, targetImageStream, quality, null);
|
||||
public static void write(final Image image, final String imageType, final ImageOutputStream targetImageStream,
|
||||
final float quality) throws IORuntimeException {
|
||||
write(image, imageType, targetImageStream, quality, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为指定格式
|
||||
*
|
||||
* @param image {@link Image}
|
||||
* @param imageType 图片类型(图片扩展名)
|
||||
* @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG)
|
||||
* @param destImageStream 写出到的目标流
|
||||
* @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩
|
||||
* @param backgroundColor 背景色{@link Color}
|
||||
* @return 是否成功写出,如果返回false表示未找到合适的Writer
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static boolean write(final Image image, String imageType, final ImageOutputStream destImageStream,
|
||||
final float quality, final Color backgroundColor) throws IORuntimeException {
|
||||
if (StrUtil.isBlank(imageType)) {
|
||||
imageType = IMAGE_TYPE_JPG;
|
||||
}
|
||||
|
||||
public static void write(final Image image, final String imageType, final ImageOutputStream destImageStream,
|
||||
final float quality, final Color backgroundColor) throws IORuntimeException {
|
||||
final BufferedImage bufferedImage = toBufferedImage(image, imageType, backgroundColor);
|
||||
final ImageWriter writer = getWriter(bufferedImage, imageType);
|
||||
return write(bufferedImage, writer, destImageStream, quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为目标文件扩展名对应的格式
|
||||
*
|
||||
* @param image {@link Image}
|
||||
* @param targetFile 目标文件
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static void write(final Image image, final File targetFile) throws IORuntimeException {
|
||||
FileUtil.touch(targetFile);
|
||||
ImageOutputStream out = null;
|
||||
try {
|
||||
out = getImageOutputStream(targetFile);
|
||||
write(image, FileNameUtil.extName(targetFile), out);
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
write(bufferedImage, destImageStream, quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ImageWriter}写出图片到输出流
|
||||
*
|
||||
* @param image 图片
|
||||
* @param writer {@link ImageWriter}
|
||||
* @param output 输出的Image流{@link ImageOutputStream}
|
||||
* @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩
|
||||
* @return 是否成功写出
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static boolean write(final Image image, final ImageWriter writer, final ImageOutputStream output, final float quality) {
|
||||
if (writer == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
writer.setOutput(output);
|
||||
final RenderedImage renderedImage = toRenderedImage(image);
|
||||
// 设置质量
|
||||
ImageWriteParam imgWriteParams = null;
|
||||
if (quality > 0 && quality < 1) {
|
||||
imgWriteParams = writer.getDefaultWriteParam();
|
||||
if (imgWriteParams.canWriteCompressed()) {
|
||||
imgWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
imgWriteParams.setCompressionQuality(quality);
|
||||
final ColorModel colorModel = renderedImage.getColorModel();// ColorModel.getRGBdefault();
|
||||
imgWriteParams.setDestinationType(new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (null != imgWriteParams) {
|
||||
writer.write(null, new IIOImage(renderedImage, null, null), imgWriteParams);
|
||||
} else {
|
||||
writer.write(renderedImage);
|
||||
}
|
||||
output.flush();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} finally {
|
||||
writer.dispose();
|
||||
}
|
||||
return true;
|
||||
public static void write(final Image image, final ImageOutputStream output, final float quality) {
|
||||
ImgWriter.of(image, null)
|
||||
.setQuality(quality)
|
||||
.write(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的Image对象和格式获取对应的{@link ImageWriter},如果未找到合适的Writer,返回null
|
||||
*
|
||||
* @param img {@link Image}
|
||||
* @param formatName 图片格式,例如"jpg"、"png"
|
||||
* @param formatName 图片格式,例如"jpg"、"png",{@code null}则使用默认值"jpg"
|
||||
* @return {@link ImageWriter}
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static ImageWriter getWriter(final Image img, final String formatName) {
|
||||
public static ImageWriter getWriter(final Image img, String formatName) {
|
||||
if (null == formatName) {
|
||||
formatName = IMAGE_TYPE_JPG;
|
||||
}
|
||||
final ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(toBufferedImage(img, formatName));
|
||||
final Iterator<ImageWriter> iter = ImageIO.getImageWriters(type, formatName);
|
||||
return iter.hasNext() ? iter.next() : null;
|
||||
@ -1669,11 +1621,15 @@ public class ImgUtil {
|
||||
/**
|
||||
* 根据给定的图片格式或者扩展名获取{@link ImageWriter},如果未找到合适的Writer,返回null
|
||||
*
|
||||
* @param formatName 图片格式或扩展名,例如"jpg"、"png"
|
||||
* @param formatName 图片格式或扩展名,例如"jpg"、"png",{@code null}则使用默认值"jpg"
|
||||
* @return {@link ImageWriter}
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static ImageWriter getWriter(final String formatName) {
|
||||
public static ImageWriter getWriter(String formatName) {
|
||||
if (null == formatName) {
|
||||
formatName = IMAGE_TYPE_JPG;
|
||||
}
|
||||
|
||||
ImageWriter writer = null;
|
||||
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(formatName);
|
||||
if (iter.hasNext()) {
|
||||
|
151
hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java
Normal file
151
hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java
Normal file
@ -0,0 +1,151 @@
|
||||
package cn.hutool.swing.img;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.Color;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 图片写出封装
|
||||
*/
|
||||
public class ImgWriter {
|
||||
|
||||
/**
|
||||
* 创建图片写出器
|
||||
*
|
||||
* @param image 图片
|
||||
* @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG)
|
||||
* @param backgroundColor 背景色{@link Color},{@code null}表示黑色或透明
|
||||
* @return {@code ImgWriter}
|
||||
*/
|
||||
public static ImgWriter of(final Image image, final String imageType, final Color backgroundColor) {
|
||||
return of(ImgUtil.toBufferedImage(image, imageType, backgroundColor), imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建图片写出器
|
||||
*
|
||||
* @param image 图片
|
||||
* @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG)
|
||||
* @return {@code ImgWriter}
|
||||
*/
|
||||
public static ImgWriter of(final Image image, final String imageType) {
|
||||
return new ImgWriter(image, imageType);
|
||||
}
|
||||
|
||||
private final RenderedImage image;
|
||||
private final ImageWriter writer;
|
||||
private ImageWriteParam writeParam;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param image {@link Image}
|
||||
* @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG)
|
||||
*/
|
||||
public ImgWriter(final Image image, final String imageType) {
|
||||
this.image = ImgUtil.toRenderedImage(image);
|
||||
this.writer = ImgUtil.getWriter(image, imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置写出质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩
|
||||
*
|
||||
* @param quality 写出质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩
|
||||
* @return this
|
||||
*/
|
||||
public ImgWriter setQuality(final float quality) {
|
||||
this.writeParam = buildParam(this.image, this.writer, quality);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG<br>
|
||||
* 此方法并不关闭流
|
||||
*
|
||||
* @param out 写出到的目标流
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public void write(final OutputStream out) throws IORuntimeException {
|
||||
write(ImgUtil.getImageOutputStream(out));
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出图像为目标文件扩展名对应的格式
|
||||
*
|
||||
* @param targetFile 目标文件
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public void write(final File targetFile) throws IORuntimeException {
|
||||
FileUtil.touch(targetFile);
|
||||
ImageOutputStream out = null;
|
||||
try {
|
||||
out = ImgUtil.getImageOutputStream(targetFile);
|
||||
write(out);
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ImageWriter}写出图片到输出流
|
||||
*
|
||||
* @param output 输出的Image流{@link ImageOutputStream}, 非空
|
||||
*/
|
||||
public void write(final ImageOutputStream output) {
|
||||
Assert.notNull(output);
|
||||
|
||||
final ImageWriter writer = this.writer;
|
||||
final RenderedImage image = this.image;
|
||||
writer.setOutput(output);
|
||||
// 设置质量
|
||||
try {
|
||||
if (null != this.writeParam) {
|
||||
writer.write(null, new IIOImage(image, null, null), this.writeParam);
|
||||
} else {
|
||||
writer.write(image);
|
||||
}
|
||||
output.flush();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} finally {
|
||||
writer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建图片写出参数
|
||||
*
|
||||
* @param renderedImage 图片
|
||||
* @param writer {@link ImageWriter}
|
||||
* @param quality 质量,范围0~1
|
||||
* @return {@link ImageWriteParam} or {@code null}
|
||||
*/
|
||||
private static ImageWriteParam buildParam(final RenderedImage renderedImage, final ImageWriter writer, final float quality) {
|
||||
// 设置质量
|
||||
ImageWriteParam imgWriteParams = null;
|
||||
if (quality > 0 && quality < 1) {
|
||||
imgWriteParams = writer.getDefaultWriteParam();
|
||||
if (imgWriteParams.canWriteCompressed()) {
|
||||
imgWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
imgWriteParams.setCompressionQuality(quality);
|
||||
final ColorModel colorModel = renderedImage.getColorModel();// ColorModel.getRGBdefault();
|
||||
imgWriteParams.setDestinationType(new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
|
||||
}
|
||||
}
|
||||
return imgWriteParams;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user