-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReadWriteImage.cpp
253 lines (191 loc) · 7.52 KB
/
ReadWriteImage.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
//Include directives
#include "ReadWriteImage.h"
//******************************************************************
//**************** Read ppm files into the code ********************
//*They need to be in 'binary' (P6) with no comments in the header *
//**The first line is the 'P' number - P6 indicates it is a binary,*
//***** then the image dimensions and finally the colour range. ****
//******************************************************************
//This header is then followed by the pixel colour data
//eg: P6
// 3264 2448
// 255
//******************************************************************
//*********Open a .ppm file in notepad++ to see this header*********
//******************************************************************
//Readfunction that will read image in and returns an image object
Image ReadWriteImage::readPPM(const char *filename)
{
//Console output
//std::cout << "Reading image ..." << std::endl;
//Creates an input file stream
std::ifstream inputFileStream;
//Opens the file to read
inputFileStream.open(filename, std::ios::binary);
//Create an image object
Image readImage;
//Try to open the file and read the contents
try
{
//If the input file can't be opened to be read
if (inputFileStream.fail())
throw("Can't open the input file - is it named correctly/is it in the right directory?");
//String to hold the image header text data
std::string header;
//Assign integers to hole the values for the image width, height and colour range
unsigned int width, height, colourRange;
//Get the header of the file
inputFileStream >> header;
//Compare the header string to see if it contains 'P6' i.e binary format
if (strcmp(header.c_str(), "P6") != 0)
throw("Can't read the input file - is it in binary format (Has P6 in the header)?");
//Get the width, height and colour range of the image file
inputFileStream >> width >> height >> colourRange;
//This will throw an exception if bad_alloc
readImage.pixels = new Image::Rgb[width * height];
//Assign the image properties
readImage.setImageProperties(width, height, colourRange, (sizeof(char) * 8) * 3);
//Skip empty lines if necessary until we get to the binary data
inputFileStream.ignore(256, '\n');
//Read each pixel one by one and
unsigned char pixel[3];
//Loop through all the pixels
for (unsigned int i = 0; i < width * height; ++i)
{
//Convert bytes to floats
inputFileStream.read(reinterpret_cast<char*>(pixel), 3);
//Assign the pixels of the image
readImage.pixels[i].setRed(pixel[0] / 255.0f);
readImage.pixels[i].setGreen(pixel[1] / 255.0f);
readImage.pixels[i].setBlue(pixel[2] / 255.0f);
}
//Close the input file
inputFileStream.close();
}
//Catch any errors
catch (const char *err)
{
//Report the error
fprintf(stderr, "%s\n", err);
//Close the input file
inputFileStream.close();
}
//Console output
//std::cout << "Image read" << std::endl;
//Return the image
return readImage;
}
//Overloaded read function that will read image in from a given std::streampos and returns an image object
Image ReadWriteImage::readPPM(const char *filename, unsigned int imgPart, const std::streampos pos)
{
//Console output
//std::cout << "Reading image ..." << std::endl;
//Creates an input file stream
std::fstream inputFileStream;
//Opens the file to read
inputFileStream.open(filename, std::ios::binary | std::ios::in);
//Create an image object
Image readImage;
//Try to open the file and read the contents
try
{
//If the input file can't be opened to be read
if (inputFileStream.fail())
throw("Can't open the input file - is it named correctly/is it in the right directory?");
//String to hold the image header text data
std::string header;
//Assign integers to hole the values for the image width, height and colour range
unsigned int width, height, colourRange;
//Get the header of the file
inputFileStream >> header;
//Compare the header string to see if it contains 'P6' i.e binary format
if (strcmp(header.c_str(), "P6") != 0)
throw("Can't read the input file - is it in binary format (Has P6 in the header)?");
//Get the width, height and colour range of the image file
inputFileStream >> width >> height >> colourRange;
//Allocate a Rgb array (size dependant on imgPart variable passed)
readImage.pixels = new Image::Rgb[width * (height / imgPart)];
//Assign the image properties
readImage.setImageProperties(width, (height / imgPart), colourRange, (sizeof(char) * 8) * 3);
//Skip empty lines if necessary until we get to the binary data
inputFileStream.ignore(256, '\n');
//Read each pixel one by one and
unsigned char pixel[3];
//Seek to the position of the input stream
inputFileStream.seekg(pos, std::ios::beg);
//Loop through all the pixels
for (unsigned int i = 0; i < width * (height / imgPart); ++i)
{
//Convert bytes to floats
inputFileStream.read(reinterpret_cast<char*>(pixel), 3);
//Assign the pixels of the image
readImage.pixels[i].setRed(pixel[0] / 255.0f);
readImage.pixels[i].setGreen(pixel[1] / 255.0f);
readImage.pixels[i].setBlue(pixel[2] / 255.0f);
}
//Close the input file
inputFileStream.close();
}
//Catch any errors
catch (const char *err)
{
//Report the error
fprintf(stderr, "%s\n", err);
//Close the input file
inputFileStream.close();
}
//Console output
//std::cout << "Image read" << std::endl;
//Return the image
return readImage;
}
//******************************************************************
//****************Write data out to a ppm file**********************
//************Constructs the header for the image file**************
//******************************************************************
//Write function which writexs an image object to file
void ReadWriteImage::writePPM(const Image &writeImg, const char *filename)
{
//Console output
//cout << "File name: " << filename << endl;
std::cout << "Writing image ..." << std::endl;
//If the image has no width or height values - cant write the image to file
if (writeImg.getWidth() == 0 || writeImg.getHeight() == 0) { fprintf(stderr, "Can't save an empty image\n"); return; }
//Create a new output file stream
std::ofstream outputFileStream;
//Try to open the file and write the image data to it
try
{
//Open the file stream to write to. Need to spec. binary mode for Windows users
outputFileStream.open(filename, std::ios::binary);
//If the file can't be opened to write to
if (outputFileStream.fail())
throw("Can't open output file");
//Add the header to the image file
outputFileStream << "P6\n" << writeImg.getWidth() << " " << writeImg.getHeight() << "\n255\n";
//Create 'bytes' to hold the red, blue and green values
unsigned char red, green, blue;
//Loop over each pixel in the image
for (unsigned int i = 0; i < writeImg.getWidth() * writeImg.getHeight(); ++i)
{
//Clamp and convert to byte format
red = static_cast<unsigned char>(std::min(1.0f, writeImg.pixels[i].getRed()) * 255);
green = static_cast<unsigned char>(std::min(1.0f, writeImg.pixels[i].getGreen()) * 255);
blue = static_cast<unsigned char>(std::min(1.0f, writeImg.pixels[i].getBlue()) * 255);
//Write the pixel colour values to the file
outputFileStream << red << green << blue;
}
//Close the output file stream
outputFileStream.close();
//Confirm image written to file
std::cout << "Image written" << std::endl;
}
//Catch any errors
catch (const char *err)
{
//Report the error
fprintf(stderr, "%s\n", err);
//Close the output file stream
outputFileStream.close();
}
}