Android to save bitmap as BMP format images

  • 2020-12-26 05:53:04
  • OfStack

For the latest project, save the image as a function, we need to save the image as jpg, png, bmp. Relatively simple for jpg and png, android provides the ES7en.compress () method to solve the problem immediately. But for the BMP format, there is no good support. I spent a few days searching the Internet for a long time, but I didn't find any useful answers. I also had some questions and no proper answers.


package com.test.bitmap;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class Mainactivity extends Activity {
ImageView img;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.sd);
img = (ImageView) findViewById(R.id.img1);
btn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
View view = v.getRootView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
if (bitmap != null) {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// bitmap.compress(CompressFormat.PNG, 90, bos);  Can only be converted into PNG , JPEG
// byte[] data = bos.toByteArray();
// img.setImageBitmap(BitmapFactory.decodeByteArray(data, 0,
// data.length));
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pixels=new int[w*h];
bitmap.getPixels(pixels, 0, w, 0, 0, w, h);


// ByteBuffer dst = ByteBuffer.allocate(bitmap.getRowBytes()
// * h);
// bitmap.copyPixelsToBuffer(dst);


// IntBuffer dst=IntBuffer.allocate(w*h);
// bitmap.copyPixelsToBuffer(dst);


byte[] rgb = addBMP_RGB_888(pixels,w,h);
byte[] header = addBMPImageHeader(rgb.length);
byte[] infos = addBMPImageInfosHeader(w, h);


byte[] buffer = new byte[54 + rgb.length];
System.arraycopy(header, 0, buffer, 0, header.length);
System.arraycopy(infos, 0, buffer, 14, infos.length);
System.arraycopy(rgb, 0, buffer, 54, rgb.length);
try {
FileOutputStream fos = new FileOutputStream(Environment
.getExternalStorageDirectory().getPath()
+ "/hello.bmp");
fos.write(buffer);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}


//BMP The file header 
private byte[] addBMPImageHeader(int size) {
byte[] buffer = new byte[14];
buffer[0] = 0x42;
buffer[1] = 0x4D;
buffer[2] = (byte) (size >> 0);
buffer[3] = (byte) (size >> 8);
buffer[4] = (byte) (size >> 16);
buffer[5] = (byte) (size >> 24);
buffer[6] = 0x00;
buffer[7] = 0x00;
buffer[8] = 0x00;
buffer[9] = 0x00;
buffer[10] = 0x36;
buffer[11] = 0x00;
buffer[12] = 0x00;
buffer[13] = 0x00;
return buffer;
}


//BMP File information header 
private byte[] addBMPImageInfosHeader(int w, int h) {
byte[] buffer = new byte[40];
buffer[0] = 0x28;
buffer[1] = 0x00;
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = (byte) (w >> 0);
buffer[5] = (byte) (w >> 8);
buffer[6] = (byte) (w >> 16);
buffer[7] = (byte) (w >> 24);
buffer[8] = (byte) (h >> 0);
buffer[9] = (byte) (h >> 8);
buffer[10] = (byte) (h >> 16);
buffer[11] = (byte) (h >> 24);
buffer[12] = 0x01;
buffer[13] = 0x00;
buffer[14] = 0x18;
buffer[15] = 0x00;
buffer[16] = 0x00;
buffer[17] = 0x00;
buffer[18] = 0x00;
buffer[19] = 0x00;
buffer[20] = 0x00;
buffer[21] = 0x00;
buffer[22] = 0x00;
buffer[23] = 0x00;
buffer[24] = (byte) 0xE0;
buffer[25] = 0x01;
buffer[26] = 0x00;
buffer[27] = 0x00;
buffer[28] = 0x02;
buffer[29] = 0x03;
buffer[30] = 0x00;
buffer[31] = 0x00;
buffer[32] = 0x00;
buffer[33] = 0x00;
buffer[34] = 0x00;
buffer[35] = 0x00;
buffer[36] = 0x00;
buffer[37] = 0x00;
buffer[38] = 0x00;
buffer[39] = 0x00;
return buffer;
}


private byte[] addBMP_RGB_888(int[] b,int w, int h) {
int len = b.length;
System.out.println(b.length);
byte[] buffer = new byte[w*h * 3];
int offset=0;
for (int i = len-1; i>=w; i-=w) {
//DIB File format last 1 Behavior of the first 1 Rows, each in left-to-right order 
int end=i,start=i-w+1;
for(int j=start;j<=end;j++){
buffer[offset]=(byte)(b[j]>>0);
buffer[offset+1]=(byte)(b[j]>>8);
buffer[offset+1]=(byte)(b[j]>>16);
offset += 3;
}
}
return buffer;
}
}

However, after I use it in this way, there will be a big color difference between the saved picture and the original one. Please see the attachment for details.
So I met a new trouble. I downloaded an UltraEdit software, and then opened the bmp image before saving and the bmp image after saving using UltraEdit. Analyze the format of bmp images. I found a very good description from the Internet. Please see the attachment for the detailed Analysis of the Chinese version. Provides two web sites for bmp format analysis:
https://www.ofstack.com/article/78186.htm
https://www.ofstack.com/article/78187.htm
Image header
1) 1-2 :(the numbers here represent "word ", that is, two bytes, same below) image file header. 0x4d42='BM', which means BMP format supported by Windows. (note: check ascii B 0 x42, M0x4d, bfType is two bytes, B low bytes, M high bytes bfType = 0 x4D42 so, rather than 0 x424D, but pay attention to)
2) 3-6: The entire file size. 4690 0000, is 00009046h=36934.
3) 7-8: Reserved, must be set to 0.
4) 9-10: Reserved, must be set to 0.
5) 11-14: Offset between graphs from file start (14+40+4* (2^biBitCount)). 4600 0000, for 00000046h=70, the above header is 35 words =70 bytes.

Bitmap information header

6) 15-18: Bitmap information header length.
7) 19-22: Bitmap width in pixels. 8000 0000, is 00000080h=128.
8) 23-26: Height of bitmap in pixels. 9000 0000 is 00000090h=144.
9) 27-28: The number of bitmaps' faces, which is always 1. 0100 is 0001h=1.
10) 29-30: Number of digits per pixel. Available in 1 (monochrome), 4 (16 colors), 8 (256 colors), 16 (64K, high color), 24 (16M, true color), 32 (4096M, enhanced true color). 1000 is 0010 h = 16.
11) 31-34: Compression description: there are 0 (no compression), 1 (RLE 8, 8-bit RLE compression), 2 (RLE 4, 4-bit RLE compression, 3 (Bitfields, bit field storage). RLE is simply compressed as pixel number + pixel value. T408 adopts the storage mode of bit field, representing one pixel with two bytes, and the bit field is allocated as r5b6g5. Figure 0300 0000 is 00000003h=3.
12) 35-38: The size of bitmap data in bytes, which must be a multiple of 4, equal to (≥ the smallest multiple of 4 of bitmap width) × bitmap height × the number of bits per pixel. 00900000 is 00009000h=80×90×2h=36864.
13) 39-42: Horizontal resolution in pixels/meters. A00F 0000 = 0000 0FA0h=4000.
14) 43-46: Vertical resolution expressed in pixels/meters. A00F 0000 = 0000 0FA0h=4000.
15) 47-50: Number of color indexes used in bitmaps. Setting it to 0 indicates the use of all palette items.
16) 51-54: Number of color indexes that have an important influence on image display. If it's 0, that means everything is important.

This 54 bit information is very important, so I made an attempt to verify whether the color deviation was caused by the difference in the header information of bmp image. The experimental method is as follows: in fact, it is very simple. In step 1, open the bmp images before and after saving using UltraEdit, copy and paste the first 54 bit value of the bmp image before saving into the head of the saved image, so that the header information of the two images is the head of the image before saving. Then the saved image under ctrl+s1 was opened again and the image did not change. Step 1: This time, do the opposite operation, that is, copy and paste the header of the saved bmp image, that is, the value of the first 54 bits, into the header of the saved bmp image, and it is found that there is no change, indicating that the file header is not the reason for the color difference.
All that is left is byte[] rgb = addBMP_RGB_888(pixels,w,h); Here's the problem. Go into this function, read it carefully, and find out where the color information is stored. Read the code and find that the original author's code has an bug. Here: buffer [offset + 1) = (byte) (b [j] > > 16); Should be buffer [offset + 2] = (byte) (b [j] > > 16); So offset should be +2, not + 1. After correcting the error, re-run 1 and find that the saved image color returns to normal, the same color as the original image. The problem has been solved.

Summary: Do not know why often encounter 1 some, the Internet is very common, but can not find the right solution to my problem, very depressed, a lot of links on the Internet are pointing to this address, but went in without more detailed explanation. I'm sorry. I'm sorry. I hope you can share some useful and feasible solutions online, which is good for everyone, so as not to waste your searching time.

Here I would like to thank the blogger of csdn for solving my problem. Of course, with other people's code, also need to think a lot, do not easily believe all.


Related articles: