00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pnmImageHeader.h"
00016 #include "pnmFileTypeRegistry.h"
00017 #include "pnmFileType.h"
00018 #include "pnmReader.h"
00019 #include "pnmWriter.h"
00020 #include "config_pnmimage.h"
00021 #include "virtualFileSystem.h"
00022 #include "zStream.h"
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 bool PNMImageHeader::
00034 read_header(const Filename &filename, PNMFileType *type,
00035 bool report_unknown_type) {
00036 PNMReader *reader = make_reader(filename, type, report_unknown_type);
00037 if (reader != (PNMReader *)NULL) {
00038 (*this) = (*reader);
00039 delete reader;
00040 return true;
00041 }
00042
00043 return false;
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 bool PNMImageHeader::
00062 read_header(istream &data, const string &filename, PNMFileType *type,
00063 bool report_unknown_type) {
00064 PNMReader *reader = PNMImageHeader::make_reader
00065 (&data, false, filename, string(), type, report_unknown_type);
00066 if (reader != (PNMReader *)NULL) {
00067 (*this) = (*reader);
00068 delete reader;
00069 return true;
00070 }
00071
00072 return false;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 PNMReader *PNMImageHeader::
00089 make_reader(const Filename &filename, PNMFileType *type,
00090 bool report_unknown_type) const {
00091 if (pnmimage_cat.is_debug()) {
00092 pnmimage_cat.debug()
00093 << "Reading image from " << filename << "\n";
00094 }
00095 bool owns_file = false;
00096 istream *file = (istream *)NULL;
00097
00098 if (filename == "-") {
00099 owns_file = false;
00100 file = &cin;
00101
00102 if (pnmimage_cat.is_debug()) {
00103 pnmimage_cat.debug()
00104 << "(reading standard input)\n";
00105 }
00106 } else {
00107 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00108 owns_file = true;
00109 file = vfs->open_read_file(filename, true);
00110 }
00111
00112 if (file == (istream *)NULL) {
00113 if (pnmimage_cat.is_debug()) {
00114 pnmimage_cat.debug()
00115 << "Unable to open file.\n";
00116 }
00117 return NULL;
00118 }
00119
00120 return make_reader(file, owns_file, filename, string(), type,
00121 report_unknown_type);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 PNMReader *PNMImageHeader::
00155 make_reader(istream *file, bool owns_file, const Filename &filename,
00156 string magic_number, PNMFileType *type,
00157 bool report_unknown_type) const {
00158 if (type == (PNMFileType *)NULL) {
00159 if (!read_magic_number(file, magic_number, 2)) {
00160
00161 if (pnmimage_cat.is_debug()) {
00162 pnmimage_cat.debug()
00163 << "Image file appears to be empty.\n";
00164 }
00165 if (owns_file) {
00166 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00167
00168
00169
00170
00171
00172
00173 vfs->close_read_file(file);
00174 }
00175 return NULL;
00176 }
00177
00178 type = PNMFileTypeRegistry::get_global_ptr()->
00179 get_type_from_magic_number(magic_number);
00180
00181 if (pnmimage_cat.is_debug()) {
00182 if (type != (PNMFileType *)NULL) {
00183 pnmimage_cat.debug()
00184 << "By magic number, image file appears to be type "
00185 << type->get_name() << ".\n";
00186 } else {
00187 pnmimage_cat.debug()
00188 << "Unable to determine image file type from magic number.\n";
00189 }
00190 }
00191 }
00192
00193 if (type == (PNMFileType *)NULL && !filename.empty()) {
00194
00195
00196 type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension(filename);
00197
00198 if (pnmimage_cat.is_debug()) {
00199 if (type != (PNMFileType *)NULL) {
00200 pnmimage_cat.debug()
00201 << "From its extension, image file is probably type "
00202 << type->get_name() << ".\n";
00203 } else {
00204 pnmimage_cat.debug()
00205 << "Unable to guess image file type from its extension.\n";
00206 }
00207 }
00208 }
00209
00210 if (type == (PNMFileType *)NULL) {
00211
00212 type = _type;
00213
00214 if (pnmimage_cat.is_debug() && type != (PNMFileType *)NULL) {
00215 pnmimage_cat.debug()
00216 << "Assuming image file type is " << type->get_name() << ".\n";
00217 }
00218 }
00219
00220 if (type == (PNMFileType *)NULL) {
00221
00222 if (report_unknown_type && pnmimage_cat.is_error()) {
00223 pnmimage_cat.error()
00224 << "Cannot determine type of image file " << filename << ".\n"
00225 << "Currently supported image types:\n";
00226 PNMFileTypeRegistry::get_global_ptr()->
00227 write(pnmimage_cat.error(false), 2);
00228 }
00229 if (owns_file) {
00230 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00231
00232
00233
00234
00235
00236
00237 vfs->close_read_file(file);
00238 }
00239 return NULL;
00240 }
00241
00242 PNMReader *reader = type->make_reader(file, owns_file, magic_number);
00243 if (reader == NULL && owns_file) {
00244 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00245 vfs->close_read_file(file);
00246 }
00247
00248 if (!reader->is_valid()) {
00249 delete reader;
00250 reader = NULL;
00251 }
00252
00253 return reader;
00254 }
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 PNMWriter *PNMImageHeader::
00270 make_writer(const Filename &filename, PNMFileType *type) const {
00271 if (pnmimage_cat.is_debug()) {
00272 pnmimage_cat.debug()
00273 << "Writing image to " << filename << "\n";
00274 }
00275 bool owns_file = false;
00276 ostream *file = (ostream *)NULL;
00277
00278 if (filename == "-") {
00279 owns_file = false;
00280 file = &cout;
00281
00282 if (pnmimage_cat.is_debug()) {
00283 pnmimage_cat.debug()
00284 << "(writing to standard output)\n";
00285 }
00286
00287 } else {
00288 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00289 Filename actual_name = Filename::binary_filename(filename);
00290 file = vfs->open_write_file(actual_name, true, true);
00291 if (file != NULL) {
00292 owns_file = true;
00293 }
00294 }
00295
00296 if (file == (ostream *)NULL) {
00297 if (pnmimage_cat.is_debug()) {
00298 pnmimage_cat.debug()
00299 << "Unable to write to file.\n";
00300 }
00301 return NULL;
00302 }
00303
00304 return make_writer(file, owns_file, filename, type);
00305 }
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 PNMWriter *PNMImageHeader::
00332 make_writer(ostream *file, bool owns_file, const Filename &filename,
00333 PNMFileType *type) const {
00334 if (type == (PNMFileType *)NULL && !filename.empty()) {
00335
00336
00337 type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension(filename);
00338
00339 if (pnmimage_cat.is_debug()) {
00340 if (type != (PNMFileType *)NULL) {
00341 pnmimage_cat.debug()
00342 << "From its extension, image file is intended to be type "
00343 << type->get_name() << ".\n";
00344 } else {
00345 pnmimage_cat.debug()
00346 << "Unable to guess image file type from its extension.\n";
00347 }
00348 }
00349 }
00350
00351 if (type == (PNMFileType *)NULL) {
00352
00353 type = _type;
00354
00355 if (pnmimage_cat.is_debug() && type != (PNMFileType *)NULL) {
00356 pnmimage_cat.debug()
00357 << "Assuming image file type is " << type->get_name() << ".\n";
00358 }
00359 }
00360
00361 if (type == (PNMFileType *)NULL) {
00362
00363 if (pnmimage_cat.is_debug()) {
00364 pnmimage_cat.debug()
00365 << "Cannot determine type of image file " << filename << ".\n";
00366 }
00367 if (owns_file) {
00368 delete file;
00369 }
00370 return NULL;
00371 }
00372
00373 PNMWriter *writer = type->make_writer(file, owns_file);
00374 if (writer == NULL && owns_file) {
00375 delete file;
00376 }
00377
00378 if (!writer->is_valid()) {
00379 delete writer;
00380 writer = NULL;
00381 }
00382
00383 return writer;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 bool PNMImageHeader::
00397 read_magic_number(istream *file, string &magic_number, int num_bytes) {
00398 while ((int)magic_number.size() < num_bytes) {
00399 int ch = file->get();
00400 if (file->eof() || file->fail()) {
00401 return false;
00402 }
00403 magic_number += (char)ch;
00404 }
00405
00406 return true;
00407 }
00408
00409
00410
00411
00412
00413
00414 void PNMImageHeader::
00415 output(ostream &out) const {
00416 out << "image: " << _x_size << " by " << _y_size << " pixels, "
00417 << _num_channels << " channels, " << _maxval << " maxval.";
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 bool PNMImageHeader::
00439 compute_histogram(PNMImageHeader::HistMap &hist,
00440 xel *array, xelval *alpha, int max_colors) {
00441 int num_pixels = _x_size * _y_size;
00442 int pi;
00443
00444 switch (get_color_type()) {
00445 case CT_invalid:
00446 return false;
00447
00448 case CT_grayscale:
00449 for (pi = 0; pi < num_pixels; pi++) {
00450 record_color(hist, PixelSpec(PPM_GETB(array[pi])));
00451 if (max_colors > 0 && (int)hist.size() > max_colors) {
00452 return false;
00453 }
00454 }
00455 return true;
00456
00457 case CT_two_channel:
00458 for (pi = 0; pi < num_pixels; pi++) {
00459 record_color(hist, PixelSpec(PPM_GETB(array[pi]), alpha[pi]));
00460 if (max_colors > 0 && (int)hist.size() > max_colors) {
00461 return false;
00462 }
00463 }
00464 return true;
00465
00466 case CT_color:
00467 for (pi = 0; pi < num_pixels; pi++) {
00468 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi])));
00469 if (max_colors > 0 && (int)hist.size() > max_colors) {
00470 return false;
00471 }
00472 }
00473 return true;
00474
00475 case CT_four_channel:
00476 for (pi = 0; pi < num_pixels; pi++) {
00477 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha[pi]));
00478 if (max_colors > 0 && (int)hist.size() > max_colors) {
00479 return false;
00480 }
00481 }
00482 return true;
00483 }
00484
00485 return false;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494 bool PNMImageHeader::
00495 compute_palette(PNMImageHeader::Palette &palette,
00496 xel *array, xelval *alpha, int max_colors) {
00497 HistMap hist;
00498
00499 int num_pixels = _x_size * _y_size;
00500
00501
00502 Palette::const_iterator pi;
00503 for (pi = palette.begin(); pi != palette.end(); ++pi) {
00504 hist.insert(HistMap::value_type(*pi, num_pixels + 1));
00505 }
00506
00507 if (!compute_histogram(hist, array, alpha, max_colors)) {
00508 return false;
00509 }
00510
00511
00512
00513 palette.reserve(hist.size());
00514 HistMap::const_iterator hi;
00515 for (hi = hist.begin(); hi != hist.end(); ++hi) {
00516 if ((*hi).second <= num_pixels) {
00517 palette.push_back((*hi).first);
00518 }
00519 }
00520
00521 return true;
00522 }
00523
00524
00525
00526
00527
00528
00529 void PNMImageHeader::PixelSpec::
00530 output(ostream &out) const {
00531 out << "(" << _red << ", " << _green << ", " << _blue << ", " << _alpha << ")";
00532 }
00533
00534
00535
00536
00537
00538
00539 void PNMImageHeader::Histogram::
00540 write(ostream &out) const {
00541 out << "Histogram: {\n";
00542 PixelCount::const_iterator pi;
00543 for (pi = _pixels.begin(); pi != _pixels.end(); ++pi) {
00544 out << " " << (*pi)._pixel << ": " << (*pi)._count << ",\n";
00545 }
00546 out << "}\n";
00547 }
00548