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 #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
00044
00045
00046
00047
00048
00049
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
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;
00085 Xmin = nx/10;
00086 istep = 1;
00087 for (i=Xmin; i < Xmax; i+=istep) {
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
00105
00106
00107
00108
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
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
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;
00156 int x0, y0, w0;
00157 int onx, ony;
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
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
00202
00203 if (strncmp (line, "DATA", 4) == 0)
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
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){
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;
00239 if (y0+ny >= ony) y0=0;
00240
00241
00242
00243 rowdata = new double* [ny];
00244 for (int i=0; i<ny; rowdata[i++] = new double [nx]);
00245
00246
00247
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
00288
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;
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
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) {;}
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
00363
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
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 }