#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include //NO WE USE g_assert for portability //#include "assert.h" #include #include "gtk-meta.h" #ifdef USE_IMLIB #include #else #include #endif #include "gdk-pixbuf-extra.h" #include "gtktopdata.h" #include "libmorph/warp.h" #include "libmorph/warp2.h" #include "libmorph/warp-gtk.h" #include "libmorph/resample.h" #include "libmorph/mesh.h" #include "mesh-gtk.h" #include "support.h" #include "utils.h" //#include "utils-mesh.h" #include "main.h" #include "settings.h" #include "interface.h" #include "dialogs.h" #include "loadsave.h" #include "utils.h" #include "feature.h" /*************************************************************** synch mesh labels ********/ /* we want the negative labels to be the highest, as if casting to unsigned */ #define MESHLABELMAP(A) (((A)<0)? 20000-(A) : (A)) #define MESHLABELDEMAP(A) (((A)>20000)? 20000-(A) : (A)) #define MAXLABEL(A,B) MESHLABELDEMAP( MAX( MESHLABELMAP(A),MESHLABELDEMAP(B))) /*************************************************************** load mesh from file */ static gboolean cmp_mesh_name(int lp,const char *file) { int l; for ( l =1; l <= MAX_WINS; l++) if( sp->im_widget[l] != NULL && sp->im_mesh_filename[l] != NULL) if( l != lp && 0==strcmp (file, sp->im_mesh_filename[l])) { gchar *s= g_strdup_printf (_("this filename is already used by the mesh of image %d") ,l); show_error(s); g_free(s); return FALSE; } return TRUE; } static inline void de_n(char *s) { int l=strlen(s); if(s[l-1]=='\n') s[l-1]=0; } gboolean load_mesh_from_file(int lp, const char * file) { FILE *fP; //int c; if(is_null(file)) return FALSE; if(!cmp_mesh_name(lp,file)) return FALSE; if((fP=fopen(file, "r"))==NULL) { showerr(file, "could not open file '%s' for read: %s"); return FALSE; } if (meshRead_stream( &(sp-> im_mesh[lp]), fP)) { show_error(_("the attempt to load mesh from file as produced an error\n(either this is not a mesh file, or the mesh file is corrupted)")); fclose(fP); return FALSE; } if(sp->im_mesh_filename[lp]) g_free(sp->im_mesh_filename[lp]); sp->im_mesh_filename[lp] = g_strdup(file); #ifdef NO_BORDER_HACK { MeshT *m =&sp->im_mesh[lp]; meshSetLabel(m,0,0,MESHPOINTSELECTED); meshSetLabel(m,0,m->ny-1,MESHPOINTSELECTED); meshSetLabel(m,m->nx-1,0,MESHPOINTSELECTED); meshSetLabel(m,m->nx-1,m->ny-1,MESHPOINTSELECTED); } #endif /* #ifdef THE_MESH_IS_NOW_FREE */ /* meshScaleFreeformat???( &(sp->im_mesh[lp]), */ /* sp->resulting_width, sp->resulting_height); */ /* #endif */ //MY_GTK_DRAW(sp-> im_widget[lp]); sp->meshes_x= MAX(sp->meshes_x, sp->im_mesh[lp].nx); sp->meshes_y= MAX(sp->meshes_y, sp->im_mesh[lp].ny); if (settings_get_value("mesh auto sync")) { int xi,yi,t=0; MeshT *this, *res; promote_meshes(); this=&(sp-> im_mesh[lp]); res=&(sp-> im_mesh[MAIN_WIN]); for(yi=0; yi < this->ny; yi++) { for(xi=0; xi < this->nx; xi++) { t+= meshGetLabel(this,xi,yi); /* this does a sort of fuzzy union */ meshSetLabel(res, xi,yi, MAXLABEL(meshGetLabel(this,xi,yi), meshGetLabel(res ,xi,yi))); }} if(t==0) { /* this is an old style mesh, with no labels: then we select all points so that they cant be smoothed */ g_message(" this mesh %s had no labels: autoselecting all point",file); for(yi=0; yi < this->ny; yi++) { for(xi=0; xi < this->nx; xi++) { meshSetLabel(this , xi,yi, -1); }}} } if(gtk_subimasel_load(&(sp-> subimasel[lp]), fP)==0) { char imagename[PATH_MAX+1]; imagename[0]=0; subimages_spinbuttons_set(lp); subimage2affines(lp); { char s[401]; s[0]=0; fgets(s,400,fP); de_n(s); if( 0==strcmp("",s)) { fgets(imagename,PATH_MAX,fP); de_n(imagename); fgets(s,400,fP); fgets(s,400,fP); de_n(s); } { if( 0==strcmp("",s)) { int old_res_w, old_res_h; fgets(s,400,fP); sscanf(s,"%d %d",&old_res_w, &old_res_h); meshScaleFreeformat( &(sp->im_mesh[lp]), sp->resulting_width/(double)old_res_w, sp->resulting_height/(double)old_res_h); } fgets(s,400,fP); fgets(s,400,fP); de_n(s); } if( 0==strcmp("",s)) { feature_load(fP); //eats the //enable this if there is another part: fgets(s,400,fP); de_n(s); } } fclose(fP);fP=NULL; if(sp-> im_filename_in[lp] && imagename[0] && 0!=strcmp(sp-> im_filename_in[lp],imagename)) { char z[601]; sprintf(z,_("this mesh was created on image '%s' and not on this image '%s'"),imagename,sp-> im_filename_in[lp]); show_warning(z); if(sp-> im_filename_in[lp] && imagename[0] ) { gchar * b1, *b2; #if GLIB_MAJOR_VERSION == 1 b1=g_basename(sp-> im_filename_in[lp]); b2=g_basename(imagename); #else b1=g_path_get_basename(sp-> im_filename_in[lp]); b2=g_path_get_basename(imagename); #endif if(b1 && b2 && 0==strcmp(b1,b2)) { set_editview( lp, EDITVIEW_EDIT); scale_loaded_pixbuf_et_rrggbb(lp);} else set_editview( lp, EDITVIEW_EYES); #if GLIB_MAJOR_VERSION >= 2 g_free(b1); g_free(b2); #endif } } else { if(sp-> subimasel[lp].orig_width != sp-> im_width[lp] || sp-> subimasel[lp].orig_height != sp->im_height[lp]) { char z[601]; sprintf(z,_("the size of the image w=%d h=%d and the size recorded in the mesh w=%d h=%d do not match"), sp-> im_width[lp],sp->im_height[lp], sp-> subimasel[lp].orig_width,sp-> subimasel[lp].orig_height); show_warning(z); set_editview( lp, EDITVIEW_EYES); } else { set_editview( lp, EDITVIEW_EDIT); scale_loaded_pixbuf_et_rrggbb(lp); } } } else show_warning("could not read subimage information from this file."); return TRUE; } /****************************************************************/ gboolean save_mesh_to_file(int lp, const char * file) { FILE *fP; /* int c; */ /* c=strlen(file); */ /* /\* delete the common initial part of cwd and filename *\/ */ /* #define REDUCE__(A) ((0==strncmp(A,file,c)) ? (A)+c:(A)) */ if(is_null(file)) return FALSE; if(lp==MAIN_WIN && settings_get_value("automatic mesh interpolation")) { if((fP=fopen(file, "r"))!=NULL) { show_error(_("This mesh is automatically generated. You don't want to overwrite another mesh with this one!")); fclose(fP); return FALSE; } } if(!cmp_mesh_name(lp,file)) return FALSE; if((fP=fopen(file, "w"))==NULL) { showerr(file, "could not open file '%s' for write: %s"); return FALSE; } { //MeshT copy; meshInit(©); meshCopy(©, &(sp-> im_mesh[lp])) ; //meshScaleFreeformat(copy,?????); if (meshWrite_stream( &(sp-> im_mesh[lp]) , fP) ==0) { if(sp->im_mesh_filename[lp]) g_free(sp->im_mesh_filename[lp]); sp->im_mesh_filename[lp] = g_strdup(file); sp-> subimasel[lp].orig_width = sp-> im_width[lp]; sp-> subimasel[lp].orig_height = sp->im_height[lp]; gtk_subimasel_save(&(sp-> subimasel[lp]), fP); if(sp->im_filename_in[lp]) fprintf(fP,"\n%s\n\n", (sp->im_filename_in[lp])); fprintf(fP,"\n%d %d\n\n", sp->resulting_width, sp->resulting_height); fprintf(fP,"\n"); feature_save(fP); fprintf(fP,"\n"); } else { char *s = g_strdup_printf("\ the attempt to save the mesh in file %s as produced an internal error", file); show_error(s); g_free(s); fclose(fP); //meshUnref(©); return FALSE; } //meshUnref(©); } fclose(fP); return TRUE; } gboolean save_diff_mesh_to_file(int lp, const char * file) { if(is_null(file)) return FALSE; FILE *fP; if((fP=fopen(file, "w"))==NULL) { showerr(file, "could not open file '%s' for write: %s"); return FALSE; } MeshT * mesh = sp->im_mesh_diff[lp], *base_mesh = &(sp->im_mesh[lp]); g_return_val_if_fail(mesh,FALSE); const int nx=mesh->nx, ny=mesh->ny ; g_return_val_if_fail( nx==base_mesh->nx && ny==base_mesh->ny,FALSE); MeshT copy; meshInit(©); meshAlloc(©,nx,ny); {int xi, yi; for(xi=0; xi < nx; xi++) { for(yi=0; yi < ny; yi++) { meshSetNoundo(©, xi,yi, meshGetx(mesh,xi,yi)-meshGetx(base_mesh,xi,yi), meshGety(mesh,xi,yi)-meshGety(base_mesh,xi,yi)); meshSetLabel(©, xi,yi,meshGetLabel(mesh,xi,yi)); }}} if (meshWrite_stream( © , fP) ==0) { fclose(fP); meshUnref(©); } else { char *s = g_strdup_printf("\ the attempt to save the differential mesh in file %s as produced an internal error", file); show_error(s); g_free(s); fclose(fP); meshUnref(©); return FALSE; } return TRUE; } gboolean load_diff_from_file(int lp, const char * file) { if(!cmp_mesh_name(lp,file)) return FALSE; FILE *fP; if((fP=fopen(file, "r"))==NULL) { showerr(file, "could not open file '%s' for read: %s"); return FALSE; } if (meshRead_stream( &(sp-> im_mesh[lp]), fP)) { show_error(_("the attempt to load mesh from file as produced an error\n(either this is not a mesh file, or the mesh file is corrupted)")); fclose(fP); return FALSE; } fclose(fP); if(sp->im_mesh_filename[lp]) g_free(sp->im_mesh_filename[lp]); sp->im_mesh_filename[lp] = g_strdup(file); /* we set this before, otherwise the "factor_normalize" goes berseker */ sp->max_wins++; GtkWidget *window=sp->im_widget[lp]=create_diff_window(); gtk_widget_set_data_top(window,"imagenum", GUINT_TO_POINTER(lp)); sp->mf.im_warp_factor[lp]=0; sp->mf.im_dissolve_factor[lp]=0; sp->im_drawingarea_widget[lp] = NULL; sp->im_widget_is_difference_mesh[lp]=TRUE; { gchar * N=compute_title (lp); gtk_window_set_title (GTK_WINDOW(sp->im_widget[lp]),N); g_free(N); } gtk_widget_show(window); return TRUE; } gboolean load_image_from_file_not_ply(int lp, const char *file) { GdkPixbuf *impixfile; #if GTK_MAJOR_VERSION < 2 impixfile= gdk_pixbuf_new_from_file(file); if (impixfile ==NULL) { showerr(file,_("\ the attempt to load the image file %s as produced error: %s")); return FALSE; } #else { GError *err=NULL; impixfile= gdk_pixbuf_new_from_file(file,&err); if(err) { show_error((err)->message);g_error_free (err); return FALSE; } } #endif { sp->im_width[lp]= gdk_pixbuf_get_width(impixfile); sp->im_height[lp]= gdk_pixbuf_get_height(impixfile); gtk_subimasel_reset( &(sp->subimasel[lp]) , sp->im_width[lp], sp->im_height[lp]); #ifndef RESCALE_RELOAD_LESS_MEM destroy_pixbuf(lp,PIXLOADED ); #endif destroy_pixmap(lp,PIXLOADED ); subimages_spinbuttons_set(lp); subimage2affines(lp); sp->im_loaded_pixbuf[lp]=impixfile; create__pixmap(lp,PIXLOADED ); render_pixmap(lp, PIXLOADED); scale_loaded_pixbuf_et_rrggbb(lp); render_pixmap(lp, PIXSUBIMAGE); //FIXME do we do this here? //render_pixmap(lp, PIXWARPED); #ifdef RESCALE_RELOAD_LESS_MEM destroy_pixbuf(lp,PIXLOADED ); impixfile=NULL; #endif if(sp->im_filename_in[lp]!=NULL) g_free(sp->im_filename_in[lp]); sp->im_filename_in[lp]=g_strdup(file); { gchar * N = compute_title (lp); gtk_window_set_title ( GTK_WINDOW(sp->im_widget[lp]), N); g_free(N); } set_editview( lp, EDITVIEW_EYES); drawingarea_configure(lp); MY_GTK_DRAW( sp-> im_widget[lp]); return TRUE; } } gboolean load_image_from_file(int lp, const char *file) { int len=strlen(file); g_assert(lp>0); if (strcmp(file+len-4,".ply")) return load_image_from_file_not_ply(lp,file); else { #if HAVE_LIBPLY_H if(!read_ply_) { show_error(_("gtkmorph could not find libply, so it cannot load PLY surfaces. Read documentations to install libply.")); return FALSE; } if(!read_ply_(file,&sp->im_ply_surface[lp])) { showerr(file,_("error while loading PLY file")); return FALSE; } return TRUE; #else show_error(_("gtkmorph was NOT compiled with PLY support")); return FALSE; #endif } } gboolean save_image_to_file(int lp, const char *file) { GdkPixbuf * pb=*(which_pixbuf_is_visible(lp)); if(sp->im_filename_out[lp] == NULL || 0!=strcmp(sp->im_filename_out[lp],file)) { if( g_file_test(file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR )) { showerr(file,_("\ This file already exists! If you really want to overwrite it, delete it.")); return FALSE; } } gboolean result= save_pixbuf_to_file(file,pb); if(result) sp->im_filename_out[lp]=g_strdup(file); return result; } /* reloads image , if necessary, and rescales it */ void reload_and_scale_image(int i) { GdkPixbuf **impixfile = which_pixbuf(i,PIXLOADED); g_assert(i > 0); if(*impixfile == NULL) { #ifndef RESCALE_RELOAD_LESS_MEM g_warning("lost original pixbuf %d... why???\n try reloading\n",i); #endif if ( sp-> im_filename_in[i] == NULL || strlen( sp-> im_filename_in[i]) == 0) { show_error ( g_strdup_printf(_("can't resize %dth image-no filename"),i)); return; } /* reload */ #if GTK_MAJOR_VERSION < 2 *impixfile= gdk_pixbuf_new_from_file(sp-> im_filename_in[i]); #else { GError *err=NULL; *impixfile= gdk_pixbuf_new_from_file(sp-> im_filename_in[i],&err); //FIXME should use err } #endif if (*impixfile ==NULL) { showerr(sp-> im_filename_in[i], _("the attempt to reload the image file %s to resize it as produced error: %s")); create__pixbuf(i, PIXLOADED); return; } } #ifdef RESCALE_RELOAD_LESS_MEM else { g_warning("the original pixbuf %d was not deallocated, reusing it\n",i); //FIXME why?? gdk_pixbuf_ref(*impixfile); } #endif g_assert(*impixfile); g_assert(&(sp->im_loaded_pixbuf[i])==impixfile); render_pixmap(i, PIXLOADED); scale_loaded_pixbuf_et_rrggbb(i); render_pixmap(i, PIXSUBIMAGE); #ifdef RESCALE_RELOAD_LESS_MEM delete_pixbuf(i, PIXLOADED); #endif }