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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
#include <cstdint>
using std::uint32_t, std::uint16_t, std::uint8_t;
struct BitmapFileHeader
{
uint16_t type;
uint32_t size;
uint16_t reserved1, reserved2;
uint32_t offset;
};
struct BitmapInfoHeader
{
uint32_t size, width, height;
uint16_t planes, bitcount;
uint32_t compression, imagesize;
uint32_t xPPM, yPPM;
uint32_t colorUse, important;
};
struct Pixel { uint8_t b, g, r; };
void read(std::istream&) { }
template <typename T, typename ...Types>
void read(std::istream& in, const T& value, const Types&... values)
{
in.read((char*)&value, sizeof value);
read(in, values...);
}
void write(std::ostream&) { }
template <typename T, typename ...Types>
void write(std::ostream& in, const T& value, const Types&... values)
{
in.write((char*)&value, sizeof value);
write(in, values...);
}
std::vector<Pixel>
readBMP(
const std::string& filename,
BitmapFileHeader& bm,
BitmapInfoHeader& info)
{
std::ifstream fin(filename, fin.binary);
if (!fin)
{
std::cerr << "Cannot open input file\n";
std::exit(EXIT_FAILURE);
}
// Read headers
read(fin, bm.type, bm.size, bm.reserved1, bm.reserved2, bm.offset);
read(fin, info.size, info.width, info.height, info.planes,
info.bitcount, info.compression, info.imagesize,
info.xPPM, info.yPPM, info.colorUse, info.important);
if (info.bitcount != 24)
{
std::cerr << "The bitmap must use 24-bit color.\n";
std::exit(EXIT_FAILURE);
}
// Seek to start of pixel data
fin.seekg(bm.offset);
// Read pixel data
std::vector<Pixel> pixels;
pixels.reserve(info.width * info.height);
uint32_t pad = 0, padding = (4 - (info.width * sizeof(Pixel) % 4)) % 4;
for (uint32_t row = 0; row < info.height; ++row)
{
for (uint32_t col = 0; col < info.width; ++col)
fin.read((char*)&pixels[row * info.width + col], sizeof(Pixel));
if (padding) fin.read((char*)&pad, padding);
}
return pixels;
}
void
writeBMP(
const std::string& filename,
BitmapFileHeader bm,
const BitmapInfoHeader& info,
const std::vector<Pixel>& pixels)
{
std::ofstream fout(filename, fout.binary);
if (!fout)
{
std::cerr << "Cannot open output file\n";
std::exit(EXIT_FAILURE);
}
bm.offset = sizeof bm + sizeof info;
// Write headers
write(fout, bm.type, bm.size, bm.reserved1, bm.reserved2, bm.offset);
write(fout, info.size, info.width, info.height, info.planes,
info.bitcount, info.compression, info.imagesize,
info.xPPM, info.yPPM, info.colorUse, info.important);
// Write pixel data
uint32_t pad = 0, padding = (4 - (info.width * sizeof(Pixel) % 4)) % 4;
for (uint32_t row = 0; row < info.height; ++row)
{
for (uint32_t col = 0; col < info.width; ++col)
fout.write((char*)&pixels[row * info.width + col], sizeof(Pixel));
if (padding) fout.write((char*)&pad, padding);
}
}
int main (int argc, char **argv)
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0] << " inputfile outputfile\n";
std::exit(EXIT_FAILURE);
}
BitmapFileHeader bm;
BitmapInfoHeader info;
auto pixels = readBMP(argv[1], bm, info);
// Print header info
std::cout << "Filesize: " << bm.size
<< " Width: " << info.width
<< " Height: " << info.height
<< " Planes: " << info.planes
<< " Bitcount: " << info.bitcount << '\n';
// Modify pixels ("invert" colors)
for (uint32_t row = 0; row < info.height; ++row)
for (uint32_t col = 0; col < info.width; ++col) {
auto p = &pixels[row * info.width + col];
p->r = 255 - p->r;
p->g = 255 - p->g;
p->b = 255 - p->b;
}
writeBMP(argv[2], bm, info, pixels);
}
|