Java文件处理(三)--图片处理系列之bmp图片颜色反向

        之前我们研究了如何获取文件的二进制编码。计算机中图片也是以二进制的方式保存。获取到图片的二进制编码后,只要对这些编码进行操作就可以想要的图片了。

        下面就来探索如何将图片颜色反向。常见的图片格式有jpg,bmp,png,gif。而jpg,png,gif都是按一定的标准进行压缩的,处理起来比较麻烦。bmp为未压缩的图片,所以我选择了bmp格式的图片进行颜色反向。 

1.准备一张bmp图片

test

  这个其实是一张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

颜色反向算法实现:

  1. 读取二进制编码
  2. 将图像数据区域的二进制编码做,其它不变
  3. 保存图片文件

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");

	}
}
效果图

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值