Last active
October 25, 2018 09:03
-
-
Save belinwu/1fb216d2233df36b7b75dac07c2e006b to your computer and use it in GitHub Desktop.
Save Android Bitmap to .bmp file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 android.graphics.Bitmap; | |
/** | |
* Android Bitmap Object to .bmp image (Windows BMP v3 24bit) file util class | |
* | |
* ref : http://en.wikipedia.org/wiki/BMP_file_format | |
* | |
* @author ultrakain ( [email protected] ) | |
* @since 2012-09-27 | |
* | |
*/ | |
public class AndroidBmpUtil { | |
private final int BMP_WIDTH_OF_TIMES = 4; | |
private 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 boolean save(Bitmap orgBitmap, String filePath){ | |
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 : bmp file's width equals 4's multiple | |
int dummySize = 0; | |
byte[] dummyBytesPerRow = null; | |
boolean hasDummy = false; | |
if(isBmpWidth4Times(width)){ | |
hasDummy = true; | |
dummySize = BMP_WIDTH_OF_TIMES - (width % BMP_WIDTH_OF_TIMES); | |
dummyBytesPerRow = new byte[dummySize * BYTE_PER_PIXEL]; | |
for(int i = 0; i < dummyBytesPerRow.length; i++){ | |
dummyBytesPerRow[i] = (byte)0xFF; | |
} | |
} | |
int[] pixels = new int[width * height]; | |
int imageSize = pixels.length * BYTE_PER_PIXEL + (height * dummySize * BYTE_PER_PIXEL); | |
int imageDataOffset = 0x36; | |
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); | |
try { | |
/** | |
* 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 | |
buffer.put(writeInt(width)); | |
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 = 0; | |
int endPosition = 0; | |
while( row > 0 ){ | |
startPosition = (row - 1) * col; | |
endPosition = row * col; | |
for(int i = startPosition; i < endPosition; i++ ){ | |
buffer.put(write24BitForPixcel(pixels[i])); | |
if(hasDummy){ | |
if(isBitmapWidthLastPixcel(width, i)){ | |
buffer.put(dummyBytesPerRow); | |
} | |
} | |
} | |
row--; | |
} | |
FileOutputStream fos = new FileOutputStream(filePath); | |
fos.write(buffer.array()); | |
fos.close(); | |
} catch (IOException e1) { | |
e1.printStackTrace(); | |
isSaveSuccess = false; | |
} | |
finally{ | |
} | |
return isSaveSuccess; | |
} | |
/** | |
* Is last pixel in Android Bitmap width | |
* @param width | |
* @param i | |
* @return | |
*/ | |
private boolean isBitmapWidthLastPixcel(int width, int i) { | |
return i > 0 && (i % (width - 1)) == 0; | |
} | |
/** | |
* BMP file is a multiples of 4? | |
* @param width | |
* @return | |
*/ | |
private boolean isBmpWidth4Times(int width) { | |
return width % BMP_WIDTH_OF_TIMES > 0; | |
} | |
/** | |
* Write integer to little-endian | |
* @param value | |
* @return | |
* @throws IOException | |
*/ | |
private 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 integer pixel to little-endian byte array | |
* @param value | |
* @return | |
* @throws IOException | |
*/ | |
private byte[] write24BitForPixcel(int value) throws IOException { | |
byte[] b = new byte[3]; | |
b[0] = (byte)(value & 0x000000FF); | |
b[1] = (byte)((value & 0x0000FF00) >> 8); | |
b[2] = (byte)((value & 0x00FF0000) >> 16); | |
return b; | |
} | |
/** | |
* Write short to little-endian byte array | |
* @param value | |
* @return | |
* @throws IOException | |
*/ | |
private byte[] writeShort(short value) throws IOException { | |
byte[] b = new byte[2]; | |
b[0] = (byte)(value & 0x00FF); | |
b[1] = (byte)((value & 0xFF00) >> 8); | |
return b; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment