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 20using namespace std; 21 22PgmImage::PgmImage(std::string filename) : 23m_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 29PgmImage::PgmImage(int w, int h, int format) : 30m_colors(255),m_w(w),m_h(h),m_format(format),m_over_allocation(256) 31{ 32 SetFormat(format); 33} 34 35PgmImage::PgmImage(unsigned char *data, int w, int h) : 36m_colors(255),m_w(w),m_h(h),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256) 37{ 38 SetData(data); 39} 40 41PgmImage::PgmImage(std::vector<unsigned char> &data, int w, int h) : 42m_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 51PgmImage::PgmImage(const PgmImage &im) : 52m_colors(255),m_w(0),m_h(0),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256) 53{ 54 DeepCopy(im, *this); 55} 56 57PgmImage& PgmImage::operator= (const PgmImage &im) 58{ 59 if (this == &im) return *this; 60 DeepCopy(im, *this); 61 return *this; 62} 63 64void 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 78PgmImage::~PgmImage() 79{ 80 81} 82 83void 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 102void 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 109bool 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 178bool 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 205void 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 227void 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 241std::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