-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathImage.cc
150 lines (126 loc) · 3.97 KB
/
Image.cc
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 <cmath>
#include <fstream>
using std::ofstream;
#include <iostream>
using std::ios;
using std::cerr;
using std::endl;
#include "Image.hh"
Image::Image(unsigned int xres_, unsigned int yres_) :
xres(xres_), yres(yres_)
{
pixels = new Color*[yres];
Color* p = new Color[xres*yres];
for (unsigned int i = 0; i < yres; ++i)
pixels[i] = p + i*xres;
}
Image::~Image()
{
delete [] pixels[0];
delete [] pixels;
}
void Image::WritePPM(const string& fname) const
{
FILE* fp = fopen(fname.c_str(), "wb");
if (!fp) {
cerr << "Failed to open \"" << fname << "\" for writing" << endl;
return;
}
fprintf(fp, "P6 %d %d 255\n", xres, yres);
#ifdef __APPLE__
const float gamma = 1.8f;
#else
// const float gamma = 2.2f;
const float gamma = 1.f;
#endif
for (int y = yres-1; y >= 0; --y) {
for (unsigned int x = 0; x < xres; ++x) {
float value;
unsigned char byte;
// Red channel
value = pixels[y][x][0];
if (value < 0.f) value = 0.f;
value = 255.f*powf(value, gamma);
byte = (unsigned char)(value > 255.f ? 255.f : value);
fputc(byte, fp);
// Green channel
value = pixels[y][x][1];
if (value < 0.f) value = 0.f;
value = 255.f*powf(value, gamma);
byte = (unsigned char)(value > 255.f ? 255.f : value);
fputc(byte, fp);
// Blue channel
value = pixels[y][x][2];
if (value < 0.f) value = 0.f;
value = 255.f*powf(value, gamma);
byte = (unsigned char)(value > 255.f ? 255.f : value);
fputc(byte, fp);
}
}
fclose(fp);
}
void Image::WriteBMP(const string& fname) const
{
ofstream out;
out.open(fname.c_str(), ios::binary);
if (out.fail()){
cerr << "Failed to open \"" << fname << "\"\n";
return;
}
// Write BMP header
char* data = new char[3];
data[0] = 'B';
data[1] = 'M';
out.write(data, 2);
unsigned long int picDataSize = xres*yres*static_cast<unsigned long int>(BMP_BYTES_PER_COLOR);
int widthSpacer = (4 - ((xres * BMP_BYTES_PER_COLOR) % 4)) % 4;
picDataSize += widthSpacer * yres;
unsigned long int fileSize = BMP_HEADER_SIZE + picDataSize;
writeLittleEndian(fileSize, out, 4);
writeLittleEndian(0, out, 4);
writeLittleEndian(BMP_HEADER_SIZE, out, 4);
writeLittleEndian(BMP_PARTIAL_HEADER_SIZE, out, 4);
writeLittleEndian(xres, out, 4);
writeLittleEndian(yres, out, 4);
writeLittleEndian(BMP_NUM_OF_PLANES, out, 2);
writeLittleEndian(BMP_BYTES_PER_COLOR * BITS_PER_BYTE, out, 2);
writeLittleEndian(BMP_COMPRESSION, out, 4);
writeLittleEndian(picDataSize, out, 4);
writeLittleEndian(0, out, 16);
// Write pixel data
float temp;
Color pixel;
for (unsigned int i = 0; i < yres; ++i)
{
for (unsigned int j = 0; j < xres; ++j)
{
pixel = pixels[i][j];
temp = pixel[2] * MAX_BYTE_VALUE;
data[0] = static_cast<char>((temp > 255.0f) ? 255 : ((temp < 0.0f) ? 0 : temp));
temp = pixel[1] * MAX_BYTE_VALUE;
data[1] = static_cast<char>((temp > 255.0f) ? 255 : ((temp < 0.0f) ? 0 : temp));
temp = pixel[0] * MAX_BYTE_VALUE;
data[2] = static_cast<char>((temp > 255.0f) ? 255 : ((temp < 0.0f) ? 0 : temp));
out.write(data, 3);
}
// Pad so that that rows are always in increments of four bytes
for (int i = 0; i < widthSpacer; ++i)
{
data[0] = static_cast<char>(0);
out.write(data, 1);
}
}
delete [] data;
out.close();
}
void Image::writeLittleEndian(unsigned long int num, ostream& out, int numBytes) const
{
char *data = new char[numBytes];
for (int i = 0; i < numBytes; ++i)
{
data[i] = static_cast<char>(num % MAX_BYTE_VALUE);
num /= MAX_BYTE_VALUE;
}
out.write(data, numBytes);
delete [] data;
}