1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
import std.stdio;
import std.file;
import std.format;
import std.string;
import std.range;
import std.algorithm;
import std.array;
import std.math;
// BMP file header (14 bytes).
struct BitmapFileHeader {
char[2] signature; // "BM" signature
uint fileSize; // Size of the file in bytes
ushort reserved1; // Reserved (0)
ushort reserved2; // Reserved (0)
uint dataOffset; // Offset to the start of image data
}
// BMP info header (40 bytes for BITMAPINFOHEADER).
struct BitmapInfoHeader {
uint size; // Size of this header (40 bytes)
int width; // Image width in pixels
int height; // Image height in pixels
ushort planes; // Number of color planes (must be 1)
ushort bitsPerPixel; // Bits per pixel (1, 4, 8, 16, 24, or 32)
uint compression; // Compression method (0 = none, 1 = RLE-8, 2 = RLE-4)
uint imageSize; // Size of the image data in bytes
int xPixelsPerMeter; // Horizontal resolution (pixels per meter)
int yPixelsPerMeter; // Vertical resolution (pixels per meter)
uint colorsUsed; // Number of colors in the palette
uint importantColors; // Number of important colors used (0 = all)
}
// RGB pixel structure.
struct RGB {
ubyte blue;
ubyte green;
ubyte red;
string toString() const {
return format("RGB(%d, %d, %d)", red, green, blue);
}
}
void main(string[] args) {
if (args.length < 2) {
writeln("Usage: main <filename.bmp>");
return;
}
string fileName = args[1];
try {
// Read the file.
auto file = File(fileName, "rb");
// Read the BMP file header.
BitmapFileHeader fileHeader;
file.rawRead((&fileHeader)[0..1]);
// Check if it's a valid BMP file
if (fileHeader.signature != "BM") {
writeln("Error: Not a valid BMP file");
return;
}
// Read the BMP info header.
BitmapInfoHeader infoHeader;
file.rawRead((&infoHeader)[0..1]);
// Display header information.
writeln("BMP File Header Information:");
writefln(" Signature: %s", fileHeader.signature);
writefln(" File Size: %d bytes", fileHeader.fileSize);
writefln(" Data Offset: %d bytes", fileHeader.dataOffset);
writeln("\nBMP Info Header Information:");
writefln(" Header Size: %d bytes", infoHeader.size);
writefln(" Image Width: %d pixels", infoHeader.width);
writefln(" Image Height: %d pixels", infoHeader.height);
writefln(" Color Planes: %d", infoHeader.planes);
writefln(" Bits Per Pixel: %d", infoHeader.bitsPerPixel);
// Display compression method.
string compressionMethod;
switch (infoHeader.compression) {
case 0: compressionMethod = "None (BI_RGB)"; break;
case 1: compressionMethod = "RLE-8 (BI_RLE8)"; break;
case 2: compressionMethod = "RLE-4 (BI_RLE4)"; break;
case 3: compressionMethod = "Bitfields (BI_BITFIELDS)"; break;
default: compressionMethod = format("Unknown (%d)", infoHeader.compression);
}
writefln(" Compression: %s", compressionMethod);
writefln(" Image Size: %d bytes", infoHeader.imageSize);
writefln(" Horizontal Resolution: %d pixels/meter", infoHeader.xPixelsPerMeter);
writefln(" Vertical Resolution: %d pixels/meter", infoHeader.yPixelsPerMeter);
writefln(" Colors Used: %d", infoHeader.colorsUsed);
writefln(" Important Colors: %d", infoHeader.importantColors);
// Calculate color depth information.
int numColors = (infoHeader.bitsPerPixel <= 8) ? (1 << infoHeader.bitsPerPixel) : 0;
if (numColors > 0) {
writefln(" Color Palette: %d colors", numColors);
} else {
writefln(" Color Palette: None (direct color)");
}
} catch (Exception e) {
writefln("Error reading BMP file: %s", e.msg);
}
}
|