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 "thumbpal.h"
00038 #include "writepng.h"
00039
00040
00041 #define SCAN_V_DIRECT 0x0001
00042 #define SCAN_V_QUICK 0x0002
00043 #define SCAN_V_HORIZONTAL 0x0004
00044 #define SCAN_V_PERIODIC 0x0008
00045 #define SCAN_V_LOG 0x0010
00046 #define SCAN_V_DIFFERENTIAL 0x0020
00047 #define SCAN_V_PLANESUB 0x0040
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 typedef enum GXSM_NETCDF_STATUS { NC_READ_OK, NC_OPEN_FAILED, NC_NOT_FROM_GXSM };
00061
00062 #define THUMB_X 96 // Thumbnail max X size
00063 #define THUMB_Y 91 // Thumbnail max Y size
00064
00065 inline int min (int x, int y) { return x<y?x:y; }
00066 inline int max (int x, int y) { return x>y?x:y; }
00067
00068 class raw_image{
00069 public:
00070 raw_image(){
00071 rgb=NULL;
00072 scan_viewmode = 0;
00073 scan_contrast = 0.;
00074 scan_bright = 0.;
00075 };
00076 virtual ~raw_image(){
00077 if(rgb){
00078 for (int i=0; i<ny; delete[] rgb[i++]);
00079 delete[] rgb;
00080 }
00081 };
00082
00083 int width() { return nx; };
00084 int height() { return ny; };
00085
00086 void SetViewMode (int vm) {
00087 scan_viewmode = vm;
00088 };
00089
00090 void SetTransfer (double c, double b){
00091 scan_contrast = c;
00092 scan_bright = b;
00093 };
00094
00095 void calc_line_regress(int y, double &slope, double &offset){
00096
00097
00098
00099 double sumi, sumy, sumiy, sumyq, sumiq;
00100 int i, istep;
00101 int Xmax, Xmin;
00102 double a, n, imean, ymean;
00103
00104 sumi = sumiq = sumy = sumyq = sumiy = 0.0;
00105 Xmax = nx-nx/10;
00106 Xmin = nx/10;
00107 istep = 1;
00108 for (i=Xmin; i < Xmax; i+=istep) {
00109 sumi += (double)i;
00110 sumiq += (double)i*(double)i;
00111 a = rowdata[y][i];
00112 sumy += a;
00113 sumyq += a * a;
00114 sumiy += a * (double)i;
00115 }
00116 n = (double)((Xmax-Xmin)/istep);
00117 if ((Xmax-Xmin) % istep != 0) n += 1.0;
00118 imean = sumi / n;
00119 ymean = sumy / n;
00120 slope = (sumiy- n * imean * ymean ) / (sumiq - n * imean * imean);
00121 offset = ymean - slope * imean;
00122 };
00123 double soft(int i, int j, double lim=0){
00124 int a,b,c,d;
00125 double z, mi, ma;
00126 int u,l;
00127
00128 a = max (0, i-1);
00129 b = min (i+1, nx-1);
00130 c = max (0, j-1);
00131 d = min (j+1, ny-1);
00132
00133 ma = mi = rowdata[j][i];
00134 u = l = 1;
00135
00136 #define MIMA(J,I) do{ z = rowdata[J][I]; if (ma < z) { u++; ma = z; } if (mi > z) { l++; mi = z; } }while(0)
00137
00138 MIMA (c,i);
00139 MIMA (c,a);
00140 MIMA (j,a);
00141 MIMA (d,a);
00142 MIMA (c,b);
00143 MIMA (j,b);
00144 MIMA (d,b);
00145 MIMA (d,i);
00146
00147 return (mi*l + ma*u)/(u+l);
00148 }
00149 void find_soft_min_max (double &min, double &max){
00150 double ihigh, ilow, imed, irange, high, low, zrange, bin_width, dz_norm;
00151 double dnum;
00152 int bin_num, med_bin, lo_bin, hi_bin;
00153 double *bins;
00154
00155
00156 low = high = soft (0,0);
00157 for (int i=0; i<ny; ++i)
00158 for (int j=0; j<nx; ++j){
00159 double v = soft (j,i);
00160 if (low > v) low = v;
00161 if (high < v) high = v;
00162 }
00163
00164
00165 zrange = high-low;
00166 dnum = zrange/3;
00167
00168 bin_num = (int)dnum;
00169 bin_width = zrange / bin_num;
00170 dz_norm = 1./bin_width;
00171
00172 bins = new double[bin_num];
00173
00174 for(int i = 0; i < bin_num; i++)
00175 bins[i] = 0.;
00176
00177 for(int col = 0; col < nx; col++)
00178 for(int line = 0; line < ny; line++){
00179 double f = (soft (col,line) - low) / bin_width;
00180 int bin = (int)f;
00181
00182 if (bin < bin_num){
00183 double f1 = (bin+1) * bin_width;
00184 if ((f+dz_norm) > f1){
00185 bins [bin] += f-bin;
00186 ++bin;
00187 if (bin < bin_num)
00188 bins [bin] += bin-f;
00189 }
00190 else
00191 bins [bin] += 1.;
00192 }
00193 }
00194
00195
00196 for(int i = 1; i < bin_num; i++)
00197 bins[i] += bins[i-1];
00198
00199 ilow = bins [bin_num/100];
00200 ihigh = bins [bin_num-bin_num/100-1];
00201 irange = ihigh - ilow;
00202 imed = ilow + irange/2.;
00203
00204 for (med_bin = 1; bins [med_bin] < imed; ++med_bin);
00205
00206 for (lo_bin = med_bin; lo_bin > (bin_num/100) && bins [lo_bin] > ilow+irange/20.; --lo_bin);
00207 for (hi_bin = med_bin; hi_bin < (bin_num-bin_num/100-1) && bins [hi_bin] < ihigh-irange/20.; ++hi_bin);
00208
00209 min = lo_bin*bin_width + low;
00210 max = hi_bin*bin_width + low;
00211
00212 delete [] bins;
00213
00214
00215 };
00216 void quick_rgb(int linreg=TRUE) {
00217 if (rgb){
00218 for (int i=0; i<ny; delete[] rgb[i++]);
00219 delete[] rgb;
00220 }
00221 rgb = new unsigned char* [ny];
00222 for (int i=0; i<ny; rgb[i++] = new unsigned char[3*nx]);
00223
00224
00225 double min, max, range;
00226 if (linreg){
00227
00228 switch (scan_viewmode){
00229 case SCAN_V_DIRECT:
00230 for (int i=0; i<ny; ++i){
00231 for (int j=0; j<nx; ++j){
00232 rowdata[i][j] *= scan_contrast;
00233 rowdata[i][j] += scan_bright;
00234 }
00235 }
00236 find_soft_min_max (min, max);
00237 break;
00238 case SCAN_V_QUICK:
00239
00240 for (int i=0; i<ny; ++i){
00241 double a,b;
00242 calc_line_regress (i, a, b);
00243 for (int j=0; j<nx; ++j){
00244 rowdata[i][j] -= j*a+b;
00245 rowdata[i][j] *= scan_contrast;
00246 rowdata[i][j] += scan_bright;
00247 }
00248 }
00249 min = 0.;
00250 if ( fabs (scan_bright) > 64.)
00251 max = 1024.;
00252 else
00253 max = 64.;
00254 break;
00255 default:
00256
00257 for (int i=0; i<ny; ++i){
00258 double a,b;
00259 calc_line_regress (i, a, b);
00260 for (int j=0; j<nx; ++j)
00261 rowdata[i][j] -= j*a+b;
00262 }
00263 find_soft_min_max (min, max);
00264 break;
00265 }
00266 }
00267
00268 range = max-min;
00269 for (int i=0; i<ny; ++i)
00270 for (int j=0, k=0; j<nx; ++j){
00271 int idx = (int)((rowdata[i][j]-min)/range*PALETTE_ENTRIES+0.5);
00272 const int limit = 255;
00273 if (idx < 0){
00274 idx /= -8; if (idx > limit) idx = limit;
00275 rgb[i][k++] = 16;
00276 rgb[i][k++] = 16;
00277 rgb[i][k++] = idx;
00278 continue;
00279 }
00280 if (idx > PALETTE_ENTRIES){
00281 idx -= PALETTE_ENTRIES;
00282 idx /= 8; if (idx > limit) idx = limit; idx = limit-idx;
00283 rgb[i][k++] = 255;
00284 rgb[i][k++] = idx;
00285 rgb[i][k++] = idx;
00286 continue;
00287 }
00288 idx *= 3;
00289 rgb[i][k++] = thumb_palette[idx++];
00290 rgb[i][k++] = thumb_palette[idx++];
00291 rgb[i][k++] = thumb_palette[idx];
00292 }
00293
00294 };
00295 unsigned char **row_rgb_pointers() { return rgb; };
00296
00297 protected:
00298 int nx, ny;
00299 int x0, y0, w0;
00300 int onx, ony;
00301 double **rowdata;
00302 unsigned char **rgb;
00303
00304 int scan_viewmode;
00305 double scan_contrast;
00306 double scan_bright;
00307 };
00308
00309 template <class NC_VAR_TYP>
00310 class raw_image_tmpl : public raw_image{
00311 public:
00312 raw_image_tmpl(NcVar *img, int thumb=1, int new_x=0, int x_off=0, int y_off=0, int width=0){
00313 x0 = x_off; y0 = y_off;
00314
00315
00316
00317 ony = img->get_dim(2)->size();
00318 onx = img->get_dim(3)->size();
00319
00320 if (width>0){
00321 w0=width;
00322 nx=new_x;
00323 ny=new_x;
00324 }else{
00325 w0=onx;
00326 if (thumb){
00327 if(onx < ony*THUMB_X/THUMB_Y){
00328 ny=THUMB_Y;
00329 nx=onx*ny/ony;
00330 }else{
00331 nx=THUMB_X;
00332 ny=ony*nx/onx;
00333 }
00334 }else{
00335 if (new_x){
00336 nx=new_x;
00337 ny=ony*nx/onx;
00338 }else{
00339 nx=onx;
00340 ny=ony;
00341 }
00342 }
00343 }
00344
00345 if (x0+nx >= onx) x0=0;
00346 if (y0+ny >= ony) y0=0;
00347
00348 rowdata = new double* [ny];
00349 for (int i=0; i<ny; rowdata[i++] = new double [nx]);
00350 convert_from_nc(img);
00351 };
00352
00353 virtual ~raw_image_tmpl(){
00354 for (int i=0; i<ny; delete [] rowdata[i++]);
00355 delete [] rowdata;
00356 };
00357
00358 void convert_from_nc(NcVar *img, int v=0){
00359 double scale = (double)nx/(double)w0;
00360 NC_VAR_TYP *row = new NC_VAR_TYP[onx];
00361
00362 for (int y=0; y<ny; y++){
00363 img->set_cur (0, v, y0+(int)((double)y/scale+.5));
00364 img->get (row, 1,1, 1,onx);
00365 for (int i=0; i<nx; ++i)
00366 rowdata[y][i] = (double)row[x0+(int)((double)i/scale+.5)];
00367 }
00368 };
00369 };
00370
00371
00372 GXSM_NETCDF_STATUS netcdf_read(const gchar *file_name, raw_image **img,
00373 int thumb, int new_x, int x_off, int y_off, int width){
00374 NcError ncerr(NcError::verbose_nonfatal);
00375 NcFile nc(file_name);
00376
00377
00378 if (! nc.is_valid())
00379 return NC_OPEN_FAILED;
00380
00381 NcVar *Data = NULL;
00382
00383
00384 if (! (Data = nc.get_var("H")))
00385
00386
00387 if (! (Data = nc.get_var("Intensity")))
00388
00389
00390 if (! (Data = nc.get_var("FloatField")))
00391
00392
00393 if (! (Data = nc.get_var("DoubleField")))
00394
00395
00396 return NC_NOT_FROM_GXSM;
00397
00398 switch (Data->type()){
00399 case ncShort: *img = new raw_image_tmpl<short> (Data, thumb, new_x, x_off, y_off, width); break;
00400 case ncLong: *img = new raw_image_tmpl<long> (Data, thumb, new_x, x_off, y_off, width); break;
00401 case ncFloat: *img = new raw_image_tmpl<float> (Data, thumb, new_x, x_off, y_off, width); break;
00402 case ncDouble: *img = new raw_image_tmpl<double> (Data, thumb, new_x, x_off, y_off, width); break;
00403 case ncByte: *img = new raw_image_tmpl<char> (Data, thumb, new_x, x_off, y_off, width); break;
00404 case ncChar: *img = new raw_image_tmpl<char> (Data, thumb, new_x, x_off, y_off, width); break;
00405 default: *img = NULL; return NC_NOT_FROM_GXSM;
00406 }
00407
00408 if(nc.get_var("viewmode")){
00409 int vm;
00410 double c,b;
00411
00412 nc.get_var("viewmode")->get(&vm);
00413 (*img)->SetViewMode (vm);
00414
00415 nc.get_var("contrast")->get(&c);
00416 nc.get_var("bright")->get(&b);
00417 (*img)->SetTransfer (c,b);
00418 }
00419
00420
00421 return NC_READ_OK;
00422 }
00423
00424
00425
00426 int write_png(gchar *file_name, raw_image *img){
00427
00428
00429
00430 mainprog_info m;
00431
00432 m.gamma = 1.;
00433 m.width = img->width();
00434 m.height = img->height();
00435 m.modtime = time(NULL);
00436 m.infile = NULL;
00437 if (! (m.outfile = fopen(file_name, "wb")))
00438 return -1;
00439 m.row_pointers = img->row_rgb_pointers();
00440 m.title = "nctopng";
00441 m.author = "Percy Zahl";
00442 m.desc = "Gxsm NC data to png";
00443 m.copyright = "GPL";
00444 m.email = "zahl@users.sourceforge.net";
00445 m.url = "http://gxsm.sf.net";
00446 m.have_bg = FALSE;
00447 m.have_time = FALSE;
00448 m.have_text = FALSE;
00449 m.pnmtype = 6;
00450 m.sample_depth = 8;
00451 m.interlaced= FALSE;
00452
00453 writepng_init (&m);
00454 writepng_encode_image (&m);
00455 writepng_encode_finish (&m);
00456 writepng_cleanup (&m);
00457
00458 return 0;
00459 }
00460
00461
00462
00463 int main(int argc, const char *argv[]) {
00464 int thumb = 1;
00465 int new_x = 0;
00466 int x_off = 0, y_off = 0, width = 0;
00467 int verbose = 0;
00468 int noquick = 0;
00469 int help = 0;
00470 gchar *filename;
00471 gchar *destinationfilename;
00472 raw_image *img = NULL;
00473 poptContext optCon;
00474
00475 struct poptOption optionsTable[] = {
00476 {"x-offset",'x',POPT_ARG_INT,&x_off,0,"x-offset",NULL},
00477 {"y-offset",'y',POPT_ARG_INT,&y_off,0,"y-offset",NULL},
00478 {"width",'w',POPT_ARG_INT,&width,0,"width",NULL},
00479 {"size",'s',POPT_ARG_INT,&new_x,0,"Size in x-direction.",NULL},
00480 {"verbose",'v',POPT_ARG_NONE,&verbose,1,"Display information.",NULL},
00481 {"noquick",'n',POPT_ARG_NONE,&noquick,1,"No-quick, default: auto analysis",NULL},
00482 {"help",'h',POPT_ARG_NONE,&help,1,"Print help.",NULL},
00483 { NULL, 0, 0, NULL, 0 }
00484 };
00485
00486 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00487 poptSetOtherOptionHelp(optCon, "gxsmfile.nc [outfile.png]");
00488 while (poptGetNextOpt(optCon) >= 0) {;}
00489
00490 if ((argc < 2 )||(help)) {
00491 poptPrintHelp(optCon, stderr, 0);
00492 exit(1);
00493 }
00494
00495 filename = g_strdup(poptGetArg(optCon));
00496 destinationfilename = g_strdup(poptGetArg(optCon));
00497
00498 if (destinationfilename == NULL){
00499 destinationfilename = g_strjoin(NULL, filename, ".png", NULL);
00500
00501
00502 }
00503
00504 if(verbose){
00505 if (new_x == 0)
00506 std::cout << "Thumbnail-size" << std::endl;
00507 else
00508 std::cout << "Rescaling to new x-size = " << new_x << std::endl;
00509 std::cout << "Sourcefile: " << filename << std::endl;
00510 std::cout << "Destinationfile: " << destinationfilename << std::endl;
00511 }
00512
00513 if (new_x > 0)
00514 thumb = 0;
00515
00516 if ( x_off + y_off + width > 0){
00517 if ( (x_off==0) || (y_off==0) || (width==0) ) {
00518 std::cout << "Please use -x and -y and -w together."<< std::endl;
00519 exit(-1);
00520 }
00521 if(verbose){
00522 std::cout << "Offset: " << x_off << " x " << y_off << std::endl;
00523 std::cout << "Width set to: " << width << std::endl;
00524 }
00525 }
00526
00527 switch (netcdf_read (filename, &img, thumb, new_x, x_off, y_off, width)){
00528 case NC_READ_OK: break;
00529 case NC_OPEN_FAILED:
00530 std::cerr << "Error opening NC file >" << filename << "<" << std::endl;
00531 exit(-1);
00532 break;
00533 case NC_NOT_FROM_GXSM:
00534 std::cerr << "Sorry, can't use this NC file >" << filename << "<" << std::endl
00535 << "Hint: doesn't look like a Gxsm nc data file!" << std::endl;
00536 exit(-1);
00537 break;
00538 }
00539
00540 if (!img){
00541 std::cerr << "Error while creating image from NC file." << std::endl;
00542 exit(-1);
00543 }
00544
00545 if (verbose)
00546 std::cout << "Converting ..." << std::endl;
00547
00548 if (noquick)
00549 img->quick_rgb(FALSE);
00550 else
00551 img->quick_rgb();
00552
00553 if (verbose)
00554 std::cout << "Writing >" << destinationfilename << "<" << std::endl;
00555
00556 write_png(destinationfilename, img);
00557
00558 if(verbose)
00559 std::cout << "Writing complete." << std::endl;
00560
00561 g_free(filename);
00562 g_free(destinationfilename);
00563 poptFreeContext(optCon);
00564 exit(0);
00565 }