diff --git a/README.md b/README.md index 01c639e07306ed29bc727aec3b2ef4e0fbffd7d9..e2dfcb98960162fd2312c5470d1c4d46c13d0e16 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ | [zig-struct-bin](./zig-struct-bin) | zig-0.13.0 | Save a struct into binary file and then reading it back. | | [zig-elf](./zig-elf) | zig-0.14.0 | Read execution header of Elf64 format in Zig. | | [c-bluetooth](./c-bluetooth) | clang-17 | Scans for all Bluetooth devices. | | [d-x11](./d-x11) | dmd-2.110 | Uses X11 to create a basic window without any bindings needed. | +| [d-bmp-header](./d-bmp-header) | dmd-2.110 | Reads BMP image header and prints the information out. | ## License diff --git a/d-bmp-header/.gitignore b/d-bmp-header/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..87e54c2147f89ced7b95a4aaad6dcdbc3f5f1f7a --- /dev/null +++ b/d-bmp-header/.gitignore @@ -0,0 +1,2 @@ +main +*.o diff --git a/d-bmp-header/Makefile b/d-bmp-header/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..10a123edd02358c373cc0e862d920280744322c0 --- /dev/null +++ b/d-bmp-header/Makefile @@ -0,0 +1,5 @@ +main: main.d + dmd main.d + +run: + ./main image.bmp diff --git a/d-bmp-header/image.bmp b/d-bmp-header/image.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b061f2d4d9476fd8a33258ff1cf893a4740dcb78 Binary files /dev/null and b/d-bmp-header/image.bmp differ diff --git a/d-bmp-header/main.d b/d-bmp-header/main.d new file mode 100644 index 0000000000000000000000000000000000000000..c8fcaf0b6b9a6a605aa616675e8da685330fd27d --- /dev/null +++ b/d-bmp-header/main.d @@ -0,0 +1,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 "); + 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); + } +}