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(长乘宽数据)
网友评论