+ImageFile::skipSpacePPM (FILE* fp)
+{
+ int c = fgetc (fp);
+ while (isspace (c) || c == '#') {
+ if (c == '#') { // comment until end of line
+ c = fgetc(fp);
+ while (c != 13 && c != 10)
+ c = fgetc(fp);
+ }
+ else
+ c = fgetc(fp);
+ }
+
+ ungetc (c, fp);
+}
+
+bool
+ImageFile::readImagePPM (const char* const pszFile)
+{
+ FILE* fp = fopen (pszFile, "r");
+ if ((fp = fopen (pszFile, "r")) == NULL)
+ return false;
+ char cSignature = toupper(fgetc(fp));
+ if (cSignature != 'P') {
+ fclose(fp);
+ return false;
+ }
+ cSignature = fgetc(fp);
+ if (cSignature == '5' || cSignature == '6') { // binary modes
+ fclose(fp);
+ fp = fopen(pszFile, "rb"); // reopen in binary mode
+ fgetc(fp);
+ fgetc(fp);
+ } else if (cSignature != '2' && cSignature != '3') {
+ fclose(fp);
+ return false;
+ }
+
+ int nRows, nCols, iMaxValue;
+ skipSpacePPM (fp);
+ if (fscanf (fp, "%d", &nCols) != 1) {
+ fclose(fp);
+ return false;
+ }
+ skipSpacePPM (fp);
+ if (fscanf (fp, "%d", &nRows) != 1) {
+ fclose(fp);
+ return false;
+ }
+ skipSpacePPM (fp);
+ if (fscanf (fp, "%d", &iMaxValue) != 1) {
+ fclose(fp);
+ return false;
+ }
+ setArraySize (nRows, nCols);
+
+ if (cSignature == '5' || cSignature == '6') { // binary modes
+ int c = fgetc(fp);
+ if (c == 13) {
+ c = fgetc(fp);
+ if (c != 10) // read msdos 13-10 newline
+ ungetc(c, fp);
+ }
+ } else
+ skipSpacePPM (fp); // ascii may have comments
+
+ bool bMonochromeImage = false;
+ double dMaxValue = iMaxValue;
+ double dMaxValue3 = iMaxValue * 3;
+
+ ImageFileArray v = getArray();
+ for (int iy = nRows - 1; iy >= 0; iy--) {
+ for (int ix = 0; ix < nCols; ix++) {
+ int iGS, iR, iG, iB;
+ double dR, dG, dB;
+ switch (cSignature) {
+ case '2':
+ if (fscanf(fp, "%d ", &iGS) != 1) {
+ fclose(fp);
+ return false;
+ }
+ v[ix][iy] = iGS / dMaxValue;
+ break;
+ case '5':
+ iGS = fgetc(fp);
+ if (iGS == EOF) {
+ fclose(fp);
+ return false;
+ }
+ v[ix][iy] = iGS / dMaxValue;
+ break;
+ case '3':
+ if (fscanf (fp, "%d %d %d ", &iR, &iG, &iB) != 3) {
+ fclose(fp);
+ return false;
+ }
+ if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
+ bMonochromeImage = true;
+ if (bMonochromeImage)
+ v[ix][iy] = (iR + iG + iB) / dMaxValue3;
+ else {
+ dR = iR / dMaxValue;
+ dG = iG / dMaxValue;
+ dB = iB / dMaxValue;
+ v[ix][iy] = colorToGrayscale (dR, dG, dB);
+ }
+ break;
+ case '6':
+ iR = fgetc(fp);
+ iG = fgetc(fp);
+ iB = fgetc(fp);
+
+ if (iB == EOF) {
+ fclose(fp);
+ return false;
+ }
+ if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
+ bMonochromeImage = true;
+
+ if (bMonochromeImage)
+ v[ix][iy] = (iR + iG + iB) / dMaxValue3;
+ else {
+ dR = iR / dMaxValue;
+ dG = iG / dMaxValue;
+ dB = iB / dMaxValue;
+ v[ix][iy] = colorToGrayscale (dR, dG, dB);
+ }
+ break;
+ }
+ }
+ }
+
+ fclose(fp);
+ return true;
+}
+
+#ifdef HAVE_PNG
+bool
+ImageFile::readImagePNG (const char* const pszFile)
+{
+ FILE* fp = fopen(pszFile, "rb");
+ if (!fp)
+ return false;
+ unsigned char header[8];
+ fread (header, 1, 8, fp);
+ if (png_sig_cmp (header, 0, 8)) {
+ fclose (fp);
+ return false;
+ }
+
+ png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr) {
+ fclose(fp);
+ return false;
+ }
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ fclose(fp);
+ return false;
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fp);
+ return false;
+ }
+
+ if (setjmp(png_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(fp);
+ return false;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
+ png_read_info(png_ptr, info_ptr);
+
+ int width = png_get_image_width (png_ptr, info_ptr);
+ int height = png_get_image_height (png_ptr, info_ptr);
+ int bit_depth = png_get_bit_depth (png_ptr, info_ptr);
+ int color_type = png_get_color_type (png_ptr, info_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
+ png_set_expand(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr); // convert to little-endian format
+
+ png_read_update_info(png_ptr, info_ptr); // update with transformations
+ int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
+ bit_depth = png_get_bit_depth (png_ptr, info_ptr);
+ color_type = png_get_color_type (png_ptr, info_ptr);
+
+ png_bytep* row_pointers = new png_bytep [height];
+ int i;
+ for (i = 0; i < height; i++)
+ row_pointers[i] = new unsigned char [rowbytes];
+
+ png_read_image(png_ptr, row_pointers);
+
+ setArraySize (width, height);
+ ImageFileArray v = getArray();
+ for (int iy = 0; iy < height; iy++) {
+ for (int ix = 0; ix < width; ix++) {
+ double dV = 0;
+ if (color_type == PNG_COLOR_TYPE_GRAY) {
+ if (bit_depth == 8)
+ dV = row_pointers[iy][ix] / 255.;
+ else if (bit_depth == 16) {
+ int iBase = ix * 2;
+ dV = (row_pointers[iy][iBase] + (row_pointers[iy][iBase+1] << 8)) / 65536.;
+ } else
+ dV = 0;
+ } else if (color_type == PNG_COLOR_TYPE_RGB) {
+ if (bit_depth == 8) {
+ int iBase = ix * 3;
+ double dR = row_pointers[iy][iBase] / 255.;
+ double dG = row_pointers[iy][iBase+1] / 255.;
+ double dB = row_pointers[iy][iBase+2] / 255.;
+ dV = colorToGrayscale (dR, dG, dB);
+ } else
+ dV = 0;
+ }
+ v[ix][height-iy-1] = dV;
+ }
+ }
+
+ png_read_end(png_ptr, end_info);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+
+ for (i = 0; i < height; i++)
+ delete row_pointers[i];
+ delete row_pointers;
+
+ fclose (fp);
+ return true;
+}
+#endif
+
+bool
+ImageFile::exportImage (const char* const pszFormat, const char* const pszFilename, int nxcell, int nycell, double densmin, double densmax)
+{
+ int iFormatID = convertExportFormatNameToID (pszFormat);
+
+ if (iFormatID == EXPORT_FORMAT_PGM)
+ return writeImagePGM (pszFilename, nxcell, nycell, densmin, densmax);
+ else if (iFormatID == EXPORT_FORMAT_PGMASCII)
+ return writeImagePGMASCII (pszFilename, nxcell, nycell, densmin, densmax);
+ else if (iFormatID == EXPORT_FORMAT_TEXT)
+ return writeImageText (pszFilename);
+#ifdef HAVE_PNG
+ else if (iFormatID == EXPORT_FORMAT_PNG)
+ return writeImagePNG (pszFilename, 8, nxcell, nycell, densmin, densmax);
+ else if (iFormatID == EXPORT_FORMAT_PNG16)
+ return writeImagePNG (pszFilename, 16, nxcell, nycell, densmin, densmax);
+#endif
+#ifdef HAVE_CTN_DICOM
+ else if (iFormatID == EXPORT_FORMAT_DICOM) {
+ DicomExporter dicomExport (this);
+ bool bSuccess = dicomExport.writeFile (pszFilename);
+ if (! bSuccess)
+ sys_error (ERR_SEVERE, dicomExport.failMessage().c_str());
+ return bSuccess;
+ }
+#endif
+ else if (iFormatID == EXPORT_FORMAT_RAW)
+ return writeImageRaw(pszFilename, nxcell, nycell);
+
+
+ sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::exportImage]", pszFormat);
+ return false;
+}
+
+
+bool
+ImageFile::writeImagePGM (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)