1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "PgmImage.h"
18 #include <cassert>
19
20 using namespace std;
21
PgmImage(std::string filename)22 PgmImage::PgmImage(std::string filename) :
23 m_w(0),m_h(0),m_colors(255),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
24 {
25 if ( !ReadPGM(filename) )
26 return;
27 }
28
PgmImage(int w,int h,int format)29 PgmImage::PgmImage(int w, int h, int format) :
30 m_colors(255),m_w(w),m_h(h),m_format(format),m_over_allocation(256)
31 {
32 SetFormat(format);
33 }
34
PgmImage(unsigned char * data,int w,int h)35 PgmImage::PgmImage(unsigned char *data, int w, int h) :
36 m_colors(255),m_w(w),m_h(h),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
37 {
38 SetData(data);
39 }
40
PgmImage(std::vector<unsigned char> & data,int w,int h)41 PgmImage::PgmImage(std::vector<unsigned char> &data, int w, int h) :
42 m_colors(255),m_w(w),m_h(h),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
43 {
44 if ( data.size() == w*h )
45 SetData(&data[0]);
46 else
47 //throw (std::exception("Size of data is not w*h."));
48 throw (std::exception());
49 }
50
PgmImage(const PgmImage & im)51 PgmImage::PgmImage(const PgmImage &im) :
52 m_colors(255),m_w(0),m_h(0),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
53 {
54 DeepCopy(im, *this);
55 }
56
operator =(const PgmImage & im)57 PgmImage& PgmImage::operator= (const PgmImage &im)
58 {
59 if (this == &im) return *this;
60 DeepCopy(im, *this);
61 return *this;
62 }
63
DeepCopy(const PgmImage & src,PgmImage & dst)64 void PgmImage::DeepCopy(const PgmImage& src, PgmImage& dst)
65 {
66 dst.m_data = src.m_data;
67
68 // PGM data
69 dst.m_w = src.m_w;
70 dst.m_h = src.m_h;
71 dst.m_format = src.m_format;
72 dst.m_colors = src.m_colors;
73
74 dst.m_comment = src.m_comment;
75 SetupRowPointers();
76 }
77
~PgmImage()78 PgmImage::~PgmImage()
79 {
80
81 }
82
SetFormat(int format)83 void PgmImage::SetFormat(int format)
84 {
85 m_format = format;
86
87 switch (format)
88 {
89 case PGM_BINARY_GRAYMAP:
90 m_data.resize(m_w*m_h+m_over_allocation);
91 break;
92 case PGM_BINARY_PIXMAP:
93 m_data.resize(m_w*m_h*3+m_over_allocation);
94 break;
95 default:
96 return;
97 break;
98 }
99 SetupRowPointers();
100 }
101
SetData(const unsigned char * data)102 void PgmImage::SetData(const unsigned char * data)
103 {
104 m_data.resize(m_w*m_h+m_over_allocation);
105 memcpy(&m_data[0],data,m_w*m_h);
106 SetupRowPointers();
107 }
108
ReadPGM(const std::string filename)109 bool PgmImage::ReadPGM(const std::string filename)
110 {
111 ifstream in(filename.c_str(),std::ios::in | std::ios::binary);
112 if ( !in.is_open() )
113 return false;
114
115 // read the header:
116 string format_header,size_header,colors_header;
117
118 getline(in,format_header);
119 stringstream s;
120 s << format_header;
121
122 s >> format_header >> m_w >> m_h >> m_colors;
123 s.clear();
124
125 if ( m_w == 0 )
126 {
127 while ( in.peek() == '#' )
128 getline(in,m_comment);
129
130 getline(in,size_header);
131
132 while ( in.peek() == '#' )
133 getline(in,m_comment);
134
135 m_colors = 0;
136
137 // parse header
138 s << size_header;
139 s >> m_w >> m_h >> m_colors;
140 s.clear();
141
142 if ( m_colors == 0 )
143 {
144 getline(in,colors_header);
145 s << colors_header;
146 s >> m_colors;
147 }
148 }
149
150 if ( format_header == "P5" )
151 m_format = PGM_BINARY_GRAYMAP;
152 else if (format_header == "P6" )
153 m_format = PGM_BINARY_PIXMAP;
154 else
155 m_format = PGM_FORMAT_INVALID;
156
157 switch(m_format)
158 {
159 case(PGM_BINARY_GRAYMAP):
160 m_data.resize(m_w*m_h+m_over_allocation);
161 in.read((char *)(&m_data[0]),m_data.size());
162 break;
163 case(PGM_BINARY_PIXMAP):
164 m_data.resize(m_w*m_h*3+m_over_allocation);
165 in.read((char *)(&m_data[0]),m_data.size());
166 break;
167 default:
168 return false;
169 break;
170 }
171 in.close();
172
173 SetupRowPointers();
174
175 return true;
176 }
177
WritePGM(const std::string filename,const std::string comment)178 bool PgmImage::WritePGM(const std::string filename, const std::string comment)
179 {
180 string format_header;
181
182 switch(m_format)
183 {
184 case PGM_BINARY_GRAYMAP:
185 format_header = "P5\n";
186 break;
187 case PGM_BINARY_PIXMAP:
188 format_header = "P6\n";
189 break;
190 default:
191 return false;
192 break;
193 }
194
195 ofstream out(filename.c_str(),std::ios::out |ios::binary);
196 out << format_header << "# " << comment << '\n' << m_w << " " << m_h << '\n' << m_colors << '\n';
197
198 out.write((char *)(&m_data[0]), m_data.size());
199
200 out.close();
201
202 return true;
203 }
204
SetupRowPointers()205 void PgmImage::SetupRowPointers()
206 {
207 int i;
208 m_rows.resize(m_h);
209
210 switch (m_format)
211 {
212 case PGM_BINARY_GRAYMAP:
213 for(i=0;i<m_h;i++)
214 {
215 m_rows[i]=&m_data[m_w*i];
216 }
217 break;
218 case PGM_BINARY_PIXMAP:
219 for(i=0;i<m_h;i++)
220 {
221 m_rows[i]=&m_data[(m_w*3)*i];
222 }
223 break;
224 }
225 }
226
ConvertToGray()227 void PgmImage::ConvertToGray()
228 {
229 if ( m_format != PGM_BINARY_PIXMAP ) return;
230
231 // Y = 0.3*R + 0.59*G + 0.11*B;
232 for ( int i = 0; i < m_w*m_h; ++i )
233 m_data[i] = (unsigned char)(0.3*m_data[3*i]+0.59*m_data[3*i+1]+0.11*m_data[3*i+2]);
234
235 m_data.resize(m_w*m_h+m_over_allocation);
236 m_format = PGM_BINARY_GRAYMAP;
237
238 SetupRowPointers();
239 }
240
operator <<(std::ostream & o,const PgmImage & im)241 std::ostream& operator<< (std::ostream& o, const PgmImage& im)
242 {
243 o << "PGM Image Info:\n";
244 o << "Size: " << im.m_w << " x " << im.m_h << "\n";
245 o << "Comment: " << im.m_comment << "\n";
246 switch (im.m_format)
247 {
248 case PgmImage::PGM_BINARY_PIXMAP:
249 o << "Format: RGB binary pixmap";
250 break;
251 case PgmImage::PGM_BINARY_GRAYMAP:
252 o << "Format: PPM binary graymap";
253 break;
254 default:
255 o << "Format: Invalid";
256 break;
257 }
258 o << endl;
259 return o;
260 }
261