最近做的项目涉及到通过后台对图片进行旋转处理的需求。经过多方查阅资料及测试,最终选定了方案。现对实验中用到实现方式做如下总结:
一、直接旋转
直接对图片进行旋转处理,但这里需注意到图片宽高像素值必须为基数,如果为偶数,图片旋转后会出现一个像素的黑边。具体实现如下:
public Map<String, Object> rotateImgGraphics2D(HttpServletRequest request) {
String src = request.getParameter("src");
String angleStr = request.getParameter("angle");
Map<String, Object> ret = new HashMap<String, Object>();
if (Tools.isEmpty(src) || Tools.isEmpty(angleStr)) {
ret.put("success", false);
ret.put("msg", "参数有误");
return ret;
}
int angle = Integer.parseInt(angleStr);
BufferedImage bufferedimage = null;
File file = null;
try {// 从服务器读取照片
int h = 0;
int w = 0;
String userDir = System.getProperty("user.dir");
file = new File(userDir + src);
bufferedimage = ImageIO.read(file);
if (angle != 0) {
if (angle / 90 % 2 == 1) {// 旋转角度为90或270...时,图像的长宽对换
h = bufferedimage.getWidth();
w = bufferedimage.getHeight();
} else {
w = bufferedimage.getWidth();
h = bufferedimage.getHeight();
}
} else {// 旋转角度为0时,返回
ret.put("success", true);
ret.put("msg", "旋转角度为0");
return ret;
}
// 将像素值转换为颜色分量和 alpha 分量的方法,返回此 ColorModel 的转换类型。
int type = bufferedimage.getColorModel().getTransparency();
BufferedImage img;
img = new BufferedImage(w, h, type);
// 创建一个 Graphics2D,可以将它绘制到此 BufferedImage 中。
Graphics2D graphics2d = img.createGraphics();
// 将当前 Graphics2D Transform 与平移转换连接。后续呈现相对于前一位置平移指定的距离。
graphics2d.translate((w - bufferedimage.getWidth()) / 2, (h - bufferedimage.getHeight()) / 2);
graphics2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, // 插值提示键
RenderingHints.VALUE_INTERPOLATION_BILINEAR);// 插值提示值——图像中最接近整数坐标样本的 4 种颜色样本被线性地插入,以生成一个颜色样本
graphics2d.rotate(Math.toRadians(angle), bufferedimage.getWidth() / 2, bufferedimage.getHeight() / 2);// 注意此处是原图片的宽和长,不是计算后的,用计算后的宽和长,保存后又黑边
graphics2d.drawImage(bufferedimage, null, null);
// 把旋转后图片存入服务器
ImageIO.write(img, src.substring(src.lastIndexOf(".") + 1), file);
graphics2d.dispose();
ret.put("success", true);
ret.put("msg", "旋转成功");
} catch (IOException e) {
e.printStackTrace();
ret.put("success", false);
ret.put("msg", "旋转失败");
}
return ret;
}
二、通过Thumbnails进行图像旋转
Thumbnails工具类能帮助我们对图片进行很好的处理,Thumbnails对图片的操作进行了很好的封装,往往很复杂的步骤能用一行代码就完成。 而且支持多种语言开发。但是不知道为什么旋转后图片质量降低了,而且有些失真。具体实现如下:
public Map<String, Object> rotateImgThumbnails(HttpServletRequest request) {
String src = request.getParameter("src");
String angleStr = request.getParameter("angle");
Map<String, Object> ret = new HashMap<String, Object>();
if (Tools.isEmpty(src) || Tools.isEmpty(angleStr)) {
ret.put("success", false);
ret.put("msg", "参数有误");
return ret;
}
int angle = Integer.parseInt(angleStr);
if (angle == 0) {
ret.put("success", true);
ret.put("msg", "旋转角度为0");
return ret;
}
BufferedImage bufferedimage = null;
File file = null;
try {
// 从服务器中读取图片,用new URL(),读取本地磁盘中照片用new File()
String userDir = System.getProperty("user.dir");
file = new File(userDir + src);
bufferedimage = ImageIO.read(file);
int w = bufferedimage.getWidth();
int h = bufferedimage.getHeight();
int max = w > h ? w : h;
Thumbnails.of(bufferedimage).size(max, max).rotate(angle)
.outputFormat(src.substring(src.lastIndexOf(".") + 1)).toFile(userDir + src);
ret.put("success", true);
ret.put("msg", "旋转成功");
} catch (IOException e) {
e.printStackTrace();
ret.put("success", false);
ret.put("msg", "旋转失败");
}
return ret;
}
三、自己封装
自己封装的方法,运用旋转矩阵算法实现图像旋转。通过这种方式,不仅保证的图片的高保真,而且不用考虑因图片宽高像素值奇偶问题导致的黑边现象。部分实现如下:
public class RotateImgUtil {
/***
* 顺时针旋转90度(通过交换图像的整数像素RGB 值)
* @param bi
* @return
*/
public static BufferedImage rotateClockwise90(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
BufferedImage bufferedImage = new BufferedImage(height, width, bi.getType());
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if(width>=height) {
bufferedImage.setRGB(j, i, bi.getRGB(i, j));
}else {
bufferedImage.setRGB(height - 1 - j, width - 1 - i, bi.getRGB(i, j));
}
}
}
if(width>=height) {
bufferedImage=rotateHorizon(bufferedImage);
}else {
bufferedImage=rotateVertical(bufferedImage);
}
return bufferedImage;
}
/***
* 逆时针旋转90度/顺时针针旋转270度(通过交换图像的整数像素RGB 值)
* @param bi
* @return
*/
public static BufferedImage rotateCounterclockwise90(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
BufferedImage bufferedImage = new BufferedImage(height, width, bi.getType());
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if(width>height) {
bufferedImage.setRGB(height - 1 - j, width - 1 - i, bi.getRGB(i, j));
}else {
bufferedImage.setRGB(j, i, bi.getRGB(i, j));
}
}
}
if(width>height) {
bufferedImage=rotateHorizon(bufferedImage);
}else {
bufferedImage=rotateVertical(bufferedImage);
}
return bufferedImage;
}
/***
* 旋转180度(通过交换图像的整数像素RGB 值)
* @param bi
* @return
*/
public static BufferedImage rotate180(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
bufferedImage.setRGB(width - i - 1, height - j - 1, bi.getRGB(i, j));
return bufferedImage;
}
/***
* 水平翻转
* @param bi
* @return
*/
public static BufferedImage rotateHorizon(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
bufferedImage.setRGB(width - i - 1, j, bi.getRGB(i, j));
return bufferedImage;
}
/***
* 垂直翻转
* @param bi
* @return
*/
public static BufferedImage rotateVertical(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
bufferedImage.setRGB(i, height - 1 - j, bi.getRGB(i, j));
return bufferedImage;
}
}