0612 | 실습 > 비트 연산자를 이용해서 데이터 뽑아내기
[1] 바이트 저장 순서 파악하기
✅ Endian
: 데이터가 있을때 어떤 순서로 메모리에 저장시킬 것인가?
예) 0x 12 34 56 78
✅ LittleEndian (intel cpu)
: 낮은 주소에 낮은 바이트부터 저장. (오른쪽부터 저장) 즉, 인간이 보았을때는 반대 순서이므로 왼쪽부터 읽게되어 반대로된 값을 읽게 된다.
예) 78 56 34 12
👉 우리가 왼쪽부터 읽지만 숫자계산은 일의자리부터 계산하는 것 처럼, 낮은자리부터 계산해야 높은자리에 반영하기 수월해지므로! BigEndian보다 불편해도 더 빠르게 진행할 수 있다는 장점이 있다.
✅ Big Endian (m1 cpu)
: 사람이 인식하는 방법과 동일. 낮은 주소에 데이터의 높은 바이트부터 저장.
예) 12 34 56 78
[2] 실습. 비트맵 이미지에 저장된 사진 사이즈 읽어오기
: 비트맵 파일은 첫 2바이트 (Signature)를 제외한 각 계층이 4바이트씩 이루어져 있으며, 각 계층마다 해당 이미지의 정보를 담고 있다.
예를 들어 File Size 는 3바이트부터 6바이트의 위치에 저장되어 있다.
19~22바이트에 해당하는 Image Width와 23~26바이트에 해당하는 Image Height를 읽어오면 이미지의 해상도를 추출해낼 수 있다.
2-1) 실습순서
- 읽어올 비트맵 이미지를 24비트로 저장 (저장 비트 타입에 따라 데이터가 조금씩 달라지므로, 여기서는 24비트로 한다)
- 자료 읽어오기
- width, height 데이터 뽑아내기 (*이 시점에서 원래 데이터와 반대로 기재되어있는 데이터를 얻게 된다)
- 현재 intel CPU를 사용중이므로 비트연산을 통해 각 바이트 위치를 바꾸기
- print해서 출력값 확인하기
import java.io.FileInputStream;
import java.io.IOException;
public class ImgSize2_ex {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("res/pic2.bmp"); //1050X 1400
// 필요없는 바이트 날리기
fis.read(); fis.read(); //signiture
fis.read();fis.read();fis.read();fis.read(); // filesize
fis.read();fis.read();fis.read();fis.read(); //reserved1,2
fis.read();fis.read();fis.read();fis.read(); // file offset to pixel Array
fis.read();fis.read();fis.read();fis.read(); // dib header size
int w1,w2,w3,w4;
int h1,h2,h3,h4;
// width 읽어오기
w1=fis.read();
w2=fis.read();
w3=fis.read();
w4=fis.read();
//height 읽어오기
h1=fis.read();
h2=fis.read();
h3=fis.read();
h4=fis.read();
//거꾸로된 데이터값 확인하기
System.out.printf("%d,%d,%d,%d%n",w1,w2,w3,w4);
System.out.printf("%d,%d,%d,%d%n",h1,h2,h3,h4);
fis.close();
// 비트연산으로 뒤집기
int weight = w4 <<24 | w3 <<16 | w2 << 8 | w1 << 0;
int height = h4 << 24 | h3 << 16 | h2 << 8 | h1 <<0;
System.out.printf("%d X %d", weight, height);
}
}
👉 바이너리 프로그램을 이용하면 거꾸로 저장되어있는 19~22, 23~26값을 (10진수로) 확인할 수 있다. 중간출력값과 일치한다! (* 3~6바이트에서 찾아서 출력한다면 file size 를 뽑아올 수 있겠지?)
👉 19,20,21,22 에 저장된 값을 22,21,20,19 순서로 뽑아야 하므로 비트연산을 통해 왼쪽으로 옮겨주는데, 1바이트가 옮겨가면 8비트로 움직이므로, 각각 24, 16, 8비트씩 움직인다.
👉 이때 1바이트씩 읽어오는 read()는 반환값이 int이므로 10진수로 수치를 확인하기 용이하다. 읽어오는값과 반환값이 다르다는 점을 기억하기.
* 마이너스값이 나오거나, 값이 일치하지 않는 경우.
1) 동일한 24비트 이미지로 비교중인지 확인하기. 나는 24비트로 전환하지 않은 파일의 데이터 vs 코드에 넣은 24비트 데이터로 비교해서 약간의 오차가 있었다.
2) 기존값 리셋하기. 비트를 밀었을때 해당 칸에 기존 스레드가 남아있으면 수치가 섞일 수 있다. & 연산자를 이용해서 값을 초기화 시켜주기.
int size =0; // 62,25,11,00 > 00,11,25,62
//ff를 2진수로 바꾸면 11111111이므로 기존값을 해치지 않고 유지할 수 있다 (&연산)
size =
n4<<24 | //(n4<<24)&0xff000000 연산자는 16진수로 표기돼서 00 두자리가 1바이트.
n3<<16 | //(n3<<16)&ox00ff0000
n2<<8 | //(n2<<8)&0x0000ff00
n1<<0; //(n1<<0)&0x000000ff