summaryrefslogtreecommitdiff
path: root/examples/animgifimage-resize.cxx
blob: 1417255b36d8d93d219645499b4626264045f38e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//
//  Test program for Fl_Anim_GIF_Image::copy().
//
#include <FL/Fl_Anim_GIF_Image.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <stdlib.h>

static Fl_Anim_GIF_Image *orig = 0;
static bool draw_grid = true;

static int events(int event_) {
  if (event_ == FL_SHORTCUT && Fl::first_window()) {
    if (Fl::event_key()=='g') {
      draw_grid = !draw_grid;
      printf("grid: %s\n", (draw_grid ? "ON" : "OFF"));
    }
    else if (Fl::event_key()=='b') {
      if (Fl_Image::scaling_algorithm() != FL_RGB_SCALING_BILINEAR)
        Fl_Image::scaling_algorithm(FL_RGB_SCALING_BILINEAR);
      else
        Fl_Image::scaling_algorithm(FL_RGB_SCALING_NEAREST);
      printf("bilenear: %s\n", (Fl_Image::scaling_algorithm() != FL_RGB_SCALING_BILINEAR ? "OFF" : "ON"));
    }
    else
      return 0;
    Fl::first_window()->redraw();
  }
  return 1;
}

class Canvas : public Fl_Box {
  typedef Fl_Box Inherited;
public:
  Canvas(int x, int y, int w, int h) :
    Inherited(x, y, w, h) {}
  void draw() FL_OVERRIDE {
    if (draw_grid) {
      // draw a transparency grid as background
      static const Fl_Color C1 = fl_rgb_color(0xcc, 0xcc, 0xcc);
      static const Fl_Color C2 = fl_rgb_color(0x88, 0x88, 0x88);
      static const int SZ = 8;
      for (int y = 0; y < h(); y += SZ) {
        for (int x = 0; x < w(); x += SZ) {
          fl_color(x%(SZ * 2) ? y%(SZ * 2) ? C1 : C2 : y%(SZ * 2) ? C2 : C1);
          fl_rectf(x, y, 32, 32);
        }
      }
    }
    // draw the current image frame over the grid
    Inherited::draw();
  }
  void do_resize(int W, int H) {
    if (image() && (image()->w() != W || image()->h() != H)) {
      Fl_Anim_GIF_Image *animgif = (Fl_Anim_GIF_Image *)image();
      animgif->stop();
      image(0);
      // delete already copied images
      if (animgif != orig ) {
        delete animgif;
      }
      Fl_Anim_GIF_Image *copied = (Fl_Anim_GIF_Image *)orig->copy(W, H);
      if (!copied->valid()) { // check success of copy
        Fl::warning("Fl_Anim_GIF_Image::copy() %d x %d failed", W, H);
      }
      else {
        printf("resized to %d x %d\n", copied->w(), copied->h());
      }
      copied->canvas(this, Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS);
    }
    window()->cursor(FL_CURSOR_DEFAULT);
  }
  static void do_resize_cb(void *d) {
    Canvas *c = (Canvas *)d;
    c->do_resize(c->w(), c->h());
  }
  void resize(int x, int y, int w, int h) FL_OVERRIDE {
    Inherited::resize(x, y, w, h);
    // decouple resize event from actual resize operation
    // to avoid lockups..
    Fl::remove_timeout(do_resize_cb, this);
    Fl::add_timeout(0.1, do_resize_cb, this);
    window()->cursor(FL_CURSOR_WAIT);
  }
};

int main(int argc, char *argv[]) {
  // setup play parameters from args
  const char *fileName = 0;
  bool bilinear = false;
  bool optimize = false;
  bool uncache = false;
  bool debug = false;
  for (int i = 1; i < argc; i++) {
    if (!strcmp(argv[i], "-b")) // turn bilinear scaling on
      bilinear = true;
    else if (!strcmp(argv[i], "-o")) // turn optimize on
      optimize = true;
    else if (!strcmp(argv[i], "-g")) // disable grid
      draw_grid = false;
    else if (!strcmp(argv[i], "-u")) // uncache
      uncache = true;
    else if (!strcmp(argv[i], "-d")) // debug
      debug = true;
    else if (argv[i][0] != '-' && !fileName) {
      fileName = argv[i];
    }
    else if (argv[i][0] == '-') {
      printf("Invalid argument: '%s'\n", argv[i]);
      exit(1);
    }
  }
  if (!fileName) {
    fprintf(stderr, "Test program for animated copy.\n");
    fprintf(stderr, "Usage: %s fileName [-b]ilinear [-o]ptimize [-g]rid [-u]ncache\n", argv[0]);
    exit(0);
  }
  Fl_Anim_GIF_Image::min_delay = 0.1; // set a minumum delay for playback

  Fl_Double_Window win(640, 480);

  // prepare a canvas for the animation
  // (we want to show it in the center of the window)
  Canvas canvas(0, 0, win.w(), win.h());
  win.resizable(win);
  win.size_range(1, 1);

  win.end();
  win.show();

  // create/load the animated gif and start it immediately.
  // We use the 'DONT_RESIZE_CANVAS' flag here to tell the
  // animation not to change the canvas size (which is the default).
  int flags = Fl_Anim_GIF_Image::Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS;
  if (optimize) {
    flags |= Fl_Anim_GIF_Image::OPTIMIZE_MEMORY;
    printf("Using memory optimization (if image supports)\n");
  }
  if (debug) {
    flags |= Fl_Anim_GIF_Image::DEBUG_FLAG;
  }
  orig = new Fl_Anim_GIF_Image(/*name_=*/ fileName,
                             /*canvas_=*/ &canvas,
                              /*flags_=*/ flags );

  // check if loading succeeded
  printf("%s: valid: %d frames: %d uncache: %d\n",
    orig->name(), orig->valid(), orig->frames(), orig->frame_uncache());
  if (orig->valid()) {
    win.copy_label(fileName);

    // print information about image optimization
    int n = 0;
    for (int i = 0; i < orig->frames(); i++) {
      if (orig->frame_x(i) != 0 || orig->frame_y(i) != 0) n++;
    }
    printf("image has %d optimized frames\n", n);

    Fl_Image::scaling_algorithm(FL_RGB_SCALING_NEAREST);
    if (bilinear) {
      Fl_Image::scaling_algorithm(FL_RGB_SCALING_BILINEAR);
      printf("Using bilinear scaling - can be slow!\n");
      // NOTE: this can be *really* slow with large sizes, if FLTK
      //       has to resize on its own without hardware scaling enabled.
    }
    orig->frame_uncache(uncache);
    if (uncache) {
      printf("Caching disabled - watch cpu load!\n");
    }

    // set initial size to fit into window
    double ratio = orig->valid() ? (double)orig->w() / orig->h() : 1;
    int W = win.w() - 40;
    int H = (double)W / ratio;
    printf("original size: %d x %d\n", orig->w(), orig->h());
    win.size(W, H);
    Fl::add_handler(events);

    return Fl::run();
  }
}