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; } }