在一次做考试系统的时候,有一个场景是考生开考前需要通过系统做拍照并进行脸部信息的比对;脸部信息的计算使用FACE++(旷视科技)的接口,但是发现查看拍照的照片信息是,考生的照片显示十分模糊,对比度变低,有验证的泛红!经过检查发现报错在Oracle 数据库的blob 字段直接查看信息是正常的,再看看在程序里生成的图片缓存文件是模糊的图像;查看生成图片的代码,十分简单,如下:
//生成图片返回图片路径
public static String createImg(byte[] bytes,String imgName,String path){
StringBuilder fullPath = new StringBuilder(imgFile(path)).append(File.separator).append(imgName).append("."+ImgType);
File img = null;
try {
img = new File(fullPath.toString());
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
BufferedImage bi =ImageIO.read(bais);
ImageIO.write(bi, ImgType, img);//
bais.close();
} catch (Exception e) {
e.printStackTrace();
}
return filePath+File.separator+imgName+"."+ImgType;
}
代码中只是简单的将图片的二进制信息写成了图片。
网上了解了一下图片生成的问题,在二进制转换成BufferedImage 对象时可以生成的图片指定BGR 颜色模型;查看BufferedImage 的API 发现有一个构造函数是需要传如图片的宽度、高度和预定义图像类型 BufferedImage(int width, int height, int imageType) ;
代码修改后,图片正常显示!代码如下:
public static String createImg(byte[] bytes,String imgName,String path){
StringBuilder fullPath = new StringBuilder(imgFile(path)).append(File.separator).append(imgName).append("."+ImgType);
File img = null;
try {
img = new File(fullPath.toString());
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
BufferedImage bi =ImageIO.read(bais);
saveJpgImage(bi,fullPath.toString());
bais.close();
} catch (Exception e) {
e.printStackTrace();
}
return filePath+File.separator+imgName+"."+ImgType;
}
public static void saveJpgImage(BufferedImage image,
String filePath) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image
.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
saveImage(bufferedImage, ImgType, filePath);
}
public static void saveImage(BufferedImage image, String format,
String filePath) {
try {
ImageIO.write(image, format, new File(filePath));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
-------------------------------------------------------------------------------
以下是网上找到别人生成各种类型的图片的最终效果对比!
package test;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.stream.*;
import org.junit.Before;
import org.junit.Test;
/**
* 加载png格式图片,使用不同方式转为png或者jpg格式的性能对比。
* */
public class PngJpgImagePerTest {
private static String PNG = "png";
private static String JPG = "jpg";
private static String SimpleSavePNG = "__SimpleSavePNG.png";
private static String Convert2ArrayAndSavePNG = "__Convert2ArrayAndSavePNG.png";
private static String NewImageSavePNG = "__NewPNG.png";
private static String NewImageSaveJPG = "__NewJPG.jpg";
private static String SaveJPG = "__JPG_quality.jpg";
/**
* 保存文件。
* */
public static void save2File(String filePath, byte[] data) {
BufferedOutputStream bufferOutput = null;
try {
bufferOutput = new BufferedOutputStream(new FileOutputStream(
new File(filePath)), 1024);
bufferOutput.write(data);
bufferOutput.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (bufferOutput != null) {
try {
bufferOutput.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
/**
* load image
* */
public static BufferedImage loadImage(String filePath) {
try {
return ImageIO.read(new File(filePath));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* simple save use ImageIO.write
*/
public static void saveImage(BufferedImage image, String format,
String filePath) {
try {
ImageIO.write(image, format, new File(filePath));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* convert to byte array.
* */
public static byte[] convert2bytes(BufferedImage image, String format) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
ImageIO.write(image, format, bout);
byte[] data = bout.toByteArray();
return data;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* create new buffer image and save using png format.
* */
public static void savePngImage(BufferedImage image, String format,
String filePath) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image
.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
saveImage(bufferedImage, PNG, filePath);
}
/**
* create new buffer image and save using jpg format.
* */
public static void saveJpgImage(BufferedImage image, String format,
String filePath) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image
.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
saveImage(bufferedImage, JPG, filePath);
}
/**
* save jpg with specified quality. 为了图片质量,quality的值不能太低。
* */
public static void saveImageUsingJPGWithQuality(BufferedImage image,
String filePath, float quality) throws Exception {
BufferedImage newBufferedImage = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
newBufferedImage.getGraphics().drawImage(image, 0, 0, null);
Iterator<ImageWriter> iter = ImageIO
.getImageWritersByFormatName("jpeg");
ImageWriter imageWriter = iter.next();
ImageWriteParam iwp = imageWriter.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(quality);
File file = new File(filePath);
FileImageOutputStream fileImageOutput = new FileImageOutputStream(file);
imageWriter.setOutput(fileImageOutput);
IIOImage iio_image = new IIOImage(newBufferedImage, null, null);
imageWriter.write(null, iio_image, iwp);
imageWriter.dispose();
}
public static void drawString(Graphics2D g2, String value, int x, int y) {
Font font = new Font("Arial", Font.BOLD, 16);
g2.setColor(Color.BLACK);
g2.setFont(font);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.drawString(value, x, y);
}
private String sourceFilePath;
private BufferedImage sourceImage;
private int loop;
private float quality;
@Before
public void setup() {
sourceFilePath = "E:\\allencode\\ImgTest\\stat.png";
sourceImage = loadImage(sourceFilePath);
loop = 10;
quality = 0.8F;
Graphics2D g2 = sourceImage.createGraphics();
draw(g2);
}
private void draw(Graphics2D g2) {
drawString(g2, "Allen Hello world.", 500, 200);
}
/**
* ImageIO.write存储图片时主要的性能消耗在计算上。
* */
@Test
public void test_01() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long start = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long end = System.currentTimeMillis();
sb.append(" saveImage = " + (end - start));
long convertStart = System.currentTimeMillis();
byte[] pngData = convert2bytes(sourceImage, PNG);
long convertEnd = System.currentTimeMillis();
sb.append(" convert = " + (convertEnd - convertStart));
long saveStart = System.currentTimeMillis();
save2File(sourceFilePath + Convert2ArrayAndSavePNG, pngData);
long saveEnd = System.currentTimeMillis();
sb.append(" save = " + (saveEnd - saveStart));
sb.append("\n");
}
System.out.println(sb);
}
/**
* ImageIO.write和新建一个BufferedImage,采用jpg或png保存的比较。
* */
@Test
public void test_02() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long start = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long end = System.currentTimeMillis();
sb.append(" saveImage = " + (end - start));
start = System.currentTimeMillis();
savePngImage(sourceImage, "png", sourceFilePath + NewImageSavePNG);
end = System.currentTimeMillis();
sb.append(" savePngImage = " + (end - start));
start = System.currentTimeMillis();
saveJpgImage(sourceImage, "jpg", sourceFilePath + NewImageSaveJPG);
end = System.currentTimeMillis();
sb.append(" saveJpgImage = " + (end - start));
sb.append("\n");
}
System.out.println(sb);
}
/**
* ImageIO.write存储图片和保存jpg的时间对比。
* */
@Test
public void test_03() throws Exception {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long pngStart = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long pngEnd = System.currentTimeMillis();
sb.append(" saveImage = " + (pngEnd - pngStart));
long jpgStart = System.currentTimeMillis();
saveImageUsingJPGWithQuality(sourceImage, sourceFilePath + SaveJPG,
quality);
long jpgEnd = System.currentTimeMillis();
sb.append(" JPGWithQuality = " + (jpgEnd - jpgStart));
sb.append(" % = " + (pngEnd - pngStart) * 1D / (jpgEnd - jpgStart));
sb.append("\n");
}
System.out.println(sb);
}
}