之前我们研究了如何获取文件的二进制编码。计算机中图片也是以二进制的方式保存。获取到图片的二进制编码后,只要对这些编码进行操作就可以想要的图片了。
下面就来探索如何将图片颜色反向。常见的图片格式有jpg,bmp,png,gif。而jpg,png,gif都是按一定的标准进行压缩的,处理起来比较麻烦。bmp为未压缩的图片,所以我选择了bmp格式的图片进行颜色反向。
1.准备一张bmp图片
![](https://i-blog.csdnimg.cn/blog_migrate/5d68d7565444b519920f91c4c0abfc45.jpeg)
这个其实是一张bmp图片,不知道为什么csdn上传了好几次都传不上bmp后缀的图片,就把后缀改成了jpg。不过不影响内容。
2.原理
bmp图片由4部分组成信息块,图像描述信息块,颜色表和图像数据区组成
下面的00001,00002表示二进制文件中第几个字节
1.文头信息块
0000-0001:文件标识,为字母ASCII码“BM”。
0002-0005:文件大小。
0006-0009:保留,每字节以“00”填写。
000A-000D:记录图像数据区的起始位置。
各字节的信息依次含义为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)。
2.图像描述信息块
000E-0011:图像描述信息块的大小,常为28H。
0012-0015:图像宽度。
0016-0019:图像高度。
001A-001B:图像的plane(平面?)总数(恒为1)。
001C-001D:记录像素的位数,很重要的数值,图片的颜色数由该值决定。
001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。
0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。
3.颜色表
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(像素的透明度值,一般不需要)。即首先4字节表示颜色号0的颜色,接下来表示颜色号1的颜色,依此类推。
4.图像数据区
---from 百度文库
我们要做处理的就是图像数据区域
反向颜色就是生成原理颜色的补色,对于二进制来说就是做补。
*~是位运算符,意义是
按位非(NOT)
按位非也叫做补,一元运算符NOT“~”是对其运算数的每一位取反。
例如:它的二进制代码为:
00101010
经过按位非运算成为
11010101
颜色反向算法实现:
- 读取二进制编码
- 将图像数据区域的二进制编码做,其它不变
- 保存图片文件
3.代码
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class j
{
public static byte[] fileToByte(String filepath) throws IOException//读取文件
{
byte[] bytes = null;
FileInputStream fis = null;
try
{
File file = new File(filepath);
fis = new FileInputStream(file);
bytes = new byte[(int) file.length()];
fis.read(bytes);
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
finally
{
fis.close();
}
return bytes;
}
public static void mywrite(byte[] data, String str)//保存图片
{
File file = new File(str); //1、建立连接
OutputStream os = null;
try
{
//2、选择输出流,以追加形式(在原有内容上追加) 写出文件 必须为true 否则为覆盖
os = new FileOutputStream(file, false);
// //和上一句功能一样,BufferedInputStream是增强流,加上之后能提高输出效率,建议
// os = new BufferedOutputStream(new FileOutputStream(file,true));
/* String string = "Programmer say : Hello World!";
byte[] data = string.getBytes(); //将字符串转换为字节数组,方便下面写入
*/
os.write(data, 0, data.length); //3、写入文件
os.flush(); //将存储在管道中的数据强制刷新出去
}
catch (FileNotFoundException e)
{
e.printStackTrace();
System.out.println("文件没有找到!");
}
catch (IOException e)
{
e.printStackTrace();
System.out.println("写入文件失败!");
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e)
{
e.printStackTrace();
System.out.println("关闭输出流失败!");
}
}
}
}
public static void main(String args[]) throws IOException
{
byte b[]=fileToByte("/storage/sdcard1/test.bmp");
byte[] b2=new byte[b.length];//新的图片的数据流
int u=0;
//读取头文件大小,头文件不用处理
for (int i=10;i < 11;i++)
{
u = 0xff & b[i];
System.out.println(0xff & b[i]);
System.out.println(String.format("%08d", Integer.parseInt(Integer.toBinaryString(0xff & b[i]))));
}
System.out.println(b.length);
/*A-D各字节的信息依次含义为:
文件头信息块大小,图像描述信息块的大小,
图像颜色表的大小,保留(为01)。
因此只需要读取第10个字节就可以了
*/
for (int i=0;i < u;i++)
{
b2[i] = b[i];
//System.out.println(String.format("%08d",Integer.parseInt(Integer.toBinaryString(0xff & b[i]))));
}//先写入头文件
for (int i=u;i < b.length;i++)
{
b2[i] = (byte) ~b[i];
//System.out.println(String.format("%08d",Integer.parseInt(Integer.toBinaryString(0xff & b[i]))));
}//处理图像
mywrite(b2, "/storage/sdcard1/result.bmp");
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/39a8e4d99b513b2d859724af0d9e5cf3.jpeg)