BMP格式函数分析器java语言数学分析项目

Posted 九死九歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BMP格式函数分析器java语言数学分析项目相关的知识,希望对你有一定的参考价值。

一、项目简介:

  先给大家看一下这个小项目的效果:

  运行后生成的pic.bmp图片

  没错,这个项目的主要功能就是通过函数生成对应的图像。

  主要是用到的技术有:IO流、BMP格式分析、面向对象程序设计。

  项目结构如下:

  Main类主要用来测试,剩下的三个类我会在下面一一介绍。

二、项目内容:

① Color类

  众所周知,图片其实就是由像素组成的二维矩阵,那我们肯定就要构建一个Color类表示像素了,图片信息的存储就是一个Color类型二维数组存储。

package www.spd.pic;

public class Color {

	public static final Color BLACK = new Color((byte)0x00, (byte)0x00, (byte)0x00);
	public static final Color RED = new Color((byte)0xff, (byte)0x00, (byte)0x00);
	public static final Color GREEN = new Color((byte)0x00, (byte)0xff, (byte)0x00);
	public static final Color BLUE = new Color((byte)0x00, (byte)0x00, (byte)0xff);


	byte red;
	byte green;
	byte blue;

	/**
	 * 三个参数分别是三种三原色对应的数值
	 * @param red 红色
	 * @param green 绿色
	 * @param blue 蓝色
	 */
	public Color(byte red, byte green, byte blue) {

		this.red = red;
		this.green = green;
		this.blue = blue;

	}

	/**
	 * 继承{@link Object#toString()}方法,以实现方便输出
	 */
	@Override
	public String toString() {
		int r = red >= 0 ? red : (red + 0x100);
		int g = green >= 0 ? green : (green + 0x100);
		int b = blue >= 0 ? blue : (blue + 0x100);
		return String.format("#%02x%02x%02x", r, g, b);
	}

	/**
	 * 将颜色信息转换成字节数组
	 * @return
	 */
	public byte[] toByteArray() {
		byte[] arr = new byte[3];
		arr[0] = blue;
		arr[1] = green;
		arr[2] = red;
		return arr;
	}

}

② BMP类:

  对于BMP的文件格式分析详见这篇博文,写的很详细,我的项目就是参考了这篇博文:位图(bmp)文件格式分析

package www.spd.pic;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BMP {

	//文件名
	String name;
	//整个BMP文件的大小
	int bfSize;
	//位图的宽度,单位是像素
	int biWidth;
	//位图的高度,单位是像素
	int biHeight;
	//位图全部像素占用的字节数,BI_RGB时可设为0
	int biSizeImage;
	//因为32位的Windows操作系统处理4个字节(32位)的速度比较快,所以BMP的每一行颜色占用的字节数规定为4的整数倍。
	//如果一行颜色有两个像素,共占用6字节,如果要补齐4*2=8字节,就要再加两个0字节。
	//经计算,appendBit = biWidth % 4;
	int appendBytes;
	//表示一行像素真正占多少字节,即本身要占的字节加上补齐字节
	int widthBytes;

	//图片的像素信息
	Color[][] pixelsMatrix;

	public BMP(String path) {
		this(new File(path));
	}

	/**
	 * 通过传参{@link java.io.File}获得图片的各种信息(即所有的成员变量)
	 * @param file BMP文件
	 */
	public BMP(File file) {

		/* 获得文件名称并通过后缀名利用正则表达式判断是不是标准的bmp图片文件 */
		name = file.getName();
		Pattern p = Pattern.compile(".*\\\\.bmp");
		Matcher m = p.matcher(name);
		if (!m.find()) throw new IllegalArgumentException("文件后缀不正确!!");

		/* 获得字节数组 */
		byte[] arr = getByteArray(file);

		if (arr == null) throw new IllegalArgumentException("文件为空文件!!");

		/* bmp文件前两字节是“bm”即0x4d42,用来做标识,若前两位不是该字节则抛出异常 */
		int bfType = byteArrayToInteger(arr, 1, 0);
		if (bfType != 0x4d42) throw new IllegalArgumentException("文件受损!!");

		bfSize = byteArrayToInteger(arr, 0x5, 0x2);
		biWidth = byteArrayToInteger(arr, 0x15, 0x12);
		biHeight = byteArrayToInteger(arr, 0x19, 0x16);
		
		/* 1c到1f位表示一个像素占多少位,24位则是常用的十六进制颜色表示所对应的,两位就是黑白图片 */
		int biBitCount = byteArrayToInteger(arr, 0x1f, 0x1c);
		if (biBitCount != 24) throw new IllegalArgumentException("图片不是24位真色彩位图!!");

		biSizeImage = byteArrayToInteger(arr, 0x27, 0x24);
		appendBytes = biWidth % 4;
		widthBytes = biWidth * 3 + appendBytes;

		pixelsMatrix = new Color[biHeight][biWidth];

		/* 双层for循环获取像素信息 */
		for (int i = 0; i < biHeight; i++) {

			int pixelEnd = (biHeight - i - 1) * widthBytes + 0x36;

			for (int j = 0; j < biWidth; j++) {

				pixelsMatrix[i][j] = new Color(arr[pixelEnd + 2], arr[pixelEnd + 1], arr[pixelEnd]);
				pixelEnd += 3;

			}

		}

	}

	/**
	 * 获得某种颜色的图片
	 * @param color 若传参红则为一张只有红色的图片。以此类推
	 * @param name 文件名
	 * @param width 图片宽度
	 * @param height 图片高度
	 */
	public BMP(Color color, String name, int width, int height) {

		this.name = name;
		biWidth = width;
		biHeight = height;
		appendBytes = biWidth % 4;
		widthBytes = biWidth * 3 + appendBytes;
		pixelsMatrix = new Color[biHeight][biWidth];

		/* 遍历矩阵把color传参给每一个像素 */
		for (int i = 0; i < biHeight; i++) {
			for (int j = 0; j < biWidth; j++) {
				pixelsMatrix[i][j] = color;
			}
		}

		biSizeImage = widthBytes * height;
		bfSize = biSizeImage + 0x36;

	}

	public BMP(String name, int width, int height) {
		this(new Color((byte)0xff, (byte)0xff, (byte)0xff), name, width, height);
	}

	public BMP(Color color, int width, int height) {
		this(color, "pic.bmp", width, height);
	}

	public BMP(int width, int height) {
		this("pic.bmp", width, height);
	}

	/**
	 * 继承{@link Object#toString()}实现打印图片信息
	 */
	@Override
	public String toString() {
		return "BMP{" +
				"\\n\\tname=\\"" + name +
				"\\", \\n\\tbfSize=" + bfSize +
				", \\n\\tbiWidth=" + biWidth +
				", \\n\\tbiHeight=" + biHeight +
				", \\n\\tbiSizeImage=" + biSizeImage +
				", \\n\\tappendBytes=" + appendBytes +
				", \\n\\twidthBytes=" + widthBytes +
				"\\n}";
	}

	/**
	 * 通过传参{@link java.io.File} 并利用缓冲流{@link java.io.BufferedInputStream}获得其字节流
	 * @param file bmp文件
	 * @return 图片文件的字节流
	 */
	private static byte[] getByteArray(File file) {

		try(BufferedInputStream bis =
					new BufferedInputStream(
							new FileInputStream(file));
			ByteArrayOutputStream baos =
					new ByteArrayOutputStream()) {

			int len = -1;
			byte[] flush = new byte[1024];

			while ((len = bis.read(flush)) != -1) {
				baos.write(flush, 0, len);
				baos.flush();
			}

			return baos.toByteArray();

		} catch (FileNotFoundException e) {

			System.err.println("文件不存在!!");
			return null;

		} catch (IOException e) {

			System.err.println("IO操作出现异常!!");
			e.printStackTrace();
			return null;

		}

	}

	/**
	 * 该方法与{@link #integerToByteArray(int, int)}相反<br/>
	 * 获得字节数组的某几位对应的整型数<br/>
	 * 主要在中{@link #BMP(File)}中调用
	 * @param arr 字节数组
	 * @param begin 开始索引
	 * @param end 结束索引
	 * @return 对应的整型数
	 */
	private int byteArrayToInteger(byte[] arr, int begin, int end) {

		int ans = 0;
		int temp;

		if (begin <= end) {
			for (int i = begin; i <= end; i++) {
				ans *= 0x100;
				temp = arr[i] >= 0 ? arr[i] : (arr[i] + 128);
				ans += temp;
			}
		}

		if (begin > end) {
			for (int i = begin; i >= end; i--) {
				ans *= 0x100;
				temp = arr[i] >= 0 ? arr[i] : (arr[i] + 128);
				ans += temp;
			}
		}

		return ans;

	}

	/**
	 * 该方法与{@link #byteArrayToInteger(byte[], int, int)}相反<br/>
	 * 获得整型数对应的字节数组
	 * 重要在{@link #toByteArray()}中调用
	 * @param size 返回的数组占几个字节
	 * @param num 整型数的值
	 * @return 返回的字节数组
	 */
	private byte[] integerToByteArray(int size, int num) {
		byte[] arr = new byte[size];
		int i = 0;
		while (num > 0) {
			byte temp = (byte) (num % 0x100);
			num /= 0x100;
			try {
				arr[i] = temp;
			} catch (IndexOutOfBoundsException e) {
				throw new IllegalArgumentException("数字数值大于2^"+size);
			}
			i++;
		}
		return arr;
	}

	/**
	 * 把图片文件整个转化成字节流
	 * @return 图片文件对应的字节流
	 */
	public byte[] toByteArray() {
		try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

			baos.write("BM".getBytes());
			baos.write(integerToByteArray(4, bfSize));
			baos.write(new byte[4]);
			baos.write(integerToByteArray(4, 0x36));
			baos.flush();

			baos.write(integerToByteArray(4, 40));
			baos.write(integerToByteArray(4, biWidth));
			baos.write(integerToByteArray(4, biHeight));
			baos.write(integerToByteArray(2, 1));
			baos.write(integerToByteArray(2, 24));
			baos.write(new byte[4]);
			baos.write(integerToByteArray(4, biSizeImage));
			baos.write(new byte[16]);
			baos.flush();

			byte[] append = new byte[appendBytes];

			for (int i = biHeight - 1; i >= 0 ; i--) {

				for (int j = 0; j < biWidth; j++) {
					baos.write(pixelsMatrix[i][j].toByteArray());
				}

				baos.write(append);
				baos.flush();

			}

			return baos.toByteArray();

		} catch (IOException e) {

			System.err.println("IO操作出现异常!!");
			e.printStackTrace();
			return null;

		}
	}

	/**
	 * 把图片文件的字节流通过输出流{@link java.io.FileOutputStream}写入到外部文件中去
	 */
	public void createFile() {

		byte[] arr = toByteArray();

		try (FileOutputStream fos = new FileOutputStream(name)) {
			fos.write(arr);
			fos.flush();
		} catch (IOException e) {
			System.err.println("将图像对象写入成图像时出线IO异常!!");
		}

	}

}

③ getPicByFunc类:

  从字面意义上来看:“从函数获得图像类”,它的下面有一个内部接口Functial,即可作为函数的,一个内部类Function,里面有一个Functial对象,和一个Color对象,表示的是一个带颜色的函数。

package www.spd.pic;

public class getPicByFunc {

	public static BMP getPic(Function func, int size) {
		return getPic("pic.bmp", func, size);
	}

	public static BMP getPic(String name, Function func, int size) {
		return getPic(name, new Function[]{func}, size);
	}

	public static BMP getPic(Function[] functions, int size) {
		return getPic("pic.bmp", functions, size);
	}

	/**
	 * 
	 * @param name 写出的文件名
	 * @param functions 几个函数
	 * @param size 图片尺寸
	 * @return 返回图片
	 */
	public static BMP getPic(String name, Function[] functions, int size) {

		BMP pic = new BMP(name, size * 40, size * 40以上是关于BMP格式函数分析器java语言数学分析项目的主要内容,如果未能解决你的问题,请参考以下文章

BMP文件格式分析

BMP图片分析

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexFile loadDexFile 函数 | 构造函数 | openDexFile 函数 )(代码片

仅此一次对BMP文件做详细分析的机会,想了解的朋友千万不能错过

Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )(代码片

linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码