gmetopng.C

Go to the documentation of this file.
00001 /* Gxsm - Gnome X Scanning Microscopy
00002  * universal STM/AFM/SARLS/SPALEED/... controlling and
00003  * data analysis software
00004  * 
00005  * Copyright (C) 1999,2000,2001 Percy Zahl
00006  *
00007  * Authors: Percy Zahl <zahl@users.sf.net>
00008  * WWW Home: http://gxsm.sf.net
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 8 c-style: "K&R" -*- */
00026 
00027 #include <cstdio>
00028 #include <cstdlib>
00029 #include <iostream>
00030 #include <fstream>
00031 #include <cmath>
00032 
00033 #include <glib.h>
00034 #include <png.h>
00035 #include <popt.h>
00036 #include "thumbpal.h"
00037 #include "writepng.h"
00038 
00039 using namespace std;
00040 
00041 // ==============================================================
00042 //
00043 // based on the nctopng code
00044 //
00045 // Read GME-STMAFM image/data generated by STMAFM/G.Meyer program
00046 // and convert them to png image/thumbnail
00047 // - read only required subgrid data (scaled down)
00048 // - use quick, "more intelligent" autoscale
00049 // - use palette
00050 //
00051 // ==============================================================
00052 
00053 #ifndef WORDS_BIGENDIAN
00054 # define WORDS_BIGENDIAN 0
00055 #endif
00056 
00057 typedef enum GME_STATUS { GME_READ_OK, GME_OPEN_FAILED, GME_FILE_NOT_VALID };
00058 
00059 #define THUMB_X 96 // Thumbnail max X size
00060 #define THUMB_Y 91 // Thumbnail max Y size
00061 
00062 class raw_image{
00063 public:
00064         raw_image(){ rgb=NULL; };
00065         virtual ~raw_image(){ 
00066                 if(rgb){
00067                         for (int i=0; i<ny; delete[] rgb[i++]);
00068                         delete[] rgb; 
00069                 }
00070         };
00071 
00072         int width() { return nx; };
00073         int height() { return ny; };
00074         void calc_line_regress(int y, double &slope, double &offset){
00075                 //
00076                 // OutputFeld[i] = InputFeld[i] - (slope * i + offset)
00077                 //
00078                 double sumi, sumy, sumiy, sumyq, sumiq;
00079                 int i, istep;
00080                 int Xmax, Xmin;
00081                 double a, n, imean, ymean;
00082                         
00083                 sumi = sumiq = sumy = sumyq = sumiy = 0.0;
00084                 Xmax = nx-nx/10; // etwas Abstand (10%) vom Rand !
00085                 Xmin = nx/10;
00086                 istep = 1;
00087                 for (i=Xmin; i < Xmax; i+=istep) { /* Rev 2 */
00088                         sumi   += (double)i;
00089                         sumiq  += (double)i*(double)i;
00090                         a =  rowdata[y][i];
00091                         sumy   += a;
00092                         sumyq  += a * a;
00093                         sumiy  += a * (double)i;
00094                 }
00095                 n = (double)((Xmax-Xmin)/istep);
00096                 if ((Xmax-Xmin) % istep != 0) n += 1.0;
00097                 imean = sumi / n;
00098                 ymean = sumy / n;
00099                 slope  = (sumiy- n * imean * ymean ) / (sumiq - n * imean * imean);
00100                 offset = ymean - slope * imean;
00101         };
00102         double soft(int i, int j, double lim=0){
00103 /*
00104                 int a,b,c,d;
00105                 a = max (0, i-1);
00106                 b = min (i+1, nx-1);
00107                 c = max (0, j-1);
00108                 d = min (j+1, ny-1);
00109 */
00110                 return rowdata[j][i];
00111         }
00112         void find_soft_min_max (double &min, double &max){
00113                 min = max = soft(0,0);
00114                 for (int i=0; i<ny; ++i)
00115                         for (int j=0; j<nx; ++j){
00116                                 double v = soft (j,i);
00117                                 if (min > v) min = v;
00118                                 if (max < v) max = v;
00119                         }
00120         };
00121         void quick_rgb(int linreg=TRUE) {
00122                         if (rgb){
00123                                 for (int i=0; i<ny; delete[] rgb[i++]);
00124                                 delete[] rgb;
00125                         }
00126                         rgb = new unsigned char* [ny];
00127                         for (int i=0; i<ny; rgb[i++] = new unsigned char[3*nx]);
00128 
00129                         if (linreg){
00130                                         // Calc and Apply "Quick"
00131                                         for (int i=0; i<ny; ++i){
00132                                                         double a,b;
00133                                                         calc_line_regress (i, a, b);
00134                                                         for (int j=0; j<nx; ++j)
00135                                                                         rowdata[i][j] -= j*a+b;
00136                                         }
00137                         }
00138 
00139                         // Find Scale
00140                         double min, max, range;
00141                         find_soft_min_max (min, max);
00142                         range = max-min;
00143                         for (int i=0; i<ny; ++i)
00144                                 for (int j=0, k=0; j<nx; ++j){
00145                                         int idx = 3*(int)((rowdata[i][j]-min)/range*PALETTE_ENTRIES+0.5);
00146                                         rgb[i][k++] = thumb_palette[idx++];
00147                                         rgb[i][k++] = thumb_palette[idx++];
00148                                         rgb[i][k++] = thumb_palette[idx];
00149                                 }
00150                         
00151         };
00152         unsigned char **row_rgb_pointers() { return rgb; };
00153 
00154 protected:
00155         int nx, ny; // image size
00156         int x0, y0, w0; // offset, data width
00157         int onx, ony; // original data size of NC-file
00158         double **rowdata;
00159         unsigned char **rgb;
00160 };
00161 
00162 void swap_ushort (unsigned short *addr){
00163         unsigned short temp1, temp2;
00164         temp1 = temp2 = *addr;
00165         *addr = ((temp2 & 0xFF) << 8) | ((temp1 >> 8) & 0xFF);
00166 }
00167 
00168 void swap_short (short *addr){
00169         unsigned short temp1, temp2;
00170         temp1 = temp2 = *addr;
00171         *addr = ((temp2 & 0xFF) << 8) | ((temp1 >> 8) & 0xFF);
00172 }
00173 
00174 
00175 class gme_image : public raw_image {
00176 public:
00177         gme_image (const gchar *file_name, int thumb, int new_x, int x_off, int y_off, int width) {
00178                 ifstream f;
00179                 gchar line[0x4000];
00180 
00181                 x0 = x_off; y0 = y_off;
00182 
00183                 // Am I resposible for that file, is it a "Gme-Dat" format ?
00184 
00185                 f.open(file_name, ios::in);
00186                 if (!f.good()){
00187                         state = GME_OPEN_FAILED;
00188                         return;
00189                 }
00190 
00191                 f.getline(line, 0x4000);
00192 
00193                 if (strncmp (line, "[Parameter]", 11) != 0){
00194                         f.close ();
00195                         state = GME_FILE_NOT_VALID;
00196                         return;
00197                 }
00198 
00199                 for (; f.good ();){
00200                         f.getline (line, 0x4000);
00201                         //                  0        1         2         3         4
00202                         //                  1234567890123456789012345678901234567890
00203                         if (strncmp (line, "DATA", 4) == 0) // start of data
00204                                 break;
00205                         if (strncmp (line, "Num.X / Num.X=", 14) == 0)
00206                                 onx = atoi (&line[14]);
00207                         if (strncmp (line, "Num.Y / Num.Y=", 14) == 0)
00208                                 ony = atoi (&line[14]);
00209                 }
00210 
00211                 //
00212                 // compute scale and offsets
00213                 //
00214                 if (width>0){
00215                         w0=width;
00216                         nx=new_x;
00217                         ny=new_x;
00218                 }else{
00219                         w0=onx;
00220                         if (thumb){
00221                                 if(onx < ony*THUMB_X/THUMB_Y){
00222                                         ny=THUMB_Y;
00223                                         nx=onx*ny/ony;
00224                                 }else{
00225                                         nx=THUMB_X;
00226                                         ny=ony*nx/onx;
00227                                 }
00228                         }else{
00229                                 if (new_x){ // scale to new X w aspect
00230                                         nx=new_x;
00231                                         ny=ony*nx/onx;
00232                                 }else{
00233                                         nx=onx; 
00234                                         ny=ony;
00235                                 }
00236                         }
00237                 }
00238                 if (x0+nx >= onx) x0=0; // fallback
00239                 if (y0+ny >= ony) y0=0; // fallback
00240 
00241 
00242                 //prepare memory
00243                 rowdata = new double* [ny];
00244                 for (int i=0; i<ny; rowdata[i++] = new double [nx]);
00245 
00246                 //
00247                 // read data
00248                 //
00249 
00250                 const unsigned long gme_data_offset = 0x4004;
00251                 double scale = (double)nx/(double)w0;
00252                 short *row = new short[onx];
00253                 short data;
00254                 
00255                 for (int y=0; y<ny; y++){
00256                         f.seekg((y0+(int)((double)y/scale+.5))*onx*sizeof(short) + gme_data_offset);
00257                         f.read((char*)row, onx*sizeof(short));
00258                         for (int i=0; i<nx; ++i){
00259                                 data = row[x0+(int)((double)i/scale+.5)];
00260                                 if (WORDS_BIGENDIAN)
00261                                         swap_short (&data);
00262                                 rowdata[y][i] = (double)data;
00263                         }
00264                 }
00265 
00266                 f.close ();
00267 
00268                 state = GME_READ_OK;
00269         };
00270 
00271         const GME_STATUS status(){
00272                 return state;
00273         };
00274         
00275 
00276         virtual ~gme_image() {
00277                 for (int i=0; i<ny; delete [] rowdata[i++]);
00278                 delete [] rowdata;
00279         };
00280 
00281 private:
00282         GME_STATUS state;
00283 };
00284 
00285 
00286 int write_png(gchar *file_name, raw_image *img){
00287 // see here for pnglib docu:
00288 // http://www.libpng.org/pub/png/libpng-manual.html
00289 
00290         mainprog_info m;
00291 
00292         m.gamma   = 1.;
00293         m.width   = img->width();
00294         m.height  = img->height();
00295         m.modtime = time(NULL);
00296         m.infile  = NULL;
00297         if (! (m.outfile = fopen(file_name, "wb")))
00298                 return -1;
00299         m.row_pointers = img->row_rgb_pointers();
00300         m.title  = "gmetopng";
00301         m.author = "P. Zahl";
00302         m.desc   = "Omicron Gme data to png";
00303         m.copyright = "GPL";
00304         m.email   = "zahl@users.sourceforge.net";
00305         m.url     = "http://gxsm.sf.net";
00306         m.have_bg   = FALSE;
00307         m.have_time = FALSE;
00308         m.have_text = FALSE;
00309         m.pnmtype   = 6; // TYPE_RGB
00310         m.sample_depth = 8;
00311         m.interlaced= FALSE;
00312 
00313         writepng_init (&m);
00314         writepng_encode_image (&m);
00315         writepng_encode_finish (&m);
00316         writepng_cleanup (&m);
00317 
00318         return 0;
00319 }
00320 
00321 
00322 /* ****************************
00323               main
00324    ***************************/
00325 int main(int argc, const char *argv[]) {
00326         int thumb = 1;
00327         int new_x = 0;
00328         int x_off = 0, y_off = 0, width = 0;    
00329         int verbose = 0;
00330         int noquick = 0;
00331         int help = 0;
00332         gchar *filename;
00333         gchar *destinationfilename;
00334         gme_image *img = NULL;
00335         poptContext optCon; 
00336 
00337         struct poptOption optionsTable[] = {
00338                 {"x-offset",'x',POPT_ARG_INT,&x_off,0,"x-offset",NULL},
00339                 {"y-offset",'y',POPT_ARG_INT,&y_off,0,"y-offset",NULL},
00340                 {"width",'w',POPT_ARG_INT,&width,0,"width",NULL},
00341                 {"size",'s',POPT_ARG_INT,&new_x,0,"Size in x-direction.",NULL},
00342                 {"verbose",'v',POPT_ARG_NONE,&verbose,1,"Display information.",NULL},
00343                 {"noquick",'n',POPT_ARG_NONE,&noquick,1,"No-quick",NULL},
00344                 {"help",'h',POPT_ARG_NONE,&help,1,"Print help.",NULL},
00345                 { NULL, 0, 0, NULL, 0 }
00346         };
00347 
00348         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00349         poptSetOtherOptionHelp(optCon, "gmefile.t[fb]? [outfile.png]");
00350         while (poptGetNextOpt(optCon) >= 0) {;} //Now parse until no more options.
00351 
00352         if ((argc < 2 )||(help)) { 
00353                 poptPrintHelp(optCon, stderr, 0);
00354                 exit(1);
00355         }
00356                 
00357         filename = g_strdup(poptGetArg(optCon));
00358         destinationfilename = g_strdup(poptGetArg(optCon));
00359 
00360         if (destinationfilename == NULL){
00361                 destinationfilename = g_strjoin(NULL, filename, ".png", NULL);
00362                 // using simple join. if you need more sophisticated
00363                 // have a look at 'mmv' for suffix handling.
00364         }
00365 
00366         if(verbose){
00367                 if (new_x == 0) 
00368                         cout << "Thumbnail-size" << endl;
00369                 else
00370                         cout << "Rescaling to new x-size = " << new_x << endl;
00371                 cout << "Sourcefile: " << filename << endl;
00372                 cout << "Destinationfile: " << destinationfilename << endl;
00373         }
00374 
00375         if (new_x > 0)
00376                 thumb = 0;
00377         
00378         if ( x_off + y_off + width > 0){
00379                 if ( (x_off==0) || (y_off==0) || (width==0) ) {
00380                         cout << "Please use -x and -y and -w together."<< endl;
00381                         exit(-1);
00382                 }
00383                 if(verbose){
00384                         cout << "Offset: " << x_off << " x " << y_off << endl;
00385                         cout << "Width set to: " << width << endl;
00386                 }
00387         }
00388                 
00389         // load & rescale image
00390         img = new gme_image(filename, thumb, new_x, x_off, y_off, width);
00391 
00392         switch (img->status()){
00393                 case GME_READ_OK: break;
00394                 case GME_OPEN_FAILED: 
00395                         cerr << "Error opening Gme file >" << filename << "<" << endl; 
00396                         exit(-1);
00397                         break;
00398                 case GME_FILE_NOT_VALID:
00399                         cerr << "invalid Gme file >" << filename << "<" << endl; 
00400                         exit(-1);
00401                         break;
00402         }
00403                 
00404         if  (!img){
00405                 cerr << "Error while creating image from Gme file." << endl;
00406                 exit(-1);
00407         }
00408                 
00409         if (verbose)
00410                 cout << "Converting ..." << endl; 
00411                 
00412         if (noquick)
00413                 img->quick_rgb(FALSE);
00414         else
00415                 img->quick_rgb();
00416 
00417         if (verbose)
00418                 cout << "Writing >" << destinationfilename << "<" << endl; 
00419                 
00420         write_png(destinationfilename, img);
00421 
00422         if(verbose)
00423                 cout << "Writing complete." << endl;
00424                 
00425         g_free(filename);
00426         g_free(destinationfilename);
00427         poptFreeContext(optCon);
00428         exit(0);
00429 }

Generated on Sat Apr 1 09:04:28 2006 for GXSM by  doxygen 1.4.6