涉及知识点:文件读写、结构体定义、内存管理、基本图像处理算法、命令行参数
要求:编写一个程序,可以在命令行输入参数,完成指定文件的缩放,并存储到新文件,命令行参数如 (zoom file1.bmp200 file2.bmp)第一个参数为可执行程序名称,第二个参数为原始图像文件名,第三个参数为缩放比例(百分比),第四个参数为新文件名。
思路:
一,写好位图文件头结构体,位图信息头结构体,像素头结构体结构体
二,从文件读取位图图像
三,图像缩放函数
四,将位图图像保存到文件;
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
#pragma pack(push, 1)
// 位图文件头结构体
struct BitmapFileHeader
{
uint16_t bfType; // 文件类型,必须为'BM'(0x4D42)
uint32_t bfSize; // 文件大小
uint16_t bfReserved1; // 保留,必须为0
uint16_t bfReserved2; // 保留,必须为0
uint32_t bfOffBits; // 从文件头到位图数据的偏移量
};
// 位图信息头结构体
struct BitmapInfoHeader
{
uint32_t biSize; // 信息头大小
int32_t biWidth; // 图像宽度
int32_t biHeight; // 图像高度
uint16_t biPlanes; // 颜色平面数,必须为1
uint16_t biBitCount; // 每个像素的位数
uint32_t biCompression; // 压缩类型,我们只支持无压缩的位图
uint32_t biSizeImage; // 图像数据大小,可以为0
int32_t biXPelsPerMeter; // 水平分辨率,像素/米
int32_t biYPelsPerMeter; // 垂直分辨率,像素/米
uint32_t biClrUsed; // 使用的颜色索引数,可以为0
uint32_t biClrImportant; // 重要的颜色索引数,可以为0
};
#pragma pack(pop)
// 像素结构体
struct Pixel
{
uint8_t blue;
uint8_t green;
uint8_t red;
};
// 图像缩放函数
vector<Pixel> ScaleImage(const vector<Pixel> &pixels, int Width, int Height, float newWidth, float newHeight)
{
vector<Pixel> scaledPixels(newWidth * newHeight);
float xRatio = static_cast<float>(Width) / newWidth;
float yRatio = static_cast<float>(Height) / newHeight;
for (int y = 0; y < newHeight; ++y)
{
for (int x = 0; x < newWidth; ++x)
{
int oldX = static_cast<int>(x * xRatio);
int oldY = static_cast<int>(y * yRatio);
scaledPixels[y * newWidth + x] = pixels[oldY * Width + oldX];
}
}
return scaledPixels;
}
// 从文件读取位图图像
vector<Pixel> LoadBitmap(const string &filename, BitmapInfoHeader &bitmapInfoHeader)
{
ifstream file(filename, ios::binary);
BitmapFileHeader fileHeader;
file.read(reinterpret_cast<char *>(&fileHeader), sizeof(fileHeader));
if (fileHeader.bfType != 0x4D42) // 是否为位图文件,(0x4d42)标志该文件是位图文件
{
cerr << "Invalid bitmap file" << endl;
}
file.read(reinterpret_cast<char *>(&bitmapInfoHeader), sizeof(bitmapInfoHeader));
if (bitmapInfoHeader.biBitCount != 24) // 是否是24位
{
cerr << "Unsupported bitmap format" << endl;
}
int dataSize = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * sizeof(Pixel); // 位图数据的字节大小
vector<Pixel> pixels(bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight); // 像素总数
file.read(reinterpret_cast<char *>(pixels.data()), dataSize);
return pixels;
}
// 将位图图像保存到文件
void SaveBitmap(const string &filename, const vector<Pixel> &pixels, const BitmapInfoHeader &bitmapInfoHeader)
{
ofstream file(filename, ios::binary);
BitmapFileHeader fileHeader;
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(fileHeader) + sizeof(bitmapInfoHeader) + pixels.size() * sizeof(Pixel);
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(fileHeader) + sizeof(bitmapInfoHeader);
file.write(reinterpret_cast<const char *>(&fileHeader), sizeof(fileHeader));
file.write(reinterpret_cast<const char *>(&bitmapInfoHeader), sizeof(bitmapInfoHeader));
file.write(reinterpret_cast<const char *>(pixels.data()), pixels.size() * sizeof(Pixel));
}
int main(int argc, char *argv[])
{
if (string(argv[1]) != "zoom")
{
cerr << "Unknown operation" << endl;
return 1;
}
string inputFilename = argv[2];
int scalePercentage = stoi(argv[3]);
string outputFilename = argv[4];
BitmapInfoHeader bitmapInfoHeader;
vector<Pixel> pixels = LoadBitmap(inputFilename, bitmapInfoHeader);
int Width = bitmapInfoHeader.biWidth;
int Height = bitmapInfoHeader.biHeight;
float newWidth = Width * (scalePercentage / 100.0f);
float newHeight = Height * (scalePercentage / 100.0f);
vector<Pixel> scaledPixels = ScaleImage(pixels, Width, Height, newWidth, newHeight);
bitmapInfoHeader.biWidth = newWidth;
bitmapInfoHeader.biHeight = newHeight;
SaveBitmap(outputFilename, scaledPixels, bitmapInfoHeader);
cout << "Image scaled successfully." << endl;
return 0;
}
仅供参考