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