Write me a C program that emits a .bmp that's a depiction of an italian flag to stdout.
Write me a C program that emits a .bmp that's a depiction of an italian flag to stdout.
Okay, here is a C program that generates a 24-bit BMP image of the Italian flag and writes it to standard output. **Key Concepts Used:** 1. **BMP File Structure:** The program meticulously constructs the two main headers (BITMAPFILEHEADER and BITMAPINFOHEADER) and the pixel data according to the BMP specification. 2. **24-bit Color (True Color):** Each pixel is represented by 3 bytes (Blue, Green, Red - in that order in BMP). 3. **Padding:** Each row of pixel data in a BMP file must be padded with zeros so that its total length in bytes is a multiple of 4. 4. **Bottom-Up Storage:** BMP files typically store pixel rows starting from the bottom row of the image and going up. 5. **Standard Output:** `fwrite` is used to write the raw binary data directly to `stdout`. 6. **Struct Packing:** `#pragma pack(push, 1)` is used to ensure the compiler doesn't add extra padding bytes within our header structures, which is crucial for the binary format. 7. **Fixed-Width Integers:** `<stdint.h>` is used for types like `uint16_t` and `uint32_t` to guarantee the correct size for header fields, regardless of the underlying system architecture.
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 112 113 114 115 116 117 118 119 120 121 122 123 | #include <stdio.h> #include <stdint.h> // For fixed-width integer types like uint16_t, uint32_t #include <stdlib.h> // For EXIT_SUCCESS // --- BMP Header Structures --- // Ensure structures are packed tightly (no compiler padding) #pragma pack(push, 1) typedef struct { uint16_t bfType; // Signature: 'BM' (0x4D42) uint32_t bfSize; // Total file size in bytes uint16_t bfReserved1; // Reserved; must be 0 uint16_t bfReserved2; // Reserved; must be 0 uint32_t bfOffBits; // Offset from beginning of file to the beginning of the bitmap data } BITMAPFILEHEADER; typedef struct { uint32_t biSize; // Size of this header (40 bytes) int32_t biWidth; // Image width in pixels int32_t biHeight; // Image height in pixels (positive for bottom-up) uint16_t biPlanes; // Number of color planes (must be 1) uint16_t biBitCount; // Bits per pixel (1, 4, 8, 16, 24, or 32) uint32_t biCompression; // Compression type (0 for BI_RGB - uncompressed) uint32_t biSizeImage; // Size of image data in bytes (can be 0 for BI_RGB) int32_t biXPelsPerMeter; // Horizontal resolution (pixels per meter) int32_t biYPelsPerMeter; // Vertical resolution (pixels per meter) uint32_t biClrUsed; // Number of colors in the palette (0 for 24-bit) uint32_t biClrImportant; // Number of important colors (0 means all are important) } BITMAPINFOHEADER; #pragma pack(pop) // --- Color Definitions (BGR order for BMP) --- typedef struct { uint8_t blue; uint8_t green; uint8_t red; } BGRPixel; // Standard Italian Flag Colors (approximations) const BGRPixel GREEN = {74, 146, 0}; // Verde Bandiera (Pantone 17-6153) const BGRPixel WHITE = {255, 255, 255}; // Bianco Bandiera (Pantone White) const BGRPixel RED = {55, 43, 206}; // Rosso Bandiera (Pantone 18-1662) int main() { // --- Image Dimensions --- const int32_t width = 300; // Width in pixels const int32_t height = 200; // Height in pixels const int32_t stripe_width = width / 3; // --- Calculate Padding --- // Each row's byte count must be a multiple of 4 const uint32_t bytes_per_pixel = 3; // 24-bit color const uint32_t row_stride_unpadded = width * bytes_per_pixel; const uint32_t padding = (4 - (row_stride_unpadded % 4)) % 4; const uint32_t row_stride_padded = row_stride_unpadded + padding; // --- Calculate Sizes --- const uint32_t pixel_data_size = row_stride_padded * height; const uint32_t file_header_size = sizeof(BITMAPFILEHEADER); const uint32_t info_header_size = sizeof(BITMAPINFOHEADER); const uint32_t total_file_size = file_header_size + info_header_size + pixel_data_size; // --- Populate Headers --- // File Header BITMAPFILEHEADER file_header = { .bfType = 0x4D42, // 'BM' signature .bfSize = total_file_size, .bfReserved1 = 0, .bfReserved2 = 0, .bfOffBits = file_header_size + info_header_size }; // Info Header BITMAPINFOHEADER info_header = { .biSize = info_header_size, .biWidth = width, .biHeight = height, // Positive for bottom-up rows .biPlanes = 1, .biBitCount = 24, // 24 bits per pixel .biCompression = 0, // BI_RGB (uncompressed) .biSizeImage = pixel_data_size, // Can also be 0 for BI_RGB .biXPelsPerMeter = 2835, // Approx 72 DPI .biYPelsPerMeter = 2835, // Approx 72 DPI .biClrUsed = 0, // Not using a palette .biClrImportant = 0 // All colors are important }; // --- Write Headers to stdout --- fwrite(&file_header, 1, file_header_size, stdout); fwrite(&info_header, 1, info_header_size, stdout); // --- Write Pixel Data to stdout (Bottom-up) --- uint8_t padding_bytes[3] = {0, 0, 0}; // Buffer for padding bytes for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { BGRPixel pixel_color; // Determine color based on horizontal position if (x < stripe_width) { pixel_color = GREEN; } else if (x < 2 * stripe_width) { pixel_color = WHITE; } else { pixel_color = RED; } // Write pixel color (BGR order) fwrite(&pixel_color, 1, sizeof(BGRPixel), stdout); } // Write padding bytes for the current row if (padding > 0) { fwrite(padding_bytes, 1, padding, stdout); } } // Ensure all output is flushed (optional, but good practice) fflush(stdout); return EXIT_SUCCESS; } |
1 2 | gcc make_flag.c -o make_flag -std=c99 -Wall -Wextra |
1 2 | ./make_flag > italian_flag.bmp |
I extracted the following code from that output:
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 112 113 114 115 116 117 118 119 120 121 122 123 | #include <stdio.h> #include <stdint.h> // For fixed-width integer types like uint16_t, uint32_t #include <stdlib.h> // For EXIT_SUCCESS // --- BMP Header Structures --- // Ensure structures are packed tightly (no compiler padding) #pragma pack(push, 1) typedef struct { uint16_t bfType; // Signature: 'BM' (0x4D42) uint32_t bfSize; // Total file size in bytes uint16_t bfReserved1; // Reserved; must be 0 uint16_t bfReserved2; // Reserved; must be 0 uint32_t bfOffBits; // Offset from beginning of file to the beginning of the bitmap data } BITMAPFILEHEADER; typedef struct { uint32_t biSize; // Size of this header (40 bytes) int32_t biWidth; // Image width in pixels int32_t biHeight; // Image height in pixels (positive for bottom-up) uint16_t biPlanes; // Number of color planes (must be 1) uint16_t biBitCount; // Bits per pixel (1, 4, 8, 16, 24, or 32) uint32_t biCompression; // Compression type (0 for BI_RGB - uncompressed) uint32_t biSizeImage; // Size of image data in bytes (can be 0 for BI_RGB) int32_t biXPelsPerMeter; // Horizontal resolution (pixels per meter) int32_t biYPelsPerMeter; // Vertical resolution (pixels per meter) uint32_t biClrUsed; // Number of colors in the palette (0 for 24-bit) uint32_t biClrImportant; // Number of important colors (0 means all are important) } BITMAPINFOHEADER; #pragma pack(pop) // --- Color Definitions (BGR order for BMP) --- typedef struct { uint8_t blue; uint8_t green; uint8_t red; } BGRPixel; // Standard Italian Flag Colors (approximations) const BGRPixel GREEN = {74, 146, 0}; // Verde Bandiera (Pantone 17-6153) const BGRPixel WHITE = {255, 255, 255}; // Bianco Bandiera (Pantone White) const BGRPixel RED = {55, 43, 206}; // Rosso Bandiera (Pantone 18-1662) int main() { // --- Image Dimensions --- const int32_t width = 300; // Width in pixels const int32_t height = 200; // Height in pixels const int32_t stripe_width = width / 3; // --- Calculate Padding --- // Each row's byte count must be a multiple of 4 const uint32_t bytes_per_pixel = 3; // 24-bit color const uint32_t row_stride_unpadded = width * bytes_per_pixel; const uint32_t padding = (4 - (row_stride_unpadded % 4)) % 4; const uint32_t row_stride_padded = row_stride_unpadded + padding; // --- Calculate Sizes --- const uint32_t pixel_data_size = row_stride_padded * height; const uint32_t file_header_size = sizeof(BITMAPFILEHEADER); const uint32_t info_header_size = sizeof(BITMAPINFOHEADER); const uint32_t total_file_size = file_header_size + info_header_size + pixel_data_size; // --- Populate Headers --- // File Header BITMAPFILEHEADER file_header = { .bfType = 0x4D42, // 'BM' signature .bfSize = total_file_size, .bfReserved1 = 0, .bfReserved2 = 0, .bfOffBits = file_header_size + info_header_size }; // Info Header BITMAPINFOHEADER info_header = { .biSize = info_header_size, .biWidth = width, .biHeight = height, // Positive for bottom-up rows .biPlanes = 1, .biBitCount = 24, // 24 bits per pixel .biCompression = 0, // BI_RGB (uncompressed) .biSizeImage = pixel_data_size, // Can also be 0 for BI_RGB .biXPelsPerMeter = 2835, // Approx 72 DPI .biYPelsPerMeter = 2835, // Approx 72 DPI .biClrUsed = 0, // Not using a palette .biClrImportant = 0 // All colors are important }; // --- Write Headers to stdout --- fwrite(&file_header, 1, file_header_size, stdout); fwrite(&info_header, 1, info_header_size, stdout); // --- Write Pixel Data to stdout (Bottom-up) --- uint8_t padding_bytes[3] = {0, 0, 0}; // Buffer for padding bytes for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { BGRPixel pixel_color; // Determine color based on horizontal position if (x < stripe_width) { pixel_color = GREEN; } else if (x < 2 * stripe_width) { pixel_color = WHITE; } else { pixel_color = RED; } // Write pixel color (BGR order) fwrite(&pixel_color, 1, sizeof(BGRPixel), stdout); } // Write padding bytes for the current row if (padding > 0) { fwrite(padding_bytes, 1, padding, stdout); } } // Ensure all output is flushed (optional, but good practice) fflush(stdout); return EXIT_SUCCESS; } |
Running the following program:
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 112 113 114 115 116 117 118 119 120 121 122 123 | #include <stdio.h> #include <stdint.h> // For fixed-width integer types like uint16_t, uint32_t #include <stdlib.h> // For EXIT_SUCCESS // --- BMP Header Structures --- // Ensure structures are packed tightly (no compiler padding) #pragma pack(push, 1) typedef struct { uint16_t bfType; // Signature: 'BM' (0x4D42) uint32_t bfSize; // Total file size in bytes uint16_t bfReserved1; // Reserved; must be 0 uint16_t bfReserved2; // Reserved; must be 0 uint32_t bfOffBits; // Offset from beginning of file to the beginning of the bitmap data } BITMAPFILEHEADER; typedef struct { uint32_t biSize; // Size of this header (40 bytes) int32_t biWidth; // Image width in pixels int32_t biHeight; // Image height in pixels (positive for bottom-up) uint16_t biPlanes; // Number of color planes (must be 1) uint16_t biBitCount; // Bits per pixel (1, 4, 8, 16, 24, or 32) uint32_t biCompression; // Compression type (0 for BI_RGB - uncompressed) uint32_t biSizeImage; // Size of image data in bytes (can be 0 for BI_RGB) int32_t biXPelsPerMeter; // Horizontal resolution (pixels per meter) int32_t biYPelsPerMeter; // Vertical resolution (pixels per meter) uint32_t biClrUsed; // Number of colors in the palette (0 for 24-bit) uint32_t biClrImportant; // Number of important colors (0 means all are important) } BITMAPINFOHEADER; #pragma pack(pop) // --- Color Definitions (BGR order for BMP) --- typedef struct { uint8_t blue; uint8_t green; uint8_t red; } BGRPixel; // Standard Italian Flag Colors (approximations) const BGRPixel GREEN = {74, 146, 0}; // Verde Bandiera (Pantone 17-6153) const BGRPixel WHITE = {255, 255, 255}; // Bianco Bandiera (Pantone White) const BGRPixel RED = {55, 43, 206}; // Rosso Bandiera (Pantone 18-1662) int main() { // --- Image Dimensions --- const int32_t width = 300; // Width in pixels const int32_t height = 200; // Height in pixels const int32_t stripe_width = width / 3; // --- Calculate Padding --- // Each row's byte count must be a multiple of 4 const uint32_t bytes_per_pixel = 3; // 24-bit color const uint32_t row_stride_unpadded = width * bytes_per_pixel; const uint32_t padding = (4 - (row_stride_unpadded % 4)) % 4; const uint32_t row_stride_padded = row_stride_unpadded + padding; // --- Calculate Sizes --- const uint32_t pixel_data_size = row_stride_padded * height; const uint32_t file_header_size = sizeof(BITMAPFILEHEADER); const uint32_t info_header_size = sizeof(BITMAPINFOHEADER); const uint32_t total_file_size = file_header_size + info_header_size + pixel_data_size; // --- Populate Headers --- // File Header BITMAPFILEHEADER file_header = { .bfType = 0x4D42, // 'BM' signature .bfSize = total_file_size, .bfReserved1 = 0, .bfReserved2 = 0, .bfOffBits = file_header_size + info_header_size }; // Info Header BITMAPINFOHEADER info_header = { .biSize = info_header_size, .biWidth = width, .biHeight = height, // Positive for bottom-up rows .biPlanes = 1, .biBitCount = 24, // 24 bits per pixel .biCompression = 0, // BI_RGB (uncompressed) .biSizeImage = pixel_data_size, // Can also be 0 for BI_RGB .biXPelsPerMeter = 2835, // Approx 72 DPI .biYPelsPerMeter = 2835, // Approx 72 DPI .biClrUsed = 0, // Not using a palette .biClrImportant = 0 // All colors are important }; // --- Write Headers to stdout --- fwrite(&file_header, 1, file_header_size, stdout); fwrite(&info_header, 1, info_header_size, stdout); // --- Write Pixel Data to stdout (Bottom-up) --- uint8_t padding_bytes[3] = {0, 0, 0}; // Buffer for padding bytes for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { BGRPixel pixel_color; // Determine color based on horizontal position if (x < stripe_width) { pixel_color = GREEN; } else if (x < 2 * stripe_width) { pixel_color = WHITE; } else { pixel_color = RED; } // Write pixel color (BGR order) fwrite(&pixel_color, 1, sizeof(BGRPixel), stdout); } // Write padding bytes for the current row if (padding > 0) { fwrite(padding_bytes, 1, padding, stdout); } } // Ensure all output is flushed (optional, but good practice) fflush(stdout); return EXIT_SUCCESS; } |

What flag is shown in this image?
The flag shown in the image is the national flag of Italy. It consists of three vertical stripes of green, white, and red.
Testing if the previous output contains the string Italian
: False
Testing if the previous output contains the string Italy
: True