BMP 파일 구조 분석|BM 시그니처·DIB 헤더·픽셀 데이터 확인 방법
BMP(Bitmap Image File)는 픽셀 기반 이미지를 저장하는 대표적인 래스터 이미지 파일 형식이다.
일반적으로 .bmp 확장자를 사용하며 Windows 환경의 이미지 처리, 프로그램 리소스, 그래픽 데이터 교환 및 파일 포맷 분석 실습에 활용된다.
BMP는 JPEG·PNG처럼 특정 압축 알고리즘을 중심으로 설계된 형식이 아니다. 파일 헤더, DIB(Device Independent Bitmap) 헤더, 선택적 색상 테이블, 픽셀 데이터 배열을 통해 이미지의 크기와 저장 방식을 정의한다.
특히 BMP 파일 구조 분석에서는 파일 시작의 BM 시그니처, 픽셀 배열 시작 오프셋, DIB 헤더 크기, 이미지 너비와 높이, 비트 깊이, 압축 방식, 행 단위 패딩을 함께 확인해야 한다.
이번 글에서는 BMP 파일 구조 분석을 중심으로 BMP 헤더, DIB 구조, 픽셀 배열, 색상 테이블, 행 패딩, 압축 및 손상 검증 원리를 설명한다.
또한 Windows PowerShell 5.1에서 사용할 수 있는 읽기 전용 코드를 통해 실제 파일의 헤더, 이미지 크기, 픽셀 데이터 범위와 SHA-256 해시값을 확인하는 방법을 알아본다.
1. BMP 파일 구조 분석이 필요한 이유
BMP 파일은 비교적 구조가 명확한 이미지 형식이지만, 파일 확장자만으로 내부 데이터의 정상 여부를 확인할 수는 없다.
다음과 같은 상황에서 BMP 구조 분석이 도움이 된다.
- BMP 파일이 열리지 않는 경우
- 이미지 크기가 잘못 표시되는 경우
- 색상이 예상과 다르게 나타나는 경우
- 이미지가 거꾸로 표시되는 경우
- 파일 끝부분의 픽셀 데이터가 누락된 경우
- BMP 파일 크기가 예상보다 큰 이유를 확인하려는 경우
- 이미지 변환 과정에서 데이터 구조가 변경되었는지 점검하려는 경우
- 원본 파일과 복사본의 무결성을 확인하려는 경우
BMP의 핵심은 헤더에 기록된 이미지 정보와 실제 픽셀 데이터 배치가 서로 일치하는지 확인하는 것이다.
단, 헤더와 픽셀 데이터 범위가 정상이라고 해서 이미지의 모든 픽셀 값이 올바르거나 파일이 안전하다는 의미는 아니다.
2. BMP 파일의 기본 개념과 특징
BMP는 비트맵 이미지를 저장하기 위한 파일 형식이다.
주요 특징은 다음과 같다.
- 대표적인 파일 시그니처
BM사용 - 파일 크기와 픽셀 배열 오프셋 기록
- 다양한 DIB 헤더 버전 지원
- 1·4·8·16·24·32비트 등 여러 비트 깊이 지원
- 일부 형식에서 색상 테이블 사용
- 비압축 픽셀 데이터 저장 가능
- 일부 RLE 및 비트 마스크 방식 지원
- 행 단위 정렬과 패딩 사용
- 이미지의 상향식·하향식 저장 방향 구분
BMP는 단순한 비압축 이미지로 알려져 있지만 모든 BMP가 비압축인 것은 아니다.
압축 방식과 픽셀 형식은 DIB 헤더의 정보를 통해 판단해야 한다.
3. BMP 파일의 전체 구조
일반적인 Windows BMP 파일은 다음과 같은 구조를 가진다.
BMP File
│
├── BITMAPFILEHEADER (14 bytes)
│ ├── Signature
│ ├── File Size
│ ├── Reserved Fields
│ └── Pixel Data Offset
│
├── DIB Header
│ ├── Header Size
│ ├── Image Width
│ ├── Image Height
│ ├── Planes
│ ├── Bit Count
│ ├── Compression
│ └── Other Fields
│
├── Optional Bit Masks / Color Table
│
└── Pixel Data Array
├── Row 1 + Padding
├── Row 2 + Padding
└── ...
위 구조는 대표적인 Windows BMP 파일의 개념도다.
실제 파일에서는 DIB 헤더 버전과 압축 방식에 따라 선택적 필드의 위치와 크기가 달라질 수 있다.
따라서 고정된 헤더 길이만 가정해 모든 BMP를 해석해서는 안 된다.
4. BMP 파일 시그니처와 Magic Number
일반적인 BMP 파일은 다음 두 바이트로 시작한다.
42 4D
ASCII로 해석하면 다음과 같다.
BM
이 값은 Windows 비트맵 파일의 대표적인 시그니처다.
| 항목 | 값 |
|---|---|
| 대표 확장자 | .bmp |
| 대표 시그니처 | BM |
| HEX | 42 4D |
| 시그니처 길이 | 2바이트 |
| 일반적인 파일 헤더 | 14바이트 |
다만 비트맵 관련 데이터가 항상 BM으로 시작하는 것은 아니다.
예를 들어 DIB 데이터만 별도로 저장된 경우에는 BMP 파일 헤더가 존재하지 않을 수 있다.
또한 OS/2 계열에는 다른 비트맵 관련 파일 형식도 존재한다.
이번 실습은 BM 시그니처를 사용하는 일반적인 Windows BMP 파일을 대상으로 한다.
5. BITMAPFILEHEADER 구조
BMP 파일의 앞부분에는 일반적으로 14바이트의 BITMAPFILEHEADER가 저장된다.
| 파일 오프셋 | 크기 | 필드 |
|---|---|---|
| 0 | 2바이트 | bfType |
| 2 | 4바이트 | bfSize |
| 6 | 2바이트 | bfReserved1 |
| 8 | 2바이트 | bfReserved2 |
| 10 | 4바이트 | bfOffBits |
각 필드의 역할
bfType
BMP 파일 식별자다. 일반적으로 BM을 사용한다.
bfSize
파일 헤더에 기록된 전체 파일 크기다.
bfReserved1·bfReserved2
일반적인 BMP 파일에서는 0으로 설정되는 예약 필드다.
bfOffBits
파일 시작을 기준으로 픽셀 배열이 시작되는 오프셋이다.
예를 들어 bfOffBits가 54라면 픽셀 배열은 파일의 54번 바이트 위치에서 시작한다.
6. BMP 헤더의 리틀엔디언 저장 방식
Windows BMP 파일의 다중 바이트 정수 필드는 일반적으로 리틀엔디언 방식으로 저장된다.
예를 들어 32비트 값 54는 다음과 같이 기록된다.
36 00 00 00
16비트 값 24는 다음과 같이 기록된다.
18 00
따라서 BMP 파일을 분석할 때 숫자 필드의 바이트 순서를 올바르게 해석해야 한다.
잘못된 바이트 순서를 적용하면 파일 크기, 픽셀 오프셋, 이미지 너비와 높이가 비정상적으로 나타날 수 있다.
7. DIB 헤더의 역할
DIB(Device Independent Bitmap) 헤더는 이미지의 주요 속성을 정의한다.
대표적으로 다음 정보를 포함한다.
- 이미지 너비와 높이
- 색상 평면 수
- 픽셀당 비트 수
- 압축 방식
- 이미지 데이터 크기
- 해상도 관련 값
- 색상 테이블 관련 정보
- 비트 마스크 및 색 공간 정보
DIB 헤더에는 여러 버전이 있다.
| DIB 헤더 | 크기 |
|---|---|
| BITMAPCOREHEADER | 12바이트 |
| BITMAPINFOHEADER | 40바이트 |
| BITMAPV2INFOHEADER | 52바이트 |
| BITMAPV3INFOHEADER | 56바이트 |
| BITMAPV4HEADER | 108바이트 |
| BITMAPV5HEADER | 124바이트 |
52·56바이트 헤더는 널리 알려진 확장 형태지만 모든 구현에서 동일하게 지원되는 것은 아니다.
이번 PowerShell 실습은 40바이트 이상의 Windows 계열 DIB 헤더 중 BITMAPINFOHEADER와 공통인 앞부분을 분석한다.
12바이트 OS/2 CORE 헤더는 별도 구조이므로 실습 대상에서 제외한다.
8. BITMAPINFOHEADER의 40바이트 구조
BITMAPINFOHEADER는 대표적인 Windows BMP DIB 헤더다.
파일 헤더 14바이트 바로 뒤에서 시작하는 일반적인 구성은 다음과 같다.
| DIB 상대 오프셋 | 크기 | 필드 |
|---|---|---|
| 0 | 4바이트 | biSize |
| 4 | 4바이트 | biWidth |
| 8 | 4바이트 | biHeight |
| 12 | 2바이트 | biPlanes |
| 14 | 2바이트 | biBitCount |
| 16 | 4바이트 | biCompression |
| 20 | 4바이트 | biSizeImage |
| 24 | 4바이트 | biXPelsPerMeter |
| 28 | 4바이트 | biYPelsPerMeter |
| 32 | 4바이트 | biClrUsed |
| 36 | 4바이트 | biClrImportant |
이 필드들은 BMP 이미지를 해석하는 데 필요한 핵심 정보다.
그러나 DIB 헤더 크기가 40바이트보다 큰 경우에는 뒤쪽에 추가 필드가 포함될 수 있다.
9. BMP 이미지 너비와 높이
BMP 이미지의 크기는 일반적으로 biWidth와 biHeight에 저장된다.
예를 들어 다음 값이 기록되어 있다고 가정하자.
biWidth = 1920
biHeight = 1080
이는 가로 1920픽셀, 세로 1080픽셀 이미지를 의미한다.
음수 높이의 의미
Windows BMP의 일부 DIB 구조에서는 biHeight가 음수일 수 있다.
biHeight = -1080
이는 일반적으로 픽셀 행이 하향식(Top-down)으로 저장된다는 의미다.
반대로 양수 높이는 일반적으로 상향식(Bottom-up) 저장을 의미한다.
| 높이 값 | 일반적인 저장 방향 |
|---|---|
| 양수 | Bottom-up |
| 음수 | Top-down |
단, 모든 압축 방식에서 음수 높이를 허용하는 것은 아니다.
10. biPlanes와 biBitCount
biPlanes
일반적인 Windows BMP에서는 biPlanes 값이 1이어야 한다.
biBitCount
픽셀당 비트 수를 나타낸다.
| 비트 깊이 | 대표적인 저장 방식 |
|---|---|
| 1비트 | 색상 테이블 인덱스 |
| 4비트 | 색상 테이블 인덱스 |
| 8비트 | 색상 테이블 인덱스 |
| 16비트 | 직접 색상 또는 비트 마스크 |
| 24비트 | 일반적인 BGR 색상 |
| 32비트 | BGRA 또는 마스크 기반 색상 |
24비트 BMP는 일반적으로 한 픽셀을 3바이트로 저장한다.
Blue | Green | Red
하지만 비트 깊이만으로 실제 채널 해석을 완전히 결정할 수는 없다.
압축 방식과 비트 마스크 정보를 함께 확인해야 한다.
11. BMP 압축 방식
BMP의 biCompression 필드는 이미지 데이터의 저장 방식을 나타낸다.
| 값 | 이름 | 의미 |
|---|---|---|
| 0 | BI_RGB | 일반적인 비압축 저장 |
| 1 | BI_RLE8 | 8비트 RLE |
| 2 | BI_RLE4 | 4비트 RLE |
| 3 | BI_BITFIELDS | 비트 마스크 기반 저장 |
| 4 | BI_JPEG | JPEG 기반 데이터 |
| 5 | BI_PNG | PNG 기반 데이터 |
| 6 | BI_ALPHABITFIELDS | 알파 비트 마스크 확장 |
이 값들은 BMP의 모든 버전에서 동일하게 지원되는 것은 아니다.
특히 압축된 BMP에서는 비압축 이미지에 적용하는 행 크기 계산을 그대로 사용할 수 없다.
따라서 먼저 biCompression을 확인하고 데이터 해석 방법을 선택해야 한다.
12. BMP 픽셀 배열의 구조
BMP의 픽셀 배열은 일반적으로 bfOffBits가 가리키는 위치에서 시작한다.
예를 들어 다음과 같은 정보가 있다고 가정하자.
bfOffBits = 54
biWidth = 3
biHeight = 2
biBitCount = 24
24비트 BMP에서 한 픽셀은 일반적으로 3바이트다.
따라서 한 행의 실제 픽셀 데이터 크기는 다음과 같다.
3 pixels × 3 bytes = 9 bytes
하지만 BMP의 일반적인 비압축 행 데이터는 4바이트 경계에 맞춰 정렬된다.
이 때문에 패딩이 추가된다.
13. BMP 행 패딩(Row Padding) 원리
일반적인 비압축 BMP에서는 각 행의 저장 크기를 4바이트 배수로 맞춘다.
행 크기 공식
RowStride =
Floor((BitsPerPixel × Width + 31) / 32) × 4
3픽셀 너비의 24비트 BMP를 예로 들어보자.
Width = 3
BitsPerPixel = 24
Pixel Bits = 3 × 24 = 72 bits
RowStride = Floor((72 + 31) / 32) × 4
= 3 × 4
= 12 bytes
실제 픽셀 데이터는 9바이트이지만 행 전체 저장 크기는 12바이트다.
따라서 패딩은 다음과 같다.
Padding = 12 - 9 = 3 bytes
픽셀 행 구조
Row 1:
[BGR][BGR][BGR][PAD PAD PAD]
Row 2:
[BGR][BGR][BGR][PAD PAD PAD]
패딩을 무시하면 다음 행의 시작 위치를 잘못 계산할 수 있다.
14. 색상 테이블(Color Table)
1·4·8비트 BMP에서는 일반적으로 색상 테이블을 사용한다.
픽셀 데이터에는 실제 색상값 대신 색상 테이블의 인덱스가 저장된다.
예를 들어 8비트 BMP에서는 하나의 픽셀이 색상 테이블의 항목 번호를 나타낼 수 있다.
대표적인 색상 테이블 크기
| 비트 깊이 | 기본 최대 색상 수 |
|---|---|
| 1비트 | 2 |
| 4비트 | 16 |
| 8비트 | 256 |
실제 색상 테이블 항목 수는 biClrUsed 등의 필드에 따라 달라질 수 있다.
Windows BITMAPINFOHEADER 계열의 일반적인 색상 테이블 항목은 4바이트 RGBQUAD 구조를 사용한다.
Blue
Green
Red
Reserved
반면 OS/2 CORE 계열은 색상 테이블 항목 구조가 다를 수 있다.
15. 비트 마스크와 16·32비트 BMP
16비트와 32비트 BMP에서는 비트 마스크를 이용해 색상 채널을 구분할 수 있다.
예를 들어 16비트 RGB565 형식은 다음과 같이 표현된다.
RRRRR GGGGGG BBBBB
- 빨간색: 5비트
- 초록색: 6비트
- 파란색: 5비트
이러한 형식에서는 마스크 정보를 정확히 읽어야 픽셀 값을 올바르게 해석할 수 있다.
특히 BI_BITFIELDS 형식에서는 빨강·초록·파랑 마스크가 헤더 뒤에 별도로 저장되거나 확장 DIB 헤더 안에 포함될 수 있다.
이번 실습 코드는 픽셀 채널을 디코딩하지 않는다.
16. BMP 파일 크기와 픽셀 데이터 경계
BMP 헤더에는 전체 파일 크기와 픽셀 배열 시작 위치가 기록된다.
또한 DIB 헤더에는 이미지 크기와 비트 깊이 등이 기록된다.
일반적인 비압축 BMP에서는 이 값들을 이용해 예상 픽셀 배열 크기를 계산할 수 있다.
예시
Width = 3
Height = 2
BitCount = 24
RowStride = 12
PixelBytes = 12 × 2 = 24
PixelOffset = 54
픽셀 배열이 차지하는 예상 범위는 다음과 같다.
Start = 54
End = 54 + 24 = 78
여기서 End는 마지막 픽셀 바이트 다음 위치다.
파일 길이가 70바이트라면 필요한 픽셀 데이터가 부족할 수 있다.
반면 파일 길이가 78바이트 이상이라고 해서 픽셀 값이나 이미지 내용이 모두 정상이라는 뜻은 아니다.
17. PowerShell 5.1로 BMP 헤더 분석하기
이번 실습에서는 BMP 파일의 기본 헤더를 읽어 시그니처, 기록된 파일 크기, 픽셀 배열 오프셋을 확인한다.
① 실습 파일
C:\FileTest\sample.bmp
실행 시에는 실제 파일 경로로 변경한다.
② PowerShell 코드
$path = "C:\FileTest\sample.bmp"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 14) {
throw "BMP file header is incomplete."
}
$header = $reader.ReadBytes(14)
$signature = [System.Text.Encoding]::ASCII.GetString(
$header, 0, 2
)
if ($signature -cne "BM") {
throw "Not a BM-type BMP file."
}
$fileSize = [System.BitConverter]::ToUInt32($header, 2)
$reserved1 = [System.BitConverter]::ToUInt16($header, 6)
$reserved2 = [System.BitConverter]::ToUInt16($header, 8)
$pixelOffset = [System.BitConverter]::ToUInt32($header, 10)
[PSCustomObject]@{
Signature = $signature
HeaderFileSize = $fileSize
ActualFileSize = $stream.Length
Reserved1 = $reserved1
Reserved2 = $reserved2
PixelDataOffset = $pixelOffset
PixelOffsetWithinFile = (
[uint64]$pixelOffset -le [uint64]$stream.Length
)
FileSizeMatches = (
[uint64]$fileSize -eq [uint64]$stream.Length
)
}
}
finally {
$stream.Dispose()
}
③ 출력 예시
Signature : BM
HeaderFileSize : 78
ActualFileSize : 78
Reserved1 : 0
Reserved2 : 0
PixelDataOffset : 54
PixelOffsetWithinFile : True
FileSizeMatches : True
위 출력은 설명을 위한 예시다.
④ 코드 해석
파일 시작의 BM 시그니처를 확인하고, 헤더에 기록된 파일 크기와 실제 파일 크기를 비교한다.
또한 픽셀 데이터 시작 오프셋이 파일 범위 안에 있는지 확인한다.
⑤ 코드의 한계
이 코드는 BITMAPFILEHEADER의 기본 필드만 확인한다.
DIB 헤더와 픽셀 데이터의 정상 여부를 판정하지 않으며, 일반적인 리틀엔디언 Windows 환경을 전제로 한다.
18. PowerShell 5.1로 DIB 헤더 분석하기
이번 실습에서는 40바이트 이상인 Windows 계열 DIB 헤더의 공통 필드를 읽는다.
① PowerShell 코드
$path = "C:\FileTest\sample.bmp"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 54) {
throw "File too short for a 40-byte DIB header."
}
$stream.Position = 0
$signature = [System.Text.Encoding]::ASCII.GetString(
$reader.ReadBytes(2)
)
if ($signature -cne "BM") {
throw "Invalid BMP signature."
}
$stream.Position = 14
$dibSize = $reader.ReadUInt32()
if ($dibSize -lt 40) {
throw "Unsupported DIB header size."
}
if (([uint64]14 + [uint64]$dibSize) -gt
[uint64]$stream.Length) {
throw "DIB header exceeds file length."
}
$width = $reader.ReadInt32()
$height = $reader.ReadInt32()
$planes = $reader.ReadUInt16()
$bitCount = $reader.ReadUInt16()
$compression = $reader.ReadUInt32()
$imageSize = $reader.ReadUInt32()
$xPelsPerMeter = $reader.ReadInt32()
$yPelsPerMeter = $reader.ReadInt32()
$colorsUsed = $reader.ReadUInt32()
$colorsImportant = $reader.ReadUInt32()
[PSCustomObject]@{
DIBHeaderSize = $dibSize
Width = $width
Height = $height
Orientation = $(if ($height -lt 0) {
"Top-down"
} else {
"Bottom-up"
})
Planes = $planes
BitCount = $bitCount
Compression = $compression
ImageSizeField = $imageSize
XPelsPerMeter = $xPelsPerMeter
YPelsPerMeter = $yPelsPerMeter
ColorsUsed = $colorsUsed
ColorsImportant = $colorsImportant
}
}
finally {
$stream.Dispose()
}
② 출력 예시
DIBHeaderSize : 40
Width : 3
Height : 2
Orientation : Bottom-up
Planes : 1
BitCount : 24
Compression : 0
ImageSizeField : 24
XPelsPerMeter : 0
YPelsPerMeter : 0
ColorsUsed : 0
ColorsImportant : 0
위 출력은 설명을 위한 예시다.
③ 코드의 한계
이 코드는 DIB 헤더의 공통 필드만 읽는다.
DIB 헤더 크기가 40바이트보다 큰 경우에도 추가 색상 공간 정보나 비트 마스크를 해석하지 않는다.
또한 12바이트 CORE 헤더는 지원하지 않는다.
19. PowerShell 5.1로 비압축 BMP 픽셀 범위 검증하기
이번 실습에서는 24비트 비압축 BMP의 행 크기와 예상 픽셀 배열 크기를 계산한다.
범위를 명확히 하기 위해 다음 조건만 지원한다.
- BM 시그니처
- DIB 헤더 40바이트 이상
- biPlanes = 1
- biBitCount = 24
- biCompression = 0
- 양수 너비
- 0이 아닌 높이
① PowerShell 코드
$path = "C:\FileTest\sample.bmp"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 54) {
throw "File too short."
}
$signature = [System.Text.Encoding]::ASCII.GetString(
$reader.ReadBytes(2)
)
if ($signature -cne "BM") {
throw "Invalid BMP signature."
}
$stream.Position = 10
$pixelOffset = $reader.ReadUInt32()
$stream.Position = 14
$dibSize = $reader.ReadUInt32()
if ($dibSize -lt 40 -or
([uint64]14 + [uint64]$dibSize) -gt
[uint64]$stream.Length) {
throw "Unsupported or incomplete DIB header."
}
$width = $reader.ReadInt32()
$height = $reader.ReadInt32()
$planes = $reader.ReadUInt16()
$bitCount = $reader.ReadUInt16()
$compression = $reader.ReadUInt32()
if ($width -le 0 -or $height -eq 0 -or
$planes -ne 1 -or $bitCount -ne 24 -or
$compression -ne 0) {
throw "Only 24-bit uncompressed BMP is supported."
}
$absHeight = [Math]::Abs([long]$height)
$rowStride = [uint64](
[Math]::Floor(
(([double]$width * 24 + 31) / 32)
) * 4
)
$pixelBytes = $rowStride * [uint64]$absHeight
$pixelEnd = [uint64]$pixelOffset + $pixelBytes
[PSCustomObject]@{
Width = $width
Height = $height
RowStride = $rowStride
ExpectedPixelBytes = $pixelBytes
PixelDataOffset = $pixelOffset
ExpectedPixelEnd = $pixelEnd
ActualFileSize = $stream.Length
PixelDataWithinFile = (
$pixelEnd -le [uint64]$stream.Length -and
[uint64]$pixelOffset -ge (
[uint64]14 + [uint64]$dibSize
)
)
}
}
finally {
$stream.Dispose()
}
② 출력 예시
Width : 3
Height : 2
RowStride : 12
ExpectedPixelBytes : 24
PixelDataOffset : 54
ExpectedPixelEnd : 78
ActualFileSize : 78
PixelDataWithinFile : True
위 출력은 설명을 위한 예시다.
③ 코드 해석
24비트 비압축 BMP의 행 크기를 4바이트 단위로 정렬하고 전체 픽셀 데이터 크기를 계산한다.
계산된 데이터 범위가 파일 안에 있는지 확인한다.
④ 코드의 한계
이 코드는 24비트 비압축 BMP의 기본적인 데이터 경계만 점검한다.
색상 테이블, 비트 마스크, RLE 압축, JPEG·PNG 포함 BMP 및 실제 픽셀 값의 유효성은 검증하지 않는다.
20. BMP 파일 손상 시 점검할 항목
BMP 파일에 문제가 발생하면 다음 항목을 순서대로 확인할 수 있다.
| 점검 항목 | 확인 목적 |
|---|---|
| BM 시그니처 | 파일 형식 식별 |
| bfSize | 헤더 기록 크기 |
| 실제 파일 크기 | 파일 누락 여부 |
| bfOffBits | 픽셀 배열 시작 위치 |
| biSize | DIB 헤더 버전 |
| biWidth | 이미지 너비 |
| biHeight | 이미지 높이·방향 |
| biPlanes | 색상 평면 수 |
| biBitCount | 비트 깊이 |
| biCompression | 압축 방식 |
| biSizeImage | 이미지 크기 필드 |
| 색상 테이블 | 인덱스 색상 해석 |
| 비트 마스크 | 색상 채널 구성 |
| Row Padding | 행 정렬 |
| Pixel Data Boundary | 데이터 범위 |
| SHA-256 | 원본 동일성 |
대표적인 손상 상황
① BMP 시그니처 오류
파일 시작의 시그니처가 예상과 다르면 형식 식별에 문제가 있을 수 있다.
② 픽셀 오프셋 오류
bfOffBits가 잘못되면 이미지 데이터가 아닌 다른 영역을 픽셀로 읽을 수 있다.
③ DIB 헤더 오류
이미지 크기나 비트 깊이 필드가 잘못되면 정상적인 픽셀 해석이 어려울 수 있다.
④ 행 패딩 계산 오류
패딩을 고려하지 않으면 이미지가 기울어지거나 색상 배열이 어긋날 수 있다.
⑤ 이미지 데이터 누락
예상 픽셀 데이터 범위가 실제 파일 길이를 초과하면 파일 손상 가능성이 있다.
21. BMP 구조 검증과 SHA-256 무결성 검증
BMP의 구조를 분석하는 작업과 파일의 동일성을 확인하는 작업은 서로 다르다.
구조 분석
파일 헤더, DIB 헤더, 픽셀 배열 오프셋과 행 패딩 등을 확인한다.
이미지 디코딩
비트 깊이와 압축 방식에 따라 실제 픽셀 값을 해석한다.
SHA-256 무결성 검증
신뢰할 수 있는 원본 해시값과 현재 파일의 해시값을 비교한다.
PowerShell 5.1 코드
$path = "C:\FileTest\sample.bmp"
Get-FileHash -LiteralPath $path -Algorithm SHA256 |
Format-List Algorithm, Hash, Path
검증 방식 비교
| 구분 | 구조 분석 | 이미지 디코딩 | SHA-256 |
|---|---|---|---|
| 확인 대상 | 헤더·픽셀 범위 | 픽셀 데이터 | 파일 전체 |
| 구조 오류 탐지 | 일부 가능 | 일부 가능 | 직접 판별 불가 |
| 원본 동일성 | 확인 불가 | 확인 불가 | 기준값과 비교 가능 |
| 색상 정확성 | 확인 불가 | 해석 후 별도 평가 | 확인 불가 |
| 파일 안전성 | 보장 불가 | 보장 불가 | 보장 불가 |
SHA-256 해시값이 신뢰할 수 있는 기준값과 일치한다면 파일의 바이트 내용이 동일하다고 매우 높은 신뢰도로 판단할 수 있다.
하지만 해시값 일치만으로 파일이 안전하거나 BMP 이미지가 올바르게 표시된다는 사실을 보장하지는 않는다.
22. 자주 묻는 질문
Q1. BMP 파일의 대표적인 시그니처는 무엇인가요?
일반적인 Windows BMP 파일은 ASCII BM, HEX 42 4D로 시작한다.
Q2. BMP 파일 헤더는 몇 바이트인가요?
일반적인 BITMAPFILEHEADER는 14바이트다. 그 뒤에 DIB 헤더와 선택적 데이터가 이어진다.
Q3. DIB 헤더는 무엇인가요?
이미지 너비와 높이, 비트 깊이, 압축 방식 등을 정의하는 헤더다.
Q4. BMP 파일은 항상 비압축인가요?
아니다. RLE, 비트 마스크 및 일부 다른 압축 저장 방식도 지원할 수 있다.
Q5. BMP 파일 크기가 큰 이유는 무엇인가요?
비압축 픽셀 데이터가 그대로 저장되는 경우가 많고, 행 패딩과 색상 테이블 등도 파일 크기에 영향을 줄 수 있기 때문이다.
Q6. BMP 이미지가 거꾸로 표시되는 이유는 무엇인가요?
픽셀 행의 상향식·하향식 저장 방향을 잘못 해석했을 가능성이 있다.
Q7. Row Padding은 무엇인가요?
일반적인 비압축 BMP에서 각 픽셀 행의 저장 크기를 4바이트 배수로 맞추기 위해 추가하는 바이트다.
Q8. BMP의 색상 테이블은 언제 사용하나요?
주로 1·4·8비트처럼 색상 인덱스를 사용하는 이미지에서 활용한다.
Q9. PowerShell로 BMP 파일 손상을 완전히 검증할 수 있나요?
헤더와 픽셀 데이터 경계의 일부 오류는 확인할 수 있지만, 모든 BMP 변형의 정상 여부를 판정하려면 해당 형식을 지원하는 이미지 디코더가 필요하다.
마무리
BMP는 BM 시그니처, BITMAPFILEHEADER, DIB 헤더, 선택적 색상 테이블 및 픽셀 배열을 기반으로 이미지를 저장하는 형식이다.
BMP 파일 구조 분석에서는 시그니처, 픽셀 데이터 오프셋, DIB 헤더 크기, 이미지 너비·높이, 비트 깊이, 압축 방식과 행 패딩을 순서대로 확인하는 것이 중요하다.
특히 24비트 비압축 BMP에서는 행 패딩을 포함한 픽셀 데이터 범위를 계산하면 파일의 일부 구조 이상을 탐지할 수 있다.
그러나 헤더와 데이터 범위가 정상이라고 해서 이미지 내용, 압축 데이터 또는 파일의 안전성이 완전히 검증되는 것은 아니다.
따라서 구조 분석과 실제 이미지 디코딩, SHA-256 기반 무결성 검증을 목적에 맞게 구분해서 사용해야 한다.
관련 글 함께 읽기
BMP와 다른 이미지 파일 형식의 구조를 비교하고 싶다면 PNG 파일 구조 분석과 TIFF 파일 구조 분석 글도 함께 참고할 수 있다.
※ 위 문장에서 PNG 파일 구조 분석과 TIFF 파일 구조 분석에 각각 기존 글의 내부 링크를 연결한다. TIFF 글은 예약 공개 이후 연결할 수 있다.
핵심 내용 3줄 요약
- BMP는 BM 시그니처, 파일 헤더와 DIB 헤더를 이용해 이미지 속성과 픽셀 데이터 위치를 정의한다.
- 비압축 BMP는 비트 깊이와 행 패딩을 고려해 실제 픽셀 데이터 범위를 계산해야 한다.
- 헤더와 데이터 경계가 정상이어도 이미지 내용 및 원본 동일성은 별도로 검증해야 한다.
공식 및 기술 참고자료
- Microsoft Learn — BITMAPFILEHEADER Structure
https://learn.microsoft.com/windows/win32/api/wingdi/ns-wingdi-bitmapfileheader - Microsoft Learn — BITMAPINFOHEADER Structure
https://learn.microsoft.com/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - Microsoft Learn — Bitmap Storage
https://learn.microsoft.com/windows/win32/gdi/bitmap-storage - Microsoft Learn — RGBQUAD Structure
https://learn.microsoft.com/windows/win32/api/wingdi/ns-wingdi-rgbquad - Microsoft Learn — BinaryReader Class
https://learn.microsoft.com/dotnet/api/system.io.binaryreader - Microsoft Learn — File.OpenRead Method
https://learn.microsoft.com/dotnet/api/system.io.file.openread - Microsoft Learn — Get-FileHash (PowerShell 5.1)
https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/get-filehash?view=powershell-5.1
※ 본문의 PowerShell 코드는 BMP 파일의 기본 헤더와 24비트 비압축 픽셀 데이터 범위를 읽기 전용으로 분석하는 학습용 예시다. 모든 BMP 변형을 지원하는 완전한 이미지 디코더가 아니며, 실제 Windows PowerShell 5.1 환경에서의 실행 검증은 별도로 필요하다.
디지털 파일 검증 연구소
댓글 0
첫 댓글을 남겨보세요.