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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include <gtk/gtk.h>
00065 #include "config.h"
00066 #include "gxsm/plugin.h"
00067 #include "gxsm/dataio.h"
00068 #include "gxsm/action_id.h"
00069 #include "gxsm/util.h"
00070 #include "gxsm/xsmtypes.h"
00071 #include "gxsm/glbvars.h"
00072
00073
00074
00075 #include "png.h"
00076 #include "readpng.h"
00077 #include "writepng.h"
00078
00079
00080
00081 using namespace std;
00082
00083
00084 static void png_im_export_init (void);
00085 static void png_im_export_query (void);
00086 static void png_im_export_about (void);
00087 static void png_im_export_configure (void);
00088 static void png_im_export_cleanup (void);
00089
00090 static void png_im_export_filecheck_load_callback (gpointer data );
00091 static void png_im_export_filecheck_save_callback (gpointer data );
00092
00093 static void png_im_export_import_callback (GtkWidget *w, void *data);
00094 static void png_im_export_export_callback (GtkWidget *w, void *data);
00095
00096
00097 GxsmPlugin png_im_export_pi = {
00098 NULL,
00099 NULL,
00100 0,
00101 NULL,
00102
00103
00104
00105 "PNG-ImExport",
00106 NULL,
00107
00108 "Im/Export PNG images.",
00109 "Percy Zahl",
00110 N_("_File/_Import/,_File/_Export/"),
00111 N_("PNG,PNG"),
00112 N_("PNG import,PNG export"),
00113 N_("PNG import and export filter."),
00114
00115 NULL,
00116 NULL,
00117 png_im_export_init,
00118 png_im_export_query,
00119
00120
00121 png_im_export_about,
00122
00123
00124 png_im_export_configure,
00125
00126
00127 NULL,
00128
00129
00130 png_im_export_cleanup
00131 };
00132
00133
00134 static const char *about_text = N_("This GXSM plugin allows im- and export of PNG image data files");
00135
00136 static const char *file_mask = "*.png";
00137
00138
00139
00140 GxsmPlugin *get_gxsm_plugin_info ( void ){
00141 png_im_export_pi.description = g_strdup_printf(N_("Gxsm im_export plugin %s"), VERSION);
00142 return &png_im_export_pi;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 static void png_im_export_query(void)
00152 {
00153 gchar **path = g_strsplit (png_im_export_pi.menupath, ",", 2);
00154 gchar **entry = g_strsplit (png_im_export_pi.menuentry, ",", 2);
00155 gchar **help = g_strsplit (png_im_export_pi.help, ",", 2);
00156
00157 static GnomeUIInfo menuinfo_i[] = {
00158 { GNOME_APP_UI_ITEM, NULL, NULL,
00159 NULL, NULL,
00160 NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN,
00161 0, GDK_CONTROL_MASK, NULL },
00162 GNOMEUIINFO_END
00163 };
00164 menuinfo_i[0].label = entry[0];
00165 menuinfo_i[0].hint = help[0];
00166 menuinfo_i[0].moreinfo = (gpointer) png_im_export_import_callback;
00167 menuinfo_i[0].user_data = png_im_export_pi.name;
00168
00169 gnome_app_insert_menus (
00170 GNOME_APP(png_im_export_pi.app->getApp()),
00171 path[0],
00172 menuinfo_i
00173 );
00174
00175
00176 static GnomeUIInfo menuinfo_e[] = {
00177 { GNOME_APP_UI_ITEM, NULL, NULL,
00178 NULL, NULL,
00179 NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE,
00180 0, GDK_CONTROL_MASK, NULL },
00181 GNOMEUIINFO_END
00182 };
00183 menuinfo_e[0].label = entry[1];
00184 menuinfo_e[0].hint = help[1];
00185 menuinfo_e[0].moreinfo = (gpointer) png_im_export_export_callback;
00186 menuinfo_e[0].user_data = png_im_export_pi.name;
00187
00188 gnome_app_insert_menus (
00189 GNOME_APP(png_im_export_pi.app->getApp()),
00190 path[1],
00191 menuinfo_e
00192 );
00193
00194 if(png_im_export_pi.status) g_free(png_im_export_pi.status);
00195 png_im_export_pi.status = g_strconcat (
00196 N_("Plugin query has attached "),
00197 png_im_export_pi.name,
00198 N_(": File IO Filters are ready to use."),
00199 NULL);
00200
00201
00202 g_strfreev (path);
00203 g_strfreev (entry);
00204 g_strfreev (help);
00205
00206
00207
00208
00209 png_im_export_pi.app->ConnectPluginToLoadFileEvent (png_im_export_filecheck_load_callback);
00210 png_im_export_pi.app->ConnectPluginToSaveFileEvent (png_im_export_filecheck_save_callback);
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220 static void png_im_export_init(void)
00221 {
00222 PI_DEBUG (DBG_L2, png_im_export_pi.name << " Plugin Init");
00223 }
00224
00225
00226 static void png_im_export_about(void)
00227 {
00228 const gchar *authors[] = { png_im_export_pi.authors, NULL};
00229 gtk_widget_show(gnome_about_new ( png_im_export_pi.name,
00230 VERSION,
00231 N_("(C) 2001 the Free Software Foundation"),
00232 about_text,
00233 authors,
00234 NULL, NULL, NULL
00235 ));
00236 }
00237
00238
00239 static void png_im_export_configure(void)
00240 {
00241 if(png_im_export_pi.app)
00242 png_im_export_pi.app->message("PNG im_export Plugin Configuration");
00243 }
00244
00245
00246 static void png_im_export_cleanup(void)
00247 {
00248 gchar **path = g_strsplit (png_im_export_pi.menupath, ",", 2);
00249 gchar **entry = g_strsplit (png_im_export_pi.menuentry, ",", 2);
00250
00251 gchar *tmp = g_strconcat (path[0], entry[0], NULL);
00252 gnome_app_remove_menus (GNOME_APP (png_im_export_pi.app->getApp()), tmp, 1);
00253 g_free (tmp);
00254
00255 tmp = g_strconcat (path[1], entry[1], NULL);
00256 gnome_app_remove_menus (GNOME_APP (png_im_export_pi.app->getApp()), tmp, 1);
00257 g_free (tmp);
00258
00259 g_strfreev (path);
00260 g_strfreev (entry);
00261
00262 PI_DEBUG (DBG_L2, "Plugin Cleanup done.");
00263 }
00264
00265
00266
00267 class PNG_ImExportFile : public Dataio{
00268 public:
00269 PNG_ImExportFile(Scan *s, const char *n) : Dataio(s,n){; };
00270 virtual FIO_STATUS Read();
00271 virtual FIO_STATUS Write();
00272 private:
00273 FIO_STATUS import_data(const char *fname);
00274 };
00275
00276 FIO_STATUS PNG_ImExportFile::Read(){
00277 FIO_STATUS ret;
00278 gchar *fname=NULL;
00279
00280 PI_DEBUG (DBG_L2, "reading");
00281
00282 fname = (gchar*)name;
00283
00284
00285 if (fname == NULL || strlen(fname) < 4)
00286 return status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
00287
00288 if (strncasecmp(fname+strlen(fname)-4,".png",4)){
00289 return status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
00290 }
00291
00292
00293
00294 ifstream f;
00295 f.open(fname, ios::in);
00296 if(!f.good()){
00297 PI_DEBUG (DBG_L2, "Error at file open. File not good/readable.");
00298 return status=FIO_OPEN_ERR;
00299 }
00300 f.close();
00301
00302
00303 if ((ret=import_data (fname)) != FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
00304 return ret;
00305
00306 return status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
00307 }
00308
00309 FIO_STATUS PNG_ImExportFile::import_data(const char *fname){
00310 FILE *infile;
00311 double display_exponent;
00312 ulg image_width, image_height, image_rowbytes;
00313 int image_channels;
00314 int rc;
00315
00316 gboolean byteswap = FALSE;
00317
00318
00319
00320 ifstream f;
00321 GString *FileList=NULL;
00322
00323 cout << "PNG::: importing from >" << fname << "<" << endl;
00324 PI_DEBUG (DBG_L2, "importing from >" << fname << "<");
00325
00326 if (!(infile = fopen(fname, "rb")))
00327 return status=FIO_OPEN_ERR;
00328
00329 cout << "PNG::: reset to defaults" << endl;
00330
00331
00332 SCAN_DATA scan_template;
00333
00334 scan->data.GetScan_Param (scan_template);
00335
00336 scan->data.GetUser_Info (scan_template);
00337
00338 scan->data.GetDisplay_Param (scan_template);
00339
00340 cout << "PNG::: readpng" << endl;
00341
00342 if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
00343 gchar *error_msg = NULL;
00344 switch (rc) {
00345 case 1:
00346 PI_DEBUG (DBG_L2, "[" << fname << "] is not a PNG file: incorrect signature");
00347 error_msg = g_strdup_printf (N_("[%s] is not a PNG file: incorrect signature"),
00348 fname);
00349 break;
00350 case 2:
00351 PI_DEBUG (DBG_L2, "[" << fname << "] has bad IHDR (libpng longjmp)");
00352 error_msg = g_strdup_printf (N_("[%s] has bad IHDR (libpng longjmp)"),
00353 fname);
00354 break;
00355 case 4:
00356 PI_DEBUG (DBG_L2, "insufficient memory");
00357 error_msg = g_strdup_printf (N_("insufficient memory"));
00358 break;
00359 default:
00360 PI_DEBUG (DBG_L2, "unknown readpng_init() error");
00361 error_msg = g_strdup_printf (N_("unknown readpng_init() error"));
00362 break;
00363 }
00364
00365 cout << error_msg << endl;
00366
00367 if (error_msg && (rc > 1 || strstr (fname, ".png"))){
00368 GtkWidget *dialog = gtk_message_dialog_new (NULL,
00369 GTK_DIALOG_DESTROY_WITH_PARENT,
00370 GTK_MESSAGE_INFO,
00371 GTK_BUTTONS_OK,
00372 error_msg);
00373 gtk_dialog_run (GTK_DIALOG (dialog));
00374 g_signal_connect_swapped (GTK_OBJECT (dialog), "response",
00375 G_CALLBACK (gtk_widget_destroy),
00376 GTK_OBJECT (dialog));
00377 }
00378 g_free (error_msg);
00379 fclose (infile);
00380 return FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
00381 }
00382
00383
00384 time_t t;
00385 time(&t);
00386 gchar *tmp = g_strconcat ((ctime(&t)), " (Imported)", NULL); scan->data.ui.SetDateOfScan (tmp); g_free (tmp);
00387 scan->data.ui.SetName (name);
00388 scan->data.ui.SetOriginalName (name);
00389 scan->data.ui.SetType ("PNG color image");
00390 scan->data.ui.SetUser ("nobody");
00391
00392 FileList = g_string_new ("Imported by GXSM from PNG.\n");
00393 g_string_sprintfa (FileList, "Original Filename: %s\n", name);
00394 g_string_append (FileList, "blaaa:\n");
00395 scan->data.ui.SetComment (FileList->str);
00396 g_string_free(FileList, TRUE);
00397 FileList=NULL;
00398
00399
00400 XsmRescourceManager xrm("PNG_IM_EXPORT");
00401 xrm.Get ("AngPerPixelX", &scan->data.s.dx, "1.0"),
00402 xrm.Get ("AngPerPixelY", &scan->data.s.dy, "1.0"),
00403
00404 scan->data.s.ntimes = 1;
00405 scan->data.s.nvalues = 4;
00406 scan->data.s.nx = image_width;
00407 scan->data.s.ny = image_height;
00408
00409
00410 scan->data.s.dz = 1;
00411 scan->data.s.rx = scan->data.s.nx*scan->data.s.dx;
00412 scan->data.s.ry = scan->data.s.ny*scan->data.s.dy;
00413 scan->data.s.rz = 256.0;
00414 scan->data.s.x0 = 0;
00415 scan->data.s.y0 = 0;
00416 scan->data.s.alpha = 0.;
00417 scan->data.display.bright = 0.;
00418 scan->data.display.vrange_z = 256.;
00419 scan->data.display.voffset_z = 0.;
00420
00421 scan->mem2d->Resize (scan->data.s.nx, scan->data.s.ny, ZD_RGBA);
00422
00423 scan->data.orgmode = SCAN_ORG_CENTER;
00424 scan->mem2d->data->MkXLookup (-scan->data.s.rx/2., scan->data.s.rx/2.);
00425 scan->mem2d->data->MkYLookup (-scan->data.s.ry/2., scan->data.s.ry/2.);
00426
00427 uch *image_data = readpng_get_image(display_exponent, &image_channels, &image_rowbytes);
00428
00429 uch *src;
00430 ulg lastrow, row;
00431 uch r, g, b, a;
00432 ulg red, green, blue;
00433
00434 for (lastrow = row = 0; row < image_height; ++row) {
00435 src = image_data + row*image_rowbytes;
00436 if (image_channels == 3) {
00437 for (int i = 0; i < image_width; ++i) {
00438 red = *src++;
00439 green = *src++;
00440 blue = *src++;
00441 scan->mem2d->PutDataPkt ((double)red, i, row, 0);
00442 scan->mem2d->PutDataPkt ((double)green, i, row, 1);
00443 scan->mem2d->PutDataPkt ((double)blue, i, row, 2);
00444 scan->mem2d->PutDataPkt (0., i, row, 3);
00445 }
00446 } else {
00447 for (int i = 0; i < image_width; ++i) {
00448 r = *src++;
00449 g = *src++;
00450 b = *src++;
00451 a = *src++;
00452 scan->mem2d->PutDataPkt ((double)r, i, row, 0);
00453 scan->mem2d->PutDataPkt ((double)g, i, row, 1);
00454 scan->mem2d->PutDataPkt ((double)b, i, row, 2);
00455 scan->mem2d->PutDataPkt ((double)a, i, row, 3);
00456
00457
00458
00459 }
00460 }
00461 }
00462 readpng_cleanup(TRUE);
00463 fclose(infile);
00464 return status=FIO_OK;
00465 }
00466
00467 FIO_STATUS PNG_ImExportFile::Write(){
00468 int pcnt=0;
00469 mainprog_info m;
00470 unsigned char **rgb;
00471
00472 PI_DEBUG (DBG_L2, "writing >" << name << "<");
00473
00474 if (name == NULL) return FIO_NO_NAME;
00475
00476 m.gamma = 1.;
00477 m.width = scan->data.s.nx;
00478 m.height = scan->data.s.ny;
00479 m.modtime = time(NULL);
00480 m.infile = NULL;
00481 if (! (m.outfile = fopen(name, "wb")))
00482 return status=FIO_OPEN_ERR;
00483
00484 rgb = new unsigned char* [m.height];
00485 for (int i=0; i<m.height; rgb[i++] = new unsigned char[3*m.width]);
00486
00487
00488
00489 if (scan->mem2d->GetNv() == 4){
00490 int k,j;
00491 for (int i=0; i<m.height; ++i)
00492 for (k=j=0; j<m.width; ++j){
00493 *(rgb[i] + k++) = (unsigned char)scan->mem2d->GetDataPkt (j, i, 0);
00494 *(rgb[i] + k++) = (unsigned char)scan->mem2d->GetDataPkt (j, i, 1);
00495 *(rgb[i] + k++) = (unsigned char)scan->mem2d->GetDataPkt (j, i, 2);
00496 }
00497 }else{
00498
00499 int k,j;
00500 int cval;
00501 ifstream cpal;
00502 char pline[256];
00503 int r,g,b,nx,ny;
00504 double val;
00505 int ival;
00506 int maxcol=1024;
00507 unsigned char tgapal[1024][3];
00508
00509 if (gapp->xsm->ZoomFlg & VIEW_PALETTE){
00510 cpal.open(xsmres.Palette, ios::in);
00511 PI_DEBUG (DBG_L2, "Using Palette: " << xsmres.Palette );
00512 if(cpal.good()){
00513 cpal.getline(pline, 255);
00514 cpal.getline(pline, 255);
00515 cpal >> nx >> ny;
00516 cpal.getline(pline, 255);
00517 cpal.getline(pline, 255);
00518
00519 for(maxcol=min(nx, 1024), cval=0; cval<maxcol; ++cval){
00520 cpal >> r >> g >> b ;
00521 tgapal[cval][0] = r;
00522 tgapal[cval][1] = g;
00523 tgapal[cval][2] = b;
00524 }
00525 cpal.close();
00526 } else {
00527 PI_DEBUG (DBG_L2, "Using Palette failed, fallback to greyscale!" );
00528 for (maxcol=256, cval=0; cval<maxcol; ++cval)
00529 tgapal[cval][2] = tgapal[cval][1] = tgapal[cval][0] = cval * 255 / maxcol;
00530 }
00531 }else{
00532 PI_DEBUG (DBG_L2, "Using greyscale palette!" );
00533 for (maxcol=256, cval=0; cval<maxcol; ++cval)
00534 tgapal[cval][2] = tgapal[cval][1] = tgapal[cval][0] = cval * 255 / maxcol;
00535 }
00536 PI_DEBUG (DBG_L2, "MaxCol#: " << maxcol );
00537 PI_DEBUG (DBG_L2, "VFlg: " << scan->data.display.ViewFlg );
00538
00539
00540
00541 scan->mem2d->SetDataRange(0, maxcol);
00542 scan->mem2d->AutoDataSkl(NULL, NULL);
00543
00544
00545 for (int i=0; i<m.height; ++i)
00546 for (k=j=0; j<m.width; ++j){
00547 val = scan->mem2d->GetDataVMode (j,i);
00548 ival = (int)((val >= maxcol ? maxcol-1 : val < 0 ? 0 : val) + .5);
00549
00550 *(rgb[i] + k++) = (unsigned char)tgapal[ival][0];
00551 *(rgb[i] + k++) = (unsigned char)tgapal[ival][1];
00552 *(rgb[i] + k++) = (unsigned char)tgapal[ival][2];
00553 }
00554 }
00555
00556 m.row_pointers = rgb;
00557 m.title = "GXSM-PNG-ImExport-PlugIn";
00558 m.author = "Percy Zahl";
00559 m.desc = "GXSM PNG export";
00560 m.copyright = "GPL";
00561 m.email = "zahl@users.sourceforge.net";
00562 m.url = "http://gxsm.sf.net";
00563 m.have_bg = FALSE;
00564 m.have_time = FALSE;
00565 m.have_text = FALSE;
00566 m.pnmtype = 6;
00567 m.sample_depth = 8;
00568 m.interlaced= FALSE;
00569
00570 writepng_init (&m);
00571 writepng_encode_image (&m);
00572 writepng_encode_finish (&m);
00573 writepng_cleanup (&m);
00574 fclose (m.outfile);
00575
00576 for (int i=0; i<m.height; delete[] rgb[i++]);
00577 delete[] rgb;
00578
00579
00580 return status=FIO_OK;
00581 }
00582
00583
00584
00585
00586
00587
00588 static void png_im_export_filecheck_load_callback (gpointer data ){
00589 gchar **fn = (gchar**)data;
00590 if (*fn){
00591 PI_DEBUG (DBG_L2, "checking >" << *fn << "<" );
00592
00593 Scan *dst = gapp->xsm->GetActiveScan();
00594 if(!dst){
00595 gapp->xsm->ActivateFreeChannel();
00596 dst = gapp->xsm->GetActiveScan();
00597 }
00598 PNG_ImExportFile fileobj (dst, *fn);
00599
00600 FIO_STATUS ret = fileobj.Read();
00601 if (ret != FIO_OK){
00602
00603 if (ret != FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
00604 *fn=NULL;
00605
00606 gapp->xsm->SetMode(-1, ID_CH_M_OFF, TRUE);
00607 PI_DEBUG (DBG_L2, "Read Error " << ((int)ret) );
00608 }else{
00609
00610 *fn=NULL;
00611
00612
00613 gapp->xsm->ActiveScan->GetDataSet(gapp->xsm->data);
00614 gapp->spm_update_all();
00615 dst->draw();
00616 }
00617 }else{
00618 PI_DEBUG (DBG_L2, "Skipping" << *fn << "<" );
00619 }
00620 }
00621
00622 static void png_im_export_filecheck_save_callback (gpointer data ){
00623 gchar **fn = (gchar**)data;
00624 if (*fn){
00625 Scan *src;
00626 PI_DEBUG (DBG_L2, "Saving/(checking) >" << *fn << "<" );
00627
00628 PNG_ImExportFile fileobj (src = gapp->xsm->GetActiveScan(), *fn);
00629
00630 FIO_STATUS ret;
00631 ret = fileobj.Write();
00632
00633 if(ret != FIO_OK){
00634
00635 if (ret != FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
00636 *fn=NULL;
00637 PI_DEBUG (DBG_L2, "Write Error " << ((int)ret) );
00638 }else{
00639
00640 *fn=NULL;
00641 }
00642 }else{
00643 PI_DEBUG (DBG_L2, "Skipping >" << *fn << "<" );
00644 }
00645 }
00646
00647
00648
00649 static void png_im_export_import_callback(GtkWidget *w, void *data){
00650 gchar **help = g_strsplit (png_im_export_pi.help, ",", 2);
00651 gchar *dlgid = g_strconcat (png_im_export_pi.name, "-import", NULL);
00652 gchar *fn = gapp->file_dialog (help[0], NULL, file_mask, NULL, dlgid);
00653 g_strfreev (help);
00654 g_free (dlgid);
00655 png_im_export_filecheck_load_callback (&fn );
00656 }
00657
00658 static void png_im_export_export_callback(GtkWidget *w, void *data){
00659 gchar **help = g_strsplit (png_im_export_pi.help, ",", 2);
00660 gchar *dlgid = g_strconcat (png_im_export_pi.name, "-export", NULL);
00661 gchar *fn = gapp->file_dialog(help[1], NULL, file_mask, NULL, dlgid);
00662 g_strfreev (help);
00663 g_free (dlgid);
00664 png_im_export_filecheck_save_callback (&fn );
00665 }