Android 保存yuyv数据y(灰度值)为bitmap原始图片,所有处理是8位像素数据

  public void saveImage(byte[] yuv, int[] rgb , int width, int height) {
 int y = 0;

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int dex = (i * width + j)*2;
                y = 0xff & yuv[dex];
                rgb[i*width + j] = 0xff000000| y << 16 | y << 8 | y;
                yuv_y[i*width + j] = yuv[dex];//一帧原始数据的y(灰度值)提取
            }
        }

   File appDir = new File(Environment.getExternalStorageDirectory(), "wy/"+getDate()+"/"+tv_scene.getText());
        if (!appDir.exists()) {
            appDir.mkdirs();
        }
 if (!TextUtils.isEmpty(text1)&&!TextUtils.isEmpty(text2)&&!TextUtils.isEmpty(text3)&&!TextUtils.isEmpty(text4)&&!TextUtils.isEmpty(text5)&&!TextUtils.isEmpty(text6)&&!TextUtils.isEmpty(text7)) {
            fileName = System.currentTimeMillis()+"_"+ tv_scene.getText()+"_"+textLh(text1)+"_"+textLh(text2)+"_"+textLh(text3)+"_"+textLh(text4)+"_"+textLh(text5)+"_"+textLh(text6)+"_"+text7+ ".bmp";

        }else {
            fileName = str = System.currentTimeMillis() +"_"+tv_scene.getText()+"_"+"7005"+"_"+"0301"+"_"+"0420"+"_"+"7005"+"_"+"0301"+"_"+"0420"+"_"+"00"+ ".bmp";

        }
        int len = yuv_y.length;
        int offset = 0;
        //原始数据 bitmap图片存储格式是从左下写到右上 ,此循环将数据颠倒存储,正好为bitmap需要的数据
        for (int i = len - 1; i >= (width - 1); i -= width) {
            // 对于bmp图,DIB文件格式最后一行为第一行,每行按从左到右顺序
            int end = i, start = i - width + 1;
            for (int j = start; j <= end; j++) {
                yuv_b[offset] = yuv_y[j];
                offset ++;
            }
        }
        //将一张640*960的图片分成 两张 640*480 的图片
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int dex = (i * width + j);
                if (i*width + j < width*height/2){
                    yuv_l[i*width + j] = yuv_b[dex];
                }else {
                    yuv_r[(i*width + j)-(width*height/2)] = yuv_b[dex];
                }


            }
        }
        //640*480的图片数据 顺时针旋转90度 为 480*640的图片
        int y_90 = 0;
        for (int j = 640-1; j >= 0; j--) {
            for (int i = 0; i < 480; i++) {

                int index = (i * 640 + j );
                int dex = (y_90 * 480 + i);

                    yuv_l_90[y_90] = yuv_l[index];

                    yuv_r_90[(y_90)] = yuv_r[index];

                y_90 ++ ;
            }

        }
        //旋转之后的两张480*640 数据拼起来 为960*640的图片数据
        for (int i = 0; i < 640; i++) {
            System.arraycopy(yuv_l_90,i*480, yuv_y, i*960, 480);
            System.arraycopy(yuv_r_90,i*480, yuv_y, i*960+480, 480);
        }


        try {
            AndroidBmpUtil bmpUtil = new AndroidBmpUtil();
//            bmpUtil.save(this,yuv_y,Cmd.width,Cmd.height, fileName,appDir);
//            bmpUtil.save(this,yuv_l_90,480,640, "_l"+fileName,appDir);
//            bmpUtil.save(this,yuv_r_90,480,640, "_r"+fileName,appDir);
//            System.arraycopy(yuv_l_90,0, yuv_y, 0, yuv_l_90.length);
//            System.arraycopy(yuv_r_90,0, yuv_y, yuv_l_90.length-1, yuv_r_90.length);

            bmpUtil.save(this,yuv_y,960,640, fileName,appDir);
            showShortMsg(fileName+"");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

这个工具类是直接保存bitmap 原始图片,占内存比较大

这个是24位bitmap图片工具类
package com.example.wyhfviewer.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import android.widget.Toast;

/**
 * Android Bitmap Object to .bmp image (Windows BMP v3 24bit) file util class
 *
 * ref : http://en.wikipedia.org/wiki/BMP_file_format
 *
 * @author ultrakain ( ultrasonic@gmail.com )
 * @since 2012-09-27
 *
 */
public class AndroidBmpUtil {

    private static final int BMP_WIDTH_OF_TIMES = 4;
    private static final int BYTE_PER_PIXEL = 3;

    /**
     * Android Bitmap Object to Window's v3 24bit Bmp Format File
     * @param orgBitmap
     * @param filePath
     * @return file saved result
     */
    public static boolean save(Bitmap orgBitmap, String filePath, File appDir) throws Exception {
        long start = System.currentTimeMillis();
        if(orgBitmap == null){
            return false;
        }

        if(filePath == null){
            return false;
        }

        boolean isSaveSuccess = true;

        //image size
        int width = orgBitmap.getWidth();
        int height = orgBitmap.getHeight();

        //image dummy data size
        //reason : the amount of bytes per image row must be a multiple of 4 (requirements of bmp format)
        byte[] dummyBytesPerRow = null;
        boolean hasDummy = false;
        int rowWidthInBytes = BYTE_PER_PIXEL * width; //source image width * number of bytes to encode one pixel.
        if(rowWidthInBytes%BMP_WIDTH_OF_TIMES>0){
            hasDummy=true;
            //the number of dummy bytes we need to add on each row
            dummyBytesPerRow = new byte[(BMP_WIDTH_OF_TIMES-(rowWidthInBytes%BMP_WIDTH_OF_TIMES))];


            //just fill an array with the dummy bytes we need to append at the end of each row


            for(int i = 0; i < dummyBytesPerRow.length; i++){
                dummyBytesPerRow[i] = (byte)0xFF;
            }
        }

        //an array to receive the pixels from the source image
        int[] pixels = new int[width * height];

        //the number of bytes used in the file to store raw image data (excluding file headers)
        int imageSize = (rowWidthInBytes+(hasDummy?dummyBytesPerRow.length:0)) * height;
        //file headers size
        int imageDataOffset = 0x36;

        //final size of the file
        int fileSize = imageSize + imageDataOffset;

        //Android Bitmap Image Data
        orgBitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        //ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
        ByteBuffer buffer = ByteBuffer.allocate(fileSize);

        /**
         * BITMAP FILE HEADER Write Start
         **/
        buffer.put((byte)0x42);
        buffer.put((byte)0x4D);

        //size
        buffer.put(writeInt(fileSize));

        //reserved
        buffer.put(writeShort((short)0));
        buffer.put(writeShort((short)0));

        //image data start offset
        buffer.put(writeInt(imageDataOffset));

        /** BITMAP FILE HEADER Write End */

        //*******************************************

        /** BITMAP INFO HEADER Write Start */
        //size
        buffer.put(writeInt(0x28));

        //width, height
        //if we add 3 dummy bytes per row : it means we add a pixel (and the image width is modified.
        buffer.put(writeInt(width+(hasDummy?(dummyBytesPerRow.length==3?1:0):0)));
        buffer.put(writeInt(height));

        //planes
        buffer.put(writeShort((short)1));

        //bit count
        buffer.put(writeShort((short)24));

        //bit compression
        buffer.put(writeInt(0));

        //image data size
        buffer.put(writeInt(imageSize));

        //horizontal resolution in pixels per meter
        buffer.put(writeInt(0));

        //vertical resolution in pixels per meter (unreliable)
        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        /** BITMAP INFO HEADER Write End */

        int row = height;
        int col = width;
        int startPosition = (row - 1) * col;
        int endPosition = row * col;
        while( row > 0 ){
            for(int i = startPosition; i < endPosition; i++ ){
                buffer.put((byte)(pixels[i] & 0x000000FF));


                buffer.put((byte)((pixels[i] & 0x0000FF00) >> 8));
                buffer.put((byte)((pixels[i] & 0x00FF0000) >> 16));
            }
            if(hasDummy){
                buffer.put(dummyBytesPerRow);
            }
            row--;
            endPosition = startPosition;
            startPosition = startPosition - col;
        }
        File file = new File(appDir, filePath);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(buffer.array());
        fos.close();
        Log.v("AndroidBmpUtil" ,System.currentTimeMillis()-start+" ms");

        return isSaveSuccess;
    }

    /**
     * Write integer to little-endian
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeInt(int value) throws IOException {
        byte[] b = new byte[4];

        b[0] = (byte)(value & 0x000000FF);
        b[1] = (byte)((value & 0x0000FF00) >> 8);
        b[2] = (byte)((value & 0x00FF0000) >> 16);
        b[3] = (byte)((value & 0xFF000000) >> 24);

        return b;
    }

    /**
     * Write short to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeShort(short value) throws IOException {
        byte[] b = new byte[2];

        b[0] = (byte)(value & 0x00FF);
        b[1] = (byte)((value & 0xFF00) >> 8);

        return b;
    }
}

使用工具类

AndroidBmpUtil bmpUtil = new AndroidBmpUtil();
 boolean isSaveResult = bmpUtil.save(bmp, fileName,appDir);
public void saveImage(Bitmap bmp) {

        File appDir = new File(Environment.getExternalStorageDirectory(), "wy");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        if (!TextUtils.isEmpty(text1)&&!TextUtils.isEmpty(text2)&&!TextUtils.isEmpty(text3)&&!TextUtils.isEmpty(text4)&&!TextUtils.isEmpty(text5)&&!TextUtils.isEmpty(text6)&&!TextUtils.isEmpty(text7)) {
            fileName = tv_scene.getText()+"_"+textLh(text1)+"_"+textLh(text2)+"_"+textLh(text3)+"_"+textLh(text4)+"_"+textLh(text5)+"_"+textLh(text6)+"_"+text7+"_"+System.currentTimeMillis() + ".bmp";

        }else {
            fileName = str = tv_scene.getText()+"_"+"7005"+"_"+"0301"+"_"+"0420"+"_"+"7005"+"_"+"0301"+"_"+"0420"+"_"+"00"+"_"+System.currentTimeMillis() + ".bmp";

        }



        try {
//使用工具类,保存原始bitmap
            AndroidBmpUtil bmpUtil = new AndroidBmpUtil();
            boolean isSaveResult = bmpUtil.save(bmp, fileName,appDir);
            showShortMsg(fileName+"");

//使用Android 原生保存,有压缩
//            FileOutputStream fos = new FileOutputStream(file);
//            bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
////            fos.flush();
////            fos.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
//        return file.getAbsolutePath();
    }

下面是8位

public class AndroidBmpUtil {

    private static final int BMP_WIDTH_OF_TIMES = 4;
    private static final int BYTE_PER_PIXEL = 1;

    /**
     * Android Bitmap Object to Window's v3 8bit Bmp Format File
     * @param
     * @param filePath
     * @return file saved result
     */
    public boolean save(Context context, byte[] yuv_y, int width, int height, String filePath, File appDir) throws Exception {
        long start = System.currentTimeMillis();
        if(yuv_y == null){
            return false;
        }

        if(filePath == null){
            return false;
        }

        boolean isSaveSuccess = true;


        //image dummy data size
        //reason : the amount of bytes per image row must be a multiple of 4 (requirements of bmp format)
        byte[] dummyBytesPerRow = null;
        boolean hasDummy = false;
        int rowWidthInBytes = BYTE_PER_PIXEL * width; //source image width * number of bytes to encode one pixel.
        if(rowWidthInBytes%BMP_WIDTH_OF_TIMES>0){
            hasDummy=true;
            //the number of dummy bytes we need to add on each row
            dummyBytesPerRow = new byte[(BMP_WIDTH_OF_TIMES-(rowWidthInBytes%BMP_WIDTH_OF_TIMES))];


            //just fill an array with the dummy bytes we need to append at the end of each row


            for(int i = 0; i < dummyBytesPerRow.length; i++){
                dummyBytesPerRow[i] = (byte)0xFF;
            }
        }

        //an array to receive the pixels from the source image
        int[] pixels = new int[width * height];

        //the number of bytes used in the file to store raw image data (excluding file headers)
        int imageSize = /*(rowWidthInBytes+(hasDummy?dummyBytesPerRow.length:0))*/width * height;
        //file headers size
        int imageDataOffset = 0x36;

        //final size of the file
        int fileSize = imageSize + imageDataOffset + 1024;


        //ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
        ByteBuffer buffer = ByteBuffer.allocate(fileSize);
        byte[] mBMPImageInfo = addBMPImageInfosHeaderTable(width, height);
        /**
         * BITMAP FILE HEADER Write Start
         **/
        buffer.put((byte)0x42);
        buffer.put((byte)0x4D);

        //size
        buffer.put(writeInt(fileSize));

        //reserved
        buffer.put(writeShort((short)0));
        buffer.put(writeShort((short)0));

        //image data start offset
        buffer.put(writeInt(imageDataOffset+1024));

        /** BITMAP FILE HEADER Write End */

        //*******************************************

        /** BITMAP INFO HEADER Write Start */
        //size
        buffer.put(writeInt(0x28));

        //width, height
        //if we add 3 dummy bytes per row : it means we add a pixel (and the image width is modified.
        buffer.put(writeInt(width/*+(hasDummy?(dummyBytesPerRow.length==3?1:0):0)*/));
        buffer.put(writeInt(height));

        //planes
        buffer.put(writeShort((short)1));

        //bit count
        buffer.put(writeShort((short)8));

        //bit compression
        buffer.put(writeInt(0));

        //image data size
        buffer.put(writeInt(imageSize));

        //horizontal resolution in pixels per meter
        buffer.put(writeInt(0));

        //vertical resolution in pixels per meter (unreliable)
        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        /** BITMAP INFO HEADER Write End */
        for(int i = 0; i < mBMPImageInfo.length; i++ ) {
            buffer.put((byte)(mBMPImageInfo[i] & 0x000000FF));
        }
        int row = height;
        int col = width;
        int startPosition = (row - 1) * col;
        int endPosition = row * col;
          //bmp格式存储从左下往右上写,我这里没有颠倒写入,可自行调试
            for(int i = 0; i < width*height; i++ ){
                buffer.put((byte)(yuv_y[i] & 0x000000FF));
            }
//        }



        Toast.makeText(context,buffer.array().length+"",Toast.LENGTH_SHORT).show();
        File file = new File(appDir, filePath);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(buffer.array());
        fos.close();
        Log.v("AndroidBmpUtil" ,System.currentTimeMillis()-start+" ms");

        return isSaveSuccess;
    }
    /**
     * 生成颜色表的示例程序(8位灰阶)如下(Java)
颜色表因位数不同而异,24位及以上可以忽略颜色表,8位图的颜色表要包含28 = 256种颜色,每种颜色由BGRA(蓝、绿、红、保留)四个元素组成,即256 * 4 = 1024,需占用1024个字节(byte)。因此,8位图的颜色表有256组颜色,每组颜色格式如下(C/C++):
BYTE rgbBlue;     //该颜色的蓝色分量
BYTE rgbGreen;    //该颜色的绿色分量
BYTE rgbRed;      //该颜色的红色分量
BYTE rgbReserved; //保留值,有人说是透明度,不过没见过bmp图能透明的,未追究
     * */
    private byte[] addBMPImageInfosHeaderTable(int w, int h) {
        byte[] buffer = new byte[256 * 4];

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

        return buffer;
    }
    /**
     * Write integer to little-endian
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeInt(int value) throws IOException {
        byte[] b = new byte[4];

        b[0] = (byte)(value & 0x000000FF);
        b[1] = (byte)((value & 0x0000FF00) >> 8);
        b[2] = (byte)((value & 0x00FF0000) >> 16);
        b[3] = (byte)((value & 0xFF000000) >> 24);

        return b;
    }

    /**
     * Write short to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeShort(short value) throws IOException {
        byte[] b = new byte[2];

        b[0] = (byte)(value & 0x00FF);
        b[1] = (byte)((value & 0xFF00) >> 8);

        return b;
    }
}

颜色表 https://blog.csdn.net/ichen86/article/details/50534197
8位bmp (头)54+1024(颜色表)+w*h(长乘宽数据)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容