package com.basic.security.utils;
|
|
import android.graphics.Bitmap;
|
import android.util.Log;
|
|
import java.io.FileOutputStream;
|
import java.io.IOException;
|
import java.nio.ByteBuffer;
|
|
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;
|
}
|
}
|