00001
00002
00003
00004
00005 #include "mrilib.h"
00006 #include "imseq.h"
00007
00008
00009
00010 typedef struct {
00011 MCW_imseq *seq ;
00012 MRI_IMARR *imar ;
00013 int rgb_count ;
00014 generic_func *kill_func ;
00015 void *kill_data ;
00016 } AIVVVV_imseq ;
00017
00018 static AIVVVV_imseq *psq_global ;
00019 static XtAppContext AIVVV_appcontext ;
00020
00021 static NI_stream AIVVV_stream = (NI_stream)NULL ;
00022 static char AIVVV_strnam[64] ;
00023 static int AIVVV_have_dummy = 0 ;
00024
00025 static void * AIVVV_imseq_popup( MRI_IMARR *, generic_func *, void * ) ;
00026 static void AIVVV_imseq_retitle( void * , char * ) ;
00027 static XtPointer AIVVV_imseq_getim( int , int , XtPointer ) ;
00028 static void AIVVV_imseq_send_CB( MCW_imseq * , XtPointer , ISQ_cbs * ) ;
00029 static void AIVVV_imseq_addto( MRI_IMAGE *im ) ;
00030 static Boolean AIVVV_workproc( XtPointer ) ;
00031 static void AIVVV_niml_quitter( char *, NI_stream , NI_element * ) ;
00032
00033
00034
00035 static char *FALLback[] =
00036 { "AFNI*fontList: 9x15bold=charset1" ,
00037 "AFNI*pbar*fontList: 6x10=charset1" ,
00038 "AFNI*imseq*fontList: 7x13=charset1" ,
00039 "AFNI*background: gray20" ,
00040 "AFNI*menu*background: gray10" ,
00041 "AFNI*borderColor: gray20" ,
00042 "AFNI*foreground: yellow" ,
00043 "AFNI*borderWidth: 0" ,
00044 "AFNI*troughColor: blue" ,
00045 "AFNI*XmLabel.translations: #override<Btn2Down>:" ,
00046 "AFNI*help*background: black" ,
00047 "AFNI*help*foreground: yellow" ,
00048 "AFNI*help*helpborder: False" ,
00049 "AFNI*help*waitPeriod: 1066" ,
00050 "AFNI*help*fontList: 9x15bold=charset1" ,
00051 "AFNI*cluefont: 9x15bold" ,
00052 "AFNI*help*cancelWaitPeriod: 50" ,
00053 NULL } ;
00054
00055 static MCW_DC *MAIN_dc ;
00056 static XtAppContext MAIN_app ;
00057 static MRI_IMARR *MAIN_imar ;
00058
00059 #define DEFAULT_NCOLOVR 20
00060
00061 static char *INIT_colovr[DEFAULT_NCOLOVR] = {
00062 "#ffff00" , "#ffcc00" , "#ff9900" , "#ff6900" , "#ff4400" , "#ff0000" ,
00063 "#0000ff" , "#0044ff" , "#0069ff" , "#0099ff" , "#00ccff" , "#00ffff" ,
00064 "green" , "limegreen" , "violet" , "hotpink" ,
00065 "white" , "#dddddd" , "#bbbbbb" , "black"
00066 } ;
00067
00068 static char *INIT_labovr[DEFAULT_NCOLOVR] = {
00069 "yellow" , "yell-oran" , "oran-yell" , "orange" , "oran-red" , "red" ,
00070 "dk-blue", "blue" , "lt-blue1" , "lt-blue2" , "blue-cyan", "cyan" ,
00071 "green" , "limegreen" , "violet" , "hotpink" ,
00072 "white" , "gry-dd" , "gry-bb" , "black"
00073 } ;
00074
00075
00076
00077 static void killer( void *pt ){ exit(0); }
00078 static void AFNI_handler(char *msg){ return ; }
00079
00080
00081
00082
00083 static void timeout_CB( XtPointer client_data , XtIntervalId *id )
00084 {
00085 ENTRY("timeout_CB") ;
00086 (void) AIVVV_imseq_popup( MAIN_imar , killer , NULL ) ;
00087 if( AIVVV_stream != (NI_stream)NULL ){
00088 XtAppAddWorkProc( AIVVV_appcontext, AIVVV_workproc, NULL ) ;
00089 NI_register_doer( "QUIT" , AIVVV_niml_quitter ) ;
00090 NI_register_doer( "EXIT" , AIVVV_niml_quitter ) ;
00091 }
00092 EXRETURN ;
00093 }
00094
00095
00096
00097 int main( int argc , char *argv[] )
00098 {
00099 int ii , verb=0 , iarg=1 , jj ;
00100 MRI_IMAGE *im ;
00101 MRI_IMARR *qar ;
00102 Widget shell ;
00103 int gnim ; char **gname=NULL ;
00104
00105 if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
00106 printf(
00107 "Usage: aiv [-v] [-p xxxx ] image ...\n"
00108 "AFNI Image Viewer program.\n"
00109 "Shows the 2D images on the command line in an AFNI-like image viewer.\n"
00110 "Can also read images in NIML '<MRI_IMAGE...>' format from a TCP/IP socket.\n"
00111 "Image file formats are those supported by to3d:\n"
00112 " * various MRI formats (e.g., DICOM, GEMS I.xxx)\n"
00113 " * raw PPM or PGM\n"
00114 " * JPEG (if djpeg is in the path)\n"
00115 " * GIF, TIFF, BMP, and PNG (if netpbm is in the path)\n"
00116 "\n"
00117 "The '-v' option will make aiv print out the image filenames\n"
00118 "as it reads them - this can be a useful progress meter if\n"
00119 "the program starts up slowly.\n"
00120 "\n"
00121 "The '-p xxxx' option will make aiv listen to TCP/IP port 'xxxx'\n"
00122 "for incoming images in the NIML '<MRI_IMAGE...>' format. The\n"
00123 "port number must be between 1024 and 65535, inclusive. For\n"
00124 "conversion to NIML '<MRI_IMAGE...>' format, see program im2niml.\n"
00125 "\n"
00126 "Normally, at least one image must be given on the command line.\n"
00127 "If the '-p xxxx' option is used, then you don't have to input\n"
00128 "any images this way; however, since the program requires at least\n"
00129 "one image to start up, a crude 'X' will be displayed. When the\n"
00130 "first image arrives via the socket, the 'X' image will be replaced.\n"
00131 "Subsequent images arriving by socket will be added to the sequence.\n"
00132 "\n-----------------------------------------------------------------\n"
00133 "Sample program fragment, for sending images from one program\n"
00134 "into a copy of aiv (which that program also starts up):\n"
00135 "\n"
00136 "#include \"mrilib.h\"\n"
00137 "NI_stream ns; MRI_IMAGE *im; float *far; int nx,ny;\n"
00138 "system(\"aiv -p 4444 &\"); /* start aiv */\n"
00139 "ns = NI_stream_open( \"tcp:localhost:4444\" , \"w\" ); /* connect to it */\n"
00140 "while(1){\n"
00141 " /** ......... create 2D nx X ny data into the far array .........**/\n"
00142 " im = mri_new_vol_empty( nx , ny , 1 , MRI_float ); /* fake image */\n"
00143 " mri_fix_data_pointer( far , im ); /* attach data */\n"
00144 " NI_element nel = mri_to_niml(im); /* convert to NIML element */\n"
00145 " NI_write_element( ns , nel , NI_BINARY_MODE ); /* send to aiv */\n"
00146 " NI_free_element(nel); mri_clear_data_pointer(im); mri_free(im);\n"
00147 "}\n"
00148 "NI_stream_writestring( ns , \"<ni_do ni_verb='QUIT'>\" ) ;\n"
00149 "NI_stream_close( ns ) ; /* do this, or the above, if done with aiv */\n"
00150 "\n"
00151 "-- Author: RW Cox\n"
00152 ) ;
00153 exit(0) ;
00154 }
00155
00156 PRINT_VERSION("aiv") ; mainENTRY("aiv main") ; machdep() ;
00157
00158
00159
00160 while( iarg < argc && argv[iarg][0] == '-' ){
00161
00162
00163
00164 if( strncmp(argv[iarg],"-v",2) == 0 ){ verb=1; iarg++; continue; }
00165
00166
00167
00168 if( strncmp(argv[iarg],"-p",2) == 0 ){
00169 int port = (int)strtol(argv[++iarg],NULL,10) ;
00170 if( AIVVV_stream != NULL ){
00171 ERROR_message("Can't use multiple '-p' options!") ;
00172 iarg++ ; continue ;
00173 }
00174 if( port <= 1023 ){
00175 ERROR_message("Illegal value after -p; not listening.") ;
00176 } else {
00177 sprintf(AIVVV_strnam,"tcp:x:%d",port) ;
00178 AIVVV_stream = NI_stream_open( AIVVV_strnam , "r" ) ;
00179 if( AIVVV_stream == (NI_stream)NULL ){
00180 ERROR_message("Can't listen to port %d!",port) ;
00181 } else {
00182 int nn ;
00183 nn = NI_stream_goodcheck(AIVVV_stream,66) ;
00184 if( verb ){
00185 if( nn > 0 ) INFO_message("Connected to port %d",port) ;
00186 else INFO_message("Listening to port %d",port) ;
00187 }
00188 }
00189 }
00190 iarg++ ; continue ;
00191 }
00192
00193
00194
00195 ERROR_message("Unknown option: %s",argv[iarg]) ;
00196 }
00197
00198
00199
00200 MCW_file_expand( argc-iarg , argv+iarg , &gnim , &gname ) ;
00201 if( gnim == 0 && AIVVV_stream==(NI_stream)NULL )
00202 ERROR_exit("No filenames on command line?!") ;
00203
00204 INIT_IMARR(MAIN_imar) ;
00205
00206 for( ii=0 ; ii < gnim ; ii++ ){
00207 if( !THD_filename_ok(gname[ii]) ) continue ;
00208 if( verb ) fprintf(stderr,"+") ;
00209 qar = mri_read_file( gname[ii] ) ;
00210 if( qar == NULL || IMARR_COUNT(qar) < 1 ){
00211 fprintf(stderr,"\n** Can't read file %s - skipping!",gname[ii]) ;
00212 continue ;
00213 } else if( verb ){
00214 fprintf(stderr,"%s",gname[ii]) ;
00215 }
00216
00217 for( jj=0 ; jj < IMARR_COUNT(qar) ; jj++ ){
00218 im = IMARR_SUBIM(qar,jj) ;
00219 if( im != NULL ) ADDTO_IMARR( MAIN_imar , im ) ;
00220 }
00221 FREE_IMARR(qar) ;
00222 }
00223
00224
00225
00226 if( IMARR_COUNT(MAIN_imar) == 0 && AIVVV_stream==(NI_stream)NULL )
00227 ERROR_exit("No images found on command line!?") ;
00228 if( IMARR_COUNT(MAIN_imar) > 0 ){
00229 fprintf(stderr, (verb) ? " = " : "++ " ) ;
00230 if( IMARR_COUNT(MAIN_imar) == 1 )
00231 fprintf(stderr,"1 image\n") ;
00232 else
00233 fprintf(stderr,"%d images\n",IMARR_COUNT(MAIN_imar)) ;
00234 }
00235
00236 if( gnim > 0 ) MCW_free_expand( gnim , gname ) ;
00237
00238
00239
00240 shell = XtVaAppInitialize( &MAIN_app , "AFNI" , NULL , 0 ,
00241 &argc , argv , FALLback , NULL ) ;
00242
00243 if( shell == NULL )
00244 ERROR_exit("Can't initialize X11") ;
00245
00246 AIVVV_appcontext = XtWidgetToApplicationContext(shell) ;
00247
00248 (void) XtAppSetWarningHandler(MAIN_app,AFNI_handler) ;
00249
00250 MAIN_dc = MCW_new_DC( shell, 128,
00251 DEFAULT_NCOLOVR, INIT_colovr, INIT_labovr, 1.0, 0 ) ;
00252
00253 srand48((long)time(NULL)) ;
00254
00255
00256
00257 (void) XtAppAddTimeOut( MAIN_app, 234, timeout_CB, NULL ) ;
00258 XtAppMainLoop(MAIN_app) ;
00259 exit(0) ;
00260 }
00261
00262
00263
00264
00265 static void * AIVVV_imseq_popup( MRI_IMARR *imar, generic_func *kfunc, void *kdata )
00266 {
00267 int ntot , ii ;
00268 MRI_IMAGE *im , *cim ;
00269 AIVVVV_imseq *psq ;
00270
00271 ENTRY("AIVVV_imseq_popup") ;
00272
00273 if( imar == NULL ) RETURN(NULL) ;
00274
00275 ntot = IMARR_COUNT(imar) ;
00276 if( ntot == 0 ){
00277 #define QQ_NXYZ 16
00278 static byte xxx[QQ_NXYZ*QQ_NXYZ] = {
00279 0,0,21,131,135,135,135,8,0,0,3,100,135,135,135,128,
00280 0,0,0,108,255,255,255,86,0,0,115,255,255,255,255,121,
00281 0,0,0,21,216,255,255,213,0,19,223,255,255,255,187,5,
00282 0,0,0,0,92,244,255,255,114,114,255,255,255,234,58,0,
00283 0,0,0,0,0,174,255,255,252,230,255,255,255,130,0,0,
00284 0,0,0,0,0,58,244,255,255,255,255,255,228,29,0,0,
00285 0,0,0,0,0,0,118,255,255,255,255,255,74,0,0,0,
00286 0,0,0,0,0,0,55,248,255,255,255,199,3,0,0,0,
00287 0,0,0,0,0,5,170,255,255,255,255,227,32,0,0,0,
00288 0,0,0,0,0,104,255,255,255,255,255,255,140,5,0,0,
00289 0,0,0,0,13,217,255,255,252,215,255,255,255,67,0,0,
00290 0,0,0,0,159,255,255,255,212,23,233,255,255,187,7,0,
00291 0,0,0,81,241,255,255,255,85,0,72,255,255,255,66,0,
00292 0,0,16,206,255,255,255,212,0,0,8,193,255,255,237,12,
00293 0,0,94,255,255,255,255,86,0,0,0,73,255,255,255,121,
00294 0,14,129,134,134,134,85,1,0,0,0,3,106,134,134,127 } ;
00295 byte *ar ; MRI_IMAGE *xim ;
00296
00297 ar = (byte *)malloc(sizeof(byte)*QQ_NXYZ*QQ_NXYZ) ;
00298 memcpy(ar,xxx,sizeof(byte)*QQ_NXYZ*QQ_NXYZ) ;
00299 xim = mri_new_vol_empty( QQ_NXYZ,QQ_NXYZ,1 , MRI_byte ) ;
00300 mri_fix_data_pointer( ar , xim ) ;
00301 xim->dx = xim->dy = 16.0 ;
00302 ADDTO_IMARR(imar,xim) ; ntot = 1 ; AIVVV_have_dummy = 1 ;
00303 }
00304
00305
00306
00307 psq = psq_global = (AIVVVV_imseq *)calloc(1,sizeof(AIVVVV_imseq)) ;
00308 if( psq == NULL ) RETURN(NULL) ;
00309
00310 psq->imar = imar ;
00311
00312 psq->kill_func = kfunc ;
00313 psq->kill_data = kdata ;
00314 psq->rgb_count = 0 ;
00315
00316
00317
00318 psq->seq = open_MCW_imseq( MAIN_dc , AIVVV_imseq_getim , psq ) ;
00319
00320 drive_MCW_imseq( psq->seq , isqDR_clearstat , NULL ) ;
00321
00322 { ISQ_options opt ;
00323
00324 ISQ_DEFAULT_OPT(opt) ;
00325 opt.save_one = False ;
00326 opt.save_pnm = False ;
00327 drive_MCW_imseq( psq->seq , isqDR_options , (XtPointer) &opt ) ;
00328 drive_MCW_imseq( psq->seq , isqDR_periodicmont , (XtPointer) 0 ) ;
00329 drive_MCW_imseq( psq->seq , isqDR_penbbox , (XtPointer) 0 ) ;
00330 }
00331
00332
00333
00334 drive_MCW_imseq( psq->seq , isqDR_realize, NULL ) ;
00335 drive_MCW_imseq( psq->seq , isqDR_title, "Images" ) ;
00336
00337 if( ntot == 1 )
00338 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid );
00339 else
00340 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid );
00341
00342
00343
00344 drive_MCW_imseq( psq->seq , isqDR_display, (XtPointer)0 ) ;
00345
00346 RETURN( (void *)psq ) ;
00347 }
00348
00349
00350
00351 static void AIVVV_imseq_retitle( void *handle , char *title )
00352 {
00353 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
00354
00355 if( psq == NULL || psq->seq == NULL || title == NULL ) return ;
00356 drive_MCW_imseq( psq->seq , isqDR_title, title ) ;
00357 return ;
00358 }
00359
00360
00361
00362
00363
00364
00365 static XtPointer AIVVV_imseq_getim( int n, int type, XtPointer handle )
00366 {
00367 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
00368 int ntot = 0 ;
00369
00370 ENTRY("AIVVV_imseq_getim") ;
00371
00372 if( psq->imar != NULL ) ntot = IMARR_COUNT(psq->imar) ;
00373 if( ntot < 1 ) ntot = 1 ;
00374
00375
00376
00377 if( type == isqCR_getstatus ){
00378 MCW_imseq_status *stat = myXtNew( MCW_imseq_status ) ;
00379
00380
00381 stat->num_total = ntot ;
00382 stat->num_series = ntot ;
00383 stat->send_CB = AIVVV_imseq_send_CB ;
00384 stat->parent = NULL ;
00385 stat->aux = NULL ;
00386
00387 stat->transforms0D = NULL ;
00388 stat->transforms2D = NULL ;
00389 stat->slice_proj = NULL ;
00390
00391 RETURN( (XtPointer)stat ) ;
00392 }
00393
00394
00395
00396
00397 if( type == isqCR_getimage || type == isqCR_getqimage ){
00398 MRI_IMAGE *im = NULL , *rim ;
00399
00400 if( psq->imar != NULL ){
00401 if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
00402 rim = IMARR_SUBIMAGE(psq->imar,n) ;
00403 if( psq->rgb_count > 0 )
00404 im = mri_to_rgb( rim ) ;
00405 else
00406 im = mri_copy( rim ) ;
00407 }
00408 RETURN( (XtPointer)im ) ;
00409 }
00410
00411 RETURN(NULL) ;
00412 }
00413
00414
00415
00416
00417
00418
00419
00420 static void AIVVV_imseq_send_CB( MCW_imseq *seq, XtPointer handle, ISQ_cbs *cbs )
00421 {
00422 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
00423
00424 ENTRY("AIVVV_imseq_send_CB") ;
00425
00426 switch( cbs->reason ){
00427 case isqCR_destroy:{
00428 myXtFree(psq->seq) ;
00429 DESTROY_IMARR( psq->imar ) ;
00430
00431 if( psq->kill_func != NULL )
00432 psq->kill_func( psq->kill_data ) ;
00433 free(psq) ;
00434 }
00435 break ;
00436
00437 case isqCR_newimage:{
00438 drive_MCW_imseq( psq->seq, isqDR_display, (XtPointer)cbs->nim );
00439 }
00440 break ;
00441 }
00442 EXRETURN ;
00443 }
00444
00445
00446
00447
00448 static void AIVVV_imseq_addto( MRI_IMAGE *im )
00449 {
00450 int ntot , num ;
00451 AIVVVV_imseq *psq = psq_global ;
00452
00453 ENTRY("AIVVV_imseq_addto") ;
00454
00455 if( im == NULL ) EXRETURN ;
00456
00457 if( im->nx < 4 || im->ny < 4 ) EXRETURN ;
00458
00459
00460
00461
00462 num = im->nz * im->nt * im->nu * im->nv * im->nw ;
00463 if( num > 1 ){
00464 MRI_IMAGE *qim ; int kk,nb ; char *iar=(char *)mri_data_pointer(im) ;
00465 nb = im->nx * im->ny * im->pixel_size ;
00466 for( kk=0 ; kk < num ; kk++ ){
00467 qim = mri_new_vol_empty( im->nx , im->ny , 1, im->kind ) ;
00468 qim->dx = im->dx ; qim->dy = im->dy ;
00469 mri_fix_data_pointer( iar + kk*nb , qim ) ;
00470 AIVVV_imseq_addto( qim ) ;
00471 }
00472 EXRETURN ;
00473 }
00474
00475 if( AIVVV_have_dummy ){
00476 IMARR_SUBIM(psq->imar,0) = im ;
00477 AIVVV_have_dummy = 0 ;
00478 } else {
00479 ADDTO_IMARR(psq->imar,im) ;
00480 }
00481 if( im->kind == MRI_rgb ) psq->rgb_count++ ;
00482
00483 drive_MCW_imseq( psq->seq , isqDR_newseq , psq ) ;
00484
00485 ntot = IMARR_COUNT(psq->imar) ;
00486 if( ntot == 2 )
00487 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
00488
00489 drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)(ntot-1) ) ;
00490 EXRETURN ;
00491 }
00492
00493
00494
00495
00496
00497
00498 static Boolean AIVVV_workproc( XtPointer fred )
00499 {
00500 int nn ;
00501 NI_element *nel ;
00502 MRI_IMAGE *im ;
00503
00504 nn = NI_stream_goodcheck(AIVVV_stream,3) ;
00505 if( nn < 0 ){
00506 NI_stream_closenow(AIVVV_stream) ;
00507 NI_sleep(9) ;
00508 AIVVV_stream = NI_stream_open( AIVVV_strnam , "r" ) ;
00509 return False ;
00510 }
00511
00512 nn = NI_stream_hasinput(AIVVV_stream,9) ;
00513 if( nn <= 0 ) return False ;
00514
00515
00516
00517 nel = (NI_element *)NI_read_element(AIVVV_stream,99) ;
00518 if( NI_element_type(nel) != NI_ELEMENT_TYPE ){
00519 NI_free_element(nel) ; return False ;
00520 }
00521
00522
00523
00524 im = niml_to_mri( nel ) ;
00525 NI_free_element( nel ) ;
00526 AIVVV_imseq_addto( im ) ;
00527 return False ;
00528 }
00529
00530
00531
00532 static void AIVVV_niml_quitter( char *obj, NI_stream ns, NI_element *nel )
00533 {
00534 INFO_message("Received remote command to exit") ;
00535 NI_stream_closenow(AIVVV_stream) ;
00536 NI_sleep(333) ;
00537 exit(0) ;
00538 }