openjpeg/src/bin/fltk/flviewer/flviewer.cxx

2612 lines
51 KiB
C++

#include <config.h>
#include "opj_apps_config.h"
/*
* author(s) and license
*/
//------------ see in main() ------------
#define HAVE_OPTION_FNFC_USES_GTK
//---------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <process.h>
//FIXME remove #define snprintf sprintf_s
#else /* not _WIN32 */
#include <unistd.h>
#include <sys/sem.h>
#define __STDC_FORMAT_MACROS
#include <stdint.h>
#endif /* _WIN32 */
#include <sys/stat.h>
#include <ctype.h>
#include <signal.h>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/Enumerations.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Box.H>
#include <FL/filename.H>
#include <FL/x.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Spinner.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Native_File_Chooser.H>
#include <FL/Fl_Overlay_Window.H>
#include <FL/Fl_Tree.H>
#include <FL/Fl_Pixmap.H>
#include "opj_stdint.h"
#include "flviewer.hh"
#include "tree.hh"
#include "viewerdefs.hh"
#include "lang/viewer_lang.h_utf8"
#include "rgb_color.hh"
#include "print_gui.hh"
#include "ps_image.hh"
#ifdef OPJ_HAVE_LIBPNG
#include "PNG.hh"
#endif
#include "OPENJPEG.hh"
#ifdef WANT_PGX
#include "PGX.hh"
#endif
#include "OPENMJ2.hh"
#include "JP2.hh"
#ifndef OPJ_PATH_LEN
#define OPJ_PATH_LEN 4096
#endif
//#define RESET_REDUCTION
#define USE_CUSTOM_ICONS
#define MAX_SPINVALUE 6.
#define DEFAULT_BACKGROUND FL_LIGHT1
#define DEFAULT_CANVAS_BACKGROUND FL_DARK2
static const char *IMG_PATTERN =
#ifdef WANT_PGX
"*.{png,j2k,j2c,jp2,jpg2,jpc,jpx,jpf,jpm,mj2,mjp2,pgx}";
#else
"*.{png,j2k,j2c,jp2,jpg2,jpc,jpx,jpf,jpm,mj2,mjp2}";
#endif
static Canvas *canvas;
static short movie_runs;
static char url_buf[512];
#define MAX_COLORBUF 31
static char bgcolor_buf[MAX_COLORBUF + 1];
static char vbuf[48];
//------------------- FORWARD ---------------------
static void print_cb(Fl_Widget *wid, void *v);
static void save_as_opj_cb(Fl_Widget *wid, void *v);
#ifdef OPJ_HAVE_LIBPNG
static void save_as_png_cb(Fl_Widget *wid, void *v);
#endif
static Fl_Double_Window *crop_win;
static Fl_Box *crop_box;
static Fl_RGB_Image *crop_img;
static int crop_win_done;
static int crop_lhs_top_x, crop_lhs_top_y;
static int crop_width, crop_height;
static int start_overlay;
static void exit_cb(Fl_Widget *wid, void *v);
static void pause_cb(Fl_Widget *wid, void *v);
static void resume_cb(Fl_Widget *wid, void *v);
static void restart_cb(Fl_Widget *wid, void *v);
static void forward_cb(Fl_Widget *wid, void *v);
static void backward_cb(Fl_Widget *wid, void *v);
static void fin_cb(Fl_Widget *wid, void *v);
static void browse_cb(Fl_Widget *wid, void *v);
static void goto_frame_cb(Fl_Widget *wid, void *v);
static void goto_track_cb(Fl_Widget *w, void *v);
static void chooser_cb(const char *cs);
#ifdef HAVE_THREADS
static int nr_threads;
#endif
char *root_dir;
static char *read_idf;
static FILE *reader;
static Fl_Spinner *threads_spinner;
static int win_w, win_h;
static Fl_Group *tiles_group;
static Fl_Button *pause_but, *resume_but, *restart_but, *backward_but,
*forward_but, *fin_but;
static Fl_Output *url_out;
static Fl_Input *goto_frame_in, *goto_track_in;
static Fl_Output *all_frames_out, *all_tracks_out;
static Fl_Group *tracks_group, *frames_group;
static Fl_Input *layer_in, *component_in;
static Fl_Output *layer_out, *component_out;
static int mj2_max_tracks, max_components, max_layers;
static int cur_component, cur_layers;
static Fl_Scroll *scroll;
static Fl_Input *area_in, *tile_in;
static Fl_Group *reduct_group;
static Fl_Input *reduct_in;
static Fl_Output *tiles_out;
static Fl_Output *reduct_out;
static Fl_Button * reload_jp2;
static int max_tiles, max_reduction, cur_tile, cur_reduction;
static int user_changed_tile, user_changed_reduct;
static int reloaded;
static int cmd_line_reduction;
static int area_x0, area_y0, area_x1, area_y1;
static int user_changed_area;
static char *jp2_file;
static char *mj2_file;
static double fscale = 1.0;
#ifdef USE_CUSTOM_ICONS
static const char *L_open_xpm[] =
{
"11 11 2 1",
". c None",
"@ c #000000",
"...@.......",
"...@@......",
"...@@@.....",
"...@@@@....",
"...@@@@@...",
"...@@@@@@..",
"...@@@@@...",
"...@@@@....",
"...@@@.....",
"...@@......",
"...@......."
};
static Fl_Pixmap L_openpixmap(L_open_xpm);
static const char *L_close_xpm[] =
{
"11 11 2 1",
". c None",
"@ c #000000",
"...........",
"...........",
"...........",
"...........",
"...........",
"@@@@@@@@@@@",
".@@@@@@@@@.",
"..@@@@@@@..",
"...@@@@@...",
"....@@@....",
".....@....."
};
static Fl_Pixmap L_closepixmap(L_close_xpm);
#endif //USE_CUSTOM_ICONS
//----------------- end FORWARD -------------------
UserTree *tree = NULL;
int UserTree::handle(int event)
{
#ifdef DEBUG_TREE
fprintf(stderr,"%s:%d:\n\tUserTree(%d,%d,%d,%d) event(%d,%d) ex(%d) ey(%d)\n",
__FILE__,__LINE__,x(),y(),x()+w(),y()+h(),
Fl::event_x(),Fl::event_y(), Fl::event_x()-x(),Fl::event_y()-y() );
#endif
if(!Fl::event_inside(x(), y(), w(), h() ) )
{
#ifdef DEBUG_TREE
fprintf(stderr,"%s:%d:\n\tNOT INSIDE TREE\n",__FILE__,__LINE__);
#endif
return 0;
}
if(event == FL_LEAVE) return 1;
return Fl_Tree::handle(event);
}
class ImageBox : public Fl_Box
{
public:
int start_x, start_y;
int lhs_top_x, lhs_top_y, rhs_top_x, rhs_top_y;
int lhs_bot_x, lhs_bot_y, rhs_bot_x, rhs_bot_y;
int lhs_x, top_y;
ImageBox(int xx, int yy, int ww, int hh)
: Fl_Box(xx, yy, ww, hh, NULL)
{
lhs_x = xx; top_y = yy;
start_x = start_y = 0;
lhs_top_x = lhs_top_y = 0;
rhs_top_x = rhs_top_y = 0;
lhs_bot_x = lhs_bot_y = 0;
rhs_bot_x = rhs_bot_y = 0;
} ;
virtual int handle(int event);
};
static ImageBox *scroll_box;
class Overlay : public Fl_Overlay_Window
{
public:
Overlay(int xx, int yy, int ww, int hh)
: Fl_Overlay_Window(xx, yy, ww, hh) {};
void draw_overlay();
};
static Overlay *main_win;
void Overlay::draw_overlay()
{
if(movie_runs || !canvas->cbuf) return;
if(start_overlay)
{
crop_width = crop_height = 0;
start_overlay = 0;
}
fl_color(FL_YELLOW);
fl_rect(scroll_box->x() + crop_lhs_top_x,
scroll_box->y() + crop_lhs_top_y,
crop_width, crop_height);
}
int ImageBox::handle(int event)
{
int ex, ey;
#ifdef DEBUG_IMAGEBOX
fprintf(stderr,"%s:%d:\n\tImageBox(%d,%d,%d,%d) event(%d,%d) ex(%d) ey(%d)\n",
__FILE__,__LINE__,x(),y(),x()+w(),y()+h(),
Fl::event_x(),Fl::event_y(), Fl::event_x()-x(),Fl::event_y()-y() );
#endif
if(!Fl::event_inside(x(), y(), w(), h() ) )
{
#ifdef DEBUG_IMAGEBOX
fprintf(stderr,"%s:%d:\n\tNOT INSIDE IMAGEBOX\n",__FILE__,__LINE__);
#endif
return 0;
}
if(event == FL_LEAVE) return 1;
if(movie_runs || !canvas->cbuf) return 1;
ex = Fl::event_x() - x(); ey = Fl::event_y() - y();
switch(event)
{
case FL_PUSH:
lhs_top_x = lhs_top_y = rhs_top_x = rhs_top_y = 0;
lhs_bot_x = lhs_bot_y = rhs_bot_x = rhs_bot_y = 0;
start_x = ex; start_y = ey;
start_overlay = 1;
main_win->redraw_overlay();
return 1;
case FL_DRAG:
if(ex > start_x) //rhs
{
if(ey < start_y) //up
{
lhs_top_x = start_x; lhs_top_y = ey;
rhs_top_x = ex; rhs_top_y = ey;
lhs_bot_x = start_x; lhs_bot_y = start_y;
lhs_bot_x = ex; rhs_bot_y = start_y;
}
else
if(ey > start_y) //down
{
lhs_top_x = start_x; lhs_top_y = start_y;
rhs_top_x = ex; rhs_top_y = start_y;
lhs_bot_x = start_x; lhs_bot_y = ey;
rhs_bot_x = ex; rhs_bot_y = ey;
}
}
else
if(ex < start_x) //lhs
{
if(ey < start_y) //up
{
lhs_top_x = ex; lhs_top_y = ey;
rhs_top_x = start_x; rhs_top_y = ey;
lhs_bot_x = ex; lhs_bot_y = start_y;
rhs_bot_x = start_x; rhs_bot_y = start_y;
}
else
if(ey > start_y) //down
{
lhs_top_x = ex; lhs_top_y = start_y;
rhs_top_x = start_x; rhs_top_y = start_y;
lhs_bot_x = ex; lhs_bot_y = ey;
rhs_bot_x = start_x; rhs_bot_y = ey;
}
}
crop_lhs_top_x = lhs_top_x;
crop_lhs_top_y = lhs_top_y;
crop_width = rhs_top_x - lhs_top_x;
crop_height = rhs_bot_y - rhs_top_y;
main_win->redraw_overlay();
return 1;
case FL_RELEASE:
return 1;
}
return Fl_Box::handle(event);
}
static void crop_cancel_cb(Fl_Widget *wid, void *v)
{
crop_win_done = 1;
crop_win->hide();
}
static void crop_print_cb(Fl_Widget *wid, void *v)
{
const void *cbuf;
int iw, ih, ic;
cbuf = canvas->cbuf;
iw = canvas->new_iwidth;
ih = canvas->new_iheight;
ic = canvas->new_idepth;
canvas->cbuf = crop_img->data()[0];
canvas->new_iwidth = crop_img->w();
canvas->new_iheight = crop_img->h();
canvas->new_idepth = crop_img->d();
print_cb(wid, v);
canvas->cbuf = cbuf;
canvas->new_iwidth = iw;
canvas->new_iheight = ih;
canvas->new_idepth = ic;
}
#ifdef OPJ_HAVE_LIBPNG
static void crop_save_as_png_cb(Fl_Widget *wid, void *v)
{
const void *cbuf;
int iw, ih, ic;
cbuf = canvas->cbuf;
iw = canvas->new_iwidth;
ih = canvas->new_iheight;
ic = canvas->new_idepth;
canvas->cbuf = crop_img->data()[0];
canvas->new_iwidth = crop_img->w();
canvas->new_iheight = crop_img->h();
canvas->new_idepth = crop_img->d();
save_as_png_cb(wid, v);
canvas->cbuf = cbuf;
canvas->new_iwidth = iw;
canvas->new_iheight = ih;
canvas->new_idepth = ic;
}
#endif
static void crop_save_as_opj_cb(Fl_Widget *wid, void *v)
{
const void *cbuf;
int iw, ih, ic;
cbuf = canvas->cbuf;
iw = canvas->new_iwidth;
ih = canvas->new_iheight;
ic = canvas->new_idepth;
canvas->cbuf = crop_img->data()[0];
canvas->new_iwidth = crop_img->w();
canvas->new_iheight = crop_img->h();
canvas->new_idepth = crop_img->d();
save_as_opj_cb(wid, v);
canvas->cbuf = cbuf;
canvas->new_iwidth = iw;
canvas->new_iheight = ih;
canvas->new_idepth = ic;
}
Fl_Menu_Item crop_popup_items[] =
{
{EXIT_s, 0, &crop_cancel_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, FL_YELLOW},
{PRINT_s, 0, &crop_print_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
#ifdef OPJ_HAVE_LIBPNG
{SAVE_AS_PNG_s, 0, &crop_save_as_png_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
#endif
{SAVE_AS_OPJ_s, 0, &crop_save_as_opj_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
{NULL, 0, NULL, NULL, 0, 0, 0, 0, 0}
};
static void crop_popup_create(int x, int y, int ww, int hh)
{
Fl_Menu_Button *popup;
popup = new Fl_Menu_Button(x, y, ww, hh);
popup->type(Fl_Menu_Button::POPUP3);
popup->menu(crop_popup_items);
}
static void crop_window_cb(Fl_Widget *wid, void *v)
{
unsigned char *dst, *d;
const unsigned char *s;
int ww, hh, idepth, i, iwidth, s_step, d_step;
if(canvas->cbuf == NULL) return;
if(crop_width == 0 && crop_height == 0) return;
//One crop window only:
if(crop_win != NULL) return;
idepth = canvas->new_idepth;
dst = (unsigned char*)malloc(crop_width * crop_height * idepth);
if(dst == NULL) return;
hh = crop_height + 10; ww = crop_width + 10;
crop_win = new Fl_Double_Window(220, 220, ww, hh);
crop_win->callback(crop_cancel_cb);
crop_win->box(FL_FLAT_BOX);
crop_win->color(main_win->color());
crop_win->begin();
crop_box = new Fl_Box(5, 5, crop_width, crop_height);
crop_box->box(FL_FLAT_BOX);
crop_box->color(scroll_box->color());
crop_box->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
// crop_win->resizable(crop_box);
crop_popup_create(0, 0, ww, hh);
crop_win_done = 0;
crop_win->end();
crop_win->show();
iwidth = canvas->new_iwidth;
s = (const unsigned char*)canvas->cbuf
+ (iwidth * crop_lhs_top_y + crop_lhs_top_x) * idepth;
s_step = iwidth * idepth;
d_step = crop_width * idepth;
d = dst;
for(i = 0; i < crop_height; ++i)
{
memcpy(d, s, d_step);
d += d_step;
s += s_step;
}
crop_img = new
Fl_RGB_Image(dst, crop_width, crop_height, idepth);
crop_box->image(crop_img);
crop_box->redraw();
while(crop_win_done == 0)
Fl::wait();
crop_win_done = 0;
delete crop_img;
crop_img = NULL;
delete crop_win;
crop_win = NULL;
}
#ifdef _WIN32
CRITICAL_SECTION CriticalSection;
#else /* not _WIN32 */
static int semid;
static struct sembuf sema;
static union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
} su;
#endif /* _WIN32 */
#ifdef _WIN32
#define IDLE_SPIN 0x00000400
#else /* not _WIN32 */
static void critical(int id, int op)
{
sema.sem_op = op; sema.sem_flg = SEM_UNDO;
if(semop(id, &sema, 1) == -1)
fprintf(stderr,"%s:%d:semop %d failed\n",__FILE__,__LINE__,op);
}
#define ENTER_CRITICAL(i) critical(i, -1)
#define LEAVE_CRITICAL(i) critical(i, 1)
#endif /* _WIN32 */
void FLViewer_clear_tree()
{
if(tree) tree->clear();
}
void FLViewer_header_deactivate()
{
tile_in->value("");
tiles_out->value("");
tiles_group->deactivate();
reduct_in->value("");
reduct_out->value("");
reduct_group->deactivate();
reload_jp2->deactivate();
area_in->deactivate();
FLViewer_area_activate(0);
FLViewer_layer_component_activate(0);
pause_but->deactivate();
resume_but->deactivate();
restart_but->deactivate();
fin_but->deactivate();
forward_but->deactivate();
backward_but->deactivate();
goto_frame_in->value("");
all_frames_out->value("");
frames_group->deactivate();
goto_track_in->value("");
all_tracks_out->value("");
tracks_group->deactivate();
}//FLViewer_header_activate()
#ifdef HAVE_THREADS
void FLViewer_threads_activate(int v)
{
if(v)
threads_spinner->activate();
else
threads_spinner->deactivate();
}
#endif
void FLViewer_movie_runs(int v)
{
movie_runs = v;
}
void FLViewer_close_reader(void)
{
if(reader)
{
fclose(reader); reader = NULL;
}
}
static void spinner_cb(Fl_Widget *wid, void *v)
{
if( !wid->contains(Fl::belowmouse())) return;
#ifdef HAVE_THREADS
{
Fl_Spinner *spin = (Fl_Spinner*)wid;
if(spin->value() < 0. || spin->value() > MAX_SPINVALUE)
spin->value(0);
nr_threads = (int)spin->value();
}
#endif
}
int FLViewer_nr_threads(void)
{
#ifdef HAVE_THREADS
threads_spinner->value(nr_threads);
return nr_threads;
#else
threads_spinner->value(0);
return 0;
#endif
}
static void zoomin_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
fscale += 0.05;
chooser_cb(read_idf);
}
static void zoomin_50_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
fscale += 0.5;
chooser_cb(read_idf);
}
static void zoomin_25_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
fscale += 0.25;
chooser_cb(read_idf);
}
static void zoomout_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
if(fscale < 0.06) return;
fscale -= 0.05;
chooser_cb(read_idf);
}
static void zoomout_50_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
if(fscale < 0.6) return;
fscale -= 0.5;
chooser_cb(read_idf);
}
static void zoomout_25_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
if(fscale < 0.3) return;
fscale -= 0.25;
chooser_cb(read_idf);
}
static void reset_zoom_cb(Fl_Widget *w, void *v)
{
if(movie_runs) return;
fscale = 1.0;
chooser_cb(read_idf);
}
static void tile_in_cb(Fl_Widget *w, void *v)
{
const char *cs;
int i;
if( !w->contains(Fl::belowmouse())) return;
cs = ((Fl_Input*)w)->value();
if(cs == NULL || *cs == 0)
i = -1;
else
i = atoi(cs);
if(i >= max_tiles) i = max_tiles - 1;
cur_tile = i;
user_changed_tile = user_changed_reduct = 1;
user_changed_area = 0;
chooser_cb(read_idf);
if(i < 0)
tile_in->value("");
else
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", i);
tile_in->value(vbuf);
}
tile_in->redraw();
}
static void area_in_cb(Fl_Widget *w, void *v)
{
const char *cs;
if( !w->contains(Fl::belowmouse())) return;
cs = ((Fl_Input*)w)->value();
if(cs == NULL || *cs == 0)
{
area_in->value("x0,y0,x1,y1");
area_in->redraw();
return;
}
area_x0 = area_y0 = area_x1 = area_y1 = 0;
if(sscanf(cs, "%d,%d,%d,%d", &area_x0,&area_y0,&area_x1,&area_y1) != 4)
{
fprintf(stderr,"AREA(%s) unusable\n",cs);
return;
}
if(area_x0 < 0 || area_x1 < 0 || area_y0 < 0 || area_y1 < 0) return;
if(area_x1 <= area_x0 || area_y1 <= area_y0) return;
user_changed_area = 1;
user_changed_tile = user_changed_reduct = 0;
tile_in->value("");
tile_in->redraw();
cur_tile = -1;
chooser_cb(read_idf);
snprintf(vbuf, sizeof(vbuf)-1, "%d,%d,%d,%d", area_x0, area_y0,
area_x1, area_y1);
area_in->value(vbuf);
area_in->redraw();
}
static void reduct_in_cb(Fl_Widget *w, void *v)
{
const char *cs;
int i;
if( !w->contains(Fl::belowmouse())) return;
cs = ((Fl_Input*)w)->value();
if(cs == NULL || *cs == 0)
i = 0;
else
i = atoi(cs);
if(i < 0) return;
if(max_reduction > 0 && i >= max_reduction) return;
cur_reduction = i;
user_changed_tile = user_changed_reduct = 1;
chooser_cb(read_idf);
snprintf(vbuf, sizeof(vbuf)-1, "%d", i);
reduct_in->value(vbuf);
reduct_in->redraw();
}
static void test_new_jp2_file()
{
int new_jp2_file;
if(reloaded)
{
reloaded = 0;
fscale = 1.0;
user_changed_area = 0;
area_x0 = area_x1 = area_y0 = area_y1 = 0;
area_in->value("x0,y0,x1,y1");
area_in->redraw();
max_tiles = max_reduction = 0;
tile_in->value("");
tile_in->redraw();
reduct_in->value("0");
reduct_in->redraw();
user_changed_tile = 0; user_changed_reduct = 0;
max_tiles = max_reduction = -1;
cur_tile = -1; cur_reduction = 0;
cur_layers = max_layers = 0;
cur_component = max_components = 0;
component_in->value("");
component_out->value("");
if(JPEG2000_build_tree(read_idf) == 0)
{
fprintf(stderr,"%s:%d:\n\t=== NO TREE BUILT ===\n",__FILE__,__LINE__);
}
return;
}
if(jp2_file)
{
if(strcmp(jp2_file, read_idf))/* New file */
{
new_jp2_file = 1;
}
else
{
new_jp2_file = 0;
}
}
else
{
new_jp2_file = 1;
}
if(new_jp2_file)
{
if(jp2_file) free(jp2_file);
jp2_file = strdup(read_idf);
if(jp2_file == NULL)
{
fprintf(stderr,"flviewer.cxx:%d:\n\tmemory out\n",__LINE__);
exit(1);
}
fscale = 1.0;
user_changed_area = 0;
area_x0 = area_y0 = area_x1 = area_y1 = 0;
area_in->value("x0,y0,x1,y1");
area_in->redraw();
tile_in->value("");
tile_in->redraw();
cur_tile = -1;
/* To get the new values:
*/
max_tiles = max_reduction = 0;
user_changed_tile = 0;
#ifdef RESET_REDUCTION
cur_reduction = 0;
reduct_in->value("");
reduct_out->value("");
user_changed_reduct = 0;
#endif
layer_in->value("");
layer_out->value("");
cur_layers = max_layers = 0;
component_in->value("");
component_out->value("");
cur_component = max_components = 0;
#ifdef HAVE_THREADS
nr_threads = 0;
threads_spinner->value(0);
threads_spinner->deactivate();
#endif
if(JPEG2000_build_tree(read_idf) == 0)
{
fprintf(stderr,"%s:%d:\n\t=== NO TREE BUILT ===\n",__FILE__,__LINE__);
}
}
}//test_new_jp2_file()
static void test_new_mj2_file()
{
int new_file;
//FLViewer_movie_runs(1);
if(mj2_file)
{
if(strcmp(mj2_file, read_idf))
{
free(mj2_file);
new_file = 1;
}
else
{
new_file = 0;
}
}
else
{
new_file = 1;
}
if(new_file)
{
mj2_file = strdup(read_idf);
if(mj2_file == NULL)
{
fprintf(stderr,"flviewer.cxx:%d:\n\tmemory out\n",__LINE__);
exit(1);
}
layer_in->value("");
layer_in->deactivate();
layer_out->value("");
layer_out->deactivate();
component_in->activate();
component_out->activate();
OPENMJ2_free_tracks();
if(JPEG2000_build_tree(read_idf) == 0)
{
fprintf(stderr,"%s:%d:\n\t=== NO TREE BUILT ===\n",__FILE__,__LINE__);
}
}
}//test_new_mj2_file()
static void reload_jp2_cb(Fl_Widget *w, void *v)
{
tile_in->value("");
tile_in->redraw();
cur_tile = -1;
cur_reduction = 0;
user_changed_tile = user_changed_reduct = 0;
reloaded = 1;
chooser_cb(read_idf);
reduct_in->value("0");
reduct_in->redraw();
}
void FLViewer_get_max_tiles_and_reduction(int *out_mx_tiles, int *out_mx_reduct)
{
*out_mx_tiles = max_tiles; *out_mx_reduct = max_reduction;
}
void FLViewer_set_max_reduction(int mx_reduct)
{
max_reduction = mx_reduct;
}
void FLViewer_set_max_tiles(int mx_tiles)
{
max_tiles = mx_tiles;
}
void FLViewer_put_max_tiles_and_reduction(int mx_tiles, int mx_reduct)
{
tiles_out->value("");
tiles_out->redraw();
reduct_out->value("");
reduct_out->redraw();
max_tiles = mx_tiles;
max_reduction = mx_reduct;
user_changed_tile = 1; user_changed_reduct = 1;
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_reduction);
reduct_in->value(vbuf);
reduct_in->redraw();
}
void FLViewer_reset_tiles_and_reduction()
{
tiles_out->value("");
tiles_out->redraw();
reduct_out->value("");
reduct_out->redraw();
user_changed_tile = user_changed_reduct = 0;
cur_tile = -1; cur_reduction = 0;
max_tiles = -1;
max_reduction = -1;
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_reduction);
reduct_in->value(vbuf);
reduct_in->redraw();
}
static void tiles_write_out(void)
{
if(user_changed_tile && user_changed_reduct)
{
if(max_tiles > 0)
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", max_tiles - 1);
tiles_out->value(vbuf);
tiles_out->redraw();
}
if(cur_reduction > -1)
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_reduction);
reduct_in->value(vbuf);
reduct_in->redraw();
}
if(max_reduction > 0)
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", max_reduction - 1);
reduct_out->value(vbuf);
reduct_out->redraw();
}
}
}
int FLViewer_has_tile_and_reduction(void)
{
return (user_changed_tile && user_changed_reduct);
}
void FLViewer_get_tile_and_reduction(int *out_tile, int *out_reduct)
{
*out_tile = cur_tile; *out_reduct = cur_reduction;
}
int FLViewer_has_area_values(void)
{
return user_changed_area;
}
void FLViewer_get_area_values(int *out_x0, int *out_y0,
int *out_x1, int *out_y1)
{
*out_x0 = area_x0; *out_y0 = area_y0;
*out_x1 = area_x1; *out_y1 = area_y1;
}
void FLViewer_set_max_mj2_tracks(unsigned int n)
{
int s;
if((s = canvas->selected_track) < 1)
s = 1;
mj2_max_tracks = (int)n-1;
snprintf(vbuf, sizeof(vbuf)-1, "%d/%d", s, mj2_max_tracks);
all_tracks_out->value(vbuf);
}
void FLViewer_set_max_components(unsigned int n)
{
max_components = (int)n;
snprintf(vbuf, sizeof(vbuf)-1, "%u", n);
component_out->value(vbuf);
}
void FLViewer_set_max_layers(unsigned int n)
{
max_layers = (int)n;
snprintf(vbuf,sizeof(vbuf)-1, "%d", max_layers);
layer_out->value(vbuf);
layer_in->value("0");
}
int FLViewer_layers()
{
return cur_layers;
}
int FLViewer_component()
{
return cur_component;
}
void FLViewer_layer_component_activate(int v)
{
if(v)
{
component_in->activate();
component_out->activate();
snprintf(vbuf, sizeof(vbuf)-1,"%d", cur_component);
component_in->value(vbuf);
snprintf(vbuf,sizeof(vbuf)-1,"%d", max_components);
component_out->value(vbuf);
layer_in->activate();
layer_out->activate();
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_layers);
layer_in->value(vbuf);
snprintf(vbuf, sizeof(vbuf)-1, "%d", max_layers);
layer_out->value(vbuf);
}
else
{
layer_in->value("");
layer_out->value("");
layer_in->deactivate();
layer_out->deactivate();
}
}
static void layer_in_cb(Fl_Widget *wid, void *v)
{
int i;
if(max_layers == 0)
{
layer_in->value("");
return;
}
i = atoi(layer_in->value());
if(i < 0 || i > max_layers)
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_layers);
layer_in->value(vbuf);
return;
}
cur_layers = i;
chooser_cb(read_idf);
}
static void component_in_cb(Fl_Widget *wid, void *v)
{
int i;
if(max_components == 0)
{
component_in->value("");
return;
}
i = atoi(component_in->value());
if(i < 0 || i > max_components)
{
snprintf(vbuf, sizeof(vbuf)-1, "%d", cur_component);
component_in->value(vbuf);
return;
}
cur_component = i;
chooser_cb(read_idf);
}
class Header : public Fl_Group
{
public:
Header(int x, int y, int w, int h, const char *l);
virtual int handle(int event);
};
static Header *header;
Header::Header(int X, int Y, int W, int H, const char *l)
: Fl_Group(X, Y, W, H, l)
{
int xx, yy, ww, bx, bw, gw, gh;
begin();
xx = X; yy = Y;
{
int ux = xx + BUTTON_W + 10;
url_out =
new Fl_Output(ux, yy, xx + W - ux, BUTTON_H, FILENAME_s);
url_out->textsize(LABEL_SIZE);
url_out->labelsize(LABEL_SIZE);
url_out->clear_visible_focus();
}
xx = X; yy += BUTTON_H + 3;
gw = 70 + FRAMES_W + 60 + FRAMES_W/2 + 4; gh = BUTTON_H + 4;
frames_group = new Fl_Group(xx, yy, gw, gh);
frames_group->box(FL_EMBOSSED_BOX);
frames_group->begin();
xx += 70; yy += 2;
all_frames_out =
new Fl_Output(xx, yy, FRAMES_W, BUTTON_H, ALLFRAMES_s);
all_frames_out->labelsize(LABEL_SIZE);
all_frames_out->textsize(LABEL_SIZE);
all_frames_out->clear_visible_focus();
xx += FRAMES_W + 60;
goto_frame_in =
new Fl_Input(xx, yy, FRAMES_W/2, BUTTON_H, START_s);
goto_frame_in->callback(goto_frame_cb);
goto_frame_in->when(FL_WHEN_ENTER_KEY_ALWAYS);
goto_frame_in->labelsize(LABEL_SIZE);
goto_frame_in->textsize(LABEL_SIZE);
frames_group->end();
xx = frames_group->x() + frames_group->w() + 5;
yy = frames_group->y();
ww = TRACKS_W/2;
gw = 70 + ww + 60 + ww + 4; gh = BUTTON_H + 4;
tracks_group = new Fl_Group(xx, yy, gw, gh);
tracks_group->box(FL_EMBOSSED_BOX);
tracks_group->begin();
xx += 70; yy += 2;
all_tracks_out =
new Fl_Output(xx, yy, ww, BUTTON_H, ALLTRACKS_s);
all_tracks_out->labelsize(LABEL_SIZE);
all_tracks_out->textsize(LABEL_SIZE);
all_tracks_out->clear_visible_focus();
xx += ww + 60;
goto_track_in =
new Fl_Input(xx, yy, ww, BUTTON_H, START_s);
goto_track_in->callback(goto_track_cb);
goto_track_in->when(FL_WHEN_ENTER_KEY_ALWAYS);
goto_track_in->labelsize(LABEL_SIZE);
goto_track_in->textsize(LABEL_SIZE);
tracks_group->end();
xx = tracks_group->x() + tracks_group->w() + 10;
yy = tracks_group->y() + 2;
{
Fl_Group *g = new Fl_Group(xx, yy, 115, BUTTON_H);
g->box(FL_FLAT_BOX);
g->color(DEFAULT_BACKGROUND+1);
g->begin();
xx += 70;
threads_spinner = new Fl_Spinner(xx, yy, 40, BUTTON_H, "Threads:");
threads_spinner->labelsize(LABEL_SIZE);
threads_spinner->minimum(0);
threads_spinner->maximum(6);
threads_spinner->step(1);
threads_spinner->value(0);
threads_spinner->callback(spinner_cb);
threads_spinner->deactivate();
g->end();
xx = g->x() + g->w();
}
xx += 10;
reload_jp2 = new Fl_Button(xx, yy, BUTTON_W + 15, BUTTON_H, RELOAD_s);
reload_jp2->callback(reload_jp2_cb);
reload_jp2->labelsize(LABEL_SIZE);
reload_jp2->deactivate();
xx = X; yy = reload_jp2->y() + reload_jp2->h() + 5;
ww = 70 + 40 + 40 + 40;
tiles_group = new Fl_Group(xx, yy, ww, BUTTON_H);
tiles_group->begin();
xx += 70;
tile_in =
new Fl_Input(xx, yy, 40, BUTTON_H, TILE_s);
tile_in->callback(tile_in_cb);
tile_in->when(FL_WHEN_RELEASE_ALWAYS);
tile_in->labelsize(LABEL_SIZE);
tile_in->textsize(LABEL_SIZE);
tile_in->value("");
tile_in->redraw();
xx += 40 + 40;
tiles_out =
new Fl_Output(xx, yy, 40, BUTTON_H, OF_s);
tiles_out->labelsize(LABEL_SIZE);
tiles_out->textsize(LABEL_SIZE);
tiles_out->clear_visible_focus();
tiles_out->value("");
tiles_out->redraw();
tiles_group->end();
tiles_group->deactivate();
xx = tiles_group->x() + tiles_group->w() + 5;
yy = tiles_group->y();
ww = 115 + 30 + 40 + 30;
reduct_group = new Fl_Group(xx, yy, ww, BUTTON_H);
reduct_group->begin();
xx += 115;
reduct_in =
new Fl_Input(xx, yy, 30, BUTTON_H, REDUCTION_s);
reduct_in->callback(reduct_in_cb);
reduct_in->when(FL_WHEN_RELEASE_ALWAYS);
reduct_in->labelsize(LABEL_SIZE);
reduct_in->textsize(LABEL_SIZE);
reduct_in->value(" ");
reduct_in->redraw();
xx += 30 + 40;
reduct_out =
new Fl_Output(xx, yy, 30, BUTTON_H, OF_s);
reduct_out->labelsize(LABEL_SIZE);
reduct_out->textsize(LABEL_SIZE);
reduct_out->clear_visible_focus();
reduct_out->value(" ");
reduct_out->redraw();
reduct_group->end();
reduct_group->deactivate();
xx = reduct_group->x() + reduct_group->w() + 10;
ww = 70 + 97;
xx += 75;
area_in =
new Fl_Input(xx, yy, 218, BUTTON_H, AREA_s);
area_in->callback(area_in_cb);
area_in->labelsize(LABEL_SIZE);
area_in->textsize(LABEL_SIZE);
area_in->value("x0,y0,x1,y1");
area_in->when(FL_WHEN_RELEASE_ALWAYS);
area_in->deactivate();
user_changed_tile = user_changed_reduct = 0;
max_tiles = 0; cur_tile = -1;
max_reduction = 0; cur_reduction = 0;
yy = tiles_group->y() + tiles_group->h() + 5;
xx = X;
bx = xx;
pause_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,STOP_s);
pause_but->callback(pause_cb);
pause_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
resume_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,GOON_s);
resume_but->callback(resume_cb);
resume_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
restart_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,RESTART_s);
restart_but->callback(restart_cb);
restart_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
fin_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,CLOSEFILE_s);
fin_but->callback(fin_cb);
fin_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
xx = fin_but->x() + fin_but->w() + 5;
yy = fin_but->y();
bx = xx;
backward_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,BACKWARD_s);
backward_but->callback(backward_cb);
backward_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
forward_but = new Fl_Button(bx,yy,BUTTON_W,BUTTON_H,FORWARD_s);
forward_but->callback(forward_cb);
forward_but->labelsize(LABEL_SIZE);
bx += BUTTON_W;
xx = forward_but->x() + forward_but->w() + 10;
yy = forward_but->y();
bw = BUTTON_W + 3;
{
Fl_Button *b = new Fl_Button(xx, yy, bw, BUTTON_H, CROP_s);
b->callback(crop_window_cb);
b->labelsize(LABEL_SIZE);
}
xx += bw + 5;
{
Fl_Button *b = new Fl_Button(xx,yy,BUTTON_W,BUTTON_H,BROWSE_s);
b->callback(browse_cb);
yy = b->y() + b->h() + 5;
}
xx = X + 70;
layer_in = new Fl_Input(xx, yy, 30, BUTTON_H, LAYER_s);
layer_in->callback(layer_in_cb);
layer_in->deactivate();
xx += layer_in->w() + 10 + 30;
layer_out = new Fl_Output(xx, yy, 30, BUTTON_H, OF_s);
layer_out->deactivate();
xx += layer_out->w() + 10 + 100;
component_in = new Fl_Input(xx, yy, 30, BUTTON_H, COMPONENT_s);
component_in->callback(component_in_cb);
component_in->deactivate();
xx += component_in->w() + 10 + 30;
component_out = new Fl_Output(xx, yy, 30, BUTTON_H, OF_s);
component_out->deactivate();
FLViewer_frames_animation(0);
end();
}/* Header::Header() */
int Header::handle(int event)
{
if(!Fl::event_inside(x(), y(), w(), h() ) ) return 0;
if(event == FL_LEAVE) return 1;
return Fl_Group::handle(event);
}
static unsigned char *print_buffer(size_t len)
{
unsigned char *buf;
if((buf = (unsigned char*)malloc(len)) != NULL)
memcpy(buf, canvas->cbuf, len);
return buf;
}
static void print_cb(Fl_Widget *wid, void *v)
{
const char *cs;
FILE *writer;
int ok, iw, ih, ic;
PSInfo ps;
PrintInfo print;
if(movie_runs || !canvas->cbuf)
{
fl_alert("%s", NO_FILE_TO_PRINT_s);
return;
}
memset(&ps, 0, sizeof(PSInfo));
memset(&print, 0, sizeof(PrintInfo));
/*----------------------------*/
Print_gui_create(&print);
/*----------------------------*/
if( !print.ok) return;
writer = fopen(print.fname_s, "wb");
if(writer == NULL)
{
cs = CANNOT_OPEN_s;
}
else
{
cs = SUCCESS_WITH_s;
ps.writer = writer;
iw = canvas->new_iwidth;
ih = canvas->new_iheight;
ic = canvas->new_idepth;
ps.src_buf = print_buffer(iw*ih*ic);
if(ps.src_buf == NULL)
{
fclose(writer); ps.writer = NULL;
return;
}
ps.bg_red = 255; ps.bg_green = 255; ps.bg_blue = 255;
ps.title_s = print.title_s;
ps.media_s = print.media_s;
ps.center = print.center;
ps.landscape = print.want_landscape;
ps.portrait = print.want_portrait;
/* want_color, want_gray */
ps.fmedia_w = (int)(print.fpaper_w * 72./25.4);
ps.fmedia_h = (int)(print.fpaper_h * 72./25.4);
ps.image_w = iw; ps.image_h = ih;
ps.image_channels = ic;
ps.fmargin_lhs = (int)(print.fmargin_lhs * 72./25.4);
ps.fmargin_top = (int)(print.fmargin_top * 72./25.4);
ps.fmargin_rhs = (int)(print.fmargin_rhs * 72./25.4);
ps.fmargin_bot = (int)(print.fmargin_bot * 72./25.4);
/*===============================*/
ok = PS_image_draw(&ps);
/*===============================*/
fclose(writer);
free(ps.src_buf);
if( !ok)
cs = FAILURE_WITH_s;
else
if(print.command_s)
{
#ifdef _WIN32
fl_message("%s\n%s",USE_SYSTEM_COMMAND_TO_PRINT_s, print.fname_s);
#else
char *cmd;
size_t len;
int ret;
len = strlen(print.command_s) + strlen(print.printer_s)
+ strlen(print.fname_s) + 32;
cmd = (char*)malloc(len);
if(cmd != NULL)
{
/*-----
'man system':
Do not use system() from a program with set-user-ID or set-group-ID
privileges, because strange values for some environment variables might
be used to subvert system integrity. Use the exec(3) family of func-
tions instead, but not execlp(3) or execvp(3)
------*/
while(print.nr_copies)
{
snprintf(cmd, len, "%s%s %s", print.command_s, print.printer_s,
print.fname_s);
ret = system(cmd);
if(WIFSIGNALED(ret)
&& (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))
break;
--print.nr_copies;
}
free(cmd);
}
#endif /* _WIN32 */
}
}
fl_message("%s\n%s", cs, print.fname_s);
if(print.remove_fname)
remove(print.fname_s);
free(print.fname_s);
free(print.printer_s);
free(print.command_s);
free(print.format_s);
free(print.title_s);
free(print.media_s);
}/* print_cb() */
#ifdef OPJ_HAVE_LIBPNG
static void save_as_png_cb(Fl_Widget *w, void *v)
{
const char *cs, *period;
char *write_idf;
int ok;
struct stat sb;
if(movie_runs || !canvas->cbuf)
{
fl_alert("%s", NO_FILE_TO_SAVE_s);
return;
}
cs = fl_input(ENTER_PNG_TO_SAVE_s, "name.png");
if(cs == NULL || *cs == 0) return;
if(stat(cs, &sb) == 0)
{
if(fl_choice(FILE_EXISTS_s, "NO", "YES", NULL) == 0) return;
}
ok =
( ((period = strrchr(cs, '.')) != NULL)
&& (strncasecmp(period, ".png", 4) == 0));
if(!ok)
{
if(fl_choice(MISSING_PNG_EXT_s, "NO", "YES", NULL) == 0)
return;
}
write_idf = strdup(cs);
if(write_idf != NULL)
{
PNG_save_file(canvas, write_idf);
free(write_idf);
}
}
#endif // OPJ_HAVE_LIBPNG
static void save_as_opj_cb(Fl_Widget *w, void *v)
{
const char *cs;
char *write_idf;
struct stat sb;
if(movie_runs || !canvas->cbuf)
{
fl_alert("%s", NO_FILE_TO_SAVE_s);
return;
}
cs = fl_input(ENTER_OPJ_TO_SAVE_s, "name.[jp2|j2k|jpc|j2c]");
if(cs == NULL || *cs == 0) return;
if(stat(cs, &sb) == 0)
{
if(fl_choice(FILE_EXISTS_s, "NO", "YES", NULL) == 0) return;
}
write_idf = strdup(cs);
if(write_idf != NULL)
{
JP2_save_file(canvas, write_idf);
free(write_idf);
}
}
/*
{"IDF",shortcut,CB,user_data,FLAGS,labeltype,LABELFONT,LABELSIZE,labelcolor}
*/
Fl_Menu_Item popup_items[] =
{
{EXIT_s, 0, &exit_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, FL_YELLOW},
{PRINT_s, 0, &print_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
{" -5%", 0, &zoomout_cb, NULL, FL_NORMAL_LABEL, 0, 4, 15, 0},
{" -25%", 0, &zoomout_25_cb, NULL, FL_NORMAL_LABEL, 0, 4, 15, 0},
{" -50%", 0, &zoomout_50_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
{" +5%", 0, &zoomin_cb, NULL, FL_NORMAL_LABEL, 0, 4, 15, 0},
{" +25%", 0, &zoomin_25_cb, NULL, FL_NORMAL_LABEL, 0, 4, 15, 0},
{" +50%", 0, &zoomin_50_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
{" 100%", 0, &reset_zoom_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
#ifdef OPJ_HAVE_LIBPNG
{SAVE_AS_PNG_s, 0, &save_as_png_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
#endif
{SAVE_AS_OPJ_s, 0, &save_as_opj_cb, NULL, FL_MENU_DIVIDER, 0, 4, 15, 0},
{NULL, 0, NULL, NULL, 0, 0, 0, 0, 0}
};
static void popup_create(int x, int y)
{
Fl_Menu_Button *popup;
popup = new Fl_Menu_Button(x, y, MAX_SCROLLER_W, MAX_SCROLLER_H);
popup->type(Fl_Menu_Button::POPUP3);
popup->menu(popup_items);
}
static void show_image(Fl_Image* img)
{
int scroll_h, scroll_w, iw, ih, win_w, win_h;
int has_hbar, has_vbar, bar_size;
unsigned char type;
if((bar_size = scroll->scrollbar_size()) == 0) bar_size = BAR_SIZE;
#ifdef _WIN32
EnterCriticalSection(&CriticalSection);
#else
ENTER_CRITICAL(semid);
#endif
has_hbar = has_vbar = 0;
iw = img->w(); ih = img->h();
/* movie without scrollbars, the whole image is visible:
*/
if( !movie_runs)
{
if(iw > MAX_SCROLLER_W)
{
has_hbar = bar_size;
if(ih + bar_size > MAX_SCROLLER_H)
has_vbar = bar_size;
}
else
if(ih > MAX_SCROLLER_H)
{
has_vbar = bar_size;
if(iw + bar_size > MAX_SCROLLER_W)
has_hbar = bar_size;
}
}
if(has_vbar)
scroll_h = MAX_SCROLLER_H;
else
scroll_h = ih + has_hbar;
if(has_hbar)
scroll_w = MAX_SCROLLER_W;
else
scroll_w = iw + has_vbar;
win_h = HEADER_H + scroll_h + BORDER_SIZE;
win_w = SCROLLER_X + scroll_w + BORDER_SIZE;
if(win_w < WINDOW_MIN_W) win_w = WINDOW_MIN_W;
if(win_h < WINDOW_MIN_H) win_h = WINDOW_MIN_H;
main_win->size(win_w, win_h);
scroll->size(scroll_w, scroll_h);
scroll_box->size(iw, ih);
scroll_box->image(img);
type = 0;
if(has_hbar) type |= Fl_Scroll::HORIZONTAL;
if(has_vbar) type |= Fl_Scroll::VERTICAL;
scroll->type(type);
scroll->scroll_to(0,0);
main_win->redraw();
#ifdef _WIN32
LeaveCriticalSection(&CriticalSection);
#else
LEAVE_CRITICAL(semid);
#endif
}/* show_image() */
void FLViewer_use_buffer(const void *b, unsigned int w, unsigned int h,
int depth)
{
Fl_RGB_Image *rgb, *new_rgb;
rgb = canvas->new_rgb;
scroll_box->image(NULL);
canvas->new_rgb = NULL;
new_rgb = new Fl_RGB_Image((unsigned char*)b, (int)w, (int)h, depth);
if(new_rgb)
{
if(fscale != 1.0)
{
Fl_Image *temp;
double fw, fh;
fw = (double)new_rgb->w() * fscale;
fh = (double)new_rgb->h() * fscale;
temp = new_rgb->copy((int)fw, (int)fh);
delete new_rgb;
new_rgb = (Fl_RGB_Image*)temp;
}
canvas->new_idepth = new_rgb->d();
canvas->new_iwidth = new_rgb->w();
canvas->new_iheight = new_rgb->h();
canvas->cbuf = new_rgb->data()[0];
show_image((Fl_Image*)new_rgb);
}
if(rgb) delete rgb;
canvas->new_rgb = new_rgb;
}/* FLViewer_use_buffer() */
void FLViewer_area_activate(int v)
{
if(v)
{
area_in->activate();
}
else
{
area_in->deactivate();
}
}
void FLViewer_tiles_activate(int v)
{
if(v)
{
tiles_group->activate();
reduct_group->activate();
reload_jp2->activate();
tiles_write_out();
}
else
{
tiles_out->value("");
tiles_out->redraw();
tiles_group->deactivate();
cur_reduction = 0; max_reduction = 0;
reduct_in->value("");
reduct_out->value("");
reduct_group->deactivate();
reload_jp2->deactivate();
}
}
void FLViewer_frames_animation(int v)
{
FLViewer_animation(v);
goto_frame_in->value("");
goto_frame_in->redraw();
all_frames_out->value("");
all_frames_out->redraw();
goto_track_in->value("");
goto_track_in->redraw();
all_tracks_out->value("");
all_tracks_out->redraw();
if(v)
{
frames_group->activate();
tracks_group->activate();
}
else
{
frames_group->deactivate();
tracks_group->deactivate();
tiles_out->value("");
tile_in->value("");
tiles_group->deactivate();
cur_reduction = 0; max_reduction = 0;
reduct_in->value("");
reduct_out->value("");
reduct_group->deactivate();
}
if(canvas)
{
canvas->selected_frame = -1;
canvas->top_frame = -1;
canvas->selected_track = -1;
canvas->top_track = -1;
}
}
void FLViewer_animation(int v)
{
if(v)
{
pause_but->activate();
resume_but->activate();
restart_but->activate();
fin_but->activate();
backward_but->activate();
forward_but->activate();
}
else
{
pause_but->deactivate();
resume_but->deactivate();
restart_but->deactivate();
fin_but->deactivate();
backward_but->deactivate();
forward_but->deactivate();
}
}
void FLViewer_mj2_animation(int v)
{
FLViewer_frames_animation(v);
}
void FLViewer_show_frame(int n, int m)
{
char all_buf[32];
snprintf(all_buf, sizeof(all_buf)-1, "%d/%d", n, m);
all_frames_out->value(all_buf);
}
void FLViewer_show_track(int n, int m)
{
char all_buf[32];
int s;
if((s = canvas->selected_track) < 1)
s = 1;
snprintf(all_buf,sizeof(all_buf)-1,"%d/%d", s, m);
all_tracks_out->value(all_buf);
}
void FLViewer_clear_wait(void)
{
url_out->value(""); url_out->redraw();
}
void FLViewer_wait(void)
{
url_out->value(WAITPLEASE_s);
}
void FLViewer_url(const char *fname, int w, int h)
{
const char *cs = NULL;
#ifdef _WIN32
cs = strrchr(fname, '\\');
#else
cs = strrchr(fname, '/');
#endif
if(cs) ++cs; else cs = fname;
snprintf(url_buf, 511, "%s (%d x %d)",cs,w,h);
url_out->value(url_buf);
}
static void load_image(FILE *fp, const char *fname, uint64_t fsize)
{
unsigned char magic_buf[32];
memset(magic_buf, 0, 32);
(void)fread(magic_buf, 1, 32, fp);
rewind(fp);
FLViewer_header_deactivate();
#ifdef OPJ_HAVE_LIBPNG
if(memcmp(magic_buf, PNG_MAGIC, 8) == 0)
{
if(tree) tree->clear();
component_in->value("");
component_in->deactivate();
component_out->value("");
component_out->deactivate();
PNG_load(canvas, fp, fname, fsize);
return;
}
#endif
if(memcmp(magic_buf, JP2_RFC3745_MAGIC, 12) == 0
&& memcmp(magic_buf+20, "\x6d\x6a\x70\x32", 4) == 0)
{
FLViewer_close_reader();
if(strlen(read_idf) > OPJ_PATH_LEN - 2)
{
fl_alert("%s:\n%s", read_idf, FILENAME_TOO_LONG_s);
return;
}
FLViewer_reset_tiles_and_reduction();
test_new_mj2_file();
OPENMJ2_load(canvas, fname, fsize);
return;
}
if(memcmp(magic_buf, JP2_RFC3745_MAGIC, 12) == 0
|| memcmp(magic_buf, JP2_MAGIC, 4) == 0
|| memcmp(magic_buf, J2K_CODESTREAM_MAGIC, 4) == 0
)
{
unsigned char *src;
FTYPInfo ftyp;
int ret;
if(strlen(read_idf) > OPJ_PATH_LEN - 2)
{
fl_alert("%s:\n%s", read_idf, FILENAME_TOO_LONG_s);
FLViewer_close_reader();
return;
}
if((src = (unsigned char*)malloc(fsize)) == NULL)
{
FLViewer_close_reader();
return;
}
(void)fread(src, 1, fsize, fp);
FLViewer_close_reader();
ret = JPEG2000_test_ftyp(fname, src, fsize, &ftyp);
free(src); src = NULL;
if(ret == 0)
{
if(ftyp.is_j2k == 0)
{
fprintf(stderr,"%s:%d:\n\tload_image(%s) FAILED\n",
__FILE__,__LINE__,fname);
return;
}
}
FLViewer_layer_component_activate(1);
test_new_jp2_file();
if(cmd_line_reduction > 0)
{
user_changed_tile = 1; user_changed_reduct = 1;
cur_reduction = cmd_line_reduction;
FLViewer_tiles_activate(1);
cmd_line_reduction = 0;
}
OPENJPEG_load(canvas, fname, src, fsize, ftyp.decod_format);
return;
}
#ifdef WANT_PGX
if(memcmp(buf, "PG", 2) == 0)
{
if(tree) tree->clear();
PGX_load(canvas, fp, fname, fsize);
return;
}
#endif //WANT_PGX
fl_alert("%s\n%s\n %s", CANNOT_USE_FILE_s, fname,
NO_DRIVER_FOUND_s);
} /* load_image() */
static void chooser_cb(const char *cs)
{
struct stat sb;
if(cs == NULL || *cs == 0) return;
if(stat(cs, &sb) < 0)
{
fl_alert("%s\n%s", FILE_NOT_FOUND_s, cs);
return;
}
if((sb.st_mode & S_IFMT) == S_IFDIR) return;
{
char dbuf[4096];
#ifdef _WIN32
strncpy(dbuf, cs, 4095); // WIN32 without soft link
#else
ssize_t n;
unsigned int reg;
char sbuf[4096];
strncpy(sbuf, cs, 4095); *dbuf = 0;
if(lstat(sbuf, &sb) == 0)
{
reg = ((S_IFREG & sb.st_mode) == (S_IFMT & sb.st_mode));
if( !reg && (n = readlink(sbuf, dbuf, 4095)) > 0)
dbuf[n] = 0;
else
strncpy(dbuf, cs, 4095);
}
#endif
if(stat(dbuf, &sb) < 0)
{
fl_alert("%s\n%s", FILE_NOT_FOUND_s, dbuf);
return;
}
if(sb.st_size == 0)
{
fl_alert("%s\n%s", FILE_SIZE_ZERO_s, dbuf);
return;
}
if(sb.st_size > FILESIZE_LIMIT)
{
fl_alert("%s\n%s\n", dbuf, FILESIZE_TOO_LONG_s);
return;
}
start_overlay = 1;
main_win->redraw_overlay();
if(canvas->cleanup)
{
canvas->cleanup();
canvas->cleanup = NULL;
}
FLViewer_close_reader();
if(read_idf)
{
free(read_idf); read_idf = NULL;
}
/*-------------------------------*/
reader = fopen(dbuf, "rb");
if(reader == NULL)
{
perror(dbuf);
fl_alert("%s\n%s", FILE_NOT_FOUND_s, dbuf);
return;
}
read_idf = strdup(dbuf);
if(read_idf == NULL)
{
fprintf(stderr,"flviewer.cxx:%d:\n\tmemory out\n",__LINE__);
exit(1);
}
movie_runs = 0;
load_image(reader, read_idf, (uint64_t)sb.st_size);
}
}/* chooser_cb() */
static void goto_frame_cb(Fl_Widget *w, void *v)
{
const char *cs;
int i;
if( !w->contains(Fl::belowmouse())) return;
cs = ((Fl_Input*)w)->value();
if(cs && *cs)
{
i = atoi(cs);
if(i < 1) return;
if(i > canvas->top_frame) i = canvas->top_frame;
canvas->selected_frame = i;
}
}
static void goto_track_cb(Fl_Widget *w, void *v)
{
const char *cs;
int i;
if( !w->contains(Fl::belowmouse())) return;
cs = ((Fl_Input*)w)->value();
if(cs && *cs)
{
i = atoi(cs);
if(i < 1) { goto_track_in->value(""); return; }
if(i > canvas->top_track)
{
if(canvas->top_track < 1)
canvas->top_track = 1;
i = canvas->top_track;
snprintf(vbuf, sizeof(vbuf)-1, "%d", i);
goto_track_in->value(vbuf);
goto_track_in->redraw();
}
canvas->selected_track = i;
}
}
int FLViewer_frame_selected(void)
{
int n;
if((n = canvas->selected_frame) >= 1)
{
canvas->selected_frame = -1;
return n;
}
return -1;
}
// see Fl::option(Fl::OPTION_FNFC_USES_GTK, false) in main()
//
static void browse_cb(Fl_Widget *wid, void *v)
{
Fl_Native_File_Chooser native;
native.title("Select Image File");
native.type(Fl_Native_File_Chooser::BROWSE_FILE);
native.filter(IMG_PATTERN);
native.preset_file(read_idf);
#ifdef _WIN32
if(canvas->cleanup)
{
canvas->cleanup();
canvas->cleanup = NULL;
}
#endif //_WIN32
switch(native.show())
{
case -1:
fprintf(stderr, "FILE_CHOOSER_ERROR: %s\n", native.errmsg());
break;
case 1: /* Cancel */
break;
default:
if(native.filename())
chooser_cb(native.filename());
break;
}
}
static void pause_cb(Fl_Widget *wid, void *v)
{
if(canvas->pause) canvas->pause();
}
static void resume_cb(Fl_Widget *wid, void *v)
{
if(canvas->resume) canvas->resume();
}
static void restart_cb(Fl_Widget *wid, void *v)
{
if(canvas->restart) canvas->restart();
}
static void backward_cb(Fl_Widget *wid, void *v)
{
if(canvas->backward) canvas->backward();
}
static void forward_cb(Fl_Widget *wid, void *v)
{
if(canvas->forward) canvas->forward();
}
static void fin_cb(Fl_Widget *wid, void *v)
{
if(canvas->fin) canvas->fin();
}
static void exit_cb(Fl_Widget *wid, void *v)
{
if(canvas->cleanup)
{
canvas->cleanup();
}
#ifdef _WIN32
DeleteCriticalSection(&CriticalSection);
#else /* not _WIN32 */
if(semctl(semid, 0, IPC_RMID, 0) == -1)
fprintf(stderr,"%s:%d: semctl IPC_RMID failed\n",__FILE__,__LINE__);
#endif /* _WIN32 */
if(read_idf != NULL) free(read_idf);
if(jp2_file != NULL) free(jp2_file);
if(mj2_file != NULL) free(mj2_file);
if(reader != NULL) fclose(reader);
free(root_dir);
delete main_win;
exit(0);
}
static void usage(void)
{
const char *bar=
"\n------------------------------------------------------------------\n";
fputs(bar, stderr);
fprintf(stderr,"%s\n"
"USAGE: flviewer [--bg BACKGROUND_COLOR] [--r INT] [FILE]\n",
PACKAGE_STRING);
fputs("\twith BACKGROUND_COLOR = "
"(\"TEXT\" | \"#RGB\" | \"rgb:R/G/B\" )\n"
"\t e.g. (--bg \"red\" | --bg \"#ff0000\" "
"| --bg \"rgb:ff/00/00\" )", stderr);
fputs("\n\t--r INT means the reduction on start, e.g. --r 2\n", stderr);
fputs(bar, stderr);
}
static void shrink_name(char *buf)
{
char *s, *d;
int ch;
s = d = buf;
while((ch = *s++))
{
if(isspace(ch)) continue;
*d++ = (char)tolower(ch);
}
*d = 0;
}
int main(int argc, char *argv[])
{
const char *fname, *s;
int i, x, y, found_bgcolor, reduct;
unsigned char rc, gc, bc;
canvas = (Canvas*)calloc(1, sizeof(Canvas));
if(canvas == NULL)
{
fprintf(stderr,"flviewer.cxx:%d:\n\tmemory out\n",__LINE__);
return 1;
}
cmd_line_reduction = reduct = 0;
#ifdef _WIN32
if(!InitializeCriticalSectionAndSpinCount(&CriticalSection,
IDLE_SPIN) )
{
fprintf(stderr,"%s:%d: InitializeCriticalSectionAndSpinCount failed\n",
__FILE__,__LINE__);
free(canvas);
return 1;
}
#else /* not _WIN32 */
semid = semget(getpid(), 1, S_IRWXU|S_IRWXG|S_IRWXO|IPC_CREAT|IPC_EXCL);
if(semid == -1)
{
fprintf(stderr,"%s:%d:semget failed\n",__FILE__,__LINE__);
perror(NULL);
free(canvas);
return 1;
}
/* triggers BUG in PowerPC: if(semctl(semid, 0, SETVAL, 1) == -1) */
su.val = 1;
if(semctl(semid, 0, SETVAL, su) == -1)
{
fprintf(stderr,"%s:%d:semctl SETVAL failed\n",__FILE__,__LINE__);
perror(NULL);
free(canvas);
return 1;
}
#endif /* _WIN32 */
Fl::visual(FL_RGB);
fl_register_images();
#ifndef _WIN32
#ifdef HAVE_OPTION_FNFC_USES_GTK
Fl::option(Fl::OPTION_FNFC_USES_GTK, false);
#endif
#endif
fname = NULL; found_bgcolor = 0;
for(i = 1; i < argc; ++i)
{
s = argv[i];
if(strcmp(s, "--help") == 0
|| strcmp(s, "-help") == 0
|| *s == '?'
|| strcmp(s, "--version") == 0
|| strcmp(s, "-V") == 0
)
{
usage();
return 0;
}
if(strcasecmp(s, "--bg") == 0)
{
++i;
s = argv[i];
if(*s == '#' || strncasecmp(s, "rgb:", 4) == 0 || isalpha(*s))
{
strncpy(bgcolor_buf, s, MAX_COLORBUF);
bgcolor_buf[MAX_COLORBUF] = 0;
found_bgcolor = 1;
if(*s != '#')
shrink_name(bgcolor_buf);
continue;
}
continue;
}
if(strcasecmp(s, "--r") == 0)
{
++i;
s = argv[i];
reduct = atoi(s);
continue;
}
if(*s != '-')
{
fname = s; continue;
}
}/* for() */
#ifdef _WIN32
if((root_dir = getenv("UserProfile")))
root_dir = strdup(root_dir);
else
root_dir = strdup("C:\\Windows\\Temp");
#else
root_dir = strdup(getenv("HOME"));
#endif
if(root_dir == NULL)
{
fprintf(stderr,"flviewer.cxx:%d:\n\tmemory out\n",__LINE__);
return 1;
}
start_overlay = 1;
win_w = WINDOW_MIN_W; win_h = WINDOW_MIN_H;
main_win = new Overlay(WIN_X, WIN_Y, win_w, win_h);
main_win->color(DEFAULT_BACKGROUND);
main_win->begin();
x = BORDER_SIZE; y = BORDER_SIZE;
header = new Header(x, y, HEADER_W, HEADER_H - BORDER_SIZE, NULL);
header->resizable(NULL);
tree = new UserTree(TREE_X, TREE_Y, TREE_W, TREE_H);
tree->begin();
tree->box(FL_DOWN_BOX);
tree->color((Fl_Color)55);
tree->selection_color((Fl_Color)55);
tree->labeltype(FL_NORMAL_LABEL);
tree->labelfont(0);
tree->labelsize(12);
tree->item_labelsize(12);
tree->labelcolor(FL_FOREGROUND_COLOR);
tree->align(Fl_Align(FL_ALIGN_TOP));
tree->when(FL_WHEN_RELEASE);
#ifdef USE_CUSTOM_ICONS
tree->openicon(&L_openpixmap);
tree->closeicon(&L_closepixmap);
#endif
tree->connectorstyle(FL_TREE_CONNECTOR_SOLID);
tree->marginleft(0);
tree->connectorwidth(7);
#if FLTK_ABI_VERSION >= 10304
tree->item_reselect_mode(FL_TREE_SELECTABLE_ALWAYS);
#endif
tree->root_label(" ");
tree->end();
if(found_bgcolor)
{
if( !rgb_color_values(bgcolor_buf, rc, gc, bc))
fl_parse_color(bgcolor_buf, rc, gc, bc);
}
else
Fl::get_color(DEFAULT_CANVAS_BACKGROUND, rc, gc, bc);
canvas->bg_red = rc; canvas->bg_green = gc;
canvas->bg_blue = bc;
scroll = new
Fl_Scroll(SCROLLER_X, SCROLLER_Y, MIN_SCROLLER_W,MIN_SCROLLER_H);
scroll->box(FL_FLAT_BOX);
scroll->begin();
scroll_box = new
ImageBox(SCROLLER_X, SCROLLER_Y, MIN_SCROLLER_W,MIN_SCROLLER_H);
scroll_box->box(FL_FLAT_BOX);
scroll_box->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
scroll_box->color(fl_rgb_color(rc, gc, bc));
scroll->end();
scroll->resizable(scroll_box);
scroll->type(0);
popup_create(SCROLLER_X, SCROLLER_Y);
main_win->end();
/*---------
main_win->size_range(main_win->w(), main_win->h(),
0, 0, 0, 0);
-----------*/
main_win->show();
if(fname)
{
if(reduct > 0)
{
cmd_line_reduction = reduct;
user_changed_tile = 1; user_changed_reduct = 1;
cur_reduction = reduct;
FLViewer_tiles_activate(1);
}
chooser_cb(fname);
}
return Fl::run();
}//main()