Java保存8位bmp文件爬坑历险记

因为工作需要,使用在安卓中处理8位bmp图片,其实Java有一个ImageIo的类javax.imageio.ImageIO。但是安卓中导入这个类的方法没有找到,直接导入rt.jar这个包就50多M,
安卓中简直没法用啊。因为从扫描仪中获取的的raw的图片原数据,就是存储色彩信息的byte[ ],需要对这个byte[ ]进行处理,添加bmp的文件头+位图信息头+调色板+位图数据。爬坑过程不说了,反正
网上的资料多是关于24位bmp保存的,而且好像都来自一个文章,关于8位调色板的很少。经历三天的煎熬,终于找到了一种方法,保存8位bmp,如果有更好的方法,欢迎指教。如果是调色板有问题,位图
会是纯白,纯黑等,无法显示正常图像。好了,代码奉上。


package com.idfounder.leakcanarydemo;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by hongzhen on 2017/7/13.
 */

public class BmpUtils {

    private byte[] bytes;
    private int index = 54;

    public BmpUtils() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    File file = new File("/sdcard/Temp/1.raw");
                    FileInputStream fileInputStream = new FileInputStream(file);
                    bytes = new byte[(int)file.length()];
                    while ((fileInputStream.read(bytes)) != -1) {

                    }
                    fileInputStream.close();
                    getBmpWith8(bytes,"/sdcard/Temp/bmp.bmp");              
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    /**
     * 保存8位位图,需要添加颜色调色板,文件信息头+位图信息头+调色板+位图数据
     * @param bufferSrc
     * @param imgPath
     */
    public void getBmpWith8(byte[] bufferSrc, String imgPath) {
        int w = 800;
        int h = 750;
        byte[] color_table = addBMP8ImageInfosHeaderTable(w, h);          //颜色表,8位图必须有
        byte[] infos = addBMP8ImageInfosHeader(w, h);                     //文件信息头
        byte[] header = addBMP8ImageHeader(bufferSrc.length, infos.length +
                color_table.length);                             //文件头
        byte[] buffer = new byte[header.length + infos.length + color_table.length
                + bufferSrc.length];                                   //申请用来组合上面四个部分的空间,这个空间直接保存就是bmp图了
        System.arraycopy(header, 0, buffer, 0, header.length);           //复制文件头
        System.arraycopy(infos, 0, buffer, header.length, infos.length); //复制文件信息头
        System.arraycopy(color_table, 0, buffer, header.length + infos.length,
                color_table.length);                             //复制颜色表
        System.arraycopy(bufferSrc, 0, buffer, header.length + infos.length +
                color_table.length, bufferSrc.length);
        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream(imgPath);
            fos.write(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    
  

    //采集原数据byte数组800*750-->640*640
    private byte[] changeByte(byte[] byteSrc) {
        int w = 640;
        int h = 640;
        byte[] bytes = new byte[w * h];
        //灰度图像8位深度
        int newbiBitCount = 8;
        //8位图像数据每行字节数为4的倍数
       int lineByte = (w * newbiBitCount / 8 + 3) / 4 * 4;
//        int offset = 0;
//        for (int i = 55; i < h - 55; i++) {
//            for (int j = 80; j < w - 80; j++) {
//                bytes[i * 640 + j] = (byte) byteSrc[i * w + j];
//                offset++;
//            }
//        }
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++)
            {
                bytes[i * w + j] = (byte) byteSrc[i * 800 + 80 + j];
            //        bytes[i * w + j] = (byte) byteSrc[(i) * (800) + (j)];
//                offset++;
            }
        }
        return bytes;
    }

    /**
     * 裁剪并旋转180度原数据
     * @param byteSrc
     * @return
     */
    private byte[] changeRotateByte(byte[] byteSrc){
        int desW=(800-640)/2;//80
        int desH=(750-640)/2;//55
        int w=640;
        int h=640;
        byte[] bytes = new byte[640 * 640];
        //灰度图像8位深度
        int newbiBitCount = 8;
        //8位图像数据每行字节数为4的倍数
        int lineByte = (w * newbiBitCount / 8 + 3) / 4 * 4;
        int offset=0;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
//                bytes[i*lineByte + j] = (byte) byteSrc[i*w+j];
                bytes[i * w + j] = (byte) byteSrc[(750-desH-i) * 800 + (800-desW - j)];
            }
        }
        return bytes;
    }

    /**
     * Bitmap图像旋转
     * @param bitMap
     * @param newWidth
     * @param newHeight
     * @return
     */
    private Bitmap changeBitmapScale(Bitmap bitMap, int newWidth, int newHeight) {

        int width = bitMap.getWidth();
        int height = bitMap.getHeight();
        // 计算缩放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要缩放的matrix参数
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的图片
        bitMap = Bitmap.createBitmap(bitMap, 0, 0, width, height, matrix, true);
        return bitMap;
    }

    /**
     * 8位位图的文件头
     * @param size
     * @param lenH
     * @return
     */
    private byte[] addBMP8ImageHeader(int size, int lenH) {
        byte[] buffer = new byte[14];
        int m_lenH = lenH + buffer.length;      //lenH:文件信息头
        //和颜色表长度之和
        size += m_lenH;     //size:颜色数据的长度+两个文件头长度+颜色表长度
        buffer[0] = 0x42;   //WORD 固定为0x4D42;
        buffer[1] = 0x4D;
        buffer[2] = (byte) (size >> 0);    //DWORD 文件大小
        buffer[3] = (byte) (size >> 8);
        buffer[4] = (byte) (size >> 16);
        buffer[5] = (byte) (size >> 24);
        buffer[6] = 0x00;    //WORD 保留字,不考虑
        buffer[7] = 0x00;
        buffer[8] = 0x00;    //WORD 保留字,不考虑
        buffer[9] = 0x00;
        buffer[10] = (byte) (m_lenH >> 0);      //DWORD 实际位图数据的偏移字
        buffer[11] = (byte) (m_lenH >> 8);      //节数,即所有三个头(文件头、
        buffer[12] = (byte) (m_lenH >> 16);     //文件信息头、颜色表)之和
        buffer[13] = (byte) (m_lenH >> 24);     //14 + 40 + 1024 = 1078
        //0x0436   0x0036=40+14=54
        return buffer;
    }

   

    private byte[] addBMP_8(byte[] b, int w, int h) {
        int len = b.length;
        System.out.println(b.length);
        byte[] buffer = new byte[w * h];
        int offset = 0;
        for (int i = len - 1; i >= (w - 1); i -= w) {
            // 对于bmp图,DIB文件格式最后一行为第一行,每行按从左到右顺序
            int end = i, start = i - w + 1;
            for (int j = start; j <= end; j++) {
                buffer[offset] = b[j];
                offset++;
            }
        }
        return buffer;
    }

    /**
     * 8位位图的位图信息头
     * @param w
     * @param h
     * @return
     */
    private byte[] addBMP8ImageInfosHeader(int w, int h) {
        byte[] buffer = new byte[40];
        int ll = buffer.length;
        buffer[0] = (byte) (ll >> 0);    //DWORD:本段头长度:40   0x0028
        buffer[1] = (byte) (ll >> 8);
        buffer[2] = (byte) (ll >> 16);
        buffer[3] = (byte) (ll >> 24);
        buffer[4] = (byte) (w >> 0);    //long:图片宽度
        buffer[5] = (byte) (w >> 8);
        buffer[6] = (byte) (w >> 16);
        buffer[7] = (byte) (w >> 24);
        buffer[8] = (byte) (h >> 0);    //long:图片高度
        buffer[9] = (byte) (h >> 8);
        buffer[10] = (byte) (h >> 16);
        buffer[11] = (byte) (h >> 24);
        buffer[12] = 0x01;           //WORD:平面数:1
        buffer[13] = 0x00;
        buffer[14] = 0x08;           //WORD:图像位数:8位
        buffer[15] = 0x00;
        buffer[16] = 0x00;           //DWORD:压缩方式,可以是0,1,2,
        buffer[17] = 0x00;           //其中0表示不压缩
        buffer[18] = 0x00;
        buffer[19] = 0x00;
        buffer[20] = 0x00;           //DWORD;实际位图数据占用的字节数,当上一个数值
        buffer[21] = 0x00;           //biCompression等于0时,这里的值可以省略不填
        buffer[22] = 0x00;
        buffer[23] = 0x00;
        buffer[24] = (byte) 0x20;    //LONG:X方向分辨率
        buffer[25] = 0x4E;           //20000(0x4E20) dpm  1 in = 0.0254 m
        buffer[26] = 0x00;
        buffer[27] = 0x00;
        buffer[28] = (byte) 0x20;    //LONG:Y方向分辨率
        buffer[29] = 0x4E;           //20000(0x4E20) dpm  1 in = 0.0254 m
        buffer[30] = 0x00;
        buffer[31] = 0x00;
        buffer[32] = 0x00;           //DWORD:使用的颜色数,如果为0,
        buffer[33] = 0x00;           //则表示默认值(2^颜色位数)
        buffer[34] = 0x00;
        buffer[35] = 0x00;
        buffer[36] = 0x00;           //DWORD:重要颜色数,如果为0,
        buffer[37] = 0x00;           //则表示所有颜色都是重要的
        buffer[38] = 0x00;
        buffer[39] = 0x00;

        return buffer;
    }

    

    /**
     * 8位位图的颜色调板
     * @param w
     * @param h
     * @return
     */
    private byte[] addBMP8ImageInfosHeaderTable(int w, int h) {
        byte[] buffer = new byte[256 * 4];

        //生成颜色表
        for (int i = 0; i < 256; i++) {
            buffer[0 + 4 * i] = (byte) i;   //Blue
            buffer[1 + 4 * i] = (byte) i;   //Green
            buffer[2 + 4 * i] = (byte) i;   //Red
            buffer[3 + 4 * i] = (byte) 0x00;   //保留值
        }

        return buffer;
    }

}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值