安卓:保存位图BMP格式的文件 [英] Android : save a Bitmap to bmp file format
问题描述
我在内存中的位图,我需要将其保存在一个bmp文件(使用 BMP格式的文件)。
有没有办法做到这一点在Android?
(我看了很多帖子建议使用PNG格式 - 这是无损的 - 但是,这不是我所需要的:我真的需要在 bmp格式)。
我已经有一些code。使用将其保存在JPEG或PNG的<一个href=\"http://developer.android.com/reference/android/graphics/Bitmap.html#com$p$pss%28android.graphics.Bitmap.Com$p$pssFormat,%20int,%20java.io.OutputStream%29\"相对=nofollow> Bitmap.com preSS 方式:
/ **
*保存数据使用的格式到文件。
*当格式为空:位图将被保存为BMP格式
** /公共无效writeBitmapToFile(位图数据,文件档案,Bitmap.Com pressFormat格式){
FileOutputStream中OS = NULL;
尝试{
OS =新的FileOutputStream(文件);
如果(格式== NULL){ // TODO:将数据写入到文件中使用bmp格式 }其他{
data.com preSS(格式,100,OS); //确定为JPEG和PNG
}
os.flush();
}赶上(例外五){
//无关code
} {最后
//无关code
}
}
(我回答我的问题)
这是我目前的解决方案。正是从这个源得到: https://github.com/ultrakain/AndroidBitmapUtil (感谢ultrakain和@Francescoverheye)
我刚固定一个小错误中必须添加到每一行(该伪字节的计算,使得在字节每行的长度是4的倍数(所要求的bmp格式规范)。对>
我也做了一些修改,以提高性能。
进口java.io.FileOutputStream中;
进口java.io.IOException异常;
进口java.nio.ByteBuffer中;进口android.graphics.Bitmap;
进口android.util.Log;公共类AndroidBmpUtil { 私有静态最终诠释BMP_WIDTH_OF_TIMES = 4;
私有静态最终诠释BYTE_PER_PIXEL = 3; / **
* Android的位图对象窗口的V3 24位BMP格式的文件
* @参数orgBitmap
* @参数文件路径
* @返回文件保存的结果
* /
公共静态布尔保存(位图orgBitmap,字符串文件路径)抛出IOException
长启动= System.currentTimeMillis的();
如果(orgBitmap == NULL){
返回false;
} 如果(文件路径== NULL){
返回false;
} 布尔isSaveSuccess =真; //图片大小
INT宽度= orgBitmap.getWidth();
INT高度= orgBitmap.getHeight(); //图像伪数据的大小
//原因:每幅影像行的字节数必须是4(bmp格式的要求)的倍数
字节[] dummyBytesPerRow = NULL;
布尔hasDummy = FALSE;
INT rowWidthInBytes = BYTE_PER_PIXEL *宽度; //源图像宽度*字节数为en code一个像素。
如果(rowWidthInBytes%BMP_WIDTH_OF_TIMES大于0){
hasDummy =真;
//虚拟的字节数,我们需要在每一行添加
dummyBytesPerRow =新的字节[(BMP_WIDTH_OF_TIMES-(rowWidthInBytes%BMP_WIDTH_OF_TIMES))];
//只需填写一个阵列,我们需要在每行的最后追加虚拟字节
的for(int i = 0; I&LT; dummyBytesPerRow.length;我++){
dummyBytesPerRow [I] =(字节)0xFF的;
}
} //阵列从源图像接收像素
INT [] =像素新INT [宽*高]。 //在文件中用于存储原始图像数据的字节数(不包括文件头)
INT IMAGESIZE =(rowWidthInBytes +(hasDummy dummyBytesPerRow.length:0))*高度;
//文件头的大小
INT imageDataOffset = 0x36数据; //文件的最终尺寸
INT档案大小= IMAGESIZE + imageDataOffset; // Android的位图图像数据
orgBitmap.getPixels(像素,0,宽度,0,0,宽度,高度); // ByteArrayOutputStream BAOS =新ByteArrayOutputStream(档案大小);
ByteBuffer的缓冲= ByteBuffer.allocate(档案大小); / **
*位图文件标题写启动
** /
buffer.put((字节)的0x42);
buffer.put((字节)送出0x4d); //尺寸
buffer.put(writeInt(档案大小)); //保留
buffer.put(与writeShort((短)0));
buffer.put(与writeShort((短)0)); //图像数据开始偏移
buffer.put(writeInt(imageDataOffset)); / **位图文件标题写结束* / // ********* / **位图信息标题写开始* /
//尺寸
buffer.put(writeInt(0x28)); //宽,高
//如果我们增加每行3个虚拟字节数:这意味着我们增加一个像素(和图像的宽度被修改。
buffer.put(writeInt(宽+(hasDummy(dummyBytesPerRow.length == 3 1:0):?0)));
buffer.put(writeInt(高度)); //飞机
buffer.put(与writeShort((短)1)); //位计数
buffer.put(与writeShort((短)24)); //位COM pression
buffer.put(writeInt(0)); //图像数据大小
buffer.put(writeInt(IMAGESIZE)); 在每米像素//水平分辨率
buffer.put(writeInt(0)); //垂直分辨率,每米像素(不可靠)
buffer.put(writeInt(0)); buffer.put(writeInt(0)); buffer.put(writeInt(0)); / **位图信息标题写结束* / INT行=高度;
INT COL =宽度;
指定startPosition INT =(行 - 1)* COL;
INT endPosition =行*关口;
而(行大于0){
的for(int i =指定startPosition; I&LT; endPosition;我++){
buffer.put((字节)(像素由[i]&放大器; 0x000000FF));
buffer.put((字节)((象素由[i]&放大器; 0x0000FF00)GT;→8));
buffer.put((字节)((象素由[i]&放大器; 0x00FF0000)GT;&GT; 16));
}
如果(hasDummy){
buffer.put(dummyBytesPerRow);
}
行 - ;
endPosition指定startPosition =;
=指定startPosition指定startPosition - 关口;
} FOS的FileOutputStream =新的FileOutputStream(文件路径);
fos.write(buffer.array());
fos.close();
Log.v(AndroidBmpUtil,System.currentTimeMillis的() - 启动+毫秒); 返回isSaveSuccess;
} / **
*写整数小端
* @参数值
* @返回
*引发IOException
* /
私人静态的byte [] writeInt(int值)抛出IOException
字节[] B =新的字节[4]; B [0] =(字节)(值安培; 0x000000FF);
B〔1〕=(字节)((值安培; 0x0000FF00)GT;→8);
B〔2] =(字节)((值安培; 0x00FF0000)GT;&GT; 16);
B〔3〕=(字节)((值安培; 0xFF000000)GT;&GT; 24); 返回b;
} / **
*短写little-endian字节数组
* @参数值
* @返回
*引发IOException
* /
私人静态的byte []与writeShort(short值)抛出IOException
字节[] B =新的字节[2]; B [0] =(字节)(值安培;设为0x00FF);
B〔1〕=(字节)((值安培;为0xFF00)GT;→8); 返回b;
}
}
I have a Bitmap in memory and I need to save it in a bmp file (using the bmp file format).
Is there any way to do it on Android ?
(I read a lot of post suggesting to use the png format - which is loss-less - but, that's not what I need: I really need the bmp format).
I already have some code to save it in jpeg or png using the Bitmap.compress method :
/**
* Save data to file using format.
* When format is null : the bitmap will be saved in bmp format
**/
public void writeBitmapToFile(Bitmap data, File file, Bitmap.CompressFormat format) {
FileOutputStream os = null;
try {
os = new FileOutputStream(file);
if(format==null){
//TODO : write data to file using the bmp format
}else{
data.compress(format, 100, os); //ok for JPEG and PNG
}
os.flush();
} catch (Exception e) {
//irrelevant code
} finally {
//irrelevant code
}
}
(I'm answering my own question)
Here is my current solution. It is derived from this source : https://github.com/ultrakain/AndroidBitmapUtil (thanks to ultrakain and @Francescoverheye )
I just fix a little bug in computation of the dummy bytes that must be added to each row (so that the length of each row in bytes is a multiple of 4 (as required by the bmp format specifications).
I also made some changes to improve the performances.
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.graphics.Bitmap;
import android.util.Log;
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) throws IOException {
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;
}
FileOutputStream fos = new FileOutputStream(filePath);
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;
}
}
这篇关于安卓:保存位图BMP格式的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!