-
Notifications
You must be signed in to change notification settings - Fork 6
/
main.cpp
145 lines (111 loc) · 4.26 KB
/
main.cpp
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
#include <iostream>
#include <string>
#include <cctype>
#include "include/filters.h"
#include "include/helpers.h"
// main file
int main(int argc, char **argv) {
try {
// Ensure proper usage
if (argc != 3) {
throw std::invalid_argument {"Usage: ./filter [infile] [outfile]"};
}
// checks same input output file
if (static_cast<std::string>(argv[1]) == static_cast<std::string>(argv[2])) {
throw std::invalid_argument {static_cast<std::string>(argv[1]) + ": input file can't same as output file"};
}
// checks the input file format
if (!checkFile(argv[1])) {
throw std::invalid_argument {static_cast<std::string>(argv[1]) + ": unsupported File Format!"};
}
// Open input file
FILE *inFile {fopen(argv[1], "r")};
// check readability
if (inFile == nullptr) {
throw std::invalid_argument {"Could not read : " + static_cast<std::string>(argv[1])};
}
// Read inFile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inFile);
// Read inFile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inFile);
// Ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || bi.biBitCount != 24 || bi.biCompression != 0) {
fclose(inFile);
throw std::runtime_error {static_cast<std::string>(argv[1]) + "Unsupported file format."};
}
// checks the output file format
if (!checkFile(argv[2])) {
fclose(inFile);
throw std::invalid_argument {static_cast<std::string>(argv[2]) + ": unsupported File Format!"};
}
// Open output file
FILE *outFile {fopen(argv[2], "w")};
// check writability
if (outFile == nullptr) {
fclose(inFile);
throw std::runtime_error {"Could not create : " + static_cast<std::string>(argv[2])};
}
int height {abs(bi.biHeight)};
int width {abs(bi.biWidth)};
// Allocate memory for image 2D array
RGBTRIPLE **image {new RGBTRIPLE*[height]};
for (int i{0}; i < height; ++i) {
image[i] = new RGBTRIPLE[width];
}
// Checks for successful memory allocation
if (image == nullptr) {
fclose(inFile);
fclose(outFile);
throw std::runtime_error {"Not enough memory to store image."};
}
// Determine padding for scanlines
size_t padding {(4 - (width * sizeof(RGBTRIPLE)) % 4) % 4};
// Iterate over infile's scanlines
for (int i {0}; i < height; i++) {
// Read row into pixel array
fread(*(image + i), sizeof(RGBTRIPLE), width, inFile);
// Skip over padding
fseek(inFile, padding, SEEK_CUR);
}
// Ask user filter choice and store
char filter {showFilterMenu()};
// Apply filter only if the user not opted to quit
if (filter != 'q') {
applyFilter(filter, height, width, image);
} else {
std::cout << "Process terminated..." << std::endl;
fclose(inFile);
fclose(outFile);
return 1;
}
// Write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outFile);
// Write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outFile);
// Write new pixels to outfile
for (int i {0}; i < height; ++i) {
// Write row to outfile
fwrite(*(image + i), sizeof(RGBTRIPLE), width, outFile);
// Write padding at end of row
for (size_t j {0}; j < padding; ++j) {
fputc(0x00, outFile);
}
}
// Free memory for image
for (int i {0}; i < height; ++i) {
delete [] image[i];
}
delete [] image;
// Close inFile
fclose(inFile);
// Close outFile
fclose(outFile);
}
catch (std::exception const &ex) {
std::cerr << ex.what() << std::endl;
return 2;
}
return 0;
}