ColorConvertOp
java.awt.image
包下面有个类java.awt.image.ColorConvertOp
,类名直译就是”颜色转换操作”。
顾名思义,它的作用就是将一个色彩空间(color space)的图像转换为另一个色彩空间的图像。有了这个神器我们就能轻易的将一张彩色图你像转换成灰度(gray)或其他色彩空间图像。
代码非常简单,只要一行。
public BufferedImage toGray(BufferedImage srcImg){ return new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(srcImg, null);}
依此类推,你可以参照ColorConvertOp
的参数说明将图像转为其他格式。
java.awt.color.ColorSpace中列出了很多支持的色彩空间定义TYPE_RGB
,TYPE_CMYK
,TYPE_HSV
,TYPE_YCbCr
….
Raster.getDataElements
有时我们通过ImageIO得到解码后的图像数据对象(BufferedImage)以后,需要获取图像矩阵的裸数据(即一个存储图像数据的byte数组)。
BufferedImage中提供了一个getRGB()方法,它返回的是一个ARGB格式int[]数组(每个int型元素的4个字节分别代表一个像素的Alpha,Red,Green,Blue四个通道)
如果你要从这个方法获取RGB的数组,你还得自己写转换代码:
/*** 返回图像的RGB格式字节数组* @param image* @return*/public static byte[] getMatrixRGB(BufferedImage image){int w = image.getWidth();int h = image.getHeight();int[] intArray = new int[w * h];byte[] matrixRGB = new byte[w * h * 3];image.getRGB(0, 0, w, h, intArray, 0, w);// ARGB->RGBfor(int i=0,b=0;i<intArray.length;++i){matrixRGB[b++]=(byte) (matrixRGB[i]&0x000000FF);matrixRGB[b++]=(byte) ((matrixRGB[i]&0x0000FF00)>>8);matrixRGB[b++]=(byte) ((matrixRGB[i]&0x00FF0000)>>16);}return matrixRGB;}
好烦呐,我以前就是这么干的,真的没有提供更好的方法吗?
不是没有更好的方法,而是我学艺不精没找到而已。
在仔细研究了BufferedImage的代码之后,才明白getRGB()只是BufferedImage为默认 RGB 颜色模型 (TYPE_INT_ARGB
)提供的一个便利性封装。
通过getRGB()源码可以知道BufferedImage对象中真正的图像数据是由成员对象raster
(java.awt.image.WritableRaster
)管理。而WritableRaster
是java.awt.image.Raster
的子类。Raster
中getDataElements方法可以我们所需要的字节数组。
还以前面图像转灰度举例,如果要从灰度图像中获取图像矩阵的字节数组,代码示例如下:
/*** 获取灰度图像的字节数组* @param image* @return*/public static byte[] getMatrixGray(BufferedImage image) {// 转灰度图像BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(image, grayImage);// getData方法返回BufferedImage的raster成员对象return (byte[]) grayImage.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null); }
注意这里return语句使用了(byte[])强制类型转换,因为getDataElements返回的是打开声明 java.lang.Object对象。
也就是说getDataElements返回的未必是byte[]类型,为什么呢?看下面getDataElements方法的说明:
看不懂没关系,我们可以看到这里的返回的类型可能是:TYPE_BYTE,TYPE_USHORT,TYPE_INT,TYPE_SHORT,TYPE_FLOAT,TYPE_DOUBLE。并不一定是byte。
那么问题来了,如何控制返回的数组类型是byte[]呢?
同样,我们可以使用前面的ColorConvertOp
对象进行转换。
比如我们需要得到图像的RGB数据:
/*** 获取图像RGB格式数据* @param image* @return*/public static byte[] getMatrixRGB(BufferedImage image){if(image.getType()!=BufferedImage.TYPE_3BYTE_BGR){// 转sRGB格式BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgbImage);// 从Raster对象中获取字节数组return (byte[]) rgbImage.getData().getDataElements(0, 0, rgbImage.getWidth(), rgbImage.getHeight(), null);}else{return (byte[]) image.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);}}