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 RHK_SPM32_STATUS { SPM32_READ_OK, SPM32_OPEN_FAILED, SPM32_FILE_NOT_VALID };
00061
00062 #define THUMB_X 96 // Thumbnail max X size
00063 #define THUMB_Y 91 // Thumbnail max Y size
00064
00065 class raw_image{
00066 public:
00067 raw_image(){ rgb=NULL; };
00068 virtual ~raw_image(){
00069 if(rgb){
00070 for (int i=0; i<ny; delete[] rgb[i++]);
00071 delete[] rgb;
00072 }
00073 };
00074
00075 int width() { return nx; };
00076 int height() { return ny; };
00077 void calc_line_regress(int y, double &slope, double &offset){
00078
00079
00080
00081 double sumi, sumy, sumiy, sumyq, sumiq;
00082 int i, istep;
00083 int Xmax, Xmin;
00084 double a, n, imean, ymean;
00085
00086 sumi = sumiq = sumy = sumyq = sumiy = 0.0;
00087 Xmax = nx-nx/10;
00088 Xmin = nx/10;
00089 istep = 1;
00090 for (i=Xmin; i < Xmax; i+=istep) {
00091 sumi += (double)i;
00092 sumiq += (double)i*(double)i;
00093 a = rowdata[y][i];
00094 sumy += a;
00095 sumyq += a * a;
00096 sumiy += a * (double)i;
00097 }
00098 n = (double)((Xmax-Xmin)/istep);
00099 if ((Xmax-Xmin) % istep != 0) n += 1.0;
00100 imean = sumi / n;
00101 ymean = sumy / n;
00102 slope = (sumiy- n * imean * ymean ) / (sumiq - n * imean * imean);
00103 offset = ymean - slope * imean;
00104 };
00105 double soft(int i, int j, double lim=0){
00106
00107
00108
00109
00110
00111
00112
00113 return rowdata[j][i];
00114 }
00115 void find_soft_min_max (double &min, double &max){
00116 min = max = soft(0,0);
00117 for (int i=0; i<ny; ++i)
00118 for (int j=0; j<nx; ++j){
00119 double v = soft (j,i);
00120 if (min > v) min = v;
00121 if (max < v) max = v;
00122 }
00123 };
00124 void quick_rgb(int linreg=TRUE) {
00125 if (rgb){
00126 for (int i=0; i<ny; delete[] rgb[i++]);
00127 delete[] rgb;
00128 }
00129 rgb = new unsigned char* [ny];
00130 for (int i=0; i<ny; rgb[i++] = new unsigned char[3*nx]);
00131
00132 if (linreg){
00133
00134 for (int i=0; i<ny; ++i){
00135 double a,b;
00136 calc_line_regress (i, a, b);
00137 for (int j=0; j<nx; ++j)
00138 rowdata[i][j] -= j*a+b;
00139 }
00140 }
00141
00142
00143 double min, max, range;
00144 find_soft_min_max (min, max);
00145 range = max-min;
00146 for (int i=0; i<ny; ++i)
00147 for (int j=0, k=0; j<nx; ++j){
00148 int idx = 3*(int)((rowdata[i][j]-min)/range*PALETTE_ENTRIES+0.5);
00149 rgb[i][k++] = thumb_palette[idx++];
00150 rgb[i][k++] = thumb_palette[idx++];
00151 rgb[i][k++] = thumb_palette[idx];
00152 }
00153
00154 };
00155 unsigned char **row_rgb_pointers() { return rgb; };
00156
00157 protected:
00158 int nx, ny;
00159 int x0, y0, w0;
00160 int onx, ony;
00161 double **rowdata;
00162 unsigned char **rgb;
00163 };
00164
00165
00166
00167 class spm32_image : public raw_image {
00168 public:
00169 spm32_image (const gchar *file_name, int thumb, int new_x, int x_off, int y_off, int width) {
00170
00171 char header[512];
00172 long dummy, type, data_offset, size;
00173
00174 x0 = x_off; y0 = y_off;
00175
00176
00177 std::ifstream f(file_name, ios::in);
00178 if (!f.good()){
00179 state = SPM32_OPEN_FAILED;
00180 return;
00181 }
00182
00183
00184 f.read(header, 512);
00185
00186
00187
00188 if (strncmp (header, "STiMage 3.1", 11) != 0){
00189 f.close ();
00190 state = SPM32_FILE_NOT_VALID;
00191 return;
00192 }
00193
00194
00195 sscanf (header + 0x20, "%ld %ld %ld %d %d %ld %ld",
00196 &type, &dummy, &dummy, &onx, &ony, &size, &dummy);
00197 sscanf (header + 0x100, "id %ld %ld",
00198 &dummy, &data_offset);
00199
00200
00201 if ( type != 0 || size != onx*ony*2 ){
00202 f.close ();
00203 state = SPM32_FILE_NOT_VALID;
00204 return;
00205 }
00206
00207
00208
00209
00210 if (width>0){
00211 w0=width;
00212 nx=new_x;
00213 ny=new_x;
00214 }else{
00215 w0=onx;
00216 if (thumb){
00217 if(onx < ony*THUMB_X/THUMB_Y){
00218 ny=THUMB_Y;
00219 nx=onx*ny/ony;
00220 }else{
00221 nx=THUMB_X;
00222 ny=ony*nx/onx;
00223 }
00224 }else{
00225 if (new_x){
00226 nx=new_x;
00227 ny=ony*nx/onx;
00228 }else{
00229 nx=onx;
00230 ny=ony;
00231 }
00232 }
00233 }
00234 if (x0+nx >= onx) x0=0;
00235 if (y0+ny >= ony) y0=0;
00236
00237
00238
00239 rowdata = new double* [ny];
00240 for (int i=0; i<ny; rowdata[i++] = new double [nx]);
00241
00242
00243
00244
00245
00246
00247 double scale = (double)nx/(double)w0;
00248 short *row = new short[onx];
00249
00250 union order {short s; char c[2];};
00251 order swap;
00252 char low;
00253
00254 for (int y=0; y<ny; y++) {
00255 f.seekg(data_offset + (y0+(int)((double)y/scale+.5))*onx*sizeof(short), ios::beg);
00256 f.read((char*)row, onx*sizeof(short));
00257
00258 for (int i=0; i<nx; ++i) {
00259 swap.s = row[x0+(int)((double)i/scale+.5)];
00260
00261 if (WORDS_BIGENDIAN) {
00262 low = swap.c[0];
00263 swap.c[0] = swap.c[1];
00264 swap.c[1] =low;
00265 }
00266
00267 rowdata[y][i] = (double)swap.s;
00268 }
00269 }
00270
00271 f.close();
00272
00273 state = SPM32_READ_OK;
00274 };
00275
00276 const RHK_SPM32_STATUS status(){
00277 return state;
00278 };
00279
00280
00281 virtual ~spm32_image() {
00282 for (int i=0; i<ny; delete [] rowdata[i++]);
00283 delete [] rowdata;
00284 };
00285
00286 private:
00287 RHK_SPM32_STATUS state;
00288 };
00289
00290
00291 int write_png(gchar *file_name, raw_image *img){
00292
00293
00294
00295 mainprog_info m;
00296
00297 m.gamma = 1.;
00298 m.width = img->width();
00299 m.height = img->height();
00300 m.modtime = time(NULL);
00301 m.infile = NULL;
00302 if (! (m.outfile = fopen(file_name, "wb")))
00303 return -1;
00304 m.row_pointers = img->row_rgb_pointers();
00305 m.title = "rhkspm32topng";
00306 m.author = "A. Klust";
00307 m.desc = "RHK SPM32 data to png";
00308 m.copyright = "GPL";
00309 m.email = "klust@users.sourceforge.net";
00310 m.url = "http://gxsm.sf.net";
00311 m.have_bg = FALSE;
00312 m.have_time = FALSE;
00313 m.have_text = FALSE;
00314 m.pnmtype = 6;
00315 m.sample_depth = 8;
00316 m.interlaced= FALSE;
00317
00318 writepng_init (&m);
00319 writepng_encode_image (&m);
00320 writepng_encode_finish (&m);
00321 writepng_cleanup (&m);
00322
00323 return 0;
00324 }
00325
00326
00327
00328
00329
00330 int main(int argc, const char *argv[]) {
00331 int thumb = 1;
00332 int new_x = 0;
00333 int x_off = 0, y_off = 0, width = 0;
00334 int verbose = 0;
00335 int noquick = 0;
00336 int help = 0;
00337 gchar *filename;
00338 gchar *destinationfilename;
00339 spm32_image *img = NULL;
00340 poptContext optCon;
00341
00342 struct poptOption optionsTable[] = {
00343 {"x-offset",'x',POPT_ARG_INT,&x_off,0,"x-offset",NULL},
00344 {"y-offset",'y',POPT_ARG_INT,&y_off,0,"y-offset",NULL},
00345 {"width",'w',POPT_ARG_INT,&width,0,"width",NULL},
00346 {"size",'s',POPT_ARG_INT,&new_x,0,"Size in x-direction.",NULL},
00347 {"verbose",'v',POPT_ARG_NONE,&verbose,1,"Display information.",NULL},
00348 {"noquick",'n',POPT_ARG_NONE,&noquick,1,"No-quick",NULL},
00349 {"help",'h',POPT_ARG_NONE,&help,1,"Print help.",NULL},
00350 { NULL, 0, 0, NULL, 0 }
00351 };
00352
00353 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
00354 poptSetOtherOptionHelp(optCon, "spm32file.sm2? [outfile.png]");
00355 while (poptGetNextOpt(optCon) >= 0) {;}
00356
00357 if ((argc < 2 )||(help)) {
00358 poptPrintHelp(optCon, stderr, 0);
00359 exit(1);
00360 }
00361
00362 filename = g_strdup(poptGetArg(optCon));
00363 destinationfilename = g_strdup(poptGetArg(optCon));
00364
00365 if (destinationfilename == NULL){
00366 destinationfilename = g_strjoin(NULL, filename, ".png", NULL);
00367
00368
00369 }
00370
00371 if(verbose){
00372 if (new_x == 0)
00373 std::cout << "Thumbnail-size" << std::endl;
00374 else
00375 std::cout << "Rescaling to new x-size = " << new_x << std::endl;
00376 std::cout << "Sourcefile: " << filename << std::endl;
00377 std::cout << "Destinationfile: " << destinationfilename << std::endl;
00378 }
00379
00380 if (new_x > 0)
00381 thumb = 0;
00382
00383 if ( x_off + y_off + width > 0){
00384 if ( (x_off==0) || (y_off==0) || (width==0) ) {
00385 std::cout << "Please use -x and -y and -w together."<< std::endl;
00386 exit(-1);
00387 }
00388 if(verbose){
00389 std::cout << "Offset: " << x_off << " x " << y_off << std::endl;
00390 std::cout << "Width set to: " << width << std::endl;
00391 }
00392 }
00393
00394
00395 img = new spm32_image(filename, thumb, new_x, x_off, y_off, width);
00396
00397 switch (img->status()){
00398 case SPM32_READ_OK: break;
00399 case SPM32_OPEN_FAILED:
00400 std::cerr << "Error opening SPM32 file >" << filename << "<" << std::endl;
00401 exit(-1);
00402 break;
00403 case SPM32_FILE_NOT_VALID:
00404 std::cerr << "invalid SPM32 file >" << filename << "<" << std::endl;
00405 exit(-1);
00406 break;
00407 }
00408
00409 if (!img){
00410 std::cerr << "Error while creating image from SPM32 file." << std::endl;
00411 exit(-1);
00412 }
00413
00414 if (verbose)
00415 std::cout << "Converting ..." << std::endl;
00416
00417 if (noquick)
00418 img->quick_rgb(FALSE);
00419 else
00420 img->quick_rgb();
00421
00422 if (verbose)
00423 std::cout << "Writing >" << destinationfilename << "<" << std::endl;
00424
00425 write_png(destinationfilename, img);
00426
00427 if(verbose)
00428 std::cout << "Writing complete." << std::endl;
00429
00430 g_free(filename);
00431 g_free(destinationfilename);
00432 poptFreeContext(optCon);
00433 exit(0);
00434 }