00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <cstdio>
00029 #include <cstdlib>
00030 #include <fstream>
00031 #include <cmath>
00032
00033 #include <glib.h>
00034 #include <netcdf.hh>
00035 #include <png.h>
00036 #include <popt.h>
00037 #include "config.h"
00038 #include "thumbpal.h"
00039 #include "writepng.h"
00040
00041 using namespace std;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #ifndef WORDS_BIGENDIAN
00057 # define WORDS_BIGENDIAN 0
00058 #endif
00059
00060 typedef enum OMICRON_SCALA_STATUS { SCALA_READ_OK, SCALA_OPEN_FAILED, SCALA_FILE_NOT_VALID };
00061
00062 #define MAXFILELENGTH 64 // Maximum length of filename.
00063 #define THUMB_X 96 // Thumbnail max X size
00064 #define THUMB_Y 91 // Thumbnail max Y size
00065
00066 class raw_image{
00067 public:
00068 raw_image(){ rgb=NULL; };
00069 virtual ~raw_image(){
00070 if(rgb){
00071 for (int i=0; i<ny; delete[] rgb[i++]);
00072 delete[] rgb;
00073 }
00074 };
00075
00076 int width() { return nx; };
00077 int height() { return ny; };
00078 void calc_line_regress(int y, double &slope, double &offset){
00079
00080
00081
00082 double sumi, sumy, sumiy, sumyq, sumiq;
00083 int i, istep;
00084 int Xmax, Xmin;
00085 double a, n, imean, ymean;
00086
00087 sumi = sumiq = sumy = sumyq = sumiy = 0.0;
00088 Xmax = nx-nx/10;
00089 Xmin = nx/10;
00090 istep = 1;
00091 for (i=Xmin; i < Xmax; i+=istep) {
00092 sumi += (double)i;
00093 sumiq += (double)i*(double)i;
00094 a = rowdata[y][i];
00095 sumy += a;
00096 sumyq += a * a;
00097 sumiy += a * (double)i;
00098 }
00099 n = (double)((Xmax-Xmin)/istep);
00100 if ((Xmax-Xmin) % istep != 0) n += 1.0;
00101 imean = sumi / n;
00102 ymean = sumy / n;
00103 slope = (sumiy- n * imean * ymean ) / (sumiq - n * imean * imean);
00104 offset = ymean - slope * imean;
00105 };
00106 double soft(int i, int j, double lim=0){
00107
00108
00109
00110
00111
00112
00113
00114 return rowdata[j][i];
00115 }
00116 void find_soft_min_max (double &min, double &max){
00117 min = max = soft(0,0);
00118 for (int i=0; i<ny; ++i)
00119 for (int j=0; j<nx; ++j){
00120 double v = soft (j,i);
00121 if (min > v) min = v;
00122 if (max < v) max = v;
00123 }
00124 };
00125 void quick_rgb(int linreg=TRUE) {
00126 if (rgb){
00127 for (int i=0; i<ny; delete[] rgb[i++]);
00128 delete[] rgb;
00129 }
00130 rgb = new unsigned char* [ny];
00131 for (int i=0; i<ny; rgb[i++] = new unsigned char[3*nx]);
00132
00133 if (linreg){
00134
00135 for (int i=0; i<ny; ++i){
00136 double a,b;
00137 calc_line_regress (i, a, b);
00138 for (int j=0; j<nx; ++j)
00139 rowdata[i][j] -= j*a+b;
00140 }
00141 }
00142
00143
00144 double min, max, range;
00145 find_soft_min_max (min, max);
00146 range = max-min;
00147 for (int i=0; i<ny; ++i)
00148 for (int j=0, k=0; j<nx; ++j){
00149 int idx = 3*(int)((rowdata[i][j]-min)/range*PALETTE_ENTRIES+0.5);
00150 rgb[i][k++] = thumb_palette[idx++];
00151 rgb[i][k++] = thumb_palette[idx++];
00152 rgb[i][k++] = thumb_palette[idx];
00153 }
00154
00155 };
00156 unsigned char **row_rgb_pointers() { return rgb; };
00157
00158 protected:
00159 int nx, ny;
00160 int x0, y0, w0;
00161 int onx, ony;
00162 double **rowdata;
00163 unsigned char **rgb;
00164 };
00165
00166
00167
00168 class scala_image : public raw_image {
00169 public:
00170 scala_image (const gchar *file_name, int thumb, int new_x, int x_off, int y_off, int width) {
00171
00172 gchar *fparname=NULL;
00173 gchar *fbasename=NULL;
00174 gchar *fsuffix=NULL;
00175
00176 x0 = x_off; y0 = y_off;
00177
00178
00179
00180
00181 fbasename = g_strndup (file_name, strlen(file_name)-4);
00182 fsuffix = g_strdup (file_name+strlen(file_name)-4);
00183 fparname = g_strconcat (fbasename, ".par", NULL);
00184
00185
00186
00187 if ( g_strncasecmp (fsuffix,".tf", 3) != 0 && g_strncasecmp (fsuffix,".tb", 3) != 0 ){
00188 state = SCALA_FILE_NOT_VALID;
00189 return;
00190 }
00191
00192
00193
00194
00195 std::ifstream parstream;
00196 parstream.open(fparname, std::ios::in);
00197 if(!parstream.good()) {
00198 state = SCALA_OPEN_FAILED;
00199 return;
00200 }
00201
00202
00203 gchar linebuf[100];
00204 while (!parstream.eof()) {
00205 parstream.getline (linebuf, 100);
00206
00207
00208 if ( g_strncasecmp (linebuf, "Image Size in X", 15) == 0)
00209 sscanf (linebuf, "%*[^0-9]%d", &onx);
00210
00211
00212 if ( g_strncasecmp (linebuf, "Image Size in Y", 15) == 0)
00213 sscanf (linebuf, "%*[^0-9]%d", &ony);
00214 }
00215
00216 parstream.close();
00217
00218
00219
00220
00221 if (width>0){
00222 w0=width;
00223 nx=new_x;
00224 ny=new_x;
00225 }else{
00226 w0=onx;
00227 if (thumb){
00228 if(onx < ony*THUMB_X/THUMB_Y){
00229 ny=THUMB_Y;
00230 nx=onx*ny/ony;
00231 }else{
00232 nx=THUMB_X;
00233 ny=ony*nx/onx;
00234 }
00235 }else{
00236 if (new_x){
00237 nx=new_x;
00238 ny=ony*nx/onx;
00239 }else{
00240 nx=onx;
00241 ny=ony;
00242 }
00243 }
00244 }
00245 if (x0+nx >= onx) x0=0;
00246 if (y0+ny >= ony) y0=0;
00247
00248
00249
00250 rowdata = new double* [ny];
00251 for (int i=0; i<ny; rowdata[i++] = new double [nx]);
00252
00253
00254
00255
00256
00257
00258 std::ifstream datstream;
00259 datstream.open(file_name, std::ios::in | std::ios::binary);
00260 if(!datstream.good()){
00261 state = SCALA_OPEN_FAILED;
00262 return;
00263 }
00264
00265 double scale = (double)nx/(double)w0;
00266 short *row = new short[onx];
00267
00268 union order {short s; char c[2];};
00269 order swap;
00270 char low;
00271
00272 for (int y=0; y<ny; y++) {
00273 datstream.seekg((y0+(int)((double)y/scale+.5))*onx*sizeof(short));
00274 datstream.read((char*)row, onx*sizeof(short));
00275
00276 for (int i=0; i<nx; ++i) {
00277 swap.s = row[x0+(int)((double)i/scale+.5)];
00278
00279 if (!WORDS_BIGENDIAN) {
00280 low = swap.c[0];
00281 swap.c[0] = swap.c[1];
00282 swap.c[1] =low;
00283 }
00284
00285 rowdata[y][i] = (double)swap.s;
00286 }
00287 }
00288
00289 datstream.close();
00290
00291 state = SCALA_READ_OK;
00292 };
00293
00294 const OMICRON_SCALA_STATUS status(){
00295 return state;
00296 };
00297
00298
00299 virtual ~scala_image() {
00300 for (int i=0; i<ny; delete [] rowdata[i++]);
00301 delete [] rowdata;
00302 };
00303
00304 private:
00305 OMICRON_SCALA_STATUS state;
00306 };
00307
00308
00309 int write_png(gchar *file_name, raw_image *img){
00310
00311
00312
00313 mainprog_info m;
00314
00315 m.gamma = 1.;
00316 m.width = img->width();
00317 m.height = img->height();
00318 m.modtime = time(NULL);
00319 m.infile = NULL;
00320 if (! (m.outfile = fopen(file_name, "wb")))
00321 return -1;
00322 m.row_pointers = img->row_rgb_pointers();
00323 m.title = "scalatopng";
00324 m.author = "A. Klust";
00325 m.desc = "Omicron Scala data to png";
00326 m.copyright = "GPL";
00327 m.email = "klust@users.sourceforge.net";
00328 m.url = "http://gxsm.sf.net";
00329 m.have_bg = FALSE;
00330 m.have_time = FALSE;
00331 m.have_text = FALSE;
00332 m.pnmtype = 6;
00333 m.sample_depth = 8;
00334 m.interlaced= FALSE;
00335
00336 writepng_init (&m);
00337 writepng_encode_image (&m);
00338 writepng_encode_finish (&m);
00339 writepng_cleanup (&m);
00340
00341 return 0;
00342 }
00343
00344
00345
00346
00347
00348 int main(int argc, const char *argv[]) {
00349 int thumb = 1;
00350 int new_x = 0;
00351 int x_off = 0, y_off = 0, width = 0;
00352 int verbose = 0;
00353 int noquick = 0;
00354 int help = 0;
00355 gchar *filename;
00356 gchar *destinationfilename;
00357 scala_image *img = NULL;
00358 poptContext optCon;
00359
00360 struct poptOption optionsTable[] = {
00361 {"x-offset",'x',POPT_ARG_INT,&x_off,0,"x-offset",NULL},
00362 {"y-offset",'y',POPT_ARG_INT,&y_off,0,"y-offset",NULL},
00363 {"width",'w',POPT_ARG_INT,&width,0,"width",NULL},
00364 {"size",'s',POPT_ARG_INT,&new_x,0,"Size in x-direction.",NULL},
00365 {"verbose",'v',POPT_ARG_NONE,&verbose,1,"Display information.",NULL},
00366 {"noquick",'n',POPT_ARG_NONE,&noquick,1,"No-quick",NULL},
00367 {"help",'h',POPT_ARG_NONE,&help,1,"Print help.",NULL},
00368 { NULL, 0, 0, NULL, 0 }
00369 };
00370
00371 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00372 poptSetOtherOptionHelp(optCon, "scalafile.t[fb]? [outfile.png]");
00373 while (poptGetNextOpt(optCon) >= 0) {;}
00374
00375 if ((argc < 2 )||(help)) {
00376 poptPrintHelp(optCon, stderr, 0);
00377 exit(1);
00378 }
00379
00380 filename = g_strndup(poptGetArg(optCon), MAXFILELENGTH);
00381 destinationfilename = g_strndup(poptGetArg(optCon), MAXFILELENGTH);
00382
00383 if (destinationfilename == NULL){
00384 destinationfilename = g_strjoin(NULL, filename, ".png", NULL);
00385
00386
00387 }
00388
00389 if(verbose){
00390 if (new_x == 0)
00391 std::cout << "Thumbnail-size" << std::endl;
00392 else
00393 std::cout << "Rescaling to new x-size = " << new_x << std::endl;
00394 std::cout << "Sourcefile: " << filename << std::endl;
00395 std::cout << "Destinationfile: " << destinationfilename << std::endl;
00396 }
00397
00398 if (new_x > 0)
00399 thumb = 0;
00400
00401 if ( x_off + y_off + width > 0){
00402 if ( (x_off==0) || (y_off==0) || (width==0) ) {
00403 std::cout << "Please use -x and -y and -w together."<< std::endl;
00404 exit(-1);
00405 }
00406 if(verbose){
00407 std::cout << "Offset: " << x_off << " x " << y_off << std::endl;
00408 std::cout << "Width set to: " << width << std::endl;
00409 }
00410 }
00411
00412
00413 img = new scala_image(filename, thumb, new_x, x_off, y_off, width);
00414
00415 switch (img->status()){
00416 case SCALA_READ_OK: break;
00417 case SCALA_OPEN_FAILED:
00418 std::cerr << "Error opening Scala file >" << filename << "<" << std::endl;
00419 exit(-1);
00420 break;
00421 case SCALA_FILE_NOT_VALID:
00422 std::cerr << "invalid Scala file >" << filename << "<" << std::endl;
00423 exit(-1);
00424 break;
00425 }
00426
00427 if (!img){
00428 std::cerr << "Error while creating image from Scala file." << std::endl;
00429 exit(-1);
00430 }
00431
00432 if (verbose)
00433 std::cout << "Converting ..." << std::endl;
00434
00435 if (noquick)
00436 img->quick_rgb(FALSE);
00437 else
00438 img->quick_rgb();
00439
00440 if (verbose)
00441 std::cout << "Writing >" << destinationfilename << "<" << std::endl;
00442
00443 write_png(destinationfilename, img);
00444
00445 if(verbose)
00446 std::cout << "Writing complete." << std::endl;
00447
00448 g_free(filename);
00449 g_free(destinationfilename);
00450 poptFreeContext(optCon);
00451 exit(0);
00452 }